def get_revisions(endpoint, pid_value): """Get revisions of given record""" try: Transaction = transaction_class(RecordMetadata) pid_type = PidStoreBase.get_pid_type_from_endpoint(endpoint) record = InspireRecord.get_record_by_pid_value(pid_value, pid_type, original_record=True) if not check_permissions_for_private_collection_read( record.get("_collections", [])): return jsonify(message="Unauthorized", code=403), 403 revisions = [] for revision in reversed(record.revisions): transaction_id = revision.model.transaction_id user = Transaction.query.filter( Transaction.id == transaction_id).one().user if user: user_email = user.email else: user_email = "system" revisions.append({ "updated": revision.updated, "revision_id": revision.revision_id, "user_email": user_email, "transaction_id": transaction_id, "rec_uuid": record.id, }) return jsonify(revisions) except Exception: raise EditorGetRevisionError
def get_revisions(endpoint, pid_value): """Get revisions of given record""" Transaction = transaction_class(RecordMetadata) pid_type = get_pid_type_from_endpoint(endpoint) record = get_db_record(pid_type, pid_value) revisions = [] for revision in reversed(record.revisions): transaction_id = revision.model.transaction_id user = Transaction.query.filter( Transaction.id == transaction_id).one().user if user: user_email = user.email else: user_email = 'system' revisions.append({ 'updated': revision.updated, 'revision_id': revision.revision_id, 'user_email': user_email, 'transaction_id': transaction_id, 'rec_uuid': record.id }) return jsonify(revisions)
def empty_trash(): from app import current_app as app with app.app_context(): events = Event.query.filter(Event.deleted_at.isnot(None)).all() users = User.query.filter(User.deleted_at.isnot(None)).all() sessions = Session.query.filter(Session.deleted_at.isnot(None)).all() pending_orders = Order.query.filter_by(status="pending") for event in events: if datetime.now() - event.deleted_at >= timedelta(days=30): DataManager.delete_event(event.id) for user in users: if datetime.now() - user.deleted_at >= timedelta(days=30): transaction = transaction_class(Event) transaction.query.filter_by(user_id=user.id).delete() delete_from_db(user, "User deleted permanently") for session_ in sessions: if datetime.now() - session_.deleted_at >= timedelta(days=30): delete_from_db(session_, "Session deleted permanently") for pending_order in pending_orders: if datetime.now() - pending_order.created_at >= timedelta(days=3): pending_order.status = "expired" save_to_db(pending_order, "Pending order expired.")
def get_revisions(endpoint, pid_value): """Get revisions of given record""" try: Transaction = transaction_class(RecordMetadata) pid_type = PidStoreBase.get_pid_type_from_endpoint(endpoint) record = InspireRecord.get_record_by_pid_value(pid_value, pid_type) revisions = [] for revision in reversed(record.revisions): transaction_id = revision.model.transaction_id user = Transaction.query.filter(Transaction.id == transaction_id).one().user if user: user_email = user.email else: user_email = "system" revisions.append( { "updated": revision.updated, "revision_id": revision.revision_id, "user_email": user_email, "transaction_id": transaction_id, "rec_uuid": record.id, } ) return jsonify(revisions) except Exception: raise EditorGetRevisionError
def delete_view(user_id): profile = DataGetter.get_user(user_id) if request.method == "GET": transaction = transaction_class(Event) transaction.query.filter_by(user_id=user_id).delete() delete_from_db(profile, "User's been permanently removed") flash("User" + user_id + " has been permanently deleted.", "danger") return redirect(url_for('.index_view'))
def delete_view(self, user_id): profile = DataGetter.get_user(user_id) if request.method == "GET": transaction = transaction_class(Event) transaction.query.filter_by(user_id=user_id).delete() delete_from_db(profile, "User's been permanently removed") flash("User" + user_id + " has been permenently deleted.", "danger") return redirect(url_for('.index_view'))
def _set_transaction_user_id_for_last_record_update(control_number, user_id): record = get_db_record('lit', control_number) revision = record.model.versions.filter_by(version_id=(record.revision_id + 1)).one() transaction_id = revision.transaction_id Transaction = transaction_class(RecordMetadata) transaction = Transaction.query.filter(Transaction.id == transaction_id).one() transaction.user_id = user_id db.session.add(transaction)
def _set_transaction_user_id_for_last_record_update(control_number, user_id): record = get_db_record('lit', control_number) revision = record.model.versions.filter_by(version_id=(record.revision_id + 1)).one() transaction_id = revision.transaction_id Transaction = transaction_class(RecordMetadata) transaction = Transaction.query.filter( Transaction.id == transaction_id).one() transaction.user_id = user_id db.session.add(transaction)
def get_history_for_entity(cls, limit=10, with_details=False): transaction = transaction_class(cls) transaction_changes = cls.__versioned__['transaction_changes'] with make_session() as session: transactions = (session .query(transaction) .join(transaction.changes) .filter(transaction_changes.entity_name.in_([cls.__name__])) .order_by(transaction.issued_at.desc()) .limit(limit) .all()) return [{ 'transaction_id': transaction.id, 'issued_at': transaction.issued_at.isoformat(), 'remote_address': transaction.remote_addr, 'changed_entities': _marshal_changed_entities(transaction, with_details) } for transaction in transactions]
def empty_trash(): with app.app_context(): events = Event.query.filter_by(in_trash=True) users = User.query.filter_by(in_trash=True) sessions = Session.query.filter_by(in_trash=True) for event in events: if datetime.now() - event.trash_date >= timedelta(days=30): DataManager.delete_event(event.id) for user in users: if datetime.now() - user.trash_date >= timedelta(days=30): transaction = transaction_class(Event) transaction.query.filter_by(user_id=user.id).delete() delete_from_db(user, "User deleted permanently") for session_ in sessions: if datetime.now() - session_.trash_date >= timedelta(days=30): delete_from_db(session_, "Session deleted permanently")
def get_data(self): Transaction = transaction_class(Account) yesterday = datetime.utcnow() - timedelta(days=1) trans = Transaction.query.order_by(Transaction.issued_at.desc()) \ .filter(Transaction.issued_at > yesterday).all() AccountVersion = version_class(Account) histories = [] for t in trans: # Note that one transaction can have effect on multiple entity for av in AccountVersion.query.filter( AccountVersion.transaction_id == t.id): history = VersionHistory(av, current_user.roles[0].name) has_real_change = set(av.changeset.keys()) != set( ['updated_at', 'last_visited_by_eve']) if has_real_change and history.can_render(): histories.append(history) return histories
def readHistorical(self, deviceId, timestamp): # transaction class Transaction = transaction_class(Qubit) # fetch the appropriate transaction transactionID = self.session.query(Transaction) \ .filter(Transaction.issued_at <= timestamp) \ .order_by(Transaction.issued_at.desc()) \ .limit(1) \ .from_self() \ .all()[0].id # construct statement to query historical data statement = text(""" SELECT d.id AS device_id, d.description, q.id AS qubit_id, q.resonance_frequency, q.t1, q.t2, g.id AS gate_id, g.name, g.amplitude, g.width, g.phase FROM devices_version d LEFT JOIN qubits_version q ON d.id = q.device_id LEFT JOIN gates_version g ON q.id = g.qubit_id WHERE d.id = {0} AND {1} = COALESCE(d.end_transaction_id, {1}) AND {1} = COALESCE(q.end_transaction_id, {1}) AND {1} = COALESCE(g.end_transaction_id, {1}) ;""".format(deviceId, transactionID)) # return a list of the tuples in the query return [row for row in self.session.execute(statement)]
def empty_trash(): from app import current_app as app with app.app_context(): events = Event.query.filter_by(in_trash=True) users = User.query.filter_by(in_trash=True) sessions = Session.query.filter_by(in_trash=True) orders = Order.query.filter_by(status="deleted") pending_orders = Order.query.filter_by(status="pending") expired_orders = Order.query.filter_by(status="expired") for event in events: if datetime.now() - event.trash_date >= timedelta(days=30): DataManager.delete_event(event.id) for user in users: if datetime.now() - user.trash_date >= timedelta(days=30): transaction = transaction_class(Event) transaction.query.filter_by(user_id=user.id).delete() delete_from_db(user, "User deleted permanently") for session_ in sessions: if datetime.now() - session_.trash_date >= timedelta(days=30): delete_from_db(session_, "Session deleted permanently") for order in orders: if datetime.now() - order.trashed_at >= timedelta(days=30): delete_from_db(order, "Order deleted permanently") for pending_order in pending_orders: if datetime.now() - pending_order.created_at >= timedelta(days=3): pending_order.status = "expired" save_to_db(pending_order, "Pending order expired.") for expired_order in expired_orders: if datetime.now() - expired_order.created_at >= timedelta(days=6): expired_order.status = "deleted" expired_order.trashed_at = datetime.now() save_to_db(expired_order, "Expired order deleted")
def test_edit_article_workflow(workflow_app, mocked_external_services): app_client = workflow_app.test_client() user = User.query.filter_by(email='*****@*****.**').one() login_user_via_session(app_client, user=user) record = { '$schema': 'http://localhost:5000/schemas/records/hep.json', 'arxiv_eprints': [ { 'categories': [ 'nucl-th' ], 'value': '1802.03287' } ], 'control_number': 123, 'document_type': ['article'], 'titles': [{'title': 'Resource Pooling in Large-Scale Content Delivery Systems'}], 'self': {'$ref': 'http://localhost:5000/schemas/records/hep.json'}, '_collections': ['Literature'] } factory = TestRecordMetadata.create_from_kwargs(json=record) eng_uuid = start('edit_article', data=factory.record_metadata.json) obj = WorkflowEngine.from_uuid(eng_uuid).objects[0] assert obj.status == ObjectStatus.WAITING assert obj.extra_data['callback_url'] user_id = user.get_id() obj.id_user = user_id # simulate changes in the editor and save new_title = 'Somebody edited this fancy title' obj.data['titles'][0]['title'] = new_title payload = { 'id': obj.id, 'metadata': obj.data, '_extra_data': obj.extra_data } app_client.put( obj.extra_data['callback_url'], data=json.dumps(payload), content_type='application/json' ) obj = WorkflowEngine.from_uuid(eng_uuid).objects[0] assert obj.status == ObjectStatus.WAITING # waiting for robot_upload assert obj.data['titles'][0]['title'] == new_title do_robotupload_callback( app=workflow_app, workflow_id=obj.id, recids=[obj.data['control_number']], ) record = get_db_record('lit', 123) assert record['titles'][0]['title'] == new_title # assert record edit transaction is by user who created the edit workflow revision = record.revisions[record.revision_id] transaction_id = revision.model.transaction_id Transaction = transaction_class(RecordMetadata) transaction = Transaction.query.filter(Transaction.id == transaction_id).one() assert transaction.user_id == int(user_id) obj = WorkflowEngine.from_uuid(eng_uuid).objects[0] assert obj.status == ObjectStatus.COMPLETED pending_records = WorkflowsPendingRecord.query.filter_by(workflow_id=obj.id).all() assert not pending_records
def transaction_class(version_object): from sqlalchemy_continuum import transaction_class transaction = transaction_class(version_object) return transaction.query.get(version_object.transaction_id)
def test_with_versioned_class(self): assert (transaction_class( self.Article) == versioning_manager.transaction_cls)
def test_with_unknown_type(self): with raises(ClassNotVersioned): transaction_class(None)
def test_with_versioned_class(self): assert transaction_class(self.Article) == versioning_manager.transaction_cls
def test_edit_article_workflow_sending_to_hep(workflow_app, mocked_external_services): app_client = workflow_app.test_client() user = User.query.filter_by(email='*****@*****.**').one() login_user_via_session(app_client, user=user) record = { '$schema': 'http://localhost:5000/schemas/records/hep.json', 'arxiv_eprints': [{ 'categories': ['nucl-th'], 'value': '1802.03287' }], 'control_number': 123, 'document_type': ['article'], 'titles': [{ 'title': 'Resource Pooling in Large-Scale Content Delivery Systems' }], 'self': { '$ref': 'http://localhost:5000/schemas/records/hep.json' }, '_collections': ['Literature'] } factory = TestRecordMetadata.create_from_kwargs(json=record) with patch.dict( workflow_app.config, { 'FEATURE_FLAG_ENABLE_REST_RECORD_MANAGEMENT': True, 'INSPIREHEP_URL': "http://web:8000" }): with requests_mock.Mocker() as requests_mocker: requests_mocker.register_uri( 'PUT', '{url}/literature/{cn}'.format( url=workflow_app.config.get("INSPIREHEP_URL"), cn=record['control_number'], ), headers={'content-type': 'application/json'}, status_code=200, json={ "metadata": { 'control_number': record['control_number'], }, 'id_': 1 }) eng_uuid = start('edit_article', data=factory.record_metadata.json) obj = WorkflowEngine.from_uuid(eng_uuid).objects[0] assert obj.status == ObjectStatus.WAITING assert obj.extra_data['callback_url'] user_id = user.get_id() obj.id_user = user_id # simulate changes in the editor and save new_title = 'Somebody edited this fancy title' obj.data['titles'][0]['title'] = new_title payload = { 'id': obj.id, 'metadata': obj.data, '_extra_data': obj.extra_data } app_client.put(obj.extra_data['callback_url'], data=json.dumps(payload), content_type='application/json') obj = WorkflowEngine.from_uuid(eng_uuid).objects[0] assert obj.status == ObjectStatus.WAITING # waiting for robot_upload assert obj.data['titles'][0]['title'] == new_title do_robotupload_callback( app=workflow_app, workflow_id=obj.id, recids=[obj.data['control_number']], ) record = get_db_record('lit', 123) assert record['titles'][0]['title'] == new_title # assert record edit transaction is by user who created the edit workflow revision = record.revisions[record.revision_id] transaction_id = revision.model.transaction_id Transaction = transaction_class(RecordMetadata) transaction = Transaction.query.filter( Transaction.id == transaction_id).one() assert transaction.user_id == int(user_id) obj = WorkflowEngine.from_uuid(eng_uuid).objects[0] assert obj.status == ObjectStatus.COMPLETED pending_records = WorkflowsPendingRecord.query.filter_by( workflow_id=obj.id).all() assert not pending_records
def test_edit_article_workflow(workflow_app, mocked_external_services): app_client = workflow_app.test_client() user = User.query.filter_by(email='*****@*****.**').one() login_user_via_session(app_client, user=user) record = { '$schema': 'http://localhost:5000/schemas/records/hep.json', 'arxiv_eprints': [{ 'categories': ['nucl-th'], 'value': '1802.03287' }], 'control_number': 123, 'document_type': ['article'], 'titles': [{ 'title': 'Resource Pooling in Large-Scale Content Delivery Systems' }], 'self': { '$ref': 'http://localhost:5000/schemas/records/hep.json' }, '_collections': ['Literature'] } factory = TestRecordMetadata.create_from_kwargs(json=record) eng_uuid = start('edit_article', data=factory.record_metadata.json) obj = WorkflowEngine.from_uuid(eng_uuid).objects[0] assert obj.status == ObjectStatus.WAITING assert obj.extra_data['callback_url'] user_id = user.get_id() obj.id_user = user_id # simulate changes in the editor and save new_title = 'Somebody edited this fancy title' obj.data['titles'][0]['title'] = new_title payload = { 'id': obj.id, 'metadata': obj.data, '_extra_data': obj.extra_data } app_client.put(obj.extra_data['callback_url'], data=json.dumps(payload), content_type='application/json') obj = WorkflowEngine.from_uuid(eng_uuid).objects[0] assert obj.status == ObjectStatus.WAITING # waiting for robot_upload assert obj.data['titles'][0]['title'] == new_title do_robotupload_callback( app=workflow_app, workflow_id=obj.id, recids=[obj.data['control_number']], ) record = get_db_record('lit', 123) assert record['titles'][0]['title'] == new_title # assert record edit transaction is by user who created the edit workflow revision = record.revisions[record.revision_id] transaction_id = revision.model.transaction_id Transaction = transaction_class(RecordMetadata) transaction = Transaction.query.filter( Transaction.id == transaction_id).one() assert transaction.user_id == int(user_id) obj = WorkflowEngine.from_uuid(eng_uuid).objects[0] assert obj.status == ObjectStatus.COMPLETED pending_records = WorkflowsPendingRecord.query.filter_by( workflow_id=obj.id).all() assert not pending_records
def test_edit_article_workflow_sending_to_hep(workflow_app, mocked_external_services): app_client = workflow_app.test_client() user = User.query.filter_by(email='*****@*****.**').one() login_user_via_session(app_client, user=user) record = { '$schema': 'http://localhost:5000/schemas/records/hep.json', 'arxiv_eprints': [ { 'categories': [ 'nucl-th' ], 'value': '1802.03287' } ], 'control_number': 123, 'document_type': ['article'], 'titles': [{'title': 'Resource Pooling in Large-Scale Content Delivery Systems'}], 'self': {'$ref': 'http://localhost:5000/schemas/records/hep.json'}, '_collections': ['Literature'] } factory = TestRecordMetadata.create_from_kwargs(json=record) with patch.dict(workflow_app.config, { 'FEATURE_FLAG_ENABLE_REST_RECORD_MANAGEMENT': True, 'INSPIREHEP_URL': "http://web:8000" }): with requests_mock.Mocker() as requests_mocker: requests_mocker.register_uri( 'PUT', '{url}/literature/{cn}'.format( url=workflow_app.config.get("INSPIREHEP_URL"), cn=record['control_number'], ), headers={'content-type': 'application/json'}, status_code=200, json={ "metadata": { 'control_number': record['control_number'], }, 'id_': 1 } ) eng_uuid = start('edit_article', data=factory.record_metadata.json) obj = WorkflowEngine.from_uuid(eng_uuid).objects[0] assert obj.status == ObjectStatus.WAITING assert obj.extra_data['callback_url'] user_id = user.get_id() obj.id_user = user_id # simulate changes in the editor and save new_title = 'Somebody edited this fancy title' obj.data['titles'][0]['title'] = new_title payload = { 'id': obj.id, 'metadata': obj.data, '_extra_data': obj.extra_data } app_client.put( obj.extra_data['callback_url'], data=json.dumps(payload), content_type='application/json' ) obj = WorkflowEngine.from_uuid(eng_uuid).objects[0] assert obj.status == ObjectStatus.WAITING # waiting for robot_upload assert obj.data['titles'][0]['title'] == new_title do_robotupload_callback( app=workflow_app, workflow_id=obj.id, recids=[obj.data['control_number']], ) record = get_db_record('lit', 123) assert record['titles'][0]['title'] == new_title # assert record edit transaction is by user who created the edit workflow revision = record.revisions[record.revision_id] transaction_id = revision.model.transaction_id Transaction = transaction_class(RecordMetadata) transaction = Transaction.query.filter(Transaction.id == transaction_id).one() assert transaction.user_id == int(user_id) obj = WorkflowEngine.from_uuid(eng_uuid).objects[0] assert obj.status == ObjectStatus.COMPLETED pending_records = WorkflowsPendingRecord.query.filter_by(workflow_id=obj.id).all() assert not pending_records