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.
21 '"Lennard de Rijk" <ljvderijk@gmail.com>',
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.
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.
62 params: a dict with params for this View
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']
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']])]
83 ('checkIsStudent', ['scope_path', ['active']]),
84 ('checkCanStudentPropose', 'scope_path')]
85 rights
['review'] = [('checkRoleAndStatusForStudentProposal',
86 [['org_admin', 'mentor', 'host'],
87 ['active'], ['new', 'pending']])]
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
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',
116 new_params
['extra_django_patterns'] = patterns
118 new_params
['extra_dynaexclude'] = ['org', 'program', 'score',
119 'status', 'mentor', 'link_id',
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
,
127 'organization': forms
.CharField(label
='Organization Link ID',
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
150 {'name': 'organization',
151 'base': forms
.CharField
,
152 'label': 'Organization Link ID',
153 'widget': widgets
.ReadOnlyInput(),
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
169 'base': forms
.CharField
,
170 'widget': widgets
.FullTinyMCE(attrs
={'rows': 10, 'cols': 40}),
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
186 'base': forms
.ChoiceField
,
190 'passthrough': ['initial', 'required', 'choices'],
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'),
198 (1,'1: Might have potential'),
200 (3,'3: Almost there'),
201 (4,'4: Made. Of. Awesome.')]
204 'base': forms
.CharField
,
205 'widget': widgets
.FullTinyMCE(attrs
={'rows': 10, 'cols': 40}),
210 'base': forms
.BooleanField
,
211 'label': 'Public review',
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
229 'base': forms
.IntegerField
,
230 'label': 'Set to rank',
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!',
236 'passthrough': ['min_value', 'required', 'help_text'],
239 'base': forms
.CharField
,
240 'label': 'Assign Mentor (Link ID)',
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().
269 fields
['link_id'] = 't%i' %(int(time
.time()*100))
271 fields
['link_id'] = entity
.link_id
273 # fill in the scope via call to super
274 super(View
, self
)._editPost
(request
, entity
, fields
)
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
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
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.
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'])
336 fields
= form
.cleaned_data
337 comment
= fields
['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():
345 reviewer
= entity
.scope
347 # check if the person commenting is an org_admin
348 # or a mentor for the given proposal
349 fields
= {'user': user_entity
,
354 reviewer
= org_admin_logic
.logic
.getForFields(fields
, unique
=True)
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.
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
,
389 'scope_path': entity
.key().name(),
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.
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
,
438 'subscribed_public': True}
440 context
['is_subscribed'] = review_follower_logic
.getForFields(fields
,
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)
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
476 fields
= self
._logic
.getKeyFieldNames()
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
,
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().
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(),
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
597 form
= params
['admin_review_form']
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
)
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.
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'])
638 # org admin found, try to adjust the assigned mentor
639 self
._adjustMentor
(entity
, fields
['mentor'])
642 # try to see if the rank is given and adjust the given_score if needed
643 rank
= fields
['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
655 # might be None (if Host or Developer is commenting)
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.
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
,
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
,
731 'scope_path': entity
.key().name(),
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
,
766 """Returns the default context for the review page.
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
779 context
['student_name'] = entity
.scope
.name()
782 context
['mentor_name'] = entity
.mentor
.name()
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"
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
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?
816 if mentor
.key() in possible_mentors
:
817 # show "No longer willing to mentor"
818 context
['remove_me_as_mentor'] = True
820 # show "I am willing to mentor"
821 context
['add_me_as_mentor'] = True
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)
834 context
['is_subscribed_public'] = follower_entity
.subscribed_public
835 context
['is_subscribed_private'] = follower_entity
.subscribed_private
839 def _adjustPossibleMentors(self
, entity
, mentor
, choice
):
840 """Adjusts the possible mentors list for a proposal.
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
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
)
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.
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
:
876 # try to locate the mentor
877 fields
= {'link_id': mentor_id
,
881 mentor_entity
= mentor_logic
.logic
.getForFields(fields
, unique
=True)
883 if not mentor_entity
:
884 # no mentor found, do not update
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.
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
905 - The newly created review
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)),
915 'scope_path': entity
.key().name(),
916 'author': user_logic
.logic
.getForCurrentAccount(),
918 'is_public': is_public
,
922 # add the given score if the review is not public
924 fields
['score'] = score
926 key_name
= review_logic
.getKeyNameFromFields(fields
)
928 return review_logic
.updateOrCreateFromKeyName(fields
, key_name
)
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
)