17 """Views for the User's own profiles. |
17 """Views for the User's own profiles. |
18 """ |
18 """ |
19 |
19 |
20 __authors__ = [ |
20 __authors__ = [ |
21 '"Sverre Rabbelier" <sverre@rabbelier.nl>', |
21 '"Sverre Rabbelier" <sverre@rabbelier.nl>', |
|
22 '"Lennard de Rijk" <ljvderijk@gmail.com>', |
22 '"Pawel Solyga" <pawel.solyga@gmail.com>', |
23 '"Pawel Solyga" <pawel.solyga@gmail.com>', |
23 ] |
24 ] |
24 |
25 |
25 |
26 |
26 from google.appengine.api import users |
27 from google.appengine.api import users |
27 |
28 |
28 from django import forms |
|
29 from django import http |
29 from django import http |
30 from django.utils.encoding import force_unicode |
30 from django.utils.encoding import force_unicode |
31 from django.utils.safestring import mark_safe |
31 from django.utils.safestring import mark_safe |
32 from django.utils.translation import ugettext |
32 from django.utils.translation import ugettext |
33 |
33 |
|
34 from soc.logic import cleaning |
34 from soc.logic import dicts |
35 from soc.logic import dicts |
35 from soc.logic import validate |
|
36 from soc.logic import models as model_logic |
36 from soc.logic import models as model_logic |
37 from soc.logic.models.site import logic as site_logic |
|
38 from soc.logic.models.user import logic as user_logic |
37 from soc.logic.models.user import logic as user_logic |
39 from soc.views import helper |
38 from soc.views import helper |
40 from soc.views import out_of_band |
|
41 from soc.views.helper import access |
39 from soc.views.helper import access |
42 from soc.views.helper import decorators |
40 from soc.views.helper import decorators |
|
41 from soc.views.helper import widgets |
43 from soc.views.models import base |
42 from soc.views.models import base |
|
43 from soc.views.models import user as user_view |
44 |
44 |
45 import soc.models.linkable |
|
46 import soc.models.user |
45 import soc.models.user |
47 import soc.views.helper |
|
48 |
|
49 |
|
50 class UserForm(helper.forms.BaseForm): |
|
51 """Django form displayed when creating or editing a User. |
|
52 """ |
|
53 class Meta: |
|
54 """Inner Meta class that defines some behavior for the form. |
|
55 """ |
|
56 #: db.Model subclass for which the form will gather information |
|
57 model = soc.models.user.User |
|
58 |
|
59 #: list of model fields which will *not* be gathered by the form |
|
60 exclude = ['account', 'former_accounts', 'is_developer'] |
|
61 |
|
62 def clean_link_id(self): |
|
63 link_id = self.cleaned_data.get('link_id').lower() |
|
64 if not validate.isLinkIdFormatValid(link_id): |
|
65 raise forms.ValidationError("This link ID is in wrong format.") |
|
66 |
|
67 user = user_logic.getForFields({'link_id': link_id}, unique=True) |
|
68 |
|
69 # Get the currently logged in user account |
|
70 current_account = users.get_current_user() |
|
71 |
|
72 if user: |
|
73 if current_account != user.account: |
|
74 raise forms.ValidationError("This link ID is already in use.") |
|
75 |
|
76 return link_id |
|
77 |
|
78 def clean_agrees_to_tos(self): |
|
79 agrees_to_tos = self.cleaned_data.get('agrees_to_tos') |
|
80 |
|
81 if not site_logic.getToS(site_logic.getSingleton()): |
|
82 return agrees_to_tos |
|
83 |
|
84 # Site settings specify a site-wide ToS, so agreement is *required* |
|
85 if agrees_to_tos: |
|
86 return True |
|
87 |
|
88 raise forms.ValidationError( |
|
89 'The site-wide Terms of Service must be accepted to participate' |
|
90 ' on this site.') |
|
91 |
46 |
92 |
47 |
93 class View(base.View): |
48 class View(base.View): |
94 """View methods for the User model. |
49 """Views for User own profiles. |
95 """ |
50 """ |
96 |
|
97 DEF_USER_ACCOUNT_INVALID_MSG_FMT = ugettext( |
|
98 'The <b><i>%(email)s</i></b> account cannot be used with this site, for' |
|
99 ' one or more of the following reasons:' |
|
100 '<ul>' |
|
101 ' <li>the account is invalid</li>' |
|
102 ' <li>the account is already attached to a User profile and cannot be' |
|
103 ' used to create another one</li>' |
|
104 ' <li>the account is a former account that cannot be used again</li>' |
|
105 '</ul>') |
|
106 |
51 |
107 def __init__(self, params=None): |
52 def __init__(self, params=None): |
108 """Defines the fields and methods required for the base View class |
53 """Defines the fields and methods required for the base View class |
109 to provide the user with list, public, create, edit and delete views. |
54 to provide the user with list, public, create, edit and delete views. |
110 |
55 |
126 |
72 |
127 new_params['name'] = "User" |
73 new_params['name'] = "User" |
128 new_params['module_name'] = "user_self" |
74 new_params['module_name'] = "user_self" |
129 new_params['url_name'] = "user" |
75 new_params['url_name'] = "user" |
130 |
76 |
131 new_params['edit_template'] = 'soc/user/edit_self.html' |
77 new_params['create_template'] = 'soc/user/edit_profile.html' |
|
78 new_params['edit_template'] = 'soc/user/edit_profile.html' |
|
79 new_params['save_message'] = [ugettext('Profile saved.')] |
|
80 new_params['edit_redirect'] = '/%(url_name)s/edit_profile' |
|
81 |
|
82 # set the specific fields for the users profile page |
|
83 new_params['extra_dynaexclude'] = ['former_accounts', |
|
84 'account', 'is_developer'] |
|
85 new_params['create_extra_dynafields'] = { |
|
86 'clean_agrees_to_tos' : cleaning.clean_agrees_to_tos('agrees_to_tos'), |
|
87 'clean_link_id': cleaning.clean_user_not_exist('link_id'),} |
|
88 |
|
89 new_params['edit_extra_dynafields'] = { |
|
90 'clean_link_id': cleaning.clean_link_id |
|
91 } |
132 |
92 |
133 new_params['sidebar_heading'] = 'User (self)' |
93 new_params['sidebar_heading'] = 'User (self)' |
134 new_params['sidebar'] = [ |
94 new_params['sidebar'] = [ |
135 (users.create_login_url("/user/edit"), 'Sign In', 'signIn'), |
95 (users.create_login_url("/"), 'Sign In', 'signIn'), |
136 ('/' + new_params['url_name'] + '/edit', 'Profile', 'edit'), |
96 ('/' + new_params['url_name'] + '/create_profile', 'Create Profile', 'create_profile'), |
|
97 ('/' + new_params['url_name'] + '/edit_profile', 'Edit Profile', 'edit_profile'), |
137 ('/' + new_params['url_name'] + '/roles', 'Roles', 'roles'), |
98 ('/' + new_params['url_name'] + '/roles', 'Roles', 'roles'), |
138 ] |
99 ] |
139 |
100 |
140 patterns = [] |
101 patterns = [] |
141 |
102 |
142 page_name = "Profile" |
103 page_name = ugettext("Create your profile") |
143 patterns += [(r'^%(url_name)s/(?P<access_type>edit)$', |
104 patterns += [(r'^%(url_name)s/(?P<access_type>create_profile)$', |
|
105 'soc.views.models.%(module_name)s.create', page_name)] |
|
106 |
|
107 page_name = ugettext("Edit your profile") |
|
108 patterns += [(r'^%(url_name)s/(?P<access_type>edit_profile)$', |
144 'soc.views.models.%(module_name)s.edit', page_name)] |
109 'soc.views.models.%(module_name)s.edit', page_name)] |
145 |
110 |
146 page_name = "Requests Overview" |
111 page_name = ugettext("List of your roles") |
147 patterns += [(r'^%(url_name)s/(?P<access_type>roles)$', |
112 patterns += [(r'^%(url_name)s/(?P<access_type>roles)$', |
148 'soc.views.models.request.list_self', page_name)] |
113 'soc.views.models.request.list_self', page_name)] |
149 |
114 |
150 new_params['django_patterns_defaults'] = patterns |
115 new_params['django_patterns_defaults'] = patterns |
151 |
116 |
152 params = dicts.merge(params, new_params) |
117 params = dicts.merge(params, new_params) |
153 |
118 |
154 super(View, self).__init__(params=params) |
119 super(View, self).__init__(params=params) |
155 |
120 |
|
121 |
156 @decorators.merge_params |
122 @decorators.merge_params |
157 @decorators.check_access |
123 @decorators.check_access |
158 def edit(self, request, access_type, |
124 def editProfile(self, request, access_type, |
159 page_name=None, params=None, seed=None, **kwargs): |
125 page_name=None, params=None, seed=None, **kwargs): |
160 """Displays User self edit page for the entity specified by **kwargs. |
126 """Displays User profile edit page for the current user. |
161 |
127 |
162 Args: |
128 Args: |
163 request: the standard Django HTTP request object |
129 request: the standard Django HTTP request object |
164 page_name: the page name displayed in templates as page and header title |
130 page_name: the page name displayed in templates as page and header title |
165 params: a dict with params for this View |
131 params: a dict with params for this View |
166 kwargs: The Key Fields for the specified entity |
132 kwargs: The Key Fields for the specified entity |
167 """ |
133 """ |
168 |
134 |
169 account = users.get_current_user() |
135 # set the link_id to the current user's link_id |
170 properties = {'account': account} |
136 user_entity = user_logic.getForCurrentAccount() |
|
137 link_id = user_entity.link_id |
171 |
138 |
172 user = user_logic.getForFields(properties, unique=True) |
139 return self.edit(request, access_type, |
|
140 page_name=page_name, params=params, seed=seed, link_id=link_id, **kwargs) |
173 |
141 |
174 # create default template context for use with any templates |
|
175 context = helper.responses.getUniversalContext(request) |
|
176 |
142 |
177 if request.method == 'POST': |
|
178 form = UserForm(request.POST) |
|
179 |
|
180 if form.is_valid(): |
|
181 new_link_id = form.cleaned_data.get('link_id') |
|
182 properties = { |
|
183 'link_id': new_link_id, |
|
184 'name': form.cleaned_data.get('name'), |
|
185 'account': account, |
|
186 'agrees_to_tos': form.cleaned_data.get('agrees_to_tos'), |
|
187 } |
|
188 |
|
189 # check if user account is not in former_accounts |
|
190 # if it is show error message that account is invalid |
|
191 if user_logic.isFormerAccount(account): |
|
192 msg = self.DEF_USER_ACCOUNT_INVALID_MSG_FMT % { |
|
193 'email': account.email()} |
|
194 error = out_of_band.Error(msg) |
|
195 return helper.responses.errorResponse( |
|
196 error, request, template=params['edit_template'], context=context) |
|
197 |
|
198 user = user_logic.updateOrCreateFromFields( |
|
199 properties, {'link_id': new_link_id}) |
|
200 |
|
201 # redirect to /user/profile?s=0 |
|
202 # (causes 'Profile saved' message to be displayed) |
|
203 return helper.responses.redirectToChangedSuffix( |
|
204 request, None, params=params['edit_params']) |
|
205 else: # request.method == 'GET' |
|
206 if user: |
|
207 # is 'Profile saved' parameter present, but referrer was not ourself? |
|
208 # (e.g. someone bookmarked the GET that followed the POST submit) |
|
209 if (request.GET.get(params['submit_msg_param_name']) |
|
210 and (not helper.requests.isReferrerSelf(request))): |
|
211 # redirect to aggressively remove 'Profile saved' query parameter |
|
212 return http.HttpResponseRedirect(request.path) |
|
213 |
|
214 # referrer was us, so select which submit message to display |
|
215 # (may display no message if ?s=0 parameter is not present) |
|
216 context['notice'] = ( |
|
217 helper.requests.getSingleIndexedParamValue( |
|
218 request, params['submit_msg_param_name'], |
|
219 values=params['save_message'])) |
|
220 |
|
221 # populate form with the existing User entity |
|
222 form = UserForm(instance=user) |
|
223 else: |
|
224 if request.GET.get(params['submit_msg_param_name']): |
|
225 # redirect to aggressively remove 'Profile saved' query parameter |
|
226 return http.HttpResponseRedirect(request.path) |
|
227 |
|
228 # no User entity exists for this Google Account, so show a blank form |
|
229 form = UserForm() |
|
230 |
|
231 context['form'] = form |
|
232 |
|
233 template = params['edit_template'] |
|
234 |
|
235 return helper.responses.respond(request, template, context) |
|
236 |
|
237 def _editGet(self, request, entity, form): |
143 def _editGet(self, request, entity, form): |
238 """See base.View._editGet(). |
144 """See base.View._editGet(). |
239 """ |
145 """ |
240 |
146 |
241 # fill in the email field with the data from the entity |
147 # set the ToS example text |
242 form.fields['email'].initial = entity.account.email() |
148 form.fields['agrees_to_tos'].example_text = user_view.view.getToSExampleText() |
|
149 form.fields['link_id'].initial = entity.link_id |
243 |
150 |
244 super(View, self)._editGet(request, entity, form) |
151 super(View, self)._editGet(request, entity, form) |
245 |
152 |
246 def _editPost(self, request, entity, fields): |
153 def _editPost(self, request, entity, fields): |
247 """See base.View._editPost(). |
154 """See base.View._editPost(). |
248 """ |
155 """ |
249 |
156 |
250 # fill in the account field with the user created from email |
157 # fill in the account field with the current User |
251 fields['account'] = users.User(fields['email']) |
158 fields['account'] = users.User() |
252 |
159 |
253 super(View, self)._editPost(request, entity, fields) |
160 super(View, self)._editPost(request, entity, fields) |
|
161 |
254 |
162 |
255 def getSidebarMenus(self, id, user, params=None): |
163 def getSidebarMenus(self, id, user, params=None): |
256 """See base.View.getSidebarMenus(). |
164 """See base.View.getSidebarMenus(). |
257 """ |
165 """ |
258 |
166 |