3 # Copyright 2008 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 Programs.
21 '"Daniel Hans" <daniel.m.hans@gmail.com>',
22 '"Sverre Rabbelier" <sverre@rabbelier.nl>',
23 '"Lennard de Rijk" <ljvderijk@gmail.com>',
29 from django
import forms
30 from django
import http
31 from django
.utils
.translation
import ugettext
33 from soc
.logic
import allocations
34 from soc
.logic
import cleaning
35 from soc
.logic
import dicts
36 from soc
.logic
.helper
import timeline
as timeline_helper
37 from soc
.logic
.models
import host
as host_logic
38 from soc
.logic
.models
import mentor
as mentor_logic
39 from soc
.logic
.models
import organization
as org_logic
40 from soc
.logic
.models
import org_admin
as org_admin_logic
41 from soc
.logic
.models
import org_app
as org_app_logic
42 from soc
.logic
.models
import student_proposal
as student_proposal_logic
43 from soc
.logic
.models
import program
as program_logic
44 from soc
.logic
.models
import student
as student_logic
45 from soc
.views
import helper
46 from soc
.views
import out_of_band
47 from soc
.views
.helper
import access
48 from soc
.views
.helper
import decorators
49 from soc
.views
.helper
import lists
50 from soc
.views
.helper
import redirects
51 from soc
.views
.helper
import widgets
52 from soc
.views
.models
import presence
53 from soc
.views
.models
import document
as document_view
54 from soc
.views
.models
import sponsor
as sponsor_view
55 from soc
.views
.sitemap
import sidebar
57 import soc
.cache
.logic
58 import soc
.logic
.models
.program
59 import soc
.models
.work
62 class View(presence
.View
):
63 """View methods for the Program model.
66 DEF_ACCEPTED_ORGS_MSG_FMT
= ugettext("These organizations have"
67 " been accepted into %(name)s, but they have not yet completed"
68 " their organization profile. You can still learn more about"
69 " each organization by visiting the links below.")
71 DEF_CREATED_ORGS_MSG_FMT
= ugettext("These organizations have been"
72 " accepted into %(name)s and have completed their organization"
73 " profiles. You can learn more about each organization by"
74 " visiting the links below.")
76 DEF_SLOTS_ALLOCATION_MSG
= ugettext("Use this view to assign slots.")
78 DEF_ACCEPTED_PROJECTS_MSG_FMT
= ugettext("These projects have been"
79 " accepted into %(name)s. You can learn more about each project"
80 " by visiting the links below.")
82 def __init__(self
, params
=None):
83 """Defines the fields and methods required for the base View class
84 to provide the user with list, public, create, edit and delete views.
87 params: a dict with params for this View
90 rights
= access
.Checker(params
)
91 rights
['any_access'] = ['allow']
92 rights
['show'] = ['allow']
93 rights
['create'] = [('checkSeeded', ['checkHasActiveRoleForScope',
95 rights
['edit'] = ['checkIsHostForProgram']
96 rights
['delete'] = ['checkIsDeveloper']
97 rights
['assign_slots'] = ['checkIsHostForProgram']
98 rights
['slots'] = ['checkIsHostForProgram']
99 rights
['show_duplicates'] = ['checkIsHostForProgram']
100 rights
['assigned_proposals'] = ['checkIsHostForProgram']
101 rights
['accepted_orgs'] = [('checkIsAfterEvent',
102 ['accepted_organization_announced_deadline', '__all__'])]
103 rights
['list_projects'] = [('checkIsAfterEvent',
104 ['accepted_students_announced_deadline', '__all__'])]
107 new_params
['logic'] = soc
.logic
.models
.program
.logic
108 new_params
['rights'] = rights
110 new_params
['scope_view'] = sponsor_view
111 new_params
['scope_redirect'] = redirects
.getCreateRedirect
113 new_params
['name'] = "Program"
114 new_params
['sidebar_grouping'] = 'Programs'
115 new_params
['document_prefix'] = "program"
117 new_params
['extra_dynaexclude'] = ['timeline', 'org_admin_agreement',
118 'mentor_agreement', 'student_agreement', 'slots_allocation']
122 (r
'^%(url_name)s/(?P<access_type>assign_slots)/%(key_fields)s$',
123 'soc.views.models.%(module_name)s.assign_slots',
125 (r
'^%(url_name)s/(?P<access_type>slots)/%(key_fields)s$',
126 'soc.views.models.%(module_name)s.slots',
127 'Assign slots (JSON)'),
128 (r
'^%(url_name)s/(?P<access_type>show_duplicates)/%(key_fields)s$',
129 'soc.views.models.%(module_name)s.show_duplicates',
130 'Show duplicate slot assignments'),
131 (r
'^%(url_name)s/(?P<access_type>assigned_proposals)/%(key_fields)s$',
132 'soc.views.models.%(module_name)s.assigned_proposals',
133 "Assigned proposals for multiple organizations"),
134 (r
'^%(url_name)s/(?P<access_type>accepted_orgs)/%(key_fields)s$',
135 'soc.views.models.%(module_name)s.accepted_orgs',
136 "List all accepted organizations"),
137 (r
'^%(url_name)s/(?P<access_type>list_projects)/%(key_fields)s$',
138 'soc.views.models.%(module_name)s.list_projects',
139 "List all student projects"),
142 new_params
['extra_django_patterns'] = patterns
144 new_params
['create_dynafields'] = [
146 'base': forms
.fields
.CharField
,
147 'label': 'Program Link ID',
151 # TODO add clean field to check for uniqueness in link_id and scope_path
152 new_params
['create_extra_dynaproperties'] = {
153 'description': forms
.fields
.CharField(widget
=helper
.widgets
.TinyMCE(
154 attrs
={'rows':10, 'cols':40})),
155 'accepted_orgs_msg': forms
.fields
.CharField(
156 widget
=helper
.widgets
.TinyMCE(attrs
={'rows':10, 'cols':40})),
157 'scope_path': forms
.CharField(widget
=forms
.HiddenInput
, required
=True),
158 'workflow': forms
.ChoiceField(choices
=[('gsoc','Project-based'),
159 ('ghop','Task-based')], required
=True),
163 ('org_admin_agreement_link_id', soc
.models
.work
.Work
.link_id
.help_text
,
164 ugettext('Organization Admin Agreement Document link ID')),
165 ('mentor_agreement_link_id', soc
.models
.work
.Work
.link_id
.help_text
,
166 ugettext('Mentor Agreement Document link ID')),
167 ('student_agreement_link_id', soc
.models
.work
.Work
.link_id
.help_text
,
168 ugettext('Student Agreement Document link ID')),
169 ('home_link_id', soc
.models
.work
.Work
.link_id
.help_text
,
170 ugettext('Home page Document link ID')),
175 for key
, help_text
, label
in reference_fields
:
176 result
[key
] = widgets
.ReferenceField(
177 reference_url
='document', filter=['__scoped__'],
178 filter_fields
={'prefix': new_params
['document_prefix']},
179 required
=False, label
=label
, help_text
=help_text
)
181 result
['workflow'] = forms
.CharField(widget
=widgets
.ReadOnlyInput(),
183 result
['clean'] = cleaning
.clean_refs(new_params
,
184 [i
for i
,_
,_
in reference_fields
])
186 new_params
['edit_extra_dynaproperties'] = result
188 document_references
= [
189 ('org_admin_agreement_link_id', 'org_admin_agreement',
190 lambda x
: x
.org_admin_agreement
),
191 ('mentor_agreement_link_id', 'mentor_agreement',
192 lambda x
: x
.mentor_agreement
),
193 ('student_agreement_link_id', 'student_agreement',
194 lambda x
: x
.student_agreement
),
197 new_params
['references'] = document_references
199 params
= dicts
.merge(params
, new_params
, sub_merge
=True)
201 super(View
, self
).__init
__(params
=params
)
203 def _getAcceptedOrgsList(self
, description
, params
, filter, use_cache
):
204 """Returns a list with all accepted orgs.
207 description: the description of the list
208 params: the params to use
209 filter: the filter to use
210 use_cache: whether or not to use the cache
213 logic
= params
['logic']
220 # only cache if all profiles are created
221 fun
= soc
.cache
.logic
.cache(self
._getData
)
222 entities
= fun(logic
.getModel(), filter, order
, logic
)
224 result
= dicts
.rename(params
, params
['list_params'])
225 result
['action'] = (redirects
.getHomeRedirect
, params
)
226 result
['description'] = description
227 result
['pagination'] = 'soc/list/no_pagination.html'
228 result
['data'] = entities
232 @decorators.merge_params
233 @decorators.check_access
234 def acceptedOrgs(self
, request
, access_type
,
235 page_name
=None, params
=None, filter=None, **kwargs
):
236 """See base.View.list.
240 logic
= params
['logic']
242 program_entity
= logic
.getFromKeyFieldsOr404(kwargs
)
244 fmt
= {'name': program_entity
.name
}
245 description
= self
.DEF_ACCEPTED_ORGS_MSG_FMT
% fmt
248 'status': 'accepted',
249 'scope': program_entity
,
252 from soc
.views
.models
import org_app
as org_app_view
253 aa_params
= org_app_view
.view
.getParams().copy() # accepted applications
255 # define the list redirect action to show the notification
256 del aa_params
['list_key_order']
257 aa_params
['list_action'] = (redirects
.getHomeRedirect
, aa_params
)
258 aa_params
['list_description'] = description
260 aa_list
= lists
.getListContent(request
, aa_params
, filter, idx
=0,
264 contents
.append(aa_list
)
266 use_cache
= not aa_list
# only cache if there are no aa's left
267 description
= self
.DEF_CREATED_ORGS_MSG_FMT
% fmt
269 filter['status'] = ['new', 'active']
271 from soc
.views
.models
.organization
import view
as org_view
272 ao_params
= org_view
.getParams().copy() # active orgs
273 ao_list
= self
._getAcceptedOrgsList
(description
, ao_params
,
276 contents
.append(ao_list
)
278 params
= params
.copy()
279 params
['list_msg'] = program_entity
.accepted_orgs_msg
281 return self
._list
(request
, params
, contents
, page_name
)
283 @decorators.merge_params
284 @decorators.check_access
285 def acceptedProjects(self
, request
, access_type
,
286 page_name
=None, params
=None, filter=None, **kwargs
):
287 """See base.View.list.
290 logic
= params
['logic']
292 program_entity
= logic
.getFromKeyFieldsOr404(kwargs
)
295 'status': 'accepted',
296 'program': program_entity
}
298 fmt
= {'name': program_entity
.name
}
299 description
= self
.DEF_ACCEPTED_PROJECTS_MSG_FMT
% fmt
301 from soc
.views
.models
import student_project
as sp_view
303 ap_params
= sp_view
.view
.getParams().copy() # accepted projects
304 ap_params
['list_action'] = (redirects
.getPublicRedirect
, ap_params
)
305 ap_params
['list_description'] = description
306 ap_params
['list_heading'] = 'soc/student_project/list/heading_all.html'
307 ap_params
['list_row'] = 'soc/student_project/list/row_all.html'
309 return self
.list(request
, access_type
, page_name
=page_name
,
310 params
=ap_params
, filter=filter)
312 @decorators.merge_params
313 @decorators.check_access
314 def slots(self
, request
, acces_type
, page_name
=None, params
=None, **kwargs
):
315 """Returns a JSON object with all orgs allocation.
318 request: the standard Django HTTP request object
319 access_type : the name of the access type which should be checked
320 page_name: the page name displayed in templates as page and header title
321 params: a dict with params for this View, not used
324 from django
.utils
import simplejson
326 program
= program_logic
.logic
.getFromKeyFieldsOr404(kwargs
)
327 program_slots
= program
.slots
334 query
= org_logic
.logic
.getQueryForFields(filter=filter)
335 organizations
= org_logic
.logic
.getAll(query
)
337 locked_slots
= adjusted_slots
= {}
339 if request
.method
== 'POST' and 'result' in request
.POST
:
340 result
= request
.POST
['result']
341 submit
= request
.GET
.get('submit')
342 load
= request
.GET
.get('load')
343 stored
= program
.slots_allocation
348 from_json
= simplejson
.loads(result
)
350 locked_slots
= dicts
.groupDictBy(from_json
, 'locked', 'slots')
353 program
.slots_allocation
= result
360 for org
in organizations
:
361 orgs
[org
.link_id
] = org
362 applications
[org
.link_id
] = org
.nr_applications
363 max[org
.link_id
] = min(org
.nr_mentors
, org
.slots_desired
)
365 max_slots_per_org
= program
.max_slots
366 min_slots_per_org
= program
.min_slots
369 allocator
= allocations
.Allocator(orgs
.keys(), applications
, max,
370 program_slots
, max_slots_per_org
,
371 min_slots_per_org
, algorithm
)
373 result
= allocator
.allocate(locked_slots
)
377 # TODO: remove adjustment here and in the JS
378 for link_id
, count
in result
.iteritems():
383 'locked': locked_slots
.get(link_id
, 0),
384 'adjustment': adjusted_slots
.get(link_id
, 0),
387 return self
.json(request
, data
)
389 @decorators.merge_params
390 @decorators.check_access
391 def assignSlots(self
, request
, access_type
, page_name
=None,
392 params
=None, **kwargs
):
393 """View that allows to assign slots to orgs.
396 from soc
.views
.models
import organization
as organization_view
398 org_params
= organization_view
.view
.getParams().copy()
399 org_params
['list_template'] = 'soc/program/allocation/allocation.html'
400 org_params
['list_heading'] = 'soc/program/allocation/heading.html'
401 org_params
['list_row'] = 'soc/program/allocation/row.html'
402 org_params
['list_pagination'] = 'soc/list/no_pagination.html'
404 program
= program_logic
.logic
.getFromKeyFieldsOr404(kwargs
)
406 description
= self
.DEF_SLOTS_ALLOCATION_MSG
413 content
= self
._getAcceptedOrgsList
(description
, org_params
, filter, False)
417 return_url
= "http://%(host)s%(index)s" % {
418 'host' : os
.environ
['HTTP_HOST'],
419 'index': redirects
.getSlotsRedirect(program
, params
)
423 'total_slots': program
.slots
,
425 'uses_slot_allocator': True,
426 'return_url': return_url
,
429 return self
._list
(request
, org_params
, contents
, page_name
, context
)
431 @decorators.merge_params
432 @decorators.check_access
433 def showDuplicates(self
, request
, access_type
, page_name
=None,
434 params
=None, **kwargs
):
435 """View in which a host can see which students have been assigned
438 For params see base.view.Public().
441 from django
.utils
import simplejson
443 from soc
.logic
.models
.proposal_duplicates
import logic
as duplicates_logic
445 program_entity
= program_logic
.logic
.getFromKeyFieldsOr404(kwargs
)
447 if request
.POST
and request
.POST
.get('result'):
448 # store result in the datastore
449 fields
= {'link_id': program_entity
.link_id
,
450 'scope': program_entity
,
451 'scope_path': program_entity
.key().id_or_name(),
452 'json_representation' : request
.POST
['result']
454 key_name
= duplicates_logic
.getKeyNameFromFields(fields
)
455 duplicates_logic
.updateOrCreateFromKeyName(fields
, key_name
)
457 response
= simplejson
.dumps({'status': 'done'})
458 return http
.HttpResponse(response
)
460 context
= helper
.responses
.getUniversalContext(request
)
461 helper
.responses
.useJavaScript(context
, params
['js_uses_all'])
462 context
['uses_duplicates'] = True
463 context
['uses_json'] = True
464 context
['page_name'] = page_name
466 # get all orgs for this program who are active and have slots assigned
467 fields
= {'scope': program_entity
,
471 query
= org_logic
.logic
.getQueryForFields(fields
)
474 'nr_of_orgs': query
.count(),
475 'program_key': program_entity
.key().id_or_name()}
476 json
= simplejson
.dumps(to_json
)
477 context
['info'] = json
478 context
['offset_length'] = 10
480 fields
= {'link_id': program_entity
.link_id
,
481 'scope': program_entity
}
482 duplicates
= duplicates_logic
.getForFields(fields
, unique
=True)
485 # we have stored information
486 # pylint: disable-msg=E1103
487 context
['duplicate_cache_content'] = duplicates
.json_representation
488 context
['date_of_calculation'] = duplicates
.calculated_on
490 # no information stored
491 context
['duplicate_cache_content'] = simplejson
.dumps({})
493 template
= 'soc/program/show_duplicates.html'
495 return helper
.responses
.respond(request
, template
=template
, context
=context
)
497 @decorators.merge_params
498 @decorators.check_access
499 def assignedProposals(self
, request
, access_type
, page_name
=None,
500 params
=None, filter=None, **kwargs
):
501 """Returns a JSON dict containing all the proposals that would have
502 a slot assigned for a specific set of orgs.
504 The request.GET limit and offset determines how many and which
505 organizations should be returned.
507 For params see base.View.public().
509 Returns: JSON object with a collection of orgs and proposals. Containing
510 identification information and contact information.
513 get_dict
= request
.GET
515 if not (get_dict
.get('limit') and get_dict
.get('offset')):
516 return self
.json(request
, {})
519 limit
= max(0, int(get_dict
['limit']))
520 offset
= max(0, int(get_dict
['offset']))
522 return self
.json(request
, {})
524 program_entity
= program_logic
.logic
.getFromKeyFieldsOr404(kwargs
)
526 fields
= {'scope': program_entity
,
530 org_entities
= org_logic
.logic
.getForFields(fields
,
531 limit
=limit
, offset
=offset
)
536 # for each org get the proposals who will be assigned a slot
537 for org
in org_entities
:
539 org_data
= {'name': org
.name
}
541 fields
= {'scope': org
,
545 org_admin
= org_admin_logic
.logic
.getForFields(fields
, unique
=True)
548 # pylint: disable-msg=E1103
549 org_data
['admin_name'] = org_admin
.name()
550 org_data
['admin_email'] = org_admin
.email
552 proposals
= student_proposal_logic
.logic
.getProposalsToBeAcceptedForOrg(
553 org
, step_size
=program_entity
.max_slots
)
556 # nothing to accept, next organization
559 # store information about the org
560 orgs_data
[org
.key().id_or_name()] = org_data
562 # store each proposal in the dictionary
563 for proposal
in proposals
:
564 student_entity
= proposal
.scope
566 proposals_data
.append(
567 {'key_name': proposal
.key().id_or_name(),
568 'proposal_title': proposal
.title
,
569 'student_key': student_entity
.key().id_or_name(),
570 'student_name': student_entity
.name(),
571 'student_contact': student_entity
.email
,
572 'org_key': org
.key().id_or_name()
575 # return all the data in JSON format
576 data
= {'orgs': orgs_data
,
577 'proposals': proposals_data
}
579 return self
.json(request
, data
)
581 def _editPost(self
, request
, entity
, fields
):
582 """See base._editPost().
585 super(View
, self
)._editPost
(request
, entity
, fields
)
588 # there is no existing entity so create a new timeline
589 fields
['timeline'] = self
._createTimelineForType
(fields
)
591 # use the timeline from the entity
592 fields
['timeline'] = entity
.timeline
594 def _createTimelineForType(self
, fields
):
595 """Creates and stores a timeline model for the given type of program.
598 workflow
= fields
['workflow']
600 timeline_logic
= program_logic
.logic
.TIMELINE_LOGIC
[workflow
]
602 properties
= timeline_logic
.getKeyFieldsFromFields(fields
)
603 key_name
= timeline_logic
.getKeyNameFromFields(properties
)
605 properties
['scope'] = fields
['scope']
607 timeline
= timeline_logic
.updateOrCreateFromKeyName(properties
, key_name
)
610 @decorators.merge_params
611 def getExtraMenus(self
, id, user
, params
=None):
612 """Returns the extra menu's for this view.
614 A menu item is generated for each program that is currently
615 running. The public page for each program is added as menu item,
616 as well as all public documents for that program.
619 params: a dict with params for this View.
622 logic
= params
['logic']
623 rights
= params
['rights']
625 # only get all invisible and visible programs
626 fields
= {'status': ['invisible', 'visible']}
627 entities
= logic
.getForFields(fields
)
631 rights
.setCurrentUser(id, user
)
633 for entity
in entities
:
636 if entity
.status
== 'visible':
637 # show the documents for this program, even for not logged in users
638 items
+= document_view
.view
.getMenusForScope(entity
, params
)
639 items
+= self
._getTimeDependentEntries
(entity
, params
, id, user
)
642 # check if the current user is a host for this program
643 rights
.doCachedCheck('checkIsHostForProgram',
644 {'scope_path': entity
.scope_path
,
645 'link_id': entity
.link_id
}, [])
647 if entity
.status
== 'invisible':
648 # still add the document links so hosts can see how it looks like
649 items
+= document_view
.view
.getMenusForScope(entity
, params
)
650 items
+= self
._getTimeDependentEntries
(entity
, params
, id, user
)
652 items
+= [(redirects
.getReviewOverviewRedirect(
653 entity
, {'url_name': 'org_app'}),
654 "Review Organization Applications", 'any_access')]
655 # add link to edit Program Profile
656 items
+= [(redirects
.getEditRedirect(entity
, params
),
657 'Edit Program Profile', 'any_access')]
658 # add link to Assign Slots
659 items
+= [(redirects
.getAssignSlotsRedirect(entity
, params
),
660 'Assign Slots', 'any_access')]
661 # add link to Show Duplicate project assignments
662 items
+= [(redirects
.getShowDuplicatesRedirect(entity
, params
),
663 'Show Duplicate Project Assignments', 'any_access')]
664 # add link to edit Program Timeline
665 items
+= [(redirects
.getEditRedirect(entity
, {'url_name': 'timeline'}),
666 "Edit Program Timeline", 'any_access')]
667 # add link to create a new Program Document
668 items
+= [(redirects
.getCreateDocumentRedirect(entity
, 'program'),
669 "Create a New Document", 'any_access')]
670 # add link to list all Program Document
671 items
+= [(redirects
.getListDocumentsRedirect(entity
, 'program'),
672 "List Documents", 'any_access')]
674 except out_of_band
.Error
:
677 items
= sidebar
.getSidebarMenu(id, user
, items
, params
=params
)
682 menu
['heading'] = entity
.short_name
683 menu
['items'] = items
684 menu
['group'] = 'Programs'
689 def _getTimeDependentEntries(self
, program_entity
, params
, id, user
):
690 """Returns a list with time dependent menu items.
694 #TODO(ljvderijk) Add more timeline dependent entries
695 timeline_entity
= program_entity
.timeline
697 if timeline_helper
.isActivePeriod(timeline_entity
, 'org_signup'):
698 # add the organization signup link
700 (redirects
.getApplyRedirect(program_entity
, {'url_name': 'org_app'}),
701 "Apply to become an Organization", 'any_access')]
703 if user
and timeline_helper
.isAfterEvent(timeline_entity
,
707 'scope': program_entity
,
710 if org_app_logic
.logic
.getForFields(filter, unique
=True):
711 # add the 'List my Organization Applications' link
713 (redirects
.getListSelfRedirect(program_entity
,
714 {'url_name' : 'org_app'}),
715 "List My Organization Applications", 'any_access')]
717 # get the student entity for this user and program
718 filter = {'user': user
,
719 'scope': program_entity
,
721 student_entity
= student_logic
.logic
.getForFields(filter, unique
=True)
724 items
+= self
._getStudentEntries
(program_entity
, student_entity
,
727 # get mentor and org_admin entity for this user and program
728 filter = {'user': user
,
729 'program': program_entity
,
731 mentor_entity
= mentor_logic
.logic
.getForFields(filter, unique
=True)
732 org_admin_entity
= org_admin_logic
.logic
.getForFields(filter, unique
=True)
734 if mentor_entity
or org_admin_entity
:
735 items
+= self
._getOrganizationEntries
(program_entity
, org_admin_entity
,
736 mentor_entity
, params
, id, user
)
738 if user
and not (student_entity
or mentor_entity
or org_admin_entity
):
739 if timeline_helper
.isActivePeriod(timeline_entity
, 'student_signup'):
740 # this user does not have a role yet for this program
741 items
+= [('/student/apply/%s' % (program_entity
.key().id_or_name()),
742 "Register as a Student", 'any_access')]
744 deadline
= 'accepted_organization_announced_deadline'
746 if timeline_helper
.isAfterEvent(timeline_entity
, deadline
):
747 url
= redirects
.getAcceptedOrgsRedirect(program_entity
, params
)
748 # add a link to list all the organizations
749 items
+= [(url
, "List participating Organizations", 'any_access')]
751 if not student_entity
:
752 # add apply to become a mentor link
753 items
+= [('/org/apply_mentor/%s' % (program_entity
.key().id_or_name()),
754 "Apply to become a Mentor", 'any_access')]
756 deadline
= 'accepted_students_announced_deadline'
758 if timeline_helper
.isAfterEvent(timeline_entity
, deadline
):
759 items
+= [(redirects
.getListProjectsRedirect(program_entity
,
760 {'url_name':'program'}),
761 "List all student projects", 'any_access')]
765 def _getStudentEntries(self
, program_entity
, student_entity
,
767 """Returns a list with menu items for students in a specific program.
772 timeline_entity
= program_entity
.timeline
774 if timeline_helper
.isActivePeriod(timeline_entity
, 'student_signup'):
775 items
+= [('/student_proposal/list_orgs/%s' % (
776 student_entity
.key().id_or_name()),
777 "Submit your Student Proposal", 'any_access')]
779 if timeline_helper
.isAfterEvent(timeline_entity
, 'student_signup_start'):
780 items
+= [(redirects
.getListSelfRedirect(student_entity
,
781 {'url_name':'student_proposal'}),
782 "List my Student Proposals", 'any_access')]
784 items
+= [(redirects
.getEditRedirect(student_entity
,
785 {'url_name': 'student'}),
786 "Edit my Student Profile", 'any_access')]
788 if timeline_helper
.isAfterEvent(timeline_entity
,
789 'accepted_students_announced_deadline'):
790 # add a link to show all projects
791 items
+= [(redirects
.getListProjectsRedirect(program_entity
,
792 {'url_name':'student'}),
793 "List my Student Projects", 'any_access')]
797 def _getOrganizationEntries(self
, program_entity
, org_admin_entity
,
798 mentor_entity
, params
, id, user
):
799 """Returns a list with menu items for org admins and mentors in a
803 # TODO(ljvderijk) think about adding specific org items like submit review
812 accepted_orgs
= decorators
.view(view
.acceptedOrgs
)
813 list_projects
= decorators
.view(view
.acceptedProjects
)
814 admin
= decorators
.view(view
.admin
)
815 assign_slots
= decorators
.view(view
.assignSlots
)
816 assigned_proposals
= decorators
.view(view
.assignedProposals
)
817 create
= decorators
.view(view
.create
)
818 delete
= decorators
.view(view
.delete
)
819 edit
= decorators
.view(view
.edit
)
820 list = decorators
.view(view
.list)
821 public
= decorators
.view(view
.public
)
822 export
= decorators
.view(view
.export
)
823 show_duplicates
= decorators
.view(view
.showDuplicates
)
824 slots
= decorators
.view(view
.slots
)
825 home
= decorators
.view(view
.home
)
826 pick
= decorators
.view(view
.pick
)