def effective_principals(self, request): userid = self.authenticated_userid(request) if userid is not None: groups = group_finder(userid, request) # If the user is a moderator check the currently selected profile if len(groups) > 0 and "group:moderators" in groups: profile = get_current_profile(request) # Try to find the profile in the list of profiles associated to # current user profile_query = ( Session.query(Profile.code) .join(users_profiles) .join(User) .filter(User.username == userid) .filter(Profile.code == profile) ) try: profile_query.one() except NoResultFound: # Profile not found: User is not moderator for current # profile, remove group 'moderator' from principals principals = AuthTktAuthenticationPolicy.effective_principals(self, request) if "group:moderators" in principals: principals.remove("group:moderators") return principals # In all other cases use Pyramid's default authentication policy return AuthTktAuthenticationPolicy.effective_principals(self, request)
def download(self): """ """ return render_to_response( get_customized_template_path(self.request, 'download_view.mak'), { 'profile': get_current_profile(self.request), 'locale': get_current_locale(self.request) }, self.request)
def _get_profile_filter(self, request): """ Return a spatial filter based on the profile boundary of the current profile which is queried from the database. Copied from the ActivityProtocol3 """ profile = self.Session.query(Profile).\ filter(Profile.code == get_current_profile(request)).\ first() if profile is None: return (Activity.id == 0) return functions.intersects(Activity.point, profile.geometry)
def _processProfile(request, dbProfile, isGlobal=False): yaml_file = APPLICATION_YAML if isGlobal is False: yaml_file = "%s/%s" % (dbProfile.code, APPLICATION_YAML) if isGlobal is False: pass # Try to find and open profile config file try: profile_stream = open("%s/%s" % (profile_directory_path(request), yaml_file), 'r') profile_config = yaml.load(profile_stream) if 'application' not in profile_config: # Not a valid config file return None app_config = profile_config['application'] # Collect values code = dbProfile.code name = app_config['name'] if 'name' in app_config else 'Unknown' active = get_current_profile(request) == dbProfile.code geometry = None if dbProfile.geometry is not None: geometry = geojson.loads(geojson.dumps(shapely.wkb.loads( str(dbProfile.geometry.geom_wkb) ))) return { 'name': name, 'profile': code, 'geometry': geometry, 'active': active } except IOError: # File not found return None
def download_customize(self, item_type): """ """ item_type = validate_item_type(item_type) if self.request.POST: format = self.request.POST.get('format', 'csv') involvements = self.request.POST.get('involvements', 'full') attributes = self.request.POST.getall('attributes') if format == 'csv': header, rows = to_flat_table( self.request, item_type, involvements=involvements, columns=attributes) return render_to_response( 'csv', {'header': header, 'rows': rows}, self.request) # Order matters: The first entry is the default value. formats = [ ('csv', 'CSV'), ] attributes = [] for config_key in getCategoryList( self.request, item_type).getAllKeys(): attributes.append(( config_key.getName(), config_key.getTranslatedName())) if item_type == 'a': template = get_customized_template_path( self.request, 'activities/download.mak') else: template = get_customized_template_path( self.request, 'stakeholders/download.mak') template_values = { 'profile': get_current_profile(self.request), 'locale': get_current_locale(self.request), 'formats': formats, 'attributes': attributes } return render_to_response(template, template_values, self.request)
def register(self): """ Returns and process user self registration form. """ _ = self.request.translate # Define a colander Schema for the self registration class Schema(colander.Schema): profile = colander.SchemaNode( colander.String(), widget=deform.widget.TextInputWidget(template='hidden'), name='profile', title='Profile', default=get_current_profile(self.request), missing=get_default_profile(self.request)) username = colander.SchemaNode( colander.String(), validator=_user_already_exists, title=_('Username')) password = colander.SchemaNode( colander.String(), validator=colander.Length(min=5), widget=deform.widget.CheckedPasswordWidget(size=20), title=_('Password')) firstname = colander.SchemaNode( colander.String(), missing=unicode(u''), title=_('First Name')) lastname = colander.SchemaNode( colander.String(), missing=unicode(u''), title=_('Last Name')) email = colander.SchemaNode( colander.String(), default='', title=_("Valid Email"), validator=_is_valid_email) schema = Schema() deform.Form.set_default_renderer(mako_renderer) buttons = [deform.Button( 'submit', _('Submit'), css_class='btn btn-primary')] form = deform.Form(schema, buttons=buttons) def succeed(): """ """ # Request all submitted values profile_field = self.request.POST.get("profile") username_field = self.request.POST.get("username") firstname_field = self.request.POST.get("firstname") lastname_field = self.request.POST.get("lastname") password_field = self.request.POST.get("password") email_field = self.request.POST.get("email") # Get the selected profile selected_profile = Session.query(Profile).filter( Profile.code == profile_field).first() # Get the initial user group user_group = Session.query(Group).filter( Group.name == "editors").first() # Create an activation uuid activation_uuid = uuid.uuid4() # Create a new user new_user = User(username_field, password_field, email_field, firstname=firstname_field, lastname=lastname_field, activation_uuid=activation_uuid, registration_timestamp=datetime.now()) # Set the user profile new_user.profiles = [selected_profile] new_user.groups = [user_group] # Commit the new user Session.add(new_user) activation_dict = { "firstname": new_user.firstname, "lastname": new_user.lastname, "activation_link": "http://%s/users/activate?uuid=%s&username="******"%s" % ( self.request.environ['HTTP_HOST'], activation_uuid, new_user.username) } email_text = render( get_customized_template_path( self.request, 'emails/account_activation.mak'), activation_dict, self.request) self._send_email( [email_field], _(u"Activate your Account"), email_text) return render_to_response( get_customized_template_path( self.request, 'users/registration_success.mak'), {}, self.request) ret = self._render_form(form, success=succeed) # 'ret' is a Response object if the form was submitted with success. In # this case, it is not possible to add any parameters to it. if not isinstance(ret, Response): self._handle_parameters() ret['profile'] = get_current_profile(self.request) ret['locale'] = get_current_locale(self.request) # Render the return values return render_to_response( get_customized_template_path( self.request, 'users/registration_form.mak'), ret, self.request) return ret
def account(self): """ Shows user account details to registered users. """ _ = self.request.translate userid = authenticated_userid(self.request) # Define a colander Schema for the self registration class Schema(colander.Schema): username = colander.SchemaNode( colander.String(), missing=None, widget=deform.widget.TextInputWidget( readonly=True, readonly_template='readonly/customTextinputReadonly'), title=_('Username')) password = colander.SchemaNode( colander.String(), validator=colander.Length(min=5), widget=deform.widget.CheckedPasswordWidget(size=20), title=_('Password')) firstname = colander.SchemaNode( colander.String(), missing=None, title=_('First Name')) lastname = colander.SchemaNode( colander.String(), missing=None, title=_('Last Name')) email = colander.SchemaNode( colander.String(), missing=None, widget=deform.widget.TextInputWidget( readonly=True, readonly_template='readonly/customTextinputReadonly'), title=_('Valid Email'),) schema = Schema() deform.Form.set_default_renderer(mako_renderer) form = deform.Form(schema, buttons=(deform.Button( title=_(u'Update'), css_class='btn btn-primary'), ), use_ajax=True) # Get the user data user = Session.query(User).filter(User.username == userid).first() data = { 'username': user.username, 'firstname': user.firstname, 'lastname': user.lastname, 'email': user.email } def succeed(): # Request all submitted values firstname_field = self.request.POST.get("firstname") lastname_field = self.request.POST.get("lastname") password_field = self.request.POST.get("password") # Update user fields user.firstname = firstname_field user.lastname = lastname_field if password_field is not None and password_field != '': user.password = password_field return Response( '<div class="alert alert-success">%s</div>' % _('Your user settings were updated.')) ret = self._render_form(form, success=succeed, appstruct=data) if not isinstance(ret, Response): self._handle_parameters() ret['profile'] = get_current_profile(self.request) ret['locale'] = get_current_locale(self.request) ret['username'] = user.username return render_to_response( get_customized_template_path( self.request, 'users/account_form.mak'), ret, self.request) return ret
def read_many(self, public=False): """ Return many :term:`Stakeholders`. .. seealso:: :ref:`read-many` For each :term:`Stakeholder`, only one version is visible, always the latest visible version to the current user. This means that logged in users can see their own pending versions and moderators of the current profile can see pending versions as well. If you don't want to show pending versions, consider using :class:`lmkp.views.stakeholders.StakeholderView.read_many_public` instead. By default, the :term:`Stakeholders` are ordered with the :term:`Stakeholder` having the most recent change being on top. Args: ``public`` (bool): A boolean indicating whether to return only versions visible to the public (eg. pending) or not. Matchdict parameters: ``/stakeholders/{output}`` ``output`` (str): If the output format is not valid, a 404 Response is returned. The following output formats are supported: ``json``: Return the :term:`Stakeholders` as JSON. ``html``: Return the :term:`Stakeholders` as HTML (eg. the `Grid View`) ``form``: Returns the form to create a new :term:`Stakeholder`. ``download``: Returns the page to download :term:`Stakeholders`. Request parameters: ``page`` (int): The page parameter is used to paginate :term:`Items`. In combination with ``pagesize`` it defines the offset. ``pagesize`` (int): The pagesize parameter defines how many :term:`Items` are displayed at once. It is used in combination with ``page`` to allow pagination. ``status`` (str): Use the status parameter to limit results to displaying only versions with a certain :term:`status`. Returns: ``HTTPResponse``. Either a HTML or a JSON response. """ output_format = get_output_format(self.request) if output_format == 'json': items = stakeholder_protocol.read_many(self.request, public=False) return render_to_response('json', items, self.request) elif output_format == 'html': page, page_size = get_page_parameters(self.request) items = stakeholder_protocol.read_many( self.request, public=public, limit=page_size, offset=page_size * page - page_size) spatial_filter = None status_filter = get_status_parameter(self.request) __, is_moderator = get_user_privileges(self.request) template_values = self.get_base_template_values() template_values.update({ 'data': items['data'] if 'data' in items else [], 'total': items['total'] if 'total' in items else 0, 'spatialfilter': spatial_filter, 'invfilter': None, 'statusfilter': status_filter, 'currentpage': page, 'pagesize': page_size, 'is_moderator': is_moderator, 'handle_query_string': handle_query_string }) return render_to_response( get_customized_template_path( self.request, 'stakeholders/grid.mak'), template_values, self.request) elif output_format == 'form': is_logged_in, __ = get_user_privileges(self.request) if not is_logged_in: raise HTTPForbidden() new_involvement = self.request.params.get('inv', None) template_values = renderForm( self.request, 'stakeholders', inv=new_involvement) if isinstance(template_values, Response): return template_values template_values.update({ 'profile': get_current_profile(self.request), 'locale': get_current_locale(self.request) }) return render_to_response( get_customized_template_path( self.request, 'stakeholders/form.mak'), template_values, self.request ) elif output_format == 'download': download_view = DownloadView(self.request) return download_view.download_customize('stakeholders') else: raise HTTPNotFound()
def evaluation(self, data=None): ret = {'success': False} json_data = self.request.json_body if data is None else data if json_data is None: ret['msg'] = 'No data provided' return ret if validate_item_type(json_data.get('item', 'a')) == 'sh': self.db_item = Stakeholder self.db_taggroup = SH_Tag_Group self.db_tag = SH_Tag self.db_key = SH_Key self.db_value = SH_Value self.protocol = StakeholderProtocol3(Session) else: self.db_item = Activity self.db_taggroup = A_Tag_Group self.db_tag = A_Tag self.db_key = A_Key self.db_value = A_Value self.protocol = ActivityProtocol3(Session) # Make sure the json is valid if 'group_by' not in json_data: ret['msg'] = "Missing parameter 'group by': At least one column " "needs to be specified." return ret if not isinstance(json_data['group_by'], list): ret['msg'] = "Parameter 'group by' needs to be an array." return ret if 'attributes' not in json_data: ret['msg'] = "Missing attributes: No attributes were specified." return ret for attr in json_data['attributes']: test, msg = self._check_function( json_data['attributes'][attr], attr) if test is not True: ret['msg'] = msg return ret if 'locales' in json_data and not isinstance( json_data['locales'], list): ret['msg'] = "Parameter 'locales' needs to be an array." return ret translate_keys = json_data.get('translate', {}).get('keys', []) if translate_keys and not isinstance(translate_keys, list): ret['msg'] = "Parameter 'translate[\'keys\']' needs to be an " "array." return ret for k in translate_keys: if not isinstance(k, list): ret['msg'] = "Value of 'translate[\'keys\']' needs to be " "an array of arrays." return ret a_ids = json_data.get('a_ids', []) if not isinstance(a_ids, list): ret['msg'] = "Parameter 'a_ids' needs to be an array." return ret for i in a_ids: if not isinstance(i, str): ret['msg'] = "Entries of parameter 'a_ids' need to be " "strings (the UUIDs of Activities)" return ret sh_ids = json_data.get('sh_ids', []) if not isinstance(sh_ids, list): ret['msg'] = "Parameter 'sh_ids' needs to be an array." return ret for i in sh_ids: if not isinstance(i, str): ret['msg'] = "Entries of parameter 'sh_ids' need to be " "strings (the UUIDs of Stakeholders)" return ret if self.db_item == Activity: this_id_filter = a_ids other_id_filter = sh_ids else: this_id_filter = sh_ids other_id_filter = a_ids this_filter = [] other_filter = [] if 'filter' in json_data: params = [] for filters in json_data.get('filter', '').split('&'): try: f = filters.split('=') if len(f) == 2: params.append((f[0], f[1])) except: pass # Simulate a request to send the filters req = DummyRequest() req.params = MultiDict(params) a_tag_filter, __, sh_tag_filter, __ = self.protocol._filter(req) if self.db_item == Activity: this_filter = a_tag_filter other_filter = sh_tag_filter else: this_filter = sh_tag_filter other_filter = a_tag_filter isInvolvementRequired = ( self.db_item == Stakeholder or len(other_filter) + len(other_id_filter) > 0) # Collect all keys to be translated (values are translated in the # query) locales = ['default'] langs = [] locales.extend(json_data.get('locales', [])) translated_keys = {} exclude_from_translation = ['Activity', 'Stakeholder'] keys = [] for key, __ in json_data.get('attributes', {}).iteritems(): if key not in exclude_from_translation and key not in keys: keys.append(key) for key in json_data.get('group_by', []): if key not in exclude_from_translation and key not in keys: keys.append(key) for key in translate_keys: for k in key: if k not in keys: keys.append(k) for l in locales: locale = l if l == 'default': locale = get_current_locale(self.request) db_lang = Session.query(Language).filter( Language.locale == locale).first() langs.append((l, db_lang)) translated_keys[l] = get_translated_db_keys( self.db_key, keys, db_lang) # Get groups groups_subqueries, groups_columns = self._get_group_by( json_data['group_by'], langs) # Get functions functions_subqueries, functions_columns = \ self._get_attribute_functions(json_data['attributes']) # Prepare basic query q = Session.query(*groups_columns + functions_columns).\ join(self.db_taggroup).\ join(self.db_item) # Join with further groups for g_sq in groups_subqueries[1:]: q = q.outerjoin(g_sq, g_sq.c.item_id == self.db_item.id) # Join with functions for f_sq in functions_subqueries: q = q.outerjoin(f_sq, f_sq.c.item_id == self.db_item.id) # Apply status filter (fix: active) q = q.filter(self.db_item.fk_status == 2) if (this_id_filter): q = q.filter(self.db_item.identifier.in_(this_id_filter)) # Apply filters filter_subqueries = self.protocol.Session.query( self.db_item.id.label('a_filter_id') ) for x in this_filter: # Collect the IDs for each filter taggroups_sq = x.subquery() single_subquery = self.protocol.Session.query( self.db_item.id.label('a_filter_id') ).\ join(self.db_taggroup).\ join(taggroups_sq, taggroups_sq.c.a_filter_tg_id == self.db_taggroup.id).\ subquery() # Join each found ID with previously found IDs filter_subqueries = filter_subqueries.\ join(single_subquery, single_subquery.c.a_filter_id == self.db_item.id) filter_subqueries = filter_subqueries.subquery() q = q.join( filter_subqueries, filter_subqueries.c.a_filter_id == self.db_item.id) # Apply profile boundary filter if self.db_item == Activity: p = json_data.get('profile', get_current_profile(self.request)) profile = Session.query(Profile).\ filter(Profile.code == p).\ first() if profile is not None: q = q.filter(geofunctions.intersects( self.db_item.point, profile.geometry)) # Apply grouping and ordering q = q.group_by(*groups_columns).\ order_by(groups_columns[0]) if isInvolvementRequired: if self.db_item == Stakeholder: inv_subquery = Session.query( Involvement.fk_stakeholder.label('id') ).\ join(Activity).\ filter(Activity.fk_status == 2) p = json_data.get('profile', get_current_profile(self.request)) profile = Session.query(Profile).\ filter(Profile.code == p).\ first() if profile is not None: inv_subquery = inv_subquery.filter(geofunctions.intersects( Activity.point, profile.geometry)) other_db_item = Activity other_db_taggroup = A_Tag_Group else: inv_subquery = Session.query( Involvement.fk_activity.label('id') ).\ join(Stakeholder).\ filter(Stakeholder.fk_status == 2) other_db_item = Stakeholder other_db_taggroup = SH_Tag_Group if (other_id_filter): inv_subquery = inv_subquery.filter( other_db_item.identifier.in_(other_id_filter)) # Apply filters filter_subqueries = self.protocol.Session.query( other_db_item.id.label('a_filter_id') ) for x in other_filter: # Collect the IDs for each filter taggroups_sq = x.subquery() try: single_subquery = self.protocol.Session.query( other_db_item.id.label('a_filter_id') ).\ join(other_db_taggroup).\ join(taggroups_sq, taggroups_sq.c.a_filter_tg_id == other_db_taggroup.id).\ subquery() except AttributeError: single_subquery = self.protocol.Session.query( other_db_item.id.label('a_filter_id') ).\ join(other_db_taggroup).\ join(taggroups_sq, taggroups_sq.c.sh_filter_tg_id == other_db_taggroup.id).\ subquery() # Join each found ID with previously found IDs filter_subqueries = filter_subqueries.\ join(single_subquery, single_subquery.c.a_filter_id == other_db_item.id) filter_subqueries = filter_subqueries.subquery() inv_subquery = inv_subquery.join( filter_subqueries, filter_subqueries.c.a_filter_id == other_db_item.id) inv_subquery = inv_subquery.subquery() q = q.filter(self.db_item.id.in_( select([inv_subquery.c.id]) )) data = [] for res in q.all(): data = _handle_single_line( data, res, json_data.get('group_by'), json_data.get('attributes'), translated_keys) # Do a translation of groupable if available groupable_translated = [] for key in translate_keys: translations = [] for k in key: t = { 'key': k, 'default': k } for locale, key_translations in translated_keys.iteritems(): translation = ( None if k not in exclude_from_translation else k) for k_t in key_translations: if len(k_t) >= 2 and k_t[0] == k: translation = k_t[1] t[locale] = translation translations.append(t) groupable_translated.append(translations) if len(groupable_translated): ret.update({ 'translate': {'keys': groupable_translated} }) ret.update({ 'success': True, 'data': data }) return ret
def _handle_application_config(request): def __check_geometry(yaml_geom, profile_name): yaml_geom_geojson = geojson.loads( json.dumps(yaml_geom), object_hook=geojson.GeoJSON.to_instance) yaml_geom_shape = shapely.geometry.asShape(yaml_geom_geojson) # Query database db_profile = Session.query(Profile).\ filter(Profile.code == profile_name).first() if db_profile is None: # Global profile does not yet exist, create it Session.add(Profile(profile_name, yaml_geom_shape.wkt)) return "Geometry for profile '%s' created." % profile_name else: # Compare existing geometry with the one in config file geom_db = (shapely.wkb.loads(str(db_profile.geometry.geom_wkb)) if db_profile.geometry else None) if geom_db and geom_db.equals(yaml_geom_shape) is True: return ("Geometry for profile '%s' did not change." % profile_name) else: # Update geometry from global profile db_profile.geometry = yaml_geom_shape.wkt return "Geometry for profile '%s' updated." % profile_name msg = [] # First check global application configuration app_stream = open("%s/%s" % (profile_directory_path(request), APPLICATION_YAML), 'r') app_config = yaml.load(app_stream) if ('application' in app_config and 'geometry' in app_config['application']): msg.append(__check_geometry(app_config['application']['geometry'], 'global')) # Then check local application configuration if available # Try to find the profile in parameters from lmkp.views.views import get_current_profile locale_code = get_current_profile(request) # Only continue if a profile was found if locale_code is not None: try: locale_app_stream = open( "%s/%s" % ( locale_profile_directory_path(request), APPLICATION_YAML), 'r') locale_app_config = yaml.load(locale_app_stream) if ('application' in locale_app_config and 'geometry' in locale_app_config['application']): msg.append(__check_geometry( locale_app_config['application']['geometry'], locale_code)) except IOError: # No localized application configuration file found pass return msg