Esempio n. 1
0
class FileInstance(db.Model, Timestamp):
    """Model for storing files.

    A file instance represents a file on disk. A file instance may be linked
    from many objects, while an object can have one and only one file instance.

    A file instance also records the storage class, size and checksum of the
    file on disk.

    Additionally, a file instance can be read only in case the storage layer
    is not capable of writing to the file (e.g. can typically be used to
    link to files on externally controlled storage).
    """

    __tablename__ = 'files_files'

    id = db.Column(
        UUIDType,
        primary_key=True,
        default=uuid.uuid4,
    )
    """Identifier of file."""

    uri = db.Column(db.Text().with_variant(mysql.VARCHAR(255), 'mysql'),
                    unique=True,
                    nullable=True)
    """Location of file."""

    storage_class = db.Column(db.String(1), nullable=True)
    """Storage class of file."""

    size = db.Column(db.BigInteger, default=0, nullable=True)
    """Size of file."""

    checksum = db.Column(db.String(255), nullable=True)
    """String representing the checksum of the object."""

    readable = db.Column(db.Boolean(name='readable'),
                         default=True,
                         nullable=False)
    """Defines if the file is read only."""

    writable = db.Column(db.Boolean(name='writable'),
                         default=True,
                         nullable=False)
    """Defines if file is writable.

    This property is used to create a file instance prior to having the actual
    file at the given URI. This is useful when e.g. copying a file instance.
    """

    last_check_at = db.Column(db.DateTime, nullable=True)
    """Timestamp of last fixity check."""

    last_check = db.Column(db.Boolean(name='last_check'), default=True)
    """Result of last fixity check."""
    @validates('uri')
    def validate_uri(self, key, uri):
        """Validate uri."""
        if len(uri) > current_app.config['FILES_REST_FILE_URI_MAX_LEN']:
            raise ValueError('FileInstance URI too long ({0}).'.format(
                len(uri)))
        return uri

    @classmethod
    def get(cls, file_id):
        """Get a file instance."""
        return cls.query.filter_by(id=file_id).one_or_none()

    @classmethod
    def get_by_uri(cls, uri):
        """Get a file instance by URI."""
        assert uri is not None
        return cls.query.filter_by(uri=uri).one_or_none()

    @classmethod
    def create(cls):
        """Create a file instance.

        Note, object is only added to the database session.
        """
        obj = cls(
            id=uuid.uuid4(),
            writable=True,
            readable=False,
            size=0,
        )
        db.session.add(obj)
        return obj

    def delete(self):
        """Delete a file instance.

        The file instance can be deleted if it has no references from other
        objects. The caller is responsible to test if the file instance is
        writable and that the disk file can actually be removed.

        .. note::

           Normally you should use the Celery task to delete a file instance,
           as this method will not remove the file on disk.
        """
        self.query.filter_by(id=self.id).delete()
        return self

    def storage(self, **kwargs):
        """Get storage interface for object.

        Uses the applications storage factory to create a storage interface
        that can be used for this particular file instance.

        :returns: Storage interface.
        """
        return current_files_rest.storage_factory(fileinstance=self, **kwargs)

    @ensure_readable()
    def update_checksum(self,
                        progress_callback=None,
                        chunk_size=None,
                        checksum_kwargs=None,
                        **kwargs):
        """Update checksum based on file."""
        self.checksum = self.storage(**kwargs).checksum(
            progress_callback=progress_callback,
            chunk_size=chunk_size,
            **(checksum_kwargs or {}))

    def clear_last_check(self):
        """Clear the checksum of the file."""
        with db.session.begin_nested():
            self.last_check = None
            self.last_check_at = datetime.utcnow()
        return self

    def verify_checksum(self,
                        progress_callback=None,
                        chunk_size=None,
                        throws=True,
                        checksum_kwargs=None,
                        **kwargs):
        """Verify checksum of file instance.

        :param bool throws: If `True`, exceptions raised during checksum
            calculation will be re-raised after logging. If set to `False`, and
            an exception occurs, the `last_check` field is set to `None`
            (`last_check_at` of course is updated), since no check actually was
            performed.
        :param dict checksum_kwargs: Passed as `**kwargs`` to
            ``storage().checksum``.
        """
        try:
            real_checksum = self.storage(**kwargs).checksum(
                progress_callback=progress_callback,
                chunk_size=chunk_size,
                **(checksum_kwargs or {}))
        except Exception as exc:
            current_app.logger.exception(str(exc))
            if throws:
                raise
            real_checksum = None
        with db.session.begin_nested():
            self.last_check = (None if real_checksum is None else
                               (self.checksum == real_checksum))
            self.last_check_at = datetime.utcnow()
        return self.last_check

    @ensure_writable()
    def init_contents(self, size=0, **kwargs):
        """Initialize file."""
        self.set_uri(*self.storage(**kwargs).initialize(size=size),
                     readable=False,
                     writable=True)

    @ensure_writable()
    def update_contents(self,
                        stream,
                        seek=0,
                        size=None,
                        chunk_size=None,
                        progress_callback=None,
                        **kwargs):
        """Save contents of stream to this file.

        :param obj: ObjectVersion instance from where this file is accessed
            from.
        :param stream: File-like stream.
        """
        self.checksum = None
        return self.storage(**kwargs).update(
            stream,
            seek=seek,
            size=size,
            chunk_size=chunk_size,
            progress_callback=progress_callback)

    @ensure_writable()
    def set_contents(self,
                     stream,
                     chunk_size=None,
                     size=None,
                     size_limit=None,
                     progress_callback=None,
                     **kwargs):
        """Save contents of stream to this file.

        :param obj: ObjectVersion instance from where this file is accessed
            from.
        :param stream: File-like stream.
        """
        self.set_uri(*self.storage(
            **kwargs).save(stream,
                           chunk_size=chunk_size,
                           size=size,
                           size_limit=size_limit,
                           progress_callback=progress_callback))

    @ensure_writable()
    def copy_contents(self,
                      fileinstance,
                      progress_callback=None,
                      chunk_size=None,
                      **kwargs):
        """Copy this file instance into another file instance."""
        if not fileinstance.readable:
            raise ValueError('Source file instance is not readable.')
        if not self.size == 0:
            raise ValueError('File instance has data.')

        self.set_uri(*self.storage(
            **kwargs).copy(fileinstance.storage(**kwargs),
                           chunk_size=chunk_size,
                           progress_callback=progress_callback))

    @ensure_readable()
    def send_file(self,
                  filename,
                  restricted=True,
                  mimetype=None,
                  trusted=False,
                  chunk_size=None,
                  as_attachment=False,
                  **kwargs):
        """Send file to client."""
        return self.storage(**kwargs).send_file(
            filename,
            mimetype=mimetype,
            restricted=restricted,
            checksum=self.checksum,
            trusted=trusted,
            chunk_size=chunk_size,
            as_attachment=as_attachment,
        )

    def set_uri(self,
                uri,
                size,
                checksum,
                readable=True,
                writable=False,
                storage_class=None):
        """Set a location of a file."""
        self.uri = uri
        self.size = size
        self.checksum = checksum
        self.writable = writable
        self.readable = readable
        self.storage_class = \
            current_app.config['FILES_REST_DEFAULT_STORAGE_CLASS'] \
            if storage_class is None else \
            storage_class
        return self
Esempio n. 2
0
class IndexStyle(db.Model, Timestamp):
    """Index style."""

    __tablename__ = 'index_style'

    id = db.Column(db.String(100), primary_key=True)
    """identifier for index style setting."""

    width = db.Column(db.Text, nullable=False, default='')
    """Index area width."""

    height = db.Column(db.Text, nullable=False, default='')
    """Index area height."""

    index_link_enabled = db.Column(db.Boolean(name='index_link_enabled'),
                                   nullable=False,
                                   default=False)

    @classmethod
    def create(cls, community_id, **data):
        """Create."""
        try:
            with db.session.begin_nested():
                obj = cls(id=community_id, **data)
                db.session.add(obj)
            db.session.commit()
            return obj
        except Exception as ex:
            current_app.logger.debug(ex)
            db.session.rollback()
        return

    @classmethod
    def get(cls, community_id):
        """Get a style."""
        return cls.query.filter_by(id=community_id).one_or_none()

    @classmethod
    def update(cls, community_id, **data):
        """
        Update the index detail info.

        :param index_id: Identifier of the index.
        :param detail: new index info for update.
        :return: Updated index info
        """
        try:
            with db.session.begin_nested():
                style = cls.get(community_id)
                if not style:
                    return

                for k, v in data.items():
                    if "width" in k or "height" in k:
                        setattr(style, k, v)
                db.session.merge(style)
            db.session.commit()
            return style
        except Exception as ex:
            current_app.logger.debug(ex)
            db.session.rollback()
        return
class Schema(db.Model):
    """Model defining analysis JSON schemas."""

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

    name = db.Column(db.String(128), unique=False, nullable=False)
    fullname = db.Column(db.String(128), unique=False, nullable=True)

    # version
    major = db.Column(db.Integer, unique=False, nullable=False, default=1)
    minor = db.Column(db.Integer, unique=False, nullable=False, default=0)
    patch = db.Column(db.Integer, unique=False, nullable=False, default=0)

    experiment = db.Column(db.String(128), unique=False, nullable=True)
    config = db.Column(json_type, default=lambda: dict(), nullable=False)

    deposit_schema = db.Column(json_type,
                               default=lambda: dict(),
                               nullable=True)

    deposit_options = db.Column(json_type,
                                default=lambda: dict(),
                                nullable=True)

    deposit_mapping = db.Column(json_type,
                                default=lambda: dict(),
                                nullable=True)

    record_schema = db.Column(json_type, default=lambda: dict(), nullable=True)

    record_options = db.Column(json_type,
                               default=lambda: dict(),
                               nullable=True)

    record_mapping = db.Column(json_type,
                               default=lambda: dict(),
                               nullable=True)

    use_deposit_as_record = db.Column(db.Boolean(create_constraint=False),
                                      unique=False,
                                      default=False)
    is_indexed = db.Column(db.Boolean(create_constraint=False),
                           unique=False,
                           default=False)

    created = db.Column(db.DateTime(), default=datetime.utcnow, nullable=False)
    updated = db.Column(db.DateTime(), default=datetime.utcnow, nullable=False)

    __tablename__ = 'schema'
    __table_args__ = (UniqueConstraint('name',
                                       'major',
                                       'minor',
                                       'patch',
                                       name='unique_schema_version'), )

    def __init__(self, *args, **kwargs):
        """Possible to set version from string."""
        version = kwargs.pop('version', None)
        if version:
            self.version = version

        super(Schema, self).__init__(*args, **kwargs)

    def __getattribute__(self, attr):
        """Map record attribute to deposit one,
        if use_deposit_as_record is ```True```."""

        if attr in SERVE_DEPOSIT_AS_RECORD_MAP.keys(
        ) and self.use_deposit_as_record:
            attr = SERVE_DEPOSIT_AS_RECORD_MAP.get(attr)

        return object.__getattribute__(self, attr)

    def __str__(self):
        """Stringify schema object."""
        return '{name}-v{version}'.format(name=self.name, version=self.version)

    @property
    def version(self):
        """Return stringified version."""
        return "{0}.{1}.{2}".format(self.major, self.minor, self.patch)

    @version.setter
    def version(self, string):
        """Set version."""
        matched = re.match(r"(\d+)\.(\d+)\.(\d+)", string)
        if matched is None:
            raise ValueError(
                'Version has to be passed as string <major>.<minor>.<patch>')

        self.major, self.minor, self.patch = matched.groups()

    @property
    def deposit_path(self):
        """Return deposit schema path."""
        prefix = current_app.config['SCHEMAS_DEPOSIT_PREFIX']
        path = urljoin(prefix, "{0}.json".format(self))
        return path

    @property
    def record_path(self):
        """Return record schema path."""
        prefix = current_app.config['SCHEMAS_RECORD_PREFIX']
        path = urljoin(prefix, "{0}.json".format(self))
        return path

    @property
    def deposit_index(self):
        """Get deposit index name."""
        path = urljoin(current_app.config['SCHEMAS_DEPOSIT_PREFIX'], str(self))
        return name_to_es_name(path)

    @property
    def record_index(self):
        """Get record index name."""
        path = urljoin(current_app.config['SCHEMAS_RECORD_PREFIX'], str(self))
        return name_to_es_name(path)

    @property
    def deposit_aliases(self):
        """Get ES deposits aliases."""
        name = name_to_es_name(self.name)
        return ['deposits', 'deposits-records', 'deposits-{}'.format(name)]

    @property
    def record_aliases(self):
        """Get ES records aliases."""
        name = name_to_es_name(self.name)
        return ['records', 'records-{}'.format(name)]

    @validates('name')
    def validate_name(self, key, name):
        """Validate if name is ES compatible."""
        if any(x in ES_FORBIDDEN for x in name):
            raise ValueError('Name cannot contain the following characters'
                             '[, ", *, \\, <, | , , , > , ?]')
        return name

    def serialize(self, resolve=False):
        """Serialize schema model."""
        serializer = resolved_schemas_serializer if resolve else schema_serializer  # noqa
        return serializer.dump(self).data

    def update(self, **kwargs):
        """Update schema instance."""
        for key, value in kwargs.items():
            setattr(self, key, value)

        return self

    def add_read_access_for_all_users(self):
        """Give read access to all authenticated users."""
        assert self.id

        db.session.add(
            ActionSystemRoles.allow(SchemaReadAction(self.id),
                                    role=authenticated_user))
        db.session.flush()

    def give_admin_access_for_user(self, user):
        """Give admin access for users."""
        assert self.id

        db.session.add(ActionUsers.allow(SchemaAdminAction(self.id),
                                         user=user))
        db.session.flush()

    @classmethod
    def get_latest(cls, name):
        """Get the latest version of schema with given name."""
        latest = cls.query \
            .filter_by(name=name) \
            .order_by(cls.major.desc(),
                      cls.minor.desc(),
                      cls.patch.desc()) \
            .first()

        if latest:
            return latest
        else:
            raise JSONSchemaNotFound(schema=name)

    @classmethod
    def get(cls, name, version):
        """Get schema by name and version."""
        matched = re.match(r"(\d+).(\d+).(\d+)", version)
        if matched is None:
            raise ValueError(
                'Version has to be passed as string <major>.<minor>.<patch>')

        major, minor, patch = matched.groups()

        try:
            schema = cls.query \
                .filter_by(name=name, major=major, minor=minor, patch=patch) \
                .one()

        except NoResultFound:
            raise JSONSchemaNotFound("{}-v{}".format(name, version))

        return schema
Esempio n. 4
0
class User(db.Model, Timestamp, UserMixin):
    """User data model."""

    __tablename__ = "accounts_user"

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

    email = db.Column(db.String(255), unique=True)
    """User email."""

    password = db.Column(db.String(255))
    """User password."""

    active = db.Column(db.Boolean(name='active'))
    """Flag to say if the user is active or not ."""

    confirmed_at = db.Column(db.DateTime)
    """When the user confirmed the email address."""

    roles = db.relationship('Role',
                            secondary=userrole,
                            backref=db.backref('users', lazy='dynamic'))
    """List of the user's roles."""

    # Enables SQLAlchemy version counter
    version_id = db.Column(db.Integer, nullable=False)
    """Used by SQLAlchemy for optimistic concurrency control."""

    __mapper_args__ = {"version_id_col": version_id}

    login_info = db.relationship("LoginInformation",
                                 back_populates="user",
                                 uselist=False,
                                 lazy="joined")

    def _get_login_info_attr(self, attr_name):
        if self.login_info is None:
            return None
        return getattr(self.login_info, attr_name)

    def _set_login_info_attr(self, attr_name, value):
        if self.login_info is None:
            self.login_info = LoginInformation()
        setattr(self.login_info, attr_name, value)

    @property
    def current_login_at(self):
        """When user logged into the current session."""
        return self._get_login_info_attr("current_login_at")

    @property
    def current_login_ip(self):
        """Current user IP address."""
        return self._get_login_info_attr("current_login_ip")

    @property
    def last_login_at(self):
        """When the user logged-in for the last time."""
        return self._get_login_info_attr("last_login_at")

    @property
    def last_login_ip(self):
        """Last user IP address."""
        return self._get_login_info_attr("last_login_ip")

    @property
    def login_count(self):
        """Count how many times the user logged in."""
        return self._get_login_info_attr("login_count")

    @current_login_at.setter
    def current_login_at(self, value):
        return self._set_login_info_attr("current_login_at", value)

    @current_login_ip.setter
    def current_login_ip(self, value):
        return self._set_login_info_attr("current_login_ip", value)

    @last_login_at.setter
    def last_login_at(self, value):
        return self._set_login_info_attr("last_login_at", value)

    @last_login_ip.setter
    def last_login_ip(self, value):
        return self._set_login_info_attr("last_login_ip", value)

    @login_count.setter
    def login_count(self, value):
        return self._set_login_info_attr("login_count", value)

    def __str__(self):
        """Representation."""
        return 'User <id={0.id}, email={0.email}>'.format(self)
Esempio n. 5
0
class ItemType(db.Model, Timestamp):
    """Represent an item type.

    The ItemType object contains a ``created`` and  a ``updated``
    properties that are automatically updated.
    """

    # Enables SQLAlchemy-Continuum versioning
    __versioned__ = {}

    __tablename__ = 'item_type'

    id = db.Column(db.Integer(), primary_key=True, autoincrement=True)
    """Identifier of item type."""

    name_id = db.Column(db.Integer(),
                        db.ForeignKey('item_type_name.id',
                                      name='fk_item_type_name_id'),
                        nullable=False)
    """Name identifier of item type."""

    item_type_name = db.relationship('ItemTypeName',
                                     backref=db.backref(
                                         'item_type',
                                         lazy='dynamic',
                                         order_by=desc('item_type.tag')))
    """Name information from ItemTypeName class."""

    harvesting_type = db.Column(db.Boolean(name='harvesting_type'),
                                nullable=False,
                                default=False)

    schema = db.Column(db.JSON().with_variant(
        postgresql.JSONB(none_as_null=True),
        'postgresql',
    ).with_variant(
        JSONType(),
        'sqlite',
    ).with_variant(
        JSONType(),
        'mysql',
    ),
                       default=lambda: dict(),
                       nullable=True)
    """Store schema in JSON format. When you create a new ``item type`` the
    ``schema`` field value should never be ``NULL``. Default value is an
    empty dict. ``NULL`` value means that the record metadata has been
    deleted. """

    form = db.Column(db.JSON().with_variant(
        postgresql.JSONB(none_as_null=True),
        'postgresql',
    ).with_variant(
        JSONType(),
        'sqlite',
    ).with_variant(
        JSONType(),
        'mysql',
    ),
                     default=lambda: dict(),
                     nullable=True)
    """Store schema form in JSON format.
    When you create a new ``item type`` the ``form`` field value should never
    be ``NULL``. Default value is an empty dict. ``NULL`` value means that the
    record metadata has been deleted.
    """

    render = db.Column(db.JSON().with_variant(
        postgresql.JSONB(none_as_null=True),
        'postgresql',
    ).with_variant(
        JSONType(),
        'sqlite',
    ).with_variant(
        JSONType(),
        'mysql',
    ),
                       default=lambda: dict(),
                       nullable=True)
    """Store page render information in JSON format. When you create a new
    ``item type`` the ``render`` field value should never be ``NULL``.
    Default value is an empty dict. ``NULL`` value means that the record
    metadata has been deleted. """

    tag = db.Column(db.Integer, nullable=False)
    """Tag of item type."""

    version_id = db.Column(db.Integer, nullable=False)
    """Used by SQLAlchemy for optimistic concurrency control."""

    edit_notes = db.relationship('ItemTypeEditHistory',
                                 order_by='ItemTypeEditHistory.created',
                                 backref='item_type')
    """Used to reference whole edit history."""

    is_deleted = db.Column(db.Boolean(name='deleted'),
                           nullable=False,
                           default=False)
    """Status of item type."""

    __mapper_args__ = {'version_id_col': version_id}

    @property
    def latest_edit_history(self):
        """Get latest edit note of self."""
        return self.edit_notes[-1].notes if self.edit_notes else {}
Esempio n. 6
0
File: models.py Progetto: mhaya/weko
class SessionLifetime(db.Model):
    """Session Lifetime model.

    Stores session life_time create_date for Session.
    """

    __tablename__ = 'session_lifetime'

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

    _lifetime = db.Column('lifetime', db.Integer, nullable=False, default=30)
    """ Session Life Time default units: minutes """

    create_date = db.Column(db.DateTime, default=datetime.now)

    is_delete = db.Column(db.Boolean(name='delete'),
                          default=False,
                          nullable=False)

    @hybrid_property
    def lifetime(self):
        """
        Get lifetime.

        :return: Lifetime.
        """
        return self._lifetime

    @lifetime.setter
    def lifetime(self, lifetime):
        """
        Set lifetime.

        :param lifetime:
        :return: Lifetime.
        """
        self._lifetime = lifetime

    def create(self, lifetime=None):
        """
        Save session lifetime.

        :param lifetime: default None
        :return:
        """
        try:
            with db.session.begin_nested():
                if lifetime:
                    self.lifetime = lifetime
                self.is_delete = False
                db.session.add(self)
            db.session.commit()
        except BaseException:
            db.session.rollback()
            raise
        return self

    @classmethod
    def get_validtime(cls):
        """Get valid lifetime.

        :returns: A :class:`~weko_admin.models.SessionLifetime` instance
            or ``None``.
        """
        return cls.query.filter_by(is_delete=False).one_or_none()

    @property
    def is_anonymous(self):
        """Return whether this UserProfile is anonymous."""
        return False
Esempio n. 7
0
File: models.py Progetto: mhaya/weko
class BillingPermission(db.Model):
    """Database for Billing Permission."""

    __tablename__ = 'billing_permission'

    user_id = db.Column(db.Integer(),
                        primary_key=True,
                        nullable=False,
                        unique=True)

    is_active = db.Column(db.Boolean(name='active'),
                          default=True,
                          nullable=False)

    @classmethod
    def create(cls, user_id, is_active=True):
        """Create new user can access billing file.

        :param user_id: user's id
        :param is_active: access state
        :return: Unit if create succesfully
        """
        try:
            obj = BillingPermission()
            with db.session.begin_nested():
                obj.user_id = user_id
                obj.is_active = is_active
                db.session.add(obj)
            db.session.commit()
        except BaseException as ex:
            db.session.rollback()
            current_app.logger.debug(ex)
            raise

        return cls

    @classmethod
    def activation(cls, user_id, is_active):
        """Change access state of user.

        :param user_id: user's id
        :param is_active: access state
        :return: Updated records
        """
        try:
            with db.session.begin_nested():
                billing_data = cls.query.filter_by(
                    user_id=user_id).one_or_none()
                if billing_data:
                    billing_data.is_active = is_active
                    db.session.merge(billing_data)
                else:
                    cls.create(user_id, is_active)
                    current_app.logger.info('New user is created!')
            db.session.commit()
        except BaseException as ex:
            db.session.rollback()
            current_app.logger.debug(ex)
            raise

        return cls

    @classmethod
    def get_billing_information_by_id(cls, user_id):
        """Get billing information by user id.

        :param user_id: user's id
        :return: Record or none
        """
        try:
            billing_information = cls.query.filter_by(
                user_id=user_id).one_or_none()
        except Exception as ex:
            current_app.logger.debug(ex)
            raise
        return billing_information
Esempio n. 8
0
class Group(db.Model):
    """Group data model."""

    __tablename__ = 'accounts_group'

    PRIVACY_POLICIES = [
        (PrivacyPolicy.PUBLIC, _('Public')),
        (PrivacyPolicy.MEMBERS, _('Group members')),
        (PrivacyPolicy.ADMINS, _('Group admins')),
    ]
    """Privacy policy choices."""

    SUBSCRIPTION_POLICIES = [
        (SubscriptionPolicy.OPEN, _('Open')),
        (SubscriptionPolicy.APPROVAL, _('Open with approval')),
        (SubscriptionPolicy.CLOSED, _('Closed')),
    ]
    """Subscription policy choices."""

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

    name = db.Column(db.String(255),
                     nullable=False,
                     unique=True,
                     index=True,
                     info=dict(
                         label=_('Name'),
                         description=_('Required. A name of a group.'),
                     ))
    """Name of group."""

    description = db.Column(
        db.Text,
        nullable=True,
        default='',
        info=dict(
            label=_('Description'),
            description=_('Optional. A short description of the group.'
                          ' Default: Empty'),
        ))
    """Description of group."""

    is_managed = db.Column(db.Boolean(name='managed'),
                           default=False,
                           nullable=False)
    """Determine if group is system managed."""

    privacy_policy = db.Column(ChoiceType(PRIVACY_POLICIES, impl=db.String(1)),
                               nullable=False,
                               default=PrivacyPolicy.MEMBERS,
                               info=dict(
                                   label=_('Privacy Policy'),
                                   widget=RadioGroupWidget(
                                       PrivacyPolicy.descriptions),
                               ))
    """Policy for who can view the list of group members."""

    subscription_policy = db.Column(ChoiceType(SUBSCRIPTION_POLICIES,
                                               impl=db.String(1)),
                                    nullable=False,
                                    default=SubscriptionPolicy.APPROVAL,
                                    info=dict(
                                        label=_('Subscription Policy'),
                                        widget=RadioGroupWidget(
                                            SubscriptionPolicy.descriptions),
                                    ))
    """Policy for how users can be subscribed to the group."""

    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."""
    def get_id(self):
        """Get group id.

        :returns: the group id
        """
        return self.id

    @classmethod
    def create(cls,
               name=None,
               description='',
               privacy_policy=None,
               subscription_policy=None,
               is_managed=False,
               admins=None):
        """Create a new group.

        :param is_managed:
        :param name: Name of group. Required and must be unique.
        :param description: Description of group. Default: ``''``
        :param privacy_policy: PrivacyPolicy
        :param subscription_policy: SubscriptionPolicy
        :param admins: list of user and/or group objects. Default: ``[]``
        :returns: Newly created group
        :raises: IntegrityError: if group with given name already exists
        """
        assert name
        assert privacy_policy is None or PrivacyPolicy.validate(privacy_policy)
        assert subscription_policy is None or SubscriptionPolicy \
            .validate(subscription_policy)
        assert admins is None or isinstance(admins, list)

        with db.session.begin_nested():
            obj = cls(
                name=name,
                description=description,
                privacy_policy=privacy_policy,
                subscription_policy=subscription_policy,
                is_managed=is_managed,
            )
            db.session.add(obj)

            for a in admins or []:
                db.session.add(
                    GroupAdmin(group=obj,
                               admin_id=a.get_id(),
                               admin_type=resolve_admin_type(a)))
        db.session.commit()

        return obj

    def delete(self):
        """Delete a group and all associated memberships."""
        with db.session.begin_nested():
            Membership.query_by_group(self).delete()
            GroupAdmin.query_by_group(self).delete()
            GroupAdmin.query_by_admin(self).delete()
            db.session.delete(self)
        db.session.commit()

    def update(self,
               name=None,
               description=None,
               privacy_policy=None,
               subscription_policy=None,
               is_managed=None):
        """Update group.

        :param is_managed:
        :param name: Name of group.
        :param description: Description of group.
        :param privacy_policy: PrivacyPolicy
        :param subscription_policy: SubscriptionPolicy
        :returns: Updated group
        """
        with db.session.begin_nested():
            if name is not None:
                self.name = name
            if description is not None:
                self.description = description
            if (privacy_policy is not None
                    and PrivacyPolicy.validate(privacy_policy)):
                self.privacy_policy = privacy_policy
            if (subscription_policy is not None
                    and SubscriptionPolicy.validate(subscription_policy)):
                self.subscription_policy = subscription_policy
            if is_managed is not None:
                self.is_managed = is_managed

            db.session.merge(self)
        db.session.commit()

        return self

    @classmethod
    def get_group_list(cls):
        """
        Get Group List.

        :return: Group list object.
        """
        grouplist = Group.query.all()
        obj = {}
        for k in grouplist:
            obj[str(k.id)] = k.name
        return obj

    @classmethod
    def get_by_name(cls, name):
        """Query group by a group name.

        :param name: Name of a group to search for.
        :returns: Group object or None.
        """
        try:
            return cls.query.filter_by(name=name).one()
        except NoResultFound:
            return None

    @classmethod
    def query_by_names(cls, names):
        """Query group by a list of group names.

        :param list names: List of the group names.
        :returns: Query object.
        """
        assert isinstance(names, list)
        return cls.query.filter(cls.name.in_(names))

    @classmethod
    def query_by_user(cls, user, with_pending=False, eager=False):
        """Query group by user.

        :param user: User object.
        :param bool with_pending: Whether to include pending users.
        :param bool eager: Eagerly fetch group members.
        :returns: Query object.
        """
        q1 = Group.query.join(Membership).filter_by(user_id=user.get_id())
        if not with_pending:
            q1 = q1.filter_by(state=MembershipState.ACTIVE)
        if eager:
            q1 = q1.options(joinedload(Group.members))

        q2 = Group.query.join(GroupAdmin).filter_by(
            admin_id=user.get_id(), admin_type=resolve_admin_type(user))
        if eager:
            q2 = q2.options(joinedload(Group.members))

        query = q1.union(q2).with_entities(Group.id)

        return Group.query.filter(Group.id.in_(query))

    @classmethod
    def search(cls, query, q):
        """Modify query as so include only specific group names.

        :param query: Query object.
        :param str q: Search string.
        :returns: Query object.
        """
        return query.filter(Group.name.like('%{0}%'.format(q)))

    def add_admin(self, admin):
        """Invite an admin to a group.

        :param admin: Object to be added as an admin.
        :returns: GroupAdmin object.
        """
        return GroupAdmin.create(self, admin)

    def remove_admin(self, admin):
        """Remove an admin from group (independent of membership state).

        :param admin: Admin to be removed from group.
        """
        return GroupAdmin.delete(self, admin)

    def add_member(self, user, state=MembershipState.ACTIVE):
        """Invite a user to a group.

        :param user: User to be added as a group member.
        :param state: MembershipState. Default: MembershipState.ACTIVE.
        :returns: Membership object or None.
        """
        return Membership.create(self, user, state)

    def remove_member(self, user):
        """Remove a user from a group (independent of their membership state).

        :param user: User to be removed from group members.
        """
        return Membership.delete(self, user)

    def invite(self, user, admin=None):
        """Invite a user to a group (should be done by admins).

        Wrapper around ``add_member()`` to ensure proper membership state.

        :param user: User to invite.
        :param admin: Admin doing the action. If provided, user is only invited
            if the object is an admin for this group. Default: None.
        :returns: Newly created Membership or None.
        """
        if admin is None or self.is_admin(admin):
            return self.add_member(user, state=MembershipState.PENDING_USER)
        return None

    def invite_by_emails(self, emails):
        """Invite users to a group by emails.

        :param list emails: Emails of users that shall be invited.
        :returns list: Newly created Memberships or Nones.
        """
        # assert emails is not None and isinstance(emails, list)

        results = []

        for email in emails:
            try:
                user = User.query.filter_by(email=email).one()
                results.append(self.invite(user))
            except NoResultFound:
                results.append(None)

        return results

    def subscribe(self, user):
        """Subscribe a user to a group (done by users).

        Wrapper around ``add_member()`` which checks subscription policy.

        :param user: User to subscribe.
        :returns: Newly created Membership or None.
        """
        if self.subscription_policy == SubscriptionPolicy.OPEN:
            return self.add_member(user)
        elif self.subscription_policy == SubscriptionPolicy.APPROVAL:
            return self.add_member(user, state=MembershipState.PENDING_ADMIN)
        elif self.subscription_policy == SubscriptionPolicy.CLOSED:
            return None

    def is_admin(self, admin):
        """Verify if given admin is the group admin.

        :param admin: Admin object.
        :returns: True or False.
        """
        if GroupAdmin.get(self, admin) is not None:
            return True
        return False

    def is_member(self, user, with_pending=False):
        """Verify if given user is a group member.

        :param user: User object.
        :param bool with_pending: Whether to include pending users or not.
        :returns: True or False.
        """
        m = Membership.get(self, user)
        if m is not None:
            if with_pending:
                return True
            elif m.state == MembershipState.ACTIVE:
                return True
        return False

    def can_see_members(self, user):
        """Determine if given user can see other group members.

        :param user: User object.
        :returns: True or False.
        """
        if self.privacy_policy == PrivacyPolicy.PUBLIC:
            return True
        elif self.privacy_policy == PrivacyPolicy.MEMBERS:
            return self.is_member(user) or self.is_admin(user)
        elif self.privacy_policy == PrivacyPolicy.ADMINS:
            return self.is_admin(user)

    def can_edit(self, user):
        """Determine if user can edit group data.

        :param user: User object.
        :returns: True or False.
        """
        if self.is_managed:
            return False
        else:
            return self.is_admin(user)

    def can_invite_others(self, user):
        """Determine if user can invite people to a group.

        Be aware that this check is independent from the people (users) which
        are going to be invited. The checked user is the one who invites
        someone, NOT who is going to be invited.

        :param user: User object.
        :returns: True or False.
        """
        if self.is_managed:
            return False
        elif self.is_admin(user):
            return True
        elif self.subscription_policy != SubscriptionPolicy.CLOSED:
            return True
        else:
            return False

    def can_leave(self, user):
        """Determine if user can leave a group.

        :param user: User object.
        :returns: True or False.
        """
        if self.is_managed:
            return False
        else:
            return self.is_member(user)

    def members_count(self):
        """Determine members count.

        :returns: Number of memberships.
        """
        return Membership.query_by_group(self.get_id()).count()
Esempio n. 9
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__ = 'oauth2server_client'

    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,
        ondelete='CASCADE',
    ),
                        nullable=True,
                        index=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(name='is_confidential'),
                                default=True)
    """Determine if client application is public or not."""

    is_internal = db.Column(db.Boolean(name='is_internal'), 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['OAUTH2SERVER_ALLOWED_GRANT_TYPES']

    @property
    def allowed_response_types(self):
        """Return allowed response types."""
        return current_app.config['OAUTH2SERVER_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('OAUTH2SERVER_CLIENT_ID_SALT_LEN'))

    def reset_client_secret(self):
        """Reset client secret."""
        self.client_secret = gen_salt(
            current_app.config.get('OAUTH2SERVER_CLIENT_SECRET_SALT_LEN'))

    @property
    def get_users(self):
        """Get number of users."""
        no_users = Token.query.filter_by(client_id=self.client_id,
                                         is_personal=False,
                                         is_internal=False).count()
        return no_users
Esempio n. 10
0
class OARepoCommunityModel(db.Model, Timestamp):
    __tablename__ = 'oarepo_communities'
    __table_args__ = {'extend_existing': True}
    __versioned__ = {'versioning': False}

    id = db.Column(
        db.String(63),
        primary_key=True,
    )
    """Primary Community identifier slug."""

    title = db.Column(db.String(128), )
    """Community title name."""

    type = db.Column(ChoiceType(choices=OAREPO_COMMUNITIES_TYPES,
                                impl=db.VARCHAR(16)),
                     default='other',
                     nullable=False)
    """Community type or focus."""

    json = db.Column(db.JSON().with_variant(
        postgresql.JSONB(none_as_null=True),
        'postgresql',
    ).with_variant(
        JSONType(),
        'sqlite',
    ).with_variant(
        JSONType(),
        'mysql',
    ),
                     default=lambda: dict(),
                     nullable=True)
    """Store community metadata in JSON format."""

    is_deleted = db.Column(
        db.Boolean(name="ck_oarepo_community_metadata_is_deleted"),
        nullable=True,
        default=False)
    """Was the OARepo community soft-deleted."""

    roles = db.relationship('Role',
                            secondary=oarepo_communities_role,
                            backref=db.backref('community', lazy='dynamic'))

    def delete_roles(self):
        """Delete roles associated with this community."""
        with db.session.begin_nested():
            for r in self.roles:
                db.session.delete(r)

    def delete(self):
        """Mark the community for deletion."""
        self.is_deleted = True
        self.delete_roles()

    def _validate_role_action(self, role, action, system=False):
        if action not in current_oarepo_communities.allowed_actions:
            raise AttributeError(f'Action {action} not allowed')
        if system:
            if role.value not in current_access.system_roles:
                raise AttributeError(f'Role {role} not in system roles')
        elif role not in self.roles:
            raise AttributeError(f'Role {role} not in community roles')

    def allow_action(self, role, action, system=False):
        """Allow action for a role."""
        self._validate_role_action(role, action, system)

        with db.session.begin_nested():
            if system:
                ar = ActionSystemRoles.query.filter_by(
                    action=action, argument=self.id,
                    role_name=role.value).first()
                if not ar:
                    ar = ActionSystemRoles(action=action,
                                           argument=self.id,
                                           role_name=role.value)
            else:
                ar = ActionRoles.query.filter_by(action=action,
                                                 argument=self.id,
                                                 role_id=role.id).first()
                if not ar:
                    ar = ActionRoles(action=action,
                                     argument=self.id,
                                     role=role)

            db.session.add(ar)
            return ar

    def deny_action(self, role, action, system=False):
        """Deny action for a role."""
        self._validate_role_action(role, action, system)

        with db.session.begin_nested():
            if system:
                ar = ActionSystemRoles.query.filter_by(
                    action=action, argument=self.id,
                    role_name=role.value).all()
            else:
                ar = ActionRoles.query.filter_by(action=action,
                                                 argument=self.id,
                                                 role=role).all()
            for a in ar:
                db.session.delete(a)

    @property
    def actions(self):
        ars = ActionRoles.query \
            .filter_by(argument=self.id) \
            .order_by(ActionRoles.action).all()
        sars = ActionSystemRoles.query \
            .filter_by(argument=self.id) \
            .order_by(ActionSystemRoles.action).all()
        ars = [{k: list(g)} for k, g in groupby(ars, key=attrgetter('action'))]
        sars = [{
            k: list(g)
        } for k, g in groupby(sars, key=attrgetter('action'))]

        return ars, sars

    @property
    def excluded_facets(self):
        return self.json.get('excluded_facets', {})

    def to_json(self):
        return dict(id=self.id,
                    title=self.title,
                    type=str(self.type),
                    metadata=self.json)
Esempio n. 11
0
class User(db.Model, Timestamp, UserMixin):
    """User data model."""

    __tablename__ = "accounts_user"

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

    _username = db.Column("username",
                          db.String(255),
                          nullable=True,
                          unique=True)
    """Lower-case version of the username, to assert uniqueness."""

    _displayname = db.Column("displayname", db.String(255), nullable=True)
    """Case-preserving version of the username."""

    email = db.Column(db.String(255), unique=True)
    """User email."""

    password = db.Column(db.String(255))
    """User password."""

    active = db.Column(db.Boolean(name="active"))
    """Flag to say if the user is active or not ."""

    confirmed_at = db.Column(db.DateTime)
    """When the user confirmed the email address."""

    roles = db.relationship("Role",
                            secondary=userrole,
                            backref=db.backref("users", lazy="dynamic"))
    """List of the user's roles."""

    # Enables SQLAlchemy version counter
    version_id = db.Column(db.Integer, nullable=False)
    """Used by SQLAlchemy for optimistic concurrency control."""

    _user_profile = db.Column(
        "profile",
        json_field,
        default=lambda: dict(),
        nullable=True,
    )
    """The user profile as a JSON field."""

    _preferences = db.Column(
        "preferences",
        json_field,
        default=lambda: dict(),
        nullable=True,
    )
    """The user's preferences stored in a JSON field."""

    __mapper_args__ = {"version_id_col": version_id}

    login_info = db.relationship("LoginInformation",
                                 back_populates="user",
                                 uselist=False,
                                 lazy="joined")

    def __init__(self, *args, **kwargs):
        """Constructor."""
        user_profile = kwargs.pop("user_profile", {})
        preferences = kwargs.pop("preferences", {})
        preferences.setdefault("visibility", "restricted")
        preferences.setdefault("email_visibility", "restricted")
        super().__init__(*args, **kwargs)
        self.user_profile = user_profile
        self.preferences = preferences

    @hybrid_property
    def username(self):
        """Get username."""
        return self._displayname

    @username.setter
    def username(self, username):
        """Set username.

        .. note:: The username will be converted to lowercase.
                  The display name will contain the original version.
        """
        if username is None:
            # if the username can't be validated, a ValueError will be raised
            self._displayname = None
            self._username = None
        else:
            validate_username(username)
            self._displayname = username
            self._username = username.lower()

    @hybrid_property
    def user_profile(self):
        """Get the user profile."""
        # NOTE: accessing this property requires an initialized app for config
        if self._user_profile is None:
            return None
        elif not isinstance(self._user_profile, UserProfileDict):
            return UserProfileDict(**self._user_profile)

        return self._user_profile

    @user_profile.setter
    def user_profile(self, value):
        """Set the user profile."""
        if value is None:
            self._user_profile = None
        else:
            self._user_profile = UserProfileDict(**value)

    @hybrid_property
    def preferences(self):
        """Get the user preferences."""
        # NOTE: accessing this property requires an initialized app for config
        if self._preferences is None:
            return None
        elif not isinstance(self._preferences, UserPreferenceDict):
            self._preferences = UserPreferenceDict(**self._preferences)

        return self._preferences

    @preferences.setter
    def preferences(self, value):
        """Set the user preferences."""
        if value is None:
            self._preferences = None
        else:
            self._preferences = UserPreferenceDict(**value)

    def _get_login_info_attr(self, attr_name):
        if self.login_info is None:
            return None
        return getattr(self.login_info, attr_name)

    def _set_login_info_attr(self, attr_name, value):
        if self.login_info is None:
            self.login_info = LoginInformation()
        setattr(self.login_info, attr_name, value)

    @property
    def current_login_at(self):
        """When user logged into the current session."""
        return self._get_login_info_attr("current_login_at")

    @property
    def current_login_ip(self):
        """Current user IP address."""
        return self._get_login_info_attr("current_login_ip")

    @property
    def last_login_at(self):
        """When the user logged-in for the last time."""
        return self._get_login_info_attr("last_login_at")

    @property
    def last_login_ip(self):
        """Last user IP address."""
        return self._get_login_info_attr("last_login_ip")

    @property
    def login_count(self):
        """Count how many times the user logged in."""
        return self._get_login_info_attr("login_count")

    @current_login_at.setter
    def current_login_at(self, value):
        return self._set_login_info_attr("current_login_at", value)

    @current_login_ip.setter
    def current_login_ip(self, value):
        return self._set_login_info_attr("current_login_ip", value)

    @last_login_at.setter
    def last_login_at(self, value):
        return self._set_login_info_attr("last_login_at", value)

    @last_login_ip.setter
    def last_login_ip(self, value):
        return self._set_login_info_attr("last_login_ip", value)

    @login_count.setter
    def login_count(self, value):
        return self._set_login_info_attr("login_count", value)

    def __str__(self):
        """Representation."""
        return "User <id={0.id}, email={0.email}>".format(self)
Esempio n. 12
0
class WidgetItem(db.Model):
    """Database for WidgetItem."""

    __tablename__ = 'widget_items'

    widget_id = db.Column(db.Integer, primary_key=True, nullable=False)
    repository_id = db.Column(db.String(100), nullable=False)
    widget_type = db.Column(db.String(100), nullable=False)
    settings = db.Column(db.JSON().with_variant(
        postgresql.JSONB(none_as_null=True),
        'postgresql',
    ).with_variant(
        JSONType(),
        'sqlite',
    ).with_variant(
        JSONType(),
        'mysql',
    ),
                         default=lambda: dict(),
                         nullable=True)
    is_enabled = db.Column(db.Boolean(name='enable'), default=True)
    is_deleted = db.Column(db.Boolean(name='deleted'), default=False)

    #
    # Query Operation
    #
    @classmethod
    def get_by_id(cls, widget_item_id):
        """Get a widget item by id."""
        widget = cls.query.filter_by(widget_id=widget_item_id).one_or_none()
        return widget

    @classmethod
    def get_id_by_repository_and_type(cls, repository, widget_type):
        """Get id by repository id and widget type.

        :param repository: Repository id
        :param widget_type: Widget type
        :return:Widget Item
        """
        widget_data = cls.query.filter_by(repository_id=repository,
                                          widget_type=widget_type,
                                          is_deleted=False).all()
        if not widget_data:
            return None

        list_id = list()
        for data in widget_data:
            list_id.append(data.widget_id)
        return list_id

    @classmethod
    def get_sequence(cls, session):
        """Get widget item next sequence.

        :param session: Session
        :return: Next sequence.
        """
        if not session:
            session = db.session
        seq = Sequence('widget_items_widget_id_seq')
        next_id = session.execute(seq)
        return next_id

    @classmethod
    def create(cls, widget_data, session):
        """Create widget item.

        :param widget_data: widget data
        :param session: session
        :return:
        """
        if not session:
            return None
        data = cls(**widget_data)
        session.add(data)

    @classmethod
    def update_by_id(cls, widget_item_id, widget_data, session=None):
        """Update the widget by id.

        Arguments:
            widget_item_id {Integer} -- Id of widget
            widget_data {Dictionary} -- data

        Returns:
            widget -- if success

        """
        if not session:
            session = db.session
        widget = cls.get_by_id(widget_item_id)
        if not widget:
            return
        for k, v in widget_data.items():
            setattr(widget, k, v)
        session.merge(widget)
        return widget

    @classmethod
    def update_setting_by_id(cls, widget_id, settings):
        """Update widget setting by widget id.

        :param widget_id:
        :param settings:
        :return: True if update successful
        """
        try:
            widget_item = cls.get_by_id(widget_id)
            with db.session.begin_nested():
                widget_item.settings = settings
                db.session.merge(widget_item)
            db.session.commit()
            return True
        except Exception as ex:
            db.session.rollback()
            current_app.logger.debug(ex)
            return False

    @classmethod
    def delete_by_id(cls, widget_id, session):
        """Delete the widget by id.

        Arguments:
            widget_id {Integer} -- The widget id

        Returns:
            widget -- If success

        """
        widget = cls.get_by_id(widget_id)
        if not widget:
            return
        setattr(widget, 'is_deleted', True)
        session.merge(widget)
        return widget
Esempio n. 13
0
class WidgetDesignPage(db.Model):
    """Database for menu pages."""

    __tablename__ = 'widget_design_page'

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

    title = db.Column(db.String(100), nullable=True)

    repository_id = db.Column(db.String(100), nullable=False)

    url = db.Column(db.String(100), nullable=False, unique=True)

    template_name = db.Column(  # May be used in the future
        db.String(100), nullable=True)

    content = db.Column(db.Text(), nullable=True, default='')

    settings = db.Column(db.JSON().with_variant(
        postgresql.JSONB(none_as_null=True),
        'postgresql',
    ).with_variant(
        JSONType(),
        'sqlite',
    ).with_variant(
        JSONType(),
        'mysql',
    ),
                         default=lambda: dict(),
                         nullable=True)

    is_main_layout = db.Column(db.Boolean('is_main_layout'), nullable=True)

    multi_lang_data = db.relationship(
        'WidgetDesignPageMultiLangData',
        backref='widget_design_page',
        cascade='all, delete-orphan',
        collection_class=attribute_mapped_collection('lang_code'))

    @classmethod
    def create_or_update(cls,
                         repository_id,
                         title,
                         url,
                         content,
                         page_id=0,
                         settings=None,
                         multi_lang_data={},
                         is_main_layout=False):
        """Insert new widget design page.

        :param repository_id: Identifier of the repository
        :param title: Page title
        :param url: Page URL
        :param content: HTML content
        :param page_id: Page identifier
        :param settings: Page widget setting data
        :param multi_lang_data: Multi language data
        :param is_main_layout: Main layout flash
        :return: True if successful, otherwise False
        """
        try:
            prev = cls.query.filter_by(id=int(page_id)).one_or_none()
            if prev:
                repository_id = prev.repository_id
            page = prev or WidgetDesignPage()

            if not repository_id or not url:
                return False

            with db.session.begin_nested():
                page.repository_id = repository_id
                page.title = title
                page.url = url
                page.content = content
                page.settings = settings
                page.is_main_layout = is_main_layout
                for lang in multi_lang_data:
                    page.multi_lang_data[lang] = \
                        WidgetDesignPageMultiLangData(
                            lang, multi_lang_data[lang])
                db.session.merge(page)
            db.session.commit()
            return True
        except Exception as ex:
            db.session.rollback()
            current_app.logger.debug(ex)
            raise ex

    @classmethod
    def delete(cls, page_id):
        """Delete widget design page.

        :param page_id: Page model's id
        :return: True if successful or False
        """
        if page_id:
            try:
                with db.session.begin_nested():
                    cls.query.filter_by(id=int(page_id)).delete()
                db.session.commit()
                return True
            except BaseException as ex:
                db.session.rollback()
                current_app.logger.debug(ex)
                raise ex
        return False

    @classmethod
    def update_settings(cls, page_id, settings=None):
        """Update design page setting.

        :param page_id: Identifier of the page.
        :param settings: Page widget setting data.
        :return: True if successful, otherwise False.
        """
        try:
            page = cls.query.filter_by(id=int(page_id)).one_or_none()
            if page:
                with db.session.begin_nested():
                    page.settings = settings
                    db.session.merge(page)
                db.session.commit()
                return True
        except Exception as ex:
            db.session.rollback()
            current_app.logger.debug(ex)
            raise ex
        return False

    @classmethod
    def update_settings_by_repository_id(cls, repository_id, settings=None):
        """Update design page setting by repository id.

        Note: ALL pages belonging to repository will have the same settings.
        Could be used to make all pages uniform in design.
        :param repository_id: Repository id.
        :param settings: Page widget setting data.
        :return: True if successful, otherwise False.
        """
        try:
            pages = cls.query.filter_by(repository_id=int(repository_id)).all()
            for page in pages:
                with db.session.begin_nested():
                    page.settings = settings
                    db.session.merge(page)
                db.session.commit()
            return True
        except Exception as ex:
            db.session.rollback()
            current_app.logger.debug(ex)
            return False

    @classmethod
    def get_all(cls):
        """
        Get all pages.

        :return: List of all pages.
        """
        return db.session.query(cls).all()

    @classmethod
    def get_all_valid(cls):
        """
        Get all pages with widget settings.

        :return: List of all pages.
        """
        return db.session.query(cls).filter(cls.settings is not None).all()

    @classmethod
    def get_by_id(cls, id):
        """
        Get widget page by id.

        Raises error if not found etc.
        :return: Single page object or exception raised.
        """
        return db.session.query(cls).filter_by(id=int(id)).one()

    @classmethod
    def get_by_id_or_none(cls, id):
        """
        Get widget page by id without raising exception.

        :return: Single page object or none.
        """
        return db.session.query(cls).filter_by(id=int(id)).one_or_none()

    @classmethod
    def get_by_url(cls, url):
        """
        Get widget page by url.

        :return: Single page objects or none.
        """
        return db.session.query(cls).filter_by(url=url).one()

    @classmethod
    def get_by_repository_id(cls, repository_id):
        """
        Get widget pages for community/repo.

        :return: Multiple page objects or empty list.
        """
        return db.session.query(cls).filter_by(
            repository_id=repository_id).all()
Esempio n. 14
0
class ObjectVersion(db.Model, Timestamp):
    """Model for storing versions of objects.

    A bucket stores one or more objects identified by a key. Each object is
    versioned where each version is represented by an ``ObjectVersion``.

    An object version can either be 1) a *normal version* which is linked to
    a file instance, or 2) a *delete marker*, which is *not* linked to a file
    instance.

    An normal object version is linked to a physical file on disk via a file
    instance. This allows for multiple object versions to point to the same
    file on disk, to optimize storage efficiency (e.g. useful for snapshotting
    an entire bucket without duplicating the files).

    A delete marker object version represents that the object at hand was
    deleted.

    The latest version of an object is marked using the ``is_head`` property.
    If the latest object version is a delete marker the object will not be
    shown in the bucket.
    """

    __tablename__ = 'files_object'

    bucket_id = db.Column(
        UUIDType,
        db.ForeignKey(Bucket.id, ondelete='RESTRICT'),
        default=uuid.uuid4,
        primary_key=True,
    )
    """Bucket identifier."""

    key = db.Column(
        db.Text().with_variant(mysql.VARCHAR(255), 'mysql'),
        primary_key=True,
    )
    """Key identifying the object."""

    version_id = db.Column(
        UUIDType,
        primary_key=True,
        default=uuid.uuid4,
    )
    """Identifier for the specific version of an object."""

    file_id = db.Column(UUIDType,
                        db.ForeignKey(FileInstance.id, ondelete='RESTRICT'),
                        nullable=True)
    """File instance for this object version.

    A null value in this column defines that the object has been deleted.
    """

    _mimetype = db.Column(
        db.String(255),
        index=True,
        nullable=True,
    )
    """MIME type of the object."""

    is_head = db.Column(db.Boolean(name='is_head'),
                        nullable=False,
                        default=True)
    """Defines if object is the latest version."""

    # Relationships definitions
    bucket = db.relationship(Bucket, backref='objects')
    """Relationship to buckets."""

    file = db.relationship(FileInstance, backref='objects')
    """Relationship to file instance."""
    @validates('key')
    def validate_key(self, key, key_):
        """Validate key."""
        return validate_key(key_)

    def __repr__(self):
        """Return representation of location."""
        return '{0}:{2}:{1}'.format(self.bucket_id, self.key, self.version_id)

    @hybrid_property
    def mimetype(self):
        """Get MIME type of object."""
        if self._mimetype:
            m = self._mimetype
        elif self.key:
            m = mimetypes.guess_type(self.key)[0]
        return m or 'application/octet-stream'

    @mimetype.setter
    def mimetype(self, value):
        """Setter for MIME type."""
        self._mimetype = value

    @property
    def basename(self):
        """Return filename of the object."""
        return basename(self.key)

    @property
    def deleted(self):
        """Determine if object version is a delete marker."""
        return self.file_id is None

    @ensure_no_file()
    @update_bucket_size
    def set_contents(self,
                     stream,
                     chunk_size=None,
                     size=None,
                     size_limit=None,
                     progress_callback=None):
        """Save contents of stream to file instance.

        If a file instance has already been set, this methods raises an
        ``FileInstanceAlreadySetError`` exception.

        :param stream: File-like stream.
        :param size: Size of stream if known.
        :param chunk_size: Desired chunk size to read stream in. It is up to
            the storage interface if it respects this value.
        """
        if size_limit is None:
            size_limit = self.bucket.size_limit

        self.file = FileInstance.create()
        self.file.set_contents(
            stream,
            size_limit=size_limit,
            size=size,
            chunk_size=chunk_size,
            progress_callback=progress_callback,
            default_location=self.bucket.location.uri,
            default_storage_class=self.bucket.default_storage_class,
        )

        return self

    @ensure_no_file()
    @update_bucket_size
    def set_location(self, uri, size, checksum, storage_class=None):
        """Set only URI location of for object.

        Useful to link files on externally controlled storage. If a file
        instance has already been set, this methods raises an
        ``FileInstanceAlreadySetError`` exception.

        :param uri: Full URI to object (which can be interpreted by the storage
            interface).
        :param size: Size of file.
        :param checksum: Checksum of file.
        :param storage_class: Storage class where file is stored ()
        """
        self.file = FileInstance()
        self.file.set_uri(uri, size, checksum, storage_class=storage_class)
        db.session.add(self.file)
        return self

    @ensure_no_file()
    @update_bucket_size
    def set_file(self, fileinstance):
        """Set a file instance."""
        self.file = fileinstance
        return self

    def send_file(self, restricted=True, trusted=False, **kwargs):
        """Wrap around FileInstance's send file."""
        return self.file.send_file(self.basename,
                                   restricted=restricted,
                                   mimetype=self.mimetype,
                                   trusted=trusted,
                                   **kwargs)

    @ensure_is_previous_version()
    def restore(self):
        """Restore this object version to become the latest version.

        Raises an exception if the object is the latest version.
        """
        # Note, copy calls create which will fail if bucket is locked.
        return self.copy()

    @ensure_not_deleted(
        msg=[ObjectVersionError('Cannot copy a delete marker.')])
    def copy(self, bucket=None, key=None):
        """Copy an object version to a given bucket + object key.

        The copy operation is handled completely at the metadata level. The
        actual data on disk is not copied. Instead, the two object versions
        will point to the same physical file (via the same FileInstance).

        .. warning::

           If the destination object exists, it will be replaced by  the new
           object version which will become the latest version.

        :param bucket: The bucket (instance or id) to copy the object to.
            Default: current bucket.
        :param key: Key name of destination object.
            Default: current object key.
        :returns: The copied object version.
        """
        return ObjectVersion.create(
            self.bucket if bucket is None else as_bucket(bucket),
            key or self.key,
            _file_id=self.file_id)

    @ensure_unlocked(getter=lambda o: not o.bucket.locked)
    def remove(self):
        """Permanently remove a specific object version from the database.

        .. warning::

           This by-passes the normal versioning and should only be used when
           you want to permanently delete a specific object version. Otherwise
           use :py:data:`ObjectVersion.delete()`.

           Note the method does not remove the associated file instance which
           must be garbage collected.

        :returns: ``self``.
        """
        with db.session.begin_nested():
            if self.file_id:
                self.bucket.size -= self.file.size
            self.query.filter_by(
                bucket_id=self.bucket_id,
                key=self.key,
                version_id=self.version_id,
            ).delete()

        return self

    @classmethod
    def create(cls,
               bucket,
               key,
               _file_id=None,
               stream=None,
               mimetype=None,
               version_id=None,
               **kwargs):
        """Create a new object in a bucket.

        The created object is by default created as a delete marker. You must
        use ``set_contents()`` or ``set_location()`` in order to change this.

        :param bucket: The bucket (instance or id) to create the object in.
        :param key: Key of object.
        :param _file_id: For internal use.
        :param stream: File-like stream object. Used to set content of object
            immediately after being created.
        :param mimetype: MIME type of the file object if it is known.
        :param kwargs: Keyword arguments passed to ``Object.set_contents()``.
        """
        bucket = as_bucket(bucket)

        if bucket.locked:
            raise BucketLockedError()

        with db.session.begin_nested():
            latest_obj = cls.query.filter(cls.bucket == bucket, cls.key == key,
                                          cls.is_head.is_(True)).one_or_none()
            if latest_obj is not None:
                latest_obj.is_head = False
                db.session.add(latest_obj)

            # By default objects are created in a deleted state (i.e.
            # file_id is null).
            obj = cls(
                bucket=bucket,
                key=key,
                version_id=version_id or uuid.uuid4(),
                is_head=True,
                mimetype=mimetype,
            )
            if _file_id:
                file_ = _file_id if isinstance(_file_id, FileInstance) else \
                    FileInstance.get(_file_id)
                obj.set_file(file_)
            db.session.add(obj)
        if stream:
            obj.set_contents(stream, **kwargs)
        return obj

    @classmethod
    def get(cls, bucket, key, version_id=None):
        """Fetch a specific object.

        By default the latest object version is returned, if
        ``version_id`` is not set.

        :param bucket: The bucket (instance or id) to get the object from.
        :param key: Key of object.
        :param version_id: Specific version of an object.
        """
        filters = [
            cls.bucket_id == as_bucket_id(bucket),
            cls.key == key,
        ]

        if version_id:
            filters.append(cls.version_id == version_id)
        else:
            filters.append(cls.is_head.is_(True))
            filters.append(cls.file_id.isnot(None))

        return cls.query.filter(*filters).one_or_none()

    @classmethod
    def get_versions(cls, bucket, key):
        """Fetch all versions of a specific object.

        :param bucket: The bucket (instance or id) to get the object from.
        :param key: Key of object.
        """
        filters = [
            cls.bucket_id == as_bucket_id(bucket),
            cls.key == key,
        ]

        return cls.query.filter(*filters).order_by(cls.key, cls.created.desc())

    @classmethod
    def delete(cls, bucket, key):
        """Delete an object.

        Technically works by creating a new version which works as a delete
        marker.

        :param bucket: The bucket (instance or id) to delete the object from.
        :param key: Key of object.
        :param version_id: Specific version to delete.
        :returns: Created delete marker object if key exists else ``None``.
        """
        bucket_id = as_bucket_id(bucket)

        obj = cls.get(bucket_id, key)
        if obj:
            return cls.create(as_bucket(bucket), key)
        return None

    @classmethod
    def get_by_bucket(cls, bucket, versions=False):
        """Return query that fetches all the objects in a bucket."""
        bucket_id = bucket.id if isinstance(bucket, Bucket) else bucket

        filters = [
            cls.bucket_id == bucket_id,
        ]

        if not versions:
            filters.append(cls.file_id.isnot(None))
            filters.append(cls.is_head.is_(True))

        return cls.query.filter(*filters).order_by(cls.key, cls.created.desc())

    @classmethod
    def relink_all(cls, old_file, new_file):
        """Relink all object versions (for a given file) to a new file.

        .. warning::

           Use this method with great care.
        """
        assert old_file.checksum == new_file.checksum
        assert old_file.id
        assert new_file.id

        with db.session.begin_nested():
            ObjectVersion.query.filter_by(file_id=str(old_file.id)).update(
                {ObjectVersion.file_id: str(new_file.id)})
Esempio n. 15
0
class MembershipRequest(db.Model):
    """Represent a community member role."""

    __tablename__ = 'communities_membership_request'

    id = db.Column(
        UUIDType,
        primary_key=True,
        default=uuid.uuid4,
    )

    user_id = db.Column(
        db.Integer,
        db.ForeignKey(User.id),
        nullable=True,
    )

    comm_id = db.Column(
        UUIDType,
        db.ForeignKey(CommunityMetadata.id),
        nullable=False,
    )

    email = db.Column(
        db.String(255),
        nullable=True,
    )

    role = db.Column(ChoiceType(CommunityRoles, impl=db.CHAR(1)),
                     nullable=True)

    is_invite = db.Column(db.Boolean(name='is_invite'),
                          nullable=False,
                          default=True)

    @classmethod
    def create(cls, comm_id, is_invite, role=None, user_id=None, email=None):
        """Create Community Membership request."""
        try:
            with db.session.begin_nested():
                obj = cls(comm_id=comm_id,
                          user_id=user_id,
                          role=role,
                          is_invite=is_invite,
                          email=email)
                db.session.add(obj)
        except IntegrityError:
            raise CommunityMemberAlreadyExists(comm_id=comm_id,
                                               user_id=user_id,
                                               role=role)
        return obj

    @classmethod
    def delete(cls, id):
        """Delete a community membership request."""
        try:
            with db.session.begin_nested():
                membership = cls.query.get(id)
                db.session.delete(membership)
        except IntegrityError:
            raise CommunityMemberDoesNotExist(id)
Esempio n. 16
0
class Token(db.Model):
    """A bearer token is the final token that can be used by the client."""

    __tablename__ = 'oauth2server_token'
    __table_args__ = (
        Index('ix_oauth2server_token_access_token',
              'access_token',
              unique=True,
              mysql_length=255),
        Index('ix_oauth2server_token_refresh_token',
              'refresh_token',
              unique=True,
              mysql_length=255),
    )

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

    client_id = db.Column(db.String(255),
                          db.ForeignKey(Client.client_id, ondelete='CASCADE'),
                          nullable=False,
                          index=True)
    """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,
                        db.ForeignKey(User.id, ondelete='CASCADE'),
                        nullable=True,
                        index=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(
        EncryptedType(
            type_in=db.String(255),
            key=secret_key,
        ), )

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

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

    _scopes = db.Column(db.Text)

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

    is_internal = db.Column(db.Boolean(name='is_internal'), default=False)
    """Determines if token is an internally generated token."""
    @property
    def scopes(self):
        """Return all scopes.

        :returns: A list of scopes.
        """
        if self._scopes:
            return self._scopes.split()
        return []

    @scopes.setter
    def scopes(self, scopes):
        """Set scopes.

        :param scopes: The list of 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.

        :returns: A list of scopes.
        """
        return [
            k for k, s in current_oauth2server.scope_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.

        :param name: Client name.
        :param user_id: User ID.
        :param scopes: The list of permitted scopes. (Default: ``None``)
        :param is_internal: If ``True`` it's a internal access token.
             (Default: ``False``)
        :returns: A new access token.
        """
        with db.session.begin_nested():
            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(
                        'OAUTH2SERVER_TOKEN_PERSONAL_SALT_LEN')),
                expires=None,
                _scopes=scopes,
                is_personal=True,
                is_internal=is_internal,
            )

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

        return t
Esempio n. 17
0
File: models.py Progetto: mhaya/weko
class AdminLangSettings(db.Model):
    """System Language Display Setting.

    Stored target language and registered language
    """

    __tablename__ = 'admin_lang_settings'

    lang_code = db.Column(db.String(3),
                          primary_key=True,
                          nullable=False,
                          unique=True)

    lang_name = db.Column(db.String(30), nullable=False)

    is_registered = db.Column(db.Boolean(name='registered'), default=True)

    sequence = db.Column(db.Integer, default=0)

    is_active = db.Column(db.Boolean(name='active'), default=True)

    @classmethod
    def parse_result(cls, in_result):
        """Parse results."""
        obj = {}
        for k in in_result:
            record = dict()
            record['lang_code'] = k.lang_code
            record['lang_name'] = k.lang_name
            record['is_registered'] = k.is_registered
            record['sequence'] = k.sequence
            record['is_active'] = k.is_active
            obj[k.lang_code] = record

        json_list = []
        for key in obj:
            json_list.append({
                'lang_code': '{0}'.format(obj[key]['lang_code']),
                'lang_name': '{0}'.format(obj[key]['lang_name']),
                'is_registered': obj[key]['is_registered'],
                'sequence': obj[key]['sequence']
            })
        sorted_list = sorted(json_list, key=lambda k: k['sequence'])
        return sorted_list

    @classmethod
    def load_lang(cls):
        """Get language list.

        :return: A list of language
        """
        lang_list = cls.query.all()

        return cls.parse_result(lang_list)

    @classmethod
    def create(cls, lang_code, lang_name, is_registered, sequence, is_active):
        """Create language."""
        try:
            dataObj = AdminLangSettings()
            with db.session.begin_nested():
                dataObj.lang_code = lang_code
                dataObj.lang_name = lang_name
                dataObj.is_registered = is_registered
                dataObj.sequence = sequence
                dataObj.is_active = is_active
                db.session.add(dataObj)
            db.session.commit()
        except BaseException as ex:
            db.session.rollback()
            current_app.logger.debug(ex)
            raise
        return cls

    @classmethod
    def update_lang(cls,
                    lang_code=None,
                    lang_name=None,
                    is_registered=None,
                    sequence=None,
                    is_active=None):
        """Save list language into database.

        :param lang_code: input language code
        :param lang_name: input language name
        :param is_registered: input boolean is language registered
        :param sequence: input order number of language
        :param is_active: input boolean is active of language
        :return: Updated record
        """
        with db.session.begin_nested():
            lang_setting_data = cls.query.filter_by(lang_code=lang_code).one()
            if lang_code is not None:
                lang_setting_data.lang_code = lang_code
            if lang_name is not None:
                lang_setting_data.lang_name = lang_name
            if is_registered is not None:
                lang_setting_data.is_registered = is_registered
            if sequence is not None:
                lang_setting_data.sequence = sequence
            if is_active is not None:
                lang_setting_data.is_active = is_active
            db.session.merge(lang_setting_data)

        db.session.commit()
        return cls

    @classmethod
    def get_lang_code(cls):
        """Get language code.

        :return: the language code
        """
        return cls.lang_code

    @classmethod
    def get_lang_name(cls):
        """Get language full name.

        :return: language full name
        """
        return cls.lang_name

    @classmethod
    def get_registered_language(cls):
        """Get registered languages.

        :return: All language have registered
        """
        result = cls.query.filter_by(is_registered=True)

        return cls.parse_result(result)

    @classmethod
    def get_active_language(cls):
        """Get active languages.

        :return: All languages have activated
        """
        result = cls.query.filter_by(is_active=True).order_by(
            asc('admin_lang_settings_sequence'))
        return cls.parse_result(result)
Esempio n. 18
0
class WidgetMultiLangData(db.Model):
    """Database for widget multiple language data."""

    __tablename__ = 'widget_multi_lang_data'

    id = db.Column(db.Integer, primary_key=True, nullable=False)
    widget_id = db.Column(db.Integer, nullable=False)
    lang_code = db.Column(db.String(3), nullable=False)
    label = db.Column(db.String(100), nullable=False)
    description_data = db.Column(db.JSON().with_variant(
        postgresql.JSONB(none_as_null=True),
        'postgresql',
    ).with_variant(
        JSONType(),
        'sqlite',
    ).with_variant(
        JSONType(),
        'mysql',
    ),
                                 default=lambda: dict(),
                                 nullable=True)

    is_deleted = db.Column(db.Boolean(name='deleted'), default=False)

    #
    # Query Operation
    #
    @classmethod
    def get_by_id(cls, widget_multi_lang_id):
        """Get widget multi language data by id.

        Arguments:
            widget_multilanguage_id {Integer} -- The ID

        Returns:
            data -- Widget multi language data

        """
        data = cls.query.filter_by(id=widget_multi_lang_id).one_or_none()
        return data

    @classmethod
    def create(cls, data, session):
        """Create Widget multi language data.

        :param data: WWidget multi language data
        :param session: session
        :return:
        """
        if not data:
            return None
        obj = cls(**data)
        session.add(obj)
        return obj

    @classmethod
    def get_by_widget_id(cls, widget_id):
        """Get list widget multilanguage data by widget ID.

        Arguments:
            widget_id {Integer} -- The widget id

        Returns:
            data -- List widget multilanguage data

        """
        list_data = cls.query.filter_by(widget_id=widget_id).all()
        return list_data

    @classmethod
    def update_by_id(cls, widget_item_id, data):
        """Update widget multilanguage data by id.

        Arguments:
            id {Integer} -- The id
            data {WidgetMultiLangData} -- The Widget multilanguage data

        Returns:
            True -- If deleted

        """
        widget_multi_lang = cls.get_by_id(widget_item_id)
        if not data:
            return
        for k, v in data.items():
            setattr(widget_multi_lang, k, v)
        db.session.merge(widget_multi_lang)
        return widget_multi_lang

    @classmethod
    def delete_by_widget_id(cls, widget_id, session):
        """Delete widget by id.

        :param widget_id: id of widget
        :param session: session of delete
        :return:
        """
        if not session:
            session = db.session
        multi_data = cls.get_by_widget_id(widget_id)
        if not multi_data:
            return False
        for data in multi_data:
            setattr(data, 'is_deleted', 'True')
        return True
Esempio n. 19
0
File: models.py Progetto: mhaya/weko
class LogAnalysisRestrictedCrawlerList(db.Model):
    """Represent restricted users from txt list to be restricted from logging.

    The LogAnalysisRestrictedCrawlerList object contains a ``created`` and  a
    ``updated`` properties that are automatically updated.
    """

    __tablename__ = 'loganalysis_restricted_crawler_list'

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

    list_url = db.Column(db.String(255), nullable=False)

    is_active = db.Column(db.Boolean(name='activated'), default=True)

    @classmethod
    def get_all(cls):
        """Get all crawler lists.

        :return: All crawler lists.
        """
        try:
            all = cls.query.order_by(asc(cls.id)).all()
        except Exception as ex:
            current_app.logger.debug(ex)
            all = []
            raise
        return all

    @classmethod
    def get_all_active(cls):
        """Get all active crawler lists.

        :return: All active crawler lists.
        """
        try:
            all = cls.query.filter(cls.is_active.is_(True)) \
                .filter(func.length(cls.list_url) > 0).all()
        except Exception as ex:
            current_app.logger.debug(ex)
            all = []
            raise
        return all

    @classmethod
    def add_list(cls, crawler_lists):
        """Add all crawler lists."""
        for list_url in crawler_lists:
            try:
                with db.session.begin_nested():
                    record = LogAnalysisRestrictedCrawlerList(
                        list_url=list_url)
                    db.session.add(record)
                db.session.commit()
            except Exception as ex:
                current_app.logger.debug(ex)
                db.session.rollback()
                raise
        return cls

    @classmethod
    def update_or_insert_list(cls, crawler_list):
        """Update or insert LogAnalysisRestrictedCrawlerList list."""
        for data in crawler_list:
            try:
                new_list = data.get('list_url', '')
                id = data.get('id', 0)
                is_active = data.get('is_active', True)
                with db.session.begin_nested():
                    current_record = cls.query.filter_by(id=id).one()
                    if current_record:
                        current_record.list_url = new_list
                        current_record.is_active = is_active
                        db.session.merge(current_record)
                    else:
                        db.session.add(
                            LogAnalysisRestrictedCrawlerList(
                                list_url=new_list))
                db.session.commit()
            except BaseException as ex:
                current_app.logger.debug(ex)
                db.session.rollback()
                raise
        return cls

    def __iter__(self):
        """TODO: __iter__."""
        for name in dir(LogAnalysisRestrictedCrawlerList):
            if not name.startswith('__') and not name.startswith('_'):
                value = getattr(self, name)
                if isinstance(value, str):
                    yield (name, value)
Esempio n. 20
0
class WidgetItem(db.Model):
    """Database for WidgetItem."""

    __tablename__ = 'widget_items'

    widget_id = db.Column(db.Integer, primary_key=True, nullable=False)
    repository_id = db.Column(db.String(100), nullable=False)
    widget_type = db.Column(db.String(100),
                            db.ForeignKey(WidgetType.type_id),
                            nullable=False)
    settings = db.Column(db.JSON().with_variant(
        postgresql.JSONB(none_as_null=True),
        'postgresql',
    ).with_variant(
        JSONType(),
        'sqlite',
    ).with_variant(
        JSONType(),
        'mysql',
    ),
                         default=lambda: dict(),
                         nullable=True)
    browsing_role = db.Column(db.Text, nullable=True)
    edit_role = db.Column(db.Text, nullable=True)
    is_enabled = db.Column(db.Boolean(name='enable'), default=True)
    is_deleted = db.Column(db.Boolean(name='deleted'), default=False)

    #
    # Relation
    #
    widgettype = db.relationship(WidgetType,
                                 backref=db.backref('repositories',
                                                    cascade='all, \
                                                    delete-orphan'))

    #
    # Query Operation
    #
    @classmethod
    def get_by_id(cls, widget_item_id):
        """Get a widget item by id."""
        widget = cls.query.filter_by(widget_id=widget_item_id).one_or_none()
        return widget

    @classmethod
    def get_id_by_repository_and_type(cls, repository, widget_type):
        """Get id by repository id and widget type.

        :param repository: Repository id
        :param widget_type: Widget type
        :return:Widget Item
        """
        widget_data = cls.query.filter_by(repository_id=repository,
                                          widget_type=widget_type,
                                          is_deleted=False).all()
        if not widget_data:
            return None

        list_id = list()
        for data in widget_data:
            list_id.append(data.widget_id)
        return list_id

    @classmethod
    def get_sequence(cls, session):
        """Get widget item next sequence.

        :param session: Session
        :return: Next sequence.
        """
        if not session:
            session = db.session
        seq = Sequence('widget_items_widget_id_seq')
        next_id = session.execute(seq)
        return next_id

    @classmethod
    def create(cls, widget_data, session):
        """Create widget item.

        :param widget_data: widget data
        :param session: session
        :return:
        """
        if not session:
            return None
        data = cls(**widget_data)
        session.add(data)

    @classmethod
    def update_by_id(cls, widget_item_id, widget_data, session=None):
        """Update the widget by id.

        Arguments:
            widget_item_id {Integer} -- Id of widget
            widget_data {Dictionary} -- data

        Returns:
            widget -- if success

        """
        if not session:
            session = db.session
        widget = cls.get_by_id(widget_item_id)
        if not widget:
            return
        for k, v in widget_data.items():
            setattr(widget, k, v)
        session.merge(widget)
        return widget

    @classmethod
    def delete_by_id(cls, widget_id, session):
        """Delete the widget by id.

        Arguments:
            widget_id {Integer} -- The widget id

        Returns:
            widget -- If success

        """
        widget = cls.get_by_id(widget_id)
        if not widget:
            return
        setattr(widget, 'is_deleted', 'True')
        session.merge(widget)
        return widget
Esempio n. 21
0
File: models.py Progetto: mhaya/weko
class RankingSettings(db.Model):
    """Ranking settings."""

    __tablename__ = 'ranking_settings'

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

    is_show = db.Column(db.Boolean(name='show'), nullable=False, default=False)

    new_item_period = db.Column(db.Integer, nullable=False, default=14)

    statistical_period = db.Column(db.Integer, nullable=False, default=365)

    display_rank = db.Column(db.Integer, nullable=False, default=10)

    rankings = db.Column(db.JSON().with_variant(
        postgresql.JSONB(none_as_null=True),
        'postgresql',
    ).with_variant(
        JSONType(),
        'sqlite',
    ).with_variant(
        JSONType(),
        'mysql',
    ),
                         default=lambda: dict(),
                         nullable=True)

    @classmethod
    def get(cls, id=0):
        """Get ranking settings."""
        return cls.query.filter_by(id=id).first()

    @classmethod
    def update(cls, id=0, data=None):
        """Update/Create ranking settings."""
        try:
            with db.session.begin_nested():
                new_data_flag = False
                settings = cls.query.filter_by(id=id).first()
                if not settings:
                    settings = RankingSettings()
                    new_data_flag = True
                settings.id = id
                settings.is_show = data.is_show
                settings.new_item_period = data.new_item_period
                settings.statistical_period = data.statistical_period
                settings.display_rank = data.display_rank
                settings.rankings = data.rankings
                if new_data_flag:
                    db.session.add(settings)
                else:
                    db.session.merge(settings)
            db.session.commit()
        except BaseException as ex:
            db.session.rollback()
            current_app.logger.debug(ex)
            raise
        return cls

    @classmethod
    def delete(cls, id=0):
        """Delete settings."""
        try:
            with db.session.begin_nested():
                cls.query.filter_by(id=id).delete()
            db.session.commit()
        except BaseException as ex:
            db.session.rollback()
            current_app.logger.debug(ex)
            raise ex
        return cls
Esempio n. 22
0
class Journal(db.Model, Timestamp):
    """
    Represent an journal.

    The Journal object contains a ``created``, a ``updated``
    properties that are automatically updated.
    """

    __tablename__ = 'journal'

    id = db.Column(db.BigInteger, primary_key=True, unique=True)
    """Identifier of the index."""

    index_id = db.Column(db.BigInteger,
                         db.ForeignKey(Index.id, ondelete='CASCADE'),
                         nullable=False)
    # """ID of Index to whom this shib user belongs."""

    index = db.relationship(Index,
                            backref=db.backref('journal', cascade='all'),
                            cascade='all, delete-orphan',
                            single_parent=True)
    """ID of Index to whom this journal belongs."""

    publication_title = db.Column(db.Text, nullable=True, default='')
    """Title of the journal."""

    print_identifier = db.Column(db.Text, nullable=True, default='')
    """Print-format identifier of the journal."""
    """
        varchar(20)
        It complies with the format of ISBN or ISSN.
          ISSN:
            "^\\d{4}-?\\d{3}[0-9X]$"
          ISBN:
            "^\\d{9}[0-9X]$"
            "^\\d+-\\d+-\\d+-[0-9X]$"
            "^97[8-9]\\d{9}[0-9X]$"
            "^97[8-9]-\\d+-\\d+-\\d+-[0-9X]$"
    """

    online_identifier = db.Column(db.Text, nullable=True, default='')
    """Online-format identifier of the journal."""
    """
        varchar(20)
        It complies with the format of ISBN or ISSN.
          ISSN:
            "^\\d{4}-?\\d{3}[0-9X]$"
          ISBN:
            "^\\d{9}[0-9X]$"
            "^\\d+-\\d+-\\d+-[0-9X]$"
            "^97[8-9]\\d{9}[0-9X]$"
            "^97[8-9]-\\d+-\\d+-\\d+-[0-9X]$"
    """

    date_first_issue_online = db.Column(db.Text, nullable=True, default='')
    """Date of first issue available online of the journal."""
    """
        varchar(10)
        It has one of the following format.
        YYYY-MM-DD and current date
        YYYY-MM
        YYYY
        YYYY is can be input only from 1700-2030
    """

    num_first_vol_online = db.Column(db.Text, nullable=True, default='')
    """Number of first volume available online of the journal."""
    """ varchar(255) """

    num_first_issue_online = db.Column(db.Text, nullable=True, default='')
    """Number of first issue available online of the journal."""
    """ varchar(255) """

    date_last_issue_online = db.Column(db.Text, nullable=True, default='')
    """Date of last issue available online of the journal."""
    """ varchar(10)
        It has one of the following format.
            YYYY-MM-DD and current date
            YYYY-MM
            YYYY
            YYYY is can be input only from 1700-2030
    """

    num_last_vol_online = db.Column(db.Text, nullable=True, default='')
    """Number of last volume available online of the journal."""
    """ varchar(255) """

    num_last_issue_online = db.Column(db.Text, nullable=True, default='')
    """Number of last issue available online of the journal."""
    """ varchar(255) """

    title_url = db.Column(db.Text, nullable=True, default='')
    """ varchar(2048)
        WEKO index search result page display URL
        [Top Page URL] /? Action = repository_opensearch & index_id = [title_id]
    """

    first_author = db.Column(db.Text, nullable=True, default='')
    """ first_author """

    title_id = db.Column(db.BigInteger, nullable=True, default=0)
    """ Output the index ID of WEKO. """

    embargo_info = db.Column(db.Text, nullable=True, default='')
    """Embargo information of the journal."""
    """ varchar(255) """

    coverage_depth = db.Column(db.Text, nullable=True, default='')
    """Coverage depth of the journal."""
    """
        varchar(255)
        Select one of the following items:
        Abstract, Fulltext, Selected Articles
    """

    coverage_notes = db.Column(db.Text, nullable=True, default='')
    """Coverage notes of the journal."""
    """ varchar(255) """

    publisher_name = db.Column(db.Text, nullable=True, default='')
    """The Publisher name of the journal."""
    """ varchar(255) """

    publication_type = db.Column(db.Text, nullable=True, default='')
    """Publication type of the journal."""
    """ varchar(255)
        Select the following item: "Serial"
    """

    date_monograph_published_print = db.Column(db.Text,
                                               nullable=True,
                                               default='')
    """" date_monograph_published_print """

    date_monograph_published_online = db.Column(db.Text,
                                                nullable=True,
                                                default='')
    """" date_monograph_published_online """

    monograph_volume = db.Column(db.Text, nullable=True, default='')
    """" monograph_volume """

    monograph_edition = db.Column(db.Text, nullable=True, default='')
    """" monograph_edition """

    first_editor = db.Column(db.Text, nullable=True, default='')
    """" first_editor """

    parent_publication_title_id = db.Column(db.BigInteger,
                                            nullable=True,
                                            default=0)
    """Parent publication identifier of the journal."""
    """
        int(11)
        An integer of 1 or larger.
            It's the index ID of index containing journal information
    """

    preceding_publication_title_id = db.Column(db.BigInteger,
                                               nullable=True,
                                               default=0)
    """Preceding publication identifier of the journal."""
    """
        int(11)
        An integer of 1 or larger.
            It's the index ID of index containing journal information
    """

    access_type = db.Column(db.Text, nullable=True, default='')
    """Access type of the journal."""
    """
        varchar(1)
        Select 1 of the following items: F, P
        Initial selection is  "F"
        Describe the following in item name of WEKO
        when registering journal information.
         F:Free
         P:Paid
    """

    language = db.Column(db.Text, nullable=True, default='')
    """Language of the journal."""
    """
        varchar(7)
        Select from language code (ISO639-2).
        In the pulldown, show:
        jpn, eng, chi, kor, (the others language by alphabet order).
    """

    title_alternative = db.Column(db.Text, nullable=True, default='')
    """Title alternative of the journal."""
    """ varchar(255) """

    title_transcription = db.Column(db.Text, nullable=True, default='')
    """Title transcription of the journal."""
    """ varchar(255) """

    ncid = db.Column(db.Text, nullable=True, default='')
    """NCID of the journal."""
    """ varchar(10)
        Allow the followoing formats.  "^[AB][ABN][0-9]{7}[0-9X]$"
    """

    ndl_callno = db.Column(db.Text, nullable=True, default='')
    """NDL Call No. of the journal."""
    """ varchar(20)
        Half-size alphanumeric symbol within 20 characters
    """

    ndl_bibid = db.Column(db.Text, nullable=True, default='')
    """NDL Call No. of the journal."""
    """ varchar(20)
        Half-size alphanumeric symbol within 20 characters
        TODO: Need to repair.
    """

    jstage_code = db.Column(db.Text, nullable=True, default='')
    """J-STAGE CDJOURNAL of the journal."""
    """ varchar(20)
        Half-size alphanumeric symbol within 20 characters
    """

    ichushi_code = db.Column(db.Text, nullable=True, default='')
    """Ichushi Code of the journal."""
    """ varchar(6)
        Allow the following input:"^J[0-9]{5}$"
    """

    deleted = db.Column(db.Text, nullable=True, default='')
    """Always output with empty string (character string length = 0)"""

    is_output = db.Column(db.Boolean(name='is_output'),
                          nullable=True,
                          default=lambda: False)

    owner_user_id = db.Column(db.Integer, nullable=True, default=0)
    """Owner user id of the journal."""
    def __iter__(self):
        """Yield distributions for non-duplicate projects in the working set.

        The yield order is the order in which the items' path entries were
        added to the working set.
        """
        for name in dir(Journal):
            if not name.startswith('__') and not name.startswith('_') \
                    and name not in dir(Timestamp):
                value = getattr(self, name)
                if value is None:
                    value = ""
                if isinstance(value, str) or isinstance(value, bool) \
                        or isinstance(value, datetime) \
                        or isinstance(value, int):
                    yield (name, value)

    # format setting for community admin page

    def __str__(self):
        """Representation."""
        return 'Journal <id={0.id}, index_name={0.publication_title}>'.format(
            self)
Esempio n. 23
0
class ItemTypeProperty(db.Model, Timestamp):
    """Represent an itemtype property.

    The ItemTypeProperty object contains a ``created`` and  a
    ``updated`` properties that are automatically updated.
    """

    __tablename__ = 'item_type_property'

    id = db.Column(db.Integer(), primary_key=True, autoincrement=True)
    """Identifier of itemtype property."""

    name = db.Column(db.Text, nullable=False, unique=True)
    """Name identifier of itemtype property."""

    schema = db.Column(db.JSON().with_variant(
        postgresql.JSONB(none_as_null=True),
        'postgresql',
    ).with_variant(
        JSONType(),
        'sqlite',
    ).with_variant(
        JSONType(),
        'mysql',
    ),
                       default=lambda: dict(),
                       nullable=True)
    """Store schema in JSON format. When you create a new
    ``ItemTypeProperty`` the ``schema`` field value should never be ``NULL``.
    Default value is an empty dict. ``NULL`` value means that the record
    metadata has been deleted. """

    form = db.Column(db.JSON().with_variant(
        postgresql.JSONB(none_as_null=True),
        'postgresql',
    ).with_variant(
        JSONType(),
        'sqlite',
    ).with_variant(
        JSONType(),
        'mysql',
    ),
                     default=lambda: dict(),
                     nullable=True)
    """Store schema form (single) in JSON format. When you create a new
    ``ItemTypeProperty`` the ``form`` field value should never be ``NULL``.
    Default value is an empty dict. ``NULL`` value means that the record
    metadata has been deleted. """

    forms = db.Column(db.JSON().with_variant(
        postgresql.JSONB(none_as_null=True),
        'postgresql',
    ).with_variant(
        JSONType(),
        'sqlite',
    ).with_variant(
        JSONType(),
        'mysql',
    ),
                      default=lambda: dict(),
                      nullable=True)
    """Store schema form (array) in JSON format. When you create a new
    ``ItemTypeProperty`` the ``forms`` field value should never be ``NULL``.
    Default value is an empty dict. ``NULL`` value means that the record
    metadata has been deleted. """

    delflg = db.Column(db.Boolean(name='delFlg'),
                       default=False,
                       nullable=False)
    """record delete flag"""

    sort = db.Column(db.Integer, nullable=True, unique=True)
    """Sort number of itemtype property."""
Esempio n. 24
0
class OAIServerSchema(db.Model, Timestamp):
    """Represent a OAIServer Schema.

    The OAIServer object contains a ``created`` and  a ``updated``
    properties that are automatically updated.
    """

    # Enables SQLAlchemy-Continuum versioning
    __versioned__ = {}

    __tablename__ = 'oaiserver_schema'

    id = db.Column(
        UUIDType,
        primary_key=True,
        default=uuid.uuid4,
    )
    """schema identifier."""

    schema_name = db.Column(
        db.String(255),
        nullable=False,
        unique=True
    )
    """Mapping Name of schema"""

    form_data = db.Column(
        db.JSON().with_variant(
            postgresql.JSONB(none_as_null=True),
            'postgresql',
        ).with_variant(
            JSONType(),
            'sqlite',
        ).with_variant(
            JSONType(),
            'mysql',
        ),
        default=lambda: dict(),
        nullable=True
    )
    """Data(schema name,root name,description) of form."""

    xsd = db.Column(
        db.JSON().with_variant(
            postgresql.JSONB(none_as_null=True),
            'postgresql',
        ).with_variant(
            JSONType(),
            'sqlite',
        ).with_variant(
            JSONType(),
            'mysql',
        ),
        default=lambda: OrderedDict(),
        nullable=False
    )
    """Xsd schema"""

    namespaces = db.Column(
        db.JSON().with_variant(
            postgresql.JSONB(none_as_null=True),
            'postgresql',
        ).with_variant(
            JSONType(),
            'sqlite',
        ).with_variant(
            JSONType(),
            'mysql',
        ),
        default=lambda: dict(),
        nullable=True
    )
    """NameSpace for xml"""

    schema_location = db.Column(
        db.String(255)
    )
    """Schema Url"""

    isvalid = db.Column(
        db.Boolean(name='isvalid'),
        nullable=False,
        default=lambda: False
    )

    is_mapping = db.Column(
        db.Boolean(name='is_mapping'),
        nullable=False,
        default=lambda: False
    )

    isfixed = db.Column(
        db.Boolean(name='isfixed'),
        nullable=False,
        default=lambda: False
    )

    version_id = db.Column(db.Integer, nullable=False)
    """Used by SQLAlchemy for optimistic concurrency control."""

    target_namespace = db.Column(db.String(255), default='')

    __mapper_args__ = {
        'version_id_col': version_id
    }
Esempio n. 25
0
class ActionNeedMixin(object):
    """Define common attributes for Action needs."""

    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    """Primary key. It allows the other fields to be nullable."""

    action = db.Column(db.String(80), index=True)
    """Name of the action."""

    exclude = db.Column(db.Boolean(name='exclude'),
                        nullable=False,
                        default=False,
                        server_default='0')
    """If set to True, deny the action, otherwise allow it."""

    argument = db.Column(db.String(255), nullable=True, index=True)
    """Action argument."""
    @classmethod
    def create(cls, action, **kwargs):
        """Create new database row using the provided action need.

        :param action: An object containing a method equal to ``'action'`` and
            a value.
        :param argument: The action argument. If this parameter is not passed,
            then the ``action.argument`` will be used instead. If the
            ``action.argument`` does not exist, ``None`` will be set as
            argument for the new action need.
        :returns: An :class:`invenio_access.models.ActionNeedMixin` instance.
        """
        assert action.method == 'action'
        argument = kwargs.pop('argument', None) or getattr(
            action, 'argument', None)
        return cls(action=action.value, argument=argument, **kwargs)

    @classmethod
    def allow(cls, action, **kwargs):
        """Allow the given action need.

        :param action: The action to allow.
        :returns: A :class:`invenio_access.models.ActionNeedMixin` instance.
        """
        return cls.create(action, exclude=False, **kwargs)

    @classmethod
    def deny(cls, action, **kwargs):
        """Deny the given action need.

        :param action: The action to deny.
        :returns: A :class:`invenio_access.models.ActionNeedMixin` instance.
        """
        return cls.create(action, exclude=True, **kwargs)

    @classmethod
    def query_by_action(cls, action, argument=None):
        """Prepare query object with filtered action.

        :param action: The action to deny.
        :param argument: The action argument. If it's ``None`` then, if exists,
            the ``action.argument`` will be taken. In the worst case will be
            set as ``None``. (Default: ``None``)
        :returns: A query object.
        """
        query = cls.query.filter_by(action=action.value)
        argument = argument or getattr(action, 'argument', None)
        if argument is not None:
            query = query.filter(
                db.or_(
                    cls.argument == str(argument),
                    cls.argument.is_(None),
                ))
        else:
            query = query.filter(cls.argument.is_(None))
        return query

    @property
    def need(self):
        """Return the need corresponding to this model instance.

        This is an abstract method and will raise NotImplementedError.
        """
        raise NotImplementedError()  # pragma: no cover
Esempio n. 26
0
class ResyncIndexes(db.Model, Timestamp):
    """ResyncIndexes model.

    Stores session life_time created for Session.
    """

    __tablename__ = 'resync_indexes'

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    """Identifier of resource list."""

    status = db.Column(db.String(),
                       nullable=False,
                       default=lambda: current_app.config[
                           'INVENIO_RESYNC_INDEXES_STATUS'].get('automatic'))
    """Status of resource list."""

    index_id = db.Column(db.BigInteger,
                         db.ForeignKey(Index.id, ondelete='CASCADE'),
                         nullable=True)
    """Index Identifier relation to resync indexes."""

    repository_name = db.Column(db.String(50), nullable=False)
    """Repository name."""

    from_date = db.Column(db.DateTime, nullable=True)
    """From Date."""

    to_date = db.Column(db.DateTime, nullable=True)
    """To Date."""

    resync_save_dir = db.Column(db.String(50), nullable=False)
    """Path directory save."""

    resync_mode = db.Column(db.String(20),
                            nullable=False,
                            default=lambda: current_app.config[
                                'INVENIO_RESYNC_INDEXES_MODE'].get('baseline'))
    """Resync mode."""

    saving_format = db.Column(
        db.String(10),
        nullable=False,
        default=lambda: current_app.config[
            'INVENIO_RESYNC_INDEXES_SAVING_FORMAT'].get('jpcoar'))
    """Saving format."""

    base_url = db.Column(db.String(255), nullable=False)
    """base url of resync."""

    is_running = db.Column(db.Boolean(), default=True)
    """is running."""

    interval_by_day = db.Column(db.Integer, nullable=False)
    """Time cycle for each change list."""

    task_id = db.Column(db.String(40), default=None)

    result = db.Column(db.JSON().with_variant(
        postgresql.JSONB(none_as_null=True),
        'postgresql',
    ).with_variant(
        JSONType(),
        'sqlite',
    ).with_variant(
        JSONType(),
        'mysql',
    ),
                       default=lambda: dict(),
                       nullable=True)

    index = db.relationship(Index,
                            backref='resync_index_id',
                            foreign_keys=[index_id])
    """Relation to the Index Identifier."""
Esempio n. 27
0
class Index(db.Model, Timestamp):
    """
    Represent an index.

    The Index object contains a ``created`` and  a ``updated``
    properties that are automatically updated.
    """

    __tablename__ = 'index'

    __table_args__ = (db.UniqueConstraint('parent',
                                          'position',
                                          name='uix_position'), )

    id = db.Column(db.BigInteger, primary_key=True, unique=True)
    """Identifier of the index."""

    parent = db.Column(db.BigInteger, nullable=False, default=0)
    """Parent Information of the index."""

    position = db.Column(db.Integer, nullable=False, default=0)
    """Children position of parent."""

    index_name = db.Column(db.Text, nullable=True, default='')
    """Name of the index."""

    index_name_english = db.Column(db.Text, nullable=False, default='')
    """English Name of the index."""

    index_link_name = db.Column(db.Text, nullable=True, default='')
    """Name of the index link."""

    index_link_name_english = db.Column(db.Text, nullable=False, default='')
    """English Name of the index link."""

    harvest_spec = db.Column(db.Text, nullable=True, default='')
    """Harvest Spec."""

    index_link_enabled = db.Column(db.Boolean(name='index_link_enabled'),
                                   nullable=False,
                                   default=False)
    """Index link enable flag."""

    comment = db.Column(db.Text, nullable=True, default='')
    """Comment of the index."""

    more_check = db.Column(db.Boolean(name='more_check'),
                           nullable=False,
                           default=False)
    """More Status of the index."""

    display_no = db.Column(db.Integer, nullable=False, default=0)
    """Display number of the index."""

    harvest_public_state = db.Column(db.Boolean(name='harvest_public_state'),
                                     nullable=False,
                                     default=True)
    """Harvest public State of the index."""

    display_format = db.Column(db.Text, nullable=True, default='1')
    """The Format of Search Resault."""

    image_name = db.Column(db.Text, nullable=False, default='')
    """The Name of upload image."""

    public_state = db.Column(db.Boolean(name='public_state'),
                             nullable=False,
                             default=False)
    """Public State of the index."""

    public_date = db.Column(db.DateTime().with_variant(mysql.DATETIME(fsp=6),
                                                       "mysql"),
                            nullable=True)
    """Public Date of the index."""

    recursive_public_state = db.Column(db.Boolean(name='recs_public_state'),
                                       nullable=True,
                                       default=False)
    """Recursive Public State of the index."""

    coverpage_state = db.Column(db.Boolean(name='coverpage_state'),
                                nullable=True,
                                default=False)
    """PDF Cover Page State of the index."""

    recursive_coverpage_check = db.Column(
        db.Boolean(name='recursive_coverpage_check'),
        nullable=True,
        default=False)
    """Recursive PDF Cover Page State of the index."""

    browsing_role = db.Column(db.Text, nullable=True)
    """Browsing Role of the  ."""

    recursive_browsing_role = db.Column(db.Boolean(name='recs_browsing_role'),
                                        nullable=True,
                                        default=False)
    """Recursive Browsing Role of the index."""

    contribute_role = db.Column(db.Text, nullable=True)
    """Contribute Role of the index."""

    recursive_contribute_role = db.Column(
        db.Boolean(name='recs_contribute_role'), nullable=True, default=False)
    """Recursive Browsing Role of the index."""

    browsing_group = db.Column(db.Text, nullable=True)
    """Browsing Group of the  ."""

    recursive_browsing_group = db.Column(
        db.Boolean(name='recs_browsing_group'), nullable=True, default=False)
    """Recursive Browsing Group of the index."""

    contribute_group = db.Column(db.Text, nullable=True)
    """Contribute Group of the index."""

    recursive_contribute_group = db.Column(
        db.Boolean(name='recs_contribute_group'), nullable=True, default=False)
    """Recursive Browsing Group of the index."""

    owner_user_id = db.Column(db.Integer, nullable=True, default=0)
    """Owner user id of the index."""

    # item_custom_sort = db.Column(db.Text, nullable=True, default='')

    item_custom_sort = db.Column(db.JSON().with_variant(
        postgresql.JSONB(none_as_null=True),
        'postgresql',
    ).with_variant(
        JSONType(),
        'sqlite',
    ).with_variant(
        JSONType(),
        'mysql',
    ),
                                 default=lambda: dict(),
                                 nullable=True)
    """The sort of item by custom setting"""

    # index_items = db.relationship('IndexItems', back_populates='index', cascade='delete')

    def __iter__(self):
        """Iter."""
        for name in dir(Index):
            if not name.startswith('__') and not name.startswith('_') \
                    and name not in dir(Timestamp):
                value = getattr(self, name)
                if value is None:
                    value = ""
                if isinstance(value, str) or isinstance(value, bool) \
                        or isinstance(value, datetime) \
                        or isinstance(value, int):
                    yield (name, value)

    # format setting for community admin page

    def __str__(self):
        """Representation."""
        return 'Index <id={0.id}, index_name={0.index_name_english}>'.format(
            self)

    @classmethod
    def have_children(cls, id):
        """Have Children."""
        children = cls.query.filter_by(parent=id).all()
        return False if (children is None or len(children) == 0) else True
Esempio n. 28
0
class SIP(db.Model, Timestamp):
    """Submission Information Package model."""

    __tablename__ = 'sipstore_sip'

    id = db.Column(UUIDType, primary_key=True, default=uuid.uuid4)
    """Id of SIP."""

    user_id = db.Column(db.Integer,
                        db.ForeignKey(User.id, name='fk_sipstore_sip_user_id'),
                        nullable=True,
                        default=None)
    """User responsible for the SIP."""

    agent = db.Column(JSONType, default=lambda: dict(), nullable=False)
    """Agent information regarding given SIP."""

    archivable = db.Column(db.Boolean(name='archivable'),
                           nullable=False,
                           default=True)
    """Boolean stating if the SIP should be archived or not."""

    archived = db.Column(db.Boolean(name='archived'),
                         nullable=False,
                         default=False)
    """Boolean stating if the SIP has been archived or not."""

    #
    # Relationships
    #
    user = db.relationship(User, backref='sips', foreign_keys=[user_id])
    """Relation to the User responsible for the SIP."""
    @classmethod
    def create(cls,
               user_id=None,
               agent=None,
               id_=None,
               archivable=True,
               archived=False):
        """Create a Submission Information Package object.

        :param user_id: Id of the user responsible for the SIP.
        :type user_id: int
        :param agent: Extra information on submitting agent in JSON format.
        :type agent: dict
        :param bool archivable: Tells if the SIP should be archived or not.
        :param bool archived: Tells if the SIP has been archived.
        """
        if user_id and (User.query.get(user_id) is None):
            raise SIPUserDoesNotExist(user_id)

        agent = agent or dict()

        if current_app.config['SIPSTORE_AGENT_JSONSCHEMA_ENABLED']:
            agent.setdefault(
                '$schema',
                current_jsonschemas.path_to_url(
                    current_app.config['SIPSTORE_DEFAULT_AGENT_JSONSCHEMA']))
            schema_path = current_jsonschemas.url_to_path(agent['$schema'])
            if not schema_path:
                raise JSONSchemaNotFound(agent['$schema'])

            schema = current_jsonschemas.get_schema(schema_path)
            validate(agent, schema)

        with db.session.begin_nested():
            obj = cls(id=id_ or uuid.uuid4(),
                      user_id=user_id,
                      agent=agent,
                      archivable=archivable,
                      archived=archived)
            db.session.add(obj)
        return obj
Esempio n. 29
0
class Banner(db.Model, Timestamp):
    """Defines a message to show to users."""

    __tablename__ = "banners"
    __versioned__ = {"versioning": False}

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

    message = db.Column(db.Text, nullable=False)
    """The message content."""

    url_path = db.Column(db.String(255), nullable=True)
    """Define in which URL /path the message will be visible."""

    category = db.Column(db.String(20), nullable=False)
    """Category of the message, for styling messages per category."""

    start_datetime = db.Column(db.DateTime,
                               nullable=False,
                               default=datetime.utcnow)
    """Start date and time (UTC), can be immediate or delayed."""

    end_datetime = db.Column(db.DateTime, nullable=True)
    """End date and time (UTC), must be after `start` or forever if null."""

    active = db.Column(db.Boolean(name="active"), nullable=False, default=True)
    """Defines if the message is active, only one at the same time."""
    @classmethod
    def create(
        cls,
        message,
        category,
        url_path=None,
        start_datetime=None,
        end_datetime=None,
        active=False,
    ):
        """Create a new banner."""
        _categories = [t[0] for t in current_app.config["BANNERS_CATEGORIES"]]
        assert category in _categories
        with db.session.begin_nested():
            obj = cls(
                message=message,
                category=category,
                url_path=url_path,
                start_datetime=start_datetime,
                end_datetime=end_datetime,
                active=active,
            )
            db.session.add(obj)
        return obj

    @classmethod
    def get_active(cls, url_path=None):
        """Return the active banner, optionally for the given /path or None."""
        url_path = url_path or ""
        now = datetime.utcnow()

        query = (cls.query.filter(cls.active.is_(True)).filter(
            cls.start_datetime <= now).filter((cls.end_datetime.is_(None))
                                              | (now <= cls.end_datetime)))

        for banner in query.all():
            if banner.url_path is None or url_path.startswith(banner.url_path):
                return banner

        return None

    @classmethod
    def disable_expired(cls):
        """Disable any old still active messages to keep everything clean."""
        now = datetime.utcnow()

        query = (cls.query.filter(cls.active.is_(True)).filter(
            cls.end_datetime.isnot(None)).filter(cls.end_datetime < now))

        for old in query.all():
            old.active = False

        db.session.commit()
Esempio n. 30
0
class Bucket(db.Model, Timestamp):
    """Model for storing buckets.

    A bucket is a container of objects. Buckets have a default location and
    storage class. Individual objects in the bucket can however have different
    locations and storage classes.

    A bucket can be marked as deleted. A bucket can also be marked as locked
    to prevent operations on the bucket.

    Each bucket can also define a quota. The size of a bucket is the size
    of all objects in the bucket (including all versions).
    """

    __tablename__ = 'files_bucket'

    id = db.Column(
        UUIDType,
        primary_key=True,
        default=uuid.uuid4,
    )
    """Bucket identifier."""

    default_location = db.Column(db.Integer,
                                 db.ForeignKey(Location.id,
                                               ondelete='RESTRICT'),
                                 nullable=False)
    """Default location."""

    default_storage_class = db.Column(
        db.String(1),
        nullable=False,
        default=lambda: current_app.config['FILES_REST_DEFAULT_STORAGE_CLASS'])
    """Default storage class."""

    size = db.Column(db.BigInteger, default=0, nullable=False)
    """Size of bucket.

    This is a computed property which can rebuilt any time from the objects
    inside the bucket.
    """

    quota_size = db.Column(
        db.BigInteger,
        nullable=True,
        default=lambda: current_app.config['FILES_REST_DEFAULT_QUOTA_SIZE'])
    """Quota size of bucket.

    Usage of this property depends on which file size limiters are installed.
    """

    max_file_size = db.Column(
        db.BigInteger,
        nullable=True,
        default=lambda: current_app.config['FILES_REST_DEFAULT_MAX_FILE_SIZE'])
    """Maximum size of a single file in the bucket.

    Usage of this property depends on which file size limiters are installed.
    """

    locked = db.Column(db.Boolean(name='locked'),
                       default=False,
                       nullable=False)
    """Lock state of bucket.

    Modifications are not allowed on a locked bucket.
    """

    deleted = db.Column(db.Boolean(name='deleted'),
                        default=False,
                        nullable=False)
    """Delete state of bucket."""

    location = db.relationship(Location, backref='buckets')
    """Location associated with this bucket."""
    def __repr__(self):
        """Return representation of location."""
        return str(self.id)

    @property
    def quota_left(self):
        """Get how much space is left in the bucket."""
        if self.quota_size:
            return max(self.quota_size - self.size, 0)

    @property
    def size_limit(self):
        """Get size limit for this bucket.

        The limit is based on the minimum output of the file size limiters.
        """
        limits = [
            lim for lim in current_files_rest.file_size_limiters(self)
            if lim.limit is not None
        ]
        return min(limits) if limits else None

    @validates('default_storage_class')
    def validate_storage_class(self, key, default_storage_class):
        """Validate storage class."""
        if default_storage_class not in \
           current_app.config['FILES_REST_STORAGE_CLASS_LIST']:
            raise ValueError('Invalid storage class.')
        return default_storage_class

    @ensure_not_deleted()
    def snapshot(self, lock=False):
        """Create a snapshot of latest objects in bucket.

        :param lock: Create the new bucket in a locked state.
        :returns: Newly created bucket with the snapshot.
        """
        with db.session.begin_nested():
            b = Bucket(
                default_location=self.default_location,
                default_storage_class=self.default_storage_class,
                quota_size=self.quota_size,
            )
            db.session.add(b)

        for o in ObjectVersion.get_by_bucket(self):
            o.copy(bucket=b)

        b.locked = True if lock else self.locked

        return b

    def get_tags(self):
        """Get tags for bucket as dictionary."""
        return {t.key: t.value for t in self.tags}

    @classmethod
    def create(cls, location=None, storage_class=None, **kwargs):
        r"""Create a bucket.

        :param location: Location of bucket (instance or name).
            Default: Default location.
        :param storage_class: Storage class of bucket.
            Default: Default storage class.
        :param \**kwargs: Keyword arguments are forwarded to the class
            constructor.
        :returns: Created bucket.
        """
        with db.session.begin_nested():
            if location is None:
                location = Location.get_default()
            elif isinstance(location, six.string_types):
                location = Location.get_by_name(location)

            obj = cls(
                default_location=location.id,
                default_storage_class=storage_class
                or current_app.config['FILES_REST_DEFAULT_STORAGE_CLASS'],
                **kwargs)
            db.session.add(obj)
        return obj

    @classmethod
    def get(cls, bucket_id):
        """Get bucket object (excluding deleted).

        :param bucket_id: Bucket identifier.
        :returns: Bucket instance.
        """
        return cls.query.filter_by(id=bucket_id, deleted=False).one_or_none()

    @classmethod
    def all(cls):
        """Return query of all buckets (excluding deleted)."""
        return cls.query.filter_by(deleted=False)

    @classmethod
    def delete(cls, bucket_id):
        """Delete a bucket.

        Does not actually delete the Bucket, just marks it as deleted.
        """
        bucket = cls.get(bucket_id)
        if not bucket or bucket.deleted:
            return False

        bucket.deleted = True
        return True

    @ensure_unlocked()
    def remove(self):
        """Permanently remove a bucket and all objects (including versions).

        .. warning::

           This by-passes the normal versioning and should only be used when
           you want to permanently delete a bucket and its objects. Otherwise
           use :py:data:`Bucket.delete()`.

           Note the method does not remove the associated file instances which
           must be garbage collected.

        :returns: ``self``.
        """
        with db.session.begin_nested():
            ObjectVersion.query.filter_by(bucket_id=self.id).delete()
            self.query.filter_by(id=self.id).delete()
        return self