1+ import logging
12import pathlib
23from functools import cached_property
34
45import yaml
6+ from core .utils .db import fast_first
57from rest_framework import serializers
68
7- from .models import ProductTourInteractionData , UserProductTour
9+ from .models import ProductTourInteractionData , ProductTourState , UserProductTour
10+
11+ logger = logging .getLogger (__name__ )
812
913PRODUCT_TOURS_CONFIGS_DIR = pathlib .Path (__file__ ).parent / 'configs'
1014
1115
1216class UserProductTourSerializer (serializers .ModelSerializer ):
17+ # steps is a list of steps in the tour loaded from the yaml file
1318 steps = serializers .SerializerMethodField (read_only = True )
19+ # awaiting is a boolean that indicates if the tour is awaiting other tours in the list of "dependencies"
20+ awaiting = serializers .SerializerMethodField (read_only = True )
1421
1522 class Meta :
1623 model = UserProductTour
@@ -29,14 +36,25 @@ def validate_name(self, value):
2936
3037 return value
3138
39+ @cached_property
3240 def load_tour_config (self ):
3341 # TODO: get product tour from yaml file. Later we move it to remote storage, e.g. S3
3442 filepath = PRODUCT_TOURS_CONFIGS_DIR / f'{ self .context ["name" ]} .yml'
3543 with open (filepath , 'r' ) as f :
3644 return yaml .safe_load (f )
3745
46+ def get_awaiting (self , obj ):
47+ config = self .load_tour_config
48+ dependencies = config .get ('dependencies' , [])
49+ for dependency in dependencies :
50+ tour = fast_first (UserProductTour .objects .filter (user = self .context ['request' ].user , name = dependency ))
51+ if not tour or tour .state != ProductTourState .COMPLETED :
52+ logger .info (f'Tour { dependency } is not completed: skipping tour { self .context ["name" ]} ' )
53+ return True
54+ return False
55+
3856 def get_steps (self , obj ):
39- config = self .load_tour_config ()
57+ config = self .load_tour_config
4058 return config .get ('steps' , [])
4159
4260 def validate_interaction_data (self , value ):
0 commit comments