Exemple #1
0
def get_mandatory_keys(request, item, translated=False):
    from lokp.config.form import getCategoryList
    if item == 'a':
        configList = getCategoryList(request, 'activities')
    elif item == 'sh':
        configList = getCategoryList(request, 'stakeholders')
    return configList.getDesiredKeyNames(translated=translated, strict=True)
Exemple #2
0
def getFilterKeys(request):
    """
    Return two lists (the first for Activities, the second for Stakeholders)
    with the keys which can be filtered.
    Each list contains:
    - [0]: display name (translated)
    - [1]: internal name
    - [2]: the type of the key
    """
    def getList(categoryList):
        list = []
        for key in categoryList.getFilterableKeys():
            name = key.getName()
            translation = key.getTranslatedName()
            type = key.getType()
            list.append([
                translation if translation is not None else name, name,
                type.lower()
            ])
        return list

    aList = getList(getCategoryList(request, 'activities'))
    shList = getList(getCategoryList(request, 'stakeholders'))

    return aList, shList
Exemple #3
0
def getOverviewKeys(request):
    """
    Return two lists (the first for Activities, the second for Stakeholders)
    with the keys which are to be used in the involvement overview. Because
    these are the keys of the other side, the first one actually contains the
    keys for Stakeholders, the second one the keys for Activities!
    """
    from lokp.config.form import getCategoryList
    return (getCategoryList(request,
                            'activities').getInvolvementOverviewKeyNames(),
            getCategoryList(request,
                            'stakeholders').getInvolvementOverviewKeyNames())
Exemple #4
0
def form_geomtaggroups(request):
    """
    Simple service to return all the mainkeys of taggroups which can have
    geometries as defined in the configuration yaml.
    """
    categorylist = getCategoryList(request, 'activities')
    return {
        'mainkeys': categorylist.getMainkeyWithGeometry(withTranslation=True)
    }
Exemple #5
0
def getGridColumnKeys(request, itemType):
    """
    Return the keys used for the grid columns in the order specified in the
    configuration yaml.
    It returns an array where each entry contains
    - the original key name (used for ordering the column)
    - the translated key name (for display purposes)
    """
    from lokp.config.form import getCategoryList
    categoryList = getCategoryList(request, itemType)
    keys = []
    for key in sorted(categoryList.getGridColumnKeyNames(),
                      key=lambda k: k[2]):
        keys.append([key[0], key[1]])
    return keys
Exemple #6
0
def getFilterValuesForKey(request, predefinedType=None, predefinedKey=None):
    """
    Return a JSON representation of all the values for a given key.
    The JSON array contains an array for each entry with:
    - [0]: The display name (translated)
    - [1]: The internal name
    """

    type = request.params.get('type', predefinedType)
    key = request.params.get('key', predefinedKey)

    if type is None:
        return {'error': 'No type specified.'}

    if key is None:
        return {'error': 'No key specified'}

    itemType = None
    if type == 'a':
        itemType = 'activities'
    elif type == 'sh':
        itemType = 'stakeholders'

    if itemType is None:
        return {'error': 'Type not valid.'}

    categoryList = getCategoryList(request, itemType)

    tag = categoryList.findTagByKeyName(key)

    if tag is None:
        return {'error': 'Key not found.'}

    values = tag.getValues()

    if len(values) == 0:
        return {'error': 'No values found for this key.'}

    ret = []
    for v in sorted(values, key=lambda val: val.getOrderValue()):
        ret.append([v.getTranslation(), v.getName()])

    return ret
Exemple #7
0
    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)
Exemple #8
0
def getMapSymbolKeys(request):
    """
    Return a list with the keys which are used for the map symbols.
    Each entry of the array has
    - name of the key (translated)
    - name of the key (original)
    - mapsymbol data (usually an order number)
    If there is an attribute set, it is moved to the top of the list with the
    help of the order number
    """
    mapSymbolKeys = getCategoryList(request,
                                    'activities').getMapSymbolKeyNames()

    attrs = request.params.get('attrs', None)

    if attrs is not None:
        for m in mapSymbolKeys:
            if m[1] in attrs:
                m[2] = 0

    return sorted(mapSymbolKeys, key=lambda k: k[2])
Exemple #9
0
def renderReadonlyForm(request, itemType, itemJson):
    """
    Function to return a rendered form in readonly mode. The form is based on
    the configuration.
    """
    taggroup_count = len(itemJson.get('taggroups', []))
    # Hack to avoid showing involvements of items to be deleted (with no
    # taggroups)
    if taggroup_count == 0:
        itemJson['involvements'] = []

    deform.Form.set_default_renderer(mako_renderer)
    configCategoryList = getCategoryList(request, itemType)
    schema = addHiddenFields(colander.SchemaNode(colander.Mapping()), itemType)
    schema.add(
        colander.SchemaNode(
            colander.String(),
            widget=deform.widget.TextInputWidget(template='hidden'),
            name='statusId',
            title='',
            missing=colander.null))
    for cat in sorted(configCategoryList.getCategories(),
                      key=lambda cat: cat.order):
        schema.add(cat.getForm(request, readonly=True))

    form = deform.Form(schema)
    data = getFormdataFromItemjson(request, itemJson, itemType, readOnly=True)

    if data == {}:
        # If no formdata is available, it is very likely that the form has some
        # errors. In this case show an error message.
        errorList = checkValidItemjson(configCategoryList,
                                       itemJson,
                                       output='list')
        if len(errorList) > 0:
            url = None
            routeName = 'activities_read_one_history' \
                if itemType == 'activities' \
                else 'stakeholders_read_one_history'
            if 'id' in itemJson:
                url = request.route_url(routeName,
                                        output='html',
                                        uid=itemJson['id'])
            errorMsg = render(
                get_customized_template_path(
                    request, 'parts/messages/item_requested_not_valid.mak'),
                {'url': url}, request)
            return {'form': errorMsg}

    if 'category' in data and data['category'] is None:
        data['category'] = 0

    data['itemType'] = itemType
    statusId = itemJson['status_id'] if 'status_id' in itemJson \
        else colander.null
    data['statusId'] = statusId
    data['taggroup_count'] = taggroup_count
    html = form.render(data, readonly=True)

    geometry = json.dumps(
        itemJson['geometry']) if 'geometry' in itemJson else None

    # extract deal areas as polygons, contained in dictionary
    dealAreas = getTaggroupGeometries(itemJson)

    return {
        'form': html,
        'geometry': geometry,
        'dealAreas': json.dumps(dealAreas)
    }
Exemple #10
0
def renderForm(request, itemType, **kwargs):
    """
    Render the form for either Activity or Stakeholder
    """

    # Get the kwargs
    itemJson = kwargs.get('itemJson', None)
    newInvolvement = kwargs.get('inv', None)

    emptyTitle = _('Empty Form')
    emptyText = _('You submitted an empty form or did not make any changes.')
    errorTitle = _('Error')

    # Activity or Stakeholder
    if itemType == 'activities':
        # The initial category of the form
        formid = 'activityform'
        otherItemType = 'stakeholders'
    elif itemType == 'stakeholders':
        # The initial category of the form
        formid = 'stakeholderform'
        otherItemType = 'activities'
    else:
        raise HTTPBadRequest(
            'Unknown itemType (neither "activities" nor "stakeholders")')

    session = request.session
    oldCategory = None

    log.debug('Session before processing the form: %s' % session)

    # Use a different template rendering engine (mako instead of chameleon)
    deform.Form.set_default_renderer(mako_renderer)

    # Check if anything was submitted at all. If so, remember which category
    # was the one submitted.
    formSubmit = False
    if request.POST != {}:
        formSubmit = True
        for p in request.POST:
            if p == 'category':
                oldCategory = request.POST[p]
                break

    # Get the configuration of the categories (as defined in the config yaml)
    configCategoryList = getCategoryList(request, itemType)

    # Determine which category to show. If reopening the form after creating a
    # new Involvement, use the category of the Involvement. Else use the first
    # category of the configuration.
    if newInvolvement is not None:
        newInvCat = configCategoryList.findCategoryByInvolvementName(
            newInvolvement)
        if newInvCat is not None:
            newCategory = newInvCat.getId()
        else:
            newCategory = configCategoryList.getFirstCategoryId()
    else:
        newCategory = configCategoryList.getFirstCategoryId()

    # Collect a list with id and names of all available categories which will
    # be used to create the buttons based cat
    categoryListButtons = []
    for cat in sorted(configCategoryList.getCategories(),
                      key=lambda cat: cat.order):
        displayName = (cat.getTranslation()
                       if cat.getTranslation() is not None else cat.getName())
        categoryListButtons.append((cat.getId(), displayName))

    captured = None
    formHasErrors = False
    # Some sort of data used for feedback. Can be Javascript or something else
    feedbackData = None

    # Handle form submission: This can also be just the "submission" of a
    # single category which does not submit the item but stores the
    # information of the submitted category in the session.
    for p in request.POST:

        if (not (p.startswith('step_') or p in ['submit', 'delete']
                 or p.startswith('createinvolvement_'))):
            continue

        createInvolvement = False
        if p.startswith('createinvolvement_'):
            # If the form was "submitted" because a new involvement is to be
            # created, we need to remove the 'create_involvement' POST value,
            # otherwise Deform cannot validate the form.
            x = p.split('_')
            createInvolvement = x[1]
            request.POST.pop(p)

        # Do a validation of the submitted form data. To do this, it is
        # necessary to recreate a form with the same category that was
        # submitted.
        buttons = []

        # Prepare a form with the submitted category
        oldschema = addHiddenFields(colander.SchemaNode(colander.Mapping()),
                                    itemType)
        oldCat = configCategoryList.findCategoryById(oldCategory)
        if oldCat is not None:
            oldschema.add(oldCat.getForm(request))
            showSessionCategories = None
            if (itemJson is None or
                (itemType in session and 'form' in session[itemType]
                 and 'id' in session[itemType]['form']
                 and session[itemType]['form']['id'] == itemJson['id'])):
                showSessionCategories = itemType
            buttons = getFormButtons(
                request,
                categoryListButtons,
                oldCategory,
                showSessionCategories=showSessionCategories)
        # creates form?
        form = deform.Form(oldschema, buttons=buttons, formid=formid)

        if p == 'delete':
            captured = {}
        else:
            try:
                # Try to validate the form
                captured = form.validate(
                    request.POST.items())  # captured contains input values

            except deform.ValidationFailure as e:
                # The submitted values contains errors. Render the same form
                # again with error messages. It will be returned later.
                html = e.render()
                formHasErrors = True
        if formHasErrors is False:
            # The form is valid, store the captured data in the session.

            log.debug('Data captured by the form: %s' % captured)

            # If there is already some data in the session.
            if itemType in session and 'form' in session[itemType]:
                sessionItem = session[itemType][
                    'form']  # sessionItem contains values saved in session
                if (captured.get('id') == sessionItem.get('id') and
                        captured.get('version') == sessionItem.get('version')
                        and oldCategory in captured):
                    # It is the same item as already in the session, add or
                    # overwrite the form data.
                    updatedCategory = captured[oldCategory]
                    sessionItem[oldCategory] = updatedCategory

                    log.debug('Updated session item: Category %s' %
                              oldCategory)

                else:
                    # A different item is already in the session. It will be
                    # overwriten.
                    if 'category' in captured:
                        del (captured['category'])
                    session[itemType]['form'] = captured

                    log.debug('Replaced session item')

            else:
                # No data is in the session yet. Store the captured data
                # there.
                if 'category' in captured:
                    del (captured['category'])
                if itemType not in session:
                    session[itemType] = {}
                session[itemType][
                    'form'] = captured  # write session data to form of itemType (can be activity etc.)

                log.debug('Added session item')

            if p.startswith('step_'):
                # A button with a next category was clicked, set a new
                # current category to show in the form
                c = p.split('_')
                newCategory = c[1]

            if createInvolvement is not False:
                # A new form is opened to create an Involvement. Store the
                # current form information in the session (camefrom).
                if itemType in session and 'camefrom' in session[itemType]:
                    # TODO
                    print("*************************")
                    print("*************************")
                    print("*************************")
                    print("there is already an activity in the session")
                    print("*************************")
                    print("*************************")
                    print("*************************")
                itemId = '' if itemJson is None or 'id' not in itemJson \
                    else itemJson['id']
                session[itemType]['camefrom'] = {
                    'id': itemId,
                    'timestamp': datetime.datetime.now(),
                    'inv': createInvolvement
                }
                if itemType == 'activities':
                    msg = render(
                        get_customized_template_path(
                            request, 'parts/messages/stakeholder_form_through_'
                            'involvement.mak'), {
                                'url':
                                request.route_url(
                                    'activities_read_many',
                                    output='form',
                                    _query={'inv': createInvolvement})
                            }, request)
                    session.flash(msg)
                    url = request.route_url('stakeholders_read_many',
                                            output='form')
                else:
                    url = request.route_url('activities_read_many',
                                            output='form')

                # Redirect to the other form.
                return HTTPFound(url)

            if p in ['submit', 'delete']:
                # The final submit button was clicked. Calculate the diff,
                # delete the session data and redirect to a confirm page.

                success = False
                posted_formid = request.POST['__formid__']

                if posted_formid not in ['activityform', 'stakeholderform']:
                    # TODO: Is this the correct way to return an error message?
                    feedbackMessage = '<span class="text-error">{}</span>: Unknown form'.format(
                        errorTitle)
                    return {
                        'form': feedbackMessage,
                        'css_links': [],
                        'js_links': [],
                        'js': None,
                        'success': False
                    }

                if p == 'delete':
                    # The Item is to be deleted. Calculate the diff to delete
                    # all tags
                    diff = calculate_deletion_diff(request, itemType)

                else:
                    if (itemType not in session
                            or 'form' not in session[itemType]):
                        # TODO: Is this the correct way to return an error
                        # message?
                        feedbackMessage = 'Session not active'
                        return {
                            'form': feedbackMessage,
                            'css_links': [],
                            'js_links': [],
                            'js': None,
                            'success': False
                        }

                    formdata = copy.copy(session[itemType]['form'])

                    log.debug('The complete formdata as in the session: %s' %
                              formdata)
                    # check
                    diff = formdataToDiff(request, formdata, itemType)

                log.debug(
                    'The uncleaned diff to create/update the activity: %s' %
                    diff)

                if diff is None:
                    # TODO: Is this the correct way to return an error message?
                    return {
                        'form':
                        '<h3 class="text-info">%s</h3><p>%s</p>' %
                        (emptyTitle, emptyText),
                        'css_links': [],
                        'js_links': [],
                        'js':
                        None,
                        'success':
                        False
                    }

                # Create or update the Item
                success, returnValues = doUpdate(request, itemType, diff)

                if success is True:

                    # Clear the session
                    doClearFormSessionData(request, itemType, 'form')

                    if (otherItemType in session
                            and 'camefrom' in session[otherItemType]):
                        # The form was submitted "indirectly"

                        camefrom = session[otherItemType]['camefrom']

                        # Clear the camefrom flag
                        doClearFormSessionData(request, otherItemType,
                                               'camefrom')

                        addToSession = addCreatedInvolvementToSession(
                            request, session, otherItemType, camefrom['inv'],
                            returnValues)
                        if addToSession is True:
                            msg = render(
                                get_customized_template_path(
                                    request,
                                    'parts/messages/stakeholder_created_'
                                    'through_involvement.mak'), {}, request)
                            session.flash(msg, 'success')

                        # Route to the other form again.
                        if itemType == 'activities':
                            url = request.route_url(
                                'stakeholders_read_many',
                                output='form',
                                _query={'inv': camefrom['inv']})
                        else:
                            activity_id = camefrom.get('id')
                            if activity_id is not None and activity_id != '':
                                url = request.route_url(
                                    'activities_read_one',
                                    output='form',
                                    uid=activity_id,
                                    _query={'inv': camefrom['inv']})
                            else:
                                url = request.route_url(
                                    'activities_read_many',
                                    output='form',
                                    _query={'inv': camefrom['inv']})

                        return HTTPFound(url)

                    else:
                        if itemType == 'activities':
                            feedbackMessage = render(
                                get_customized_template_path(
                                    request, 'parts/messages/activity_created_'
                                    'success.mak'),
                                {
                                    'url':
                                    request.route_url('activities_read_one',
                                                      output='html',
                                                      uid=returnValues['id'])
                                }, request)
                        else:
                            feedbackMessage = render(
                                get_customized_template_path(
                                    request,
                                    'parts/messages/stakeholder_created_'
                                    'success.mak'),
                                {
                                    'url':
                                    request.route_url('stakeholders_read_one',
                                                      output='html',
                                                      uid=returnValues['id'])
                                }, request)

                else:
                    feedbackMessage = '<h3 class="text-error">%s</h3>%s' % (
                        errorTitle, returnValues)

                return {
                    'form': feedbackMessage,
                    'css_links': [],
                    'js_links': [],
                    'js': feedbackData,
                    'success': success
                }
    # END Post-request
    if formHasErrors is False:
        # If nothing was submitted or the captured form data was stored
        # correctly, create a form with the (new) current category.
        newschema = addHiddenFields(colander.SchemaNode(colander.Mapping()),
                                    itemType)
        newCat = configCategoryList.findCategoryById(newCategory)
        if newCat is not None:
            newschema.add(
                newCat.getForm(request))  # send get request to config/form.py
        showSessionCategories = None
        if (itemJson is None
                or (itemType in session and 'id' in session[itemType]
                    and session[itemType]['id'] == itemJson['id'])):
            showSessionCategories = itemType
        buttons = getFormButtons(request,
                                 categoryListButtons,
                                 newCategory,
                                 showSessionCategories=showSessionCategories)

        form = deform.Form(newschema, buttons=buttons, formid=formid)

        # The form contains empty data by default
        data = {'category': newCategory}

        # Decide which data to show in the form
        sessionItem = None
        if itemType in session and 'form' in session[itemType]:
            sessionItem = copy.copy(session[itemType]['form'])

        if itemJson is not None and itemType not in session:
            # An item was provided to show in the form (edit form) and no
            # values are in the session yet.
            # Simply show the data of the provided item in the form.
            data = getFormdataFromItemjson(request, itemJson, itemType,
                                           newCategory)
        elif itemJson is not None and sessionItem is not None:
            # An item was provided to show in the form (edit form) and there
            # are some values in the session.

            if (itemJson['id'] == sessionItem['id']
                    and itemJson['version'] == sessionItem['version']):
                # The item in the session and the item provided are the same.
                if str(newCategory) in sessionItem:
                    # The current category of the form is already in the
                    # session so we display this data.
                    sessionItem['category'] = newCategory
                    data = sessionItem
                else:
                    # The current category of the form is not yet in the
                    # session so we use the data of the itemjson to populate
                    # the form.
                    data = getFormdataFromItemjson(request, itemJson, itemType,
                                                   newCategory)
                if formSubmit is False and request.params.get('inv') is None:
                    # If the form is rendered for the first time, inform the
                    # user that session was used.

                    url = request.route_url('form_clear_session',
                                            item=itemType,
                                            attr='form',
                                            _query={'url': request.url})
                    msg = render(
                        get_customized_template_path(
                            request,
                            'parts/messages/unsaved_data_same_form.mak'),
                        {'url': url}, request)
                    session.flash(msg)

            else:
                # The item in the session is not the same as the item provided.
                # Use the itemjson to populate the form
                data = getFormdataFromItemjson(request, itemJson, itemType,
                                               newCategory)

                # Inform the user that there is data in the session.
                item_name = sessionItem['id'][:6] \
                    if sessionItem['id'] != colander.null else ''
                if sessionItem['id'] != colander.null:
                    if itemType == 'activities':
                        item_url = request.route_url('activities_read_one',
                                                     output='form',
                                                     uid=sessionItem['id'])
                    elif itemType == 'stakeholders':
                        item_url = request.route_url('stakeholders_read_one',
                                                     output='form',
                                                     uid=sessionItem['id'])
                else:
                    if itemType == 'activities':
                        item_url = request.route_url('activities_read_many',
                                                     output='form')
                    elif itemType == 'stakeholders':
                        item_url = request.route_url('stakeholders_read_many',
                                                     output='form')

                msg = render(
                    get_customized_template_path(
                        request,
                        'parts/messages/unsaved_data_different_form.mak'), {
                            'url': item_url,
                            'name': item_name,
                            'type': itemType
                        }, request)
                session.flash(msg)

        elif itemJson is None and sessionItem is not None:
            # No item was provided (create form) but some data was found in the
            # session.

            if (sessionItem['id'] != colander.null
                    and sessionItem['version'] != colander.null):
                # The item in the session is not new. Show empty form data
                # (already defined) and inform the user.
                item_name = sessionItem['id'][:6] \
                    if sessionItem['id'] != colander.null \
                    else _('Unknown Item')
                if sessionItem['id'] != colander.null:
                    if itemType == 'activities':
                        item_url = request.route_url('activities_read_one',
                                                     output='form',
                                                     uid=sessionItem['id'])
                    elif itemType == 'stakeholders':
                        item_url = request.route_url('stakeholders_read_one',
                                                     output='form',
                                                     uid=sessionItem['id'])
                else:
                    if itemType == 'activities':
                        item_url = request.route_url('activities_read_many',
                                                     output='form')
                    elif itemType == 'stakeholders':
                        item_url = request.route_url('stakeholders_read_many',
                                                     output='form')

                msg = render(
                    get_customized_template_path(
                        request,
                        'parts/messages/unsaved_data_different_form.mak'), {
                            'url': item_url,
                            'name': item_name,
                            'type': itemType
                        }, request)
                session.flash(msg)

            else:
                # The item in the session is new.
                # If the form is rendered for the first time, inform the
                # user that session was used.

                sessionItem['category'] = newCategory
                data = sessionItem

                if formSubmit is False and newInvolvement is None:
                    # Inform the user that data from the session is used.
                    url = request.route_url('form_clear_session',
                                            item=itemType,
                                            attr='form',
                                            _query={'url': request.url})
                    msg = render(
                        get_customized_template_path(
                            request,
                            'parts/messages/unsaved_data_same_form.mak'),
                        {'url': url}, request)
                    session.flash(msg)

        elif itemJson is not None:
            # An item was provided to show in the form (edit form)
            # Simply show the data of the provided item in the form.
            data = getFormdataFromItemjson(request, itemJson, itemType,
                                           newCategory)

        else:
            # No itemjson and no sessionitem, do nothing (empty data already
            # defined above).
            pass

        #        log.debug('Data used to populate the form: %s' % data)

        html = form.render(data)

    # If the current category contains involvements (eg. to add Stakeholders to
    # an Activity), show a (initially empty) div which will contain the form
    # for Stakeholders.
    if str(newCategory) in configCategoryList.getInvolvementCategoryIds():
        html += '<div id="stakeholderformcontainer"></div>'

    # Add JS and CSS requirements (for widgets)
    resources = form.get_widget_resources()

    log.debug('Session after processing the form: %s' % session)

    return {
        'form': html,
        'css_links': resources['css'],
        'js_links': resources['js'],
        'success': not formHasErrors
    }
Exemple #11
0
def to_flat_table(request, item_type, involvements='full', columns=[]):

    # Query the Items with the protocol.
    # Important: Query the Items with the original database language! This
    # prevents errors when different main keys (eg. "Remark") have the exact
    # same translation. Instead, the translation happens when filling the row
    # with the help of the configs.
    item_type = validate_item_type(item_type)
    if item_type == 'a':
        items = activity_protocol.read_many(request,
                                            public=True,
                                            translate=False)
        other_item_type = validate_item_type('sh')
    else:
        # Query Stakeholders through Activities.
        items = stakeholder_protocol.read_many_by_activities(request,
                                                             public=True,
                                                             translate=False)
        other_item_type = validate_item_type('a')

    META_HEADER = ['id', 'version', 'timestamp']
    if item_type == 'a':
        META_HEADER.append('geometry')

    config_taggroups = []
    max_involvements = 0

    # Collect the taggroups based on the form configuration.
    config_taggroups = []
    for config_taggroup in getCategoryList(request,
                                           item_type).getAllTaggroups():
        config_taggroup_entry = {
            'count': 0,
            'config': config_taggroup,
            'main_key': config_taggroup.getMaintag().getKey().getName()
        }
        config_taggroups.append(config_taggroup_entry)

    # Find out how many times each taggroup occurs. This defines how many
    # columns are needed in the table.
    for item in items.get('data', []):

        # Taggroups: Identified by their main tags.
        current_main_keys = []
        for main_key in get_main_keys_from_item_json(item):
            main_key_already_found = next(
                (i for i in current_main_keys if i['key'] == main_key), None)
            if main_key_already_found:
                main_key_already_found['count'] += 1
            else:
                current_main_keys.append({'key': main_key, 'count': 1})
        for main_key in current_main_keys:
            config_main_key = next((i for i in config_taggroups
                                    if i['main_key'] == main_key['key']), None)
            if config_main_key is not None:
                config_main_key['count'] = max(config_main_key['count'],
                                               main_key['count'])

        # Involvements
        if involvements != 'none':
            max_involvements = max(max_involvements,
                                   len(item.get('involvements', [])))

    # Create the headers
    header = []
    header.extend(META_HEADER)
    for config_taggroup_entry in config_taggroups:
        config_taggroup = config_taggroup_entry.get('config')
        config_mainkey = config_taggroup.getMaintag().getKey()
        for i in range(max(config_taggroup_entry.get('count'), 1)):
            for config_tag in sorted(
                    config_taggroup.getTags(),
                    key=lambda t: t != config_taggroup.getMaintag()):

                if (columns and config_tag.getKey().getName() not in columns):
                    continue

                key_name = config_tag.getKey().getTranslatedName()
                # If the taggroup contains multiple tags, add the main key as
                # prefix
                if len(config_taggroup.getTags()) > 1:
                    key_name = '%s_%s' % (config_mainkey.getTranslatedName(),
                                          key_name)
                # If the taggroup is repeated, add a number as suffix.
                if (config_taggroup.getRepeatable()
                        or config_mainkey.getType().lower()
                        in ['checkbox', 'inputtoken']):
                    key_name = '%s_%s' % (key_name, i + 1)

                header.append(str("%s" % key_name).encode('utf-8'))

                if columns:
                    try:
                        config_taggroup_entry['columns'].append(key_name)
                    except KeyError:
                        config_taggroup_entry['columns'] = [key_name]

    if involvements != 'none':
        inv_keys = [
            i[0] for i in getCategoryList(
                request, other_item_type).getInvolvementOverviewKeyNames()
        ]

        involvement_header = inv_keys + ['inv_role', 'inv_id']
        for i in range(max_involvements):
            for inv_header in involvement_header:
                inv_key_name = '%s_%s' % (inv_header, i + 1)
                header.append(str("%s" % inv_key_name).encode('utf-8'))

    # Create the rows
    rows = []
    for item in items.get('data', []):
        row = []

        # Metadata
        for key in META_HEADER:
            if key == 'geometry':
                row.append(",".join(
                    map(str,
                        item.get(key, {}).get("coordinates", []))))
            else:
                row.append(item.get(key, None))

        # Taggroups
        for config_taggroup_entry in config_taggroups:
            found_taggroups = []
            config_taggroup = config_taggroup_entry.get('config')
            config_mainkey = config_taggroup.getMaintag().getKey()

            for taggroup in sorted(item.get('taggroups', []),
                                   key=lambda tg: tg.get('tg_id', 0)):

                if taggroup['main_tag']['key'] != config_mainkey.getName():
                    continue

                for config_tag in sorted(
                        config_taggroup.getTags(),
                        key=lambda t: t != config_taggroup.getMaintag()):

                    if (columns
                            and config_tag.getKey().getName() not in columns):
                        continue

                    value = get_value_by_key_from_taggroup_json(
                        taggroup,
                        config_tag.getKey().getName())

                    for config_value in config_tag.getValues():
                        if config_value.getName() == value:
                            value = config_value.getTranslation()

                    if (config_tag.getKey().getType().lower() == 'file'
                            and value):
                        # Uploaded files are displayed with a URL to view the
                        # file
                        files = []
                        try:
                            for v in value.split(','):
                                filename = str('%s' %
                                               v.split('|')[0]).encode('utf-8')
                                url = request.route_url(
                                    'file_view',
                                    action='view',
                                    identifier=v.split('|')[1])
                                files.append('%s (%s)' % (filename, url))
                            value = '|'.join(files)
                        except:
                            pass

                    if not value:
                        value = ''

                    found_taggroups.append(str("%s" % value).encode("utf-8"))

            # Fill up the rest of the values with None
            if columns:
                try:
                    taggroup_length = len(config_taggroup_entry['columns'])
                except KeyError:
                    taggroup_length = 0
            else:
                taggroup_length = max(config_taggroup_entry.get('count'),
                                      1) * len(config_taggroup.getTags())
            found_taggroups.extend([None] *
                                   (taggroup_length - len(found_taggroups)))

            row.extend(found_taggroups)

        # Involvements
        if involvements != 'none':
            inv_row = []
            for involvement in sorted(item.get('involvements', []),
                                      key=lambda i:
                                      (i.get('role_id'), i.get('timestamp'))):
                inv_data = [None] * len(involvement_header)

                # Overview keys
                for i, config_sh_key in enumerate(
                        involvement_header[:len(involvement_header) - 2]):
                    inv_value = get_value_by_key_from_item_json(
                        involvement.get('data', {}), config_sh_key)
                    inv_data[i] = str("%s" % inv_value).encode("utf-8")

                # Metadata
                inv_data[len(inv_data) - 2] = involvement.get('role', None)
                inv_data[len(inv_data) - 1] = involvement.get('data', {}).get(
                    'id', None)
                inv_row.extend(inv_data)

            # Fill the rest with None
            inv_row.extend(
                [None] *
                (len(involvement_header) * max_involvements - len(inv_row)))
            row.extend(inv_row)

        rows.append(row)

    return header, rows
Exemple #12
0
def _extractKeyValues(request, itemType, lang, separator):
    """
    Helper function to extract the keys and values of the database and their
    translations.
    """

    keys = []
    values = []
    strings = []
    valueStrings = []

    originalCategoryList = getCategoryList(request, itemType, lang='en')
    translatedCategoryList = getCategoryList(request, itemType, lang=lang)

    originalTags = sorted(
        originalCategoryList.getAllTags(), key=lambda t: t.getKey().getName())
    translatedTags = sorted(
        translatedCategoryList.getAllTags(),
        key=lambda t: t.getKey().getName())

    strings.append(separator.join([
        'Name (original)',              # [0]
        'Name (translation)',           # [1]
        'Helptext (original)',          # [2]
        'Helptext (translation)',       # [3]
        'Type',                         # [4]
        'Belongs to Key',               # [5]
        'Additional comments'           # [6]
    ]))

    # Keys
    for i, originalTag in enumerate(originalTags):

        originalKeyName = originalTag.getKey().getTranslatedName()

        # Add each key only once
        if originalKeyName in keys:
            continue

        keys.append(originalKeyName)
        originalKey = originalTag.getKey()
        translatedTag = translatedTags[i]
        translatedKey = translatedTag.getKey()
        strings.append(separator.join([
            originalKeyName,
            translatedKey.getTranslatedName(True),
            originalKey.getTranslatedHelptext(),
            translatedKey.getTranslatedHelptext(True),
            'key',
            '-'
        ]))

        originalValues = sorted(
            originalTag.getValues(), key=lambda val: val.getName())
        translatedValues = sorted(
            translatedTag.getValues(), key=lambda val: val.getName())

        if len(originalValues) > 0 and len(translatedValues) == len(
                originalValues):
            for j, originalValue in enumerate(originalValues):

                originalValueName = originalValue.getTranslation()

                # Add each value only once
                if originalValueName in values:
                    continue

                values.append(originalValueName)
                translatedValue = translatedValues[j]
                valueStrings.append(separator.join([
                    originalValueName,
                    translatedValue.getTranslation(True),
                    '',
                    '',
                    'value',
                    originalKeyName
                ]))

    return strings + valueStrings
Exemple #13
0
def getActiveFilters(request):
    """
    Get the active filters of a request in a list.
    The list contains another list for each active filter with
    - [0]: the query string as provided in the parameter
    - [1]: a clean text representation (translated) of the filter
    """

    # Map the operators
    operators = {
        'like': '=',
        'nlike': '!=',
        'ilike': '=',
        'eq': '=',
        'ne': '!=',
        'lt': '<',
        'lte': '<=',
        'gt': '>',
        'gte': '>='
    }

    aList = getCategoryList(request, 'activities')
    shList = getCategoryList(request, 'stakeholders')

    # Extract query_strings from url
    scheme, netloc, path, query_string, fragment = urllib.parse.urlsplit(
        request.url)
    queryparams = urllib.parse.parse_qs(query_string)

    filters = []
    for q in queryparams:
        if q.startswith('a__') or q.startswith('sh__'):
            queryparts = q.split('__')

            if len(queryparts) != 3:
                continue

            if queryparts[0] == 'a':
                itemName = render(
                    get_customized_template_path(request,
                                                 'parts/items/activity.mak'),
                    {}, request)
                configList = aList
            elif queryparts[0] == 'sh':
                itemName = render(
                    get_customized_template_path(
                        request, 'parts/items/stakeholder.mak'), {}, request)
                configList = shList
            else:
                continue

            key = queryparts[1]
            op = queryparts[2]

            # Use translated key for display
            displayKey = key
            tag = configList.findTagByKeyName(key)
            if tag is not None:
                displayKey = tag.getKey().getTranslatedName()

            for v in queryparams[q]:
                # Use translated value for display
                displayValue = v
                if tag is not None:
                    valueObject = tag.findValueByName(v)
                    if valueObject is not None:
                        displayValue = valueObject.getTranslation()
                q_string = '%s=%s' % (q, v)
                q_display = (
                    '(%s) %s %s %s' %
                    (itemName, displayKey, operators[op], displayValue))
                filters.append([q_string, q_display])

    return filters
Exemple #14
0
    def read_selected(self):
        """
        Return a rendered HTML string with the details of one or multiple
        activities. Uses the protocol to query the data, extracts map details
        keys (defined by "mapdetail: true" in the configuration YAML) and passes
        it to the customized template for rendering.

        :return: str.
        """
        max_activities_visible = 3

        uids_string = self.request.matchdict.get('uids', None)
        uids = [
            uid for uid in uids_string.split(',') if validate_uuid(uid) is True
        ]

        if not uids:
            raise HTTPNotFound()

        activity_detail_keys = list(
            getCategoryList(self.request, 'a').get_map_detail_keys())
        stakeholder_detail_keys = list(
            getCategoryList(self.request, 'sh').get_map_detail_keys())

        activity_list = []
        for uid in uids[:max_activities_visible]:
            read_one = activity_protocol.read_one(self.request,
                                                  uid=uid,
                                                  public=False,
                                                  translate=False)

            activity = read_one['data'][0]

            activity_dict = {
                'identifier': uid,
                'short_identifier': shorten_uuid(uid),
            }
            for taggroup in activity.get('taggroups', []):
                key = taggroup.get('main_tag', {}).get('key')
                value = taggroup.get('main_tag', {}).get('value')
                if key in activity_detail_keys:
                    if key not in activity_dict:
                        activity_dict[key] = []
                    activity_dict[key].append(value)

            stakeholder_list = []
            for stakeholder in activity.get('involvements', []):
                stakeholder_dict = {}
                for taggroup in stakeholder.get('data',
                                                {}).get('taggroups', []):
                    key = taggroup.get('main_tag', {}).get('key')
                    value = taggroup.get('main_tag', {}).get('value')
                    if key in stakeholder_detail_keys:
                        if key not in stakeholder_dict:
                            stakeholder_dict[key] = []
                        stakeholder_dict[key].append(value)
                if stakeholder_dict:
                    stakeholder_list.append(stakeholder_dict)

            activity_list.append((activity_dict, stakeholder_list))

        return render(
            get_customized_template_path(
                self.request, 'parts/items/activities_map_details.mak'),
            {
                'activity_list': activity_list,
                'additional_activities': len(uids) - max_activities_visible,
            }, self.request)
Exemple #15
0
def renderReadonlyCompareForm(request,
                              itemType,
                              refFeature,
                              newFeature,
                              review=False):
    """
    Return a rendered form used for comparison (for comparison or review
    purposes).
    """
    reviewableMessage = None

    deform.Form.set_default_renderer(mako_renderer_compare)
    configCategoryList = getCategoryList(request, itemType)

    compareMode = 'review' if review is True else 'compare'
    schema = addHiddenFields(colander.SchemaNode(colander.Mapping()), itemType)
    for cat in configCategoryList.getCategories():
        schema.add(cat.getForm(request, readonly=True, compare=compareMode))

    schema.add(
        colander.SchemaNode(colander.String(),
                            widget=deform.widget.HiddenWidget(),
                            name='geomchange',
                            title='',
                            missing=colander.null))

    form = deform.Form(schema)
    validComparison = True

    refData = {}
    if refFeature is not None:
        refData = getFormdataFromItemjson(request,
                                          refFeature.to_table(request),
                                          itemType,
                                          readOnly=True)
        if refData == {}:
            validComparison = False

    newData = {}
    if newFeature is not None:
        newData = getFormdataFromItemjson(request,
                                          newFeature.to_table(request),
                                          itemType,
                                          readOnly=True,
                                          compareFeature=newFeature)
        if newData == {}:
            validComparison = False

        if review is True and 'reviewable' in newData:
            reviewable = newData['reviewable']
            if reviewable == -2:
                reviewableMessage = _(
                    'At least one of the involvements prevents automatic '
                    'revision. Please review these involvements separately.')
            elif reviewable == -3:
                reviewableMessage = _(
                    'This version contains changed involvements which prevent '
                    'automatic revision. Please review these involvements.')
            elif reviewable < 0:
                reviewableMessage = 'Something went wrong.'

        if review is True and 'reviewable' not in newData and refFeature and \
                newFeature and len(refFeature.get_involvements()) > \
                len(newFeature.get_involvements()) and \
                itemType == 'stakeholders':
            # If the Stakeholder is to be deleted (no taggroups), do not show
            # the warning and enable review
            if len(newFeature.get_taggroups()) > 0:
                reviewableMessage = _(
                    'At least one of the involvements prevents automatic '
                    'revision. Please review these involvements separately.')

    if validComparison is False:
        # If no formdata is available, it is very likely that the form has some
        # errors. In this case show an error message.
        url = None
        routeName = 'activities_read_one_history' if itemType == 'activities' \
            else 'stakeholders_read_one_history'
        if refFeature is not None:
            url = request.route_url(routeName,
                                    output='html',
                                    uid=refFeature.get_guid())
        elif newFeature is not None:
            url = request.route_url(routeName,
                                    output='html',
                                    uid=newFeature.get_guid())
        errorMsg = render(
            get_customized_template_path(
                request, 'parts/messages/comparison_not_valid.mak'),
            {'url': url}, request)
        return {'error': errorMsg}

    data = mergeFormdata(refData, newData)

    geometry = None
    if itemType == 'activities':
        newGeometry = newFeature.get_geometry() if newFeature is not None \
            else None
        refGeometry = refFeature.get_geometry() if refFeature is not None \
            else None

        # get polygeon geometries from taggroups
        newDealAreas = getTaggroupGeometriesCompare(newData)
        refDealAreas = getTaggroupGeometriesCompare(refData)

        geometry = json.dumps({
            'ref': {
                'geometry': refGeometry,
                'dealAreas': json.dumps(refDealAreas)
            },
            'new': {
                'geometry': newGeometry,
                'dealAreas': json.dumps(newDealAreas)
            },
        })

    # renders form; passes variables (readonly and geometry) to template
    ## TODO: in custom map mapping: pass params like this
    html = form.render(data, readonly=True, geometry=geometry)

    return {
        'form': html,
        'geometry': geometry,
        'reviewableMessage': reviewableMessage,
    }
Exemple #16
0
def doUpdate(request, itemType, diff):
    """
    Function to do the update / create of an Activity or a Stakeholder.
    Returns
    - a boolean indicating the success of the update
    - either a dict with some return values of the newly created item (if
      success is true) or an error message (if success if false)
    """
    if itemType not in ['activities', 'stakeholders']:
        return False, 'Not a valid Item'

    if itemType == 'activities':
        protocol = ActivityProtocol(DBSession)
    else:
        protocol = StakeholderProtocol(DBSession)

    # Use the protocol to create/update the Item
    ids = protocol.create(request, data=diff)

    if ids is None or len(ids) != 1:
        return False, _('The Item could not be created or updated.')

    item = ids[0]

    # Query the Item again to put together the return values. This is needed if
    # the created Item is to be used directly as an involvement.

    # Use the protocol to query the created item
    feature = protocol.read_one_by_version(request, item.identifier,
                                           item.version)

    if feature is None:
        return False, _('The Item was created but not found.'), None

    unknownString = _('Unknown')

    # We need to know which fields of the Item are used to populate the display
    # fields in the involvement overview.
    categorylist = getCategoryList(request, itemType)

    # Set all values to 'unknown' first
    keyValues = []
    overviewKeys = [
        o[0] for o in categorylist.getInvolvementOverviewKeyNames()
    ]
    for k in overviewKeys:
        keyValues.append([k, unknownString])

    # Update the value if available
    for tg in feature.get_taggroups():
        for k in keyValues:
            if tg.get_tag_by_key(k[0]) is not None:
                k[1] = tg.get_tag_by_key(k[0]).get_value()

    returnDict = {}
    for k in keyValues:
        returnDict[k[0]] = k[1]

    # Add the version and the id to the dict as well
    returnDict['version'] = item.version
    returnDict['id'] = str(item.identifier)

    return True, returnDict
Exemple #17
0
def _extractCategories(request, lang, separator):
    """
    Helper function to extract the categories of the database and their
    translations.
    """

    def _processCategories(
            originalCategoryList, translatedCategoryList, type, separator):

        categories = []
        strings = []

        originalCategories = sorted(
            originalCategoryList.getCategories(), key=lambda c: c.getId())
        translatedCategories = sorted(
            translatedCategoryList.getCategories(), key=lambda c: c.getId())

        for i, originalCategory in enumerate(originalCategories):
            translatedCategory = translatedCategories[i]

            # Add each category only once
            if originalCategory.getName() not in categories:
                categories.append(originalCategory.getName())
                strings.append(separator.join([
                    originalCategory.getName(),
                    translatedCategory.getTranslation(True),
                    type
                ]))

            # Subcategories
            originalSubcategories = sorted(
                originalCategory.getThematicgroups(), key=lambda c: c.getId())
            translatedSubcategories = sorted(
                translatedCategory.getThematicgroups(),
                key=lambda c: c.getId())

            for j, originalSubcategory in enumerate(originalSubcategories):
                translatedSubcategory = translatedSubcategories[j]

                # Add each subcategory only once
                if originalSubcategory.getName() not in categories:
                    categories.append(originalSubcategory.getName())
                    strings.append(separator.join([
                        originalSubcategory.getName(),
                        translatedSubcategory.getTranslation(True),
                        type
                    ]))

        return strings

    strings = []
    strings.append(separator.join([
        'Name (original)',
        'Name (translation)',
        'Type',
        'Additional comments'
    ]))

    for t in ['activities', 'stakeholders']:
        strings += _processCategories(
            getCategoryList(request, t, lang='en'),
            getCategoryList(request, t, lang=lang),
            t,
            separator)

    return strings