From a829074584312402956b746196dcd95a00b4ac84 Mon Sep 17 00:00:00 2001 From: MrMeeb Date: Wed, 6 Nov 2024 12:00:08 +0000 Subject: [PATCH] 4.57.2 --- app/app/account_linking.py | 20 +++++++++++++ app/app/dashboard/views/lifetime_licence.py | 2 +- ...49dde9_preserve_user_id_on_alias_delete.py | 28 +++++++++++++++++++ ...210efa3_revert_user_id_in_deleted_alias.py | 28 +++++++++++++++++++ app/oneshot/send_lifetime_user_events.py | 28 ++++++++++--------- app/oneshot/send_plan_change_events.py | 24 +++++----------- 6 files changed, 99 insertions(+), 31 deletions(-) create mode 100644 app/migrations/versions/2024_110610_4882cc49dde9_preserve_user_id_on_alias_delete.py create mode 100644 app/migrations/versions/2024_110612_bc9aa210efa3_revert_user_id_in_deleted_alias.py diff --git a/app/app/account_linking.py b/app/app/account_linking.py index 02160e6..56b1da8 100644 --- a/app/app/account_linking.py +++ b/app/app/account_linking.py @@ -3,12 +3,15 @@ from dataclasses import dataclass from enum import Enum from typing import Optional +import arrow from arrow import Arrow from newrelic import agent from sqlalchemy import or_ from app.db import Session from app.email_utils import send_welcome_email +from app.events.event_dispatcher import EventDispatcher +from app.events.generated.event_pb2 import UserPlanChanged, EventContent from app.partner_user_utils import create_partner_user, create_partner_subscription from app.utils import sanitize_email, canonicalize_email from app.errors import ( @@ -54,6 +57,21 @@ class LinkResult: strategy: str +def send_user_plan_changed_event(partner_user: PartnerUser) -> Optional[int]: + subscription_end = partner_user.user.get_active_subscription_end( + include_partner_subscription=False + ) + end_timestamp = None + if partner_user.user.lifetime: + end_timestamp = arrow.get("2038-01-01").timestamp + elif subscription_end: + end_timestamp = subscription_end.timestamp + event = UserPlanChanged(plan_end_time=end_timestamp) + EventDispatcher.send_event(partner_user.user, EventContent(user_plan_change=event)) + Session.flush() + return end_timestamp + + def set_plan_for_partner_user(partner_user: PartnerUser, plan: SLPlan): sub = PartnerSubscription.get_by(partner_user_id=partner_user.id) if plan.type == SLPlanType.Free: @@ -88,6 +106,8 @@ def set_plan_for_partner_user(partner_user: PartnerUser, plan: SLPlan): action=UserAuditLogAction.SubscriptionExtended, message="Extended partner subscription", ) + Session.flush() + send_user_plan_changed_event(partner_user) Session.commit() diff --git a/app/app/dashboard/views/lifetime_licence.py b/app/app/dashboard/views/lifetime_licence.py index d853d18..918144a 100644 --- a/app/app/dashboard/views/lifetime_licence.py +++ b/app/app/dashboard/views/lifetime_licence.py @@ -47,7 +47,7 @@ def lifetime_licence(): user=current_user, content=EventContent( user_plan_change=UserPlanChanged( - plan_end_time=arrow.get("2100-01-01").timestamp + plan_end_time=arrow.get("2038-01-01").timestamp ) ), ) diff --git a/app/migrations/versions/2024_110610_4882cc49dde9_preserve_user_id_on_alias_delete.py b/app/migrations/versions/2024_110610_4882cc49dde9_preserve_user_id_on_alias_delete.py new file mode 100644 index 0000000..df68db1 --- /dev/null +++ b/app/migrations/versions/2024_110610_4882cc49dde9_preserve_user_id_on_alias_delete.py @@ -0,0 +1,28 @@ +"""Preserve user id on alias delete + +Revision ID: 4882cc49dde9 +Revises: 32f25cbf12f6 +Create Date: 2024-11-06 10:10:40.235991 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '4882cc49dde9' +down_revision = '32f25cbf12f6' +branch_labels = None +depends_on = None + + +def upgrade(): + op.add_column('deleted_alias', sa.Column('user_id', sa.Integer(), server_default=None, nullable=True)) + with op.get_context().autocommit_block(): + op.create_index('ix_deleted_alias_user_id_created_at', 'deleted_alias', ['user_id', 'created_at'], unique=False, postgresql_concurrently=True) + + +def downgrade(): + with op.get_context().autocommit_block(): + op.drop_index('ix_deleted_alias_user_id_created_at', table_name='deleted_alias') + op.drop_column('deleted_alias', 'user_id') diff --git a/app/migrations/versions/2024_110612_bc9aa210efa3_revert_user_id_in_deleted_alias.py b/app/migrations/versions/2024_110612_bc9aa210efa3_revert_user_id_in_deleted_alias.py new file mode 100644 index 0000000..8de4ae2 --- /dev/null +++ b/app/migrations/versions/2024_110612_bc9aa210efa3_revert_user_id_in_deleted_alias.py @@ -0,0 +1,28 @@ +"""Revert user id on deleted alias + +Revision ID: bc9aa210efa3 +Revises: 4882cc49dde9 +Create Date: 2024-11-06 12:44:44.129691 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'bc9aa210efa3' +down_revision = '4882cc49dde9' +branch_labels = None +depends_on = None + + +def upgrade(): + with op.get_context().autocommit_block(): + op.drop_index('ix_deleted_alias_user_id_created_at', table_name='deleted_alias') + op.drop_column('deleted_alias', 'user_id') + + +def downgrade(): + op.add_column('deleted_alias', sa.Column('user_id', sa.Integer(), server_default=None, nullable=True)) + with op.get_context().autocommit_block(): + op.create_index('ix_deleted_alias_user_id_created_at', 'deleted_alias', ['user_id', 'created_at'], unique=False, postgresql_concurrently=True) diff --git a/app/oneshot/send_lifetime_user_events.py b/app/oneshot/send_lifetime_user_events.py index a280f32..a1b0730 100644 --- a/app/oneshot/send_lifetime_user_events.py +++ b/app/oneshot/send_lifetime_user_events.py @@ -7,7 +7,7 @@ from sqlalchemy import func from app.events.event_dispatcher import EventDispatcher from app.events.generated.event_pb2 import UserPlanChanged, EventContent -from app.models import PartnerUser +from app.models import PartnerUser, User from app.db import Session parser = argparse.ArgumentParser( @@ -27,25 +27,27 @@ if max_pu_id == 0: max_pu_id = Session.query(func.max(PartnerUser.id)).scalar() print(f"Checking partner user {pu_id_start} to {max_pu_id}") -step = 100 +step = 1000 done = 0 start_time = time.time() with_lifetime = 0 for batch_start in range(pu_id_start, max_pu_id, step): - partner_users = ( - Session.query(PartnerUser).filter( - PartnerUser.id >= batch_start, PartnerUser.id < batch_start + step + users = ( + Session.query(User) + .join(PartnerUser, PartnerUser.user_id == User.id) + .filter( + PartnerUser.id >= batch_start, + PartnerUser.id < batch_start + step, + User.lifetime == True, # noqa :E712 ) ).all() - for partner_user in partner_users: - done += 1 - if not partner_user.user.lifetime: + for user in users: + # Just in case the == True cond is wonky + if not user.lifetime: continue with_lifetime += 1 - event = UserPlanChanged(plan_end_time=arrow.get("2100-01-01").timestamp) - EventDispatcher.send_event( - partner_user.user, EventContent(user_plan_change=event) - ) + event = UserPlanChanged(plan_end_time=arrow.get("2038-01-01").timestamp) + EventDispatcher.send_event(user, EventContent(user_plan_change=event)) Session.flush() Session.commit() elapsed = time.time() - start_time @@ -55,6 +57,6 @@ for batch_start in range(pu_id_start, max_pu_id, step): time_remaining = remaining / time_per_alias hours_remaining = time_remaining / 60.0 print( - f"\PartnerUser {batch_start}/{max_pu_id} {done} {hours_remaining:.2f} mins remaining" + f"\PartnerUser {batch_start}/{max_pu_id} {with_lifetime} {hours_remaining:.2f} mins remaining" ) print(f"With SL lifetime {with_lifetime}") diff --git a/app/oneshot/send_plan_change_events.py b/app/oneshot/send_plan_change_events.py index 2afae40..50e38a7 100644 --- a/app/oneshot/send_plan_change_events.py +++ b/app/oneshot/send_plan_change_events.py @@ -5,8 +5,7 @@ import time import arrow from sqlalchemy import func -from app.events.event_dispatcher import EventDispatcher -from app.events.generated.event_pb2 import UserPlanChanged, EventContent +from app.account_linking import send_user_plan_changed_event from app.models import PartnerUser from app.db import Session @@ -39,21 +38,12 @@ for batch_start in range(pu_id_start, max_pu_id, step): ) ).all() for partner_user in partner_users: - subscription_end = partner_user.user.get_active_subscription_end( - include_partner_subscription=False - ) - end_timestamp = None - if partner_user.user.lifetime: - with_lifetime += 1 - end_timestamp = arrow.get("2100-01-01").timestamp - elif subscription_end: - with_premium += 1 - end_timestamp = subscription_end.timestamp - event = UserPlanChanged(plan_end_time=end_timestamp) - EventDispatcher.send_event( - partner_user.user, EventContent(user_plan_change=event) - ) - Session.flush() + subscription_end = send_user_plan_changed_event(partner_user) + if subscription_end is not None: + if subscription_end > arrow.get("2038-01-01").timestamp: + with_lifetime += 1 + else: + with_premium += 1 updated += 1 Session.commit() elapsed = time.time() - start_time