-
Notifications
You must be signed in to change notification settings - Fork 9
CON-297 Refresh channels on a bouquet #25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v2
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| """allow null values on channels table | ||
|
|
||
| Revision ID: 9f4ff449f825 | ||
| Revises: ffc544c2bbe6 | ||
| Create Date: 2019-09-11 14:19:44.002569 | ||
|
|
||
| """ | ||
| from alembic import op | ||
| import sqlalchemy as sa | ||
|
|
||
|
|
||
| # revision identifiers, used by Alembic. | ||
| revision = '9f4ff449f825' | ||
| down_revision = 'ffc544c2bbe6' | ||
| branch_labels = None | ||
| depends_on = None | ||
|
|
||
|
|
||
| def upgrade(): | ||
| # ### commands auto generated by Alembic - please adjust! ### | ||
| with op.batch_alter_table("channels") as batch: | ||
| batch.alter_column('channel_id', | ||
| existing_type=sa.VARCHAR(), | ||
| nullable=True) | ||
| batch.alter_column('extra_atrributes', | ||
| existing_type=sa.VARCHAR(), | ||
| nullable=True) | ||
| batch.alter_column('resource_id', | ||
| existing_type=sa.VARCHAR(), | ||
| nullable=True) | ||
| # ### end Alembic commands ### | ||
|
|
||
|
|
||
| def downgrade(): | ||
| # ### commands auto generated by Alembic - please adjust! ### | ||
| with op.batch_alter_table("channels") as batch: | ||
| batch.alter_column('resource_id', | ||
| existing_type=sa.VARCHAR(), | ||
| nullable=False) | ||
| batch.alter_column('extra_atrributes', | ||
| existing_type=sa.VARCHAR(), | ||
| nullable=False) | ||
| batch.alter_column('channel_id', | ||
| existing_type=sa.VARCHAR(), | ||
| nullable=False) | ||
| # ### end Alembic commands ### |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,25 @@ | ||
| from flask import make_response, jsonify | ||
| from flask_restful import Resource | ||
| from api.v2.helpers.bouquets.bouquets_helper import query_all_bouquets | ||
| from api.v2.helpers.bouquets.bouquets_helper import ( | ||
| query_all_bouquets, refresh_bouquet_channels) | ||
|
|
||
|
|
||
| class Bouquets(Resource): | ||
| def get(self): | ||
| bouquets = query_all_bouquets() | ||
|
|
||
| return make_response(jsonify({"bouquets": bouquets}), 200) | ||
|
|
||
|
|
||
| class RefreshChannels(Resource): | ||
| def post(self, api_type, bouquet_id): | ||
| response = make_response( | ||
| jsonify( | ||
| {'Error': 'Endpoint accepts only graphql_api/restful_api'} | ||
| ), 404) | ||
| if (api_type == 'restful_api') or (api_type == 'graphql_api'): | ||
| refresh = refresh_bouquet_channels(api_type, bouquet_id) | ||
| response = make_response( | ||
| jsonify(refresh['response']), refresh['code']) | ||
|
|
||
| return response |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,9 @@ | ||
| import requests | ||
| from api.v2.models.bouquets.bouquets_model import Bouquets as BouquetsModel | ||
| from api.v2.models.channels.channels_model import Channels as ChannelsModel | ||
| from api.v2.models.bouquets.bouquets_schema import BouquetsSchema | ||
| from api.v2.helpers.channels.channels_helper import ( | ||
| query_bouquet_channels, query_channel) | ||
|
|
||
|
|
||
| def query_all_bouquets(): | ||
|
|
@@ -9,3 +13,87 @@ def query_all_bouquets(): | |
| bouquets = BouquetsSchema(many=True).dump(all_bouquets) | ||
|
|
||
| return bouquets | ||
|
|
||
|
|
||
| def query_bouquet(bouquet_id): | ||
| bouquet_query = BouquetsModel.query.filter_by( | ||
| state='active', id=bouquet_id).first() | ||
| bouquet = BouquetsSchema().dump(bouquet_query) | ||
| return bouquet | ||
|
|
||
|
|
||
| def refresh_bouquet_channels(api_type, bouquet_id): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This operation can take a while if you are waiting for a response. Let's consider using Celery to queue requests and create a notifications table to store tasks statuses which users will use to monitor their tasks. |
||
| """helper function for refreshing channels""" | ||
| response = {'response': {'Error': 'Bouquet not found!'}, 'code': 404} | ||
| bouquet = query_bouquet(bouquet_id) | ||
| if bouquet: | ||
| response = {'response': | ||
| {"Error": "Refresh endpoint not responding appropriatly"}, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please correct typo |
||
| 'code': 424 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any reason why we are using this HTTP status code? It seems to represent
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is to check if the refresh URL endpoint is responding as required. If an error occurs at this point it is to be because of that dependency and not necessarily on our endpoint |
||
| } | ||
| bouquet_channels = fetch_bouquet_channels( | ||
| api_type, bouquet['refresh_url']) | ||
| if bouquet_channels: | ||
| channel_update = update_channels(bouquet_id, bouquet_channels) | ||
| response = {'response': { | ||
| "Success": channel_update}, 'code': 200} | ||
|
|
||
| return response | ||
|
|
||
|
|
||
| def fetch_bouquet_channels(api_type, refresh_url): | ||
| if api_type == 'restful_api': | ||
| return restful_channels(refresh_url) | ||
|
|
||
| return graphql_channels(refresh_url) | ||
|
|
||
|
|
||
| def graphql_channels(refresh_url): | ||
| """fetch channels from bouquets with grapghql endpoints""" | ||
| channels_query = ( | ||
| { | ||
| "query": | ||
| "{ allChannels { channels { calendarId, firebaseToken } } }" | ||
| }) | ||
| try: | ||
| response = requests.get(url=refresh_url, json=channels_query) | ||
| channels = response.json()['data']['allChannels']['channels'] | ||
| except Exception: | ||
| channels = False | ||
| return channels | ||
|
|
||
|
|
||
| def restful_channels(refresh_url): | ||
| """fetch channels from bouquets with restful endpoints""" | ||
| try: | ||
| response = requests.get(refresh_url) | ||
| channels = response.json()['channels'] | ||
| except Exception: | ||
| channels = False | ||
| return channels | ||
|
|
||
|
|
||
| def update_channels(bouquet_id, bouquet_channels): | ||
| subscribed_channels = query_bouquet_channels(bouquet_id) | ||
| for channel in bouquet_channels: | ||
| existing_channel = filter( | ||
| lambda subscribed_channel: | ||
| subscribed_channel['calendar_id'] == channel['calendarId'], | ||
| subscribed_channels) | ||
| if not list(existing_channel): | ||
| ChannelsModel(channel_id="", calendar_id=channel['calendarId'], | ||
| resource_id="", | ||
| extra_atrributes=channel['firebaseToken'], | ||
| bouquet_id=bouquet_id).save() | ||
|
|
||
| for channel in subscribed_channels: | ||
| db_channel = query_channel(channel['id']) | ||
| existing_channel = filter( | ||
| lambda bouquet_channel: | ||
| bouquet_channel['calendarId'] == channel['calendar_id'], | ||
| bouquet_channels) | ||
| if not list(existing_channel): | ||
| db_channel.state = 'deleted' | ||
| db_channel.save() | ||
|
|
||
| return 'Bouquet channels refreshed succesfully' | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please let's fix the typo
boquets, it should bebouquet.