1 #!/usr/bin/python2.5 |
|
2 # |
|
3 # Copyright 2008 the Melange authors. |
|
4 # |
|
5 # Licensed under the Apache License, Version 2.0 (the "License"); |
|
6 # you may not use this file except in compliance with the License. |
|
7 # You may obtain a copy of the License at |
|
8 # |
|
9 # http://www.apache.org/licenses/LICENSE-2.0 |
|
10 # |
|
11 # Unless required by applicable law or agreed to in writing, software |
|
12 # distributed under the License is distributed on an "AS IS" BASIS, |
|
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
14 # See the License for the specific language governing permissions and |
|
15 # limitations under the License. |
|
16 |
|
17 """Views for editing and examining User profiles. |
|
18 """ |
|
19 |
|
20 __authors__ = [ |
|
21 '"Pawel Solyga" <pawel.solyga@gmail.com>', |
|
22 ] |
|
23 |
|
24 |
|
25 from google.appengine.api import users |
|
26 |
|
27 from django import forms |
|
28 from django import http |
|
29 from django.utils.translation import ugettext_lazy |
|
30 |
|
31 from soc.logic import accounts |
|
32 from soc.logic import models |
|
33 from soc.logic import out_of_band |
|
34 from soc.logic import validate |
|
35 from soc.views import helper |
|
36 from soc.views import simple |
|
37 from soc.views.helper import decorators |
|
38 |
|
39 import soc.logic |
|
40 import soc.models.user |
|
41 import soc.views.helper.forms |
|
42 import soc.views.helper.requests |
|
43 import soc.views.helper.responses |
|
44 |
|
45 |
|
46 class UserForm(helper.forms.BaseForm): |
|
47 """Django form displayed when creating or editing a User. |
|
48 """ |
|
49 class Meta: |
|
50 """Inner Meta class that defines some behavior for the form. |
|
51 """ |
|
52 #: db.Model subclass for which the form will gather information |
|
53 model = soc.models.user.User |
|
54 |
|
55 #: list of model fields which will *not* be gathered by the form |
|
56 exclude = ['account', 'former_accounts', 'is_developer'] |
|
57 |
|
58 def clean_link_id(self): |
|
59 link_id = self.cleaned_data.get('link_id') |
|
60 if not validate.isLinkIdFormatValid(link_id): |
|
61 raise forms.ValidationError("This link ID is in wrong format.") |
|
62 |
|
63 user = models.user.logic.getForFields({'link_id': link_id}, |
|
64 unique=True) |
|
65 |
|
66 # Get the currently logged in user account |
|
67 current_account = users.get_current_user() |
|
68 |
|
69 if user: |
|
70 if current_account != user.account: |
|
71 raise forms.ValidationError("This link ID is already in use.") |
|
72 |
|
73 return link_id |
|
74 |
|
75 |
|
76 DEF_USER_PROFILE_EDIT_TMPL = 'soc/user/edit_self.html' |
|
77 DEF_USER_ACCOUNT_INVALID_MSG = 'This account is invalid.' |
|
78 |
|
79 SUBMIT_MSG_PARAM_NAME = 's' |
|
80 |
|
81 SUBMIT_MESSAGES = ( |
|
82 ugettext_lazy('Profile saved.'), |
|
83 ) |
|
84 |
|
85 SUBMIT_MSG_PROFILE_SAVED = 0 |
|
86 |
|
87 SUBMIT_PROFILE_SAVED_PARAMS = { |
|
88 SUBMIT_MSG_PARAM_NAME: SUBMIT_MSG_PROFILE_SAVED, |
|
89 } |
|
90 |
|
91 @decorators.view |
|
92 def edit(request, page_name=None, link_id=None, |
|
93 template=DEF_USER_PROFILE_EDIT_TMPL): |
|
94 """View for a User to modify the properties of a User Model entity. |
|
95 |
|
96 Args: |
|
97 request: the standard django request object |
|
98 page_name: the page name displayed in templates as page and header title |
|
99 link_id: the User's site-unique "link_id" extracted from the URL |
|
100 template: the template path to use for rendering the template |
|
101 |
|
102 Returns: |
|
103 A subclass of django.http.HttpResponse which either contains the form to |
|
104 be filled out, or a redirect to the correct view in the interface. |
|
105 """ |
|
106 account = users.get_current_user() |
|
107 |
|
108 # create default template context for use with any templates |
|
109 context = helper.responses.getUniversalContext(request) |
|
110 |
|
111 if (not account) and (not link_id): |
|
112 # not logged in, and no link ID, so request that the user sign in |
|
113 return simple.requestLogin(request, page_name, template, context, |
|
114 # TODO(tlarsen): /user/profile could be a link to a help page instead |
|
115 login_message_fmt=ugettext_lazy( |
|
116 'To create a new <a href="/user/profile">User Profile</a>' |
|
117 ' or modify an existing one, you must first' |
|
118 ' <a href="%(sign_in)s">sign in</a>.')) |
|
119 |
|
120 if (not account) and link_id: |
|
121 # not logged in, so show read-only public profile for link_id user |
|
122 return simple.public(request, page_name=page_name, template=template, |
|
123 link_id=link_id, context=context) |
|
124 |
|
125 link_id_user = None |
|
126 |
|
127 # try to fetch User entity corresponding to link_id if one exists |
|
128 try: |
|
129 if link_id: |
|
130 link_id_user = accounts.getUserFromLinkIdOr404(link_id) |
|
131 except out_of_band.ErrorResponse, error: |
|
132 # show custom 404 page when link ID doesn't exist in Datastore |
|
133 return simple.errorResponse(request, page_name, error, template, context) |
|
134 |
|
135 # link_id_user will be None here if link ID was already None... |
|
136 if link_id_user and (link_id_user.account != account): |
|
137 # link_id_user exists but is not the currently logged in Google Account, |
|
138 # so show public view for that (other) User entity |
|
139 return simple.public(request, page_name=page_name, template=template, |
|
140 link_id=link_id, context=context) |
|
141 |
|
142 if request.method == 'POST': |
|
143 form = UserForm(request.POST) |
|
144 |
|
145 if form.is_valid(): |
|
146 new_link_id = form.cleaned_data.get('link_id') |
|
147 properties = { |
|
148 'link_id': new_link_id, |
|
149 'nick_name': form.cleaned_data.get("nick_name"), |
|
150 'account': account, |
|
151 } |
|
152 |
|
153 # check if user account is not in former_accounts |
|
154 # if it is show error message that account is invalid |
|
155 if models.user.logic.isFormerAccount(account): |
|
156 msg = DEF_USER_ACCOUNT_INVALID_MSG |
|
157 error = out_of_band.ErrorResponse(msg) |
|
158 return simple.errorResponse(request, page_name, error, template, context) |
|
159 |
|
160 user = models.user.logic.updateOrCreateFromFields(properties, {'link_id': new_link_id}) |
|
161 |
|
162 # redirect to /user/profile?s=0 |
|
163 # (causes 'Profile saved' message to be displayed) |
|
164 return helper.responses.redirectToChangedSuffix( |
|
165 request, None, params=SUBMIT_PROFILE_SAVED_PARAMS) |
|
166 else: # request.method == 'GET' |
|
167 # try to fetch User entity corresponding to Google Account if one exists |
|
168 user = models.user.logic.getForFields({'account': account}, unique=True) |
|
169 |
|
170 if user: |
|
171 # is 'Profile saved' parameter present, but referrer was not ourself? |
|
172 # (e.g. someone bookmarked the GET that followed the POST submit) |
|
173 if (request.GET.get(SUBMIT_MSG_PARAM_NAME) |
|
174 and (not helper.requests.isReferrerSelf(request, |
|
175 suffix=link_id))): |
|
176 # redirect to aggressively remove 'Profile saved' query parameter |
|
177 return http.HttpResponseRedirect(request.path) |
|
178 |
|
179 # referrer was us, so select which submit message to display |
|
180 # (may display no message if ?s=0 parameter is not present) |
|
181 context['notice'] = ( |
|
182 helper.requests.getSingleIndexedParamValue( |
|
183 request, SUBMIT_MSG_PARAM_NAME, values=SUBMIT_MESSAGES)) |
|
184 |
|
185 # populate form with the existing User entity |
|
186 form = UserForm(instance=user) |
|
187 else: |
|
188 if request.GET.get(SUBMIT_MSG_PARAM_NAME): |
|
189 # redirect to aggressively remove 'Profile saved' query parameter |
|
190 return http.HttpResponseRedirect(request.path) |
|
191 |
|
192 # no User entity exists for this Google Account, so show a blank form |
|
193 form = UserForm() |
|
194 |
|
195 context['form'] = form |
|
196 return helper.responses.respond(request, template, context) |
|
197 |
|
198 |
|
199 @decorators.view |
|
200 def create(request, page_name=None, template=DEF_USER_PROFILE_EDIT_TMPL): |
|
201 """create() view is same as edit() view, but with no link_id supplied. |
|
202 """ |
|
203 return edit(request, page_name=page_name, link_id=None, template=template) |
|