"""Push notifications views.""" from datetime import datetime from flask import Response, jsonify from flask.views import MethodView from flask_apispec import MethodResource, doc, marshal_with, use_kwargs from flask_sqlalchemy_replication import ReplicaType, set_replica from sqlalchemy import func from apollo_main_db.push_notifications.models import NotificationSetting, PushMessage, UserDeviceToken, \ UserNotificationSetting from auth import util as auth_util from core.exceptions import BadRequest from core.http_status import HTTP_201_CREATED, HTTP_204_NO_CONTENT from core.pagination import paginate from core.util import FilterMixin, get_request_json from main_db.base import session as db_session from push_notifications import serializers as push_serializers class UserDeviceRegisterView(MethodView): """Endpoint for registering user device""" def post(self): data = get_request_json(push_serializers.UserDeviceInput()) user_id = auth_util.get_user().user_id response = Response() device_token = db_session.query(UserDeviceToken).filter_by(user_id=user_id, token=data["token"]).first() if device_token and device_token.is_active: return response if device_token and not device_token.is_active: device_token.is_active = True else: db_session.add(UserDeviceToken(user_id=user_id, token=data["token"])) response.status_code = HTTP_201_CREATED # deactivate other user devices with the same device token db_session.query(UserDeviceToken).filter( UserDeviceToken.token == data["token"], UserDeviceToken.user_id != user_id ).update({UserDeviceToken.is_active: False}) db_session.commit() return response class UserDeviceUnRegisterView(MethodView): """Endpoint for unregistering user device""" def post(self): data = get_request_json(push_serializers.UserDeviceInput()) db_session.query(UserDeviceToken).filter_by(user_id=auth_util.get_user().user_id, token=data["token"]).update( {"is_active": False} ) db_session.commit() return Response() def get_push_message_response_schema(): """Get push message output schema.""" output_schema = push_serializers.PushMessageOutputItemSchema() output_schema.context = {"current_datetime": datetime.now()} return output_schema def process_push_message_response(data: list, *args, **kwargs) -> list: """Dump push message page.""" return get_push_message_response_schema().dump(data, many=True).data @doc("Endpoint to get all user's push messages.") class PushMessageAllView(MethodResource, FilterMixin): filter_serializer = push_serializers.FilterPushMessage @use_kwargs(push_serializers.PushMessageSchema, locations=("query",)) @marshal_with(push_serializers.PushMessageOutputSchema, code=200, description="User's push messages.", apply=False) @marshal_with(None, code=401, description="Authentication failed") @set_replica(ReplicaType.MASTER) @paginate(full_data=False, update_page=process_push_message_response) def get(self, **data): query = ( db_session.query(PushMessage) .filter(PushMessage.user_id == auth_util.get_user().user_id) .order_by(PushMessage.created_at.desc()) ) return self.filter_query(query) @doc("Endpoint to get user's specific push message.") class PushMessageView(MethodResource, FilterMixin): filter_serializer = push_serializers.FilterPushMessage @marshal_with( push_serializers.PushMessageOutputItemSchema, code=200, description="User's specific push message.", apply=False ) @marshal_with(None, code=401, description="Authentication failed") @set_replica(ReplicaType.MASTER) def get(self, push_id): query = ( db_session.query(PushMessage) .filter(PushMessage.user_id == auth_util.get_user().user_id) .order_by(PushMessage.created_at.desc()) ) query = self.filter_query(query) push_message = query.filter(PushMessage.id == push_id).first() return jsonify(get_push_message_response_schema().dump(push_message).data) class PushMessageBulkUpdateView(MethodView): """Endpoint for bulk updating Push Messages""" def put(self): get_request_json(push_serializers.PushMessageBulkInput()) return Response() class SettingsView(MethodView): """Endpoint for getting/setting user's notification preferences""" @set_replica(ReplicaType.MASTER) def get(self): sq = ( db_session.query(UserNotificationSetting.setting_id.label("setting_id")) .filter_by(user_id=auth_util.get_user().user_id) .subquery() ) data = ( db_session.query( NotificationSetting.id, NotificationSetting.code, (func.IF(sq.c.setting_id.is_(None), False, True)).label("enabled"), ) .outerjoin(sq, sq.c.setting_id == NotificationSetting.id) .all() ) return jsonify({"items": push_serializers.PushMessageSettingOutput().dump(data, many=True).data}) def post(self): setting_id = get_request_json(push_serializers.PushMessageSettingInput())["id"] user_id = auth_util.get_user().user_id parent_setting_id, = ( db_session.query(NotificationSetting.parent_id).filter(NotificationSetting.id == setting_id).one() ) saved_setting = ( db_session.query(UserNotificationSetting).filter_by(setting_id=setting_id, user_id=user_id).scalar() ) saved_parent_setting = ( db_session.query(UserNotificationSetting).filter_by(setting_id=parent_setting_id, user_id=user_id).scalar() if parent_setting_id else True ) if saved_setting or not saved_parent_setting: raise BadRequest db_session.add(UserNotificationSetting(user_id=user_id, setting_id=setting_id)) db_session.commit() return Response(status=HTTP_201_CREATED) def delete(self): setting_id = get_request_json(push_serializers.PushMessageSettingInput())["id"] user_id = auth_util.get_user().user_id if not db_session.query(UserNotificationSetting).filter_by(setting_id=setting_id, user_id=user_id).scalar(): raise BadRequest db_session.query(UserNotificationSetting).filter_by(user_id=user_id, setting_id=setting_id).delete() db_session.commit() return Response(status=HTTP_204_NO_CONTENT)