コード例 #1
0
ファイル: models.py プロジェクト: chokribr/invenio-1
    def filter_communities(cls, p, so):
        """Search for communities.

        Helper function which takes from database only those communities which
        match search criteria. Uses parameter 'so' to set communities in the
        correct order.

        Parameter 'page' is introduced to restrict results and return only
        slice of them for the current page. If page == 0 function will return
        all communities that match the pattern.
        """
        query = cls.query
        if p:
            query = query.filter(
                db.or_(
                    cls.id.like("%" + p + "%"),
                    cls.title.like("%" + p + "%"),
                    cls.description.like("%" + p + "%"),
                ))
        if so in cfg['COMMUNITIES_SORTING_OPTIONS']:
            order = so == 'title' and db.asc or db.desc
            query = query.order_by(order(getattr(cls, so)))
        else:
            query = query.order_by(db.desc(cls.ranking))
        return query
コード例 #2
0
def render_page(path):
    """Internal interface to the page view."""
    page = Page.query.filter(
        db.or_(Page.url == request.path,
               Page.url == request.path + "/")).first()
    return render_template([page.template_name, cfg['PAGES_DEFAULT_TEMPLATE']],
                           page=page)
コード例 #3
0
ファイル: views.py プロジェクト: mhellmic/b2share
def render_page(path):
    """
    Internal interface to the page view.
    """
    page = Page.query.filter(db.or_(Page.url == request.path,
                                    Page.url == request.path + "/")).first()
    return render_template([page.template_name, cfg['PAGES_DEFAULT_TEMPLATE']],
                           page=page)
コード例 #4
0
ファイル: models.py プロジェクト: dset0x/invenio-checker-old
    def modified_requested_recids(self):
        # Get all records that are already associated to this rule
        # If this is returning an empty set, you forgot to run bibindex
        try:
            associated_records = intbitset(zip(
                *db.session
                .query(CheckerRecord.id_bibrec)
                .filter(
                    CheckerRecord.name_checker_rule == self.name
                ).all()
            )[0])
        except IndexError:
            associated_records = intbitset()

        # Store requested records that were until now unknown to this rule
        requested_ids = self.requested_recids
        for requested_id in requested_ids - associated_records:
            new_record = CheckerRecord(id_bibrec=requested_id,
                                       name_checker_rule=self.name)
            db.session.add(new_record)
        db.session.commit()

        # Figure out which records have been edited since the last time we ran
        # this rule
        try:
            recids = zip(
                *db.session
                .query(CheckerRecord.id_bibrec)
                .outerjoin(Bibrec)
                .filter(
                    CheckerRecord.id_bibrec.in_(requested_ids),
                    CheckerRecord.name_checker_rule == self.name,
                    db.or_(
                        self.force_run_on_unmodified_records,
                        db.or_(
                            CheckerRecord.last_run == None,
                            CheckerRecord.last_run < Bibrec.modification_date,
                        ),
                    )
                )
            )[0]
        except IndexError:
            recids = set()
        return intbitset(recids)
コード例 #5
0
ファイル: provider.py プロジェクト: chokribr/invenio-1
def get_user(username, password, *args, **kwargs):
    """Get user for grant type password.

    Needed for grant type 'password'. Note, grant type password is by default
    disabled.
    """
    user = User.query.filter(
        db.or_(User.nickname == username, User.email == username)).first()
    if user.verify_password(password, migrate=True):
        return user
コード例 #6
0
ファイル: models.py プロジェクト: IFCA/lifewatch_osf
    def search(cls, query, q):
        """Modify query as so include only specific members.

        :param query: Query object.
        :param str q: Search string.
        :returs: Query object.
        """
        query = query.join(User).filter(
            db.or_(User.nickname.like("%" + q + "%"),
                   User.email.like("%" + q + "%")))
        return query
コード例 #7
0
ファイル: admin.py プロジェクト: osub3/invenio
def index():
    """WebSearch admin interface with editable collection tree."""
    collection = Collection.query.get_or_404(1)
    orphans = Collection.query.filter(
        db.not_(db.or_(
            Collection.id.in_(db.session.query(
                              CollectionCollection.id_son).subquery()),
            Collection.id.in_(db.session.query(
                              CollectionCollection.id_dad).subquery())
        ))).all()

    return dict(collection=collection, orphans=orphans)
コード例 #8
0
ファイル: admin.py プロジェクト: crepererum/invenio
def index():
    """WebSearch admin interface with editable collection tree."""
    collection = Collection.query.get_or_404(1)
    orphans = Collection.query.filter(
        db.not_(db.or_(
            Collection.id.in_(db.session.query(
                              CollectionCollection.id_son).subquery()),
            Collection.id.in_(db.session.query(
                              CollectionCollection.id_dad).subquery())
        ))).all()

    return dict(collection=collection, orphans=orphans)
コード例 #9
0
ファイル: views.py プロジェクト: mhellmic/b2share
def handle_not_found(exception, **extra):
    """Custom blueprint exception handler."""

    if not isinstance(exception, NotFound):
        return

    page = Page.query.filter(db.or_(Page.url == request.path,
                                    Page.url == request.path + "/")).first()
    if page is not None:
        _add_url_rule(page.url)
        # Modify request to call our errorhandler.
        request.url_rule.endpoint = blueprint.name + '.view'
コード例 #10
0
ファイル: __init__.py プロジェクト: osub3/invenio
def authenticate(nickname_or_email=None,
                 password=None,
                 login_method=None,
                 remember=False):
    """
    Find user identified by given information and login method.

    :param nickname_or_email: User nickname or email address
    :param password: Password used only in login methods that need it
    :param login_method: Login method (default: 'Local')
    :return: UserInfo
    """
    from invenio.base.i18n import _
    from invenio.ext.sqlalchemy import db
    from invenio_accounts.models import User
    from sqlalchemy.orm.exc import NoResultFound

    where = [
        db.or_(User.nickname == nickname_or_email,
               User.email == nickname_or_email)
    ]

    try:
        user = User.query.filter(*where).one()
        if login_method == 'Local' and password is not None:
            if not user.verify_password(password, migrate=True):
                return False
    except NoResultFound:
        return None
    except Exception:
        current_app.logger.exception("Problem checking password.")
        return False

    if login_method is not None and \
            user.settings['login_method'] != login_method:
        flash(
            _(
                "You are not authorized to use '%(x_login_method)s' login "
                "method.",
                x_login_method=login_method), 'error')
        return False

    if user.note == '2':  # account is not confirmed
        flash(_("You have not yet verified your email address."), 'warning')

    if user.note == '0':  # account is blocked
        logout_user()
        return False

    if remember:
        session.permanent = True
    return login_user(user.id, remember=remember)
コード例 #11
0
ファイル: models.py プロジェクト: egabancho/invenio-groups
    def search(cls, query, q):
        """Modify query as so include only specific members.

        :param query: Query object.
        :param str q: Search string.
        :returs: Query object.
        """
        query = query.join(User).filter(
            db.or_(
                User.nickname.like("%"+q+"%"),
                User.email.like("%"+q+"%")
            )
        )
        return query
コード例 #12
0
ファイル: models.py プロジェクト: ffelsner/invenio
    def generate_slug(name):
        """Generate a slug for the knowledge.

        :param name: text to slugify
        :return: slugified text
        """
        slug = slugify(name)

        i = KnwKB.query.filter(db.or_(
            KnwKB.slug.like(slug),
            KnwKB.slug.like(slug + '-%'),
        )).count()

        return slug + ('-{0}'.format(i) if i > 0 else '')
コード例 #13
0
ファイル: decorators.py プロジェクト: chokribr/invenio-1
        def decorated_function(*args, **kwargs):
            if not model or not columns:
                return f(*args, **kwargs)
            where = []
            for column, op in iteritems(columns):
                try:
                    values = request.values.getlist(column)
                    if not values:
                        continue
                    column_keys = column.split('.')
                    if hasattr(model, column_keys[0]):
                        cond = reduce(
                            lambda x, y: getattr(x.property.table.columns, y),
                            column_keys[1:], getattr(model, column_keys[0]))
                        current_app.logger.debug("Filtering by: %s = %s" %
                                                 (cond, values))

                        # Multi-values support
                        if len(values) > 0:
                            # Ignore empty values when using start with,
                            # contains or similar.
                            # FIXME: add per field configuration
                            values = [
                                value for value in values
                                if len(value) > 0 or filter_empty
                            ]
                            if op == operators.eq:
                                where.append(db.in_(values))
                            else:
                                or_list = []
                                for value in values:
                                    or_list.append(op(cond, value))
                                where.append(db.or_(*or_list))
                        else:
                            where.append(op(cond, value))
                except:
                    flash(
                        g._("Invalid filtering key '%(x_key)s'.",
                            x_key=column))
            if form is not None:
                filter_form = form(request.values)

                @register_template_context_processor
                def inject_filter_form():
                    return dict(filter_form=filter_form)

            # Generate ClauseElement for filtered columns.
            kwargs['filter'] = db.and_(*where)
            return f(*args, **kwargs)
コード例 #14
0
    def generate_slug(name):
        """Generate a slug for the knowledge.

        :param name: text to slugify
        :return: slugified text
        """
        slug = slugify(name)

        i = KnwKB.query.filter(
            db.or_(
                KnwKB.slug.like(slug),
                KnwKB.slug.like(slug + '-%'),
            )).count()

        return slug + ('-{0}'.format(i) if i > 0 else '')
コード例 #15
0
ファイル: models.py プロジェクト: IFCA/lifewatch_osf
    def query_by_group(cls, group_or_id, with_invitations=False, **kwargs):
        """Get a group's members."""
        if isinstance(group_or_id, Group):
            id_group = group_or_id.id
        else:
            id_group = group_or_id

        if not with_invitations:
            return cls._filter(cls.query.filter_by(id_group=id_group),
                               **kwargs)
        else:
            return cls.query.filter(
                Membership.id_group == id_group,
                db.or_(Membership.state == MembershipState.PENDING_USER,
                       Membership.state == MembershipState.ACTIVE))
コード例 #16
0
def authenticate(nickname_or_email=None,
                 password=None,
                 login_method='Local',
                 remember=False):
    """
    Find user identified by given information and login method.

    :param nickname_or_email: User nickname or email address
    :param password: Password used only in login methods that need it
    :param login_method: Login method (default: 'Local')
    :return: UserInfo
    """
    from invenio.base.i18n import _
    from invenio.ext.sqlalchemy import db
    from invenio.modules.accounts.models import User
    from sqlalchemy.orm.exc import NoResultFound

    where = [
        db.or_(User.nickname == nickname_or_email,
               User.email == nickname_or_email)
    ]
    if login_method == 'Local' and password is not None:
        where.append(User.password == password)
    try:
        user = User.query.filter(*where).one()
    except NoResultFound:
        return None
    except Exception:
        return False

    if user.settings['login_method'] != login_method:
        flash(
            _(
                "You are not authorized to use '%(x_login_method)s' login "
                "method.",
                x_login_method=login_method), 'error')
        return False

    if user.note == '2':  # account is not confirmed
        logout_user()
        flash(
            _("You have not yet confirmed the email address for the \
            '%(login_method)s' authentication method.",
              login_method=login_method), 'warning')
    if remember:
        session.permanent = True
    return login_user(user.id, remember=remember)
コード例 #17
0
ファイル: decorators.py プロジェクト: jirikuncar/invenio-base
        def decorated_function(*args, **kwargs):
            if not model or not columns:
                return f(*args, **kwargs)
            where = []
            for column, op in iteritems(columns):
                try:
                    values = request.values.getlist(column)
                    if not values:
                        continue
                    column_keys = column.split('.')
                    if hasattr(model, column_keys[0]):
                        cond = reduce(lambda x, y:
                                      getattr(x.property.table.columns, y),
                                      column_keys[1:],
                                      getattr(model, column_keys[0]))
                        current_app.logger.debug("Filtering by: %s = %s" %
                                                 (cond, values))

                        # Multi-values support
                        if len(values) > 0:
                            # Ignore empty values when using start with,
                            # contains or similar.
                            # FIXME: add per field configuration
                            values = [value for value in values
                                      if len(value) > 0 or filter_empty]
                            if op == operators.eq:
                                where.append(db.in_(values))
                            else:
                                or_list = []
                                for value in values:
                                    or_list.append(op(cond, value))
                                where.append(db.or_(*or_list))
                        else:
                            where.append(op(cond, value))
                except:
                    flash(g._("Invalid filtering key '%(x_key)s'.",
                              x_key=column))
            if form is not None:
                filter_form = form(request.values)

                @register_template_context_processor
                def inject_filter_form():
                    return dict(filter_form=filter_form)
            # Generate ClauseElement for filtered columns.
            kwargs['filter'] = db.and_(*where)
            return f(*args, **kwargs)
コード例 #18
0
ファイル: rules.py プロジェクト: Dziolas/invenio-checker
    def modified_records(self, user_ids):
        # Get all records that are already associated to this rule
        try:
            associated_records = zip(
                *db.session
                .query(CheckerRecord.id_bibrec)
                .filter(
                    CheckerRecord.name_checker_rule==self['name']
                ).all()
            )[0]
        except IndexError:
            associated_records = []

        # Store requested records that were until now unknown to this rule
        requested_ids = self.query.requested_ids(user_ids)
        for requested_id in requested_ids:
            if requested_id not in associated_records:
                new_record = CheckerRecord(id_bibrec=requested_id,
                                           name_checker_rule=self['name'])
                db.session.add(new_record)
        db.session.commit()

        # Figure out which records have been edited since the last time we ran
        # this rule
        try:
            return zip(
                *db.session
                .query(CheckerRecord.id_bibrec)
                .outerjoin(Bibrec)
                .filter(
                    db.and_(
                        CheckerRecord.id_bibrec.in_(requested_ids),
                        CheckerRecord.name_checker_rule == self['name'],
                        db.or_(
                            CheckerRecord.last_run < Bibrec.modification_date,
                            db.and_(
                                CheckerRecord.last_run > Bibrec.modification_date,
                                CheckerRecord.expecting_modification == True
                            )
                        )
                    )
                )
            )[0]
        except IndexError:
            return []
コード例 #19
0
ファイル: __init__.py プロジェクト: Letreguilly/invenio
def authenticate(nickname_or_email=None, password=None,
                 login_method=None, remember=False):
    """
    Find user identified by given information and login method.

    :param nickname_or_email: User nickname or email address
    :param password: Password used only in login methods that need it
    :param login_method: Login method (default: 'Local')
    :return: UserInfo
    """
    from invenio.base.i18n import _
    from invenio.ext.sqlalchemy import db
    from invenio_accounts.models import User
    from sqlalchemy.orm.exc import NoResultFound

    where = [db.or_(User.nickname == nickname_or_email,
                    User.email == nickname_or_email)]

    try:
        user = User.query.filter(*where).one()
        if login_method == 'Local' and password is not None:
            if not user.verify_password(password, migrate=True):
                return False
    except NoResultFound:
        return None
    except Exception:
        current_app.logger.exception("Problem checking password.")
        return False

    if login_method is not None and \
            user.settings['login_method'] != login_method:
        flash(_("You are not authorized to use '%(x_login_method)s' login "
                "method.", x_login_method=login_method), 'error')
        return False

    if user.note == '2':  # account is not confirmed
        flash(_("You have not yet verified your email address."), 'warning')

    if user.note == '0':  # account is blocked
        logout_user()
        return False

    if remember:
        session.permanent = True
    return login_user(user.id, remember=remember)
コード例 #20
0
def handle_not_found(exception, **extra):
    """Custom blueprint exception handler."""
    if not isinstance(exception, NotFound):
        return

    page = Page.query.filter(
        db.or_(Page.url == request.path,
               Page.url == request.path + "/")).first()
    if page is not None:
        _add_url_rule(page.url)
        # Modify request to call our errorhandler.
        req_endpoint = request.url_rule.endpoint
        request.url_rule.endpoint = blueprint.name + '.view'

        @after_this_request
        def restore_url_map(response):
            request.url_rule.endpoint = req_endpoint
            return response
コード例 #21
0
ファイル: __init__.py プロジェクト: Theer108/invenio
def authenticate(nickname_or_email=None, password=None, login_method="Local", remember=False):
    """
    Find user identified by given information and login method.

    :param nickname_or_email: User nickname or email address
    :param password: Password used only in login methods that need it
    :param login_method: Login method (default: 'Local')
    :return: UserInfo
    """
    from invenio.base.i18n import _
    from invenio.ext.sqlalchemy import db
    from invenio.modules.accounts.models import User
    from sqlalchemy.orm.exc import NoResultFound

    where = [db.or_(User.nickname == nickname_or_email, User.email == nickname_or_email)]
    if login_method == "Local" and password is not None:
        where.append(User.password == password)
    try:
        user = User.query.filter(*where).one()
    except NoResultFound:
        return None
    except Exception:
        return False

    if user.settings["login_method"] != login_method:
        flash(
            _("You are not authorized to use '%(x_login_method)s' login " "method.", x_login_method=login_method),
            "error",
        )
        return False

    if user.note == "2":  # account is not confirmed
        logout_user()
        flash(
            _(
                "You have not yet confirmed the email address for the \
            '%(login_method)s' authentication method.",
                login_method=login_method,
            ),
            "warning",
        )
    if remember:
        session.permanent = True
    return login_user(user.id, remember=remember)
コード例 #22
0
ファイル: manage.py プロジェクト: CharlotteIrisC/invenio
def upload(service, src, dest, user=None):
    """Upload a file."""
    from invenio.ext.login import login_user, logout_user
    from invenio.ext.sqlalchemy import db

    from invenio_accounts.models import User
    from invenio.modules.cloudconnector import utils
    from invenio_oauthclient.views.client import setup_app

    # Get user instance
    user = User.query.filter(db.or_(
        User.nickname == user,
        User.email == user,
        User.id == user)).one()

    login_user(user.id)
    setup_app()
    utils.upload(service, src, dest)
    logout_user()
コード例 #23
0
ファイル: models.py プロジェクト: rsalas82/lw-daap
    def filter_projects(cls, p, so):
        """Search for projects.

        Helper function which takes from database only those projects which
        match search criteria. Uses parameter 'so' to set projects in the
        correct order.

        Parameter 'page' is introduced to restrict results and return only
        slice of them for the current page. If page == 0 function will return
        all projects that match the pattern.
        """
        query = cls.query
        if p:
            query = query.filter(
                db.or_(cls.id.like("%" + p + "%"), cls.title.like("%" + p + "%"), cls.description.like("%" + p + "%"))
            )
        if so in cfg["PROJECTS_SORTING_OPTIONS"]:
            order = so == "title" and db.asc or db.desc
            query = query.order_by(order(getattr(cls, so)))
        return query
コード例 #24
0
ファイル: models.py プロジェクト: egabancho/invenio-groups
    def query_by_group(cls, group_or_id, with_invitations=False, **kwargs):
        """Get a group's members."""
        if isinstance(group_or_id, Group):
            id_group = group_or_id.id
        else:
            id_group = group_or_id

        if not with_invitations:
            return cls._filter(
                cls.query.filter_by(id_group=id_group),
                **kwargs
            )
        else:
            return cls.query.filter(
                Membership.id_group == id_group,
                db.or_(
                    Membership.state == MembershipState.PENDING_USER,
                    Membership.state == MembershipState.ACTIVE
                )
            )
コード例 #25
0
ファイル: models.py プロジェクト: Theer108/invenio
    def filter_communities(cls, p, so):
        """Search for communities.

        Helper function which takes from database only those communities which
        match search criteria. Uses parameter 'so' to set communities in the
        correct order.

        Parameter 'page' is introduced to restrict results and return only
        slice of them for the current page. If page == 0 function will return
        all communities that match the pattern.
        """
        query = cls.query
        if p:
            query = query.filter(db.or_(
                cls.id.like("%" + p + "%"),
                cls.title.like("%" + p + "%"),
                cls.description.like("%" + p + "%"),
            ))
        if so in cfg['COMMUNITIES_SORTING_OPTIONS']:
            order = so == 'title' and db.asc or db.desc
            query = query.order_by(order(getattr(cls, so)))
        else:
            query = query.order_by(db.desc(cls.ranking))
        return query
コード例 #26
0
ファイル: models.py プロジェクト: IFCA/lifewatch_osf
    def filter_instruments(cls, p, so):
        """Search for instruments.

        Helper function which takes from database only those instruments which
        match search criteria. Uses parameter 'so' to set instruments in the
        correct order.

        Parameter 'page' is introduced to restrict results and return only
        slice of them for the current page. If page == 0 function will return
        all instruments that match the pattern.
        """
        #current_app.logger.debug(cls)
        #current_app.logger.debug(p)
        #current_app.logger.debug(so)
        query = cls.query
        if p:
            query = query.filter(db.or_(
                cls.id.like("%" + p + "%"),
                cls.name.like("%" + p + "%"),
            ))
        if so in cfg['INSTRUMENTS_SORTING_OPTIONS']:
            order = so == 'name' and db.asc or db.desc
            query = query.order_by(order(getattr(cls, so)))
        return query
コード例 #27
0
ファイル: holdingpen.py プロジェクト: pombredanne/invenio-3
def details(objectid):
    """Display info about the object."""
    from ..utils import get_workflow_info
    from invenio.ext.sqlalchemy import db
    from itertools import groupby

    of = "hd"
    bwobject = BibWorkflowObject.query.get_or_404(objectid)
    previous_object, next_object = get_previous_next_objects(
        session.get("holdingpen_current_ids"), objectid)

    formatted_data = bwobject.get_formatted_data(of)
    extracted_data = extract_data(bwobject)

    action_name = bwobject.get_action()
    if action_name:
        action = actions[action_name]
        rendered_actions = action().render(bwobject)
    else:
        rendered_actions = {}

    if bwobject.id_parent:
        history_objects_db_request = BibWorkflowObject.query.filter(
            db.or_(BibWorkflowObject.id_parent == bwobject.id_parent,
                   BibWorkflowObject.id == bwobject.id_parent,
                   BibWorkflowObject.id == bwobject.id)).all()
    else:
        history_objects_db_request = BibWorkflowObject.query.filter(
            db.or_(BibWorkflowObject.id_parent == bwobject.id,
                   BibWorkflowObject.id == bwobject.id)).all()

    history_objects = {}
    temp = groupby(history_objects_db_request, lambda x: x.version)
    for key, value in temp:
        if key != ObjectVersion.RUNNING:
            value = list(value)
            value.sort(key=lambda x: x.modified, reverse=True)
            history_objects[key] = value

    history_objects = sum(history_objects.values(), [])
    for obj in history_objects:
        obj._class = HOLDINGPEN_WORKFLOW_STATES[obj.version]["class"]
        obj.message = HOLDINGPEN_WORKFLOW_STATES[obj.version]["message"]
    results = get_rendered_task_results(bwobject)
    workflow_definition = get_workflow_info(extracted_data['workflow_func'])
    task_history = bwobject.get_extra_data().get('_task_history', [])
    return render_template(
        'workflows/details.html',
        bwobject=bwobject,
        rendered_actions=rendered_actions,
        history_objects=history_objects,
        bwparent=extracted_data['bwparent'],
        info=extracted_data['info'],
        log=extracted_data['logtext'],
        data_preview=formatted_data,
        workflow=extracted_data['w_metadata'],
        task_results=results,
        previous_object=previous_object,
        next_object=next_object,
        task_history=task_history,
        workflow_definition=workflow_definition,
        versions=ObjectVersion,
        pretty_date=pretty_date,
        workflow_class=workflows.get(extracted_data['w_metadata'].name),
    )
コード例 #28
0
ファイル: holdingpen.py プロジェクト: dset0x/invenio
def details(objectid):
    """Display info about the object."""
    from ..utils import get_workflow_info
    from invenio.ext.sqlalchemy import db
    from itertools import groupby

    of = "hd"
    bwobject = BibWorkflowObject.query.get_or_404(objectid)
    previous_object, next_object = get_previous_next_objects(
        session.get("holdingpen_current_ids"),
        objectid
    )

    formatted_data = bwobject.get_formatted_data(of)
    extracted_data = extract_data(bwobject)

    action_name = bwobject.get_action()
    if action_name:
        action = actions[action_name]
        rendered_actions = action().render(bwobject)
    else:
        rendered_actions = {}

    if bwobject.id_parent:
        history_objects_db_request = BibWorkflowObject.query.filter(
            db.or_(BibWorkflowObject.id_parent == bwobject.id_parent,
                   BibWorkflowObject.id == bwobject.id_parent,
                   BibWorkflowObject.id == bwobject.id)).all()
    else:
        history_objects_db_request = BibWorkflowObject.query.filter(
            db.or_(BibWorkflowObject.id_parent == bwobject.id,
                   BibWorkflowObject.id == bwobject.id)).all()

    history_objects = {}
    temp = groupby(history_objects_db_request,
                   lambda x: x.version)
    for key, value in temp:
        if key != ObjectVersion.RUNNING:
            value = list(value)
            value.sort(key=lambda x: x.modified, reverse=True)
            history_objects[key] = value

    history_objects = sum(history_objects.values(), [])
    for obj in history_objects:
        obj._class = HOLDINGPEN_WORKFLOW_STATES[obj.version]["class"]
        obj.message = HOLDINGPEN_WORKFLOW_STATES[obj.version]["message"]
    results = get_rendered_task_results(bwobject)
    workflow_definition = get_workflow_info(extracted_data['workflow_func'])
    task_history = bwobject.get_extra_data().get('_task_history', [])
    return render_template('workflows/details.html',
                           bwobject=bwobject,
                           rendered_actions=rendered_actions,
                           history_objects=history_objects,
                           bwparent=extracted_data['bwparent'],
                           info=extracted_data['info'],
                           log=extracted_data['logtext'],
                           data_preview=formatted_data,
                           workflow=extracted_data['w_metadata'],
                           task_results=results,
                           previous_object=previous_object,
                           next_object=next_object,
                           task_history=task_history,
                           workflow_definition=workflow_definition,
                           versions=ObjectVersion,
                           pretty_date=pretty_date,
                           workflow_class=workflows.get(extracted_data['w_metadata'].name),
                           )