@@ -40,6 +40,7 @@ def find_assistant(): # Taken from Flask-ask courtesy of @voutilad
4040session_id = LocalProxy (lambda : find_assistant ().session_id )
4141user = LocalProxy (lambda : find_assistant ().user )
4242storage = LocalProxy (lambda : find_assistant ().storage )
43+ profile = LocalProxy (lambda : find_assistant ().profile )
4344
4445# Converter shorthands for commonly used system entities
4546_converter_shorthands = {
@@ -65,6 +66,7 @@ class Assistant(object):
6566 blueprint {Flask Blueprint} -- Flask Blueprint instance to initialize (Default: {None})
6667 route {str} -- entry point to which initial Alexa Requests are forwarded (default: {None})
6768 project_id {str} -- Google Cloud Project ID, required to manage contexts from flask-assistant
69+ client_id {Str} -- Actions on Google client ID used for account linking
6870 dev_token {str} - Dialogflow dev access token used to register and retrieve agent resources
6971 client_token {str} - Dialogflow client access token required for querying agent
7072 """
@@ -77,12 +79,14 @@ def __init__(
7779 project_id = None ,
7880 dev_token = None ,
7981 client_token = None ,
82+ client_id = None ,
8083 ):
8184
8285 self .app = app
8386 self .blueprint = blueprint
8487 self ._route = route
8588 self .project_id = project_id
89+ self .client_id = client_id
8690 self ._intent_action_funcs = {}
8791 self ._intent_mappings = {}
8892 self ._intent_converts = {}
@@ -108,6 +112,9 @@ def __init__(
108112 "Assistant object must be intialized with either an app or blueprint"
109113 )
110114
115+ if self .client_id is None :
116+ self .client_id = self .app .config .get ("AOG_CLIENT_ID" )
117+
111118 if project_id is None :
112119 import warnings
113120
@@ -243,11 +250,19 @@ def storage(self):
243250
244251 @storage .setter
245252 def storage (self , value ):
246- if not isintance (value , dict ):
253+ if not isinstance (value , dict ):
247254 raise TypeError ("Storage must be a dictionary" )
248255
249256 self .user ["userStorage" ] = value
250257
258+ @property
259+ def profile (self ):
260+ return getattr (_app_ctx_stack .top , "_assist_profile" , None )
261+
262+ @profile .setter
263+ def profile (self , value ):
264+ _app_ctx_stack .top ._assist_profile = value
265+
251266 def _register_context_to_func (self , intent_name , context = []):
252267 required = self ._required_contexts .get (intent_name )
253268 if required :
@@ -372,6 +387,23 @@ def _dump_result(self, view_func, result):
372387 def _parse_session_id (self ):
373388 return self .request ["session" ].split ("/sessions/" )[1 ]
374389
390+ def _set_user_profile (self ):
391+ if self .client_id is None :
392+ return
393+
394+ if self .user .get ("idToken" ) is not None :
395+ from flask_assistant .utils import decode_token
396+
397+ token = self .user ["idToken" ]
398+ profile_payload = decode_token (token , self .client_id )
399+ for k in ["sub" , "iss" , "aud" , "iat" , "exp" ]:
400+ profile_payload .pop (k )
401+
402+ self .profile = profile_payload
403+
404+
405+
406+
375407 def _flask_assitant_view_func (self , nlp_result = None , * args , ** kwargs ):
376408 if nlp_result : # pass API query result directly
377409 self .request = nlp_result
@@ -401,6 +433,7 @@ def _flask_assitant_view_func(self, nlp_result=None, *args, **kwargs):
401433 payload = original_request .get ("payload" )
402434 if payload and payload .get ("user" ):
403435 self .user = original_request ["payload" ]["user" ]
436+ self ._set_user_profile ()
404437
405438 # Get access token from request
406439 if original_request and original_request .get ("user" ):
0 commit comments