Increased the length of the timebased link_id to handle more items at once.
[Melange.git] / app / soc / views / models / student_proposal.py
blob354a1d6bfa86ffd7d4dd398ad6c138a5d6b3e71d
1 #!/usr/bin/python2.5
3 # Copyright 2009 the Melange authors.
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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.
17 """Views for Student Proposal.
18 """
20 __authors__ = [
21 '"Lennard de Rijk" <ljvderijk@gmail.com>',
25 import datetime
26 import time
28 from django import forms
29 from django import http
31 from soc.logic import cleaning
32 from soc.logic import dicts
33 from soc.logic.models import mentor as mentor_logic
34 from soc.logic.models import organization as org_logic
35 from soc.logic.models import org_admin as org_admin_logic
36 from soc.logic.models import student as student_logic
37 from soc.logic.models import user as user_logic
38 from soc.views import helper
39 from soc.views import out_of_band
40 from soc.views.helper import access
41 from soc.views.helper import decorators
42 from soc.views.helper import dynaform
43 from soc.views.helper import params as params_helper
44 from soc.views.helper import redirects
45 from soc.views.helper import responses
46 from soc.views.helper import widgets
47 from soc.views.models import base
48 from soc.views.models import student as student_view
50 import soc.logic.models.student_proposal
53 class View(base.View):
54 """View methods for the Student Proposal model.
55 """
57 def __init__(self, params=None):
58 """Defines the fields and methods required for the base View class
59 to provide the user with list, public, create, edit and delete views.
61 Params:
62 params: a dict with params for this View
63 """
65 rights = access.Checker(params)
66 rights['create'] = ['checkIsDeveloper']
67 rights['edit'] = [('checkCanStudentPropose', 'scope_path'),
68 ('checkRoleAndStatusForStudentProposal',
69 [['proposer'], ['active'], ['new', 'pending']])]
70 rights['delete'] = ['checkIsDeveloper']
71 rights['show'] = [
72 ('checkRoleAndStatusForStudentProposal',
73 [['proposer', 'org_admin', 'mentor', 'host'],
74 ['active', 'inactive'],
75 ['new', 'pending', 'accepted', 'rejected']])]
76 rights['list'] = ['checkIsDeveloper']
77 rights['list_orgs'] = [
78 ('checkIsStudent', ['scope_path', ['active']]),
79 ('checkCanStudentPropose', 'scope_path')]
80 rights['list_self'] = [
81 ('checkIsStudent', ['scope_path', ['active', 'inactive']])]
82 rights['apply'] = [
83 ('checkIsStudent', ['scope_path', ['active']]),
84 ('checkCanStudentPropose', 'scope_path')]
85 rights['review'] = [('checkRoleAndStatusForStudentProposal',
86 [['org_admin', 'mentor', 'host'],
87 ['active'], ['new', 'pending']])]
89 new_params = {}
90 new_params['logic'] = soc.logic.models.student_proposal.logic
91 new_params['rights'] = rights
92 new_params['name'] = "Student Proposal"
93 new_params['url_name'] = "student_proposal"
94 new_params['sidebar_grouping'] = 'Students'
96 new_params['scope_view'] = student_view
97 new_params['scope_redirect'] = redirects.getCreateRedirect
99 new_params['no_create_with_key_fields'] = True
101 patterns = [
102 (r'^%(url_name)s/(?P<access_type>apply)/%(scope)s$',
103 'soc.views.models.%(module_name)s.apply',
104 'Create a new %(name)s'),
105 (r'^%(url_name)s/(?P<access_type>list_self)/%(scope)s$',
106 'soc.views.models.%(module_name)s.list_self',
107 'List my %(name_plural)s'),
108 (r'^%(url_name)s/(?P<access_type>list_orgs)/%(scope)s$',
109 'soc.views.models.%(module_name)s.list_orgs',
110 'List my %(name_plural)s'),
111 (r'^%(url_name)s/(?P<access_type>review)/%(key_fields)s$',
112 'soc.views.models.%(module_name)s.review',
113 'Review %(name)s'),
116 new_params['extra_django_patterns'] = patterns
118 new_params['extra_dynaexclude'] = ['org', 'program', 'score',
119 'status', 'mentor', 'link_id',
120 'possible_mentors']
122 new_params['create_extra_dynaproperties'] = {
123 'content': forms.fields.CharField(required=True,
124 widget=widgets.FullTinyMCE(attrs={'rows': 25, 'cols': 100})),
125 'scope_path': forms.CharField(widget=forms.HiddenInput,
126 required=True),
127 'organization': forms.CharField(label='Organization Link ID',
128 required=True),
129 'clean_organization': cleaning.clean_link_id('organization'),
130 'clean_additional_info': cleaning.clean_url('additional_info'),
131 'clean': cleaning.validate_student_proposal('organization',
132 'scope_path', student_logic, org_logic),
135 new_params['edit_extra_dynaproperties'] = {
136 'organization': forms.CharField(label='Organization Link ID',
137 widget=widgets.ReadOnlyInput),
138 'link_id': forms.CharField(widget=forms.HiddenInput)
141 new_params['edit_template'] = 'soc/student_proposal/edit.html'
142 new_params['review_template'] = 'soc/student_proposal/review.html'
144 params = dicts.merge(params, new_params)
146 super(View, self).__init__(params=params)
148 # create the special form for students
149 dynafields = [
150 {'name': 'organization',
151 'base': forms.CharField,
152 'label': 'Organization Link ID',
153 'widget': widgets.ReadOnlyInput(),
154 'required': False,
158 dynaproperties = params_helper.getDynaFields(dynafields)
160 student_create_form = dynaform.extendDynaForm(
161 dynaform=self._params['create_form'],
162 dynaproperties=dynaproperties)
164 params['student_create_form'] = student_create_form
166 # create the special form for public review
167 dynafields = [
168 {'name': 'comment',
169 'base': forms.CharField,
170 'widget': widgets.FullTinyMCE(attrs={'rows': 10, 'cols': 40}),
171 'label': 'Comment',
172 'required': False,
176 dynaproperties = params_helper.getDynaFields(dynafields)
178 public_review_form = dynaform.newDynaForm(dynamodel=None,
179 dynabase=helper.forms.BaseForm, dynainclude=None,
180 dynaexclude=None, dynaproperties=dynaproperties)
181 params['public_review_form'] = public_review_form
183 # create the special form for mentors
184 dynafields = [
185 {'name': 'score',
186 'base': forms.ChoiceField,
187 'label': 'Score',
188 'initial': 0,
189 'required': False,
190 'passthrough': ['initial', 'required', 'choices'],
191 'example_text':
192 'A score will only be assigned if the review is private!',
193 'choices': [(-4,'-4: Wow. This. Sucks.'),
194 (-3,'-3: Needs a lot of work'),
195 (-2,'-2: This is bad'),
196 (-1,'-1: I dont like this'),
197 (0,'0: No score'),
198 (1,'1: Might have potential'),
199 (2,'2: Good'),
200 (3,'3: Almost there'),
201 (4,'4: Made. Of. Awesome.')]
203 {'name': 'comment',
204 'base': forms.CharField,
205 'widget': widgets.FullTinyMCE(attrs={'rows': 10, 'cols': 40}),
206 'label': 'Comment',
207 'required': False,
209 {'name': 'public',
210 'base': forms.BooleanField,
211 'label': 'Public review',
212 'initial': False,
213 'required': False,
214 'help_text': 'By ticking this box the score will not be assigned, '
215 'and the review will be public.',
219 dynaproperties = params_helper.getDynaFields(dynafields)
221 mentor_review_form = dynaform.newDynaForm(dynamodel=None,
222 dynabase=helper.forms.BaseForm, dynainclude=None,
223 dynaexclude=None, dynaproperties=dynaproperties)
224 params['mentor_review_form'] = mentor_review_form
226 # TODO see if autocomplete can be used for mentor field
227 dynafields = [
228 {'name': 'rank',
229 'base': forms.IntegerField,
230 'label': 'Set to rank',
231 'help_text':
232 'Set this proposal to the given rank (ignores the given score)',
233 'example_text': 'A rank will only be assigned if the review is private!',
234 'min_value': 1,
235 'required': False,
236 'passthrough': ['min_value', 'required', 'help_text'],
238 {'name': 'mentor',
239 'base': forms.CharField,
240 'label': 'Assign Mentor (Link ID)',
241 'required': False,
242 'help_text': 'Fill in the Link ID of the Mentor '
243 'you would like to assign to this Proposal. '
244 'Leave this box empty if you don\'t want any mentor assigned.',
248 dynaproperties = params_helper.getDynaFields(dynafields)
250 admin_review_form = dynaform.extendDynaForm(dynaform=mentor_review_form,
251 dynaproperties=dynaproperties)
253 params['admin_review_form'] = admin_review_form
255 def _editGet(self, request, entity, form):
256 """See base.View._editGet().
259 form.fields['link_id'].initial = entity.link_id
260 form.fields['organization'].initial = entity.org.link_id
262 return super(View, self)._editGet(request, entity, form)
264 def _editPost(self, request, entity, fields):
265 """See base.View._editPost().
268 if not entity:
269 fields['link_id'] = 't%i' %(int(time.time()*100))
270 else:
271 fields['link_id'] = entity.link_id
273 # fill in the scope via call to super
274 super(View, self)._editPost(request, entity, fields)
276 if not entity:
277 # creating a new application so set the program and org field
278 fields['program'] = fields['scope'].scope
280 filter = {'scope': fields['program'],
281 'link_id': fields['organization']}
282 fields['org'] = org_logic.logic.getForFields(filter, unique=True)
284 # explicitly change the last_modified_on since the content has been edited
285 fields['last_modified_on'] = datetime.datetime.now()
287 @decorators.merge_params
288 @decorators.check_access
289 def public(self, request, access_type,
290 page_name=None, params=None, **kwargs):
291 """View in which the student can see and reply to the comments on the
292 Student Proposal.
294 For params see base.view.Public().
297 context = helper.responses.getUniversalContext(request)
298 helper.responses.useJavaScript(context, params['js_uses_all'])
299 context['page_name'] = page_name
301 try:
302 entity = self._logic.getFromKeyFieldsOr404(kwargs)
303 except out_of_band.Error, error:
304 return helper.responses.errorResponse(
305 error, request, template=params['error_public'], context=context)
307 context['entity'] = entity
308 context['entity_type'] = params['name']
309 context['entity_type_url'] = params['url_name']
311 if request.method == 'POST':
312 return self.publicPost(request, context, params, entity, **kwargs)
313 else: # request.method == 'GET'
314 return self.publicGet(request, context, params, entity, **kwargs)
316 def publicPost(self, request, context, params, entity, **kwargs):
317 """Handles the POST request for the entity's public page.
319 Args:
320 entity: the student proposal entity
321 rest: see base.View.public()
324 # populate the form using the POST data
325 form = params['public_review_form'](request.POST)
327 if not form.is_valid():
328 # get some entity specific context
329 self.updatePublicContext(context, entity, params)
331 # return the invalid form response
332 return self._constructResponse(request, entity=entity, context=context,
333 form=form, params=params, template=params['public_template'])
335 # get the commentary
336 fields = form.cleaned_data
337 comment = fields['comment']
339 if comment:
340 # create a new public review containing the comment
341 user_entity = user_logic.logic.getForCurrentAccount()
343 if user_entity.key() == entity.scope.user.key():
344 # student is posting
345 reviewer = entity.scope
346 else:
347 # check if the person commenting is an org_admin
348 # or a mentor for the given proposal
349 fields = {'user': user_entity,
350 'scope': entity.org,
351 'status': 'active',
354 reviewer = org_admin_logic.logic.getForFields(fields, unique=True)
356 if not reviewer:
357 # no org_admin found, maybe it's a mentor?
358 reviewer = mentor_logic.logic.getForFields(filter, unique=True)
360 # create the review (reviewer might be None if a Host or Developer is posting)
361 self._createReviewFor(entity, reviewer, comment, is_public=True)
363 # redirect to the same page
364 return http.HttpResponseRedirect('')
366 def publicGet(self, request, context, params, entity, **kwargs):
367 """Handles the GET request for the entity's public page.
369 Args:
370 entity: the student proposal entity
371 rest see base.View.public()
374 from soc.logic.models.review_follower import logic as review_follower_logic
376 get_dict = request.GET
378 if get_dict.get('subscription') and (
379 get_dict['subscription'] in ['on', 'off']):
381 subscription = get_dict['subscription']
383 # get the current user
384 user_entity = user_logic.logic.getForCurrentAccount()
386 # create the fields that should be in the ReviewFollower entity
387 fields = {'link_id': user_entity.link_id,
388 'scope': entity,
389 'scope_path': entity.key().name(),
390 'user': user_entity
392 # get the keyname for the ReviewFollower entity
393 key_name = review_follower_logic.getKeyNameFromFields(fields)
395 # determine if we should set subscribed_public to True or False
396 if subscription == 'on':
397 fields['subscribed_public'] = True
398 elif subscription == 'off':
399 fields['subscribed_public'] = False
401 # update the ReviewFollower
402 review_follower_logic.updateOrCreateFromKeyName(fields, key_name)
404 # get some entity specific context
405 self.updatePublicContext(context, entity, params)
407 context['form'] = params['public_review_form']()
408 template = params['public_template']
410 return responses.respond(request, template, context=context)
412 def updatePublicContext(self, context, entity, params):
413 """Updates the context for the public page with information from the entity.
415 Args:
416 context: the context that should be updated
417 entity: a student proposal_entity used to set context
418 params: dict with params for the view using this context
421 from soc.logic.models.review import logic as review_logic
422 from soc.logic.models.review_follower import logic as review_follower_logic
424 student_entity = entity.scope
426 context['student_name'] = student_entity.name()
428 user_entity = user_logic.logic.getForCurrentAccount()
430 # check if the current user is the student
431 if user_entity.key() == student_entity.user.key():
432 # show the proposal edit link
433 context['edit_link'] = redirects.getEditRedirect(entity, params)
435 # check if the current user is subscribed to this proposal's public reviews
436 fields = {'user': user_entity,
437 'scope': entity,
438 'subscribed_public': True}
440 context['is_subscribed'] = review_follower_logic.getForFields(fields,
441 unique=True)
443 context['public_reviews'] = review_logic.getReviewsForEntity(entity,
444 is_public=True, order=['created'])
446 @decorators.merge_params
447 @decorators.check_access
448 def apply(self, request, access_type,
449 page_name=None, params=None, **kwargs):
450 """Special view used to prepopulate the form with the organization
451 contributors template.
453 For params see base.View.public()
455 get_dict = request.GET
457 if get_dict.get('organization'):
458 # organization chosen, prepopulate with template
460 # get the organization
461 student_entity = student_logic.logic.getFromKeyName(kwargs['scope_path'])
462 program_entity = student_entity.scope
464 filter = {'link_id': get_dict['organization'],
465 'scope': program_entity}
467 org_entity = org_logic.logic.getForFields(filter, unique=True)
469 if org_entity:
470 # organization found use special form
471 params['create_form'] = params['student_create_form']
472 kwargs['content'] = org_entity.contrib_template
474 # Create page is an edit page with no key fields
475 empty_kwargs = {}
476 fields = self._logic.getKeyFieldNames()
477 for field in fields:
478 empty_kwargs[field] = None
480 return super(View, self).edit(request, access_type, page_name=page_name,
481 params=params, seed=kwargs, **empty_kwargs)
483 @decorators.merge_params
484 @decorators.check_access
485 def edit(self, request, access_type,
486 page_name=None, params=None, seed=None, **kwargs):
487 """If the POST contains (action, Withdraw) the proposal in kwargs
488 will be marked as invalid.
490 For params see base.View.edit()
493 # check if request.POST contains action
494 post_dict = request.POST
495 if 'action' in post_dict and post_dict['action'] == 'Withdraw':
496 # withdraw this proposal
497 filter = {'scope_path': kwargs['scope_path'],
498 'link_id': kwargs['link_id']}
500 proposal_logic = params['logic']
501 student_proposal_entity = proposal_logic.getForFields(filter, unique=True)
503 # update the entity mark it as invalid
504 proposal_logic.updateEntityProperties(student_proposal_entity,
505 {'status': 'invalid'})
507 # redirect to the program's homepage
508 redirect_url = redirects.getHomeRedirect(student_proposal_entity.program,
509 {'url_name': 'program'})
511 return http.HttpResponseRedirect(redirect_url)
513 return super(View, self).edit(request=request, access_type=access_type,
514 page_name=page_name, params=params, seed=seed, **kwargs)
516 @decorators.merge_params
517 @decorators.check_access
518 def listOrgs(self, request, access_type,
519 page_name=None, params=None, **kwargs):
520 """Lists all organization which the given student can propose to.
522 For params see base.View.public().
525 from soc.views.models import organization as org_view
527 student_entity = student_logic.logic.getFromKeyName(kwargs['scope_path'])
529 filter = {'scope' : student_entity.scope,
530 'status': 'active'}
532 list_params = org_view.view.getParams().copy()
533 list_params['list_description'] = ('List of %(name_plural)s you can send '
534 'your proposal to.') % list_params
535 list_params['list_action'] = (redirects.getStudentProposalRedirect,
536 {'student_key': student_entity.key().name(),
537 'url_name': params['url_name']})
539 return self.list(request, access_type=access_type, page_name=page_name,
540 params=list_params, filter=filter, **kwargs)
542 @decorators.merge_params
543 @decorators.check_access
544 def listSelf(self, request, access_type,
545 page_name=None, params=None, **kwargs):
546 """Lists all proposals from the current logged-in user
547 for the given student.
549 For params see base.View.public().
552 student_entity = student_logic.logic.getFromKeyName(kwargs['scope_path'])
554 filter = {'scope' : student_entity,
555 'status': ['new', 'pending', 'accepted', 'rejected']}
557 list_params = params.copy()
558 list_params['list_description'] = 'List of my %(name_plural)s' % list_params
559 list_params['list_action'] = (redirects.getPublicRedirect, list_params)
561 return self.list(request, access_type=access_type, page_name=page_name,
562 params=list_params, filter=filter, **kwargs)
564 @decorators.merge_params
565 @decorators.check_access
566 def review(self, request, access_type,
567 page_name=None, params=None, **kwargs):
568 """View that allows Organization Admins and Mentors to review the proposal.
570 For Args see base.View.public().
573 try:
574 entity = self._logic.getFromKeyFieldsOr404(kwargs)
575 except out_of_band.Error, error:
576 return helper.responses.errorResponse(
577 error, request, template=params['error_public'])
579 # get the context for this webpage
580 context = responses.getUniversalContext(request)
581 responses.useJavaScript(context, params['js_uses_all'])
582 context['page_name'] = page_name
583 context['entity'] = entity
584 context['entity_type'] = params['name']
585 context['entity_type_url'] = params['url_name']
587 # get the roles important for reviewing an application
588 filter = {'user': user_logic.logic.getForCurrentAccount(),
589 'scope': entity.org,
590 'status': 'active'}
592 org_admin_entity = org_admin_logic.logic.getForFields(filter, unique=True)
593 mentor_entity = mentor_logic.logic.getForFields(filter, unique=True)
595 # decide which form to use
596 if org_admin_entity:
597 form = params['admin_review_form']
598 else:
599 form = params['mentor_review_form']
601 if request.method == 'POST':
602 return self.reviewPost(request, context, params, entity,
603 form, org_admin_entity, mentor_entity, **kwargs)
604 else:
605 # request.method == 'GET'
606 return self.reviewGet(request, context, params, entity,
607 form, org_admin_entity, mentor_entity, **kwargs)
609 def reviewPost(self, request, context, params, entity, form,
610 org_admin, mentor, **kwargs):
611 """Handles the POST request for the proposal review view.
613 Args:
614 entity: the student proposal entity
615 form: the form to use in this view
616 org_admin: org admin entity for the current user/proposal (iff available)
617 mentor: mentor entity for the current user/proposal (iff available)
618 rest: see base.View.public()
620 # populate the form using the POST data
621 form = form(request.POST)
623 if not form.is_valid():
624 # return the invalid form response
625 # get all the extra information that should be in the context
626 review_context = self._getDefaultReviewContext(entity, org_admin, mentor)
627 context = dicts.merge(context, review_context)
629 return self._constructResponse(request, entity=entity, context=context,
630 form=form, params=params, template=params['review_template'])
632 fields = form.cleaned_data
633 is_public = fields['public']
634 comment = fields['comment']
635 given_score = int(fields['score'])
637 if org_admin:
638 # org admin found, try to adjust the assigned mentor
639 self._adjustMentor(entity, fields['mentor'])
640 reviewer = org_admin
642 # try to see if the rank is given and adjust the given_score if needed
643 rank = fields['rank']
644 if rank:
645 ranker = self._logic.getRankerFor(entity)
646 # if a very high rank is filled in use the highest one that returns a score
647 rank = min(ranker.TotalRankedScores(), rank)
648 # ranker uses zero-based ranking
649 score_and_rank = ranker.FindScore(rank-1)
650 # get the score at the requested rank
651 score_at_rank = score_and_rank[0][0]
652 # calculate the score that should be given to end up at the given rank
653 given_score = score_at_rank - entity.score
654 else:
655 # might be None (if Host or Developer is commenting)
656 reviewer = mentor
658 if reviewer and (not is_public) and (given_score is not 0):
659 # if it is not a public comment and it's made by a member of the
660 # organization we update the score of the proposal
661 new_score = given_score + entity.score
663 properties = {'score': new_score}
665 # if the proposal is new we change it status to pending
666 if entity.status == 'new':
667 properties['status'] = 'pending'
669 # update the proposal with the new score
670 self._logic.updateEntityProperties(entity, properties)
672 # create the review entity
673 if comment or (given_score is not 0):
674 self._createReviewFor(entity, reviewer, comment, given_score, is_public)
676 # redirect to the same page
677 return http.HttpResponseRedirect('')
679 def reviewGet(self, request, context, params, entity, form,
680 org_admin, mentor, **kwargs):
681 """Handles the GET request for the proposal review view.
683 Args:
684 entity: the student proposal entity
685 form: the form to use in this view
686 org_admin: org admin entity for the current user/proposal (iff available)
687 mentor: mentor entity for the current user/proposal (iff available)
688 rest: see base.View.public()
691 from soc.logic.models.review_follower import logic as review_follower_logic
693 get_dict = request.GET
695 # check if the current user is a mentor and wants
696 # to change his role for this app
697 choice = get_dict.get('mentor')
698 if mentor and choice:
699 self._adjustPossibleMentors(entity, mentor, choice)
701 is_ineligible = get_dict.get('ineligible')
702 if org_admin and is_ineligible:
703 # mark the proposal invalid and return to the list
704 properties = {'status': 'invalid'}
705 self._logic.updateEntityProperties(entity, properties)
707 redirect = redirects.getListProposalsRedirect(entity.org,
708 {'url_name': 'org'})
709 return http.HttpResponseRedirect(redirect)
711 # check if we should change the subscription state for the current user
712 public_subscription = None
713 private_subscription = None
715 if get_dict.get('public_subscription') and (
716 get_dict['public_subscription'] in ['on', 'off']):
718 public_subscription = get_dict['public_subscription'] == 'on'
720 if get_dict.get('private_subscription') and (
721 get_dict['private_subscription'] in ['on', 'off']):
722 private_subscription = get_dict['private_subscription'] == 'on'
724 if public_subscription != None or private_subscription != None:
725 # get the current user
726 user_entity = user_logic.logic.getForCurrentAccount()
728 # create the fields that should be in the ReviewFollower entity
729 fields = {'link_id': user_entity.link_id,
730 'scope': entity,
731 'scope_path': entity.key().name(),
732 'user': user_entity
734 # get the keyname for the ReviewFollower entity
735 key_name = review_follower_logic.getKeyNameFromFields(fields)
737 # determine which subscription properties we should change
738 if public_subscription != None:
739 fields['subscribed_public'] = public_subscription
741 if private_subscription != None:
742 fields['subscribed_private'] = private_subscription
744 # update the ReviewFollower
745 review_follower_logic.updateOrCreateFromKeyName(fields, key_name)
747 # set the initial score since the default is ignored
748 initial = {'score': 0}
750 if org_admin and entity.mentor:
751 # set the mentor field to the current mentor
752 initial['mentor'] = entity.mentor.link_id
754 context['form'] = form(initial)
756 # get all the extra information that should be in the context
757 review_context = self._getDefaultReviewContext(entity, org_admin, mentor)
758 context = dicts.merge(context, review_context)
760 template = params['review_template']
762 return responses.respond(request, template, context=context)
764 def _getDefaultReviewContext(self, entity, org_admin,
765 mentor):
766 """Returns the default context for the review page.
768 Args:
769 entity: Student Proposal entity
770 org_admin: org admin entity for the current user/proposal (iff available)
771 mentor: mentor entity for the current user/proposal (iff available)
774 from soc.logic.models.review import logic as review_logic
775 from soc.logic.models.review_follower import logic as review_follower_logic
777 context = {}
779 context['student_name'] = entity.scope.name()
781 if entity.mentor:
782 context['mentor_name'] = entity.mentor.name()
783 else:
784 context['mentor_name'] = "No mentor assigned"
786 # set the possible mentors in the context
787 possible_mentors = entity.possible_mentors
789 if not possible_mentors:
790 context['possible_mentors'] = "None"
791 else:
792 mentor_names = []
794 for mentor_key in possible_mentors:
795 possible_mentor = mentor_logic.logic.getFromKeyName(mentor_key.name())
796 mentor_names.append(possible_mentor.name())
798 context['possible_mentors'] = ', '.join(mentor_names)
800 # TODO(ljvderijk) listing of total given scores per mentor
801 # a dict with key as role.user ?
803 # order the reviews by ascending creation date
804 order = ['created']
806 # get the public reviews
807 context['public_reviews'] = review_logic.getReviewsForEntity(entity,
808 is_public=True, order=order)
810 # get the private reviews
811 context['private_reviews'] = review_logic.getReviewsForEntity(entity,
812 is_public=False, order=order)
814 # which button should we show to the mentor?
815 if mentor:
816 if mentor.key() in possible_mentors:
817 # show "No longer willing to mentor"
818 context['remove_me_as_mentor'] = True
819 else:
820 # show "I am willing to mentor"
821 context['add_me_as_mentor'] = True
823 if org_admin:
824 context['is_org_admin'] = True
826 user_entity = user_logic.logic.getForCurrentAccount()
828 # check if the current user is subscribed to public or private reviews
829 fields = {'scope': entity,
830 'user': user_entity,}
831 follower_entity = review_follower_logic.getForFields(fields, unique=True)
833 if follower_entity:
834 context['is_subscribed_public'] = follower_entity.subscribed_public
835 context['is_subscribed_private'] = follower_entity.subscribed_private
837 return context
839 def _adjustPossibleMentors(self, entity, mentor, choice):
840 """Adjusts the possible mentors list for a proposal.
842 Args:
843 entity: Student Proposal entity
844 mentor: Mentor entity
845 choice: 1 means want to mentor, 0 do not want to mentor
847 possible_mentors = entity.possible_mentors
849 if choice == '1':
850 # add the mentor to possible mentors list if not already in
851 if mentor.key() not in possible_mentors:
852 possible_mentors.append(mentor.key())
853 fields = {'possible_mentors': possible_mentors}
854 self._logic.updateEntityProperties(entity, fields)
855 elif choice == '0':
856 # remove the mentor from the possible mentors list
857 if mentor.key() in possible_mentors:
858 possible_mentors.remove(mentor.key())
859 fields = {'possible_mentors': possible_mentors}
860 self._logic.updateEntityProperties(entity, fields)
862 def _adjustMentor(self, entity, mentor_id):
863 """Changes the mentor to the given link_id.
865 Args:
866 entity: Student Proposal entity
867 mentor_id: Link ID of the mentor that needs to be assigned
868 Iff not given then removes the assigned mentor
871 if entity.mentor and entity.mentor.link_id == mentor_id:
872 # no need to change
873 return
875 if mentor_id:
876 # try to locate the mentor
877 fields = {'link_id': mentor_id,
878 'scope': entity.org,
879 'status': 'active'}
881 mentor_entity = mentor_logic.logic.getForFields(fields, unique=True)
883 if not mentor_entity:
884 # no mentor found, do not update
885 return
886 else:
887 # reset to None
888 mentor_entity = None
890 # update the proposal
891 properties = {'mentor': mentor_entity}
892 self._logic.updateEntityProperties(entity, properties)
894 def _createReviewFor(self, entity, reviewer, comment, score=0, is_public=True):
895 """Creates a review for the given proposal.
897 Args:
898 entity: Student Proposal entity for which the review should be created
899 reviewer: A role entity of the reviewer (if possible, else None)
900 comment: The textual contents of the review
901 score: The score of the review (only used if the review is not public)
902 is_public: Determines if the review is a public review
904 Returns:
905 - The newly created review
908 import time
910 from soc.logic.models.review import logic as review_logic
912 # create the fields for the review entity
913 fields = {'link_id': 't%i' %(int(time.time()*100)),
914 'scope': entity,
915 'scope_path': entity.key().name(),
916 'author': user_logic.logic.getForCurrentAccount(),
917 'content': comment,
918 'is_public': is_public,
919 'reviewer': reviewer
922 # add the given score if the review is not public
923 if not is_public:
924 fields['score'] = score
926 key_name = review_logic.getKeyNameFromFields(fields)
928 return review_logic.updateOrCreateFromKeyName(fields, key_name)
931 view = View()
933 admin = decorators.view(view.admin)
934 apply = decorators.view(view.apply)
935 create = decorators.view(view.create)
936 delete = decorators.view(view.delete)
937 edit = decorators.view(view.edit)
938 list = decorators.view(view.list)
939 list_orgs = decorators.view(view.listOrgs)
940 list_self = decorators.view(view.listSelf)
941 public = decorators.view(view.public)
942 review = decorators.view(view.review)
943 export = decorators.view(view.export)
944 pick = decorators.view(view.pick)