|
1 #!/usr/bin/python2.5 |
|
2 # |
|
3 # Copyright 2009 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 """GHOP specific views for Programs. |
|
18 """ |
|
19 |
|
20 __authors__ = [ |
|
21 '"Madhusudan.C.S" <madhusudancs@gmail.com>', |
|
22 '"Lennard de Rijk" <ljvderijk@gmail.com>', |
|
23 ] |
|
24 |
|
25 |
|
26 import datetime |
|
27 import os |
|
28 |
|
29 from django import forms |
|
30 from django import http |
|
31 from django.utils.translation import ugettext |
|
32 |
|
33 from soc.logic import cleaning |
|
34 from soc.logic import dicts |
|
35 from soc.logic.helper import timeline as timeline_helper |
|
36 from soc.logic.models import host as host_logic |
|
37 from soc.views import out_of_band |
|
38 from soc.views import helper |
|
39 from soc.views.helper import decorators |
|
40 from soc.views.helper import dynaform |
|
41 from soc.views.helper import lists |
|
42 from soc.views.helper import params as params_helper |
|
43 from soc.views.helper import redirects |
|
44 from soc.views.helper import widgets |
|
45 from soc.views.models import document as document_view |
|
46 from soc.views.models import program |
|
47 from soc.views.sitemap import sidebar |
|
48 |
|
49 import soc.cache.logic |
|
50 |
|
51 from soc.modules.ghop.logic.models import mentor as ghop_mentor_logic |
|
52 from soc.modules.ghop.logic.models import org_admin as ghop_org_admin_logic |
|
53 from soc.modules.ghop.logic.models import program as ghop_program_logic |
|
54 from soc.modules.ghop.logic.models import student as ghop_student_logic |
|
55 from soc.modules.ghop.logic.models import task as ghop_task_logic |
|
56 from soc.modules.ghop.models import task as ghop_task_model |
|
57 from soc.modules.ghop.views.helper import access as ghop_access |
|
58 from soc.modules.ghop.views.helper import redirects as ghop_redirects |
|
59 |
|
60 import soc.modules.ghop.logic.models.program |
|
61 |
|
62 |
|
63 class View(program.View): |
|
64 """View methods for the GHOP Program model. |
|
65 """ |
|
66 |
|
67 DEF_PARTICIPATING_ORGS_MSG_FMT = ugettext( |
|
68 'The following is a list of all the participating organizations under ' |
|
69 'the programme %(name)s. To know more about each organization and see ' |
|
70 'the tasks published by them please visit the corresponding links.') |
|
71 |
|
72 DEF_TASK_QUOTA_ALLOCATION_MSG = ugettext( |
|
73 "Use this view to assign task quotas.") |
|
74 |
|
75 DEF_TASK_QUOTA_ERROR_MSG_FMT = ugettext( |
|
76 "Task Quota limit for the organizations %s do not contain" |
|
77 " a valid number(>0) and has not been updated.") |
|
78 |
|
79 def __init__(self, params=None): |
|
80 """Defines the fields and methods required for the program View class |
|
81 to provide the user with list, public, create, edit and delete views. |
|
82 |
|
83 Params: |
|
84 params: a dict with params for this View |
|
85 """ |
|
86 |
|
87 rights = ghop_access.GHOPChecker(params) |
|
88 rights['show'] = ['allow'] |
|
89 rights['create'] = [('checkSeeded', ['checkHasActiveRoleForScope', |
|
90 host_logic.logic])] |
|
91 rights['edit'] = [('checkIsHostForProgram', |
|
92 [ghop_program_logic.logic])] |
|
93 rights['delete'] = ['checkIsDeveloper'] |
|
94 rights['task_difficulty'] = [('checkIsHostForProgram', |
|
95 [ghop_program_logic.logic])] |
|
96 rights['task_type'] = [('checkIsHostForProgram', |
|
97 [ghop_program_logic.logic])] |
|
98 rights['difficulty_tag_edit'] = [('checkIsHostForProgram', |
|
99 [ghop_program_logic.logic])] |
|
100 rights['type_tag_edit'] = [('checkIsHostForProgram', |
|
101 [ghop_program_logic.logic])] |
|
102 |
|
103 new_params = {} |
|
104 new_params['logic'] = soc.modules.ghop.logic.models.program.logic |
|
105 new_params['rights'] = rights |
|
106 |
|
107 new_params['name'] = "GHOP Program" |
|
108 new_params['module_name'] = "program" |
|
109 new_params['sidebar_grouping'] = 'Programs' |
|
110 |
|
111 new_params['module_package'] = 'soc.modules.ghop.views.models' |
|
112 new_params['url_name'] = 'ghop/program' |
|
113 |
|
114 # TODO: this list can be reduced after GSoC has been moved |
|
115 new_params['extra_dynaexclude'] = ['apps_tasks_limit', |
|
116 'min_slots', 'max_slots', |
|
117 'slots', 'slot_allocation', |
|
118 'allocations_visible', |
|
119 'task_difficulties', 'task_types', |
|
120 ] |
|
121 |
|
122 patterns = [] |
|
123 patterns += [ |
|
124 (r'^%(url_name)s/(?P<access_type>assign_task_quotas)/%(key_fields)s$', |
|
125 '%(module_package)s.%(module_name)s.assign_task_quotas', |
|
126 'Assign task quota limits'), |
|
127 (r'^%(url_name)s/(?P<access_type>task_difficulty)/%(key_fields)s$', |
|
128 '%(module_package)s.%(module_name)s.task_difficulty_edit', |
|
129 'Edit Task Difficulty Tags'), |
|
130 (r'^%(url_name)s/(?P<access_type>task_type)/%(key_fields)s$', |
|
131 '%(module_package)s.%(module_name)s.task_type_edit', |
|
132 'Edit Task Type Tags'), |
|
133 (r'^%(url_name)s/(?P<access_type>difficulty_tag_edit)$', |
|
134 '%(module_package)s.%(module_name)s.difficulty_tag_edit', |
|
135 'Edit a Difficulty Tag'), |
|
136 (r'^%(url_name)s/(?P<access_type>type_tag_edit)$', |
|
137 '%(module_package)s.%(module_name)s.task_type_tag_edit', |
|
138 'Edit a Task Type Tag'), |
|
139 ] |
|
140 |
|
141 new_params['extra_django_patterns'] = patterns |
|
142 |
|
143 params = dicts.merge(params, new_params, sub_merge=True) |
|
144 |
|
145 super(View, self).__init__(params=params) |
|
146 |
|
147 dynafields = [ |
|
148 {'name': 'task_difficulties', |
|
149 'base': forms.CharField, |
|
150 'label': 'Task Difficulty Levels', |
|
151 'widget': widgets.ReadOnlyInput(), |
|
152 'required': False, |
|
153 'help_text': ugettext('Lists all the difficulty levels that ' |
|
154 'can be assigned to a task. Edit them ' |
|
155 'from the Program menu on sidebar.'), |
|
156 }, |
|
157 {'name': 'task_types', |
|
158 'base': forms.CharField, |
|
159 'label': 'Task Type Tags', |
|
160 'widget': widgets.ReadOnlyInput(), |
|
161 'required': False, |
|
162 'help_text': ugettext('Lists all the types a task can be in. ' |
|
163 'Edit them from the Program menu on sidebar.'), |
|
164 }, |
|
165 ] |
|
166 |
|
167 dynaproperties = params_helper.getDynaFields(dynafields) |
|
168 |
|
169 edit_form = dynaform.extendDynaForm( |
|
170 dynaform=self._params['edit_form'], |
|
171 dynaproperties=dynaproperties) |
|
172 |
|
173 self._params['edit_form'] = edit_form |
|
174 |
|
175 def _editGet(self, request, entity, form): |
|
176 """See base.View._editGet(). |
|
177 """ |
|
178 |
|
179 # TODO: can't a simple join operation do this? |
|
180 tds = ghop_task_model.TaskDifficultyTag.get_by_scope(entity) |
|
181 if tds: |
|
182 td_str = '' |
|
183 for td in tds[:-1]: |
|
184 td_str += str(td) + ', ' |
|
185 |
|
186 td_str += str(tds[-1]) |
|
187 |
|
188 form.fields['task_difficulties'].initial = td_str |
|
189 |
|
190 tts = ghop_task_model.TaskTypeTag.get_by_scope(entity) |
|
191 if tts: |
|
192 tt_str = '' |
|
193 for tt in tts[:-1]: |
|
194 tt_str += str(tt) + ', ' |
|
195 |
|
196 tt_str += str(tts[-1]) |
|
197 |
|
198 form.fields['task_types'].initial = tt_str |
|
199 |
|
200 return super(View, self)._editGet(request, entity, form) |
|
201 |
|
202 @decorators.merge_params |
|
203 @decorators.check_access |
|
204 def assignTaskQuotas(self, request, access_type, page_name=None, |
|
205 params=None, filter=None, **kwargs): |
|
206 """View that allows to assign task quotas for accepted GHOP organization. |
|
207 |
|
208 This view allows the program admin to set the task quota limits |
|
209 and change them at any time when the program is active. |
|
210 """ |
|
211 |
|
212 # TODO: Once GAE Task APIs arrive, this view will be managed by them |
|
213 program = ghop_program_logic.logic.getFromKeyFieldsOr404(kwargs) |
|
214 |
|
215 from soc.modules.ghop.views.models import \ |
|
216 organization as ghop_organization_view |
|
217 |
|
218 org_params = ghop_organization_view.view.getParams().copy() |
|
219 |
|
220 context = {} |
|
221 |
|
222 if request.method == 'POST': |
|
223 return self.assignTaskQuotasPost(request, context, org_params, |
|
224 page_name, params, program, |
|
225 **kwargs) |
|
226 else: # request.method == 'GET' |
|
227 return self.assignTaskQuotasGet(request, context, org_params, |
|
228 page_name, params, program, |
|
229 **kwargs) |
|
230 |
|
231 def assignTaskQuotasPost(self, request, context, org_params, |
|
232 page_name, params, entity, **kwargs): |
|
233 """Handles the POST request for the task quota allocation page. |
|
234 |
|
235 Args: |
|
236 entity: the program entity |
|
237 rest: see base.View.public() |
|
238 """ |
|
239 |
|
240 ghop_org_logic = org_params['logic'] |
|
241 |
|
242 error_orgs = '' |
|
243 for link_id, task_count in request.POST.items(): |
|
244 fields = { |
|
245 'link_id': link_id, |
|
246 'scope': entity, |
|
247 'scope_path': entity.key().id_or_name(), |
|
248 } |
|
249 key_name = ghop_org_logic.getKeyNameFromFields(fields) |
|
250 |
|
251 try: |
|
252 task_count = int(task_count) |
|
253 if task_count >= 0: |
|
254 fields['task_quota_limit'] = task_count |
|
255 ghop_org_logic.updateOrCreateFromKeyName(fields, key_name) |
|
256 else: |
|
257 raise ValueError |
|
258 except ValueError: |
|
259 org_entity = ghop_org_logic.getFromKeyName(key_name) |
|
260 error_orgs += org_entity.name + ', ' |
|
261 |
|
262 if error_orgs: |
|
263 context['error_message'] = self.DEF_TASK_QUOTA_ERROR_MSG_FMT % ( |
|
264 error_orgs[:-2]) |
|
265 |
|
266 return self.assignTaskQuotasGet(request, context, org_params, |
|
267 page_name, params, entity, |
|
268 **kwargs) |
|
269 |
|
270 # redirect to the same page |
|
271 return http.HttpResponseRedirect('') |
|
272 |
|
273 def assignTaskQuotasGet(self, request, context, org_params, |
|
274 page_name, params, entity, **kwargs): |
|
275 """Handles the GET request for the task quota allocation page. |
|
276 |
|
277 Args: |
|
278 entity: the program entity |
|
279 rest see base.View.public() |
|
280 """ |
|
281 |
|
282 org_params['list_template'] = ('modules/ghop/program/' |
|
283 'allocation/allocation.html') |
|
284 org_params['list_heading'] = ('modules/ghop/program/' |
|
285 'allocation/heading.html') |
|
286 org_params['list_row'] = 'modules/ghop/program/allocation/row.html' |
|
287 org_params['list_pagination'] = 'soc/list/no_pagination.html' |
|
288 |
|
289 description = self.DEF_TASK_QUOTA_ALLOCATION_MSG |
|
290 |
|
291 filter = { |
|
292 'scope': entity, |
|
293 'status': 'active', |
|
294 } |
|
295 |
|
296 content = self._getAcceptedOrgsList(description, org_params, |
|
297 filter, False) |
|
298 |
|
299 contents = [content] |
|
300 |
|
301 return self._list(request, org_params, contents, page_name, context) |
|
302 |
|
303 @decorators.merge_params |
|
304 def getExtraMenus(self, id, user, params=None): |
|
305 """See soc.views.models.program.View.getExtraMenus(). |
|
306 """ |
|
307 |
|
308 logic = params['logic'] |
|
309 rights = params['rights'] |
|
310 |
|
311 # only get all invisible and visible programs |
|
312 fields = {'status': ['invisible', 'visible']} |
|
313 entities = logic.getForFields(fields) |
|
314 |
|
315 menus = [] |
|
316 |
|
317 rights.setCurrentUser(id, user) |
|
318 |
|
319 for entity in entities: |
|
320 items = [] |
|
321 |
|
322 if entity.status == 'visible': |
|
323 # show the documents for this program, even for not logged in users |
|
324 items += document_view.view.getMenusForScope(entity, params) |
|
325 items += self._getTimeDependentEntries(entity, params, id, user) |
|
326 |
|
327 try: |
|
328 # check if the current user is a host for this program |
|
329 rights.doCachedCheck('checkIsHostForProgram', |
|
330 {'scope_path': entity.scope_path, |
|
331 'link_id': entity.link_id}, []) |
|
332 |
|
333 if entity.status == 'invisible': |
|
334 # still add the document links so hosts can see how it looks like |
|
335 items += document_view.view.getMenusForScope(entity, params) |
|
336 items += self._getTimeDependentEntries(entity, params, id, user) |
|
337 |
|
338 items += [(redirects.getReviewOverviewRedirect( |
|
339 entity, {'url_name': 'ghop/org_app', 'scope_view': self}), |
|
340 "Review Organization Applications", 'any_access')] |
|
341 # add link to edit Program Profile |
|
342 items += [(redirects.getEditRedirect(entity, params), |
|
343 'Edit Program Profile', 'any_access')] |
|
344 # add link to Assign Task Quota limits |
|
345 items += [(ghop_redirects.getAssignTaskQuotasRedirect(entity, params), |
|
346 'Assign Task Quota limits', 'any_access')] |
|
347 # add link to edit Program Timeline |
|
348 items += [(redirects.getEditRedirect( |
|
349 entity, {'url_name': 'ghop/timeline'}), |
|
350 "Edit Program Timeline", 'any_access')] |
|
351 # add link to create a new Program Document |
|
352 items += [(redirects.getCreateDocumentRedirect(entity, 'ghop/program'), |
|
353 "Create a New Document", 'any_access')] |
|
354 # add link to list all Program Document |
|
355 items += [(redirects.getListDocumentsRedirect(entity, 'ghop/program'), |
|
356 "List Documents", 'any_access')] |
|
357 # add link to edit Task Difficulty Levels |
|
358 items += [(ghop_redirects.getDifficultyEditRedirect( |
|
359 entity, {'url_name': 'ghop/program'}), |
|
360 "Edit Task Difficulty Levels", 'any_access')] |
|
361 # add link to edit Task Type Tags |
|
362 items += [(ghop_redirects.getTaskTypeEditRedirect( |
|
363 entity, {'url_name': 'ghop/program'}), |
|
364 "Edit Task Type Tags", 'any_access')] |
|
365 |
|
366 except out_of_band.Error: |
|
367 pass |
|
368 |
|
369 items = sidebar.getSidebarMenu(id, user, items, params=params) |
|
370 if not items: |
|
371 continue |
|
372 |
|
373 menu = {} |
|
374 menu['heading'] = entity.short_name |
|
375 menu['items'] = items |
|
376 menu['group'] = 'Programs' |
|
377 menus.append(menu) |
|
378 |
|
379 return menus |
|
380 |
|
381 def _getTimeDependentEntries(self, ghop_program_entity, params, id, user): |
|
382 """Returns a list with time dependent menu items. |
|
383 """ |
|
384 |
|
385 items = [] |
|
386 |
|
387 timeline_entity = ghop_program_entity.timeline |
|
388 |
|
389 # get the student entity for this user and program |
|
390 filter = {'user': user, |
|
391 'scope': ghop_program_entity, |
|
392 'status': 'active'} |
|
393 student_entity = ghop_student_logic.logic.getForFields(filter, unique=True) |
|
394 |
|
395 if student_entity: |
|
396 items += self._getStudentEntries(ghop_program_entity, student_entity, |
|
397 params, id, user) |
|
398 |
|
399 # get mentor and org_admin entity for this user and program |
|
400 filter = {'user': user, |
|
401 'program': ghop_program_entity, |
|
402 'status': 'active'} |
|
403 mentor_entity = ghop_mentor_logic.logic.getForFields(filter, unique=True) |
|
404 org_admin_entity = ghop_org_admin_logic.logic.getForFields( |
|
405 filter, unique=True) |
|
406 |
|
407 if mentor_entity or org_admin_entity: |
|
408 items += self._getOrganizationEntries( |
|
409 ghop_program_entity, org_admin_entity, |
|
410 mentor_entity, params, id, user) |
|
411 |
|
412 if user and not (student_entity or mentor_entity or org_admin_entity): |
|
413 if timeline_helper.isActivePeriod(timeline_entity, 'student_signup'): |
|
414 # this user does not have a role yet for this program |
|
415 items += [('/ghop/student/apply/%s' % ( |
|
416 ghop_program_entity.key().id_or_name()), |
|
417 "Register as a Student", 'any_access')] |
|
418 |
|
419 if timeline_helper.isAfterEvent(timeline_entity, 'org_signup_start'): |
|
420 url = ghop_redirects.getParticipatingOrgsRedirect( |
|
421 ghop_program_entity, params) |
|
422 # add a link to list all the organizations |
|
423 items += [(url, "List participating Organizations", 'any_access')] |
|
424 |
|
425 return items |
|
426 |
|
427 def _getStudentEntries(self, ghop_program_entity, student_entity, |
|
428 params, id, user): |
|
429 """Returns a list with menu items for students in a specific program. |
|
430 """ |
|
431 |
|
432 items = [] |
|
433 |
|
434 timeline_entity = ghop_program_entity.timeline |
|
435 |
|
436 if timeline_helper.isAfterEvent(timeline_entity, |
|
437 'student_signup_start'): |
|
438 # add a link to show all projects |
|
439 items += [(redirects.getListProjectsRedirect(ghop_program_entity, |
|
440 {'url_name':'ghop/task'}), |
|
441 "List my Tasks", 'any_access')] |
|
442 |
|
443 items += [(redirects.getEditRedirect(student_entity, |
|
444 {'url_name': 'ghop/student'}), |
|
445 "Edit my Student Profile", 'any_access')] |
|
446 |
|
447 items += [(redirects.getManageRedirect(student_entity, |
|
448 {'url_name':'ghop/student'}), |
|
449 "Resign as a Student", 'any_access')] |
|
450 |
|
451 return items |
|
452 |
|
453 @decorators.merge_params |
|
454 @decorators.check_access |
|
455 def taskDifficultyEdit(self, request, access_type, page_name=None, |
|
456 params=None, filter=None, **kwargs): |
|
457 """View method used to edit Difficulty Level tags. |
|
458 """ |
|
459 |
|
460 params = dicts.merge(params, self._params) |
|
461 |
|
462 try: |
|
463 entity = self._logic.getFromKeyFieldsOr404(kwargs) |
|
464 except out_of_band.Error, error: |
|
465 return helper.responses.errorResponse( |
|
466 error, request, template=params['error_public']) |
|
467 |
|
468 context = helper.responses.getUniversalContext(request) |
|
469 helper.responses.useJavaScript(context, params['js_uses_all']) |
|
470 context['page_name'] = page_name |
|
471 |
|
472 context['program_key_name'] = entity.key().name() |
|
473 |
|
474 context['difficulties'] = ghop_task_model.TaskDifficultyTag.get_by_scope( |
|
475 entity) |
|
476 |
|
477 params['edit_template'] = 'modules/ghop/program/tag/difficulty.html' |
|
478 |
|
479 return self._constructResponse(request, entity, context, None, params) |
|
480 |
|
481 @decorators.merge_params |
|
482 @decorators.check_access |
|
483 def difficultyTagEdit(self, request, access_type, page_name=None, |
|
484 params=None, filter=None, **kwargs): |
|
485 """View method used to edit a supplied Difficulty level tag. |
|
486 """ |
|
487 |
|
488 get_params = request.GET |
|
489 |
|
490 order = get_params.getlist('order') |
|
491 program_key_name = get_params.get('program_key_name') |
|
492 |
|
493 program_entity = ghop_program_logic.logic.getFromKeyName( |
|
494 program_key_name) |
|
495 |
|
496 if order: |
|
497 for index, elem in enumerate(order): |
|
498 ghop_task_model.TaskDifficultyTag.update_order( |
|
499 program_entity, elem, index) |
|
500 return http.HttpResponse() |
|
501 else: |
|
502 tag_data = get_params.getlist('tag_data') |
|
503 |
|
504 tag_name = tag_data[0].strip() |
|
505 tag_value = tag_data[1].strip() |
|
506 |
|
507 if tag_name: |
|
508 if not tag_value: |
|
509 ghop_task_model.TaskDifficultyTag.delete_tag( |
|
510 program_entity, tag_name) |
|
511 elif tag_name != tag_value: |
|
512 ghop_task_model.TaskDifficultyTag.copy_tag( |
|
513 program_entity, tag_name, tag_value) |
|
514 else: |
|
515 ghop_task_model.TaskDifficultyTag.get_or_create( |
|
516 program_entity, tag_value) |
|
517 |
|
518 return http.HttpResponse(tag_value) |
|
519 |
|
520 @decorators.merge_params |
|
521 @decorators.check_access |
|
522 def taskTypeEdit(self, request, access_type, page_name=None, |
|
523 params=None, filter=None, **kwargs): |
|
524 """View method used to edit Task Type tags. |
|
525 """ |
|
526 |
|
527 params = dicts.merge(params, self._params) |
|
528 |
|
529 try: |
|
530 entity = self._logic.getFromKeyFieldsOr404(kwargs) |
|
531 except out_of_band.Error, error: |
|
532 return helper.responses.errorResponse( |
|
533 error, request, template=params['error_public']) |
|
534 |
|
535 context = helper.responses.getUniversalContext(request) |
|
536 helper.responses.useJavaScript(context, params['js_uses_all']) |
|
537 context['page_name'] = page_name |
|
538 |
|
539 context['program_key_name'] = entity.key().name() |
|
540 |
|
541 context['task_types'] = ghop_task_model.TaskTypeTag.get_by_scope( |
|
542 entity) |
|
543 |
|
544 params['edit_template'] = 'modules/ghop/program/tag/task_type.html' |
|
545 |
|
546 return self._constructResponse(request, entity, context, None, params) |
|
547 |
|
548 @decorators.merge_params |
|
549 @decorators.check_access |
|
550 def taskTypeTagEdit(self, request, access_type, page_name=None, |
|
551 params=None, filter=None, **kwargs): |
|
552 """View method used to edit a supplied Task Type tag. |
|
553 """ |
|
554 |
|
555 get_params = request.GET |
|
556 |
|
557 order = get_params.getlist('order') |
|
558 program_key_name = get_params.get('program_key_name') |
|
559 |
|
560 program_entity = ghop_program_logic.logic.getFromKeyName( |
|
561 program_key_name) |
|
562 |
|
563 if order: |
|
564 for index, elem in enumerate(order): |
|
565 ghop_task_model.TaskTypeTag.update_order( |
|
566 program_entity, elem, index) |
|
567 return http.HttpResponse() |
|
568 else: |
|
569 tag_data = get_params.getlist('tag_data') |
|
570 program_key_name = get_params.get('program_key_name') |
|
571 |
|
572 tag_name = tag_data[0].strip() |
|
573 tag_value = tag_data[1].strip() |
|
574 |
|
575 program_entity = ghop_program_logic.logic.getFromKeyName( |
|
576 program_key_name) |
|
577 |
|
578 if tag_name: |
|
579 if not tag_value: |
|
580 ghop_task_model.TaskTypeTag.delete_tag( |
|
581 program_entity, tag_name) |
|
582 elif tag_name != tag_value: |
|
583 ghop_task_model.TaskTypeTag.copy_tag( |
|
584 program_entity, tag_name, tag_value) |
|
585 else: |
|
586 ghop_task_model.TaskTypeTag.get_or_create(program_entity, tag_value) |
|
587 |
|
588 return http.HttpResponse(tag_value) |
|
589 |
|
590 |
|
591 view = View() |
|
592 |
|
593 admin = decorators.view(view.admin) |
|
594 assign_task_quotas = decorators.view(view.assignTaskQuotas) |
|
595 create = decorators.view(view.create) |
|
596 delete = decorators.view(view.delete) |
|
597 edit = decorators.view(view.edit) |
|
598 list = decorators.view(view.list) |
|
599 public = decorators.view(view.public) |
|
600 export = decorators.view(view.export) |
|
601 home = decorators.view(view.home) |
|
602 difficulty_tag_edit = decorators.view(view.difficultyTagEdit) |
|
603 task_type_tag_edit = decorators.view(view.taskTypeTagEdit) |
|
604 task_difficulty_edit = decorators.view(view.taskDifficultyEdit) |
|
605 task_type_edit = decorators.view(view.taskTypeEdit) |