| #!/usr/bin/env python2.5 |
| # |
| # Copyright 2011 the Melange authors. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| """Module containing the AccessChecker class that contains helper functions |
| for checking access. |
| """ |
| |
| __authors__ = [ |
| '"Selwyn Jacob" <selwynjacob90@gmail.com>', |
| '"Lennard de Rijk" <ljvderijk@gmail.com>', |
| ] |
| |
| |
| from django.core.urlresolvers import reverse |
| from django.utils.translation import ugettext |
| |
| from soc.logic import dicts |
| from soc.logic.exceptions import AccessViolation |
| from soc.logic.exceptions import BadRequest |
| from soc.logic.exceptions import NotFound |
| from soc.logic.exceptions import RedirectRequest |
| from soc.models.org_app_record import OrgAppRecord |
| from soc.views.helper import access_checker |
| from soc.views.helper import request_data |
| |
| from soc.modules.gci.models.profile import GCIProfile |
| from soc.modules.gci.models.task import GCITask |
| from soc.modules.gci.models.task import UNPUBLISHED |
| |
| |
| DEF_ALREADY_PARTICIPATING_AS_NON_STUDENT = ugettext( |
| 'You cannot register as a student since you are already a ' |
| 'mentor or organization administrator in %s.') |
| |
| DEF_ALL_WORK_STOPPED = ugettext( |
| 'All work on tasks has stopped. You can no longer place comments, ' |
| 'submit work or make any changes to existing tasks.') |
| |
| DEF_NO_TASK_CREATE_PRIV = ugettext( |
| 'You do not have sufficient privileges to create a new task for %s.' ) |
| |
| DEF_NO_TASK_EDIT_PRIV = ugettext( |
| 'You do not have sufficient privileges to edit a new task for %s.' ) |
| |
| DEF_NO_PREV_ORG_MEMBER = ugettext( |
| 'To apply as an organization for GCI you must have been a member of an ' |
| 'organization in Google Summer of Code or Google Code In.') |
| |
| DEF_TASK_UNEDITABLE_STATUS = ugettext( |
| 'This task is already published and published tasks cannot be edited.') |
| |
| DEF_TASK_MUST_BE_IN_STATES = ugettext( |
| 'The task must be in one of the followings states %s') |
| |
| DEF_TASK_MAY_NOT_BE_IN_STATES = ugettext( |
| 'The task may not be in one of the followings states %s') |
| |
| DEF_ORG_APP_REJECTED = ugettext( |
| 'This org application has been rejected') |
| |
| |
| class Mutator(access_checker.Mutator): |
| """Helper class for access checking. |
| |
| Mutates the data object as requested. |
| """ |
| |
| def unsetAll(self): |
| self.data.task = access_checker.unset |
| self.data.comments = access_checker.unset |
| self.data.work_submissions = access_checker.unset |
| super(Mutator, self).unsetAll() |
| |
| def profileFromKwargs(self): |
| """Retrieves profile from the kwargs for GCI. |
| """ |
| super(Mutator, self).profileFromKwargs(GCIProfile) |
| |
| def taskFromKwargs(self, comments=False, work_submissions=True): |
| """Sets the GCITask entity in RequestData object. |
| |
| The entity that is set will always be in a valid state and for the program |
| that is set in the RequestData. |
| |
| Args: |
| comments: If true the comments on this task are added to RequestData |
| work_submissions: If true the work submissions on this task are added to |
| RequestData |
| """ |
| id = long(self.data.kwargs['id']) |
| task = GCITask.get_by_id(id) |
| |
| if not task or (task.program.key() != self.data.program.key()) or \ |
| task.status == 'invalid': |
| error_msg = access_checker.DEF_ID_BASED_ENTITY_NOT_EXISTS % { |
| 'model': 'GCITask', |
| 'id': id, |
| } |
| raise NotFound(error_msg) |
| |
| self.data.task = task |
| |
| if comments: |
| self.data.comments = task.comments() |
| |
| if work_submissions: |
| self.data.work_submissions = task.workSubmissions() |
| |
| def taskFromKwargsIfId(self): |
| """Sets the GCITask entity in RequestData object if ID exists or None. |
| """ |
| if not 'id' in self.data.kwargs: |
| self.data.task = None |
| return |
| |
| self.taskFromKwargs() |
| |
| def orgAppFromOrgId(self): |
| org_id = self.data.GET.get('org_id') |
| |
| if not org_id: |
| raise BadRequest('Missing org_id') |
| |
| q = OrgAppRecord.all() |
| q.filter('survey', self.data.org_app) |
| q.filter('org_id', org_id) |
| |
| self.data.org_app_record = q.get() |
| |
| if not self.data.org_app_record: |
| raise NotFound("There is no org_app for the org_id %s" % org_id) |
| |
| if self.data.org_app_record.status != 'accepted': |
| raise AccessViolation(DEF_ORG_APP_REJECTED) |
| |
| |
| class DeveloperMutator(access_checker.DeveloperMutator, |
| Mutator): |
| pass |
| |
| |
| class AccessChecker(access_checker.AccessChecker): |
| """Access checker for GCI specific methods. |
| """ |
| |
| def isTaskVisible(self): |
| """Checks if the task is visible to the public. |
| """ |
| assert access_checker.isSet(self.data.task) |
| |
| if not self.data.timeline.tasksPubliclyVisible(): |
| period = self.data.timeline.tasksPubliclyVisibleOn() |
| raise AccessViolation( |
| access_checker.DEF_PAGE_INACTIVE_BEFORE % period) |
| |
| if not self.data.task.isPublished(): |
| error_msg = access_checker.DEF_PAGE_INACTIVE |
| raise AccessViolation(error_msg) |
| |
| def isTaskInState(self, states): |
| """Checks if the task is in any of the given states. |
| |
| Args: |
| states: List of states in which a task may be for this check to pass. |
| """ |
| assert access_checker.isSet(self.data.task) |
| |
| if self.data.task.status not in states: |
| raise AccessViolation(DEF_TASK_MUST_BE_IN_STATES %states) |
| |
| def isTaskNotInStates(self, states): |
| """Checks if the task is not in any of the given states. |
| |
| Args: |
| states: List of states in which a task may not be for this check to pass. |
| """ |
| assert access_checker.isSet(self.data.task) |
| |
| if self.data.task.status in states: |
| raise AccessViolation(DEF_TASK_MAY_NOT_BE_IN_STATES %states) |
| |
| def canApplyStudent(self, edit_url): |
| """Checks if a user may apply as a student to the program. |
| """ |
| self.isLoggedIn() |
| |
| if self.data.profile: |
| if self.data.profile.student_info: |
| raise RedirectRequest(edit_url) |
| else: |
| raise AccessViolation( |
| DEF_ALREADY_PARTICIPATING_AS_NON_STUDENT % |
| self.data.program.name) |
| |
| self.studentSignupActive() |
| |
| # custom pre-registration age check for GCI students |
| age_check = self.data.request.COOKIES.get('age_check', None) |
| if not age_check or age_check == '0': |
| # no age check done or it failed |
| kwargs = dicts.filter(self.data.kwargs, ['sponsor', 'program']) |
| age_check_url = reverse('gci_age_check', kwargs=kwargs) |
| raise RedirectRequest(age_check_url) |
| |
| def canTakeOrgApp(self): |
| """A user can take the GCI org app if he/she participated in GSoC or GCI |
| as a non-student. |
| """ |
| from soc.modules.gsoc.models.profile import GSoCProfile |
| |
| self.isUser() |
| |
| q = GSoCProfile.all() |
| q.filter('is_student', False) |
| q.filter('status IN', ['active', 'inactive']) |
| q.filter('user', self.data.user) |
| gsoc_profile = q.get() |
| |
| q = GCIProfile.all() |
| q.filter('is_student', False) |
| q.filter('status IN', ['active', 'inactive']) |
| q.filter('user', self.data.user) |
| gci_profile = q.get() |
| |
| if not (gsoc_profile or gci_profile): |
| raise AccessViolation(DEF_NO_PREV_ORG_MEMBER) |
| |
| def canCreateNewOrg(self): |
| """A user can create a new org if they have an accepted org app. |
| """ |
| assert self.data.org_app |
| |
| #$ if |
| # raise AccessDenied |
| |
| if not self.data.profile: |
| org_id = self.data.GET['org_id'] |
| profile_url = self.data.redirect.createProfile('org_admin').urlOf( |
| 'create_gci_profile') |
| raise RedirectRequest(profile_url + '?new_org=' + org_id) |
| |
| def isBeforeAllWorkStopped(self): |
| """Raises AccessViolation if all work on tasks has stopped. |
| """ |
| if not self.data.timeline.allWorkStopped(): |
| return |
| |
| raise AccessViolation(DEF_ALL_WORK_STOPPED) |
| |
| def canCreateTask(self): |
| """Checks whether the currently logged in user can edit the task. |
| """ |
| assert access_checker.isSet(self.data.organization) |
| assert access_checker.isSet(self.data.mentor_for) |
| |
| valid_org_keys = [o.key() for o in self.data.mentor_for] |
| if self.data.organization.key() not in valid_org_keys: |
| raise AccessViolation(DEF_NO_TASK_CREATE_PRIV % ( |
| self.data.organization.name)) |
| |
| if (request_data.isBefore(self.data.timeline.orgsAnnouncedOn()) \ |
| or self.data.timeline.tasksClaimEnded()): |
| raise AccessViolation(access_checker.DEF_PAGE_INACTIVE) |
| |
| def canEditTask(self): |
| """Checks whether the currently logged in user can edit the task. |
| """ |
| assert access_checker.isSet(self.data.task) |
| assert access_checker.isSet(self.data.mentor_for) |
| |
| task = self.data.task |
| |
| valid_org_keys = [o.key() for o in self.data.mentor_for] |
| if task.org.key() not in valid_org_keys: |
| raise AccessViolation(DEF_NO_TASK_EDIT_PRIV % ( |
| task.org.name)) |
| |
| if task.status not in UNPUBLISHED: |
| raise AccessViolation(DEF_TASK_UNEDITABLE_STATUS) |
| |
| if (request_data.isBefore(self.data.timeline.orgsAnnouncedOn()) \ |
| or self.data.timeline.tasksClaimEnded()): |
| raise AccessViolation(access_checker.DEF_PAGE_INACTIVE) |
| |
| class DeveloperAccessChecker(access_checker.DeveloperAccessChecker): |
| """Developer access checker for GCI specific methods. |
| """ |
| pass |