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 Organizations.
21 '"Augie Fackler" <durin42@gmail.com>',
22 '"Sverre Rabbelier" <sverre@rabbelier.nl>',
23 '"Lennard de Rijk" <ljvderijk@gmail.com>',
29 from django
import forms
30 from django
.utils
.translation
import ugettext
32 from soc
.logic
import cleaning
33 from soc
.logic
import dicts
34 from soc
.logic
import accounts
35 from soc
.logic
.helper
import timeline
as timeline_helper
36 from soc
.logic
.models
import mentor
as mentor_logic
37 from soc
.logic
.models
import organization
as org_logic
38 from soc
.logic
.models
import org_admin
as org_admin_logic
39 from soc
.logic
.models
import org_app
as org_app_logic
40 from soc
.logic
.models
import user
as user_logic
41 from soc
.views
import helper
42 from soc
.views
import out_of_band
43 from soc
.views
.helper
import access
44 from soc
.views
.helper
import decorators
45 from soc
.views
.helper
import dynaform
46 from soc
.views
.helper
import lists
47 from soc
.views
.helper
import redirects
48 from soc
.views
.helper
import widgets
49 from soc
.views
.models
import group
51 import soc
.models
.organization
52 import soc
.logic
.models
.organization
54 class View(group
.View
):
55 """View methods for the Organization model.
58 DEF_ACCEPTED_PROJECTS_MSG_FMT
= ugettext("These projects have"
59 " been accepted into %s. You can learn more about"
60 " each project by visiting the links below.")
62 def __init__(self
, params
=None):
63 """Defines the fields and methods required for the base View class
64 to provide the user with list, public, create, edit and delete views.
67 original_params: a dict with params for this View
70 from soc
.views
.models
import program
as program_view
72 rights
= access
.Checker(params
)
73 rights
['any_access'] = ['allow']
74 rights
['show'] = ['allow']
75 rights
['create'] = ['checkIsDeveloper']
76 rights
['edit'] = [('checkHasActiveRoleForKeyFieldsAsScope',
77 org_admin_logic
.logic
,),
78 ('checkGroupIsActiveForLinkId', org_logic
.logic
)]
79 rights
['delete'] = ['checkIsDeveloper']
80 rights
['home'] = ['allow']
81 rights
['public_list'] = ['allow']
82 rights
['apply_mentor'] = ['checkIsUser']
83 rights
['list_requests'] = [('checkHasActiveRoleForKeyFieldsAsScope',
84 org_admin_logic
.logic
)]
85 rights
['list_roles'] = [('checkHasActiveRoleForKeyFieldsAsScope',
86 org_admin_logic
.logic
)]
87 rights
['applicant'] = [('checkIsApplicationAccepted',
89 rights
['list_proposals'] = [('checkHasAny', [
90 [('checkHasActiveRoleForKeyFieldsAsScope', [org_admin_logic
.logic
]),
91 ('checkHasActiveRoleForKeyFieldsAsScope', [mentor_logic
.logic
])]
95 new_params
['logic'] = soc
.logic
.models
.organization
.logic
96 new_params
['rights'] = rights
98 new_params
['scope_view'] = program_view
99 new_params
['scope_redirect'] = redirects
.getCreateRedirect
101 new_params
['name'] = "Organization"
102 new_params
['url_name'] = "org"
103 new_params
['document_prefix'] = "org"
104 new_params
['sidebar_grouping'] = 'Organizations'
106 new_params
['public_template'] = 'soc/organization/public.html'
107 new_params
['list_row'] = 'soc/organization/list/row.html'
108 new_params
['list_heading'] = 'soc/organization/list/heading.html'
109 new_params
['home_template'] = 'soc/organization/home.html'
111 new_params
['application_logic'] = org_app_logic
112 new_params
['group_applicant_url'] = True
113 new_params
['sans_link_id_public_list'] = True
115 new_params
['extra_dynaexclude'] = ['slots', 'slots_calculated',
116 'nr_applications', 'nr_mentors']
121 (r
'^%(url_name)s/(?P<access_type>apply_mentor)/%(scope)s$',
122 'soc.views.models.%(module_name)s.apply_mentor',
123 "List of all %(name_plural)s you can apply to"),
124 (r
'^%(url_name)s/(?P<access_type>list_proposals)/%(key_fields)s$',
125 'soc.views.models.%(module_name)s.list_proposals',
126 "List of all Student Proposals for this %(name)s"),
129 new_params
['extra_django_patterns'] = patterns
131 new_params
['create_dynafields'] = [
133 'base': forms
.fields
.CharField
,
134 'label': 'Organization Link ID',
138 new_params
['create_extra_dynaproperties'] = {
139 'scope_path': forms
.CharField(widget
=forms
.HiddenInput
,
141 'description': forms
.fields
.CharField(
142 widget
=helper
.widgets
.FullTinyMCE(
143 attrs
={'rows': 25, 'cols': 100})),
144 'contrib_template': forms
.fields
.CharField(
145 widget
=helper
.widgets
.FullTinyMCE(
146 attrs
={'rows': 25, 'cols': 100})),
147 'clean_description': cleaning
.clean_html_content('description'),
148 'clean_contrib_template': cleaning
.clean_html_content(
150 'clean_ideas': cleaning
.clean_url('ideas'),
151 'clean': cleaning
.validate_new_group('link_id', 'scope_path',
152 soc
.logic
.models
.organization
, org_app_logic
)
155 new_params
['edit_extra_dynaproperties'] = {
156 'clean': cleaning
.clean_refs(new_params
, ['home_link_id'])
159 params
= dicts
.merge(params
, new_params
)
161 super(View
, self
).__init
__(params
=params
)
163 # create and store the special form for applicants
165 'link_id': forms
.CharField(widget
=widgets
.ReadOnlyInput(),
167 'clean_link_id': cleaning
.clean_link_id('link_id')
170 applicant_create_form
= dynaform
.extendDynaForm(
171 dynaform
= self
._params
['create_form'],
172 dynaproperties
= updated_fields
)
174 self
._params
['applicant_create_form'] = applicant_create_form
176 @decorators.merge_params
177 @decorators.check_access
178 def applyMentor(self
, request
, access_type
,
179 page_name
=None, params
=None, **kwargs
):
180 """Shows a list of all organizations and you can choose one to
181 apply to become a mentor.
184 request: the standard Django HTTP request object
185 access_type : the name of the access type which should be checked
186 page_name: the page name displayed in templates as page and header title
187 params: a dict with params for this View
188 kwargs: the Key Fields for the specified entity
191 list_params
= params
.copy()
192 list_params
['list_action'] = (redirects
.getRequestRedirectForRole
, 'mentor')
193 list_params
['list_description'] = ugettext('Choose an Organization which '
194 'you want to become a Mentor for.')
196 filter = {'scope_path': kwargs
['scope_path'],
199 return self
.list(request
, access_type
,
200 page_name
, params
=list_params
, filter=filter)
202 @decorators.merge_params
203 @decorators.check_access
204 def listProposals(self
, request
, access_type
,
205 page_name
=None, params
=None, **kwargs
):
206 """Lists all proposals for the organization given in kwargs.
208 For params see base.View.public().
211 from soc
.logic
.models
.ranker_root
import logic
as ranker_root_logic
212 from soc
.logic
.models
import student_proposal
as sp_logic
213 from soc
.models
import student_proposal
214 from soc
.views
.helper
import list_info
as list_info_helper
215 from soc
.views
.models
import student_proposal
as student_proposal_view
218 org_entity
= self
._logic
.getFromKeyFieldsOr404(kwargs
)
219 except out_of_band
.Error
, error
:
220 return helper
.responses
.errorResponse(
221 error
, request
, template
=params
['error_public'])
224 context
['entity'] = org_entity
226 list_params
= student_proposal_view
.view
.getParams().copy()
227 list_params
['list_template'] = 'soc/student_proposal/list_for_org.html'
228 list_params
['list_key_order'] = [
229 'title', 'abstract', 'content', 'additional_info', 'mentor',
230 'possible_mentors', 'score', 'status', 'created_on',
233 ranked_params
= list_params
.copy()# ranked proposals
234 ranked_params
['list_row'] = ('soc/%(module_name)s/list/'
235 'detailed_row.html' % list_params
)
236 ranked_params
['list_heading'] = ('soc/%(module_name)s/list/'
237 'detailed_heading.html' % list_params
)
238 ranked_params
['list_description'] = '%s already under review sent to %s' % (
239 ranked_params
['name_plural'], org_entity
.name
)
240 ranked_params
['list_action'] = (redirects
.getReviewRedirect
, ranked_params
)
242 # TODO(ljvderijk) once sorting with IN operator is fixed,
243 # make this list show more
244 filter = {'org': org_entity
,
247 # order by descending score
250 prop_list
= lists
.getListContent(
251 request
, ranked_params
, filter, order
=order
, idx
=0)
253 proposals
= prop_list
['data']
255 # get a list of scores
256 scores
= [[proposal
.score
] for proposal
in proposals
]
258 # retrieve the ranker
259 fields
= {'link_id': student_proposal
.DEF_RANKER_NAME
,
262 ranker_root
= ranker_root_logic
.getForFields(fields
, unique
=True)
263 ranker
= ranker_root_logic
.getRootFromEntity(ranker_root
)
265 # retrieve the ranks for these scores
266 ranks
= [rank
+1 for rank
in ranker
.FindRanks(scores
)]
268 # link the proposals to the rank
269 ranking
= dict([i
for i
in itertools
.izip(proposals
, ranks
)])
271 assigned_proposals
= []
273 # only when the program allows allocations
274 # to be seen we should color the list
275 if org_entity
.scope
.allocations_visible
:
276 assigned_proposals
= sp_logic
.getProposalsToBeAcceptedForOrg(org_entity
)
278 # show the amount of slots assigned on the webpage
279 context
['slots_visible'] = True
281 ranking_keys
= dict([(k
.key(),v
) for k
,v
in ranking
.iteritems()])
282 proposal_keys
= [i
.key() for i
in assigned_proposals
]
284 # update the prop_list with the ranking and coloring information
285 prop_list
['info'] = (list_info_helper
.getStudentProposalInfo(ranking_keys
,
286 proposal_keys
), None)
288 # check if the current user is a mentor
289 user_entity
= user_logic
.logic
.getForCurrentAccount()
291 fields
= {'user': user_entity
,
292 'scope': org_entity
,}
293 mentor_entity
= mentor_logic
.logic
.getForFields(fields
, unique
=True)
296 mp_params
= list_params
.copy() # proposals mentored by current user
298 description
= ugettext('List of %s sent to %s you are mentoring') % (
299 mp_params
['name_plural'], org_entity
.name
)
300 mp_params
['list_description'] = description
301 mp_params
['list_action'] = (redirects
.getReviewRedirect
, mp_params
)
303 filter = {'org': org_entity
,
304 'mentor': mentor_entity
,
307 mp_list
= lists
.getListContent(
308 request
, mp_params
, filter, idx
=1, need_content
=True)
310 new_params
= list_params
.copy() # new proposals
311 new_params
['list_description'] = 'List of new %s sent to %s ' % (
312 new_params
['name_plural'], org_entity
.name
)
313 new_params
['list_action'] = (redirects
.getReviewRedirect
, new_params
)
315 filter = {'org': org_entity
,
319 new_list
= lists
.getListContent(
320 request
, new_params
, filter, idx
=2, need_content
=True)
322 ip_params
= list_params
.copy() # ineligible proposals
324 description
= ugettext('List of ineligible %s sent to %s ') % (
325 ip_params
['name_plural'], org_entity
.name
)
327 ip_params
['list_description'] = description
328 ip_params
['list_action'] = (redirects
.getReviewRedirect
, ip_params
)
330 filter = {'org': org_entity
,
333 ip_list
= lists
.getListContent(
334 request
, ip_params
, filter, idx
=3, need_content
=True)
336 # fill contents with all the needed lists
338 contents
.append(new_list
)
340 contents
.append(prop_list
)
342 if mentor_entity
and mp_list
!= None:
343 contents
.append(mp_list
)
346 contents
.append(ip_list
)
348 # call the _list method from base to display the list
349 return self
._list
(request
, list_params
, contents
, page_name
, context
)
351 @decorators.merge_params
352 @decorators.check_access
353 def listPublic(self
, request
, access_type
, page_name
=None,
354 params
=None, filter=None, **kwargs
):
355 """See base.View.list.
358 account
= accounts
.getCurrentAccount()
359 user
= user_logic
.logic
.getForAccount(account
) if account
else None
362 rights
= self
._params
['rights']
363 rights
.setCurrentUser(account
, user
)
366 except out_of_band
.Error
:
369 params
= params
.copy()
372 params
['list_action'] = (redirects
.getAdminRedirect
, params
)
374 params
['list_action'] = (redirects
.getPublicRedirect
, params
)
378 new_filter
['scope_path'] = kwargs
['scope_path']
379 new_filter
['status'] = 'active'
380 filter = dicts
.merge(filter, new_filter
)
382 content
= lists
.getListContent(request
, params
, filter)
385 return self
._list
(request
, params
, contents
, page_name
)
387 def _public(self
, request
, entity
, context
):
388 """See base.View._public().
391 from soc
.views
.models
import student_project
as student_project_view
393 ap_params
= student_project_view
.view
.getParams().copy() # accepted projects
395 # define the list redirect action to show the notification
396 ap_params
['list_action'] = (redirects
.getPublicRedirect
, ap_params
)
397 ap_params
['list_description'] = self
.DEF_ACCEPTED_PROJECTS_MSG_FMT
% (
399 ap_params
['list_heading'] = 'soc/student_project/list/heading.html'
400 ap_params
['list_row'] = 'soc/student_project/list/row.html'
402 # only show projects that have not failed
403 filter = {'scope': entity
,
404 'status': ['accepted', 'mid_term_passed', 'passed']}
406 ap_list
= lists
.getListContent(request
, ap_params
, filter, idx
=0,
412 contents
.append(ap_list
)
414 # construct the list and put it into the context
415 context
['list'] = soc
.logic
.lists
.Lists(contents
)
417 return super(View
, self
)._public
(request
=request
,
418 entity
=entity
, context
=context
)
420 def _getExtraMenuItems(self
, role_description
, params
=None):
421 """Used to create the specific Organization menu entries.
423 For args see group.View._getExtraMenuItems().
427 group_entity
= role_description
['group']
428 program_entity
= group_entity
.scope
429 roles
= role_description
['roles']
431 if roles
.get('org_admin') or roles
.get('mentor'):
432 # add a link to view all the student proposals
433 submenu
= (redirects
.getListProposalsRedirect(group_entity
, params
),
434 "View all Student Proposals", 'any_access')
435 submenus
.append(submenu
)
438 if roles
.get('org_admin'):
439 # add a link to manage student projects after they have been announced
440 if timeline_helper
.isAfterEvent(program_entity
.timeline
,
441 'accepted_students_announced_deadline'):
442 submenu
= (redirects
.getManageOverviewRedirect(group_entity
,
443 {'url_name': 'student_project'}),
444 "Manage Student Projects", 'any_access')
445 submenus
.append(submenu
)
447 # add a link to the management page
448 submenu
= (redirects
.getListRolesRedirect(group_entity
, params
),
449 "Manage Admins and Mentors", 'any_access')
450 submenus
.append(submenu
)
452 # add a link to invite an org admin
453 submenu
= (redirects
.getInviteRedirectForRole(group_entity
, 'org_admin'),
454 "Invite an Admin", 'any_access')
455 submenus
.append(submenu
)
457 # add a link to invite a member
458 submenu
= (redirects
.getInviteRedirectForRole(group_entity
, 'mentor'),
459 "Invite a Mentor", 'any_access')
460 submenus
.append(submenu
)
462 # add a link to the request page
463 submenu
= (redirects
.getListRequestsRedirect(group_entity
, params
),
464 "List Requests and Invites", 'any_access')
465 submenus
.append(submenu
)
467 # add a link to the edit page
468 submenu
= (redirects
.getEditRedirect(group_entity
, params
),
469 "Edit Organization Profile", 'any_access')
470 submenus
.append(submenu
)
472 if roles
.get('org_admin') or roles
.get('mentor'):
473 submenu
= (redirects
.getCreateDocumentRedirect(group_entity
, 'org'),
474 "Create a New Document", 'any_access')
475 submenus
.append(submenu
)
477 submenu
= (redirects
.getListDocumentsRedirect(group_entity
, 'org'),
478 "List Documents", 'any_access')
479 submenus
.append(submenu
)
482 if roles
.get('org_admin'):
483 # add a link to the resign page
484 submenu
= (redirects
.getManageRedirect(roles
['org_admin'],
485 {'url_name': 'org_admin'}),
486 "Resign as Admin", 'any_access')
487 submenus
.append(submenu
)
489 # add a link to the edit page
490 submenu
= (redirects
.getEditRedirect(roles
['org_admin'],
491 {'url_name': 'org_admin'}),
492 "Edit My Admin Profile", 'any_access')
493 submenus
.append(submenu
)
496 if roles
.get('mentor'):
497 # add a link to the resign page
498 submenu
= (redirects
.getManageRedirect(roles
['mentor'],
499 {'url_name' : 'mentor'}),
500 "Resign as Mentor", 'any_access')
501 submenus
.append(submenu
)
503 # add a link to the edit page
504 submenu
= (redirects
.getEditRedirect(roles
['mentor'],
505 {'url_name': 'mentor'}),
506 "Edit My Mentor Profile", 'any_access')
507 submenus
.append(submenu
)
514 admin
= decorators
.view(view
.admin
)
515 applicant
= decorators
.view(view
.applicant
)
516 apply_mentor
= decorators
.view(view
.applyMentor
)
517 create
= decorators
.view(view
.create
)
518 delete
= decorators
.view(view
.delete
)
519 edit
= decorators
.view(view
.edit
)
520 home
= decorators
.view(view
.home
)
521 list = decorators
.view(view
.list)
522 list_proposals
= decorators
.view(view
.listProposals
)
523 list_public
= decorators
.view(view
.listPublic
)
524 list_requests
= decorators
.view(view
.listRequests
)
525 list_roles
= decorators
.view(view
.listRoles
)
526 public
= decorators
.view(view
.public
)
527 export
= decorators
.view(view
.export
)
528 pick
= decorators
.view(view
.pick
)