def get_review_recipients(deposit, host_url, config):
    # mail of reviewer
    reviewer_mail = current_user.email
    recipients = [
        reviewer_mail,
    ]

    # mail of owner
    # owners = deposit.get("_deposit", {}).get("owners")
    owner_mail = "-"
    try:
        owner = deposit["_deposit"]["owners"][0]
        owner_mail = User.query.filter_by(id=owner).one().email
        recipients.append(owner_mail)
    except IndexError:
        pass

    cadi_id = deposit.get("analysis_context", {}).get("cadi_id")
    if cadi_id:
        # if cadi mail Hypernews if review from admin reviewer (stat committee)
        cms_stats_commitee_email = current_app.config.get(
            "CMS_STATS_QUESTIONNAIRE_ADMIN_ROLES")

        # check that current user is an admin reviewer
        if (cms_stats_commitee_email
                and Permission(RoleNeed(cms_stats_commitee_email)).can()):
            add_hypernews_mail_to_recipients(recipients, cadi_id)

    subject = create_base_subject(config, cadi_id)
    message = create_base_message(deposit, host_url)
    message += f"Submitted by {owner_mail}, and reviewed by {reviewer_mail}."

    return subject, message, recipients
示例#2
0
def files_permission_factory(obj, action=None):
    """Permission for files are always based on the type of record.

    Record bucket: Read access only with open access.
    Deposit bucket: Read/update with restricted access.
    """
    # Extract bucket id
    bucket_id = None
    if isinstance(obj, Bucket):
        bucket_id = str(obj.id)
    elif isinstance(obj, ObjectVersion):
        bucket_id = str(obj.bucket_id)
    elif isinstance(obj, MultipartObject):
        bucket_id = str(obj.bucket_id)
    elif isinstance(obj, FileObject):
        bucket_id = str(obj.bucket_id)

    # Retrieve record
    if bucket_id is not None:
        # Record or deposit bucket
        rb = RecordsBuckets.query.filter_by(bucket_id=bucket_id).one_or_none()
        if rb is not None:
            record = Record.get_record(rb.record_id)
            if is_publication(record.model):
                return PublicationFilesPermission(record, action)
            elif is_deposit(record.model):
                return DepositFilesPermission(record, action)

    return Permission(superuser_access)
def test_entry_points():
    """Test admin views discovery through entry points."""
    from flask_principal import Permission
    app = Flask('testapp')
    admin_app = InvenioAdmin(app,
                             permission_factory=lambda x: Permission(),
                             view_class_factory=lambda x: x)
    # Check if model views were added by checking the labels of menu items
    menu_items = {str(item.name): item for item in admin_app.admin.menu()}
    assert 'OneAndTwo' in menu_items  # Category for ModelOne and ModelTwo
    assert 'Four' in menu_items  # Category for ModelOne and ModelTwo
    assert 'Model One' not in menu_items  # ModelOne should go to a category
    assert 'Model Two' not in menu_items  # ModelTwo should go to a category
    assert 'Model Three' in menu_items  # ModelThree goes straight to menu
    assert isinstance(menu_items['Model Three'], flask_admin.menu.MenuView)
    assert isinstance(menu_items['OneAndTwo'], flask_admin.menu.MenuCategory)
    assert menu_items['OneAndTwo'].is_category()
    assert not menu_items['Model Three'].is_category()
    submenu_items = {
        str(item.name): item
        for item in menu_items['OneAndTwo'].get_children()
    }
    assert 'Model One' in submenu_items
    assert 'Model Two' in submenu_items
    assert not submenu_items['Model One'].is_category()
    assert not submenu_items['Model Two'].is_category()
    assert isinstance(submenu_items['Model One'], flask_admin.menu.MenuView)
    assert isinstance(submenu_items['Model Two'], flask_admin.menu.MenuView)
    four_item = menu_items['Four'].get_children()[0]
    assert four_item.name == 'View number Four'
    assert isinstance(four_item, flask_admin.menu.MenuView)
示例#4
0
def get_review_recipients(deposit, config):
    # mail of owner
    owner = deposit["_deposit"]["owners"][0]
    owner_mail = User.query.filter_by(id=owner).one().email

    # mail of reviewer
    reviewer_mail = current_user.email

    recipients = list({owner_mail, reviewer_mail})
    cadi_id = deposit.get("analysis_context", {}).get("cadi_id")
    cadi_regex = current_app.config.get("CADI_REGEX")

    # if CADI ID mail Hypernews if review from admin reviewer (stat commitee)
    if cadi_id:
        cms_stats_commitee_email = current_app.config.get(
            "CMS_STATS_QUESTIONNAIRE_ADMIN_ROLES")

        # check that current user is a aon reviewer
        if (cms_stats_commitee_email
                and Permission(RoleNeed(cms_stats_commitee_email)).can()):
            # mail for reviews - Hypernews
            # should be sent to hn-cms-<cadi-id>@cern.ch if
            #  well-formed cadi id
            hypernews_mail = \
                current_app.config.get("CMS_HYPERNEWS_EMAIL_FORMAT")
            if re.match(cadi_regex, cadi_id) and hypernews_mail:
                recipients.append(hypernews_mail.format(cadi_id))

    message = f"Submitted by {owner_mail}, and reviewed by {reviewer_mail}."
    return message, recipients
示例#5
0
def community_curation(record, user):
    """Generate a list of pending and accepted communities with permissions.

    Return a 4-tuple of lists (in order):
     * 'pending' communities, which can be curated by given user
     * 'accepted' communities, which can be curated by given user
     * All 'pending' communities
     * All 'accepted' communities
    """
    irs = ZenodoCommunity.get_irs(record).all()
    pending = list(set(ir.community for ir in irs))
    accepted = [Community.get(c) for c in record.get('communities', [])]
    # Additionally filter out community IDs that did not resolve (None)
    accepted = [c for c in accepted if c]

    # Check for global curation permission (all communities on this record).
    global_perm = None
    if user.is_anonymous:
        global_perm = False
    elif Permission(ActionNeed('admin-access')).can():
        global_perm = True

    if global_perm:
        return (pending, accepted, pending, accepted)
    else:
        return (
            [c for c in pending if _can_curate(c, user, record)],
            [c for c in accepted
             if _can_curate(c, user, record, accepted=True)],
            pending,
            accepted,
        )
def admin_permission_factory(admin_view):
    """Factory for creating a permission for an admin.

    :param admin_view: Instance of administration view which is currently being
        protected.
    :returns: Permission instance.
    """
    return Permission(action_admin_access)
示例#7
0
def create_permissions(*permissions):
    """Create permissions with given needs and excludes."""
    _permissions = []
    for _needs in permissions:
        permission = Permission()
        permission.explicit_needs.update(_needs.get("needs", set()))
        permission.explicit_excludes.update(_needs.get("excludes", set()))
        _permissions.append(permission)
    return _permissions
示例#8
0
def admin_permission_factory(view):
    """Create a permission for an admin.

    It tries to load a :class:`invenio_access.permissions.DynamicPermission`
    instance if `invenio_access` is installed.
    Otherwise, it loads a :class:`flask_principal.Permission` instance.
    :param admin_view: Instance of administration view which is currently being
        protected.
    :returns: Permission instance.
    """
    return Permission(superuser_access)
示例#9
0
 def _init_owners(self, identity, record, **kwargs):
     """If the record has no owners yet, add the current user."""
     # if the given identity is that of a user, we add the
     # corresponding user to the owners
     # (record.parent.access.owners) and commit the parent
     # otherwise, the parent's owners stays empty
     is_sys_id = Permission(system_process).allows(identity)
     if not record.parent.access.owners and not is_sys_id:
         owner_dict = {"user": identity.id}
         record.parent.access.owners.add(owner_dict)
         record.parent.commit()
示例#10
0
def action_read():
    """View only allowed to open action."""
    identity = g.identity
    actions = {}
    for action in access.actions.values():
        actions[action.value] = Permission(action).allows(identity)

    message = 'You are opening a page requiring the "read" permission'
    return render_template("invenio_access/limited.html",
                           message=message,
                           actions=actions,
                           identity=identity)
示例#11
0
 def _load_additional_permissions(self):
     # owners of the deposit are allowed to read the deposit.
     needs = set(UserNeed(owner_id)
              for owner_id in self.deposit['_deposit']['owners'])
     # add specific permission to read deposits of this community
     # in this publication state
     needs.add(read_deposit_need_factory(
         community=self.deposit['community'],
         publication_state=self.deposit['publication_state'],
     ))
     permission = Permission(*needs)
     self.permissions.add(permission)
示例#12
0
def admin_permission_factory():
    """Factory for creating a permission for an admin.

    :returns: Permission instance.
    """
    try:
        pkg_resources.get_distribution('invenio-access')
        from invenio_access.permissions import DynamicPermission as Permission
    except pkg_resources.DistributionNotFound:
        from flask_principal import Permission

    return Permission(action_admin_access)
def files_permission_factory(obj, action=None):
    """Permission factory for deposit files."""
    bucket_id = str(obj.id) if isinstance(obj, Bucket) else str(obj.bucket_id)

    try:
        bucket = RecordsBuckets.query.filter_by(
            bucket_id=bucket_id
        ).one()

        return DepositFilesPermission(bucket.record, action)

    except NoResultFound:
        return Permission()
示例#14
0
def admin_permission_factory(admin_view):
    """Factory for creating a permission for an admin.

    :param admin_view: Instance of administration view which is currently being
        protected.
    :returns: Permission instance.
    """
    try:
        pkg_resources.get_distribution('invenio-access')
        from invenio_access.permissions import DynamicPermission as Permission
    except pkg_resources.DistributionNotFound:
        from flask_principal import Permission

    return Permission(action_admin_access)
示例#15
0
def files_permission_factory(obj, action=None):
    """Permission factory for deposit files."""
    bucket_id = str(obj.id) if isinstance(obj, Bucket) else str(obj.bucket_id)

    try:
        bucket = RecordsBuckets.query.filter_by(bucket_id=bucket_id).one()
        record_type = _get_record_type(bucket.record.id)

        return {
            'recid': RecordFilesPermission(bucket.record, action),
            'depid': DepositFilesPermission(bucket.record, action)
        }[record_type]

    except (NoResultFound, KeyError):
        return Permission()
示例#16
0
def delete(user_id):
    """Delete spam."""
    # Only admin can access this view
    if not Permission(ActionNeed('admin-access')).can():
        abort(403)

    user = User.query.get(user_id)
    deleteform = DeleteSpamForm()
    communities = Community.query.filter_by(id_user=user.id)

    rs = RecordsSearch(index='records').query(
        Q('query_string', query="owners: {0}".format(user.id)))
    rec_count = rs.count()

    ctx = {
        'user': user,
        'form': deleteform,
        'is_new': False,
        'communities': communities,
        'rec_count': rec_count,
    }

    if deleteform.validate_on_submit():

        if deleteform.remove_all_communities.data:
            for c in communities:
                if not c.deleted_at:
                    if not c.description.startswith('--SPAM--'):
                        c.description = '--SPAM--' + c.description
                    if c.oaiset:
                        db.session.delete(c.oaiset)
                    c.delete()
            db.session.commit()
        if deleteform.deactivate_user.data:
            _datastore.deactivate_user(user)
            db.session.commit()
        # delete_record function commits the session internally
        # for each deleted record
        if deleteform.remove_all_records.data:
            for r in rs.scan():
                delete_record(r.meta.id, 'spam', int(current_user.get_id()))

        flash("Spam removed", category='success')
        return redirect(url_for('.delete', user_id=user.id))
    else:
        records = islice(rs.scan(), 10)
        ctx.update(records=records)
        return render_template('zenodo_spam/delete.html', **ctx)
示例#17
0
def admin_permission_factory():
    """Factory for creating a permission for an admin `deposit-admin-access`.

    If `invenio-access` module is installed, it returns a
    :class:`invenio_access.permissions.DynamicPermission` object.
    Otherwise, it returns a :class:`flask_principal.Permission` object.

    :returns: Permission instance.
    """
    try:
        pkg_resources.get_distribution('invenio-access')
        from invenio_access.permissions import DynamicPermission as Permission
    except pkg_resources.DistributionNotFound:
        from flask_principal import Permission

    return Permission(action_admin_access)
示例#18
0
def index():
    """Basic test view."""
    identity = g.identity
    actions = {}
    for action in access.actions.values():
        actions[action.value] = Permission(action).allows(identity)

    if current_user.is_anonymous:
        return render_template("invenio_access/open.html",
                               actions=actions,
                               identity=identity)
    else:
        return render_template("invenio_access/limited.html",
                               message='',
                               actions=actions,
                               identity=identity)
示例#19
0
def admin_permission_factory(admin_view):
    """Default factory for creating a permission for an admin.

    It tries to load a :class:`invenio_access.permissions.DynamicPermission`
    instance if `invenio_access` is installed.
    Otherwise, it loads a :class:`flask_principal.Permission` instance.

    :param admin_view: Instance of administration view which is currently being
        protected.
    :returns: Permission instance.
    """
    try:
        pkg_resources.get_distribution('invenio-access')
        from invenio_access.permissions import DynamicPermission as Permission
    except pkg_resources.DistributionNotFound:
        from flask_principal import Permission

    return Permission(action_admin_access)
示例#20
0
def test_invenio_access_permission(app):
    """Permission is always denied if not explicitly granted."""
    fake_identity = FakeIdentity()

    InvenioAccess(app)
    with app.test_request_context():
        db.session.begin(nested=True)
        user = User(email='*****@*****.**')
        permission = Permission(ActionNeed('read'))

        assert not permission.allows(fake_identity)

        db.session.add(ActionUsers(action='read', user=user))
        db.session.commit()

        assert not permission.allows(fake_identity)

        fake_identity.provides.add(UserNeed(user.id))
        assert permission.allows(fake_identity)
示例#21
0
 def _load_additional_permissions(self):
     """Create additional permission."""
     if self.action in _read_actions:
         if self.record['open_access']:
             # allow everybody to see open_access records
             self.permissions.clear()
             self.permissions.add(Permission())
         else:
             needs = set()
             needs.add(read_restricted_files(self.record['community']))
             needs.add(read_restricted_files(None))
             # all actions are granted to the owner
             for owner_id in self.record['_deposit']['owners']:
                 needs.add(UserNeed(owner_id))
             self.permissions.add(StrictDynamicPermission(*needs))
     else:
         # Nobody can change the files of a published record.
         self.permissions.clear()
         self.permissions.add(DenyAllPermission)
示例#22
0
def app(base_app):
    """Flask application fixture."""

    base_app._internal_jsonschemas = InvenioJSONSchemas(base_app)

    InvenioREST(base_app)
    InvenioRecordsREST(base_app)

    InvenioRecords(base_app)
    InvenioPIDStore(base_app)
    base_app.url_map.converters['pid'] = PIDConverter
    SampleExt(base_app)
    OARepoMappingIncludesExt(base_app)
    LoginManager(base_app)
    Permission(base_app)
    InvenioAccess(base_app)
    Principal(base_app)
    OARepoValidate(base_app)
    Actions(base_app)
    base_app.register_blueprint(
        invenio_records_rest.views.create_blueprint_from_app(base_app))
    login_manager = LoginManager()
    login_manager.init_app(base_app)
    login_manager.login_view = 'login'

    @login_manager.user_loader
    def basic_user_loader(user_id):
        user_obj = User.query.get(int(user_id))
        return user_obj

    @base_app.route('/test/login/<int:id>', methods=['GET', 'POST'])
    def test_login(id):
        print("test: logging user with id", id)
        response = make_response()
        user = User.query.get(id)
        login_user(user)
        set_identity(user)
        return response

    app_loaded.send(None, app=base_app)

    with base_app.app_context():
        yield base_app
示例#23
0
# -*- coding: utf-8 -*-
#
# This file is part of INSPIRE.
# Copyright (C) 2014-2017 CERN.
#
# INSPIRE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# INSPIRE is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with INSPIRE. If not, see <http://www.gnu.org/licenses/>.
#
# In applying this license, CERN does not waive the privileges and immunities
# granted to it by virtue of its status as an Intergovernmental Organization
# or submit itself to any jurisdiction.

from __future__ import absolute_import, division, print_function

from invenio_access.permissions import (Permission, ParameterizedActionNeed)

action_editor_manage_tickets = ParameterizedActionNeed('editor_manage_tickets',
                                                       argument=None)

editor_manage_tickets_permission = Permission(action_editor_manage_tickets)
# the Free Software Foundation, version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Invenio-SIP2 permissions."""

from flask import abort
from flask_login import current_user
from invenio_access.permissions import Permission, SystemRoleNeed

admin_user = Permission(SystemRoleNeed('admin'))


def deny_all():
    """Deny all permission."""
    return type('Deny', (), {'can': lambda self: False})()


def check_permission(permission):
    """Abort if permission is not allowed.

    :param permission: The permission to check.
    """
    if permission is not None and not permission.can():
        if not current_user.is_authenticated:
            abort(401)
示例#25
0
 def custom_views_permissions_factory(action):
     if action == "circulation-loan-force-checkout":
         # fake permission for a specific user
         return Permission(UserNeed(librarian2.id))
     else:
         return default_factory(action)
示例#26
0
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Permissions for this module."""

from functools import wraps

from flask import abort, current_app, redirect, url_for
from flask_login import current_user
from flask_principal import RoleNeed
from flask_security import login_required, roles_required
from invenio_access.permissions import Permission

from .modules.patrons.api import Patron

request_item_permission = Permission(RoleNeed('patron'))
librarian_permission = Permission(RoleNeed('librarian'),
                                  RoleNeed('system_librarian'))
admin_permission = Permission(RoleNeed('admin'))
editor_permission = Permission(RoleNeed('editor'), RoleNeed('admin'))


def staffer_is_authenticated(user=None):
    """Checks if user (librarian or system_librarian) is authenticated.

    :return: patron records if user is logged in and authenticated and has
    librarian or system_librarian role.
    :return False otherwise.
    """
    if not user:
        user = current_user
示例#27
0
def backoffice_permission(*args, **kwargs):
    """Return permission to allow only librarians and admins."""
    return Permission(backoffice_access_action)
示例#28
0
def circulation_permission(patron_pid):
    """Return circulation status permission for a patron."""
    return Permission(UserNeed(int(patron_pid)), backoffice_access_action)
示例#29
0
def authenticated_user_permission(*args, **kwargs):
    """Return an object that evaluates if the current user is authenticated."""
    return Permission(authenticated_user)
示例#30
0
def exp_permission_factory(experiment):
    """Experiment permission factory."""
    return Permission(
        ActionNeed('{}-access'.format(experiment.lower()))
    )