Merge branch 'feature/admin' into feature/refactor_data_loading
This commit is contained in:
commit
cf09d986ea
1
Pipfile
1
Pipfile
|
@ -40,6 +40,7 @@ gunicorn = "*"
|
||||||
werkzeug = "*"
|
werkzeug = "*"
|
||||||
sentry-sdk = {extras = ["flask"],version = "==0.14.4"}
|
sentry-sdk = {extras = ["flask"],version = "==0.14.4"}
|
||||||
flask-mail = "*"
|
flask-mail = "*"
|
||||||
|
flask-admin = "*"
|
||||||
|
|
||||||
[requires]
|
[requires]
|
||||||
python_version = "3.7"
|
python_version = "3.7"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"hash": {
|
"hash": {
|
||||||
"sha256": "6c89585086260ebcb41918b8ef3b1d9e189e1b492208d3ff000a138bc2f2fcee"
|
"sha256": "282ec41cafca86628782987347085a494c52318c94e56d36d4bbd6a44092b110"
|
||||||
},
|
},
|
||||||
"pipfile-spec": 6,
|
"pipfile-spec": 6,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
@ -261,6 +261,13 @@
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==1.1.2"
|
"version": "==1.1.2"
|
||||||
},
|
},
|
||||||
|
"flask-admin": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:68c761d8582d59b1f7702013e944a7ad11d7659a72f3006b89b68b0bd8df61b8"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.5.6"
|
||||||
|
},
|
||||||
"flask-bcrypt": {
|
"flask-bcrypt": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:d71c8585b2ee1c62024392ebdbc447438564e2c8c02b4e57b56a4cafd8d13c5f"
|
"sha256:d71c8585b2ee1c62024392ebdbc447438564e2c8c02b4e57b56a4cafd8d13c5f"
|
||||||
|
@ -890,6 +897,13 @@
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==1.0.1"
|
"version": "==1.0.1"
|
||||||
},
|
},
|
||||||
|
"wtforms": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:6ff8635f4caeed9f38641d48cfe019d0d3896f41910ab04494143fc027866e1b",
|
||||||
|
"sha256:861a13b3ae521d6700dac3b2771970bd354a63ba7043ecc3a82b5288596a1972"
|
||||||
|
],
|
||||||
|
"version": "==2.3.1"
|
||||||
|
},
|
||||||
"xlrd": {
|
"xlrd": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:546eb36cee8db40c3eaa46c351e67ffee6eeb5fa2650b71bc4c758a29a1b29b2",
|
"sha256:546eb36cee8db40c3eaa46c351e67ffee6eeb5fa2650b71bc4c758a29a1b29b2",
|
||||||
|
|
|
@ -4,6 +4,8 @@ import sentry_sdk
|
||||||
|
|
||||||
import connexion
|
import connexion
|
||||||
from jinja2 import Environment, FileSystemLoader
|
from jinja2 import Environment, FileSystemLoader
|
||||||
|
from flask_admin import Admin
|
||||||
|
from flask_admin.contrib.sqla import ModelView
|
||||||
from flask_cors import CORS
|
from flask_cors import CORS
|
||||||
from flask_marshmallow import Marshmallow
|
from flask_marshmallow import Marshmallow
|
||||||
from flask_mail import Mail
|
from flask_mail import Mail
|
||||||
|
@ -37,13 +39,16 @@ ma = Marshmallow(app)
|
||||||
|
|
||||||
from crc import models
|
from crc import models
|
||||||
from crc import api
|
from crc import api
|
||||||
|
from crc.api import admin
|
||||||
|
|
||||||
connexion_app.add_api('api.yml', base_path='/v1.0')
|
connexion_app.add_api('api.yml', base_path='/v1.0')
|
||||||
|
|
||||||
|
|
||||||
# Convert list of allowed origins to list of regexes
|
# Convert list of allowed origins to list of regexes
|
||||||
origins_re = [r"^https?:\/\/%s(.*)" % o.replace('.', '\.') for o in app.config['CORS_ALLOW_ORIGINS']]
|
origins_re = [r"^https?:\/\/%s(.*)" % o.replace('.', '\.') for o in app.config['CORS_ALLOW_ORIGINS']]
|
||||||
cors = CORS(connexion_app.app, origins=origins_re)
|
cors = CORS(connexion_app.app, origins=origins_re)
|
||||||
|
|
||||||
|
# Sentry error handling
|
||||||
if app.config['ENABLE_SENTRY']:
|
if app.config['ENABLE_SENTRY']:
|
||||||
sentry_sdk.init(
|
sentry_sdk.init(
|
||||||
dsn="https://25342ca4e2d443c6a5c49707d68e9f40@o401361.ingest.sentry.io/5260915",
|
dsn="https://25342ca4e2d443c6a5c49707d68e9f40@o401361.ingest.sentry.io/5260915",
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
# Admin app
|
||||||
|
|
||||||
|
from flask import url_for
|
||||||
|
from flask_admin import Admin
|
||||||
|
from flask_admin.contrib import sqla
|
||||||
|
from flask_admin.contrib.sqla import ModelView
|
||||||
|
from werkzeug.utils import redirect
|
||||||
|
|
||||||
|
from crc import db, app
|
||||||
|
from crc.api.user import verify_token, verify_token_admin
|
||||||
|
from crc.models.approval import ApprovalModel
|
||||||
|
from crc.models.file import FileModel
|
||||||
|
from crc.models.study import StudyModel
|
||||||
|
from crc.models.user import UserModel
|
||||||
|
from crc.models.workflow import WorkflowModel
|
||||||
|
|
||||||
|
|
||||||
|
class AdminModelView(sqla.ModelView):
|
||||||
|
can_create = False
|
||||||
|
can_edit = False
|
||||||
|
can_delete = False
|
||||||
|
page_size = 50 # the number of entries to display on the list view
|
||||||
|
column_exclude_list = ['bpmn_workflow_json', ]
|
||||||
|
column_display_pk = True
|
||||||
|
can_export = True
|
||||||
|
|
||||||
|
def is_accessible(self):
|
||||||
|
return verify_token_admin()
|
||||||
|
|
||||||
|
def inaccessible_callback(self, name, **kwargs):
|
||||||
|
# redirect to login page if user doesn't have access
|
||||||
|
return redirect(url_for('home'))
|
||||||
|
|
||||||
|
class UserView(AdminModelView):
|
||||||
|
column_filters = ['uid']
|
||||||
|
|
||||||
|
class StudyView(AdminModelView):
|
||||||
|
column_filters = ['id', 'primary_investigator_id']
|
||||||
|
column_searchable_list = ['title']
|
||||||
|
|
||||||
|
class ApprovalView(AdminModelView):
|
||||||
|
column_filters = ['study_id', 'approver_uid']
|
||||||
|
|
||||||
|
class WorkflowView(AdminModelView):
|
||||||
|
column_filters = ['study_id', 'id']
|
||||||
|
|
||||||
|
class FileView(AdminModelView):
|
||||||
|
column_filters = ['workflow_id']
|
||||||
|
|
||||||
|
admin = Admin(app)
|
||||||
|
|
||||||
|
admin.add_view(StudyView(StudyModel, db.session))
|
||||||
|
admin.add_view(ApprovalView(ApprovalModel, db.session))
|
||||||
|
admin.add_view(UserView(UserModel, db.session))
|
||||||
|
admin.add_view(WorkflowView(WorkflowModel, db.session))
|
||||||
|
admin.add_view(FileView(FileModel, db.session))
|
Loading…
Reference in New Issue