Merge lp:~widelands-dev/widelands-website/delete_user into lp:widelands-website
- delete_user
- Merge into trunk
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Merged at revision: | 500 | ||||||||
Proposed branch: | lp:~widelands-dev/widelands-website/delete_user | ||||||||
Merge into: | lp:widelands-website | ||||||||
Diff against target: |
749 lines (+295/-143) 25 files modified
django_messages_wl/views.py (+1/-1) media/css/comments.css (+1/-0) news/feeds.py (+0/-22) news/urls.py (+4/-4) pybb/feeds.py (+1/-10) settings.py (+8/-0) templates/django_messages/view.html (+3/-2) templates/mainpage.html (+1/-1) templates/pybb/feeds/posts_description.html (+5/-1) templates/pybb/feeds/topics_description.html (+5/-1) templates/pybb/last_posts.html (+1/-1) templates/threadedcomments/inlines/comments.html (+1/-1) templates/wiki/feeds/history_description.html (+6/-1) templates/wiki/recentchanges.html (+2/-1) templates/wlprofile/delete_me.html (+42/-0) templates/wlprofile/edit_profile.html (+7/-12) templates/wlprofile/view_profile.html (+75/-59) urls.py (+0/-4) wiki/feeds.py (+2/-16) wlprofile/context_processors.py (+6/-0) wlprofile/migrations/0002_profile_deleted.py (+20/-0) wlprofile/models.py (+1/-0) wlprofile/templatetags/wlprofile_extras.py (+9/-2) wlprofile/urls.py (+2/-0) wlprofile/views.py (+92/-4) |
||||||||
To merge this branch: | bzr merge lp:~widelands-dev/widelands-website/delete_user | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
GunChleoc | Approve | ||
kaputtnik (community) | Needs Resubmitting | ||
Review via email: mp+354978@code.launchpad.net |
Commit message
Make it possible to 'delete a user by himself, which means clean his data and show 'Deleted' in every place where a username is shown.
Description of the change
Added a link in the edit profile page which switch to a page showing what deletion means. After clicking on 'I am sure, delete me', the following changes are made:
- Log the user immediately out
- Delete possible playtime scheduling dates
- Delete the Online Gaming Password
- Clean the users profile page, including physically deleting his current image of avatar
- Deactivate all subscriptions for this user
- Put all his PMs in the users trash
- Set the user inactive, also set 'is_staff' and 'is_superuser' to false
- Set the users E-Mail to the value of settings.
- Show the value of settings.
- Prevent sending PMs to a deleted user
- Prevent showing the users profile by directly typing the url in the browsers addressbar
The decision when to show the DELETED_USERNAME is done by comparing the value of the new boolean field 'deleted' in the model wlprofile.Profile. I have added this new field because other comparisons (e.g. against 'is_staff' or the anonymized Email address) seems a bit iffy to me.
What username should shown for a deleted user? Currently this is 'Deleted', if we want another name it should be consistent with the username rules, which means it should contain only alphanumeric, _, @, +, . and - characters.
Just found that the DELETED_
Additional cleanup:
- Removed unused functions for feeds
GunChleoc (gunchleoc) wrote : | # |
How about calling the deleted user "Anonymous"?
GunChleoc (gunchleoc) : | # |
kaputtnik (franku) wrote : | # |
Thanks for your suggestions, all changed :)
> How about calling the deleted user "Anonymous"?
Not sure... reading "Anonymous" as a username may lead into the conclusion that anonymous writing is possible. My first idea for such a username was "Deleted_User" or "User_deleted" but i found it too long. Ideally it should be some name which describes the action and that makes clear that a user did it by himself (and not a forum moderator or admin -> censor alarm). "Self_removed" or so...
Regarding my comment on 2018-09-15: I wasn't able to find a solution to prevent writing PMs to such a user. It is a flaw of django-messages, so i filed a bugreport to the project -> https:/
So from my side this can go in if we have agreed on a username to show for deleted users (plural ;) ). But we can change it also anytime later on.
kaputtnik (franku) : | # |
GunChleoc (gunchleoc) wrote : | # |
How about "Former Member(s)"?
Or "Ancestor(s)"? Would fit with the tribes terminology theme
I agree, don't waste too much energy into trying to write a Javascript.
kaputtnik (franku) wrote : | # |
"Ancestor" = "Vorfahre" oder "Ahn"? I think that wouldn't fit.
The name has to follow the Username rules, so no space.
Ex-Member?
We could choose "anonymized" insted of "Anonymous".
One question about the online gaming password: I have removed the string "WARNING: The online gaming password is transmitted in cleartext. Do not use your website password!" AFAIK it is not transmitted in cleartext anymore? Just to be sure.
GunChleoc (gunchleoc) wrote : | # |
Let's go with Ex-Member, that's good enough for me.
I think removing the warning is fine - the warning is shown in Build 19, and will become obsolete in Build 20. So, warning people in-game should suffice.
kaputtnik (franku) wrote : | # |
Merged and deployed, sorry for the server errors... had forgotten to run the migrate command :-D
Preview Diff
1 | === modified file 'django_messages_wl/views.py' | |||
2 | --- django_messages_wl/views.py 2018-04-18 12:04:12 +0000 | |||
3 | +++ django_messages_wl/views.py 2018-09-19 18:09:08 +0000 | |||
4 | @@ -15,7 +15,7 @@ | |||
5 | 15 | if request.is_ajax(): | 15 | if request.is_ajax(): |
6 | 16 | q = request.GET.get('term', '') | 16 | q = request.GET.get('term', '') |
7 | 17 | 17 | ||
9 | 18 | usernames = User.objects.filter(username__icontains=q) | 18 | usernames = User.objects.exclude(is_active=False).filter(username__icontains=q) |
10 | 19 | results = [] | 19 | results = [] |
11 | 20 | for user in usernames: | 20 | for user in usernames: |
12 | 21 | name_json = {'value': user.username} | 21 | name_json = {'value': user.username} |
13 | 22 | 22 | ||
14 | === modified file 'media/css/comments.css' | |||
15 | --- media/css/comments.css 2012-05-04 19:07:35 +0000 | |||
16 | +++ media/css/comments.css 2018-09-19 18:09:08 +0000 | |||
17 | @@ -17,6 +17,7 @@ | |||
18 | 17 | text-align: center; | 17 | text-align: center; |
19 | 18 | border-right: 1px solid #998; | 18 | border-right: 1px solid #998; |
20 | 19 | height: 100%; | 19 | height: 100%; |
21 | 20 | min-width: 54px; | ||
22 | 20 | } | 21 | } |
23 | 21 | 22 | ||
24 | 22 | .comment .text { | 23 | .comment .text { |
25 | 23 | 24 | ||
26 | === modified file 'news/feeds.py' | |||
27 | --- news/feeds.py 2018-04-08 14:40:17 +0000 | |||
28 | +++ news/feeds.py 2018-09-19 18:09:08 +0000 | |||
29 | @@ -21,25 +21,3 @@ | |||
30 | 21 | 21 | ||
31 | 22 | def item_pubdate(self, item): | 22 | def item_pubdate(self, item): |
32 | 23 | return item.publish | 23 | return item.publish |
33 | 24 | |||
34 | 25 | # Currently not used / not checked for compatibility for django 1.8 | ||
35 | 26 | |||
36 | 27 | |||
37 | 28 | class NewsPostsByCategory(Feed): | ||
38 | 29 | title = 'Widelands.org posts category feed' | ||
39 | 30 | |||
40 | 31 | def get_object(self, bits): | ||
41 | 32 | if len(bits) != 1: | ||
42 | 33 | raise ObjectDoesNotExist | ||
43 | 34 | return Category.objects.get(slug__exact=bits[0]) | ||
44 | 35 | |||
45 | 36 | def link(self, item): | ||
46 | 37 | if not item: | ||
47 | 38 | raise FeedDoesNotExist | ||
48 | 39 | return item.get_absolute_url() | ||
49 | 40 | |||
50 | 41 | def description(self, item): | ||
51 | 42 | return 'Posts recently categorized as %s' % item.title | ||
52 | 43 | |||
53 | 44 | def items(self, item): | ||
54 | 45 | return item.post_set.published()[:10] | ||
55 | 46 | 24 | ||
56 | === modified file 'news/urls.py' | |||
57 | --- news/urls.py 2016-12-13 18:28:51 +0000 | |||
58 | +++ news/urls.py 2018-09-19 18:09:08 +0000 | |||
59 | @@ -1,25 +1,25 @@ | |||
60 | 1 | from django.conf.urls import * | 1 | from django.conf.urls import * |
61 | 2 | from django.views.generic import ListView | 2 | from django.views.generic import ListView |
62 | 3 | from news.views import NewsList, YearNews, MonthNews, NewsDetail, CategoryView | 3 | from news.views import NewsList, YearNews, MonthNews, NewsDetail, CategoryView |
63 | 4 | from news.feeds import NewsPostsFeed | ||
64 | 5 | |||
65 | 4 | 6 | ||
66 | 5 | urlpatterns = [ | 7 | urlpatterns = [ |
67 | 6 | url(r'^(?P<year>[0-9]{4})/(?P<month>[-\w]+)/(?P<day>[0-9]+)/(?P<slug>[-\w]+)/$', | 8 | url(r'^(?P<year>[0-9]{4})/(?P<month>[-\w]+)/(?P<day>[0-9]+)/(?P<slug>[-\w]+)/$', |
68 | 7 | NewsDetail.as_view(), | 9 | NewsDetail.as_view(), |
69 | 8 | name='news_detail'), | 10 | name='news_detail'), |
70 | 9 | |||
71 | 10 | url(r'^(?P<year>\d{4})/(?P<month>[-\w]+)/$', | 11 | url(r'^(?P<year>\d{4})/(?P<month>[-\w]+)/$', |
72 | 11 | MonthNews.as_view(), | 12 | MonthNews.as_view(), |
73 | 12 | name='news_archive_month'), | 13 | name='news_archive_month'), |
74 | 13 | |||
75 | 14 | url(r'^(?P<year>\d{4})/$', | 14 | url(r'^(?P<year>\d{4})/$', |
76 | 15 | YearNews.as_view(), | 15 | YearNews.as_view(), |
77 | 16 | name='news_archive_year'), | 16 | name='news_archive_year'), |
78 | 17 | |||
79 | 18 | url(r'^category/(?P<slug>[-\w]+)/', | 17 | url(r'^category/(?P<slug>[-\w]+)/', |
80 | 19 | CategoryView.as_view(), | 18 | CategoryView.as_view(), |
81 | 20 | name='category_posts'), | 19 | name='category_posts'), |
82 | 21 | |||
83 | 22 | url(r'^$', | 20 | url(r'^$', |
84 | 23 | NewsList.as_view(template_name='news/post_list.html'), | 21 | NewsList.as_view(template_name='news/post_list.html'), |
85 | 24 | name='news_index'), | 22 | name='news_index'), |
86 | 23 | # Feed | ||
87 | 24 | url(r'^feed/$', NewsPostsFeed()) | ||
88 | 25 | ] | 25 | ] |
89 | 26 | 26 | ||
90 | === modified file 'pybb/feeds.py' | |||
91 | --- pybb/feeds.py 2018-04-08 14:40:17 +0000 | |||
92 | +++ pybb/feeds.py 2018-09-19 18:09:08 +0000 | |||
93 | @@ -3,6 +3,7 @@ | |||
94 | 3 | from django.core.exceptions import ObjectDoesNotExist | 3 | from django.core.exceptions import ObjectDoesNotExist |
95 | 4 | from django.utils.feedgenerator import Atom1Feed | 4 | from django.utils.feedgenerator import Atom1Feed |
96 | 5 | from pybb.models import Post, Topic, Forum | 5 | from pybb.models import Post, Topic, Forum |
97 | 6 | from django.conf import settings | ||
98 | 6 | 7 | ||
99 | 7 | 8 | ||
100 | 8 | class PybbFeed(Feed): | 9 | class PybbFeed(Feed): |
101 | @@ -60,11 +61,6 @@ | |||
102 | 60 | def items_for_object(self, obj): | 61 | def items_for_object(self, obj): |
103 | 61 | return Post.objects.filter(hidden=False, topic__forum=obj).order_by('-created')[:15] | 62 | return Post.objects.filter(hidden=False, topic__forum=obj).order_by('-created')[:15] |
104 | 62 | 63 | ||
105 | 63 | def item_author_name(self, item): | ||
106 | 64 | """Takes the object returned by get_object and returns the feeds's | ||
107 | 65 | auhor's name as a Python string.""" | ||
108 | 66 | return item.user.username | ||
109 | 67 | |||
110 | 68 | # Validated through http://validator.w3.org/feed/ | 64 | # Validated through http://validator.w3.org/feed/ |
111 | 69 | 65 | ||
112 | 70 | 66 | ||
113 | @@ -78,8 +74,3 @@ | |||
114 | 78 | 74 | ||
115 | 79 | def items_for_object(self, item): | 75 | def items_for_object(self, item): |
116 | 80 | return Topic.objects.exclude(posts__hidden=True).filter(forum=item).order_by('-created')[:15] | 76 | return Topic.objects.exclude(posts__hidden=True).filter(forum=item).order_by('-created')[:15] |
117 | 81 | |||
118 | 82 | def item_author_name(self, item): | ||
119 | 83 | """Takes the object returned by get_object and returns the feeds's | ||
120 | 84 | auhor's name as a Python string.""" | ||
121 | 85 | return item.user.username | ||
122 | 86 | 77 | ||
123 | === modified file 'settings.py' | |||
124 | --- settings.py 2018-09-04 18:17:07 +0000 | |||
125 | +++ settings.py 2018-09-19 18:09:08 +0000 | |||
126 | @@ -142,6 +142,7 @@ | |||
127 | 142 | 'django.template.context_processors.static', | 142 | 'django.template.context_processors.static', |
128 | 143 | 'django.template.context_processors.tz', | 143 | 'django.template.context_processors.tz', |
129 | 144 | 'django_messages.context_processors.inbox', | 144 | 'django_messages.context_processors.inbox', |
130 | 145 | 'wlprofile.context_processors.deleted_user_data', | ||
131 | 145 | ], | 146 | ], |
132 | 146 | }, | 147 | }, |
133 | 147 | }, | 148 | }, |
134 | @@ -322,6 +323,13 @@ | |||
135 | 322 | # Number of stored users | 323 | # Number of stored users |
136 | 323 | ONLINE_MAX = 25 | 324 | ONLINE_MAX = 25 |
137 | 324 | 325 | ||
138 | 326 | ########################################### | ||
139 | 327 | # Settings for users who deleted themself # | ||
140 | 328 | ########################################### | ||
141 | 329 | |||
142 | 330 | DELETED_MAIL_ADDRESS = '' | ||
143 | 331 | DELETED_USERNAME = 'Ex-Member' | ||
144 | 332 | |||
145 | 325 | try: | 333 | try: |
146 | 326 | from local_settings import * | 334 | from local_settings import * |
147 | 327 | except ImportError: | 335 | except ImportError: |
148 | 328 | 336 | ||
149 | === modified file 'templates/django_messages/view.html' | |||
150 | --- templates/django_messages/view.html 2016-03-02 21:02:38 +0000 | |||
151 | +++ templates/django_messages/view.html 2018-09-19 18:09:08 +0000 | |||
152 | @@ -30,8 +30,9 @@ | |||
153 | 30 | </td> | 30 | </td> |
154 | 31 | </tr> | 31 | </tr> |
155 | 32 | </table> | 32 | </table> |
157 | 33 | {% ifequal message.recipient user %} | 33 | {% if message.recipient == user and not message.sender.wlprofile.deleted %} |
158 | 34 | {{ context.deleted_email_address }} | ||
159 | 34 | <button type="button" onclick="location.href='{% url 'messages_reply' message.id %}';">{% trans "Reply" %}</button> | 35 | <button type="button" onclick="location.href='{% url 'messages_reply' message.id %}';">{% trans "Reply" %}</button> |
161 | 35 | {% endifequal %} | 36 | {% endif %} |
162 | 36 | <button type="button" onclick="location.href='{% url 'messages_delete' message.id %}';">{% trans "Delete" %}</button> | 37 | <button type="button" onclick="location.href='{% url 'messages_delete' message.id %}';">{% trans "Delete" %}</button> |
163 | 37 | {% endblock %} | 38 | {% endblock %} |
164 | 38 | 39 | ||
165 | === modified file 'templates/mainpage.html' | |||
166 | --- templates/mainpage.html 2016-03-02 21:02:38 +0000 | |||
167 | +++ templates/mainpage.html 2018-09-19 18:09:08 +0000 | |||
168 | @@ -12,7 +12,7 @@ | |||
169 | 12 | {% block extra_head %} | 12 | {% block extra_head %} |
170 | 13 | <meta name="google-site-verification" content="1A5uFV_zNuXazJ46-572-_lLzcCTEQ77iHaSPFZd53Y" /> | 13 | <meta name="google-site-verification" content="1A5uFV_zNuXazJ46-572-_lLzcCTEQ77iHaSPFZd53Y" /> |
171 | 14 | <link rel="stylesheet" type="text/css" media="all" href="{{ MEDIA_URL }}css/news.css" /> | 14 | <link rel="stylesheet" type="text/css" media="all" href="{{ MEDIA_URL }}css/news.css" /> |
173 | 15 | <link rel="alternate" type="application/rss+xml" title="Widelands News" href="/feeds/news/" /> | 15 | <link rel="alternate" type="application/rss+xml" title="Widelands News" href="news/feed/" /> |
174 | 16 | 16 | ||
175 | 17 | {{ block.super}}{% endblock %} | 17 | {{ block.super}}{% endblock %} |
176 | 18 | {% block content %} | 18 | {% block content %} |
177 | 19 | 19 | ||
178 | === modified file 'templates/pybb/feeds/posts_description.html' | |||
179 | --- templates/pybb/feeds/posts_description.html 2014-12-01 06:32:12 +0000 | |||
180 | +++ templates/pybb/feeds/posts_description.html 2018-09-19 18:09:08 +0000 | |||
181 | @@ -1,2 +1,6 @@ | |||
183 | 1 | {{ obj.user }}:<br> | 1 | {% if obj.user.wlprofile.deleted %} |
184 | 2 | {{ DELETED_USERNAME }} | ||
185 | 3 | {% else %} | ||
186 | 4 | {{ obj.user }} | ||
187 | 5 | {% endif %}wrote:<br> | ||
188 | 2 | {{ obj.body_html|safe }} | 6 | {{ obj.body_html|safe }} |
189 | 3 | 7 | ||
190 | === modified file 'templates/pybb/feeds/topics_description.html' | |||
191 | --- templates/pybb/feeds/topics_description.html 2014-12-01 06:32:12 +0000 | |||
192 | +++ templates/pybb/feeds/topics_description.html 2018-09-19 18:09:08 +0000 | |||
193 | @@ -1,2 +1,6 @@ | |||
195 | 1 | {{ obj.head.user }}:<br> | 1 | {% if obj.head.user.wlprofile.deleted %} |
196 | 2 | {{ DELETED_USERNAME }} | ||
197 | 3 | {% else %} | ||
198 | 4 | {{ obj.head.user }} | ||
199 | 5 | {% endif %}wrote:<br> | ||
200 | 2 | {{ obj.head.body_html|safe }} | 6 | {{ obj.head.body_html|safe }} |
201 | 3 | 7 | ||
202 | === modified file 'templates/pybb/last_posts.html' | |||
203 | --- templates/pybb/last_posts.html 2016-10-10 19:32:14 +0000 | |||
204 | +++ templates/pybb/last_posts.html 2018-09-19 18:09:08 +0000 | |||
205 | @@ -12,7 +12,7 @@ | |||
206 | 12 | <li> | 12 | <li> |
207 | 13 | {{ post.topic.forum.name }}<br /> | 13 | {{ post.topic.forum.name }}<br /> |
208 | 14 | <a href="{{ post.get_absolute_url }}" title="{{ post.topic.name }}">{{ post.topic.name|pybb_cut_string:30 }}</a><br /> | 14 | <a href="{{ post.get_absolute_url }}" title="{{ post.topic.name }}">{{ post.topic.name|pybb_cut_string:30 }}</a><br /> |
210 | 15 | by <a href="{% url 'profile_view' post.user %}">{{post.user.username}}</a> {{ post.created|minutes }} ago | 15 | by {{ post.user|user_link }} {{ post.created|minutes }} ago |
211 | 16 | </li> | 16 | </li> |
212 | 17 | {% endfor %} | 17 | {% endfor %} |
213 | 18 | </ul> | 18 | </ul> |
214 | 19 | 19 | ||
215 | === modified file 'templates/threadedcomments/inlines/comments.html' | |||
216 | --- templates/threadedcomments/inlines/comments.html 2016-05-15 14:41:54 +0000 | |||
217 | +++ templates/threadedcomments/inlines/comments.html 2018-09-19 18:09:08 +0000 | |||
218 | @@ -16,7 +16,7 @@ | |||
219 | 16 | <td class="author" rowspan="2"> | 16 | <td class="author" rowspan="2"> |
220 | 17 | {% if comment.user.wlprofile.avatar %} | 17 | {% if comment.user.wlprofile.avatar %} |
221 | 18 | <a href="{% url 'profile_view' comment.user %}"> | 18 | <a href="{% url 'profile_view' comment.user %}"> |
223 | 19 | <img style="width: 50px; height: 50px;" src="{{ comment.user.wlprofile.avatar.url }}" /> | 19 | <img src="{{ comment.user.wlprofile.avatar.url }}" /> |
224 | 20 | </a> | 20 | </a> |
225 | 21 | <br /> | 21 | <br /> |
226 | 22 | {% endif %} | 22 | {% endif %} |
227 | 23 | 23 | ||
228 | === modified file 'templates/wiki/feeds/history_description.html' | |||
229 | --- templates/wiki/feeds/history_description.html 2017-12-11 08:42:55 +0000 | |||
230 | +++ templates/wiki/feeds/history_description.html 2018-09-19 18:09:08 +0000 | |||
231 | @@ -1,4 +1,9 @@ | |||
232 | 1 | {% load i18n %} | 1 | {% load i18n %} |
233 | 2 | 2 | ||
235 | 3 | {% trans "edited by user" %} {{ obj.editor.username }} {% trans "at"%} {{ obj.modified }}<br> | 3 | {% trans "Edited by user" %} {% if obj.editor.wlprofile.deleted %} |
236 | 4 | {{ DELETED_USERNAME }} | ||
237 | 5 | {% else %} | ||
238 | 6 | {{ obj.editor.username }} | ||
239 | 7 | {% endif %} | ||
240 | 8 | {% trans "at"%} {{ obj.modified }}<br> | ||
241 | 4 | {{ obj.comment }} | 9 | {{ obj.comment }} |
242 | 5 | 10 | ||
243 | === modified file 'templates/wiki/recentchanges.html' | |||
244 | --- templates/wiki/recentchanges.html 2017-08-16 21:13:43 +0000 | |||
245 | +++ templates/wiki/recentchanges.html 2018-09-19 18:09:08 +0000 | |||
246 | @@ -3,6 +3,7 @@ | |||
247 | 3 | {% load humanize i18n %} | 3 | {% load humanize i18n %} |
248 | 4 | {% load pagination_tags %} | 4 | {% load pagination_tags %} |
249 | 5 | {% load custom_date %} | 5 | {% load custom_date %} |
250 | 6 | {% load wlprofile_extras %} | ||
251 | 6 | 7 | ||
252 | 7 | {% block title %} | 8 | {% block title %} |
253 | 8 | {% trans "Recent Changes" %} - {{ block.super }} | 9 | {% trans "Recent Changes" %} - {{ block.super }} |
254 | @@ -42,7 +43,7 @@ | |||
255 | 42 | <a href="{% url 'wiki_article' change.article.title %}">{{ change.article.title }}</a> | 43 | <a href="{% url 'wiki_article' change.article.title %}">{{ change.article.title }}</a> |
256 | 43 | </td> | 44 | </td> |
257 | 44 | <td>{{ change.modified|custom_date:user }}</td> | 45 | <td>{{ change.modified|custom_date:user }}</td> |
259 | 45 | <td>{{ change.editor }}</td> | 46 | <td>{{ change.editor|user_link }}</td> |
260 | 46 | <td>{{ change.comment }}</td> | 47 | <td>{{ change.comment }}</td> |
261 | 47 | </tr> | 48 | </tr> |
262 | 48 | {% endfor %} | 49 | {% endfor %} |
263 | 49 | 50 | ||
264 | === added file 'templates/wlprofile/delete_me.html' | |||
265 | --- templates/wlprofile/delete_me.html 1970-01-01 00:00:00 +0000 | |||
266 | +++ templates/wlprofile/delete_me.html 2018-09-19 18:09:08 +0000 | |||
267 | @@ -0,0 +1,42 @@ | |||
268 | 1 | {% extends "wlprofile/base.html" %} | ||
269 | 2 | |||
270 | 3 | {% load i18n %} | ||
271 | 4 | {% load wlprofile_extras %} | ||
272 | 5 | |||
273 | 6 | {% block title %} | ||
274 | 7 | {% trans "Delete me" %} - {{ block.super }} | ||
275 | 8 | {% endblock %} | ||
276 | 9 | |||
277 | 10 | {% block content %} | ||
278 | 11 | <h1>{% trans "Delete your account" %}</h1> | ||
279 | 12 | |||
280 | 13 | <div class="blogEntry"> | ||
281 | 14 | <h3>Hi {{ user }},</h3> | ||
282 | 15 | <p>we are sorry that you want to leave our community <img src="/wlmedia/img/smileys/face-sad.png" alt="Sad smiley"></p> | ||
283 | 16 | <h3>What deleting yourself means:</h3> | ||
284 | 17 | <ul> | ||
285 | 18 | <li>Your account will be deactivated. This means: | ||
286 | 19 | <ul> | ||
287 | 20 | <li>You will be immediately logged out and unable to log in again.</li> | ||
288 | 21 | <li>The Username "{{ user }}" will continue to be reserved, so registering again with that username will not be possible.</li> | ||
289 | 22 | </ul> | ||
290 | 23 | </li> | ||
291 | 24 | <li>Your <a href="{% url 'profile_edit' %}">profile</a> will be deleted and your currently used avatar image will be deleted.</li> | ||
292 | 25 | <li> | ||
293 | 26 | All your <a href="{% url 'messages_inbox' %}">private messages</a> will be moved into the <a href="{% url 'messages_trash' %}">trash</a>. | ||
294 | 27 | They will stay there until such time that the sender or recipient will also delete them.</li> | ||
295 | 28 | <li>All your <a href="{% url 'notification_notices' %}">subscriptions</a> will be removed.</li> | ||
296 | 29 | <li>Your email address will be removed, so you will not receive any notification mails anymore.</li> | ||
297 | 30 | <li> | ||
298 | 31 | <b>Nothing</b> that you have posted (forum posts, comments and uploaded maps) will be deleted. | ||
299 | 32 | Instead of your user name, the string "{{ DELETED_USERNAME }}" will be shown.</li> | ||
300 | 33 | <li>Your online gaming password will be reset.</li> | ||
301 | 34 | <li>All dates given in the <a href="{% url 'scheduling_scheduling' %}">Playtime scheduler</a> will be deleted</li> | ||
302 | 35 | </ul> | ||
303 | 36 | <p class="errormessage"><b>This step can't be undone!</b></p> | ||
304 | 37 | <p> | ||
305 | 38 | <button type="button" onclick="location.href='{% url 'do_delete' %}';" style="font-weight: normal;">I am sure, please delete me</button> | ||
306 | 39 | <button type="button" onclick="location.href='{% url 'profile_edit' %}';">Cancel</button> | ||
307 | 40 | </p> | ||
308 | 41 | </div> | ||
309 | 42 | {% endblock %} | ||
310 | 0 | 43 | ||
311 | === modified file 'templates/wlprofile/edit_profile.html' | |||
312 | --- templates/wlprofile/edit_profile.html 2016-06-26 09:04:15 +0000 | |||
313 | +++ templates/wlprofile/edit_profile.html 2018-09-19 18:09:08 +0000 | |||
314 | @@ -41,17 +41,12 @@ | |||
315 | 41 | <input type="submit" value="{% trans "Save" %}" /> | 41 | <input type="submit" value="{% trans "Save" %}" /> |
316 | 42 | {% csrf_token %} | 42 | {% csrf_token %} |
317 | 43 | </form> | 43 | </form> |
330 | 44 | <br /> | 44 | |
331 | 45 | <br /> | 45 | <h2>Other options:</h2> |
332 | 46 | <p> | 46 | <ul> |
333 | 47 | <a href="{% url 'auth_password_change' %}">Change website password</a> | 47 | <li><a href="{% url 'auth_password_change' %}">Change website password</a></li> |
334 | 48 | <br /> | 48 | <li><a href="{% url 'wlggz_changepw' %}">Change online gaming password</a></li> |
335 | 49 | You will be redirected to an encrypted connection. The website password is <strong>not</strong> transmitted in cleartext. | 49 | <li><a href="{% url 'delete_me' %}">Delete me</a></li> |
336 | 50 | </p> | 50 | </ul> |
325 | 51 | <p> | ||
326 | 52 | <a href="{% url 'wlggz_changepw' %}">Change online gaming password</a> | ||
327 | 53 | <br /> | ||
328 | 54 | <strong class="errormessage">WARNING: The online gaming password is transmitted in cleartext. Do not use your website password!</strong> | ||
329 | 55 | </p> | ||
337 | 56 | </div> | 51 | </div> |
338 | 57 | {% endblock %} | 52 | {% endblock %} |
339 | 58 | 53 | ||
340 | === modified file 'templates/wlprofile/view_profile.html' | |||
341 | --- templates/wlprofile/view_profile.html 2017-07-27 06:01:32 +0000 | |||
342 | +++ templates/wlprofile/view_profile.html 2018-09-19 18:09:08 +0000 | |||
343 | @@ -4,7 +4,13 @@ | |||
344 | 4 | {% load custom_date %} | 4 | {% load custom_date %} |
345 | 5 | 5 | ||
346 | 6 | {% block title %} | 6 | {% block title %} |
348 | 7 | {{ profile.user.username }}'s Profile - {{ block.super }} | 7 | {% if not profile.deleted %} |
349 | 8 | {{ profile.user.username }}'s | ||
350 | 9 | {% else %} | ||
351 | 10 | Deleted Users Profile | ||
352 | 11 | {% endif %} | ||
353 | 12 | - Profile | ||
354 | 13 | {{ block.super }} | ||
355 | 8 | {% endblock %} | 14 | {% endblock %} |
356 | 9 | 15 | ||
357 | 10 | {% block content %} | 16 | {% block content %} |
358 | @@ -13,66 +19,76 @@ | |||
359 | 13 | <a class="invertedColor" href="{% url 'profile_edit' %}">Edit Profile</a> | 19 | <a class="invertedColor" href="{% url 'profile_edit' %}">Edit Profile</a> |
360 | 14 | {% endifequal %} | 20 | {% endifequal %} |
361 | 15 | </div> | 21 | </div> |
363 | 16 | <h1>{{ profile.user.username }}'s Profile</h1> | 22 | <h1>{% if not profile.deleted %} |
364 | 23 | {{ profile.user.username }}'s | ||
365 | 24 | {% else %} | ||
366 | 25 | Deleted User | ||
367 | 26 | {% endif %} | ||
368 | 27 | Profile | ||
369 | 28 | </h1> | ||
370 | 17 | 29 | ||
371 | 18 | <div class="blogEntry"> | 30 | <div class="blogEntry"> |
429 | 19 | <table> | 31 | {% if not profile.deleted %} |
430 | 20 | <tr> | 32 | <table> |
431 | 21 | <td> | 33 | <tr> |
432 | 22 | {% if profile.avatar %} | 34 | <td> |
433 | 23 | <img src="{{ profile.avatar.url }}" alt="Avatar" /> | 35 | {% if profile.avatar %} |
434 | 24 | {% endif %} | 36 | <img src="{{ profile.avatar.url }}" alt="Avatar" /> |
435 | 25 | </td> | 37 | {% endif %} |
436 | 26 | <td> | 38 | </td> |
437 | 27 | {% ifnotequal user profile.user %} | 39 | <td> |
438 | 28 | <button onclick="window.location.href='{% url 'messages_compose_to' profile.user %}';"> | 40 | {% ifnotequal user profile.user %} |
439 | 29 | <img src="{{ MEDIA_URL }}forum/img/send_pm.png" alt ="" class="middle" /> | 41 | <button onclick="window.location.href='{% url 'messages_compose_to' profile.user %}';"> |
440 | 30 | <span class="middle">{% trans "Send PM" %}</span> | 42 | <img src="{{ MEDIA_URL }}forum/img/send_pm.png" alt ="" class="middle" /> |
441 | 31 | </button> | 43 | <span class="middle">{% trans "Send PM" %}</span> |
442 | 32 | {% endifnotequal %} | 44 | </button> |
443 | 33 | </td> | 45 | {% endifnotequal %} |
444 | 34 | </tr> | 46 | </td> |
445 | 35 | <tr> | 47 | </tr> |
446 | 36 | <td class="grey">Joined:</td> | 48 | <tr> |
447 | 37 | <td>{{ profile.user.date_joined|custom_date:user|title }}</td> | 49 | <td class="grey">Joined:</td> |
448 | 38 | </tr> | 50 | <td>{{ profile.user.date_joined|custom_date:user|title }}</td> |
449 | 39 | <tr> | 51 | </tr> |
450 | 40 | <td class="grey">Forum Posts:</td> | 52 | <tr> |
451 | 41 | <td>{{ profile.post_count }}</td> | 53 | <td class="grey">Forum Posts:</td> |
452 | 42 | </tr> | 54 | <td>{{ profile.post_count }}</td> |
453 | 43 | <tr> | 55 | </tr> |
454 | 44 | <td class="grey">Website:</td> | 56 | <tr> |
455 | 45 | <td><a href="{{profile.site}}">{{ profile.site }}</a></td> | 57 | <td class="grey">Website:</td> |
456 | 46 | </tr> | 58 | <td><a href="{{profile.site}}">{{ profile.site }}</a></td> |
457 | 47 | <tr> | 59 | </tr> |
458 | 48 | <td class="grey">Location:</td> | 60 | <tr> |
459 | 49 | <td>{{ profile.location }}</td> | 61 | <td class="grey">Location:</td> |
460 | 50 | </tr> | 62 | <td>{{ profile.location }}</td> |
461 | 51 | <tr> | 63 | </tr> |
462 | 52 | <td class="grey">Jabber:</td> | 64 | <tr> |
463 | 53 | <td>{{ profile.jabber }}</td> | 65 | <td class="grey">Jabber:</td> |
464 | 54 | </tr> | 66 | <td>{{ profile.jabber }}</td> |
465 | 55 | <tr> | 67 | </tr> |
466 | 56 | <td class="grey">ICQ:</td> | 68 | <tr> |
467 | 57 | <td>{{ profile.icq }}</td> | 69 | <td class="grey">ICQ:</td> |
468 | 58 | </tr> | 70 | <td>{{ profile.icq }}</td> |
469 | 59 | <tr> | 71 | </tr> |
470 | 60 | <td class="grey">MSN:</td> | 72 | <tr> |
471 | 61 | <td>{{ profile.msn }}</td> | 73 | <td class="grey">MSN:</td> |
472 | 62 | </tr> | 74 | <td>{{ profile.msn }}</td> |
473 | 63 | <tr> | 75 | </tr> |
474 | 64 | <td class="grey">AIM:</td> | 76 | <tr> |
475 | 65 | <td>{{ profile.aim }}</td> | 77 | <td class="grey">AIM:</td> |
476 | 66 | </tr> | 78 | <td>{{ profile.aim }}</td> |
477 | 67 | <tr> | 79 | </tr> |
478 | 68 | <td class="grey">Yahoo:</td> | 80 | <tr> |
479 | 69 | <td>{{ profile.yahoo }}</td> | 81 | <td class="grey">Yahoo:</td> |
480 | 70 | </tr> | 82 | <td>{{ profile.yahoo }}</td> |
481 | 71 | <tr> | 83 | </tr> |
482 | 72 | <td class="grey">Signature:</td> | 84 | <tr> |
483 | 73 | <td>{{ profile.signature|urlize|linebreaks }}</td> | 85 | <td class="grey">Signature:</td> |
484 | 74 | </tr> | 86 | <td>{{ profile.signature|urlize|linebreaks }}</td> |
485 | 75 | </table> | 87 | </tr> |
486 | 88 | </table> | ||
487 | 89 | {% else %} | ||
488 | 90 | <p>This user has deleted his data ...</p> | ||
489 | 91 | {% endif %} | ||
490 | 76 | </div> | 92 | </div> |
491 | 77 | 93 | ||
492 | 78 | {% endblock %} | 94 | {% endblock %} |
493 | 79 | 95 | ||
494 | === modified file 'urls.py' | |||
495 | --- urls.py 2018-05-24 19:17:36 +0000 | |||
496 | +++ urls.py 2018-09-19 18:09:08 +0000 | |||
497 | @@ -4,7 +4,6 @@ | |||
498 | 4 | from django.contrib import admin | 4 | from django.contrib import admin |
499 | 5 | admin.autodiscover() | 5 | admin.autodiscover() |
500 | 6 | 6 | ||
501 | 7 | from news.feeds import NewsPostsFeed | ||
502 | 8 | from django.views.generic.base import RedirectView | 7 | from django.views.generic.base import RedirectView |
503 | 9 | from django.views.generic import TemplateView | 8 | from django.views.generic import TemplateView |
504 | 10 | from django.contrib.syndication.views import Feed | 9 | from django.contrib.syndication.views import Feed |
505 | @@ -28,9 +27,6 @@ | |||
506 | 28 | url(r'^accounts/', include('registration.backends.hmac.urls')), | 27 | url(r'^accounts/', include('registration.backends.hmac.urls')), |
507 | 29 | url('^', include('django.contrib.auth.urls')), | 28 | url('^', include('django.contrib.auth.urls')), |
508 | 30 | 29 | ||
509 | 31 | # Feed for news | ||
510 | 32 | url(r'^feeds/news/$', NewsPostsFeed()), | ||
511 | 33 | |||
512 | 34 | # Formerly 3rd party | 30 | # Formerly 3rd party |
513 | 35 | url(r'^notification/', include('notification.urls')), | 31 | url(r'^notification/', include('notification.urls')), |
514 | 36 | 32 | ||
515 | 37 | 33 | ||
516 | === modified file 'wiki/feeds.py' | |||
517 | --- wiki/feeds.py 2016-12-13 18:28:51 +0000 | |||
518 | +++ wiki/feeds.py 2018-09-19 18:09:08 +0000 | |||
519 | @@ -19,19 +19,12 @@ | |||
520 | 19 | 19 | ||
521 | 20 | def item_pubdate(self, item): | 20 | def item_pubdate(self, item): |
522 | 21 | """Return the item's pubdate. | 21 | """Return the item's pubdate. |
524 | 22 | 22 | ||
525 | 23 | It's this modified date | 23 | It's this modified date |
527 | 24 | 24 | ||
528 | 25 | """ | 25 | """ |
529 | 26 | return item.modified | 26 | return item.modified |
530 | 27 | 27 | ||
531 | 28 | def item_author_name(self, item): | ||
532 | 29 | """Takes the object returned by items(), and returns the feeds's | ||
533 | 30 | auhor's name as a Python string.""" | ||
534 | 31 | if item.is_anonymous_change(): | ||
535 | 32 | return 'Anonymous' | ||
536 | 33 | return item.editor.username | ||
537 | 34 | |||
538 | 35 | # Validated through http://validator.w3.org/feed/ | 28 | # Validated through http://validator.w3.org/feed/ |
539 | 36 | 29 | ||
540 | 37 | 30 | ||
541 | @@ -84,10 +77,3 @@ | |||
542 | 84 | 77 | ||
543 | 85 | def item_updateddate(self, item): | 78 | def item_updateddate(self, item): |
544 | 86 | return item.modified | 79 | return item.modified |
545 | 87 | |||
546 | 88 | def item_author_name(self, item): | ||
547 | 89 | """Takes the object returned by items(), and returns the feeds's | ||
548 | 90 | auhor's name as a Python string.""" | ||
549 | 91 | if item.is_anonymous_change(): | ||
550 | 92 | return 'Anonymous' | ||
551 | 93 | return item.editor.username | ||
552 | 94 | 80 | ||
553 | === added file 'wlprofile/context_processors.py' | |||
554 | --- wlprofile/context_processors.py 1970-01-01 00:00:00 +0000 | |||
555 | +++ wlprofile/context_processors.py 2018-09-19 18:09:08 +0000 | |||
556 | @@ -0,0 +1,6 @@ | |||
557 | 1 | from django.conf import settings | ||
558 | 2 | |||
559 | 3 | |||
560 | 4 | def deleted_user_data(request): | ||
561 | 5 | context = {'DELETED_USERNAME': settings.DELETED_USERNAME} | ||
562 | 6 | return context | ||
563 | 0 | 7 | ||
564 | === added file 'wlprofile/migrations/0002_profile_deleted.py' | |||
565 | --- wlprofile/migrations/0002_profile_deleted.py 1970-01-01 00:00:00 +0000 | |||
566 | +++ wlprofile/migrations/0002_profile_deleted.py 2018-09-19 18:09:08 +0000 | |||
567 | @@ -0,0 +1,20 @@ | |||
568 | 1 | # -*- coding: utf-8 -*- | ||
569 | 2 | # Generated by Django 1.11.12 on 2018-09-13 21:23 | ||
570 | 3 | from __future__ import unicode_literals | ||
571 | 4 | |||
572 | 5 | from django.db import migrations, models | ||
573 | 6 | |||
574 | 7 | |||
575 | 8 | class Migration(migrations.Migration): | ||
576 | 9 | |||
577 | 10 | dependencies = [ | ||
578 | 11 | ('wlprofile', '0001_initial'), | ||
579 | 12 | ] | ||
580 | 13 | |||
581 | 14 | operations = [ | ||
582 | 15 | migrations.AddField( | ||
583 | 16 | model_name='profile', | ||
584 | 17 | name='deleted', | ||
585 | 18 | field=models.BooleanField(default=False), | ||
586 | 19 | ), | ||
587 | 20 | ] | ||
588 | 0 | 21 | ||
589 | === modified file 'wlprofile/models.py' | |||
590 | --- wlprofile/models.py 2016-12-13 18:28:51 +0000 | |||
591 | +++ wlprofile/models.py 2018-09-19 18:09:08 +0000 | |||
592 | @@ -48,6 +48,7 @@ | |||
593 | 48 | upload_to='wlprofile/avatars/', width=settings.AVATAR_WIDTH, height=settings.AVATAR_HEIGHT) | 48 | upload_to='wlprofile/avatars/', width=settings.AVATAR_WIDTH, height=settings.AVATAR_HEIGHT) |
594 | 49 | show_signatures = models.BooleanField( | 49 | show_signatures = models.BooleanField( |
595 | 50 | _('Show signatures'), blank=True, default=True) | 50 | _('Show signatures'), blank=True, default=True) |
596 | 51 | deleted = models.BooleanField(default=False) | ||
597 | 51 | 52 | ||
598 | 52 | class Meta: | 53 | class Meta: |
599 | 53 | verbose_name = _('Profile') | 54 | verbose_name = _('Profile') |
600 | 54 | 55 | ||
601 | === modified file 'wlprofile/templatetags/wlprofile_extras.py' | |||
602 | --- wlprofile/templatetags/wlprofile_extras.py 2018-04-08 14:40:17 +0000 | |||
603 | +++ wlprofile/templatetags/wlprofile_extras.py 2018-09-19 18:09:08 +0000 | |||
604 | @@ -12,12 +12,19 @@ | |||
605 | 12 | from django import template | 12 | from django import template |
606 | 13 | from django.urls import reverse | 13 | from django.urls import reverse |
607 | 14 | from django.utils.safestring import mark_safe | 14 | from django.utils.safestring import mark_safe |
608 | 15 | from django.contrib.auth.models import User | ||
609 | 16 | from django.conf import settings | ||
610 | 15 | 17 | ||
611 | 16 | register = template.Library() | 18 | register = template.Library() |
612 | 17 | 19 | ||
613 | 18 | 20 | ||
614 | 19 | @register.filter | 21 | @register.filter |
615 | 20 | def user_link(user): | 22 | def user_link(user): |
618 | 21 | data = u'<a href="%s">%s</a>' % ( | 23 | |
619 | 22 | reverse('profile_view', args=[user.username]), user.username) | 24 | if user.is_authenticated and user.wlprofile.deleted: |
620 | 25 | # Check for is_authenticated is needed for threadedcomments reply_to.js | ||
621 | 26 | return mark_safe('<span title="This user has left our community">{}</span>'.format(settings.DELETED_USERNAME)) | ||
622 | 27 | else: | ||
623 | 28 | data = u'<a href="%s">%s</a>' % ( | ||
624 | 29 | reverse('profile_view', args=[user.username]), user.username) | ||
625 | 23 | return mark_safe(data) | 30 | return mark_safe(data) |
626 | 24 | 31 | ||
627 | === modified file 'wlprofile/urls.py' | |||
628 | --- wlprofile/urls.py 2016-12-13 18:28:51 +0000 | |||
629 | +++ wlprofile/urls.py 2018-09-19 18:09:08 +0000 | |||
630 | @@ -14,6 +14,8 @@ | |||
631 | 14 | 14 | ||
632 | 15 | urlpatterns = [ | 15 | urlpatterns = [ |
633 | 16 | url(r'^edit/$', views.edit, name='profile_edit'), | 16 | url(r'^edit/$', views.edit, name='profile_edit'), |
634 | 17 | url(r'^delete/$', views.delete_me, name='delete_me'), | ||
635 | 18 | url(r'^do_delete/$', views.do_delete, name='do_delete'), | ||
636 | 17 | url(r'^(?P<user>.*)/$', views.view, name='profile_view'), | 19 | url(r'^(?P<user>.*)/$', views.view, name='profile_view'), |
637 | 18 | url(r'^$', views.view, name='profile_view'), | 20 | url(r'^$', views.view, name='profile_view'), |
638 | 19 | ] | 21 | ] |
639 | 20 | 22 | ||
640 | === modified file 'wlprofile/views.py' | |||
641 | --- wlprofile/views.py 2018-05-30 16:59:16 +0000 | |||
642 | +++ wlprofile/views.py 2018-09-19 18:09:08 +0000 | |||
643 | @@ -4,14 +4,102 @@ | |||
644 | 4 | from django.urls import reverse | 4 | from django.urls import reverse |
645 | 5 | from django.contrib.auth.decorators import login_required | 5 | from django.contrib.auth.decorators import login_required |
646 | 6 | from django.contrib.auth.models import User | 6 | from django.contrib.auth.models import User |
648 | 7 | from django.shortcuts import render | 7 | from django.shortcuts import render, redirect |
649 | 8 | from django.http import HttpResponseRedirect | 8 | from django.http import HttpResponseRedirect |
650 | 9 | from django.shortcuts import get_object_or_404 | 9 | from django.shortcuts import get_object_or_404 |
651 | 10 | from django.conf import settings | ||
652 | 10 | 11 | ||
653 | 11 | from forms import EditProfileForm | 12 | from forms import EditProfileForm |
657 | 12 | import settings | 13 | |
658 | 13 | 14 | ||
659 | 14 | # Settings | 15 | @login_required |
660 | 16 | def delete_me(request): | ||
661 | 17 | """Show a page to inform the user what deleting means.""" | ||
662 | 18 | |||
663 | 19 | context = { | ||
664 | 20 | 'user': request.user | ||
665 | 21 | } | ||
666 | 22 | return render(request, 'wlprofile/delete_me.html', | ||
667 | 23 | context) | ||
668 | 24 | |||
669 | 25 | |||
670 | 26 | @login_required | ||
671 | 27 | def do_delete(request): | ||
672 | 28 | """Delete user specific data. | ||
673 | 29 | |||
674 | 30 | We can't really delete a user who has posted some valid posts (no spam) because otherwise | ||
675 | 31 | we have foreign keys constraints in the database. All we can do is to do some cleanup and | ||
676 | 32 | anonymization. | ||
677 | 33 | """ | ||
678 | 34 | |||
679 | 35 | from django.contrib.auth import logout | ||
680 | 36 | from wlprofile.models import Profile | ||
681 | 37 | from notification.models import NoticeSetting | ||
682 | 38 | |||
683 | 39 | user = get_object_or_404(User, username=request.user) | ||
684 | 40 | |||
685 | 41 | # Log the user out. We do this as early as possible but after | ||
686 | 42 | # we get the User object. | ||
687 | 43 | logout(request) | ||
688 | 44 | |||
689 | 45 | # Clean possible Playtime availabilities | ||
690 | 46 | from wlscheduling.models import Availabilities | ||
691 | 47 | try: | ||
692 | 48 | events = Availabilities.objects.filter(user=user) | ||
693 | 49 | for event in events: | ||
694 | 50 | event.delete() | ||
695 | 51 | except: | ||
696 | 52 | pass | ||
697 | 53 | |||
698 | 54 | # Clean the Online gaming password | ||
699 | 55 | from wlggz.models import GGZAuth | ||
700 | 56 | try: | ||
701 | 57 | ggz_user = GGZAuth.objects.get(user=user) | ||
702 | 58 | ggz_user.delete() | ||
703 | 59 | except: | ||
704 | 60 | pass | ||
705 | 61 | |||
706 | 62 | # Clean the profile | ||
707 | 63 | profile = user.wlprofile | ||
708 | 64 | upload_to = Profile._meta.get_field('avatar').upload_to | ||
709 | 65 | |||
710 | 66 | if upload_to in profile.avatar.name: | ||
711 | 67 | # Delete the avatar file | ||
712 | 68 | profile.avatar.delete() | ||
713 | 69 | |||
714 | 70 | # Delete the profile and recreate it to get a clean profile page | ||
715 | 71 | # We create a new one to have the anymous.png as avatar | ||
716 | 72 | profile.delete() | ||
717 | 73 | profile = Profile(user=user, deleted=True) | ||
718 | 74 | profile.save() | ||
719 | 75 | |||
720 | 76 | # Deactivate all subscriptions | ||
721 | 77 | notice_settings = NoticeSetting.objects.filter(user=user) | ||
722 | 78 | for setting in notice_settings: | ||
723 | 79 | setting.send = False | ||
724 | 80 | setting.save() | ||
725 | 81 | |||
726 | 82 | # Put all PMs in the trash of the user. They stay as long in the trash until the sender or recipient | ||
727 | 83 | # has also put the message in the trash. | ||
728 | 84 | from django_messages.models import Message | ||
729 | 85 | from datetime import datetime | ||
730 | 86 | messages = Message.objects.inbox_for(user) | ||
731 | 87 | for message in messages: | ||
732 | 88 | message.recipient_deleted_at = datetime.now() | ||
733 | 89 | message.save() | ||
734 | 90 | messages = Message.objects.outbox_for(user) | ||
735 | 91 | for message in messages: | ||
736 | 92 | message.sender_deleted_at = datetime.now() | ||
737 | 93 | message.save() | ||
738 | 94 | |||
739 | 95 | # Do some settings in django.auth.User | ||
740 | 96 | user.is_active = False | ||
741 | 97 | user.is_staff = False | ||
742 | 98 | user.is_superuser = False | ||
743 | 99 | user.email = settings.DELETED_MAIL_ADDRESS | ||
744 | 100 | user.save() | ||
745 | 101 | |||
746 | 102 | return redirect('mainpage') | ||
747 | 15 | 103 | ||
748 | 16 | 104 | ||
749 | 17 | @login_required | 105 | @login_required |
Just found that it is still possible to write a PM to a deleted user, if the recipient is written by hand in the recipient field. When the DELETED_ USER_MAILADDRES S is empty an email isn't sent, but there is no error message shown to the user.