blob: 451e255072c82f3b30ae5915b57974c4b9bcb791 [file] [log] [blame]
#!/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
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# See the License for the specific language governing permissions and
# limitations under the License.
"""Module containing the RequestData object that will be created for each
request in the GCI module.
import datetime
from google.appengine.ext import db
from soc.logic.exceptions import NotFound
from import Site
from soc.views.helper import request_data
from soc.modules.gci.logic.helper import timeline as timeline_helper
from soc.modules.gci.models.program import GCIProgram
from soc.modules.gci.models.profile import GCIProfile
from soc.modules.gci.models.organization import GCIOrganization
from soc.modules.gci.views.helper import url_names
class TimelineHelper(request_data.TimelineHelper):
"""Helper class for the determination of the currently active period.
see the super class, soc.views.helper.request_data.TimelineHelper
def currentPeriod(self):
"""Return where we are currently on the timeline.
# This is required as a protection against the cases when the
# org apps are not created for the program and hence there is
# no way we can determine if the org app has started.
if self.beforeProgramStart():
return 'kickoff_period'
if self.beforeOrgSignupStart():
return 'kickoff_period'
if self.orgSignup():
return 'org_signup_period'
if self.studentSignup():
return 'student_signup_period'
if self.tasksPubliclyVisible() and self.programActive():
return 'working_period'
return 'offseason'
def nextDeadline(self):
"""Determines the next deadline on the timeline.
if self.beforeOrgSignupStart():
return ("Org Application Starts", self.orgSignupStart())
# we do not have deadlines for any of those programs that are not active
if not self.programActive():
return ("", None)
if self.orgSignup():
return ("Org Application Deadline", self.orgSignupEnd())
if request_data.isBetween(self.orgSignupEnd(), self.orgsAnnouncedOn()):
return ("Accepted Orgs Announced In", self.orgsAnnouncedOn())
if self.orgsAnnounced() and self.beforeStudentSignupStart():
return ("Student Application Opens", self.studentSignupStart())
if self.studentSignup():
return ("Student Application Deadline", self.studentSignupEnd())
if request_data.isBetween(self.tasksPubliclyVisible(),
return ("Tasks Claim Deadline", self.tasksClaimEndOn())
if request_data.isBetween(self.tasksClaimEndOn(), self.stopAllWorkOn()):
return ("Work Submission Deadline", self.stopAllWorkOn())
return ('', None)
def tasksPubliclyVisibleOn(self):
return self.timeline.tasks_publicly_visible
def tasksPubliclyVisible(self):
return request_data.isAfter(self.tasksPubliclyVisibleOn())
def tasksClaimEndOn(self):
return self.timeline.task_claim_deadline
def tasksClaimEnded(self):
return request_data.isAfter(self.tasksClaimEndOn())
def stopAllWorkOn(self):
return self.timeline.stop_all_work_deadline
def allWorkStopped(self):
return request_data.isAfter(self.stopAllWorkOn())
def stopAllReviewsOn(self):
return self.timeline.work_review_deadline
def allReviewsStopped(self):
return request_data.isAfter(self.stopAllReviewsOn())
def winnersAnnouncedOn(self):
return self.timeline.winners_announced_deadline
def winnersAnnounced(self):
return request_data.isAfter(self.winnersAnnouncedOn())
def remainingTime(self):
"""Returns the remaining time in the program a tuple of days, hrs and mins.
end = self.stopAllWorkOn()
return timeline_helper.remainingTimeSplit(end)
def tasksVisibleInTime(self):
"""Returns the remaining time till the tasks are publicly visible to
the students.
end = self.tasksPubliclyVisibleOn()
return timeline_helper.remainingTimeSplit(end)
def completePercentage(self):
"""Computes the remaining time percentage
It is VERY IMPORTANT TO NOTE here that this percentage is between the
task opening date and the date task can be last claimed.
However if the all work stop deadline is set after the task claim date
that will only be visible on per task basis, this percentage would still
return zero.
start = self.tasksPubliclyVisibleOn()
end = self.tasksClaimEndOn()
if not start or not end:
return 0.0
return timeline_helper.completePercentage(start, end)
def stopwatchPercentage(self):
"""Computes the closest matching percentage for the static clock images.
complete_percentage = self.completePercentage()
return timeline_helper.stopwatchPercentage(complete_percentage)
class RequestData(request_data.RequestData):
"""Object containing data we query for each request in the GCI module.
The only view that will be exempt is the one that creates the program.
site: The Site entity
user: The user entity (if logged in)
css_path: a part of the css to fetch the GCI specific CSS resources
program: The GCI program entity that the request is pointing to
programs: All GCI programs.
program_timeline: The GCITimeline entity
timeline: A TimelineHelper entity
profile: The GCIProfile entity of the current user
is_host: is the current user a host of the program
is_mentor: is the current user a mentor in the program
is_student: is the current user a student in the program
is_org_admin: is the current user an org admin in the program
org_map: map of retrieved organizations
org_admin_for: the organizations the current user is an admin for
mentor_for: the organizations the current user is a mentor for
student_info: the StudentInfo for the current user and program
organization: the GCIOrganization for the current url
out_of_band: 404 when the program does not exist
def __init__(self):
"""Constructs an empty RequestData object.
super(RequestData, self).__init__()
# module wide fields
self.css_path = 'gci'
# program wide fields
self._programs = None
self.program = None
self.program_timeline = None
self.org_app = None
# user profile specific fields
self.profile = None
self.is_host = False
self.is_mentor = False
self.is_student = False
self.is_org_admin = False
self.org_map = {}
self.mentor_for = []
self.org_admin_for = []
self.student_info = None
self.organization = None
def programs(self):
"""Memorizes and returns a list of all programs.
if not self._programs:
self._programs = list(GCIProgram.all())
return self._programs
def getOrganization(self, org_key):
"""Retrieves the specified organization.
if org_key not in self.org_map:
org = db.get(org_key)
self.org_map[org_key] = org
return self.org_map[org_key]
def orgAdminFor(self, organization):
"""Returns true iff the user is admin for the specified organization.
Organization may either be a key or an organization instance.
if self.is_host:
return True
if isinstance(organization, db.Model):
organization = organization.key()
return organization in [i.key() for i in self.org_admin_for]
def mentorFor(self, organization):
"""Returns true iff the user is mentor for the specified organization.
Organization may either be a key or an organization instance.
if self.is_host:
return True
if isinstance(organization, db.Model):
organization = organization.key()
return organization in [i.key() for i in self.mentor_for]
def _requestQuery(self, organization):
"""Returns a query to retrieve a Request for this user.
if isinstance(organization, db.Model):
organization = organization.key()
from soc.modules.gci.models.request import GCIRequest
query = GCIRequest.all()
query.filter('user', self.user)
query.filter('org', organization)
return query
def populate(self, redirect, request, args, kwargs):
"""Populates the fields in the RequestData object.
request: Django HTTPRequest object.
args & kwargs: The args and kwargs django sends along.
super(RequestData, self).populate(redirect, request, args, kwargs)
if kwargs.get('sponsor') and kwargs.get('program'):
program_key_name = "%s/%s" % (kwargs['sponsor'], kwargs['program'])
program_key = db.Key.from_path('GCIProgram', program_key_name)
program_key = Site.active_program.get_value_for_datastore(
program_key_name =
timeline_key = db.Key.from_path('GCITimeline', program_key_name)
org_app_key_name = 'gci_program/%s/orgapp' % program_key_name
org_app_key = db.Key.from_path('OrgAppSurvey', org_app_key_name)
keys = [program_key, timeline_key, org_app_key]
self.program, self.program_timeline, self.org_app = db.get(keys)
if not self.program:
raise NotFound("There is no program for url '%s'" % program_key_name)
self.timeline = TimelineHelper(self.program_timeline, self.org_app)
if kwargs.get('organization'):
fields = [self.program.key().id_or_name(), kwargs.get('organization')]
org_key_name = '/'.join(fields)
self.organization = GCIOrganization.get_by_key_name(org_key_name)
if not self.organization:
raise NotFound("There is no organization for url '%s'" % org_key_name)
if self.user:
key_name = '%s/%s' % (self.program.key().name(), self.user.link_id)
self.profile = GCIProfile.get_by_key_name(
key_name, parent=self.user)
host_key = GCIProgram.scope.get_value_for_datastore(self.program)
self.is_host = host_key in self.user.host_for
if self.profile and self.profile.status != 'invalid':
org_keys = set(self.profile.mentor_for + self.profile.org_admin_for)
prop = GCIProfile.student_info
student_info_key = prop.get_value_for_datastore(self.profile)
if student_info_key:
self.student_info = db.get(student_info_key)
self.is_student = True
orgs = db.get(org_keys)
org_map = self.org_map = dict((i.key(), i) for i in orgs)
self.mentor_for = org_map.values()
self.org_admin_for = [org_map[i] for i in self.profile.org_admin_for]
self.is_org_admin = self.is_host or bool(self.org_admin_for)
self.is_mentor = self.is_org_admin or bool(self.mentor_for)
class RedirectHelper(request_data.RedirectHelper):
"""Helper for constructing redirects.
def document(self, document):
"""Override this method to set GCI specific _url_name.
super(RedirectHelper, self).document(document)
self._url_name = 'show_gci_document'
return self
def homepage(self, program=None):
"""Sets the _url_name for the homepage of the current GCI program.
program: the link_id of the program for which we need to get the homepage
super(RedirectHelper, self).homepage(program)
self._url_name = 'gci_homepage'
return self
def dashboard(self):
"""Sets the _url_name for dashboard page of the current GCI program.
super(RedirectHelper, self).dashboard()
self._url_name = 'gci_dashboard'
return self
def events(self):
"""Sets the _url_name for the events page, if it is set.
super(RedirectHelper, self).events()
self._url_name = 'gci_events'
return self
def orgHomepage(self, link_id):
"""Sets the _url_name for the specified org homepage
super(RedirectHelper, self).orgHomepage(link_id)
self._url_name = url_names.GCI_ORG_HOME
return self
def request(self, request):
"""Sets the _url_name for a request.
assert request
if request.type == 'Request':
self.userId(request.parent_key().name(), request.key().id())
self._url_name = url_names.GCI_RESPOND_REQUEST
self._url_name = url_names.GCI_RESPOND_INVITE
return self
def invite(self, role=None, organization=None):
"""Sets args for an url_patterns.INVITE redirect.
if not role:
assert 'role' in self._data.kwargs
role = self._data.kwargs['role']
self.kwargs['role'] = role
return self
def editProfile(self):
"""Returns the URL for the edit profile page.
self._url_name = 'edit_gci_profile'
return self