import datetime from typing import Optional import flask from sqlalchemy import func, or_ from atlas_um.consts import NON_PRODUCTION_ENVS from atlas_um.extensions import notifications from atlas_um.helpers.either import Either, Right, Left from atlas_um.helpers.services import BaseLogicService from atlas_um.logs import logger from atlas_um.pgdb import ( DNAAccount, Auth0Account, DNAAccountExternalState, Auth0AccountExternalState, InternalUserDomain, ) from atlas_um.pgdb import pgdb from atlas_um.settings import Settings class NonActiveAccountsNotificationsService(BaseLogicService): MAX_ITEMS_IN_NOTIFICATION = 30 NOTIFICATIONS_CLAIM_NAME_EXTERNAL_ID = "extra_features" NOTIFICATIONS_CLAIM_VALUE_EXTERNAL_ID = "accounts-validation-notifications" def process(self) -> Optional[Either]: data = self.get_non_active_accounts_data() accounts = ( DNAAccount.query.activated() .by_claim_external_ids( Settings.RELATED_CLAIMS_NAMESPACE, self.NOTIFICATIONS_CLAIM_NAME_EXTERNAL_ID, self.NOTIFICATIONS_CLAIM_VALUE_EXTERNAL_ID, ) .all() ) for dna_account in accounts: self._send_notification(data, dna_account) return Right(None) def _send_notification(self, data, dna_account): if Settings.FLASK_ENV in NON_PRODUCTION_ENVS: environment_url = f"https://{Settings.DOMAIN}" else: environment_url = "" report_url = f"https://{Settings.DOMAIN}/accounts_validation/accounts_states_report" # noqa body = flask.render_template( "notifications/accounts_validation.html", dna_account=dna_account, data=data[: self.MAX_ITEMS_IN_NOTIFICATION], report_url=report_url, environment_url=environment_url, ) result = notifications.send_email( "Sony Music Product Design & Engineering - Accounts validation", dna_account.email, body, ) if result.is_left: msg = "Error sending accounts validation notification" logger.bind(dna_account=dna_account).error(msg) return Left(msg) @staticmethod def get_non_active_accounts_data(): domains_to_check = [Settings.MAIN_INTERNAL_DOMAIN] domains_to_check.extend( [item.domain for item in InternalUserDomain.query.all()] ) all_accounts_subquery = ( pgdb.session.query( DNAAccount.email.label("email"), DNAAccountExternalState.is_active.label("is_active"), DNAAccountExternalState.last_login.label("last_login"), ) .select_from(DNAAccount) .join( DNAAccountExternalState, DNAAccount.id == DNAAccountExternalState.dna_account_id, isouter=True, ) .where( func.split_part(DNAAccount.email, "@", 2).in_( domains_to_check ), or_( DNAAccount.expiration_date == None, # noqa DNAAccount.expiration_date > datetime.datetime.now().date(), ), ) .union( pgdb.session.query( Auth0Account.email.label("email"), Auth0AccountExternalState.is_active.label("is_active"), Auth0AccountExternalState.last_login.label("is_active"), ) .select_from(Auth0Account) .join( Auth0AccountExternalState, Auth0Account.id == Auth0AccountExternalState.auth0_account_id, # noqa isouter=True, ) .where( func.split_part(Auth0Account.email, "@", 2).in_( domains_to_check ), Auth0Account.blocked == False, # noqaq ) ) .subquery() ) accounts_query = ( pgdb.session.query( all_accounts_subquery.c.email, func.max(all_accounts_subquery.c.last_login), ) .select_from(all_accounts_subquery) .where(all_accounts_subquery.c.email != None) # noqa .group_by(all_accounts_subquery.c.email) .having( or_( func.bool_or(all_accounts_subquery.c.is_active) == False, # noqa func.bool_or(all_accounts_subquery.c.is_active) == None, # noqa ) ) .order_by(all_accounts_subquery.c.email) ) return accounts_query.all()