Added feed_url to StudentProject.
[Melange.git] / app / soc / views / models / student_project.py
blob8889e8c31d7755e1d36d860e780fd2d77cdd48c3
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 Project.
18 """
20 __authors__ = [
21 '"Lennard de Rijk" <ljvderijk@gmail.com>',
25 import time
27 from django import forms
29 from soc.logic import cleaning
30 from soc.logic import dicts
31 from soc.logic.models import mentor as mentor_logic
32 from soc.logic.models.organization import logic as org_logic
33 from soc.logic.models.org_admin import logic as org_admin_logic
34 from soc.logic.models import student as student_logic
35 from soc.logic.models.student_project import logic as project_logic
36 from soc.views import out_of_band
37 from soc.views.helper import access
38 from soc.views.helper import decorators
39 from soc.views.helper import dynaform
40 from soc.views.helper import forms as forms_helper
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 responses
45 from soc.views.models import base
46 from soc.views.models import organization as org_view
48 import soc.logic.models.student_project
51 class View(base.View):
52 """View methods for the Student Project model.
53 """
55 def __init__(self, params=None):
56 """Defines the fields and methods required for the base View class
57 to provide the user with list, public, create, edit and delete views.
59 Params:
60 params: a dict with params for this View
61 """
63 rights = access.Checker(params)
64 rights['create'] = ['checkIsDeveloper']
65 rights['edit'] = ['checkIsDeveloper']
66 rights['delete'] = ['checkIsDeveloper']
67 rights['show'] = ['allow']
68 rights['list'] = ['checkIsDeveloper']
69 rights['manage'] = [('checkHasActiveRoleForScope',
70 org_admin_logic),
71 ('checkStudentProjectHasStatus', ['accepted', 'mid_term_passed'])]
72 rights['manage_overview'] = [('checkHasActiveRoleForScope',
73 org_admin_logic)]
74 # TODO lack of better name here!
75 rights['st_edit'] = ['checkIsMyStudentProject',
76 ('checkStudentProjectHasStatus',
77 ['accepted', 'mid_term_passed', 'passed'])
80 new_params = {}
81 new_params['logic'] = soc.logic.models.student_project.logic
82 new_params['rights'] = rights
83 new_params['name'] = "Student Project"
84 new_params['url_name'] = "student_project"
85 new_params['sidebar_grouping'] = 'Students'
87 new_params['scope_view'] = org_view
88 new_params['scope_redirect'] = redirects.getCreateRedirect
90 new_params['no_create_with_key_fields'] = True
92 new_params['extra_dynaexclude'] = ['program', 'status', 'link_id',
93 'mentor', 'student']
95 new_params['create_extra_dynaproperties'] = {
96 'scope_path': forms.CharField(widget=forms.HiddenInput,
97 required=True),
98 'student_id': forms.CharField(label='Student Link ID',
99 required=True),
100 'mentor_id': forms.CharField(label='Mentor Link ID',
101 required=True),
102 'clean_abstract': cleaning.clean_content_length('abstract'),
103 'clean_student': cleaning.clean_link_id('student'),
104 'clean_mentor': cleaning.clean_link_id('mentor'),
105 'clean_additional_info': cleaning.clean_url('additional_info'),
106 'clean_feed_url': cleaning.clean_feed_url,
107 'clean': cleaning.validate_student_project('scope_path',
108 'mentor_id', 'student_id')
111 new_params['edit_extra_dynaproperties'] = {
112 'link_id': forms.CharField(widget=forms.HiddenInput),
115 patterns = [
116 (r'^%(url_name)s/(?P<access_type>manage_overview)/%(scope)s$',
117 'soc.views.models.%(module_name)s.manage_overview',
118 'Overview of %(name_plural)s to Manage for'),
119 (r'^%(url_name)s/(?P<access_type>manage)/%(key_fields)s$',
120 'soc.views.models.%(module_name)s.manage',
121 'Manage %(name)s'),
122 (r'^%(url_name)s/(?P<access_type>st_edit)/%(key_fields)s$',
123 'soc.views.models.%(module_name)s.st_edit',
124 'Edit my %(name)s'),
127 new_params['extra_django_patterns'] = patterns
129 new_params['edit_template'] = 'soc/student_project/edit.html'
131 # TODO(ljvderijk) list all projects for one student
132 # TODO(ljvderijk) add manage item to org menu for admins
134 params = dicts.merge(params, new_params)
136 super(View, self).__init__(params=params)
138 # create the form that students will use to edit their projects
139 dynaproperties = {
140 'clean_abstract': cleaning.clean_content_length('abstract'),
141 'clean_additional_info': cleaning.clean_url('additional_info'),
142 'clean_feed_url': cleaning.clean_feed_url,
145 student_edit_form = dynaform.newDynaForm(
146 dynabase = params['dynabase'],
147 dynamodel = params['logic'].getModel(),
148 dynaexclude = params['create_dynaexclude'],
149 dynaproperties = dynaproperties,
152 params['student_edit_form'] = student_edit_form
155 def _editGet(self, request, entity, form):
156 """See base.View._editGet().
159 form.fields['link_id'].initial = entity.link_id
160 form.fields['student_id'].initial = entity.student.link_id
161 form.fields['mentor_id'].initial = entity.mentor.link_id
163 return super(View, self)._editGet(request, entity, form)
165 def _editPost(self, request, entity, fields):
166 """See base.View._editPost().
169 if not entity:
170 fields['link_id'] = 't%i' % (int(time.time()*100))
171 else:
172 fields['link_id'] = entity.link_id
174 # fill in the scope via call to super
175 super(View, self)._editPost(request, entity, fields)
177 # editing a project so set the program, student and mentor field
178 if entity:
179 organization = entity.scope
180 else:
181 organization = fields['scope']
183 fields['program'] = organization.scope
185 filter = {'scope': fields['program'],
186 'link_id': fields['student_id']}
187 fields['student'] = student_logic.logic.getForFields(filter, unique=True)
189 filter = {'scope': organization,
190 'link_id': fields['mentor_id'],
191 'status': 'active'}
192 fields['mentor'] = mentor_logic.logic.getForFields(filter, unique=True)
194 @decorators.merge_params
195 @decorators.check_access
196 def manage(self, request, access_type,
197 page_name=None, params=None, **kwargs):
198 """View that allows Organization Admins to manage their Student Projects.
200 For params see base.View().public()
203 try:
204 entity = self._logic.getFromKeyFieldsOr404(kwargs)
205 except out_of_band.Error, error:
206 return responses.errorResponse(
207 error, request, template=params['error_public'])
209 # get the context for this webpage
210 context = responses.getUniversalContext(request)
211 responses.useJavaScript(context, params['js_uses_all'])
212 context['page_name'] = "%s '%s' from %s" % (page_name, entity.title,
213 entity.student.name())
215 # use another template and make the cancel button goes to the public view
216 params['edit_template'] = 'soc/student_project/manage.html'
217 params['edit_cancel_redirect'] = redirects.getManageOverviewRedirect(
218 entity.scope, params)
220 # get all mentors for this organization
221 fields = {'scope': entity.scope,
222 'status': 'active'}
223 mentors = mentor_logic.logic.getForFields(fields)
225 choices = [(mentor.link_id,'%s (%s)' %(mentor.name(), mentor.link_id))
226 for mentor in mentors]
228 # create the form that org admins will use to reassign a mentor
229 dynafields = [
230 {'name': 'mentor_id',
231 'base': forms.ChoiceField,
232 'label': 'Mentor',
233 'required': True,
234 'passthrough': ['required', 'choices', 'label'],
235 'choices': choices,
238 dynaproperties = params_helper.getDynaFields(dynafields)
240 mentor_edit_form = dynaform.newDynaForm(
241 dynabase = params['dynabase'],
242 dynaproperties = dynaproperties,
245 params['mentor_edit_form'] = mentor_edit_form
247 if request.POST:
248 return self.managePost(request, context, params, entity, **kwargs)
249 else: #request.GET
250 return self.manageGet(request, context, params, entity, **kwargs)
252 def manageGet(self, request, context, params, entity, **kwargs):
253 """Handles the GET request for the project's manage page.
255 Args:
256 entity: the student project entity
257 rest: see base.View.public()
260 # populate form with the current mentor
261 initial = {'mentor_id': entity.mentor.link_id}
262 form = params['mentor_edit_form'](initial=initial)
264 return self._constructResponse(request, entity, context, form, params)
266 def managePost(self, request, context, params, entity, **kwargs):
267 """Handles the POST request for the project's manage page.
269 Args:
270 entity: the student project entity
271 rest: see base.View.public()
274 form = params['mentor_edit_form'](request.POST)
276 if not form.is_valid():
277 return self._constructResponse(request, entity, context, form, params)
279 _, fields = forms_helper.collectCleanedFields(form)
281 # get the mentor from the form
282 fields = {'link_id': fields['mentor_id'],
283 'scope': entity.scope,
284 'status': 'active'}
285 mentor = mentor_logic.logic.getForFields(fields, unique=True)
287 # update the project with the assigned mentor
288 fields = {'mentor': mentor}
289 project_logic.updateEntityProperties(entity, fields)
291 return self.manageGet(request, context, params, entity)
293 @decorators.merge_params
294 @decorators.check_access
295 def manageOverview(self, request, access_type,
296 page_name=None, params=None, **kwargs):
297 """View that allows Organization Admins to see an overview of
298 their Organization's Student Projects.
300 For params see base.View().public()
303 # make sure the organization exists
304 org_entity = org_logic.getFromKeyNameOr404(kwargs['scope_path'])
305 fields = {'scope': org_entity}
307 # get the context for this webpage
308 context = responses.getUniversalContext(request)
309 responses.useJavaScript(context, params['js_uses_all'])
310 context['page_name'] = '%s %s' % (page_name, org_entity.name)
312 list_params = params.copy()
314 #list all active projects
315 fields['status'] = ['accepted', 'mid_term_passed']
316 active_params = list_params.copy()
317 active_params['list_description'] = \
318 'List of all active %(name_plural)s' % list_params
319 active_params['list_action'] = (redirects.getManageRedirect, list_params)
321 active_list = lists.getListContent(
322 request, active_params, fields, idx=0)
324 # list all failed projects
325 fields['status'] = ['mid_term_failed', 'final_failed']
326 failed_params = list_params.copy()
327 failed_params['list_description'] = ('List of all failed %(name_plural)s, '
328 'these cannot be managed.') % list_params
329 failed_params['list_action'] = (redirects.getPublicRedirect, list_params)
331 failed_list = lists.getListContent(
332 request, failed_params, fields, idx=1, need_content=True)
334 #list all completed projects
335 fields['status'] = ['passed']
336 completed_params = list_params.copy()
337 completed_params['list_description'] = ('List of %(name_plural)s that have '
338 'successfully completed the program, '
339 'these cannot be managed.' % list_params)
340 completed_params['list_action'] = (redirects.getPublicRedirect, list_params)
342 completed_list = lists.getListContent(
343 request, completed_params, fields, idx=2, need_content=True)
345 # always show the list with active projects
346 content = [active_list]
348 if failed_list != None:
349 # do not show empty failed list
350 content.append(failed_list)
352 if completed_list != None:
353 # do not show empty completed list
354 content.append(completed_list)
356 # call the _list method from base to display the list
357 return self._list(request, list_params, content,
358 context['page_name'], context)
360 @decorators.merge_params
361 @decorators.check_access
362 def stEdit(self, request, access_type,
363 page_name=None, params=None, **kwargs):
364 """View that allows students to edit information about their project.
366 For params see base.View().public()
369 try:
370 entity = self._logic.getFromKeyFieldsOr404(kwargs)
371 except out_of_band.Error, error:
372 return responses.errorResponse(
373 error, request, template=params['error_public'])
375 # get the context for this webpage
376 context = responses.getUniversalContext(request)
377 responses.useJavaScript(context, params['js_uses_all'])
378 context['page_name'] = page_name
379 # cancel should go to the public view
380 params['edit_cancel_redirect'] = redirects.getPublicRedirect(entity, params)
382 if request.POST:
383 return self.stEditPost(request, context, params, entity, **kwargs)
384 else: #request.GET
385 return self.stEditGet(request, context, params, entity, **kwargs)
387 def stEditGet(self, request, context, params, entity, **kwargs):
388 """Handles the GET request for the student's edit page.
390 Args:
391 entity: the student project entity
392 rest: see base.View.public()
395 # populate form with the existing entity
396 form = params['student_edit_form'](instance=entity)
398 return self._constructResponse(request, entity, context, form, params)
400 def stEditPost(self, request, context, params, entity, **kwargs):
401 """Handles the POST request for the student's edit page.
403 Args:
404 entity: the student project entity
405 rest: see base.View.public()
408 form = params['student_edit_form'](request.POST)
410 if not form.is_valid():
411 return self._constructResponse(request, entity, context, form, params)
413 _, fields = forms_helper.collectCleanedFields(form)
415 project_logic.updateEntityProperties(entity, fields)
417 return self.stEditGet(request, context, params, entity, **kwargs)
420 view = View()
422 admin = decorators.view(view.admin)
423 create = decorators.view(view.create)
424 delete = decorators.view(view.delete)
425 edit = decorators.view(view.edit)
426 list = decorators.view(view.list)
427 manage = decorators.view(view.manage)
428 manage_overview = decorators.view(view.manageOverview)
429 public = decorators.view(view.public)
430 st_edit = decorators.view(view.stEdit)
431 export = decorators.view(view.export)
432 pick = decorators.view(view.pick)