Пример #1
0
class IdxINDEXIdxINDEX(db.Model):

    """Represent an IdxINDEXIdxINDEX record."""

    __tablename__ = 'idxINDEX_idxINDEX'
    id_virtual = db.Column(db.MediumInteger(9, unsigned=True),
                           db.ForeignKey(IdxINDEX.id), nullable=False,
                           server_default='0', primary_key=True)
    id_normal = db.Column(db.MediumInteger(9, unsigned=True),
                          db.ForeignKey(IdxINDEX.id), nullable=False,
                          server_default='0', primary_key=True)

    virtual = db.relationship(
        IdxINDEX,
        backref=db.backref('normal'),
        primaryjoin="and_(IdxINDEXIdxINDEX.id_virtual==IdxINDEX.id)"
    )

    normal = db.relationship(
        IdxINDEX,
        backref=db.backref('virtual'),
        primaryjoin="and_(IdxINDEXIdxINDEX.id_normal==IdxINDEX.id)"
    )

    @staticmethod
    def is_virtual(id_virtual):
        """Check if index is virtual."""
        return db.session.query(
            IdxINDEXIdxINDEX.query.filter_by(
                id_virtual=id_virtual).exists()).scalar()
Пример #2
0
class KnwKBDDEF(db.Model):
    """Represent a KnwKBDDEF record."""

    __tablename__ = 'knwKBDDEF'
    id_knwKB = db.Column(db.MediumInteger(8, unsigned=True),
                         db.ForeignKey(KnwKB.id),
                         nullable=False,
                         primary_key=True)
    id_collection = db.Column(db.MediumInteger(unsigned=True),
                              db.ForeignKey(Collection.id),
                              nullable=True)
    output_tag = db.Column(db.Text, nullable=True)
    search_expression = db.Column(db.Text, nullable=True)
    kb = db.relationship(KnwKB,
                         backref=db.backref('kbdefs',
                                            uselist=False,
                                            cascade="all, delete-orphan"),
                         single_parent=True)
    collection = db.relationship(Collection, backref=db.backref('kbdefs'))

    def to_dict(self):
        """Return a dict representation of KnwKBDDEF."""
        return {
            'field': self.output_tag,
            'expression': self.search_expression,
            'coll_id': self.id_collection,
            'collection': self.collection.name if self.collection else None
        }
Пример #3
0
class PageList(db.Model):
    """Represent association between page and list."""
    __tablename__ = 'pagesLIST'

    id = db.Column(db.Integer(15, unsigned=True),
                   nullable=False,
                   primary_key=True,
                   autoincrement=True)
    """PageList identifier."""

    list_id = db.Column(db.Integer(15, unsigned=True),
                        db.ForeignKey(Page.id),
                        nullable=False)
    """Id of a list."""

    page_id = db.Column(db.Integer(15, unsigned=True),
                        db.ForeignKey(Page.id),
                        nullable=False)
    """Id of a page."""

    order = db.Column(db.Integer(15, unsigned=True), nullable=False)

    list = db.relationship(Page,
                           backref=db.backref("pages",
                                              cascade="all, delete-orphan"),
                           foreign_keys=[list_id])
    """Relation to the list."""

    page = db.relationship(Page,
                           backref=db.backref("lists",
                                              cascade="all, delete-orphan"),
                           foreign_keys=[page_id])
    """Relation to the page."""
Пример #4
0
class WtgTAGRecord(db.Model, Serializable):

    """Connection between Tag and Record."""

    __tablename__ = 'wtgTAG_bibrec'
    __public__ = set(['id_tag', 'id_bibrec', 'date_added'])

    # tagTAG.id
    id_tag = db.Column(db.Integer(15, unsigned=True),
                       db.ForeignKey(WtgTAG.id),
                       nullable=False,
                       primary_key=True)

    # Bibrec.id
    id_bibrec = db.Column(db.Integer(15, unsigned=True),
                          db.ForeignKey(Bibrec.id),
                          nullable=False,
                          primary_key=True)

    # Annotation
    annotation = db.Column(
        db.Text(convert_unicode=True),
        default='')

    # Creation date
    date_added = db.Column(db.DateTime,
                           default=datetime.now)

    # Relationships
    tag = db.relationship(WtgTAG,
                          backref=db.backref('records_association',
                                             cascade='all'))

    tag_query = db.relationship(WtgTAG,
                                backref=db.backref('records_association_query',
                                                   cascade='all',
                                                   lazy='dynamic'))

    bibrec = db.relationship(Bibrec,
                             backref=db.backref('tags_association',
                                                cascade='all'))

    bibrec_query = db.relationship(Bibrec,
                                   backref=db.backref('tags_association_query',
                                                      cascade='all',
                                                      lazy='dynamic'))

    def __init__(self, bibrec=None, **kwargs):
        """TODO."""
        super(WtgTAGRecord, self).__init__(**kwargs)

        if bibrec is not None:
            self.bibrec = bibrec
Пример #5
0
class SbmCOLLECTIONSbmDOCTYPE(db.Model):
    """Represents a SbmCOLLECTIONSbmDOCTYPE record."""

    __tablename__ = 'sbmCOLLECTION_sbmDOCTYPE'
    id = db.Column(db.Integer(11),
                   nullable=False,
                   autoincrement=True,
                   primary_key=True)
    _id_father = db.Column(db.Integer(11),
                           db.ForeignKey(SbmCOLLECTION.id),
                           nullable=True,
                           name="id_father")
    id_son = db.Column(db.Char(10),
                       db.ForeignKey(SbmDOCTYPE.sdocname),
                       nullable=False)
    catalogue_order = db.Column(db.Integer(11),
                                nullable=False,
                                server_default='0')

    father = db.relationship(
        SbmCOLLECTION,
        backref=db.backref('sonDoctype', uselist=False),
    )

    @db.hybrid_property
    def id_father(self):
        """Get id_father."""
        return self._id_father

    @id_father.setter
    def id_father(self, value):
        """Set id_father."""
        self._id_father = value or None
Пример #6
0
class BsrMETHODDATABUCKET(db.Model):

    """Represent a BsrMETHODDATABUCKET record."""

    __tablename__ = 'bsrMETHODDATABUCKET'

    id_bsrMETHOD = db.Column(db.MediumInteger(9, unsigned=True),
                             db.ForeignKey(BsrMETHOD.id), autoincrement=False,
                             primary_key=True, nullable=False)
    bucket_no = db.Column(db.TinyInteger(2), primary_key=True, nullable=False,
                          autoincrement=False)
    bucket_data = db.Column(db.LargeBinary)
    bucket_last_value = db.Column(db.String(255))
    last_updated = db.Column(db.DateTime)

    method = db.relationship(BsrMETHOD, backref=db.backref(
        "buckets",
        collection_class=attribute_mapped_collection("bucket_no"),
        cascade="all, delete-orphan"
        )
    )

    @property
    def data(self):
        """Return bucket data as intbitset."""
        return intbitset(self.bucket_data)
Пример #7
0
class SbmCOLLECTIONSbmCOLLECTION(db.Model):
    """Represents a SbmCOLLECTIONSbmCOLLECTION record."""

    __tablename__ = 'sbmCOLLECTION_sbmCOLLECTION'

    id = db.Column(db.Integer(11),
                   nullable=False,
                   autoincrement=True,
                   primary_key=True)
    _id_father = db.Column(db.Integer(11),
                           db.ForeignKey(SbmCOLLECTION.id),
                           nullable=True,
                           name='id_father')
    id_son = db.Column(db.Integer(11),
                       db.ForeignKey(SbmCOLLECTION.id),
                       nullable=False)
    catalogue_order = db.Column(db.Integer(11),
                                nullable=False,
                                server_default='0')

    son = db.relationship(
        SbmCOLLECTION,
        backref=db.backref('father', uselist=False),
        single_parent=True,
        primaryjoin="and_(SbmCOLLECTIONSbmCOLLECTION.id_son==SbmCOLLECTION.id) "
    )
    father = db.relationship(
        SbmCOLLECTION,
        backref=db.backref('son', uselist=False),
        single_parent=True,
        primaryjoin=
        "and_(SbmCOLLECTIONSbmCOLLECTION.id_father==SbmCOLLECTION.id) ")

    @db.hybrid_property
    def id_father(self):
        """Get id_father."""
        return self._id_father

    @id_father.setter
    def id_father(self, value):
        """Set id_father."""
        self._id_father = value or None
Пример #8
0
class RnkMETHODNAME(db.Model):
    """Represent a RnkMETHODNAME record."""

    __tablename__ = 'rnkMETHODNAME'
    id_rnkMETHOD = db.Column(db.MediumInteger(9, unsigned=True),
                             db.ForeignKey(RnkMETHOD.id),
                             primary_key=True)
    ln = db.Column(db.Char(5), primary_key=True, server_default='')
    type = db.Column(db.Char(3), primary_key=True, server_default='sn')
    value = db.Column(db.String(255), nullable=False)
    method = db.relationship(RnkMETHOD,
                             backref=db.backref('names', lazy='dynamic'))
Пример #9
0
class UserUsergroup(db.Model):
    """Represent a UserUsergroup record."""

    USER_STATUS = {
        'ADMIN': 'A',
        'MEMBER': 'M',
        'PENDING': 'P',
    }

    def __str__(self):
        """Return string representation."""
        return "%s:%s" % (self.user.nickname, self.usergroup.name)

    __tablename__ = 'user_usergroup'

    id_user = db.Column(db.Integer(15, unsigned=True),
                        db.ForeignKey(User.id),
                        nullable=False,
                        server_default='0',
                        primary_key=True)
    id_usergroup = db.Column(db.Integer(15, unsigned=True),
                             db.ForeignKey(Usergroup.id),
                             nullable=False,
                             server_default='0',
                             primary_key=True)
    user_status = db.Column(db.CHAR(1), nullable=False, server_default='')
    user_status_date = db.Column(db.DateTime,
                                 nullable=False,
                                 default=datetime.now,
                                 onupdate=datetime.now)
    user = db.relationship(User, backref=db.backref('usergroups'))
    usergroup = db.relationship(Usergroup,
                                backref=db.backref(
                                    'users', cascade="all, delete-orphan"))

    def is_admin(self):
        """Return True if user is a admin."""
        return self.user_status == self.USER_STATUS['ADMIN']
Пример #10
0
class BsrMETHODNAME(db.Model):

    """Represent a BsrMETHODNAME record."""

    __tablename__ = 'bsrMETHODNAME'

    id_bsrMETHOD = db.Column(db.MediumInteger(9, unsigned=True),
                             db.ForeignKey(BsrMETHOD.id),
                             primary_key=True, nullable=False,
                             autoincrement=False)
    ln = db.Column(db.String(5), primary_key=True, nullable=False)
    type = db.Column(db.String(3), primary_key=True, nullable=False)
    value = db.Column(db.String(255), nullable=False)
    method = db.relationship(BsrMETHOD, backref=db.backref('names',
                                                           lazy='dynamic'))
Пример #11
0
class CollectionFormat(db.Model):

    """Represent a CollectionFormat record."""

    __tablename__ = 'collection_format'
    id_collection = db.Column(db.MediumInteger(9, unsigned=True),
                              db.ForeignKey(Collection.id), primary_key=True)
    format_code = db.Column('format', db.String(10), primary_key=True)
    score = db.Column(db.TinyInteger(4, unsigned=True),
                      nullable=False, server_default='0')

    collection = db.relationship(
        Collection, backref=db.backref(
            'formats', order_by=db.desc(score)
        ), order_by=db.desc(score))

    @property
    def format(self):
        """Return output format definition."""
        return output_formats[self.format_code]
Пример #12
0
class Instrument(db.Model):
    __tablename__ = 'instrument'

    """ Fields """
    id = db.Column(db.Integer(255, unsigned=True),
                        nullable=False, primary_key=True,
                        )
    user_id = db.Column(db.Integer(255, unsigned=True), db.ForeignKey(User.id),
                        nullable=False,
                        )

    name = db.Column(db.String(length=255),
                     nullable=True, default='',
                     info=dict(
                         label=_("Name"),
                         description=_(''),
                         )
                     )

    access_right = db.Column(db.String(length=12),
                            nullable=True, default='',
                            info=dict(
                                label=_("Access right"),
                                description=_(''),
                                )
                            )

    embargo_date = db.Column(db.DateTime,
                            nullable=True, default='',
                            info=dict(
                                label=_("Embargo date"),
                                description=_(''),
                                )
                           )

    access_conditions = db.Column(db.String(length=4000),
                            nullable=True, default='',
                            info=dict(
                                label=_("Conditions"),
                                description=_(''),
                                )
                           )

    license = db.Column(db.String(length=50),
                            nullable=True, default='',
                            info=dict(
                                label=_("License"),
                                description=_(''),
                                )
                           )


    """ Relationships """

    user = db.relationship(
        User, backref=db.backref("instruments", uselist=False,
                                 cascade="all, delete-orphan"))

    form_class = InstrumentForm

    flags = {}

    values = {}

    @classmethod
    def from_json(self, dct):
        return Instrument(id = dct['idInstrument'], user_id=int(dct['owner']['idUser']), name = dct['name'], access_right = dct['accessRight'],
                embargo_date = dct['embargoDate'], access_conditions=dct['conditions'], license = dct['license'])

    def get_owner(self):
        owner = User.query.filter_by(id=self.user_id).first()
        current_app.logger.debug(owner)
        current_app.logger.debug(owner.nickname)
        return owner.nickname

    #
    # Collection management
    #
    def get_collection_name(self):
        return '%s-%s' % (cfg['INSTRUMENTS_COLLECTION_PREFIX'], self.id)

    def get_collection_dbquery(self):
        return '%s:%s' % ("980__a", self.get_collection_name())

    def get_instrument_records(self, record_types=[], public=None, curated=None):
        """ Return all records of this instruments"""
        from invenio.legacy.search_engine import search_pattern_parenthesised
        from invenio.modules.records.models import Record
        q = ['980__:%s' % self.get_collection_name()]
        if record_types:
            qtypes = ['980__:%s' % t for t in record_types]
            if len(qtypes) > 1:
                q.append('(%s)' % ' OR '.join(qtypes))
            else:
                q.extend(qtypes)
        if public is not None:
            q.append('983__b:%s' % public)
        if curated is not None:
            q.append('983__a:%s' % curated)
        p = (' AND '.join(q))
        recids = search_pattern_parenthesised(p=p)
        records = Record.query.filter(Record.id.in_(recids))
        return records

    def save_collectionname(self, collection, name):
        if collection.id:
            c_name = Collectionname.query.filter_by(
                id_collection=collection.id, ln=CFG_SITE_LANG, type='ln'
            ).first()
            if c_name:
                update_changed_fields(c_name, dict(value=name))
                return c_name

        c_name = Collectionname(
            collection=collection,
            ln=CFG_SITE_LANG,
            type='ln',
            value=name,
        )
        db.session.add(c_name)
        return c_name

    def save_collectioncollection(self, collection):
        """Create or update CollectionCollection object."""
        dad = Collection.query.filter_by(
            name=cfg['INSTRUMENTS_PARENT_NAME']).first()

        if collection.id:
            c_tree = CollectionCollection.query.filter_by(
                id_dad=dad.id,
                id_son=collection.id
            ).first()
            if c_tree:
                update_changed_fields(c_tree, dict(
                    type=cfg['INSTRUMENTS_COLLECTION_TYPE'],
                    score=cfg['INSTRUMENTS_COLLECTION_SCORE']))
                return c_tree

        c_tree = CollectionCollection(
            dad=dad,
            son=collection,
            type=cfg['INSTRUMENTS_COLLECTION_TYPE'],
            score=cfg['INSTRUMENTS_COLLECTION_SCORE'],
        )
        db.session.add(c_tree)
        return c_tree

    def save_collectionformat(self, collection):
        """Create or update CollectionFormat object."""
        fmt = Format.query.filter_by(code=cfg['INSTRUMENTS_OUTPUTFORMAT']).first()

        if collection.id:
            c_fmt = CollectionFormat.query.filter_by(
                id_collection=collection.id
            ).first()
            if c_fmt:
                update_changed_fields(c_fmt, dict(id_format=fmt.id, score=1))
                return c_fmt

        c_fmt = CollectionFormat(
            collection=collection,
            id_format=fmt.id,
        )
        db.session.add(c_fmt)
        return c_fmt

    def save_acl(self, c):
        # Role - use Community id, because role name is limited to 32 chars.
        role_name = 'instrument_role_%s' % self.id
        role = AccROLE.query.filter_by(name=role_name).first()
        if not role:
            rule = 'allow group "%s"\ndeny any' % self.get_group_name()
            role = AccROLE(
                name=role_name,
                description='Owner of instruments %s' % self.name,
                firerole_def_ser=serialize(compile_role_definition(rule)),
                firerole_def_src=rule)
            db.session.add(role)

        # Argument
        fields = dict(keyword='collection', value=c.name)
        arg = AccARGUMENT.query.filter_by(**fields).first()
        if not arg:
            arg = AccARGUMENT(**fields)
            db.session.add(arg)

        # Action
        action = AccACTION.query.filter_by(name='viewrestrcoll').first()

        # User role
        alluserroles = UserAccROLE.query.filter_by(role=role).all()
        userrole = None
        if alluserroles:
            # Remove any user which is not the owner
            for ur in alluserroles:
                if ur.id_user == self.user_id:
                    db.session.delete(ur)
                else:
                    userrole = ur

        if not userrole:
            userrole = UserAccROLE(id_user=self.user_id, role=role)
            db.session.add(userrole)

        # Authorization
        auth = AccAuthorization.query.filter_by(role=role, action=action,
                                                argument=arg).first()
        if not auth:
            auth = AccAuthorization(role=role, action=action, argument=arg,
                                    argumentlistid=1)

    def save_collection(self):
        collection_name = self.get_collection_name()
        c = Collection.query.filter_by(name=collection_name).first()
        fields = dict(
            name=collection_name,
            dbquery=self.get_collection_dbquery()
        )
        if c:
            update_changed_fields(c, fields)
        else:
            c = Collection(**fields)
            db.session.add(c)
            db.session.commit()
        self.collection = c
        self.save_collectionname(c, self.name)
        self.save_collectioncollection(c)
        self.save_collectionformat(c)
        self.save_acl(c)
        db.session.commit()

    def delete_collection(self):
        if self.collection:
            CollectionFormat.query.filter_by(
                id_collection=self.collection.id).delete()
            Collectionname.query.filter_by(
                id_collection=self.collection.id).delete()
            CollectionCollection.query.filter_by(
                id_son=self.collection.id).delete()
            db.session.delete(self.collection)
            db.session.commit()

    def get_group_name(self):
        return 'instruments-group-%d' % self.id

    def save_group(self):
        g = self.group
        if not g:
            g = Group.create(self.get_group_name(),
                             description='Group for instruments %s' % self.id,
                             privacy_policy=PrivacyPolicy.MEMBERS,
                             subscription_policy=SubscriptionPolicy.APPROVAL,
                             is_managed=False,
                             admins=[self.owner])
            g.add_member(self.owner)
            self.group = g
            db.session.commit()

    def is_user_allowed(self, user=None):
        if not user:
            from flask_login import current_user
            user = current_user
        uid = user.get_id()
        groups = user.get('group', [])
        return self.user_id == uid or self.group.name in groups

    def is_empty(self):
        if self.eresable:
            # Ensure instruments has not records.
            from invenio.legacy.search_engine import search_pattern
            q = '980__:%s' % self.get_collection_name()
            recids = search_pattern(p=q)
            if len(recids) != 0:
                self.eresable = False
                db.session.commit()
                return False
            else:
                return True
        return False

    @classmethod
    def get_instrument(cls, id):
        try:
            return cls.query.get(int(id))
        except ValueError:
            return None

    @classmethod
    def get_or_create(cls):
        instance = cls.get()
        if instance:
            return instance
        else:
            return cls.create()

    @classmethod
    def create(cls):
        try:
            obj = cls(
                user_id=current_user.get_id(),
            )
            db.session.add(obj)
            db.session.commit()
            # PROFILE CREATE SIGNAL
            return obj
        except IntegrityError as e:
            db.session.rollback()
            raise e
        except Exception as e:
            raise e

    @classmethod
    def get(cls):
        try:
            return cls.query.filter_by(user_id=current_user.get_id()).one()
        except NoResultFound:
            return None

    @classmethod
    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


    def get_access_right(self):
        for tuple in ACCESS_RIGHTS_CHOICES:
            if tuple[0] == self.access_right:
                return tuple[1]

    def get_license(self):
        licenses = _kb_license_choices(True, True, True)
        for tuple in licenses:
            if tuple[0] == self.license:
                return tuple[1]

    def get_groups(self):
        import json
        groups = findGroupByInstrumentId(self.id)
        groups_text = ""
        for group in json.loads(groups):
            groups_text += group['name'] + " | "
        return groups_text[:-3]

    def complete(self):
        """
        Set state of draft to completed.
        """
        self.completed = True

    def get_form(self, formdata=None, load_draft=True,
                 validate_draft=False):
        """
        Create form instance with draft data and form data if provided.

        :param formdata: Incoming form data.
        :param files: Files to ingest into form
        :param load_draft: True to initialize form with draft data.
        :param validate_draft: Set to true to validate draft data, when no form
             data is provided.
        """
        if not self.has_form():
            raise FormDoesNotExists(self.id)

        draft_data = unicodifier(self.values) if load_draft else {}
        formdata = MultiDict(formdata or {})

        form = self.form_class(
            formdata=formdata, **draft_data
        )

        if formdata:
            form.reset_field_data(exclude=formdata.keys())

        # Set field flags
        if load_draft and self.flags:
            form.set_flags(self.flags)

        if validate_draft and draft_data and formdata is None:
            form.validate()

        return form

    def has_form(self):
        return self.form_class is not None

    def process(self, data, complete_form=False):
        """
        Process, validate and store incoming form data and return response.
        """


        # The form is initialized with form and draft data. The original
        # draft_data is accessible in Field.object_data, Field.raw_data is the
        # new form data and Field.data is the processed form data or the
        # original draft data.
        #
        # Behind the scences, Form.process() is called, which in turns call
        # Field.process_data(), Field.process_formdata() and any filters
        # defined.
        #
        # Field.object_data contains the value of process_data(), while
        # Field.data contains the value of process_formdata() and any filters
        # applied.


        # Run form validation which will call Field.pre_valiate(),
        # Field.validators, Form.validate_<field>() and Field.post_validate().
        # Afterwards Field.data has been validated and any errors will be
        # present in Field.errors.
        # validated = form.validate()
        form = self.get_form(formdata=data)
        validated = form.validate()

        # Call Form.run_processors() which in turn will call
        # Field.run_processors() that allow fields to set flags (hide/show)
        # and values of other fields after the entire formdata has been
        # processed and validated.
        validated_flags, validated_data, validated_msgs = (
            form.get_flags(), form.data, form.messages
        )

        form.post_process(formfields=[] if complete_form else data.keys())
        post_processed_flags, post_processed_data, post_processed_msgs = (
            form.get_flags(), form.data, form.messages
        )

        # Save form values
        self.update(form)

        # Build result dictionary
        process_field_names = None if complete_form else data.keys()


        # Determine if some fields where changed during post-processing.
        changed_values = dict(
            (name, value) for name, value in post_processed_data.items()
            if validated_data[name] != value
        )

        # Determine changed flags
        changed_flags = dict(
            (name, flags) for name, flags in post_processed_flags.items()
            if validated_flags.get(name, []) != flags
        )
        # Determine changed messages
        changed_msgs = dict(
            (name, messages) for name, messages in post_processed_msgs.items()
            if validated_msgs.get(name, []) != messages or
            process_field_names is None or name in process_field_names
        )

        result = {}


        if changed_msgs:
            result['messages'] = changed_msgs
        if changed_values:
            result['values'] = changed_values


        if 'access_right' in data:
            if post_processed_data['access_right'] == 'open':
                result['hidden_off'] = ['name', 'license', 'access_right']
                result['hidden_on'] = ['embargo_date', 'access_groups', 'access_conditions']
                result['disabled_off'] = ['name', 'license', 'access_right']
                result['disabled_on'] = ['embargo_date', 'access_groups', 'access_conditions']
            if post_processed_data['access_right'] == 'embargoed':
                result['hidden_off'] = ['name', 'license', 'access_right', 'embargo_date']
                result['hidden_on'] = ['access_groups', 'access_conditions']
                result['disabled_off'] = ['name', 'license', 'access_right', 'embargo_date']
                result['disabled_on'] = ['access_groups', 'access_conditions']
            if post_processed_data['access_right'] == 'restricted':
                result['hidden_off'] = ['name', 'access_right', 'access_groups', 'access_conditions']
                result['hidden_on'] = ['license', 'embargo_date']
                result['disabled_off'] = ['name', 'access_right', 'access_groups', 'access_conditions']
                result['disabled_on'] = ['license', 'embargo_date']
            if post_processed_data['access_right'] == 'closed':
                result['hidden_off'] = ['name', 'access_right']
                result['hidden_on'] = ['access_groups', 'access_conditions', 'license', 'embargo_date']
                result['disabled_off'] = ['name', 'access_right']
                result['disabled_on'] = ['access_groups', 'access_conditions', 'license', 'embargo_date']

        return form, validated, result

    def update(self, form):
        """
        Update draft values and flags with data from form.
        """
        data = dict((key, value) for key, value in form.data.items()
                    if value is not None)
        self.values = data
        self.flags = form.get_flags()

    def __str__(self):
        instrumentStr = self.name + ',' + self.access_right + ',' + \
                        self.access_conditions + ',' + self.license + ',' + str(self.embargo_date)
        return instrumentStr
Пример #13
0
class CmtRECORDCOMMENT(db.Model):
    """Represents a CmtRECORDCOMMENT record."""

    __tablename__ = 'cmtRECORDCOMMENT'

    id = db.Column(db.Integer(15, unsigned=True),
                   nullable=False,
                   primary_key=True,
                   autoincrement=True)
    id_bibrec = db.Column(db.MediumInteger(8, unsigned=True),
                          db.ForeignKey(Bibrec.id),
                          nullable=False,
                          server_default='0')
    id_user = db.Column(db.Integer(15, unsigned=True),
                        db.ForeignKey(User.id),
                        nullable=False,
                        server_default='0')
    title = db.Column(db.String(255), nullable=False, server_default='')
    body = db.Column(db.Text, nullable=False)
    date_creation = db.Column(db.DateTime,
                              nullable=False,
                              server_default='1900-01-01 00:00:00')
    star_score = db.Column(db.TinyInteger(5, unsigned=True),
                           nullable=False,
                           server_default='0')
    nb_votes_yes = db.Column(db.Integer(10),
                             nullable=False,
                             server_default='0')
    nb_votes_total = db.Column(db.Integer(10, unsigned=True),
                               nullable=False,
                               server_default='0')
    nb_abuse_reports = db.Column(db.Integer(10),
                                 nullable=False,
                                 server_default='0')
    status = db.Column(db.Char(2),
                       nullable=False,
                       index=True,
                       server_default='ok')
    round_name = db.Column(db.String(255), nullable=False, server_default='')
    restriction = db.Column(db.String(50), nullable=False, server_default='')
    in_reply_to_id_cmtRECORDCOMMENT = db.Column(db.Integer(15, unsigned=True),
                                                db.ForeignKey(id),
                                                nullable=False,
                                                server_default='0')
    reply_order_cached_data = db.Column(db.Binary, nullable=True)
    bibrec = db.relationship(Bibrec, backref='recordcomments')
    user = db.relationship(User, backref='recordcomments')
    replies = db.relationship('CmtRECORDCOMMENT',
                              backref=db.backref('parent',
                                                 remote_side=[id],
                                                 order_by=date_creation))

    @property
    def is_deleted(self):
        """Check if is deleted."""
        return self.status != 'ok'

    def is_collapsed(self, id_user):
        """Return true if the comment is collapsed by user."""
        return CmtCOLLAPSED.query.filter(
            db.and_(CmtCOLLAPSED.id_bibrec == self.id_bibrec,
                    CmtCOLLAPSED.id_cmtRECORDCOMMENT == self.id,
                    CmtCOLLAPSED.id_user == id_user)).count() > 0

    @session_manager
    def collapse(self, id_user):
        """Collapse comment beloging to user."""
        c = CmtCOLLAPSED(id_bibrec=self.id_bibrec,
                         id_cmtRECORDCOMMENT=self.id,
                         id_user=id_user)
        db.session.add(c)
        db.session.commit()

    def expand(self, id_user):
        """Expand comment beloging to user."""
        CmtCOLLAPSED.query.filter(
            db.and_(CmtCOLLAPSED.id_bibrec == self.id_bibrec,
                    CmtCOLLAPSED.id_cmtRECORDCOMMENT == self.id,
                    CmtCOLLAPSED.id_user == id_user)).delete(
                        synchronize_session=False)

    __table_args__ = (db.Index('cmtRECORDCOMMENT_reply_order_cached_data',
                               reply_order_cached_data,
                               mysql_length=40), db.Model.__table_args__)

    @classmethod
    def count(cls, *criteria, **filters):
        """Count how many comments."""
        return cls.query.filter(*criteria).filter_by(**filters).count()
Пример #14
0
class GroupAdmin(db.Model):
    """Represent an administrator of a group."""

    __tablename__ = 'groupADMIN'

    __table_args__ = (db.UniqueConstraint('group_id', 'admin_type',
                                          'admin_id'), db.Model.__table_args__)

    id = db.Column(db.Integer(15, unsigned=True),
                   nullable=False,
                   primary_key=True,
                   autoincrement=True)
    """GroupAdmin identifier."""

    group_id = db.Column(db.Integer(15, unsigned=True),
                         db.ForeignKey(Group.id),
                         nullable=False,
                         primary_key=True)
    """Group for membership."""

    admin_type = db.Column(db.Unicode(255))
    """Generic relationship to an object."""

    admin_id = db.Column(db.Integer)
    """Generic relationship to an object."""

    #
    # Relations
    #

    group = db.relationship(Group,
                            backref=db.backref('admins',
                                               cascade="all, delete-orphan"))
    """Group relationship."""

    admin = generic_relationship(admin_type, admin_id)
    """Generic relationship to administrator of group."""
    @classmethod
    def create(cls, group, admin):
        """Create a new group admin.

        :param group: Group object.
        :param admin: Admin object.
        :returns: Newly created GroupAdmin object.
        :raises: IntegrityError
        """
        try:
            obj = cls(
                group=group,
                admin=admin,
            )
            db.session.add(obj)

            db.session.commit()
            return obj
        except IntegrityError:
            db.session.rollback()
            raise

    @classmethod
    def get(cls, group, admin):
        """Get specific GroupAdmin object."""
        try:
            ga = cls.query.filter_by(
                group=group,
                admin_id=admin.get_id(),
                admin_type=resolve_admin_type(admin)).one()
            return ga
        except Exception:
            return None

    @classmethod
    def delete(cls, group, admin):
        """Delete admin from group.

        :param group: Group object.
        :param admin: Admin object.
        """
        try:
            obj = cls.query.filter(cls.admin == admin,
                                   cls.group == group).one()
            db.session.delete(obj)
            db.session.commit()
        except Exception:
            db.session.rollback()
            raise

    @classmethod
    def query_by_group(cls, group):
        """Get all admins for a specific group."""
        return cls.query.filter_by(group=group)

    @classmethod
    def query_by_admin(cls, admin):
        """Get all groups for for a specific admin."""
        return cls.query.filter_by(admin_type=resolve_admin_type(admin),
                                   admin_id=admin.get_id())

    @classmethod
    def query_admins_by_group_ids(cls, groups_ids=None):
        """Get count of admins per group."""
        assert groups_ids is None or isinstance(groups_ids, list)

        query = db.session.query(Group.id, func.count(
            GroupAdmin.id)).join(GroupAdmin).group_by(Group.id)

        if groups_ids:
            query = query.filter(Group.id.in_(groups_ids))

        return query
Пример #15
0
class Membership(db.Model):
    """Represent a users membership of a group."""

    MEMBERSHIP_STATE = {
        MembershipState.PENDING_ADMIN: _("Pending admin approval"),
        MembershipState.PENDING_USER: _("Pending member approval"),
        MembershipState.ACTIVE: _("Active"),
    }
    """Membership state choices."""

    __tablename__ = 'groupMEMBER'

    id_user = db.Column(db.Integer(15, unsigned=True),
                        db.ForeignKey(User.id),
                        nullable=False,
                        primary_key=True)
    """User for membership."""

    id_group = db.Column(db.Integer(15, unsigned=True),
                         db.ForeignKey(Group.id),
                         nullable=False,
                         primary_key=True)
    """Group for membership."""

    state = db.Column(ChoiceType(MEMBERSHIP_STATE, impl=db.String(1)),
                      nullable=False)
    """State of membership."""

    created = db.Column(db.DateTime, nullable=False, default=datetime.now)
    """Creation timestamp."""

    modified = db.Column(db.DateTime,
                         nullable=False,
                         default=datetime.now,
                         onupdate=datetime.now)
    """Modification timestamp."""

    #
    # Relations
    #

    user = db.relationship(User, backref=db.backref('groups'))
    """User relaionship."""

    group = db.relationship(Group,
                            backref=db.backref('members',
                                               cascade="all, delete-orphan"))
    """Group relationship."""
    @classmethod
    def get(cls, group, user):
        """Get membership for given user and group.

        :param group: Group object.
        :param user: User object.
        :returns: Membership or None.
        """
        try:
            m = cls.query.filter_by(id_user=user.get_id(), group=group).one()
            return m
        except Exception:
            return None

    @classmethod
    def _filter(cls, query, state=MembershipState.ACTIVE, eager=None):
        """Filter a query result."""
        query = query.filter_by(state=state)

        eager = eager or []
        for field in eager:
            query = query.options(joinedload(field))

        return query

    @classmethod
    def query_by_user(cls, user, **kwargs):
        """Get a user's memberships."""
        return cls._filter(cls.query.filter_by(id_user=user.get_id()),
                           **kwargs)

    @classmethod
    def query_invitations(cls, user, eager=False):
        """Get all invitations for given user."""
        if eager:
            eager = [Membership.group]
        return cls.query_by_user(user,
                                 state=MembershipState.PENDING_USER,
                                 eager=eager)

    @classmethod
    def query_requests(cls, admin, eager=False):
        """Get all pending group requests."""
        # Get direct pending request
        # if hasattr(admin, 'is_admin') and admin.is_superadmin:
        #     q1 = GroupAdmin.query.with_entities(
        #         GroupAdmin.group_id)
        # else:
        q1 = GroupAdmin.query_by_admin(admin).with_entities(
            GroupAdmin.group_id)
        q2 = Membership.query.filter(
            Membership.state == MembershipState.PENDING_ADMIN,
            Membership.id_group.in_(q1),
        )

        # Get request from admin groups your are member of
        q3 = Membership.query_by_user(
            user=admin,
            state=MembershipState.ACTIVE).with_entities(Membership.id_group)
        q4 = GroupAdmin.query.filter(
            GroupAdmin.admin_type == 'Group',
            GroupAdmin.admin_id.in_(q3)).with_entities(GroupAdmin.group_id)
        q5 = Membership.query.filter(
            Membership.state == MembershipState.PENDING_ADMIN,
            Membership.id_group.in_(q4))

        query = q2.union(q5)

        return query

    @classmethod
    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))

    @classmethod
    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

    @classmethod
    def order(cls, query, field, s):
        """Modify query as so to order the results.

        :param query: Query object.
        :param str s: Orderinig: ``asc`` or ``desc``.
        :returs: Query object.
        """
        if s == "asc":
            query = query.order_by(asc(field))
        elif s == "desc":
            query = query.order_by(desc(field))
        return query

    @classmethod
    def create(cls, group, user, state=MembershipState.ACTIVE):
        """Create a new membership."""
        try:
            membership = cls(
                id_user=user.get_id(),
                id_group=group.id,
                state=state,
            )
            db.session.add(membership)
            db.session.commit()

            return membership
        except IntegrityError:
            db.session.rollback()
            raise

    @classmethod
    def delete(cls, group, user):
        """Delete membership."""
        try:
            cls.query.filter_by(group=group, id_user=user.get_id()).delete()
            db.session.commit()
        except Exception:
            db.session.rollback()
            raise

    def accept(self):
        """Activate membership."""
        self.state = MembershipState.ACTIVE
        db.session.commit()

    def reject(self):
        """Remove membership."""
        try:
            db.session.delete(self)
            db.session.commit()
        except Exception:
            db.session.rollback()
            raise

    def is_active(self):
        """Check if membership is in an active state."""
        return self.state == MembershipState.ACTIVE
Пример #16
0
class Token(db.Model):

    """A bearer token is the final token that can be used by the client."""

    __tablename__ = 'oauth2TOKEN'

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    """Object ID."""

    client_id = db.Column(
        db.String(255), db.ForeignKey('oauth2CLIENT.client_id'),
        nullable=False,
    )
    """Foreign key to client application."""

    client = db.relationship(
        'Client',
        backref=db.backref(
            'oauth2tokens',
            cascade="all, delete-orphan"
        ))
    """SQLAlchemy relationship to client application."""

    user_id = db.Column(
        db.Integer(15, unsigned=True), db.ForeignKey('user.id'), nullable=True
    )
    """Foreign key to user."""

    user = db.relationship(
        User,
        backref=db.backref(
            "oauth2tokens",
            cascade="all, delete-orphan",
        )
    )
    """SQLAlchemy relationship to user."""

    token_type = db.Column(db.String(255), default='bearer')
    """Token type - only bearer is supported at the moment."""

    access_token = db.Column(String255EncryptedType(
        type_in=db.String(255),
        key=secret_key),
        unique=True
    )

    refresh_token = db.Column(String255EncryptedType(
        type_in=db.String(255),
        key=secret_key,
        engine=NoneAesEngine),
        unique=True, nullable=True
    )

    expires = db.Column(db.DateTime, nullable=True)

    _scopes = db.Column(db.Text)

    is_personal = db.Column(db.Boolean, default=False)
    """Personal accesss token."""

    is_internal = db.Column(db.Boolean, default=False)
    """Determines if token is an internally generated token."""

    @property
    def scopes(self):
        """Return all scopes."""
        if self._scopes:
            return self._scopes.split()
        return []

    @scopes.setter
    def scopes(self, scopes):
        """Set scopes."""
        validate_scopes(scopes)
        self._scopes = " ".join(set(scopes)) if scopes else ""

    def get_visible_scopes(self):
        """Get list of non-internal scopes for token."""
        from .registry import scopes as scopes_registry
        return [k for k, s in scopes_registry.choices() if k in self.scopes]

    @classmethod
    def create_personal(cls, name, user_id, scopes=None, is_internal=False):
        """Create a personal access token.

        A token that is bound to a specific user and which doesn't expire, i.e.
        similar to the concept of an API key.
        """
        scopes = " ".join(scopes) if scopes else ""

        c = Client(
            name=name,
            user_id=user_id,
            is_internal=True,
            is_confidential=False,
            _default_scopes=scopes
        )
        c.gen_salt()

        t = Token(
            client_id=c.client_id,
            user_id=user_id,
            access_token=gen_salt(
                current_app.config.get('OAUTH2_TOKEN_PERSONAL_SALT_LEN')
            ),
            expires=None,
            _scopes=scopes,
            is_personal=True,
            is_internal=is_internal,
        )

        db.session.add(c)
        db.session.add(t)
        db.session.commit()

        return t
Пример #17
0
class UserProfile(db.Model):
    __tablename__ = 'UserProfile'

    """ Fields """
    user_id = db.Column(db.Integer(255, unsigned=True), db.ForeignKey(User.id),
                        nullable=False, primary_key=True,
                        )

    name = db.Column(db.String(length=255),
                     nullable=True, default='',
                     info=dict(
                         label=_("Name"),
                         description=_(''),
                         )
                     )

    institution = db.Column(db.String(length=255),
                            nullable=True, default='',
                            info=dict(
                                label=_("Institution"),
                                description=_(''),
                                )
                            )

    email = db.Column(db.String(length=255),
                      nullable=True, default='',
                      info=dict(
                          label=_("Contact e-mail"),
                          description=_(''),
                          )
                      )

    social_profiles = db.Column(db.String(length=255),
                                nullable=True, default='',
                                info=dict(
                                    label=_("Social networks"),
                                    description=_(''),
                                    )
                                )

    ei_user = db.Column(db.String(length=255),
                        nullable=True, default='',
                        info=dict(
                            label=_("User name"),
                            description=_(''),
                            )
                        )

    ei_pass = db.Column(db.String(length=255),
                        nullable=True, default='',
                        info=dict(
                            label=_("Password"),
                            description=_(''),
                            )
                        )

    user_proxy = db.Column(db.Text(length=10000),
                           nullable=True, default='',)

    csr_priv_key = db.Column(db.Text(length=10000),
                             nullable=True, default='')

    ssh_public_key = db.Column(db.Text(length=2000),
                               nullable=True, default='',
                               info=dict(
                                   label=_("SSH public key"),
                                   description=_('Paste your SSH public key, '
                                                 'it\'s important to copy the '
                                                 'key exactly without adding '
                                                 'newlines or whitespace.'),
                                   )
                               )

    user_db = db.Column(db.String(length=255),
                               nullable=True, default='',
                               info=dict(
                                   label=_("User DB"),
                                   description=_(''),
                                   )
                               )

    pass_db = db.Column(db.String(length=255),
                               nullable=True, default='',
                               info=dict(
                                   label=_("Password DB"),
                                   description=_(''),
                                   )
                               )

    token_onedata = db.Column(db.String(length=255),
                               nullable=True, default='',
                               info=dict(
                                   label=_("OneData token"),
                                   description=_(''),
                                   )
                               )

    created = db.Column(db.DateTime, nullable=False, default=datetime.now)
    modified = db.Column(db.DateTime, nullable=False, default=datetime.now,
                         onupdate=datetime.now)

    """ Relationships """

    user = db.relationship(
        User, backref=db.backref("UserProfile", uselist=False,
                                 cascade="all, delete-orphan"))

    @classmethod
    def create(cls):
        try:
            obj = cls(
                user_id=current_user.get_id(),
            )
            db.session.add(obj)
            db.session.commit()
            # PROFILE CREATE SIGNAL
            return obj
        except IntegrityError as e:
            db.session.rollback()
            raise e
        except Exception as e:
            raise e

    @classmethod
    def get(cls):
        try:
            return cls.query.filter_by(user_id=current_user.get_id()).one()
        except NoResultFound:
            return None

    @classmethod
    def get_or_create(cls):
        instance = cls.get()
        if instance:
            return instance
        else:
            return cls.create()

    def update(self, **data):
        for value in data:
            setattr(self, value, data[value])
        try:
            db.session.commit()
            return self
        except Exception as e:
            raise e
Пример #18
0
class KnwKBRVAL(db.Model):
    """Represent a KnwKBRVAL record."""

    __tablename__ = 'knwKBRVAL'
    m_key = db.Column(db.String(255),
                      nullable=False,
                      primary_key=True,
                      index=True)
    m_value = db.Column(db.Text().with_variant(mysql.TEXT(30), 'mysql'),
                        nullable=False)
    id_knwKB = db.Column(db.MediumInteger(8, unsigned=True),
                         db.ForeignKey(KnwKB.id),
                         nullable=False,
                         server_default='0',
                         primary_key=True)
    kb = db.relationship(
        KnwKB,
        backref=db.backref(
            'kbrvals',
            cascade="all, delete-orphan",
            collection_class=attribute_mapped_collection("m_key")))

    @staticmethod
    def query_kb_mappings(kbid, sortby="to", key="", value="", match_type="s"):
        """Return a list of all mappings from the given kb, ordered by key.

        If key given, give only those with left side (mapFrom) = key.
        If value given, give only those with right side (mapTo) = value.

        :param kb_name: knowledge base name. if "", return all
        :param sortby: the sorting criteria ('from' or 'to')
        :param key: return only entries where key matches this
        :param value: return only entries where value matches this
        :param match_type: s=substring, e=exact, sw=startswith
        """
        # query
        query = KnwKBRVAL.query.filter(KnwKBRVAL.id_knwKB == kbid)
        # filter
        if len(key) > 0:
            if match_type == "s":
                key = "%" + key + "%"
            elif match_type == "sw":
                key = key + "%"
        else:
            key = '%'
        if len(value) > 0:
            if match_type == "s":
                value = "%" + value + "%"
            elif match_type == "sw":
                value = value + "%"
        else:
            value = '%'
        query = query.filter(KnwKBRVAL.m_key.like(key),
                             KnwKBRVAL.m_value.like(value))
        # order by
        if sortby == "from":
            query = query.order_by(KnwKBRVAL.m_key)
        else:
            query = query.order_by(KnwKBRVAL.m_value)
        return query

    def to_dict(self):
        """Return a dict representation of KnwKBRVAL."""
        # FIXME remove 'id' dependency from invenio modules
        return {
            'id': self.m_key + "_" + str(self.id_knwKB),
            'key': self.m_key,
            'value': self.m_value,
            'kbid': self.kb.id if self.kb else None,
            'kbname': self.kb.name if self.kb else None
        }
Пример #19
0
class BibWorkflowObject(db.Model):
    """Data model for wrapping data being run in the workflows.

    Main object being passed around in the workflows module
    when using the workflows API.

    It can be instantiated like this:

    .. code-block:: python

        obj = BibWorkflowObject()
        obj.save()

    Or, like this:

    .. code-block:: python

        obj = BibWorkflowObject.create_object()

    BibWorkflowObject provides some handy functions such as:

    .. code-block:: python

        obj.set_data("<xml ..... />")
        obj.get_data() == "<xml ..... />"
        obj.set_extra_data({"param": value})
        obj.get_extra_data() == {"param": value}
        obj.add_task_result("myresult", {"result": 1})

    Then to finally save the object

    .. code-block:: python

        obj.save()

    Now you can for example run it in a workflow:

    .. code-block:: python

        obj.start_workflow("sample_workflow")
    """

    __tablename__ = "bwlOBJECT"

    id = db.Column(db.Integer, primary_key=True)

    # Our internal data column. Default is encoded dict.
    _data = db.Column(db.LargeBinary,
                      nullable=False,
                      default=get_default_data())
    _extra_data = db.Column(db.LargeBinary,
                            nullable=False,
                            default=get_default_extra_data())

    _id_workflow = db.Column(db.String(36),
                             db.ForeignKey('bwlWORKFLOW.uuid'),
                             nullable=True,
                             name="id_workflow")
    version = db.Column(db.Integer(3),
                        default=ObjectVersion.INITIAL,
                        nullable=False,
                        index=True)
    id_parent = db.Column(db.Integer,
                          db.ForeignKey("bwlOBJECT.id"),
                          default=None)
    child_objects = db.relationship("BibWorkflowObject",
                                    remote_side=[id_parent])
    created = db.Column(db.DateTime, default=datetime.now, nullable=False)
    modified = db.Column(db.DateTime,
                         default=datetime.now,
                         onupdate=datetime.now,
                         nullable=False)
    status = db.Column(db.String(255), default="", nullable=False)
    data_type = db.Column(db.String(150),
                          default="",
                          nullable=True,
                          index=True)
    uri = db.Column(db.String(500), default="")
    id_user = db.Column(db.Integer, default=0, nullable=False)

    child_logs = db.relationship("BibWorkflowObjectLog",
                                 backref=db.backref('bibworkflowobject'),
                                 cascade="all, delete, delete-orphan")

    workflow = db.relationship(Workflow,
                               backref=db.backref(
                                   'objects', cascade="all, delete-orphan"))

    _log = None

    @db.hybrid_property
    def id_workflow(self):
        """Get id_workflow."""
        return self._id_workflow

    @id_workflow.setter
    def id_workflow(self, value):
        """Set id_workflow."""
        self._id_workflow = str(value) if value else None

    @property
    def log(self):
        """Access logger object for this instance."""
        if not self._log:
            db_handler_obj = BibWorkflowLogHandler(BibWorkflowObjectLog, "id")
            self._log = get_logger(logger_name="object.%s" % (self.id, ),
                                   db_handler_obj=db_handler_obj,
                                   loglevel=logging.DEBUG,
                                   obj=self)
        return self._log

    def get_data(self):
        """Get data saved in the object."""
        return cPickle.loads(base64.b64decode(self._data))

    def set_data(self, value):
        """Save data to the object."""
        self._data = base64.b64encode(cPickle.dumps(value))

    def get_extra_data(self):
        """Get extra data saved to the object."""
        return cPickle.loads(base64.b64decode(self._extra_data))

    def set_extra_data(self, value):
        """Save extra data to the object.

        :param value: what you want to replace extra_data with.
        :type value: dict
        """
        self._extra_data = base64.b64encode(cPickle.dumps(value))

    def get_workflow_name(self):
        """Return the workflow name for this object."""
        try:
            if self.id_workflow:
                return Workflow.query.get(self.id_workflow).name
        except AttributeError:
            # Workflow non-existent
            pass
        return

    def get_formatted_data(self, of=None):
        """Get the formatted representation for this object."""
        from .registry import workflows
        if of is None:
            of = cfg.get("WORKFLOWS_HOLDING_PEN_DEFAULT_OUTPUT_FORMAT")
        try:
            name = self.get_workflow_name()
            if not name:
                return ""
            workflow_definition = workflows[name]
            formatted_data = workflow_definition.formatter(self, of=of)
        except (KeyError, AttributeError):
            # Somehow the workflow or formatter does not exist
            from invenio.ext.logging import register_exception
            register_exception(alert_admin=True)
            formatted_data = ""
        return formatted_data

    def __repr__(self):
        """Represent a BibWorkflowObject."""
        return "<BibWorkflowObject(id = %s, data = %s, id_workflow = %s, " \
               "version = %s, id_parent = %s, created = %s, extra_data = %s)" \
               % (str(self.id), str(self.get_data()), str(self.id_workflow),
                  str(self.version), str(self.id_parent), str(self.created),
                  str(self.get_extra_data()))

    def __eq__(self, other):
        """Enable equal operators on BibWorkflowObjects."""
        if isinstance(other, BibWorkflowObject):
            if self._data == other._data and \
                    self._extra_data == other._extra_data and \
                    self.id_workflow == other.id_workflow and \
                    self.version == other.version and \
                    self.id_parent == other.id_parent and \
                    isinstance(self.created, datetime) and \
                    isinstance(self.modified, datetime):
                return True
            else:
                return False
        return NotImplemented

    def __ne__(self, other):
        """Enable equal operators on BibWorkflowObjects."""
        return not self.__eq__(other)

    def add_task_result(self,
                        name,
                        result,
                        template="workflows/results/default.html"):
        """Add a new task result defined by name.

        The name is the dictionary key used to group similar types of
        results as well as a possible label for the result.

        The result is a dictionary given as context to the template
        when rendered. The result given here is added to a list of results
        for this name.

        .. code-block:: python

                obj = BibWorkflowObject()  # or BibWorkflowObject.query.get(id)
                obj.add_task_result("foo", my_result, "path/to/template")

        :param name: The name of the task in human friendly way.
                     It is used as a key and label for the result rendering.
        :type name: string

        :param result: The result to store - passed to render_template().
        :type result: dict

        :param template: The location of the template to render the result.
        :type template: string
        """
        extra_data = getattr(self, "extra_data", self.get_extra_data())
        task_result = {"name": name, "result": result, "template": template}
        if name in extra_data["_tasks_results"]:
            extra_data["_tasks_results"][name].append(task_result)
        else:
            extra_data["_tasks_results"][name] = [task_result]
        self.set_extra_data(extra_data)

    def update_task_results(self, name, results):
        """Update tasks results by name.

        The name is the dictionary key used to group similar types of
        results as well as a possible label for the result.

        This functions allows you to update (replace) the list of results
        associated with a name where each result is structured like this:

        .. code-block:: python

                task_result = {
                   "name": "foo",
                   "result": result,
                   "template": template
                }
                obj = BibWorkflowObject()  # or BibWorkflowObject.query.get(id)
                obj.update_task_results("foo", [task_result])

        :param name: The name of the task in human friendly way.
                     It is used as a key and label for the result rendering.
        :type name: string

        :param results: List of results to store - passed to render_template().
        :type results: list

        :param template: The location of the template to render the result.
        :type template: string
        """
        extra_data = getattr(self, "extra_data", self.get_extra_data())
        extra_data["_tasks_results"][name] = results
        self.set_extra_data(extra_data)

    def get_tasks_results(self):
        """Return the complete set of tasks results.

        The result is given as a dictionary where each result is
        structured like:

        .. code-block:: python

                task_result = {
                   "name": name,
                   "result": result,
                   "template": template
                }

        :return: dictionary of results as {name: [result, ..], ..}
        """
        return self.get_extra_data()["_tasks_results"]

    def set_action(self, action, message):
        """Set the action to be taken for this object.

        Assign an special "action" to this object to be taken
        in consideration in Holding Pen. The widget is referred to
        by a string with the filename minus extension.

        A message is also needed to tell the user the action
        required in a textual way.

        :param action: name of the action to add (i.e. "approval")
        :type action: string

        :param message: message to show to the user
        :type message: string
        """
        extra_data = self.get_extra_data()
        extra_data["_action"] = action
        extra_data["_message"] = message
        self.set_extra_data(extra_data)

    def get_action(self):
        """Retrieve the currently assigned action, if any.

        :return: name of action assigned as string, or None
        """
        return self.get_extra_data().get("_action")

    def get_action_message(self):
        """Retrieve the currently assigned widget, if any."""
        try:
            return unicodifier(self.get_extra_data()["_message"])
        except KeyError:
            # No widget
            return ""

    def set_error_message(self, msg):
        """Set an error message."""
        extra_data = self.get_extra_data()
        extra_data["_error_msg"] = msg
        self.set_extra_data(extra_data)

    def reset_error_message(self):
        """Reset the error message."""
        extra_data = self.get_extra_data()
        if "_error_msg" in extra_data:
            del extra_data["_error_msg"]
            self.set_extra_data(extra_data)

    def get_error_message(self):
        """Retrieve the error message, if any."""
        if "error_msg" in self.get_extra_data():
            # Backwards compatibility
            extra_data = self.get_extra_data()
            msg = extra_data["error_msg"]
            del extra_data["error_msg"]
            self.set_extra_data(extra_data)
            self.set_error_message(msg)
        try:
            return self.get_extra_data()["_error_msg"]
        except KeyError:
            # No message
            return ""

    def remove_action(self):
        """Remove the currently assigned action."""
        extra_data = self.get_extra_data()
        extra_data["_action"] = None
        extra_data["_message"] = ""
        if "_widget" in extra_data:
            del extra_data["_widget"]
        self.set_extra_data(extra_data)

    def start_workflow(self, workflow_name, delayed=False, **kwargs):
        """Run the workflow specified on the object.

        Will start workflows execution for the object using
        :py:func:`.api.start` (or :py:func:`.api.start_delayed`
        if `delayed=True`).


        :param workflow_name: name of workflow to run
        :type workflow_name: str

        :param delayed: should the workflow run asynchronously?
        :type delayed: bool

        :return: BibWorkflowEngine (or AsynchronousResultWrapper).
        """
        if delayed:
            from .api import start_delayed as start_func
        else:
            from .api import start as start_func
        self.save()
        return start_func(workflow_name, data=[self], **kwargs)

    def continue_workflow(self,
                          start_point="continue_next",
                          delayed=False,
                          **kwargs):
        """Continue the workflow for this object.

        Will continue a previous execution for the object using
        :py:func:`.api.continue_oid` (or :py:func:`.api.continue_oid_delayed`
        if `delayed=True`).

        The parameter `start_point` allows you to specify the point of where
        the workflow shall continue:

        * restart_prev: will restart from the previous task

        * continue_next: will continue to the next task

        * restart_task: will restart the current task

        :param start_point: where should the workflow start from?
        :type start_point: str

        :param delayed: should the workflow run asynchronously?
        :type delayed: bool

        :return: BibWorkflowEngine (or AsynchronousResultWrapper).
        """
        from .errors import WorkflowAPIError

        self.save()
        if not self.id_workflow:
            raise WorkflowAPIError("No workflow associated with object: %r" %
                                   (repr(self), ))
        if delayed:
            from .api import continue_oid_delayed as continue_func
        else:
            from .api import continue_oid as continue_func
        return continue_func(self.id, start_point, **kwargs)

    def change_status(self, message):
        """Change the status."""
        self.status = message

    def get_current_task(self):
        """Return the current task from the workflow engine for this object."""
        extra_data = self.get_extra_data()
        try:
            return extra_data["_task_counter"]
        except KeyError:
            # Assume old version "task_counter"
            return extra_data["task_counter"]

    def get_current_task_info(self):
        """Return dictionary of current task function info for this object."""
        from .utils import get_workflow_definition, get_func_info

        task_pointer = self.get_current_task()
        name = self.get_workflow_name()
        if not name:
            return ""
        current_task = get_workflow_definition(name)
        for step in task_pointer:
            current_task = current_task[step]
            if callable(current_task):
                return get_func_info(current_task)

    def save_to_file(self,
                     directory=None,
                     prefix="workflow_object_data_",
                     suffix=".obj"):
        """Save the contents of self.data['data'] to file.

        Returns path to saved file.

        Warning: Currently assumes non-binary content.
        """
        if directory is None:
            directory = cfg['CFG_TMPSHAREDDIR']
        tmp_fd, filename = tempfile.mkstemp(dir=directory,
                                            prefix=prefix,
                                            suffix=suffix)
        os.write(tmp_fd, self.get_data())
        os.close(tmp_fd)
        return filename

    def get_log(self, *criteria, **filters):
        """Return a list of log entries from BibWorkflowObjectLog.

        You can specify additional filters following the SQLAlchemy syntax.

        Get all the logs for the object:

        .. code-block:: python

            b = BibWorkflowObject.query.get(1)
            b.get_log()

        Get all the logs for the object labeled as ERROR.

        .. code-block:: python

            b = BibWorkflowObject.query.get(1)
            b.get_log(BibWorkflowObjectLog.log_type == logging.ERROR)

        :return: list of BibWorkflowObjectLog
        """
        criterions = [BibWorkflowObjectLog.id_object == self.id] + \
            list(criteria)
        res = BibWorkflowObjectLog.query.filter(*criterions).filter_by(
            **filters)
        return res.all()

    def __getstate__(self):
        """Return internal dict."""
        return self.__dict__

    def __setstate__(self, state):
        """Update interal dict with given state."""
        self.__dict__ = state

    def copy(self, other):
        """Copy data and metadata except id and id_workflow."""
        self._data = other._data
        self._extra_data = other._extra_data
        self.version = other.version
        self.id_parent = other.id_parent
        self.created = other.created
        self.modified = other.modified
        self.status = other.status
        self.data_type = other.data_type
        self.uri = other.uri

    @session_manager
    def save(self, version=None, task_counter=None, id_workflow=None):
        """Save object to persistent storage."""
        if task_counter is not None:
            if isinstance(task_counter, list):
                self.log.debug("Saving task counter: %s" % (task_counter, ))
                extra_data = self.get_extra_data()
                extra_data["_task_counter"] = task_counter
                self.set_extra_data(extra_data)
            else:
                raise ValueError("Task counter must be a list!")

        if version is not None:
            if version != self.version:
                self.modified = datetime.now()
            self.version = version
        if id_workflow is not None:
            self.id_workflow = id_workflow
        db.session.add(self)
        if self.id is not None:
            self.log.debug("Saving object: %s" % (self.id or "new", ))
        workflow_object_saved.send(self)

    @classmethod
    def get(cls, *criteria, **filters):
        """Wrapper of SQLAlchemy to get a BibWorkflowObject.

        A wrapper for the filter and filter_by functions of SQLAlchemy.
        Define a dict with which columns should be filtered by which values.

        .. code-block:: python

            Workflow.get(uuid=uuid)
            Workflow.get(Workflow.uuid != uuid)

        The function supports also "hybrid" arguments.

        .. code-block:: python

            Workflow.get(Workflow.module_name != 'i_hate_this_module',
                         user_id=user_id)

        See also SQLAlchemy BaseQuery's filter and filter_by documentation.
        """
        return cls.query.filter(*criteria).filter_by(**filters)

    @classmethod
    @session_manager
    def delete(cls, oid):
        """Delete a BibWorkflowObject."""
        if isinstance(oid, BibWorkflowObject):
            db.session.delete(oid)
        else:
            db.session.delete(
                BibWorkflowObject.get(BibWorkflowObject.id == oid).first())

    @classmethod
    @session_manager
    def create_object(cls, **kwargs):
        """Create a new Workflow Object with given content."""
        obj = BibWorkflowObject(**kwargs)
        db.session.add(obj)
        return obj

    @classmethod
    @session_manager
    def create_object_revision(cls, old_obj, version, **kwargs):
        """Create a Workflow Object copy with customized values."""
        # Create new object and copy it
        obj = BibWorkflowObject(**kwargs)
        obj.copy(old_obj)

        # Overwrite some changes

        obj.version = version
        obj.created = datetime.now()
        obj.modified = datetime.now()
        for key, value in iteritems(kwargs):
            setattr(obj, key, value)
        db.session.add(obj)
        return obj
Пример #20
0
class WtgTAG(db.Model, Serializable):
    """A Tag."""

    __tablename__ = 'wtgTAG'
    __public__ = set(['id', 'name', 'id_owner'])

    #
    # Access Rights
    #
    ACCESS_NAMES = {
        0: 'Nothing',
        10: 'View',
        20: 'Add',
        30: 'Add and remove',
        40: 'Manage',
    }

    ACCESS_LEVELS = \
        dict((v, k) for (k, v) in iteritems(ACCESS_NAMES))

    ACCESS_RIGHTS = {
        0: [],
        10: ['view'],
        20: ['view', 'add'],
        30: ['view', 'add', 'remove'],
        40: ['view', 'add', 'remove', 'edit'],
    }

    ACCESS_OWNER_DEFAULT = ACCESS_LEVELS['Manage']
    ACCESS_GROUP_DEFAULT = ACCESS_LEVELS['View']

    # Primary key
    id = db.Column(db.Integer(15, unsigned=True),
                   primary_key=True,
                   nullable=False,
                   autoincrement=True)

    # Name
    name = db.Column(db.String(255),
                     nullable=False,
                     server_default='',
                     index=True)

    # Owner
    id_user = db.Column(db.Integer(15, unsigned=True),
                        db.ForeignKey(User.id),
                        server_default='0')

    # Access rights of owner
    user_access_rights = db.Column(db.Integer(2, unsigned=True),
                                   nullable=False,
                                   default=ACCESS_OWNER_DEFAULT)

    # Group
    # equal to 0 for private tags
    id_usergroup = db.Column(db.Integer(15, unsigned=True),
                             db.ForeignKey(Usergroup.id),
                             server_default='0')

    # Group access rights
    group_access_rights = db.Column(db.Integer(2, unsigned=True),
                                    nullable=False,
                                    default=ACCESS_GROUP_DEFAULT)

    # Access rights of everyone
    public_access_rights = db.Column(db.Integer(2, unsigned=True),
                                     nullable=False,
                                     default=ACCESS_LEVELS['Nothing'])

    # Visibility in document description
    show_in_description = db.Column(db.Boolean, nullable=False, default=True)

    # Relationships
    user = db.relationship(User, backref=db.backref('tags', cascade='all'))

    user_query = db.relationship(User,
                                 backref=db.backref('tags_query',
                                                    cascade='all',
                                                    lazy='dynamic'))

    usergroup = db.relationship(Usergroup,
                                backref=db.backref('tags', cascade='all'))

    # association proxy of "user_keywords" collection
    # to "keyword" attribute
    records = association_proxy('records_association', 'bibrec')

    # Calculated fields
    @db.hybrid_property
    def record_count(self):
        """TODO."""
        return self.records_association_query.count()

    @record_count.expression
    def record_count(cls):
        """TODO."""
        return db.select([db.func.count(WtgTAGRecord.id_bibrec)]) \
                 .where(WtgTAGRecord.id_tag == cls.id) \
                 .label('record_count')

    @db.validates('user_access_rights')
    @db.validates('group_access_rights')
    @db.validates('public_access_rights')
    def validate_user_access_rights(self, key, value):
        """Check if the value is among defined levels."""
        assert value in WtgTAG.ACCESS_NAMES
        return value
Пример #21
0
class Client(db.Model):

    """A client is the app which want to use the resource of a user.

    It is suggested that the client is registered by a user on your site, but
    it is not required.

    The client should contain at least these information:

        client_id: A random string
        client_secret: A random string
        client_type: A string represents if it is confidential
        redirect_uris: A list of redirect uris
        default_redirect_uri: One of the redirect uris
        default_scopes: Default scopes of the client

    But it could be better, if you implemented:

        allowed_grant_types: A list of grant types
        allowed_response_types: A list of response types
        validate_scopes: A function to validate scopes
    """

    __tablename__ = 'oauth2CLIENT'

    name = db.Column(
        db.String(40),
        info=dict(
            label=_('Name'),
            description=_('Name of application (displayed to users).'),
            validators=[validators.DataRequired()]
        )
    )
    """Human readable name of the application."""

    description = db.Column(
        db.Text(),
        default=u'',
        info=dict(
            label=_('Description'),
            description=_('Optional. Description of the application'
                          ' (displayed to users).'),
        )
    )
    """Human readable description."""

    website = db.Column(
        URLType(),
        info=dict(
            label=_('Website URL'),
            description=_('URL of your application (displayed to users).'),
        ),
        default=u'',
    )

    user_id = db.Column(db.ForeignKey('user.id'), nullable=True)
    """Creator of the client application."""

    client_id = db.Column(db.String(255), primary_key=True)
    """Client application ID."""

    client_secret = db.Column(
        db.String(255), unique=True, index=True, nullable=False
    )
    """Client application secret."""

    is_confidential = db.Column(db.Boolean, default=True)
    """Determine if client application is public or not."""

    is_internal = db.Column(db.Boolean, default=False)
    """Determins if client application is an internal application."""

    _redirect_uris = db.Column(db.Text)
    """A newline-separated list of redirect URIs. First is the default URI."""

    _default_scopes = db.Column(db.Text)
    """A space-separated list of default scopes of the client.

    The value of the scope parameter is expressed as a list of space-delimited,
    case-sensitive strings.
    """

    user = db.relationship(
        User,
        backref=db.backref(
            "oauth2clients",
            cascade="all, delete-orphan",
        )
    )
    """Relationship to user."""

    @property
    def allowed_grant_types(self):
        """Return allowed grant types."""
        return current_app.config['OAUTH2_ALLOWED_GRANT_TYPES']

    @property
    def allowed_response_types(self):
        """Return allowed response types."""
        return current_app.config['OAUTH2_ALLOWED_RESPONSE_TYPES']

    # def validate_scopes(self, scopes):
    #     return self._validate_scopes

    @property
    def client_type(self):
        """Return client type."""
        if self.is_confidential:
            return 'confidential'
        return 'public'

    @property
    def redirect_uris(self):
        """Return redirect uris."""
        if self._redirect_uris:
            return self._redirect_uris.splitlines()
        return []

    @redirect_uris.setter
    def redirect_uris(self, value):
        """Validate and store redirect URIs for client."""
        if isinstance(value, six.text_type):
            value = value.split("\n")

        value = [v.strip() for v in value]

        for v in value:
            validate_redirect_uri(v)

        self._redirect_uris = "\n".join(value) or ""

    @property
    def default_redirect_uri(self):
        """Return default redirect uri."""
        try:
            return self.redirect_uris[0]
        except IndexError:
            pass

    @property
    def default_scopes(self):
        """List of default scopes for client."""
        if self._default_scopes:
            return self._default_scopes.split(" ")
        return []

    @default_scopes.setter
    def default_scopes(self, scopes):
        """Set default scopes for client."""
        validate_scopes(scopes)
        self._default_scopes = " ".join(set(scopes)) if scopes else ""

    def validate_scopes(self, scopes):
        """Validate if client is allowed to access scopes."""
        try:
            validate_scopes(scopes)
            return True
        except ScopeDoesNotExists:
            return False

    def gen_salt(self):
        """Generate salt."""
        self.reset_client_id()
        self.reset_client_secret()

    def reset_client_id(self):
        """Reset client id."""
        self.client_id = gen_salt(
            current_app.config.get('OAUTH2_CLIENT_ID_SALT_LEN')
        )

    def reset_client_secret(self):
        """Reset client secret."""
        self.client_secret = gen_salt(
            current_app.config.get('OAUTH2_CLIENT_SECRET_SALT_LEN')
        )
Пример #22
0
class Author(db.Model):
    """Model representing an author entity.

    Each author may be associated to an Invenio author bibrec (record),
    an Invenio user and may have publications. Moreover,
    an author may have fellow coauthors and citations (based on his
    publications).
    """

    __tablename__ = 'authors_author'

    # When deleting a number of signatures, it should not be expected
    # by the mapper that the same number of authors should be deleted,
    # as many signatures can be associated with a publication. This
    # disables the default behaviour of the mapper to show a warning.
    __mapper_args__ = {'confirm_deleted_rows': False}

    id = db.Column(db.Integer(15, unsigned=True),
                   primary_key=True,
                   autoincrement=True,
                   nullable=False)
    """Id of the author (required)."""

    id_bibrec = db.Column(db.MediumInteger(8, unsigned=True),
                          db.ForeignKey(Record.id))
    """Id of the associated Invenio author bibrec."""

    id_user = db.Column(db.Integer(15, unsigned=True), db.ForeignKey(User.id))
    """Id of the associated Invenio user."""

    user = db.relationship('User', backref=db.backref("author", uselist=False))
    """Invenio user associated with this author."""
    publications = db.relationship('Publication',
                                   secondary='authors_signature',
                                   secondaryjoin="""and_(
                                    Signature.id_publication == Publication.id,
                                    Signature.attribution.in_(
                                     ('unknown', 'verified')))""")
    """Publications of the author."""
    @property
    def record(self):
        """Get the Invenio author record in JSON format.

        :return: an instance of an author record in JSON format
        """
        return get_record(self.id_bibrec)

    @property
    def coauthors(self):
        """Get the the authors co-writing this author's publications.

        :return: Author objects
        """
        return (coauthor for publication in self.publications
                for coauthor in publication.authors if coauthor != self)

    @property
    def citations(self):
        """Get the citations of this author's publications.

        :return: Publication objects
        """
        return (citation for publication in self.publications
                for citation in publication.citations)

    def __repr__(self):
        """Return a printable representation of an Author."""
        return 'Author(id=%s)' % self.id

    @utils.session_manager
    def delete(self):
        """Delete an author and modify the associated signatures.

        When deleting an author, the author field in the associated
        signatures should be set to None.

        Note: This is the mandatory way to delete a publication when
        using database engines that do not support 'ON DELETE' clauses
        (e.g. MyISAM of MySQL).
        """
        for s in Signature.query.filter(Signature.author == self).all():
            s.author = None
            db.session.add(s)
        db.session.commit()

        db.session.delete(self)