blob: 4fe30084621ab15821d73eb814649eba559f5df1 [file] [log] [blame]
# Copyright 2014 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.
"""Logic for projects."""
import logging
from google.appengine.api import datastore_errors
from google.appengine.ext import ndb
from melange.utils import rich_bool
from summerofcode.models import project as project_model
# list of properties of Proposal model which cannot be updated
# by updateProposal function
_PROPERTIES_NOT_FOR_UPDATE = ['program', 'organization']
ILLEGAL_PROJECT_STATE = 'illegal_project_state'
def queryAcceptedProjects(program_key):
"""Returns a query to fetch all projects accepted for the specified program.
Args:
program_key: ndb.Key of the program.
Returns:
ndb.Query object to fetch all projects accepted for the specified program.
"""
return project_model.Project.query(
project_model.Project.program == ndb.Key.from_old_key(program_key),
project_model.Project.status == project_model.Status.ACCEPTED)
def queryAllProjects(program_key):
"""Returns a query to fetch all projects for the specified program.
Args:
program_key: ndb.Key of the program.
Returns:
ndb.Query object to fetch all projects for the specified program.
"""
return project_model.Project.query(
project_model.Project.program == ndb.Key.from_old_key(program_key))
def queryAllProjectsForStudent(student_key):
"""Returns a query to fetch all projects for the specified student.
Args:
student_key: ndb.Key of the student.
Returns:
ndb.Query object to fetch all projects for the specified student.
"""
return project_model.Project.query(ancestor=student_key)
def queryAcceptedProjectsForOrg(org_key):
"""Returns a query to fetch all projects accepted for
the specified organization.
Args:
org_ket: ndb.Key of the organization.
Returns:
ndb.Query object to fetch all projects accepted for the specified
organization.
"""
return project_model.Project.query(
project_model.Project.organization == org_key,
project_model.Project.status == project_model.Status.ACCEPTED)
def queryAllProjectsForOrgMember(profile_key):
"""Returns a query to fetch all projects mentored by the specified
organization memebr.
Args:
profile_key: ndb.Key of the profile.
Returns:
ndb.Query object to fetch all projects mentored by specified profile.
"""
return project_model.Project.query(
project_model.Project.mentors == profile_key)
@ndb.transactional
def updateProject(project_key, project_properties):
"""Updates the specified project based on the specified properties.
Args:
project_key: Project key.
project_properties: A dict containing properties to be updated.
Returns:
rich_bool.RichBool whose value is set to True if the project has been
successfully updated. In that case, extra part points to the newly updated
project entity. Otherwise, rich_bool.RichBool whose value is set to
False and extra part is a string that represents the reason why the action
could not be completed.
"""
for prop in project_properties:
if prop in _PROPERTIES_NOT_FOR_UPDATE:
raise ValueError('Property %s cannot be updated by this function' % prop)
project = project_key.get()
try:
project.populate(**project_properties)
project.put()
return rich_bool.RichBool(True, project)
except ValueError as e:
logging.warning(e)
return rich_bool.RichBool(False, extra=str(e))
except datastore_errors.BadValueError as e:
logging.warning(e)
return rich_bool.RichBool(False, extra=str(e))
except TypeError as e:
logging.warning(e)
return rich_bool.RichBool(False, extra=str(e))
@ndb.transactional
def withdrawProject(project_key):
"""Withdraws the specified project.
Args:
project_key: ndb.Key of the project.
Returns:
rich_bool.RichBool whose value is set to True, if the specified project
is successfully withdrawn at this time. Otherwise, rich_bool.RichBool whose
value is set to False and extra part is a string that represents the reason
why the project cannot be withdrawn.
"""
project = project_key.get()
if project.status == project_model.Status.ACCEPTED:
project.status = project_model.Status.WITHDRAWN
profile = project_key.parent().get()
profile.student_data.number_of_projects -= 1
ndb.put_multi([project, profile])
return rich_bool.TRUE
elif project.status == project_model.Status.WITHDRAWN:
return rich_bool.TRUE
elif project.status == project_model.Status.FAILED:
return rich_bool.RichBool(False, ILLEGAL_PROJECT_STATE)
@ndb.transactional
def acceptProject(project_key):
"""Marks the specified project as accepted.
Please note that this function does not have anything to do with the
corresponding proposal. The function may be used, for example, to accept
a project which was withdrawn before.
Args:
project_key: ndb.Key of the project.
Returns:
rich_bool.RichBool whose value is set to True, if the specified project
is successfully accepted at this time. Otherwise, rich_bool.RichBool whose
value is set to False and extra part is a string that represents the reason
why the project cannot be accepted.
"""
project = project_key.get()
if project.status == project_model.Status.ACCEPTED:
return rich_bool.TRUE
elif project.status == project_model.Status.WITHDRAWN:
project.status = project_model.Status.ACCEPTED
profile = project_key.parent().get()
profile.student_data.number_of_projects += 1
ndb.put_multi([project, profile])
return rich_bool.TRUE
elif project.status == project_model.Status.FAILED:
return rich_bool.RichBool(False, ILLEGAL_PROJECT_STATE)
@ndb.transactional
def assignMentors(project_key, mentors):
"""Assigns the specified mentors to the specified project.
Args:
project_key: ndb.Key of the project.
mentors: List of profile_model.Profile entities of the mentors to
assign for the project.
Returns:
rich_bool.RichBool whose value is set to True, if the specified project
is assigned the specified mentors. Otherwise, rich_bool.RichBool
whose value is set to False and extra part is a list of profile entities
of users who are not eligible to be assigned as mentors.
"""
project = project_key.get()
if not mentors:
return rich_bool.RichBool(False, [])
else:
not_valid = [
mentor for mentor in mentors
if project.organization not in mentor.mentor_for]
if not_valid:
return rich_bool.RichBool(False, not_valid)
else:
project.mentors = [mentor.key for mentor in mentors]
project.put()
return rich_bool.TRUE