# HG changeset patch # User Lennard de Rijk # Date 1232815174 0 # Node ID 606871fda11ca13ced8f112fcca61e25b5899458 # Parent 36a90d0e92115c63f40f88898ed00f9c2a931bf3 Added request creation and processing to role.py. This is used if you want to request to become a certain role for a group. For instance becoming a club member. The process request view will also be used to cancel outstanding invites might this be necessary. Patch by: Lennard de Rijk Reviewed by: to-be-reviewed diff -r 36a90d0e9211 -r 606871fda11c app/soc/templates/soc/request/process_request.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/soc/templates/soc/request/process_request.html Sat Jan 24 16:39:34 2009 +0000 @@ -0,0 +1,38 @@ +{% extends "soc/base.html" %} +{% comment %} +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. +{% endcomment %} +{% load forms_helpers %} + +{% block header_title %} +{{ page_name }} for {{ entity.requester.link_id }} +{% endblock %} + +{% block body %} +

+ +This is a request from {{ entity.link_id }} to become a {{ entity.role_verbose }} for {{entity.scope.name }}. +Please select your response. + +

+ + + + + + + + + + +{% endblock %} diff -r 36a90d0e9211 -r 606871fda11c app/soc/views/models/club_admin.py --- a/app/soc/views/models/club_admin.py Sat Jan 24 14:14:14 2009 +0000 +++ b/app/soc/views/models/club_admin.py Sat Jan 24 16:39:34 2009 +0000 @@ -55,6 +55,9 @@ rights['delete'] = [access.checkIsDeveloper] rights['invite'] = [access.checkIsClubAdminForClub] rights['accept_invite'] = [access.checkCanCreateFromRequest('club_admin')] + rights['request'] = [access.deny] + rights['process_request'] = [access.checkIsClubAdminForClub, + access.checkCanProcessRequest('club_admin')] new_params = {} new_params['logic'] = soc.logic.models.club_admin.logic @@ -117,5 +120,7 @@ edit = view.edit invite = view.invite list = view.list +process_request = view.processRequest public = view.public +request = view.request export = view.export diff -r 36a90d0e9211 -r 606871fda11c app/soc/views/models/host.py --- a/app/soc/views/models/host.py Sat Jan 24 14:14:14 2009 +0000 +++ b/app/soc/views/models/host.py Sat Jan 24 16:39:34 2009 +0000 @@ -64,6 +64,9 @@ rights['invite'] = [access.checkIsHost] rights['list'] = [access.checkIsHost] rights['accept_invite'] = [access.checkCanCreateFromRequest('host')] + rights['request'] = [access.deny] + rights['process_request'] = [access.checkIsHost, + access.checkCanProcessRequest('host')] new_params = {} @@ -153,6 +156,7 @@ edit = view.edit invite = view.invite list = view.list +process_request = view.processRequest public = view.public +request = view.request export = view.export - diff -r 36a90d0e9211 -r 606871fda11c app/soc/views/models/request.py --- a/app/soc/views/models/request.py Sat Jan 24 14:14:14 2009 +0000 +++ b/app/soc/views/models/request.py Sat Jan 24 16:39:34 2009 +0000 @@ -39,6 +39,7 @@ from soc.views import out_of_band from soc.views.helper import access from soc.views.helper import decorators +from soc.views.helper import dynaform from soc.views.helper import redirects from soc.views.helper import responses from soc.views.helper import widgets @@ -107,11 +108,28 @@ new_params['extra_django_patterns'] = patterns new_params['invite_processing_template'] = 'soc/request/process_invite.html' + new_params['request_processing_template'] = 'soc/request/process_request.html' params = dicts.merge(params, new_params) super(View, self).__init__(params=params) + # create and store the special forms for invite and requests + params['invite_form'] = params['create_form'] + + updated_fields = { + 'link_id': forms.CharField(widget=widgets.ReadOnlyInput(), + required=True), + 'group_id' : forms.CharField(widget=widgets.ReadOnlyInput(), + required=True)} + + request_form = dynaform.extendDynaForm( + dynaform = self._params['create_form'], + dynafields = updated_fields) + + params['request_form'] = request_form + + @decorators.merge_params @decorators.check_access def processInvite(self, request, access_type, diff -r 36a90d0e9211 -r 606871fda11c app/soc/views/models/role.py --- a/app/soc/views/models/role.py Sat Jan 24 14:14:14 2009 +0000 +++ b/app/soc/views/models/role.py Sat Jan 24 16:39:34 2009 +0000 @@ -28,6 +28,8 @@ from soc.logic import dicts from soc.logic.models import request as request_logic +from soc.logic.models import user as user_logic +from soc.logic.helper import notifications as notifications_helper from soc.logic.helper import request as request_helper from soc.views.helper import decorators from soc.views.helper import redirects @@ -58,13 +60,19 @@ """ new_params = {} - # TODO(ljvderijk) add request and process_request + # TODO(ljvderijk) parameterize these patterns patterns = [(r'^%(url_name)s/(?Pinvite)/%(scope)s$', 'soc.views.models.%(module_name)s.invite', - 'Create invite for %(name_plural)s'), + 'Create invite for %(name)s'), (r'^%(url_name)s/(?Paccept_invite)/%(scope)s/%(lnp)s$', 'soc.views.models.%(module_name)s.accept_invite', - 'Accept invite for %(name_plural)s')] + 'Accept invite for %(name)s'), + (r'^%(url_name)s/(?Prequest)/%(scope)s$', + 'soc.views.models.%(module_name)s.request', + 'Create a Request to become %(name)s'), + (r'^%(url_name)s/(?Pprocess_request)/%(scope)s/%(lnp)s$', + 'soc.views.models.%(module_name)s.process_request', + 'Process request for %(name)s')] new_params['extra_django_patterns'] = patterns new_params['scope_redirect'] = redirects.getInviteRedirect @@ -113,7 +121,7 @@ # get the request view parameters and initialize the create form request_params = request_view.view.getParams() - form = request_params['create_form'](initial=fields) + form = request_params['invite_form'](initial=fields) # construct the appropriate response return super(View, self)._constructResponse(request, entity=None, @@ -132,7 +140,7 @@ # get the request view parameters and populate the form using POST data request_params = request_view.view.getParams() - form = request_params['create_form'](request.POST) + form = request_params['invite_form'](request.POST) if not form.is_valid(): # return the invalid form response @@ -143,22 +151,11 @@ key_name, form_fields = soc.views.helper.forms.collectCleanedFields(form) # get the group entity for which this request is via the scope_path - group_key_fields = kwargs['scope_path'].rsplit('/', 1) - - if len(group_key_fields) == 1: - # there is only a link_id - fields = {'link_id': group_key_fields[0]} - else: - # there is a scope_path and link_id - fields = {'scope_path': group_key_fields[0], - 'link_id': group_key_fields[1]} - - group = params['group_logic'].getForFields(fields, unique=True) - - if group.scope_path: - request_scope_path = '%s/%s' % [group.scope_path, group.link_id] - else: - request_scope_path = group.link_id + group = self._getGroupEntityFromScopePath(params['group_logic'], + kwargs['scope_path']) + + # get the request scope path + request_scope_path = self._getRequestScopePathFromGroup(group) # create the fields for the new request entity request_fields = {'link_id': form_fields['link_id'].link_id, @@ -175,10 +172,51 @@ # create the request entity entity = request_logic.logic.updateOrCreateFromKeyName(request_fields, key_name) - + + # send out an invite notification + notifications_helper.sendInviteNotification(entity) + # TODO(ljvderijk) redirect to a more useful place like the group homepage return http.HttpResponseRedirect('/') + def _getGroupEntityFromScopePath(self, group_logic, scope_path): + """Returns a group entity by using the given scope_path that's in kwargs. + + Args: + group_logic: logic for the group which should be retrieved + kwargs: the Key Fields for the specified entity + """ + group_key_fields = scope_path.rsplit('/',1) + + if len(group_key_fields) == 1: + # there is only a link_id + fields = {'link_id' : group_key_fields[0]} + else: + # there is a scope_path and link_id + fields = {'scope_path' : group_key_fields[0], + 'link_id' : group_key_fields[1]} + + group = group_logic.getForFields(fields, unique=True) + + return group + + def _getRequestScopePathFromGroup(self, group_entity): + """Returns the scope_path that should be put in a request for a given group. + + Args: + group_entity: The group entity for which the request scope_path should + be returned. + """ + + if group_entity.scope_path: + request_scope_path = '%s/%s' % [ + group_entity.scope_path, group_entity.link_id] + else: + request_scope_path = group_entity.link_id + + return request_scope_path + + @decorators.merge_params @decorators.check_access def acceptInvite(self, request, access_type, @@ -281,3 +319,150 @@ kwargs: the Key Fields for the specified entity """ pass + + + @decorators.merge_params + @decorators.check_access + def request(self, request, access_type, + page_name=None, params=None, **kwargs): + """Handles the GET request concerning the view that creates a request + for attaining a certain Role. + + Args: + request: the standard Django HTTP request object + page_name: the page name displayed in templates as page and header title + params: a dict with params for this View + kwargs: the Key Fields for the specified entity + """ + + # get the context for this webpage + context = responses.getUniversalContext(request) + context['page_name'] = page_name + + if request.method == 'POST': + return self.requestPost(request, context, params, **kwargs) + else: + # request.method == 'GET' + return self.requestGet(request, context, params, **kwargs) + + def requestGet(self, request, context, params, **kwargs): + """Handles the GET request concerning the creation of a request + to attain a role. + + Args: + request: the standard Django HTTP request object + context: dictionary containing the context for this view + params: a dict with params for this View + kwargs: the Key Fields for the specified entity + """ + + # set right fields for the request form + user_entity = user_logic.logic.getForCurrentAccount() + fields = {'link_id' : user_entity.link_id, + 'role' : '%(module_name)s' %(params), + 'group_id' : kwargs['scope_path']} + + # get the request view parameters and initialize the create form + request_params = request_view.view.getParams() + form = request_params['request_form'](initial=fields) + + # construct the appropriate response + return super(View, self)._constructResponse(request, entity=None, + context=context, form=form, params=params) + + def requestPost(self, request, context, params, **kwargs): + """Handles the POST request concerning the creation of a request + to attain a role. + + Args: + request: the standard Django HTTP request object + context: dictionary containing the context for this view + params: a dict with params for this View + kwargs: the Key Fields for the specified entity + """ + + # get the request view parameters and populate the form using POST data + request_params = request_view.view.getParams() + form = request_params['invite_form'](request.POST) + + if not form.is_valid(): + # return the invalid form response + return self._constructResponse(request, entity=None, context=context, + form=form, params=params) + + # get the group entity for which this request is via the scope_path + group = self._getGroupEntityFromScopePath(params['group_logic'], + kwargs['scope_path']) + + # get the request scope path + request_scope_path = self._getRequestScopePathFromGroup(group) + + # defensively set the fields we need for this request and set state to new + user_entity = user_logic.logic.getForCurrentAccount() + request_fields = {'link_id' : user_entity.link_id, + 'scope' : group, + 'scope_path' : request_scope_path, + 'role' : params['module_name'], + 'role_verbose' : params['name'], + 'state' : 'new'} + + # extract the key_name for the new request entity + key_fields = request_logic.logic.getKeyFieldsFromDict(request_fields) + key_name = request_logic.logic.getKeyNameForFields(key_fields) + + # create the request entity + entity = request_logic.logic.updateOrCreateFromKeyName(request_fields, key_name) + + # TODO(ljvderijk) send out a message to alert the users able to process this request + + # redirect to roles overview + return http.HttpResponseRedirect('/user/roles') + + + @decorators.merge_params + @decorators.check_access + def processRequest(self, request, access_type, + page_name=None, params=None, **kwargs): + """Creates the page upon which a request can be processed. + + Args: + request: the standard Django HTTP request object + access_type : the name of the access type which should be checked + page_name: the page name displayed in templates as page and header title + params: a dict with params for this View + kwargs: the Key Fields for the specified entity + """ + + # get the context for this webpage + context = responses.getUniversalContext(request) + context['page_name'] = page_name + + # get the request entity using the information from kwargs + fields = {'link_id': kwargs['link_id'], + 'scope_path': kwargs['scope_path'], + 'role': params['module_name']} + request_entity = request_logic.logic.getForFields(fields, unique=True) + + get_dict = request.GET + + if 'status' in get_dict.keys(): + if get_dict['status'] in ['group_accepted', 'rejected', 'ignored']: + # update the request_entity and redirect away from this page + request_state = get_dict['status'] + request_logic.logic.updateModelProperties(request_entity, { + 'state': get_dict['status']}) + + if request_state == 'group_accepted': + notifications_helper.sendInviteNotification(request_entity) + + # TODO(ljvderijk) redirect to group requests overview + return http.HttpResponseRedirect('/') + + # put the entity in the context + context['entity'] = request_entity + context['module_name'] = params['module_name'] + + #display the request processing page using the appropriate template + template = request_view.view.getParams()['request_processing_template'] + + return responses.respond(request, template, context=context) \ No newline at end of file