Skip to content
This repository was archived by the owner on May 20, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
328 changes: 328 additions & 0 deletions .docker/CAMEL.sql

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion .docker/DB.Dockerfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
FROM mariadb:latest
FROM mysql:latest

COPY .docker/CAMEL.sql /docker-entrypoint-initdb.d/CAMEL.sql
8 changes: 7 additions & 1 deletion .docker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,13 @@ To verify that it works.
5.4. `docker-compose down`

6. We assume that you have a database dump of MySQL in the root folder.
It could have been created via `mysqldump --add-drop-table -u admin -p`cat /etc/psa/.psa.shadow` dbname > dbname.sql`
It could have been created via `mysqldump --add-drop-table -u admin -p` cat /etc/psa/.psa.shadow` dbname > dbname.sql`

In CAMEL's current state, to run `mysqldump` from the Dockerized MariaDB, try:

`docker exec [CONTAINER ID] [path to mysqldump executible] -u [USERNAME] --password=[PASSWORD] CAMEL > CAMEL.sql`
or
`docker exec 16b028adef6f mysqldump -u camel --password=abcdef CAMEL > CAMEL.sql`

This database dump could be imported in the database server once started by using
`mysql -u admin -p`cat /etc/psa/.psa.shadow` -h camel-database dbname < dbname.sql`
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ camel.conf
public/app/app.config.js
__pycache__
auth/.htpasswd
.docker/.DS_Store
.DS_Store
6 changes: 6 additions & 0 deletions api/Camel/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,11 @@ def __init__(self):
from Camel.auth import Auth, Logout
from Camel.experiment import Experiment, ExperimentList
from Camel.field import Field, FieldList
from Camel.field_mut import FieldMut, FieldMutList
from Camel.reference import Reference, ReferenceList
from Camel.attachment import Attachment
from Camel.pubmed import PubMed
from Camel.mutation import Mutation, MutationList

## Init Flask App
app = Flask(__name__)
Expand All @@ -54,8 +56,12 @@ def __init__(self):
api.add_resource(Logout, '/auth/logout')
api.add_resource(ExperimentList, '/experiment')
api.add_resource(Experiment, '/experiment/<int:id>')
api.add_resource(MutationList, '/mutation')
api.add_resource(Mutation, '/mutation/<int:id>')
api.add_resource(FieldList, '/field')
api.add_resource(Field, '/field/<string:id>')
api.add_resource(FieldMutList, '/field_mut')
api.add_resource(FieldMut, '/field_mut/<string:id>')
api.add_resource(ReferenceList, '/reference')
api.add_resource(Reference, '/reference/<int:id>')
api.add_resource(Attachment, '/attachment')
Expand Down
4 changes: 2 additions & 2 deletions api/Camel/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ def wrapped_endpoint(self, *args, **kwargs):
'WWW-Authenticate': 'Basic realm="Login Required"'
})

if 'AuthToken' not in request.headers:
if 'Authheader' not in request.headers:
return unauthorised

token = request.headers['AuthToken']
token = request.headers['Authheader']
db = db_connect(config)
sql = "SELECT `token` from `sessions` WHERE `token` = %(token)s"
c = db.cursor()
Expand Down
193 changes: 193 additions & 0 deletions api/Camel/field_mut.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
from pathlib import Path
import shutil

from flask_restful import request, reqparse
from MySQLdb.cursors import DictCursor

from Camel import CamelResource, config
from Camel.auth import login_required

class FieldMutList(CamelResource):

def __init__(self):
self.reqparse = reqparse.RequestParser()

##POST arguments
self.reqparse.add_argument('title', required = True, type = str, location = 'json')
self.reqparse.add_argument('unit', required = True, type = str, location = 'json')
self.reqparse.add_argument('description', required = True, type = str, location = 'json')
self.reqparse.add_argument('type_column', required = True, type = str, location = 'json')
self.reqparse.add_argument('options', required = True, type = str, location = 'json')
self.reqparse.add_argument('link', required = True, type = int, location = 'json')
self.reqparse.add_argument('required', required = True, type = int, location = 'json')
self.reqparse.add_argument('group', required = True, type = int, location = 'json')
self.reqparse.add_argument('weight', required = True, type = int, location = 'json')
self.reqparse.add_argument('group_id', required = True, type = int, location = 'json')

super(FieldMutList, self).__init__()

def retrieveFieldData(self):
sql = ("SELECT `id`, `title`, `unit`, `description`, `type_column`, `options`, `link`, `required`, `weight`, `group`, `group_id` "
"FROM `fields_mut` "
"ORDER BY `weight`")

c = self.db.cursor(DictCursor)
c.execute(sql)
rows = c.fetchall()
c.close()
return rows

def get(self):
rows = self.retrieveFieldData()
return rows


@login_required
def post(self):
sql = ("INSERT INTO `fields` (`title`, `unit`, `description`, `type_column`, `options`, `link`, `required`, `weight`, `group`, `group_id`) "
"VALUES (%(title)s, %(unit)s, %(description)s, %(type_column)s, %(options)s, %(link)s, %(required)s, %(weight)s, %(group)s, %(group_id)s)")

args = self.reqparse.parse_args()
c = self.db.cursor()
c.execute(sql, args)
newid = c.lastrowid
self.db.commit()
c.close()

args['id'] = newid
return args, 201


class FieldMut(CamelResource):
def __init__(self):
self.reqparse = reqparse.RequestParser()

##PUT arguments
self.reqparse.add_argument('title', type = str, location = 'json')
self.reqparse.add_argument('unit', type = str, location = 'json')
self.reqparse.add_argument('description', type = str, location = 'json')
self.reqparse.add_argument('options', type = str, location = 'json')
self.reqparse.add_argument('link', type = int, location = 'json')
self.reqparse.add_argument('required', type = int, location = 'json')
self.reqparse.add_argument('group', type = int, location = 'json')
self.reqparse.add_argument('weight', type = int, location = 'json')
self.reqparse.add_argument('group_id', type = int, location = 'json')

##Optional GET argument
self.reqparse.add_argument('timeline', type = int, help = 'timeline is an optional flag [0|1]', location= 'args')

super(FieldMut, self).__init__()


def get(self, id):
self.reqparse.parse_args()

sql = ("SELECT `id`, `title`, `unit`, `type_column` "
"FROM `fields_mut` ")

tokens = {}
if id.isnumeric():
sql += "WHERE `id` = %(id)s"
tokens['id'] = id
else:
sql += "WHERE `title` = %(title)s"
tokens['title'] = id

c = self.db.cursor(DictCursor)
c.execute(sql, tokens)
field_props = c.fetchone()
c.close()

type_col = field_props['type_column']

if 'timeline' not in request.args or not request.args['timeline'] == '1':
sql = ("SELECT ef.`{type_col}` value, COUNT(*) number "
"FROM `experiments_fields` ef "
"WHERE ef.`field_id` = %(field_id)s "
"GROUP BY `value` "
"ORDER BY `number` DESC").format(type_col=type_col)

else:
sql = ("SELECT ef.`{type_col}` value, r.`year`, COUNT(*) number "
"FROM `experiments_fields` ef "
"JOIN `experiments_references` er ON er.`experiment_id` = ef.`experiment_id` "
"JOIN `references` r ON r.`id` = er.`reference_id` "
"WHERE ef.`field_id` = %(field_id)s "
"GROUP BY `value`, `year` "
"ORDER BY `year`").format(type_col=type_col)

tokens = {}
tokens['field_id'] = field_props['id'];

c = self.db.cursor(DictCursor)
print(sql)
c.execute(sql, tokens)
field_stats = c.fetchall()
field_props['values'] = field_stats;
c.close()

return field_props

@login_required
def put(self, id):
sql = "SELECT count(*) FROM `fields_mut` WHERE `id` = %(id)s"
c = self.db.cursor()
c.execute(sql, {'id': id})
res = c.fetchone()
c.close()
if res[0] != 1:
return "No such field"

args = self.reqparse.parse_args()
if request.json:
sql = "UPDATE `fields_mut` SET "
updates = []
for arg_key in request.json:
if arg_key in args:
updates.append("`{arg_key}` = %({arg_key})s ".format(arg_key=arg_key))
sql+=', '.join(updates)
sql+="WHERE id = %(id)s"
c = self.db.cursor()
tokens = args
tokens['id'] = id
c.execute(sql, tokens)
self.db.commit()
c.close()

return "Update succesful", 204

@login_required
def delete(self, id):
## Does field exist?
sql = "SELECT `id`, `type_column` FROM `fields_mut` WHERE `id` = %(id)s"
c = self.db.cursor()
c.execute(sql, {'id': id})
res = c.fetchall()

if len(res) != 1:
return "No such field"
else:
type_column = res[0][1]

## Clean up ATTACH field
if type_column == 'value_ATTACH':
upload_conf = config['uploads']
upload_path = Path(upload_conf['PATH'])
sql = "SELECT `experiment_id` FROM `experiments_fields` WHERE `field_id` = %(id)s"
c.execute(sql, {'id': id})
res = c.fetchall()
for row in res:
exp_id = row[0]
attachment_dir = upload_path.joinpath(str(exp_id), str(id))
shutil.rmtree(attachment_dir, ignore_errors=True)

## Delete from db
sql = "DELETE FROM `fields_mut` WHERE `id` = %(id)s"

c.execute(sql, {'id': id})

self.db.commit()
c.close()

return "Field deleted", 204

Loading