Skip to content
This repository was archived by the owner on Jun 26, 2025. It is now read-only.

Commit e314b0c

Browse files
committed
Merge branch 'release/0.3.7'
2 parents 29c0119 + 7e7ca92 commit e314b0c

28 files changed

+129
-186
lines changed

.gitignore

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ var/
2323
*.egg-info/
2424
.installed.cfg
2525
*.egg
26+
MANIFEST
2627

2728
# PyInstaller
2829
# Usually these files are written by a python script from a template
@@ -37,31 +38,72 @@ pip-delete-this-directory.txt
3738
# Unit test / coverage reports
3839
htmlcov/
3940
.tox/
41+
.nox/
4042
.coverage
43+
.coverage.*
4144
.cache
4245
nosetests.xml
4346
coverage.xml
47+
*.cover
48+
.hypothesis/
49+
.pytest_cache/
4450

4551
# Translations
4652
*.mo
4753
*.pot
4854

4955
# Django stuff:
5056
*.log
57+
local_settings.py
58+
db.sqlite3
59+
60+
# Flask stuff:
61+
instance/
62+
.webassets-cache
5163

5264
# Sphinx documentation
5365
docs/_build/
5466

5567
# PyBuilder
5668
target/
5769

70+
# IPython
71+
profile_default/
72+
ipython_config.py
73+
74+
# Environments
75+
.env
76+
.venv
77+
env/
78+
venv/
79+
ENV/
80+
env.bak/
81+
venv.bak/
82+
83+
84+
# Spyder project settings
85+
.spyderproject
86+
.spyproject
87+
88+
# pipenv
89+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
90+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
91+
# having no cross-platform support, pipenv may install dependencies that don’t work, or not
92+
# install all needed dependencies.
93+
Pipfile.lock
94+
95+
# pyenv
96+
.python-version
97+
98+
5899
# Pycharm
59100
.idea/
60101

61-
# Virtualenv
62-
venv/
102+
# vscode
103+
.vscode
104+
63105

64-
###SublimeText###
106+
# SublimeText
65107

66108
# cache files for sublime text
67109
*.tmlanguage.cache
@@ -76,4 +118,18 @@ venv/
76118
*.sublime-project
77119

78120
# sftp configuration file
79-
sftp-config.json
121+
sftp-config.json
122+
123+
# Rope project settings
124+
.ropeproject
125+
126+
# mkdocs documentation
127+
/site
128+
129+
# mypy
130+
.mypy_cache/
131+
.dmypy.json
132+
dmypy.json
133+
134+
# Pyre type checker
135+
.pyre/

flask_assistant/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
intent,
2020
request,
2121
access_token,
22+
user,
2223
)
2324

2425
from flask_assistant.response import ask, tell, event, build_item, permission

flask_assistant/core.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ def find_assistant(): # Taken from Flask-ask courtesy of @voutilad
3939
context_manager = LocalProxy(lambda: find_assistant().context_manager)
4040
convert_errors = LocalProxy(lambda: find_assistant().convert_errors)
4141
session_id = LocalProxy(lambda: find_assistant().session_id)
42+
user = LocalProxy(lambda: find_assistant().user)
4243

4344
# Converter shorthands for commonly used system entities
4445
_converter_shorthands = {
@@ -220,6 +221,14 @@ def session_id(self):
220221
def session_id(self, value):
221222
_app_ctx_stack.top._assist_session_id = value
222223

224+
@property
225+
def user(self):
226+
return getattr(_app_ctx_stack.top, "_assist_user", {})
227+
228+
@user.setter
229+
def user(self, value):
230+
_app_ctx_stack.top._assist_user = value
231+
223232
def _register_context_to_func(self, intent_name, context=[]):
224233
required = self._required_contexts.get(intent_name)
225234
if required:
@@ -367,8 +376,16 @@ def _flask_assitant_view_func(self, nlp_result=None, *args, **kwargs):
367376
# TODO: acces context_manager from assist, instead of own object
368377
self.context_manager._assist = self
369378

370-
# Get access token from request
379+
371380
original_request = self.request.get("originalDetectIntentRequest")
381+
382+
if original_request:
383+
payload = original_request.get('payload')
384+
if payload and payload.get('user'):
385+
self.user = original_request["payload"]["user"]
386+
387+
388+
# Get access token from request
372389
if original_request and original_request.get("user"):
373390
self.access_token = original_request["user"].get("accessToken")
374391

flask_assistant/integrations/google.py

Lines changed: 0 additions & 158 deletions
This file was deleted.

flask_assistant/manager.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
from flask_assistant import logger
2+
3+
14
def parse_context_name(context_obj):
25
"""Parses context name from Dialogflow's contextsession prefixed context path"""
36
return context_obj["name"].split("/contexts/")[1]
@@ -69,6 +72,7 @@ def get(self, context_name, default=None):
6972
def set(self, context_name, param, val):
7073
context = self.get(context_name)
7174
context.set(param, val)
75+
self._cache[context.name] = context
7276
return context
7377

7478
def get_param(self, context_name, param):
@@ -83,6 +87,15 @@ def update(self, contexts_json):
8387
context.parameters = obj.get("parameters", {})
8488
self._cache[context.name] = context
8589

90+
def clear_all(self):
91+
logger.info("Clearing all contexts")
92+
new_cache = {}
93+
for name, context in self._cache.items():
94+
context.lifespan = 0
95+
new_cache[name] = context
96+
97+
self._cache = new_cache
98+
8699
@property
87100
def status(self):
88101
return {"Active contexts": self.active, "Expired contexts": self.expired}

flask_assistant/response.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,21 @@ def __init__(self, speech, display_text=None, is_ssml=False):
2828
}
2929

3030
if "ACTIONS_ON_GOOGLE" in self._integrations:
31+
self._set_user_storage()
3132
self._integrate_with_actions(self._speech, self._display_text, is_ssml)
3233

3334
def add_msg(self, speech, display_text=None, is_ssml=False):
3435
self._messages.append({"text": {"text": [speech]}})
3536
if "ACTIONS_ON_GOOGLE" in self._integrations:
3637
self._integrate_with_actions(speech, display_text, is_ssml)
3738

38-
return self
39+
def _set_user_storage(self):
40+
from flask_assistant.core import user
41+
42+
# If empty or unspecified,
43+
# the existing persisted token will be unchanged.
44+
if user.get("userStorage"):
45+
self._response["payload"]["google"]["userStorage"] = user["userStorage"]
3946

4047
def _integrate_with_actions(self, speech=None, display_text=None, is_ssml=False):
4148
if display_text is None:
@@ -313,16 +320,26 @@ class permission(_Response):
313320
Arguments:
314321
permissions {list} -- list of permissions to request for eg. ['DEVICE_PRECISE_LOCATION']
315322
context {str} -- Text explaining the reason/value for the requested permission
323+
update_intent {str} -- name of the intent that the user wants to get updates from
316324
"""
317325

318-
def __init__(self, permissions, context=None):
326+
def __init__(self, permissions, context=None, update_intent=None):
319327
super(permission, self).__init__(speech=None)
320328
self._messages[:] = []
329+
330+
if isinstance(permissions, str):
331+
permissions = [permissions]
332+
333+
if "UPDATE" in permissions and update_intent is None:
334+
raise ValueError("update_intent is required to ask for UPDATE permission")
335+
321336
self._response["payload"]["google"]["systemIntent"] = {
322337
"intent": "actions.intent.PERMISSION",
323338
"data": {
324339
"@type": "type.googleapis.com/google.actions.v2.PermissionValueSpec",
325340
"optContext": context,
326341
"permissions": permissions,
342+
"updatePermissionValueSpec": {"intent": update_intent},
327343
},
328344
}
345+

0 commit comments

Comments
 (0)