Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
167d521
docs: update contributing guidelines documentation 📝
brionmario Apr 14, 2019
38a6bf5
chore(models): add genre model to applications
brionmario Apr 14, 2019
33fcbdb
refactor(app): rename applications to application :truck:
brionmario Apr 14, 2019
eee4ad9
chore(models): add application type to application model
brionmario Apr 14, 2019
55a273d
chore(models): add method to generate genre meta from file
brionmario Apr 14, 2019
c445108
chore(manager): add command to generate db metadata
brionmario Apr 14, 2019
4c1ac0c
chore(migrations): update migrations :alembic:
brionmario Apr 14, 2019
42bda1a
fix(app): fix table recognition issue in migration :bug:
brionmario Apr 14, 2019
8548a0d
chore(app): add method to generate app type meta from file
brionmario Apr 15, 2019
275776b
chore(migrations): update migrations :alembic:
brionmario Apr 15, 2019
54d5d2a
chore(views): implement application GET and POST methods
brionmario Apr 15, 2019
a2f7a8e
refactor(models): refactor application models and schemas
brionmario Apr 15, 2019
65e67af
chore(views): implement type and genre relationship in application view
brionmario Apr 15, 2019
41fff1c
chore(meta): change application meta structure
brionmario Apr 15, 2019
14d5270
chore(meta): change genre meta structure
brionmario Apr 15, 2019
3c4634a
chore(migrations): update migrations :alembic:
brionmario Apr 15, 2019
d1102c6
refactor(models): put models in separate files :recycle:
brionmario Apr 15, 2019
08d68b9
chore(migrations): update migrations :alembic:
brionmario Apr 15, 2019
f87f498
chore(views): add validations to application routes
brionmario Apr 15, 2019
9de44ea
feat(views): implement basic application routes :sparkles:
brionmario Apr 15, 2019
56a4e4c
Merge pull request #1 from brionmario/feature/applications
brionmario Apr 15, 2019
77e49ae
refactor(app): change folder structure :truck:
brionmario Apr 15, 2019
a2f368f
refactor(app): move routes to v1 folder :truck:
brionmario Apr 15, 2019
adf5311
chore(app): add unique identifier and developer to applications model
brionmario Apr 15, 2019
0c1c2b4
Merge branch 'develop' into feature/applications
brionmario Apr 15, 2019
a803062
Merge pull request #2 from brionmario/feature/applications
brionmario Apr 15, 2019
db9f809
chore(models): add questionnaire and session models
brionmario Apr 15, 2019
97392b3
feat(core): implement sessions related functionality :sparkes:
brionmario Apr 15, 2019
79ec5c6
chore(migrations): update migrations :alembic:
brionmario Apr 15, 2019
7965cd6
Merge pull request #3 from brionmario/feature/sessions
brionmario Apr 15, 2019
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
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"python.pythonPath": "venv/bin/python3.7"
}
11 changes: 8 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,14 @@ The scope should be the name of the npm package affected (as perceived by the pe

The following is the list of supported scopes:

- **config**
- **core**
- **common**
- **app**
- **tests**
- **models**
- **views**
- **manager**
- **vcs**
- **core**
- **routes**
- **deps**
- **migrations**
- **config**
16 changes: 13 additions & 3 deletions app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,26 @@ def create_app(config_name):
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # disabling sqlalchemy event system

CONFIG[config_name].init_app(app)

root = CONFIG[config_name].APPLICATION_ROOT

# flask migrate doesn't recognize the tables without this import
from app.models import Application, Genre, ApplicationType, Session, Questionnaire

# Set up extensions
db.init_app(app)

# Create app blueprints
from .main import main as main_blueprint
from app.routes.v1 import main as main_blueprint
app.register_blueprint(main_blueprint, url_prefix=root + '/')

from .applications import applications as applications_blueprint
app.register_blueprint(applications_blueprint, url_prefix=root + '/applications')
from app.routes.v1 import application as application_blueprint
app.register_blueprint(application_blueprint, url_prefix=root + '/application')

from app.routes.v1 import session as session_blueprint
app.register_blueprint(session_blueprint, url_prefix=root + '/session')

from app.routes.v1 import questionnaire as questionnaire_blueprint
app.register_blueprint(questionnaire_blueprint, url_prefix=root + '/questionnaire')

return app
1 change: 0 additions & 1 deletion app/applications/__init__.py

This file was deleted.

13 changes: 0 additions & 13 deletions app/applications/views.py

This file was deleted.

1 change: 0 additions & 1 deletion app/main/__init__.py

This file was deleted.

4 changes: 4 additions & 0 deletions app/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@
"""

from .application import * # noqa
from .application_type import * # noqa
from .genre import * # noqa
from .session import * # noqa
from .questionnaire import * # noqa
34 changes: 28 additions & 6 deletions app/models/application.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,40 @@
from marshmallow import fields, validate
from .application_type import ApplicationTypeSchema
from .genre import GenreSchema
from .. import db, ma


class Application(db.Model):
__tablename__ = 'applications'
__tablename__ = 'application'

id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(250), nullable=False)
name = db.Column(db.String(100), nullable=False)
identifier = db.Column(db.String(100), nullable=False)
developer = db.Column(db.String(100), nullable=False)
type_id = db.Column(db.Integer, db.ForeignKey('application_type.id', use_alter=True, name='fk_type_id'), nullable=False)
description = db.Column(db.String(250), nullable=False)
creation_date = db.Column(db.TIMESTAMP, server_default=db.func.current_timestamp(), nullable=False)
genre = db.Column(db.String(250), nullable=False)
genre_id = db.Column(db.Integer, db.ForeignKey('genre.id', use_alter=True, name='fk_genre_id'), nullable=False)
sessions = db.relationship('Session', backref='app', lazy='dynamic')

def __init__(self, name, genre):
def __init__(self, name, identifier, developer, type, description, genre):
self.name = name
self.identifier = identifier
self.developer = developer
self.type = type
self.description = description
self.genre = genre

def __repr__(self):
return '<Application %r>' % self.id


class ApplicationSchema(ma.Schema):
class Meta:
fields = ('id', 'name', 'creation_date', 'genre')
id = fields.Integer(dump_only=True)
name = fields.String(required=True, validate=validate.Length(1, 100))
identifier = fields.String()
developer = fields.String(required=True, validate=validate.Length(1, 100))
type = fields.Nested(ApplicationTypeSchema, dump_only=True)
description = fields.String(required=True, validate=validate.Length(1, 250))
creation_date = fields.DateTime()
genre = fields.Nested(GenreSchema, dump_only=True)
56 changes: 56 additions & 0 deletions app/models/application_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import os
import json
from marshmallow import fields, validate
from .. import db, ma

APPLICATION_TYPE_META_FILE_PATH = 'meta/application_type.meta.json'


class ApplicationType(db.Model):
__tablename__ = 'application_type'

id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False)
display_name = db.Column(db.String(100), nullable=False)
display_name_full = db.Column(db.String(250), nullable=False)
applications = db.relationship('Application', backref='type', lazy='dynamic')

def __init__(self, name, display_name, display_name_full):
self.name = name
self.display_name = display_name
self.display_name_full = display_name_full

@classmethod
def seed(cls):
if cls.is_table_empty(cls):
if os.path.exists(APPLICATION_TYPE_META_FILE_PATH):
with open(APPLICATION_TYPE_META_FILE_PATH) as app_type_meta_json:
data = json.load(app_type_meta_json)
for item in data['types']:
app_type = ApplicationType(name=item['name'], display_name=item['display_name'], display_name_full=item['display_name_full'])
app_type.save()
print("Adding application type metadata: {}".format(app_type))
else:
# TODO: Add exception
print("Couldn't locate meta file")
else:
print('Table is already filled')

def save(self):
db.session.add(self)
db.session.commit()

def is_table_empty(self):
if not self.query.all():
return True
return False

def __repr__(self):
return '<ApplicationType %r>' % self.id


class ApplicationTypeSchema(ma.Schema):
id = fields.Integer()
name = fields.String(required=True)
display_name = fields.String(required=True)
display_name_full = fields.String(required=True)
53 changes: 53 additions & 0 deletions app/models/genre.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import os
import json
from marshmallow import fields
from .. import db, ma

GENRE_META_FILE_PATH = 'meta/genre.meta.json'


class Genre(db.Model):
__tablename__ = 'genre'

id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
display_name = db.Column(db.String(250), nullable=False)
applications = db.relationship('Application', backref='genre', lazy='dynamic')

def __init__(self, name, display_name):
self.name = name
self.display_name = display_name

@classmethod
def seed(cls):
if cls.is_table_empty(cls):
if os.path.exists(GENRE_META_FILE_PATH):
with open(GENRE_META_FILE_PATH) as genre_meta_json:
data = json.load(genre_meta_json)
for item in data['genre']:
genre = Genre(name=item['name'], display_name=item['display_name'])
genre.save()
print("Adding genre metadata: {}".format(genre))
else:
# TODO: Add exception
print("Couldn't locate meta file")
else:
print('Table is already filled')

def save(self):
db.session.add(self)
db.session.commit()

def is_table_empty(self):
if not self.query.all():
return True
return False

def __repr__(self):
return '<Genre %r>' % self.id


class GenreSchema(ma.Schema):
id = fields.Integer()
name = fields.String(required=True)
display_name = fields.String(required=True)
32 changes: 32 additions & 0 deletions app/models/questionnaire.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from marshmallow import fields, validate
from .. import db, ma


class Questionnaire(db.Model):
__tablename__ = 'questionnaire'

id = db.Column(db.Integer, primary_key=True)
pre = db.Column(db.JSON, nullable=False)
post = db.Column(db.JSON, nullable=False, default={})
creation_date = db.Column(db.TIMESTAMP, server_default=db.func.current_timestamp(), nullable=False)
session = db.relationship("Session", uselist=False, backref="questionnaire")

def __init__(self, pre, post):
self.pre = pre
self.post = post

def __repr__(self):
return '<Questionnaire %r>' % self.id


class SymptomSchema(ma.Schema):
name = fields.String(required=False)
display_name = fields.String(required=False)
score = fields.String(required=False)


class QuestionnaireSchema(ma.Schema):
id = fields.Integer(dump_only=True)
pre = fields.List(fields.Nested(SymptomSchema), dump_only=True)
post = fields.List(fields.Nested(SymptomSchema), dump_only=True)
creation_date = fields.DateTime()
37 changes: 37 additions & 0 deletions app/models/session.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from marshmallow import fields, validate
from .. import db, ma
from .application import ApplicationSchema
from .questionnaire import QuestionnaireSchema


class Session(db.Model):
__tablename__ = 'session'

id = db.Column(db.Integer, primary_key=True)
app_id = db.Column(db.Integer, db.ForeignKey('application.id', use_alter=True, name='fk_app_id'), nullable=False)
creation_date = db.Column(db.TIMESTAMP, server_default=db.func.current_timestamp(), nullable=False)
expected_emotions = db.Column(db.JSON, nullable=False)
questionnaire_id = db.Column(db.Integer, db.ForeignKey('questionnaire.id', use_alter=True, name='fk_questionnaire_id'), nullable=False)
cssi_score = db.Column(db.Float, nullable=False, default=0)
latency_scores = db.Column(db.JSON, nullable=False, default={})
total_latency_score = db.Column(db.Float, nullable=False, default=0)
sentiment_scores = db.Column(db.JSON, nullable=False, default={})
total_sentiment_score = db.Column(db.Float, nullable=False, default=0)
questionnaire_scores = db.Column(db.JSON, nullable=True, default={})
total_questionnaire_score = db.Column(db.Float, nullable=False, default=0)

def __init__(self, app, expected_emotions, questionnaire):
self.app = app
self.expected_emotions = expected_emotions
self.questionnaire = questionnaire

def __repr__(self):
return '<Session %r>' % self.id


class SessionSchema(ma.Schema):
id = fields.Integer(dump_only=True)
creation_date = fields.DateTime()
expected_emotions = fields.List(fields.String(), dump_only=True)
app = fields.Nested(ApplicationSchema, dump_only=True)
questionnaire = fields.Nested(QuestionnaireSchema, dump_only=True)
1 change: 1 addition & 0 deletions app/routes/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from app.routes.v1 import * # noqa
4 changes: 4 additions & 0 deletions app/routes/v1/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from app.routes.v1.application import application # noqa
from app.routes.v1.main import main # noqa
from app.routes.v1.session import session # noqa
from app.routes.v1.questionnaire import questionnaire # noqa
81 changes: 81 additions & 0 deletions app/routes/v1/application.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# (c) Copyright 2019 Brion Mario.
# (c) This file is part of the CSSI REST API and is made available under MIT license.
# (c) For more information, see https://github.com/brionmario/cssi-api/blob/master/LICENSE.txt
# (c) Please forward any queries to the given email address. email: brion@apareciumlabs.com

"""Application routes module

This modules contains all the different routes to interact with applications.

Authors:
Brion Mario

"""

import uuid
from flask import Blueprint, jsonify, request
from app.models import Application, ApplicationType, ApplicationSchema, Genre
from app import db

application = Blueprint('application', __name__)

application_schema = ApplicationSchema(strict=True)
applications_schema = ApplicationSchema(many=True, strict=True)


@application.route('/', methods=['GET'])
def get_applications():
"""Get a list of all the Applications"""
applications = Application.query.all()
result = applications_schema.dump(applications).data
return jsonify({'status': 'success', 'message': None, 'data': result}), 200


@application.route('/<int:id>', methods=['GET'])
def get_application(id):
"""Get info on an Applications when an id is passed in"""
application = Application.query.get(id)
result = application_schema.dump(application).data
return jsonify({'status': 'success', 'message': None, 'data': result}), 200


@application.route('/', methods=['POST'])
def create_application():
"""Create a new Application"""

json_data = request.get_json(force=True)

if not json_data:
return jsonify({'status': 'error', 'message': 'No input was provided.'}), 400

# Validate and deserialize input
data, errors = application_schema.load(json_data)
if errors:
return jsonify({'status': 'error', 'message': 'Incorrect format of data provided.', 'data': errors}), 422

name = request.json['name']
identifier = str(uuid.uuid4().hex)
developer = request.json['developer']
type = ApplicationType.query.filter_by(id=request.json['type']).first()
description = request.json['description']
genre = Genre.query.filter_by(id=request.json['genre']).first()

# validate application type
if not type:
return {'status': 'error', 'message': 'Invalid Application Type'}, 400

# validate genre
if not genre:
return {'status': 'error', 'message': 'Invalid Genre Type'}, 400

new_application = Application(name=name, identifier=identifier, developer=developer, type=type, description=description, genre=genre)

db.session.add(new_application)
db.session.commit()

result = application_schema.dump(new_application).data

return jsonify({'status': 'success', 'message': 'Created new application {}.'.format(name), 'data': result}), 201
File renamed without changes.
Loading