예제 #1
0
파일: rest.py 프로젝트: weblate/sonar
    def post(pid=None):
        """Save the file and associate it to the deposit record."""
        deposit = DepositRecord.get_record_by_pid(pid)

        if not deposit:
            abort(400)

        if 'key' not in request.args or 'type' not in request.args:
            abort(400)

        # Type must be either "main" or "additional"
        if request.args['type'] not in ['main', 'additional']:
            abort(400)

        key = request.args['key']

        # Store document
        deposit.files[key] = BytesIO(request.get_data())
        deposit.files[key]['label'] = re.search(r'(.*)\..*$', key).group(1)
        deposit.files[key]['category'] = request.args['type']
        deposit.files[key]['type'] = 'file'

        deposit.commit()
        db.session.commit()

        return make_response(jsonify(deposit.files[key].dumps()))
예제 #2
0
def deposit(app, db, user, pdf_file, bucket_location, deposit_json,
            embargo_date):
    """Deposit fixture."""
    json = copy.deepcopy(deposit_json)
    json['user'] = {
        '$ref': 'https://sonar.ch/api/users/{pid}'.format(pid=user['pid'])
    }

    deposit = DepositRecord.create(json, dbcommit=True, with_bucket=True)

    with open(pdf_file, 'rb') as file:
        content = file.read()

    deposit.files['main.pdf'] = BytesIO(content)
    deposit.files['main.pdf']['label'] = 'Main file'
    deposit.files['main.pdf']['category'] = 'main'
    deposit.files['main.pdf']['type'] = 'file'
    deposit.files['main.pdf']['embargo'] = True
    deposit.files['main.pdf']['embargoDate'] = embargo_date.isoformat()
    deposit.files['main.pdf']['exceptInOrganisation'] = True

    deposit.files['additional.pdf'] = BytesIO(content)
    deposit.files['additional.pdf']['label'] = 'Additional file 1'
    deposit.files['additional.pdf']['category'] = 'additional'
    deposit.files['additional.pdf']['type'] = 'file'
    deposit.files['additional.pdf']['embargo'] = False
    deposit.files['additional.pdf']['exceptInOrganisation'] = False

    deposit.commit()
    deposit.reindex()
    db.session.commit()

    return deposit
예제 #3
0
파일: rest.py 프로젝트: weblate/sonar
    def put(pid=None, key=None):
        """Update metadata linked to file."""
        deposit = DepositRecord.get_record_by_pid(pid)

        if not deposit:
            abort(400)

        json = request.get_json()

        if key not in deposit.files:
            abort(400)

        for item in json.items():
            deposit.files[key][item[0]] = item[1]

        if not deposit.files[key].get('embargoDate'):
            deposit.files[key].data.pop('embargoDate')

        try:
            deposit.commit()
            db.session.commit()
        except Exception:
            abort(400)

        return make_response(jsonify(deposit.files[key].dumps()))
예제 #4
0
    def read(cls, user, record):
        """Read permission check.

        :param user: Logged user.
        :param recor: Record to check.
        :returns: True is action can be done.
        """
        # At least for submitters logged users.
        if not current_user_record or not current_user_record.is_submitter:
            return False

        # Superuser is allowd
        if current_user_record.is_superuser:
            return True

        deposit = DepositRecord.get_record_by_pid(record['pid'])
        deposit = deposit.replace_refs()

        # Moderators are allowed only for their organisation's deposits.
        if current_user_record.is_moderator:
            return current_organisation['pid'] == deposit['user'][
                'organisation']['pid']

        # Submitters have only access to their own deposits.
        return current_user_record['pid'] == deposit['user']['pid']
예제 #5
0
def publish(pid=None):
    """Publish a deposit or send a message for review."""
    deposit = DepositRecord.get_record_by_pid(pid)

    if not deposit or deposit[
            'step'] != DepositRecord.STEP_DIFFUSION or deposit[
                'status'] not in [
                    DepositRecord.STATUS_IN_PROGRESS,
                    DepositRecord.STATUS_ASK_FOR_CHANGES
                ]:
        abort(400)

    user = UserRecord.get_record_by_ref_link(deposit['user']['$ref'])

    # Deposit can be validated directly
    if user.is_granted(UserRecord.ROLE_MODERATOR):
        deposit['status'] = DepositRecord.STATUS_VALIDATED

        # Create document based on deposit
        deposit.create_document()
    else:
        deposit['status'] = DepositRecord.STATUS_TO_VALIDATE

        subdivision = SubdivisionRecord.get_record_by_ref_link(
            user['subdivision']['$ref']) if user.get('subdivision') else None

        moderators_emails = user.get_moderators_emails(
            subdivision['pid'] if subdivision else None)

        email_subject = _('Deposit to validate')
        if subdivision:
            email_subject += f' ({get_language_value(subdivision["name"])})'

        if moderators_emails:
            # Send an email to validators
            send_email(
                moderators_emails, email_subject, 'deposits/email/validation',
                {
                    'deposit': deposit,
                    'user': user,
                    'link': current_app.config.get('SONAR_APP_ANGULAR_URL')
                }, False)

    deposit.log_action(user, 'submit')

    deposit.commit()
    deposit.reindex()
    db.session.commit()

    return make_response()
예제 #6
0
def test_user_resolver(app, organisation, roles):
    """Test user resolver."""
    UserRecord.create({
        'pid': '1',
        'full_name': 'Jules Brochu',
        'email': '*****@*****.**',
        'roles': ['user'],
        'organisation': {
            '$ref': 'https://sonar.ch/api/organisations/org'
        }
    })

    record = DepositRecord.create(
        {'user': {
            '$ref': 'https://sonar.ch/api/users/1'
        }}, with_bucket=False)

    assert record.replace_refs().get('user')['email'] == '*****@*****.**'
예제 #7
0
    def read(cls, user, record):
        """Read permission check.

        :param user: Current user record.
        :param record: Record to check.
        :returns: True is action can be done.
        """
        # At least for submitters logged users.
        if not user or not user.is_submitter:
            return False

        if user.is_superuser:
            return True

        deposit = DepositRecord.get_record_by_pid(record['pid'])
        deposit = deposit.replace_refs()

        # Admin is allowed only for same organisation's records
        if user.is_admin:
            return current_organisation['pid'] == deposit['user'][
                'organisation']['pid']

        # Special rules for moderators
        if user.is_moderator:
            user = user.replace_refs()

            # Deposit does not belong to user's organisation
            if current_organisation['pid'] != deposit['user']['organisation'][
                    'pid']:
                return False

            # Moderator has no subdivision, he can read the deposit
            if not user.get('subdivision'):
                return True

            # User has a subdivision, he can only read his own deposits and
            # deposits from the same subdivision
            return user['pid'] == deposit['user'][
                'pid'] or deposit.has_subdivision(
                    user.get('subdivision', {}).get('pid'))

        # Submitters have only access to their own deposits.
        return user['pid'] == deposit['user']['pid']
예제 #8
0
    def _make_deposit(role='submitter', organisation=None):
        user = make_user(role, organisation)

        deposit_json['user'] = {
            '$ref': 'https://sonar.ch/api/users/{pid}'.format(pid=user['pid'])
        }

        deposit_json.pop('pid', None)

        record = DepositRecord.create(deposit_json,
                                      dbcommit=True,
                                      with_bucket=True)

        with open(pdf_file, 'rb') as file:
            content = file.read()

        record.files['main.pdf'] = BytesIO(content)
        record.files['main.pdf']['label'] = 'Main file'
        record.files['main.pdf']['category'] = 'main'
        record.files['main.pdf']['type'] = 'file'
        record.files['main.pdf']['embargo'] = True
        record.files['main.pdf']['embargoDate'] = embargo_date.isoformat()
        record.files['main.pdf']['exceptInOrganisation'] = True

        record.files['additional.pdf'] = BytesIO(content)
        record.files['additional.pdf']['label'] = 'Additional file 1'
        record.files['additional.pdf']['category'] = 'additional'
        record.files['additional.pdf']['type'] = 'file'
        record.files['additional.pdf']['embargo'] = False
        record.files['additional.pdf']['exceptInOrganisation'] = False

        record.commit()
        record.reindex()
        db.session.commit()

        return record
예제 #9
0
파일: rest.py 프로젝트: weblate/sonar
def extract_metadata(pid=None):
    """Publish a deposit or send a message for review."""
    deposit = DepositRecord.get_record_by_pid(pid)

    if not deposit:
        abort(400)

    main_file = [
        file for file in deposit.files
        if file['category'] == 'main' and file.mimetype == 'application/pdf'
    ]

    if not main_file:
        abort(500)

    # Get file content
    with main_file[0].file.storage().open() as pdf_file:
        content = pdf_file.read()

    # Extract data from pdf
    pdf_extractor = PDFExtractor()
    pdf_metadata = format_extracted_data(pdf_extractor.process_raw(content))

    return make_response(jsonify(pdf_metadata))
예제 #10
0
 def get_deposit(cls, parent_record):
     """Get the deposit from the parent record."""
     return DepositRecord.get_record_by_pid(parent_record.get('pid'))
예제 #11
0
파일: rest.py 프로젝트: weblate/sonar
 def get(pid=None):
     """Get list of files associated with bucket."""
     deposit = DepositRecord.get_record_by_pid(pid)
     return make_response(jsonify(deposit.files.dumps()))
예제 #12
0
파일: rest.py 프로젝트: weblate/sonar
def review(pid=None):
    """Review a deposit and change the deposit status depending on action."""
    deposit = DepositRecord.get_record_by_pid(pid)

    if not deposit or deposit['status'] != DepositRecord.STATUS_TO_VALIDATE:
        abort(400)

    payload = request.get_json()

    if not payload:
        abort(400)

    if 'action' not in payload or 'user' not in payload or payload[
            'action'] not in [
                DepositRecord.REVIEW_ACTION_APPROVE,
                DepositRecord.REVIEW_ACTION_REJECT,
                DepositRecord.REVIEW_ACTION_ASK_FOR_CHANGES
            ]:
        abort(400)

    user = UserRecord.get_record_by_ref_link(payload['user']['$ref'])

    if not user or not user.is_moderator:
        abort(403)

    subject = None
    status = None

    if payload['action'] == DepositRecord.REVIEW_ACTION_APPROVE:
        subject = _('Deposit approval')
        status = DepositRecord.STATUS_VALIDATED

        # Create document based on deposit
        deposit.create_document()
    elif payload['action'] == DepositRecord.REVIEW_ACTION_REJECT:
        subject = _('Deposit rejection')
        status = DepositRecord.STATUS_REJECTED
    else:
        subject = _('Ask for changes on deposit')
        status = DepositRecord.STATUS_ASK_FOR_CHANGES

    deposit['status'] = status

    # Log action
    deposit.log_action(payload['user'], payload['action'], payload['comment'])

    # Load user who creates the deposit
    deposit_user = UserRecord.get_record_by_ref_link(deposit['user']['$ref'])

    send_email(
        [deposit_user['email']], subject,
        'deposits/email/{action}'.format(action=payload['action']), {
            'deposit': deposit,
            'deposit_user': deposit_user,
            'user': user,
            'date': datetime.now().strftime('%d.%m.%Y %H:%M:%S'),
            'comment': payload['comment'],
            'link': current_app.config.get('SONAR_APP_ANGULAR_URL')
        }, False)

    deposit.commit()
    deposit.reindex()
    db.session.commit()

    return make_response(jsonify(deposit))