-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #10 from kids-first/person-entity
✨ Create person entity
- Loading branch information
Showing
22 changed files
with
790 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import os | ||
basedir = os.path.abspath(os.path.dirname(__file__)) | ||
|
||
|
||
class Config: | ||
HOST = "0.0.0.0" | ||
SSL_DISABLE = os.environ.get("SSL_DISABLE", False) | ||
|
||
RESTPLUS_MASK_SWAGGER = False | ||
|
||
@staticmethod | ||
def init_app(app): | ||
pass | ||
|
||
|
||
class DevelopmentConfig(Config): | ||
DEBUG = True | ||
SSL_DISABLE = True | ||
SQLALCHEMY_DATABASE_URI = os.environ.get("DEV_DATABASE_URL") or \ | ||
"sqlite:///" + os.path.join(basedir, "data-dev.sqlite") | ||
SQLALCHEMY_TRACK_MODIFICATIONS = True | ||
|
||
|
||
class TestingConfig(Config): | ||
SERVER_NAME = "localhost" | ||
TESTING = True | ||
WTF_CSRF_ENABLED = False | ||
SQLALCHEMY_DATABASE_URI = os.environ.get("TEST_DATABASE_URL") or \ | ||
"sqlite:///" + os.path.join(basedir, "data-test.sqlite") | ||
SQLALCHEMY_TRACK_MODIFICATIONS = True | ||
|
||
|
||
class ProductionConfig(Config): | ||
# Should use postgres | ||
SQLALCHEMY_DATABASE_URI = os.environ.get("DATABASE_URL") or \ | ||
"sqlite:///" + os.path.join(basedir, "data.sqlite") | ||
|
||
@classmethod | ||
def init_app(cls, app): | ||
Config.init_app(app) | ||
|
||
# email errors to the administrators | ||
import logging | ||
from logging.handlers import SMTPHandler | ||
credentials = None | ||
secure = None | ||
|
||
|
||
class UnixConfig(ProductionConfig): | ||
@classmethod | ||
def init_app(cls, app): | ||
ProductionConfig.init_app(app) | ||
|
||
# log to syslog | ||
import logging | ||
from logging.handlers import SysLogHandler | ||
syslog_handler = SysLogHandler() | ||
syslog_handler.setLevel(logging.WARNING) | ||
app.logger.addHandler(syslog_handler) | ||
|
||
|
||
config = { | ||
"development": DevelopmentConfig, | ||
"testing": TestingConfig, | ||
"production": ProductionConfig, | ||
"unix": UnixConfig, | ||
|
||
"default": DevelopmentConfig | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
# -*- coding: utf-8 -*- | ||
"""The app module, containing the app factory function.""" | ||
from flask import Flask | ||
|
||
from dataservice import commands | ||
from dataservice.extensions import db, migrate | ||
from dataservice.api.person.models import Person | ||
from config import config | ||
|
||
|
||
def create_app(config_name): | ||
""" | ||
An application factory | ||
""" | ||
app = Flask(__name__) | ||
app.url_map.strict_slashes = False | ||
app.config.from_object(config[config_name]) | ||
|
||
# Register Flask extensions | ||
register_extensions(app) | ||
register_shellcontext(app) | ||
register_commands(app) | ||
register_blueprints(app) | ||
|
||
return app | ||
|
||
|
||
def register_shellcontext(app): | ||
""" | ||
Register shell context objects | ||
""" | ||
|
||
def shell_context(): | ||
"""Shell context objects.""" | ||
return {'db': db, | ||
'Person': Person} | ||
|
||
app.shell_context_processor(shell_context) | ||
|
||
|
||
def register_commands(app): | ||
""" | ||
Register Click commands | ||
""" | ||
app.cli.add_command(commands.test) | ||
|
||
|
||
def register_extensions(app): | ||
""" | ||
Register Flask extensions | ||
""" | ||
|
||
# SQLAlchemy | ||
db.init_app(app) | ||
|
||
# Migrate | ||
migrate.init_app(app, db) | ||
|
||
|
||
def register_error_handlers(app): | ||
""" | ||
Register error handlers | ||
""" | ||
pass | ||
|
||
|
||
def register_blueprints(app): | ||
from dataservice.api import api_v1 | ||
app.register_blueprint(api_v1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
Primary API for interacting with the Kid's First Data Model. | ||
|
||
## Service-Wide Standards and Functionality | ||
|
||
### Field Masking | ||
|
||
Partial data fetching is supported via the `X-Fields` header. | ||
To specifiy that only some fields are to be returned, include a bracketed, | ||
coma-delimited list under the `X-Fields` header: | ||
|
||
`X-Fields: {kf_id, name}` | ||
|
||
Brackets may be nested to filter on nested fields: | ||
|
||
`X-Fields: {kf_id, name, type{format, extension}}` | ||
|
||
An asterisk may be used to specify all fields: | ||
|
||
`X-Fields: *` | ||
|
||
Or all sub-fields: | ||
|
||
`X-Fields: {kf_id, type{*}}` | ||
|
||
Or all root fields, but with only some sub-fields: | ||
|
||
`X-Fields: {*, type{format}}` | ||
|
||
|
||
|
||
### Pagination | ||
|
||
``` | ||
{ | ||
pages: [ | ||
{ "doc_id": 30, "value": "Lorem" }, | ||
{ "doc_id": 31, "value": "ipsum" }, | ||
{ "doc_id": 32, "value": "dolor" }, | ||
... | ||
{ "doc_id": 40, "value": "amet" } | ||
], | ||
from: 30, | ||
to: 40, | ||
results: 10, | ||
total: 1204, | ||
message: "Success", | ||
status: 200 | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
from flask import Blueprint | ||
from flask_restplus import Api | ||
from dataservice.api.person import person_api | ||
|
||
api_v1 = Blueprint('api', __name__, url_prefix='/v1') | ||
|
||
api = Api(api_v1, | ||
title='Kids First Data Service', | ||
description=open('dataservice/api/README.md').read(), | ||
version='0.1', | ||
default='', | ||
default_label='') | ||
|
||
api.add_namespace(person_api) | ||
|
||
|
||
@api.documentation | ||
def redoc_ui(): | ||
""" Uses ReDoc for swagger documentation """ | ||
docs_page = """<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>API Docs</title> | ||
<!-- needed for mobile devices --> | ||
<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
</head> | ||
<body> | ||
<redoc spec-url="{}"></redoc> | ||
<script src="https://rebilly.github.io/ReDoc/releases/latest/redoc.min.js"> | ||
</script> | ||
</body> | ||
</html> | ||
""".format(api.specs_url) | ||
return docs_page |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import uuid | ||
|
||
|
||
def assign_id(): | ||
return str(uuid.uuid4()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
from datetime import datetime | ||
from sqlalchemy.ext.declarative import declared_attr | ||
|
||
from dataservice.extensions import db | ||
from dataservice.api.common.id_service import assign_id | ||
|
||
|
||
class IDMixin: | ||
""" | ||
Defines base ID columns common on all Kids First tables | ||
""" | ||
_id = db.Column(db.Integer(), primary_key=True) | ||
kf_id = db.Column(db.String(32), unique=True, default=assign_id()) | ||
uuid = db.Column(db.String(32), unique=True, default=assign_id()) | ||
|
||
|
||
class TimestampMixin: | ||
""" | ||
Defines the common timestammp columns on all Kids First tables | ||
""" | ||
created_at = db.Column(db.DateTime(), default=datetime.now()) | ||
modified_at = db.Column(db.DateTime(), default=datetime.now()) | ||
|
||
|
||
class HasFileMixin: | ||
@declared_attr | ||
def file_id(cls): | ||
return db.Column('file_id', db.ForeignKey('file._id')) | ||
|
||
@declared_attr | ||
def files(cls): | ||
return db.relationship("File") | ||
|
||
|
||
class Base(db.Model, IDMixin, TimestampMixin): | ||
""" | ||
Defines base SQlAlchemy model class | ||
""" | ||
pass | ||
|
||
|
||
class File(Base): | ||
""" | ||
Defines a file | ||
""" | ||
__tablename__ = "file" | ||
name = db.Column(db.String(32)) | ||
data_type = db.Column(db.String(32)) | ||
size = db.Column(db.Integer(), default=0) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
A person is one of the central entities of the Kid's First DCC. | ||
|
||
### Fields | ||
|
||
`kf_id` - the unique identifier assigned by Kid's First used as the primary | ||
reference to this Person | ||
|
||
`source_name` - the identifier used by the original contributor of the data | ||
|
||
`date_created` - the date the person`s record was created in the DCC | ||
|
||
`date_modified` - the last date that the record's fields were modified. | ||
Restricted to fields of the entity itself, not any of it's related entities. | ||
|
||
### Identifiers | ||
|
||
The Kid's First DCC assigns a unique, internal identifier of the form: | ||
`KF-P000000` on creation of a new Person. This identifier is used accross the | ||
Kids First Data Service and Data Resource Portal It is expected that the Person | ||
also have an identifier unique to the study it came from. This field is to be | ||
captured in the `source_name` property of the Person upon creation. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from .resources import person_api |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
from dataservice.extensions import db | ||
from dataservice.api.common.model import Base | ||
|
||
|
||
class Person(Base): | ||
""" | ||
Person entity. | ||
:param _id: Unique id assigned by RDBMS | ||
:param kf_id: Unique id given by the Kid's First DCC | ||
:param external_id: Name given to person by contributor | ||
:param created_at: Time of object creation | ||
:param modified_at: Last time of object modification | ||
""" | ||
__tablename__ = "person" | ||
external_id = db.Column(db.String(32)) |
Oops, something went wrong.