blob: 7ca7d4910d14854faaa90a70c160dce43b6f2449 [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
#
# 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 view for GSoC project details page.
"""
from google.appengine.ext import db
from django.utils.translation import ugettext
from soc.logic.exceptions import BadRequest
from soc.views.helper.access_checker import isSet
from soc.views.template import Template
from soc.views.toggle_button import ToggleButtonTemplate
from soc.modules.gsoc.logic import profile as profile_logic
from soc.modules.gsoc.models.project import GSoCProject
from soc.modules.gsoc.views import assign_mentor
from soc.modules.gsoc.views.base import RequestHandler
from soc.modules.gsoc.views.forms import GSoCModelForm
from soc.modules.gsoc.views.helper import url_patterns
from soc.modules.gsoc.views.helper.url_patterns import url
class ProjectDetailsForm(GSoCModelForm):
"""Constructs the form to edit the project details
"""
class Meta:
model = GSoCProject
css_prefix = 'gsoc_project'
fields = ['title', 'abstract', 'public_info',
'additional_info', 'feed_url']
class ProjectDetailsUpdate(RequestHandler):
"""Encapsulate the methods required to generate Project Details update form.
"""
def templatePath(self):
return 'v2/modules/gsoc/project_details/update.html'
def djangoURLPatterns(self):
"""Returns the list of tuples for containing URL to view method mapping.
"""
return [
url(r'project/update/%s$' % url_patterns.PROJECT, self,
name='gsoc_update_project')
]
def checkAccess(self):
"""Access checks for GSoC project details page.
"""
self.check.isLoggedIn()
self.check.isActiveStudent()
self.mutator.projectFromKwargs()
self.check.canStudentUpdateProject()
def context(self):
"""Handler to for GSoC project details page HTTP get request.
"""
project_details_form = ProjectDetailsForm(self.data.POST or None,
instance=self.data.project)
context = {
'page_name': 'Update project details',
'project': self.data.project,
'forms': [project_details_form],
'error': project_details_form.errors,
}
return context
def validate(self):
"""Validate the form data and save if valid.
"""
project_details_form = ProjectDetailsForm(self.data.POST or None,
instance=self.data.project)
if not project_details_form.is_valid():
return False
project_details_form.save()
return True
def post(self):
"""Post handler for the project details update form.
"""
if self.validate():
self.redirect.project()
self.redirect.to('gsoc_project_details')
else:
self.get()
class UserActions(Template):
"""Template to render the left side user actions.
"""
DEF_FEATURED_PROJECT_HELP = ugettext(
'Choosing Yes features this project on program home page. The '
'project is featured when Yes is displayed in bright orange.')
def __init__(self, data):
super(UserActions, self).__init__(data)
self.toggle_buttons = []
def context(self):
assert isSet(self.data.project)
r = self.data.redirect.project()
featured_project = ToggleButtonTemplate(
self.data, 'on_off', 'Featured', 'project-featured',
r.urlOf('gsoc_featured_project'),
checked=self.data.project.is_featured,
help_text=self.DEF_FEATURED_PROJECT_HELP,
labels={
'checked': 'Yes',
'unchecked': 'No'})
self.toggle_buttons.append(featured_project)
context = {
'title': 'Project Actions',
'toggle_buttons': self.toggle_buttons,
}
r = self.data.redirect
all_mentors_keys = profile_logic.queryAllMentorsKeysForOrg(
self.data.project.org)
context['assign_mentor'] = assign_mentor.AssignMentorFields(
self.data, self.data.project.mentors,
r.project().urlOf('gsoc_project_assign_mentors'),
all_mentors=all_mentors_keys, mentor_required=True,
allow_multiple=True)
return context
def templatePath(self):
return "v2/modules/gsoc/project_details/_user_action.html"
class ProjectDetails(RequestHandler):
"""Encapsulate all the methods required to generate GSoC project
details page.
"""
def templatePath(self):
return 'v2/modules/gsoc/project_details/base.html'
def djangoURLPatterns(self):
"""Returns the list of tuples for containing URL to view method mapping.
"""
return [
url(r'project/%s$' % url_patterns.PROJECT, self,
name='gsoc_project_details')
]
def checkAccess(self):
"""Access checks for GSoC project details page.
"""
self.mutator.projectFromKwargs()
def context(self):
"""Handler to for GSoC project details page HTTP get request.
"""
project = self.data.project
r = self.redirect
context = {
'page_name': 'Project details',
'project': project,
'org_home_link': r.organization(project.org).urlOf('gsoc_org_home'),
}
if self.data.orgAdminFor(self.data.project.org):
context['user_actions'] = UserActions(self.data)
user_is_owner = self.data.user and \
(self.data.user.key() == self.data.project_owner.parent_key())
if user_is_owner:
context['update_link'] = r.project().urlOf('gsoc_update_project')
return context
class AssignMentors(RequestHandler):
"""View which handles assigning mentor to a project.
"""
def djangoURLPatterns(self):
return [
url(r'project/assign_mentors/%s$' % url_patterns.PROJECT,
self, name='gsoc_project_assign_mentors'),
]
def checkAccess(self):
self.mutator.projectFromKwargs()
assert isSet(self.data.project.org)
self.check.isOrgAdminForOrganization(self.data.project.org)
def assignMentors(self, mentor_keys):
"""Assigns the mentor to the project.
Args:
mentor_keys: List of mentor profile keys to to be assigned
to the project.
"""
assert isSet(self.data.project)
project_key = self.data.project.key()
def assign_mentor_txn():
project = db.get(project_key)
project.mentors = mentor_keys
db.put(project)
db.run_in_transaction(assign_mentor_txn)
def validate(self):
str_mentor_keys = self.data.POST.getlist('assign_mentor')
if str_mentor_keys:
org = self.data.project.org
# need the list to set conversion and back to list conversion
# to ensure that same mentor doesn't get assigned to the
# project more than once
mentor_keys = set([db.Key(k) for k in str_mentor_keys if k])
if mentor_keys < set(
profile_logic.queryAllMentorsKeysForOrg(org)):
return list(mentor_keys)
raise BadRequest("Invalid post data.")
return None
def post(self):
assert isSet(self.data.project)
mentor_keys = self.validate()
if mentor_keys:
self.assignMentors(mentor_keys)
project_owner = self.data.project.parent()
self.redirect.project(self.data.project.key().id(),
project_owner.link_id)
self.redirect.to('gsoc_project_details')
def get(self):
"""Special Handler for HTTP GET request since this view only handles POST.
"""
self.error(405)
class FeaturedProject(RequestHandler):
"""View which handles making the project featured by toggle button.
"""
def djangoURLPatterns(self):
return [
url(r'project/featured/%s$' % url_patterns.PROJECT,
self, name='gsoc_featured_project'),
]
def checkAccess(self):
self.mutator.projectFromKwargs()
assert isSet(self.data.project.org)
self.check.isOrgAdminForOrganization(self.data.project.org)
def toggleFeatured(self, value):
"""Makes the project featured.
Args:
value: can be either "checked" or "unchecked".
"""
assert isSet(self.data.project)
if value != 'checked' and value != 'unchecked':
raise BadRequest("Invalid post data.")
if value == 'checked' and not self.data.project.is_featured:
raise BadRequest("Invalid post data.")
if value == 'unchecked' and self.data.project.is_featured:
raise BadRequest("Invalid post data.")
project_key = self.data.project.key()
def make_featured_txn():
# transactionally get latest version of the proposal
project = db.get(project_key)
if value == 'unchecked':
project.is_featured = True
elif value == 'checked':
project.is_featured = False
db.put(project)
db.run_in_transaction(make_featured_txn)
def post(self):
value = self.data.POST.get('value')
self.toggleFeatured(value)
def get(self):
"""Special Handler for HTTP GET request since this view only handles POST.
"""
self.error(405)