diff --git a/app/__init__.py b/app/__init__.py index 885f7376c..2fbdc29ab 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -60,6 +60,7 @@ def create_app(app_name=None): from app.accept_invite.rest import accept_invite from app.notifications_statistics.rest import notifications_statistics as notifications_statistics_blueprint from app.template_statistics.rest import template_statistics as template_statistics_blueprint + from app.events.rest import events as events_blueprint application.register_blueprint(service_blueprint, url_prefix='/service') application.register_blueprint(user_blueprint, url_prefix='/user') @@ -72,6 +73,7 @@ def create_app(app_name=None): application.register_blueprint(accept_invite, url_prefix='/invite') application.register_blueprint(notifications_statistics_blueprint) application.register_blueprint(template_statistics_blueprint) + application.register_blueprint(events_blueprint) return application diff --git a/app/dao/events_dao.py b/app/dao/events_dao.py new file mode 100644 index 000000000..d47237d3b --- /dev/null +++ b/app/dao/events_dao.py @@ -0,0 +1,6 @@ +from app import db + + +def dao_create_event(event): + db.session.add(event) + db.session.commit() diff --git a/app/events/__init__.py b/app/events/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/app/events/rest.py b/app/events/rest.py new file mode 100644 index 000000000..d3d38454e --- /dev/null +++ b/app/events/rest.py @@ -0,0 +1,22 @@ +from flask import ( + Blueprint, + jsonify, + request +) + +from app.errors import register_errors +from app.schemas import event_schema +from app.dao.events_dao import dao_create_event + +events = Blueprint('events', __name__, url_prefix='/events') +register_errors(events) + + +@events.route('', methods=['POST']) +def create_event(): + data = request.get_json() + event, errors = event_schema.load(data) + if errors: + return jsonify(result="error", message=errors), 400 + dao_create_event(event) + return jsonify(data=event_schema.dump(event).data), 201 diff --git a/app/models.py b/app/models.py index d644289bf..4318b50d8 100644 --- a/app/models.py +++ b/app/models.py @@ -35,13 +35,13 @@ class User(db.Model): index=False, unique=False, nullable=False, - default=datetime.datetime.now) + default=datetime.datetime.utcnow) updated_at = db.Column( db.DateTime, index=False, unique=False, nullable=True, - onupdate=datetime.datetime.now) + onupdate=datetime.datetime.utcnow) _password = db.Column(db.String, index=False, unique=False, nullable=False) mobile_number = db.Column(db.String, index=False, unique=False, nullable=False) password_changed_at = db.Column(db.DateTime, index=False, unique=False, nullable=True) @@ -414,3 +414,18 @@ class TemplateStatistics(db.Model): unique=False, nullable=False, default=datetime.datetime.utcnow) + + +class Event(db.Model): + + __tablename__ = 'events' + + id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + event_type = db.Column(db.String(255), nullable=False) + created_at = db.Column( + db.DateTime, + index=False, + unique=False, + nullable=False, + default=datetime.datetime.utcnow) + data = db.Column(JSON, nullable=False) diff --git a/app/schemas.py b/app/schemas.py index 9818e6a97..6909fa85c 100644 --- a/app/schemas.py +++ b/app/schemas.py @@ -325,6 +325,11 @@ class TemplateHistorySchema(ma.Schema): created_by_id = fields.UUID() +class EventSchema(BaseSchema): + class Meta: + model = models.Event + + user_schema = UserSchema() user_schema_load_json = UserSchema(load_json=True) service_schema = ServiceSchema() @@ -352,3 +357,4 @@ template_statistics_schema = TemplateStatisticsSchema() service_history_schema = ServiceHistorySchema() api_key_history_schema = ApiKeyHistorySchema() template_history_schema = TemplateHistorySchema() +event_schema = EventSchema() diff --git a/migrations/versions/0009_events_table.py b/migrations/versions/0009_events_table.py new file mode 100644 index 000000000..929eaebbc --- /dev/null +++ b/migrations/versions/0009_events_table.py @@ -0,0 +1,32 @@ +"""empty message + +Revision ID: 0009_events_table +Revises: 0008_archive_template +Create Date: 2016-04-26 13:08:42.892813 + +""" + +# revision identifiers, used by Alembic. +revision = '0009_events_table' +down_revision = '0008_archive_template' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +def upgrade(): + ### commands auto generated by Alembic - please adjust! ### + op.create_table('events', + sa.Column('id', postgresql.UUID(as_uuid=True), nullable=False), + sa.Column('event_type', sa.String(length=255), nullable=False), + sa.Column('created_at', sa.DateTime(), nullable=False), + sa.Column('data', postgresql.JSON(), nullable=False), + sa.PrimaryKeyConstraint('id') + ) + ### end Alembic commands ### + + +def downgrade(): + ### commands auto generated by Alembic - please adjust! ### + op.drop_table('events') + ### end Alembic commands ### diff --git a/tests/app/dao/test_events_dao.py b/tests/app/dao/test_events_dao.py new file mode 100644 index 000000000..3f6226531 --- /dev/null +++ b/tests/app/dao/test_events_dao.py @@ -0,0 +1,19 @@ + +from app.dao.events_dao import dao_create_event + +from app.models import Event + + +def test_create_event(notify_db, notify_db_session): + assert Event.query.count() == 0 + data = { + 'event_type': 'sucessful_login', + 'data': {'something': 'random', 'in_fact': 'could be anything'} + } + + event = Event(**data) + dao_create_event(event) + + assert Event.query.count() == 1 + event_from_db = Event.query.first() + assert event == event_from_db diff --git a/tests/app/events/__init__.py b/tests/app/events/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/app/events/test_rest.py b/tests/app/events/test_rest.py new file mode 100644 index 000000000..0568d26a4 --- /dev/null +++ b/tests/app/events/test_rest.py @@ -0,0 +1,26 @@ +import json +from tests import create_authorization_header + + +def test_create_event(notify_api): + with notify_api.test_request_context(): + with notify_api.test_client() as client: + data = { + 'event_type': 'sucessful_login', + 'data': {'something': 'random', 'in_fact': 'could be anything'} + } + path = '/events' + auth_header = create_authorization_header( + path=path, + method='POST', + request_body=json.dumps(data)) + headers = [('Content-Type', 'application/json'), auth_header] + response = client.post( + path, + data=json.dumps(data), + headers=headers) + assert response.status_code == 201 + resp_json = json.loads(response.get_data(as_text=True))['data'] + assert resp_json['event_type'] == data['event_type'] + assert resp_json['data']['something'] == data['data']['something'] + assert resp_json['data']['in_fact'] == data['data']['in_fact']