1- import asyncio
21import calendar
32import codecs
43import csv
76import os
87import tracemalloc
98import uuid
10- from functools import wraps
11- from typing import BinaryIO , TypeVar , cast
9+ from typing import BinaryIO , Optional , TypeVar , cast
1210
1311import typer
1412from pydantic import parse_obj_as
3937from apps .workspaces .db .schemas .user_applet_access import UserAppletAccessSchema
4038from apps .workspaces .domain .constants import Role
4139from config import settings
40+ from infrastructure .commands .utils import coro
4241from infrastructure .database import atomic , session_manager
4342from infrastructure .dependency .cdn import get_operations_bucket
4443from infrastructure .utility import CDNClient , ObjectNotFoundError
@@ -132,18 +131,12 @@ def is_last_day_of_month(date: datetime.date):
132131 return date .day == mdays [date .month ]
133132
134133
135- def coro (f ):
136- @wraps (f )
137- def wrapper (* args , ** kwargs ):
138- return asyncio .run (f (* args , ** kwargs ))
139-
140- return wrapper
141-
142-
143- def ensure_configured ():
144- if not APPLET_ID :
134+ def get_applet_id (applet_id : uuid .UUID | None = None ) -> uuid .UUID :
135+ _applet_id = str (applet_id ) if applet_id else APPLET_ID
136+ if not _applet_id :
145137 print ("[bold red]Error: applet export not configured[/bold red]" )
146138 exit (1 )
139+ return uuid .UUID (_applet_id )
147140
148141
149142def create_csv (data : list [dict ], columns : list | None = None , append_to : BinaryIO | None = None ) -> BinaryIO | None :
@@ -170,7 +163,7 @@ async def save_csv(path: str, data: list[dict], cdn_client: CDNClient, columns:
170163 await cdn_client .upload (path , f )
171164
172165
173- async def _export_flows ():
166+ async def _export_flows (applet_id : uuid . UUID , path_prefix : str ):
174167 """
175168 select
176169 split_part(fh.applet_id , '_', 1) applet_id,
@@ -200,7 +193,7 @@ async def _export_flows():
200193 )
201194 .join (FlowItemHistory , FlowItemHistory .activity_flow_id == FlowHistory .id_version )
202195 .join (ActivityHistory , ActivityHistory .id_version == FlowItemHistory .activity_id )
203- .where (FlowHistory .applet_id .like (f"{ APPLET_ID } _%" ))
196+ .where (FlowHistory .applet_id .like (f"{ applet_id } _%" ))
204197 .order_by (text ("applet_version" ), FlowHistory .order , FlowItemHistory .order )
205198 )
206199 res = await session .execute (
@@ -210,7 +203,7 @@ async def _export_flows():
210203 data = res .all ()
211204
212205 cdn_client = await get_operations_bucket ()
213- key = cdn_client .generate_key (PATH_PREFIX , str (APPLET_ID ), PATH_FLOW_FILE_NAME )
206+ key = cdn_client .generate_key (path_prefix , str (applet_id ), PATH_FLOW_FILE_NAME )
214207 await save_csv (key , parse_obj_as (list [dict ], data ), cdn_client )
215208
216209
@@ -219,22 +212,28 @@ async def _export_flows():
219212 f' flow data as csv file'
220213)
221214@coro
222- async def export_flows ():
215+ async def export_flows (
216+ applet_id : Optional [uuid .UUID ] = typer .Option (None , "--applet_id" , "-a" ),
217+ path_prefix : Optional [str ] = typer .Option (PATH_PREFIX , "--path-prefix" , "-p" ),
218+ ):
223219 """
224220 Create and upload to s3 csv file with flow data
225221 """
226- ensure_configured ()
227- print ("Flow export start" )
222+ assert path_prefix
223+ applet_id = get_applet_id (applet_id )
224+ print (f"Flow export start { applet_id } " )
228225 tracemalloc .start ()
229- await _export_flows ()
226+ await _export_flows (applet_id , path_prefix )
230227 _ , peak = tracemalloc .get_traced_memory ()
231228 tracemalloc .stop ()
232229 print ("Flow export finished" )
233230 print ("Peak memory usage:" , peak )
234231
235232
236233##### Daily user flow schedule stuff
237- async def get_user_flow_events (session : AsyncSession , scheduled_date : datetime .date ) -> list [FlowEventRawRow ]:
234+ async def get_user_flow_events (
235+ session : AsyncSession , scheduled_date : datetime .date , applet_id : uuid .UUID
236+ ) -> list [FlowEventRawRow ]:
238237 cte = (
239238 select (
240239 EventSchema .applet_id ,
@@ -297,7 +296,7 @@ async def get_user_flow_events(session: AsyncSession, scheduled_date: datetime.d
297296 ),
298297 )
299298 .where (
300- AppletSchema .id == uuid . UUID ( APPLET_ID ) ,
299+ AppletSchema .id == applet_id ,
301300 cte .c .event_id != null (),
302301 ActivityFlowSchema .is_hidden == false (),
303302 )
@@ -391,21 +390,24 @@ def filter_events(raw_events_rows: list[TRawRow], schedule_date: datetime.date)
391390@coro
392391async def export_flow_schedule (
393392 run_date : datetime .datetime = typer .Argument (None , help = "run date" ),
393+ applet_id : Optional [uuid .UUID ] = typer .Option (None , "--applet_id" , "-a" ),
394+ path_prefix : Optional [str ] = typer .Option (PATH_PREFIX , "--path-prefix" , "-p" ),
394395 force : bool = typer .Option (
395396 False ,
396397 "--force" ,
397398 "-f" ,
398399 help = "Force run even if job executed before" ,
399400 ),
400401):
401- ensure_configured ()
402+ assert path_prefix
403+ applet_id = get_applet_id (applet_id )
402404 scheduled_date = run_date .date () if run_date else datetime .date .today ()
403405
404- job_name = f"export_flow_schedule_{ scheduled_date } "
406+ job_name = f"export_flow_schedule_{ applet_id } _ { scheduled_date } "
405407
406408 session_maker = session_manager .get_session ()
407409 async with session_maker () as session :
408- owner_role = await UserAppletAccessCRUD (session ).get_applet_owner (uuid . UUID ( APPLET_ID ) )
410+ owner_role = await UserAppletAccessCRUD (session ).get_applet_owner (applet_id )
409411 owner_id = owner_role .user_id
410412
411413 job_service = JobService (session , owner_id )
@@ -422,12 +424,12 @@ async def export_flow_schedule(
422424 if job .status != JobStatus .in_progress :
423425 await job_service .change_status (job .id , JobStatus .in_progress )
424426
425- print (f"Flow schedule export start ({ scheduled_date } )" )
427+ print (f"Flow schedule export start { applet_id } ({ scheduled_date } )" )
426428 tracemalloc .start ()
427429
428430 try :
429431 async with session_maker () as session :
430- raw_data = await get_user_flow_events (session , scheduled_date )
432+ raw_data = await get_user_flow_events (session , scheduled_date , applet_id )
431433 print (f"Num raw rows is { len (raw_data )} " )
432434 filtered = filter_events (raw_data , scheduled_date )
433435 print (f"Num filtered rows is { len (filtered )} " )
@@ -449,13 +451,13 @@ async def export_flow_schedule(
449451 result .append (outrow )
450452
451453 cdn_client = await get_operations_bucket ()
452- unique_prefix = f"{ APPLET_ID } /flow-schedule"
454+ unique_prefix = f"{ applet_id } /flow-schedule"
453455
454456 prev_filename = PATH_USER_FLOW_SCHEDULE_FILE_NAME .format (date = scheduled_date - datetime .timedelta (days = 1 ))
455- prev_key = cdn_client .generate_key (PATH_PREFIX , unique_prefix , prev_filename )
457+ prev_key = cdn_client .generate_key (path_prefix , unique_prefix , prev_filename )
456458
457459 filename = PATH_USER_FLOW_SCHEDULE_FILE_NAME .format (date = scheduled_date )
458- key = cdn_client .generate_key (PATH_PREFIX , unique_prefix , filename )
460+ key = cdn_client .generate_key (path_prefix , unique_prefix , filename )
459461
460462 path = settings .uploads_dir / filename
461463
@@ -488,7 +490,9 @@ async def export_flow_schedule(
488490
489491
490492##### Daily user activity schedule stuff
491- async def get_user_activity_events (session : AsyncSession , scheduled_date : datetime .date ) -> list [ActivityEventRawRow ]:
493+ async def get_user_activity_events (
494+ session : AsyncSession , scheduled_date : datetime .date , applet_id : uuid .UUID
495+ ) -> list [ActivityEventRawRow ]:
492496 cte = (
493497 select (
494498 EventSchema .applet_id ,
@@ -551,7 +555,7 @@ async def get_user_activity_events(session: AsyncSession, scheduled_date: dateti
551555 ),
552556 )
553557 .where (
554- AppletSchema .id == uuid . UUID ( APPLET_ID ) ,
558+ AppletSchema .id == applet_id ,
555559 cte .c .event_id != null (),
556560 ActivitySchema .is_hidden == false (),
557561 )
@@ -566,21 +570,24 @@ async def get_user_activity_events(session: AsyncSession, scheduled_date: dateti
566570@coro
567571async def export_activity_schedule (
568572 run_date : datetime .datetime = typer .Argument (None , help = "run date" ),
573+ applet_id : Optional [uuid .UUID ] = typer .Option (None , "--applet_id" , "-a" ),
574+ path_prefix : Optional [str ] = typer .Option (PATH_PREFIX , "--path-prefix" , "-p" ),
569575 force : bool = typer .Option (
570576 False ,
571577 "--force" ,
572578 "-f" ,
573579 help = "Force run even if job executed before" ,
574580 ),
575581):
576- ensure_configured ()
582+ assert path_prefix
583+ applet_id = get_applet_id (applet_id )
577584 scheduled_date = run_date .date () if run_date else datetime .date .today ()
578585
579- job_name = f"export_activity_schedule_{ scheduled_date } "
586+ job_name = f"export_activity_schedule_{ applet_id } _ { scheduled_date } "
580587
581588 session_maker = session_manager .get_session ()
582589 async with session_maker () as session :
583- owner_role = await UserAppletAccessCRUD (session ).get_applet_owner (uuid . UUID ( APPLET_ID ) )
590+ owner_role = await UserAppletAccessCRUD (session ).get_applet_owner (applet_id )
584591 owner_id = owner_role .user_id
585592
586593 job_service = JobService (session , owner_id )
@@ -596,13 +603,13 @@ async def export_activity_schedule(
596603 raise
597604 if job .status != JobStatus .in_progress :
598605 await job_service .change_status (job .id , JobStatus .in_progress )
599- print ("Activity schedule export start" )
606+ print (f "Activity schedule export start { applet_id } ( { scheduled_date } ) " )
600607 tracemalloc .start ()
601608
602609 try :
603610 session_maker = session_manager .get_session ()
604611 async with session_maker () as session :
605- raw_data = await get_user_activity_events (session , scheduled_date )
612+ raw_data = await get_user_activity_events (session , scheduled_date , applet_id )
606613 print (f"Num raw rows is { len (raw_data )} " )
607614 filtered = filter_events (raw_data , scheduled_date )
608615 print (f"Num filtered rows is { len (filtered )} " )
@@ -624,13 +631,13 @@ async def export_activity_schedule(
624631 result .append (outrow )
625632
626633 cdn_client = await get_operations_bucket ()
627- unique_prefix = f"{ APPLET_ID } /activity-schedule"
634+ unique_prefix = f"{ applet_id } /activity-schedule"
628635
629636 prev_filename = PATH_USER_ACTIVITY_SCHEDULE_FILE_NAME .format (date = scheduled_date - datetime .timedelta (days = 1 ))
630- prev_key = cdn_client .generate_key (PATH_PREFIX , unique_prefix , prev_filename )
637+ prev_key = cdn_client .generate_key (path_prefix , unique_prefix , prev_filename )
631638
632639 filename = PATH_USER_ACTIVITY_SCHEDULE_FILE_NAME .format (date = scheduled_date )
633- key = cdn_client .generate_key (PATH_PREFIX , unique_prefix , filename )
640+ key = cdn_client .generate_key (path_prefix , unique_prefix , filename )
634641
635642 path = settings .uploads_dir / filename
636643
0 commit comments