blob: 121e7502f767ab80b2362edfd0cc4f2ab362d2d4 [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 GSoC module.
import datetime
from google.appengine.api import users
from google.appengine.ext import db
from django.core.urlresolvers import reverse
from soc.logic import system
from soc.logic import site
from soc.logic import user
from soc.views.helper.access_checker import isSet
def isBefore(date):
"""Returns True iff date is before utcnow().
Returns False if date is not set.
return date and datetime.datetime.utcnow() < date
def isAfter(date):
"""Returns True iff date is after utcnow().
Returns False if date is not set.
return date and date < datetime.datetime.utcnow()
def isBetween(start, end):
"""Returns True iff utcnow() is between start and end.
return isAfter(start) and isBefore(end)
class TimelineHelper(object):
"""Helper class for the determination of the currently active period.
Methods ending with "On", "Start", or "End" return a date.
Methods ending with "Between" return a tuple with two dates.
Methods ending with neither return a Boolean.
def __init__(self, timeline, org_app):
self.timeline = timeline
self.org_app = org_app
def currentPeriod(self):
"""Return where we are currently on the timeline.
def nextDeadline(self):
"""Determines the next deadline on the timeline.
def orgsAnnouncedOn(self):
return self.timeline.accepted_organization_announced_deadline
def beforeProgramStart(self):
return isBefore(self.timeline.program_start)
def programActiveBetween(self):
return (self.timeline.program_start, self.timeline.program_end)
def orgSignupStart(self):
return self.org_app.survey_start if self.org_app else None
def orgSignupEnd(self):
return self.org_app.survey_end if self.org_app else None
def orgSignupBetween(self):
return (self.org_app.survey_start, self.org_app.survey_end) if \
self.org_app else (None, None)
def studentSignupStart(self):
return self.timeline.student_signup_start
def studentSignupEnd(self):
return self.timeline.student_signup_end
def studentsSignupBetween(self):
return (self.timeline.student_signup_start,
def programActive(self):
start, end = self.programActiveBetween()
return isBetween(start, end)
def beforeOrgSignupStart(self):
return self.org_app and isBefore(self.orgSignupStart())
def afterOrgSignupStart(self):
return self.org_app and isAfter(self.orgSignupStart())
def orgSignup(self):
if not self.org_app:
return False
start, end = self.orgSignupBetween()
return isBetween(start, end)
def orgsAnnounced(self):
return isAfter(self.orgsAnnouncedOn())
def beforeStudentSignupStart(self):
return isBefore(self.studentSignupStart())
def afterStudentSignupStart(self):
return isAfter(self.studentSignupStart())
def studentSignup(self):
start, end = self.studentsSignupBetween()
return isBetween(start, end)
def afterStudentSignupEnd(self):
return isAfter(self.studentSignupEnd())
def surveyPeriod(self, survey):
start = survey.survey_start
end = survey.survey_end
return isAfter(start) and isBefore(end)
def afterSurveyStart(self, survey):
return isAfter(survey.survey_start)
def afterSurveyEnd(self, survey):
return isAfter(survey.survey_end)
class RequestData(object):
"""Object containing data we query for each request.
site: the Site entity
user: the user entity (if logged in)
request: the request object (as provided by django)
args: the request args (as provided by djang)
kwargs: the request kwargs (as provided by django)
path: the url of the current query, encoded as utf-8 string
full_path: same as path, but including any GET args
login_url: login url that redirects to the current path
logout_url: logout url that redirects to the current path
GET: the GET dictionary (from the request object)
POST: the POST dictionary (from the request object)
is_developer: is the current user a developer
gae_user: the Google Appengine user object
def __init__(self):
"""Constructs an empty RequestData object.
""" = None
self.user = None
self.request = None
self.args = []
self.kwargs = {}
self.GET = None
self.POST = None
self.path = None
self.full_path = None
self.is_developer = False
self.gae_user = None
self.css_path = 'gsoc'
self._login_url = None
self._logout_url = None
self._ds_write_disabled = None
def login_url(self):
"""Memoizes and returns the login_url for the current path.
if not self._login_url:
self._login_url = users.create_login_url(self.full_path)
return self._login_url
def logout_url(self):
"""Memoizes and returns the logout_url for the current path.
if not self._logout_url:
self._logout_url = users.create_logout_url(self.full_path)
return self._logout_url
def ds_write_disabled(self):
"""Memoizes and returns whether datastore writes are disabled.
if self._ds_write_disabled is not None:
return self._ds_write_disabled
if self.request.method == 'GET':
val= self.request.GET.get('dsw_disabled', '')
if val.isdigit() and int(val) == 1:
self._ds_write_disabled = True
return True
self._ds_write_disabled = not db.WRITE_CAPABILITY.is_enabled()
return self._ds_write_disabled
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.
self.redirect = redirect
self.request = request
self.args = args
self.kwargs = kwargs
self.GET = request.GET
self.POST = request.POST
self.path = request.path.encode('utf-8')
self.full_path = request.get_full_path().encode('utf-8')
# XSRF middleware already retrieved it for us
if not hasattr(request, 'site'): = site.singleton() =
self.user = user.current()
if users.is_current_user_admin():
self.is_developer = True
if self.user and self.user.is_developer:
self.is_developer = True
self.gae_user = users.get_current_user()
def appliedTo(self, organization):
"""Returns true iff the user has applied for the specified organization.
Organization may either be a key or an organization instance.
query = self._requestQuery(organization)
query.filter('type', 'Request')
return bool(query.get())
def invitedTo(self, organization):
"""Returns the role the user has been invited to,.
Organization may either be a key or an organization instance.
Returns None if no invite was sent.
query = self._requestQuery(organization)
query.filter('type', 'Invitation')
invite = query.get()
return invite.role if invite else None
class RedirectHelper(object):
"""Helper for constructing redirects.
def __init__(self, data, response):
"""Initializes the redirect helper.
self._data = data
self._response = response
def _clear(self):
"""Clears the internal state.
self._no_url = False
self._url_name = None
self._url = None
self.args = []
self.kwargs = {}
def sponsor(self, program=None):
"""Sets kwargs for an url_patterns.SPONSOR redirect.
if not program:
assert isSet(self._data.program)
program = self._data.program
self.kwargs['sponsor'] = program.scope_path
return self
def program(self, program=None):
"""Sets kwargs for an url_patterns.PROGRAM redirect.
if not program:
assert isSet(self._data.program)
program = self._data.program
self.kwargs['program'] = program.link_id
return self
def organization(self, organization=None):
"""Sets the kwargs for an url_patterns.ORG redirect.
if not organization:
assert isSet(self._data.organization)
organization = self._data.organization
self.kwargs['organization'] = organization.link_id
return self
def id(self, id=None):
"""Sets the kwargs for an url_patterns.ID redirect.
if not id:
assert 'id' in self._data.kwargs
id = self._data.kwargs['id']
self.kwargs['id'] = id
return self
def key(self, key=None):
"""Sets the kwargs for an url_patterns.KEY redirect.
if not key:
assert 'key' in self._data.kwargs
key = self._data.kwargs['key']
self.kwargs['key'] = key
return self
def createProfile(self, role):
"""Sets args for an url_patterns.CREATE_PROFILE redirect.
self.kwargs['role'] = role
return self
def profile(self, user=None):
"""Sets args for an url_patterns.PROFILE redirect.
if not user:
assert 'user' in self._data.kwargs
user = self._data.kwargs['user']
self.kwargs['user'] = user
return self
def document(self, document):
"""Sets args for an url_patterns.DOCUMENT redirect.
If document is not set, a call to url() will return None.
if not document:
self._no_url = True
return self
if isinstance(document, db.Model):
key = document.key()
key = document
self.args ='/')
return self
def urlOf(self, name, full=False, secure=False, cbox=False, extra=[]):
"""Returns the resolved url for name.
Uses internal state for args and kwargs.
if self.args:
url = reverse(name, args=self.args)
elif self.kwargs:
url = reverse(name, kwargs=self.kwargs)
url = reverse(name)
url = self._appendGetArgs(url, cbox=cbox, extra_get_args=extra)
return self._fullUrl(url, full, secure)
def url(self, full=False, secure=False):
"""Returns the url of the current state.
if self._no_url:
return None
assert self._url or self._url_name
if self._url:
return self._fullUrl(self._url, full, secure)
return self.urlOf(self._url_name, full=full, secure=secure)
def _fullUrl(self, url, full, secure):
"""Returns the full version of the url iff full.
The full version starts with http:// and includes getHostname().
if (not full) and (system.isLocal() or not secure):
return url
if secure:
protocol = 'https'
hostname = system.getSecureHostname()
protocol = 'http'
hostname = system.getHostname(self._data)
return '%s://%s%s' % (protocol, hostname, url)
def _appendAnchor(self, url, anchor=None):
"""Appends the anchor to the URL.
if anchor:
url = '%s#%s' % (url, anchor)
return url
def _appendGetArgs(self, url, cbox=False, validated=False,
"""Appends GET arguments to the specified URL.
get_args = extra_get_args[:]
if cbox:
if validated:
if get_args:
# check if the url has already a question mark
if url.find('?') == -1:
url = url + '?'
url = url + '&'
# append all the GET arguments at the end of the URL
if get_args:
url = url + '&'.join(get_args)
return url
def to(self, name=None, validated=False, full=False, secure=False,
cbox=False, extra=[], anchor=None):
"""Redirects to the resolved url for name.
Uses internal state for args and kwargs.
name: Name of the URL pattern
validated: If set to True will add &validated to GET arguments
full: Whether the URL should include the protocol
secure: Whether the protocol of the URL should be set to HTTPS
cbox: If set to True will add &cbox=true to GET arguments
extra: List of additional arguments that will be added as GET arguments
if self._url:
url = self._url
assert name or self._url_name
url = self.urlOf(name or self._url_name)
url = self._appendAnchor(url, anchor)
url = self._appendGetArgs(url, cbox=cbox, validated=validated,
self.toUrl(url, full=full, secure=secure)
def toUrl(self, url, full=False, secure=False):
"""Redirects to the specified url.
from django.utils.encoding import iri_to_uri
url = self._fullUrl(url, full, secure)
self._response.status_code = 302
self._response["Location"] = iri_to_uri(url)
def login(self):
"""Sets the _url to the login url.
self._url = self._data.login_url
return self
def logout(self):
"""Sets the _url to the logout url.
self._url = self._data.logout_url
return self
def acceptedOrgs(self):
"""Sets the _url_name to the list of all accepted orgs.
return self
def homepage(self, program=None):
"""Sets the _url_name for the homepage of the current program.
program: the link_id of the program for which we need to get the homepage
return self
def searchpage(self):
"""Sets the _url_name for the searchpage of the current program.
return self
def orgHomepage(self, link_id):
"""Sets the _url_name for the specified org homepage
self.kwargs['organization'] = link_id
return self
def dashboard(self):
"""Sets the _url_name for dashboard page of the current program.
return self
def events(self):
"""Sets the _url_name for the events page, if it is set.
return self