diff --git a/querybook/server/app/auth/utils.py b/querybook/server/app/auth/utils.py index 1a204c58c..957d525dc 100644 --- a/querybook/server/app/auth/utils.py +++ b/querybook/server/app/auth/utils.py @@ -29,6 +29,14 @@ def id(self): def get_id(self): return str(self.id) + @property + def username(self): + return self._user_dict["username"] + + @property + def email(self): + return self._user_dict["email"] + @property def is_admin(self): return UserRoleType.ADMIN.value in self._user_dict["roles"] diff --git a/querybook/server/lib/query_analysis/templating.py b/querybook/server/lib/query_analysis/templating.py index 86a8336ab..8af2b428e 100644 --- a/querybook/server/lib/query_analysis/templating.py +++ b/querybook/server/lib/query_analysis/templating.py @@ -7,7 +7,10 @@ from jinja2.sandbox import SandboxedEnvironment from jinja2 import meta +from slugify import slugify + from app.db import with_session +from flask_login import current_user from lib import metastore from logic import admin as admin_logic @@ -68,6 +71,12 @@ def get_default_variables(): return { "today": datetime.today().strftime("%Y-%m-%d"), "yesterday": (datetime.today() - timedelta(1)).strftime("%Y-%m-%d"), + "current_user": ( + current_user.username if current_user.is_authenticated else None + ), + "current_user_email": ( + current_user.email if current_user.is_authenticated else None + ), } @@ -172,6 +181,11 @@ def get_templated_query_env(engine_id: int, session=None): latest_partition=create_get_latest_partition(engine_id, session=session) ) + # Inject filters + jinja_env.filters.update( + slugify=lambda x: slugify(x, separator="_"), + ) + # Template rendering config jinja_env.trim_blocks = True jinja_env.lstrip_blocks = True diff --git a/querybook/webapp/components/TemplateGuide/guides/predefined.md b/querybook/webapp/components/TemplateGuide/guides/predefined.md index dc7bbe1c6..88130cb0a 100644 --- a/querybook/webapp/components/TemplateGuide/guides/predefined.md +++ b/querybook/webapp/components/TemplateGuide/guides/predefined.md @@ -29,6 +29,30 @@ Gets rendered to: SELECT * FROM users WHERE created_at = '2022-02-24'; ``` +`{{ current_user }}`: Map to the current user's username in Querybook. Example use case: + +```sql +SELECT * FROM tickets WHERE assigned_to = '{{ current_user }}'; +``` + +Gets rendered to: + +```sql +SELECT * FROM tickets WHERE assigned_to = 'john_doe'; +``` + +`{{ current_user_email }}`: Map to the current user's email in Querybook. Example use case: + +```sql +SELECT * FROM tickets WHERE assigned_to_email = '{{ current_user_email }}'; +``` + +Gets rendered to: + +```sql +SELECT * FROM tickets WHERE assigned_to_email = 'john_doe@querybook.org' +``` + ## Functions `{{ latest_partition('.', '') }}`: @@ -66,3 +90,21 @@ This gets rendered to: SELECT * FROM default.pins WHERE dt = '2022-02-25'; ``` + +## Filters + +Filters transform the output of template variables, and are applied using the pipe character `|`. Filters can be chained together by using multiple pipe characters. A list of built-in filters can be found [here](https://jinja.palletsprojects.com/en/3.1.x/templates/#list-of-builtin-filters). + +Custom filters are also available: + +`{{ ... | slugify }}`: Transforms a string into a format suitable for use in table names, column names, URLs, etc. It converts all characters to lowercase and replaces spaces with underscores. It also removes special characters and Unicode. Example use case: + +```sql +CREATE TABLE default.report_{{ today | slugify }} AS ... +``` + +Gets rendered to: + +```sql +CREATE TABLE default.report_2022_02_25 AS ... +``` diff --git a/requirements/base.txt b/requirements/base.txt index 096d94648..aaf284afb 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -19,6 +19,7 @@ flask-socketio==5.3.3 # Query templating Jinja2==3.1.3 # From Flask +python-slugify==8.0.4 # Celery celery==5.2.7