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()))
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
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()))
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']
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()
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'] == '*****@*****.**'
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']
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
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))
def get_deposit(cls, parent_record): """Get the deposit from the parent record.""" return DepositRecord.get_record_by_pid(parent_record.get('pid'))
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()))
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))