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 """Developer views for editing and examining Sponsor 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 |
|
30 from soc.logic import models |
|
31 from soc.logic import out_of_band |
|
32 from soc.logic import validate |
|
33 from soc.logic.models import sponsor |
|
34 from soc.views import helper |
|
35 from soc.views import simple |
|
36 from soc.views.helper import access |
|
37 from soc.views.helper import decorators |
|
38 from soc.views.user import profile |
|
39 |
|
40 import soc.logic |
|
41 import soc.models.sponsor as sponsor_model |
|
42 import soc.views.helper.forms |
|
43 import soc.views.helper.requests |
|
44 import soc.views.helper.responses |
|
45 import soc.views.helper.widgets |
|
46 import soc.views.out_of_band |
|
47 |
|
48 |
|
49 class CreateForm(helper.forms.BaseForm): |
|
50 """Django form displayed when creating a Sponsor. |
|
51 """ |
|
52 class Meta: |
|
53 """Inner Meta class that defines some behavior for the form. |
|
54 """ |
|
55 #: db.Model subclass for which the form will gather information |
|
56 model = sponsor_model.Sponsor |
|
57 |
|
58 #: list of model fields which will *not* be gathered by the form |
|
59 exclude = ['founder', 'inheritance_line'] |
|
60 |
|
61 # TODO(pawel.solyga): write validation functions for other fields |
|
62 def clean_link_id(self): |
|
63 link_id = self.cleaned_data.get('link_id') |
|
64 if not validate.isLinkIdFormatValid(link_id): |
|
65 raise forms.ValidationError("This link ID is in wrong format.") |
|
66 if models.sponsor.logic.getFromFields(link_id=link_id): |
|
67 raise forms.ValidationError("This link ID is already in use.") |
|
68 return link_id |
|
69 |
|
70 |
|
71 class EditForm(CreateForm): |
|
72 """Django form displayed when editing a Sponsor. |
|
73 """ |
|
74 link_id = forms.CharField(widget=helper.widgets.ReadOnlyInput()) |
|
75 founded_by = forms.CharField(widget=helper.widgets.ReadOnlyInput(), |
|
76 required=False) |
|
77 |
|
78 def clean_link_id(self): |
|
79 link_id = self.cleaned_data.get('link_id') |
|
80 if not validate.isLinkIdFormatValid(link_id): |
|
81 raise forms.ValidationError("This link ID is in wrong format.") |
|
82 return link_id |
|
83 |
|
84 |
|
85 DEF_SITE_SPONSOR_PROFILE_EDIT_TMPL = 'soc/site/sponsor/profile/edit.html' |
|
86 DEF_SPONSOR_NO_LINK_ID_CHANGE_MSG = 'Sponsor link ID cannot be changed.' |
|
87 DEF_CREATE_NEW_SPONSOR_MSG = ' You can create a new sponsor by visiting' \ |
|
88 ' <a href="/site/sponsor/profile">Create ' \ |
|
89 'a New Sponsor</a> page.' |
|
90 |
|
91 @decorators.view |
|
92 def edit(request, page_name=None, link_id=None, |
|
93 template=DEF_SITE_SPONSOR_PROFILE_EDIT_TMPL): |
|
94 """View for a Developer to modify the properties of a Sponsor 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 Sponsor's site-unique "link_id" extracted from the URL |
|
100 template: the "sibling" template (or a search list of such templates) |
|
101 from which to construct the public.html template name (or names) |
|
102 |
|
103 Returns: |
|
104 A subclass of django.http.HttpResponse which either contains the form to |
|
105 be filled out, or a redirect to the correct view in the interface. |
|
106 """ |
|
107 |
|
108 try: |
|
109 access.checkIsDeveloper(request) |
|
110 except soc.views.out_of_band.AccessViolationResponse, alt_response: |
|
111 return alt_response.response() |
|
112 |
|
113 # create default template context for use with any templates |
|
114 context = helper.responses.getUniversalContext(request) |
|
115 context['page_name'] = page_name |
|
116 |
|
117 user = models.user.logic.getForFields( |
|
118 {'account': users.get_current_user()}, unique=True) |
|
119 sponsor_form = None |
|
120 existing_sponsor = None |
|
121 |
|
122 # try to fetch Sponsor entity corresponding to link_id if one exists |
|
123 try: |
|
124 existing_sponsor = sponsor.logic.getIfFields(link_id=link_id) |
|
125 except out_of_band.ErrorResponse, error: |
|
126 # show custom 404 page when link ID doesn't exist in Datastore |
|
127 error.message = error.message + DEF_CREATE_NEW_SPONSOR_MSG |
|
128 return simple.errorResponse(request, page_name, error, template, context) |
|
129 |
|
130 if request.method == 'POST': |
|
131 if existing_sponsor: |
|
132 sponsor_form = EditForm(request.POST) |
|
133 else: |
|
134 sponsor_form = CreateForm(request.POST) |
|
135 |
|
136 if sponsor_form.is_valid(): |
|
137 if link_id: |
|
138 # Form doesn't allow to change link_id but somebody might want to |
|
139 # abuse that manually, so we check if form link_id is the same as |
|
140 # url link_id |
|
141 if sponsor_form.cleaned_data.get('link_id') != link_id: |
|
142 msg = DEF_SPONSOR_NO_LINK_ID_CHANGE_MSG |
|
143 error = out_of_band.ErrorResponse(msg) |
|
144 return simple.errorResponse(request, page_name, error, template, context) |
|
145 |
|
146 fields = {} |
|
147 |
|
148 # Ask for all the fields and pull them out |
|
149 for field in sponsor_form.cleaned_data: |
|
150 value = sponsor_form.cleaned_data.get(field) |
|
151 fields[field] = value |
|
152 |
|
153 if not existing_sponsor: |
|
154 fields['founder'] = user |
|
155 |
|
156 form_ln = fields['link_id'] |
|
157 key_fields = models.sponsor.logic.getKeyFieldsFromKwargs(fields) |
|
158 form_sponsor = models.sponsor.logic.updateOrCreateFromFields( |
|
159 fields, key_fields) |
|
160 |
|
161 if not form_sponsor: |
|
162 return http.HttpResponseRedirect('/') |
|
163 |
|
164 # redirect to new /site/sponsor/profile/form_link_id?s=0 |
|
165 # (causes 'Profile saved' message to be displayed) |
|
166 return helper.responses.redirectToChangedSuffix( |
|
167 request, None, form_ln, |
|
168 params=profile.SUBMIT_PROFILE_SAVED_PARAMS) |
|
169 |
|
170 else: # request.method == 'GET' |
|
171 if existing_sponsor: |
|
172 # is 'Profile saved' parameter present, but referrer was not ourself? |
|
173 # (e.g. someone bookmarked the GET that followed the POST submit) |
|
174 if (request.GET.get(profile.SUBMIT_MSG_PARAM_NAME) |
|
175 and (not helper.requests.isReferrerSelf(request, 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, profile.SUBMIT_MSG_PARAM_NAME, |
|
184 values=profile.SUBMIT_MESSAGES)) |
|
185 |
|
186 # populate form with the existing Sponsor entity |
|
187 founder_link_id = existing_sponsor.founder.link_id |
|
188 sponsor_form = EditForm(instance=existing_sponsor, |
|
189 initial={'founded_by': founder_link_id}) |
|
190 else: |
|
191 if request.GET.get(profile.SUBMIT_MSG_PARAM_NAME): |
|
192 # redirect to aggressively remove 'Profile saved' query parameter |
|
193 return http.HttpResponseRedirect(request.path) |
|
194 |
|
195 # no Sponsor entity exists for this link ID, so show a blank form |
|
196 sponsor_form = CreateForm() |
|
197 |
|
198 context.update({'form': sponsor_form, |
|
199 'entity': existing_sponsor, |
|
200 'entity_type': sponsor_model.Sponsor.TYPE_NAME, |
|
201 'entity_type_short': sponsor_model.Sponsor.TYPE_NAME_SHORT}) |
|
202 |
|
203 return helper.responses.respond(request, template, context) |
|
204 |
|
205 |
|
206 DEF_SITE_SPONSOR_PROFILE_CREATE_TMPL = 'soc/group/profile/edit.html' |
|
207 |
|
208 @decorators.view |
|
209 def create(request, page_name=None, template=DEF_SITE_SPONSOR_PROFILE_CREATE_TMPL): |
|
210 """create() view is same as edit() view, but with no link_id supplied. |
|
211 """ |
|
212 return edit(request, page_name=page_name, link_id=None, template=template) |
|
213 |
|
214 |
|
215 @decorators.view |
|
216 def delete(request, page_name=None, link_id=None, |
|
217 template=DEF_SITE_SPONSOR_PROFILE_EDIT_TMPL): |
|
218 """Request handler for a Developer to delete Sponsor Model entity. |
|
219 |
|
220 Args: |
|
221 request: the standard django request object |
|
222 page_name: the page name displayed in templates as page and header title |
|
223 link_id: the Sponsor's site-unique "link_id" extracted from the URL |
|
224 template: the "sibling" template (or a search list of such templates) |
|
225 from which to construct the public.html template name (or names) |
|
226 |
|
227 Returns: |
|
228 A subclass of django.http.HttpResponse which redirects |
|
229 to /site/sponsor/list. |
|
230 """ |
|
231 |
|
232 try: |
|
233 access.checkIsDeveloper(request) |
|
234 except soc.views.out_of_band.AccessViolationResponse, alt_response: |
|
235 return alt_response.response() |
|
236 |
|
237 # create default template context for use with any templates |
|
238 context = helper.responses.getUniversalContext(request) |
|
239 context['page_name'] = page_name |
|
240 |
|
241 existing_sponsor = None |
|
242 |
|
243 # try to fetch Sponsor entity corresponding to link_id if one exists |
|
244 try: |
|
245 existing_sponsor = models.sponsor.logic.getIfFields(link_id=link_id) |
|
246 except out_of_band.ErrorResponse, error: |
|
247 # show custom 404 page when link ID doesn't exist in Datastore |
|
248 error.message = error.message + DEF_CREATE_NEW_SPONSOR_MSG |
|
249 return simple.errorResponse(request, page_name, error, template, context) |
|
250 |
|
251 if existing_sponsor: |
|
252 # TODO(pawel.solyga): Create specific delete method for Sponsor model |
|
253 # Check if Sponsor can be deleted (has no Hosts and Programs) |
|
254 models.sponsor.logic.delete(existing_sponsor) |
|
255 |
|
256 return http.HttpResponseRedirect('/site/sponsor/list') |
|