Skip to content
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""subscriber and subscription tables

Revision ID: b95e7b9d7311
Revises: e511d62f38b7
Create Date: 2019-12-19 12:02:14.160467

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = 'b95e7b9d7311'
down_revision = 'e511d62f38b7'
branch_labels = None
depends_on = None


def upgrade():
op.create_table('subscribers',
sa.Column('date_created', sa.DateTime(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True),
sa.Column('date_updated', sa.DateTime(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True),
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('subscriber_name', sa.Text(), nullable=False),
sa.Column('username', sa.Text(), nullable=False),
sa.Column('password', sa.Text(), nullable=False),
sa.Column('notification_url', sa.Text(), nullable=False),
sa.Column('subscription_method_id', sa.Integer(), nullable=True),
sa.Column('bouquet_id', sa.Integer(), nullable=True),
sa.PrimaryKeyConstraint('id'),
sa.ForeignKeyConstraint(['subscription_method_id'], ['subscriptions.id'], name='fk_subscribers_subscriptions', onupdate='CASCADE', ondelete='CASCADE'),
sa.ForeignKeyConstraint(['bouquet_id'], ['bouquets.id'], name='fk_subscribers_bouquets', onupdate='CASCADE', ondelete='CASCADE')
),
op.create_table('subscriptions',
sa.Column('date_created', sa.DateTime(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True),
sa.Column('date_updated', sa.DateTime(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True),
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.Text(), nullable=False),
sa.PrimaryKeyConstraint('id')
)


def downgrade():
op.drop_table('subscribers'),
op.drop_table('subscriptions')
3 changes: 2 additions & 1 deletion api/v2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from flask import Blueprint

from api.v2.controllers.channels.channels_controller import Channels
from api.v2.controllers.bouquets.bouquets_controller import Bouquets
from api.v2.controllers.bouquets.bouquets_controller import Bouquets, SendNotifications
from api.v2.controllers.logs.logs_controller import Logs


Expand All @@ -15,4 +15,5 @@

mrm_push.add_resource(Channels, '/channels', strict_slashes=False)
mrm_push.add_resource(Bouquets, '/bouquets', strict_slashes=False)
mrm_push.add_resource(SendNotifications, '/notifications', strict_slashes=False)
mrm_push.add_resource(Logs, '/logs', strict_slashes=False)
34 changes: 33 additions & 1 deletion api/v2/controllers/bouquets/bouquets_controller.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import requests
import datetime

from flask import make_response, jsonify, request
from flask_restful import Resource

from api.v2.helpers.bouquets.bouquets_helper import query_all_bouquets, query_bouquet
from api.v2.helpers.channels.channels_helper import query_channel
from api.v2.helpers.subscriber.subscriber_helper import get_subscribers
from api.v2.models.bouquets.bouquets_model import Bouquets as BouquetsModel
from api.v2.models.logs.logs_model import Logs
from api.v2.utilities.validators import validate_bouquet_adding
from api.v2.helpers.credentials import check_bouquet_credentials

Expand Down Expand Up @@ -42,5 +48,31 @@ def delete(self):
if not bouquet:
return make_response(jsonify({'message': 'The bouquet you want to delete is not found'}), 404)
BouquetsModel.delete_bouquet(BouquetsModel, bouquet_id)
return make_response(jsonify({'message': 'The bouquet was deleted successfully'}), 200)
return make_response(jsonify({'message': 'The bouquet was deleted successfully'}), 200)


class SendNotifications(Resource):

def post(self):
"""function to receive notifications and send them to subscriber"""
resource_id = request.headers['X-Goog-Resource-ID']
channel = query_channel(resource_id)
if not channel:
return make_response(jsonify({'message': 'Channel not found'}), 404)

bouquet_id = channel['bouquet_id']
subscribers = get_subscribers(bouquet_id)
if not subscribers:
return make_response(jsonify({'message': 'Subscribers not found'}), 404)

for subscriber in subscribers:
calendar_id = channel['calendar_id']
notification_url = subscriber['notification_url']
results = requests.post(url=notification_url, json=calendar_id)
Logs.save_log(timestamp = datetime.datetime.now(),
calendar_id=calendar_id,
subscriber_name = subscriber['subscriber_name'],
subscription_method = subscriber['subscription'].name,
payload = results.status_code)

return make_response(jsonify({'message': 'Notifications sent'}), 200)
7 changes: 7 additions & 0 deletions api/v2/helpers/channels/channels_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,10 @@ def query_all_channels():
channels = ChannelsSchema(many=True).dump(all_channels)

return channels

def query_channel(resource_id):
channel = ChannelsModel.query.filter_by(resource_id=resource_id).first()
if channel:
return ChannelsSchema(many=False).dump(channel)

return None
Empty file.
16 changes: 16 additions & 0 deletions api/v2/helpers/subscriber/subscriber_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from api.v2.models.subscriber.subscriber_model import Subscribers as SubscriberModel
from api.v2.models.subscriber.subscriber_schema import SubscribersSchema

def get_subscribers(bouquet_id):
subscribers = SubscriberModel.query.filter_by(bouquet_id=bouquet_id).all()
if subscribers:
return SubscribersSchema(many=True).dump(subscribers)

return None

def get_subscriber(suscriber_id):
subscriber = SubscriberModel.query.filter_by(id=suscriber_id).first()
if subscriber:
return SubscribersSchema(many=False).dump(subscriber)

return None
Empty file.
30 changes: 30 additions & 0 deletions api/v2/models/subscriber/subscriber_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from sqlalchemy import (Column, String, Integer, Enum, ForeignKey, Text)
from sqlalchemy.schema import Sequence
from sqlalchemy.orm import relationship

from api.v2.helpers.database import Base
from api.v2.utilities.utility import Utility, StateType

from api.v2.models.subscription_method.subscription_method_model import Subscriptions


class Subscribers(Base, Utility):
__tablename__ = 'subscribers'
id = Column(Integer, Sequence('subscribers_id_seq', start=1, increment=1), primary_key=True)
subscriber_name = Column(Text, nullable=False)
username = Column(Text, nullable=False)
password = Column(Text, nullable=False)
notification_url = Column(Text, nullable=False)
subscription_method_id = Column(Integer, ForeignKey('subscriptions.id',
name='fk_subscribers_subscriptions', ondelete='CASCADE'))
bouquet_id = Column(Integer, ForeignKey('bouquets.id',
name='fk_subscribers_bouquets', ondelete='CASCADE'))
subscription = relationship('Subscriptions', backref='subscriptions')

def __init__(self, **kwargs):
self.subscriber_name = kwargs['subscriber_name']
self.username = kwargs['username']
self.password = kwargs['password']
self.notification_url = kwargs['notification_url']
self.subscription_method_id = kwargs['subscription_method_id']
self.bouquet_id = kwargs['bouquet_id']
9 changes: 9 additions & 0 deletions api/v2/models/subscriber/subscriber_schema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from ma import ma
from api.v2.models.subscriber.subscriber_model import Subscribers


class SubscribersSchema(ma.Schema):
class Meta:
model = Subscribers
fields = ("id", "subscriber_name", "username",
"notification_url", "subscription_method_id", "bouquet_id", "subscription")
Empty file.
15 changes: 15 additions & 0 deletions api/v2/models/subscription_method/subscription_method_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from sqlalchemy import (Column, String, Integer, Enum, ForeignKey, Text)
from sqlalchemy.schema import Sequence
from sqlalchemy.orm import relationship

from api.v2.helpers.database import Base
from api.v2.utilities.utility import Utility, StateType


class Subscriptions(Base, Utility):
__tablename__ = 'subscriptions'
id = Column(Integer, autoincrement=True, primary_key=True)
name = Column(Text, nullable=False)

def __init__(self, **kwargs):
self.name = kwargs['name']
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from ma import ma
from api.v2.models.subscription_method.subscription_method_model import Subscriptions


class SubscribersSchema(ma.Schema):
class Meta:
model = Subscriptions
fields = ("id", "name")
19 changes: 19 additions & 0 deletions tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
from api.v2.helpers.database import engine, db_session, Base
from api.v2.models.channels.channels_model import Channels
from api.v2.models.bouquets.bouquets_model import Bouquets
from api.v2.models.subscriber.subscriber_model import Subscribers
from api.v2.models.subscription_method.subscription_method_model import Subscriptions
from api.v2.models.logs.logs_model import Logs

sys.path.append(os.getcwd())
Expand Down Expand Up @@ -144,10 +146,27 @@ def setUp(self):
calendar_id="emilereas@gmail.com",
resource_id="9ty4bejkkfvdw",
extra_atrributes='t284nff94nf', bouquet_id=1)

channel_two = Channels(channel_id="564dfg67jn56h7jh6n",
calendar_id="emilereasw@gmail.com",
resource_id="9ty4bejkkfvdww",
extra_atrributes='t284nff94nfn', bouquet_id=2)

subscription = Subscriptions(name="compact")

subscriber = Subscribers(subscriber_name="Manzi",
username="manzif6",
password="password1",
notification_url='https://notificati.com',
subscription_method_id=1,
bouquet_id=1)
subscription.save()
channel.save()
channel_two.save()
bouquet.save()
bouquet_two.save()
log.save()
subscriber.save()

db_session.commit()

Expand Down
33 changes: 32 additions & 1 deletion tests/test_bouquets/test_bouquets.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,18 @@

from tests.base import BaseTestCase

from api.v2.controllers.bouquets.bouquets_controller import Bouquets
from api.v2.controllers.bouquets.bouquets_controller import Bouquets, SendNotifications

headers = {
'Content-Type': 'application/json',
'Token': 'token',
'X-Goog-Channel-ID': 123456,
'X-Goog-Channel-Token': 'fmdpe5wgN',
'X-Goog-Channel-Expiration': '2019-07-12T17:15:38Z',
'X-Goog-Resource-ID': '9ty4bejkkfvdw',
'X-Goog-Resource-URI': 'andela.com_37343037343034@resource.calendar.google.com',
'X-Goog-Message-Number': 1
}

class TestBouquets(BaseTestCase):
def test_get_all_bouquets(self):
Expand Down Expand Up @@ -74,3 +85,23 @@ def test_delete_bouquet_with_invalid_id(self):
response = self.app_test.delete("/v2/bouquets?bouquet_id=mmm")
self.assertTrue(b"The bouquet id should be an integer. Try again" in response.data)
self.assertEqual(response.status_code, 400)

def test_get_notifications_with_no_channels(self):
# Should return 404 when there is no channels
headers['X-Goog-Resource-ID'] = '5CcS2uZQikVsiOG7oeB4gx0oLrcmm'
response = self.app_test.post("/v2/notifications", headers=headers)
self.assertTrue(b"Channel not found" in response.data)
self.assertEqual(response.status_code, 404)

def test_get_notifications_with_no_subscribers(self):
# Should return 404 when there is no subscribers
headers['X-Goog-Resource-ID'] = '9ty4bejkkfvdww'
response = self.app_test.post("/v2/notifications", headers=headers)
self.assertTrue(b"Subscribers not found" in response.data)
self.assertEqual(response.status_code, 404)

def test_get_notifications_with_channels(self):
# Should return 200 when the notification has been sent
response = self.app_test.post("/v2/notifications", headers=headers)
self.assertTrue(b"Notifications sent" in response.data)
self.assertEqual(response.status_code, 200)