1+ <!doctype html>
2+ < html lang ="en ">
3+ < head >
4+ < meta charset ="utf-8 ">
5+ < meta name ="viewport " content ="width=device-width, initial-scale=1, minimum-scale=1 " />
6+ < meta name ="generator " content ="pdoc 0.10.0 " />
7+ < title > supertokens_python.recipe.dashboard.api.analytics API documentation</ title >
8+ < meta name ="description " content ="Documentation for supertokens_python - SuperTokens Python SDK " />
9+ < link rel ="preload stylesheet " as ="style " href ="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css " integrity ="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs= " crossorigin >
10+ < link rel ="preload stylesheet " as ="style " href ="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css " integrity ="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg= " crossorigin >
11+ < link rel ="stylesheet preload " as ="style " href ="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css " crossorigin >
12+ < style > : root {--highlight-color : # fe9 }.flex {display : flex !important }body {line-height : 1.5em }# content {padding : 20px }# sidebar {padding : 30px ;overflow : hidden}# sidebar > * : last-child {margin-bottom : 2cm }.http-server-breadcrumbs {font-size : 130% ;margin : 0 0 15px 0 }# footer {font-size : .75em ;padding : 5px 30px ;border-top : 1px solid # ddd ;text-align : right}# footer p {margin : 0 0 0 1em ;display : inline-block}# footer p : last-child {margin-right : 30px }h1 , h2 , h3 , h4 , h5 {font-weight : 300 }h1 {font-size : 2.5em ;line-height : 1.1em }h2 {font-size : 1.75em ;margin : 1em 0 .50em 0 }h3 {font-size : 1.4em ;margin : 25px 0 10px 0 }h4 {margin : 0 ;font-size : 105% }h1 : target , h2 : target , h3 : target , h4 : target , h5 : target , h6 : target {background : var (--highlight-color );padding : .2em 0 }a {color : # 058 ;text-decoration : none;transition : color .3s ease-in-out}a : hover {color : # e82 }.title code {font-weight : bold}h2 [id ^= "header-" ]{margin-top : 2em }.ident {color : # 900 }pre code {background : # f8f8f8 ;font-size : .8em ;line-height : 1.4em }code {background : # f2f2f1 ;padding : 1px 4px ;overflow-wrap : break-word}h1 code {background : transparent}pre {background : # f8f8f8 ;border : 0 ;border-top : 1px solid # ccc ;border-bottom : 1px solid # ccc ;margin : 1em 0 ;padding : 1ex }# http-server-module-list {display : flex;flex-flow : column}# http-server-module-list div {display : flex}# http-server-module-list dt {min-width : 10% }# http-server-module-list p {margin-top : 0 }.toc ul , # index {list-style-type : none;margin : 0 ;padding : 0 }# index code {background : transparent}# index h3 {border-bottom : 1px solid # ddd }# index ul {padding : 0 }# index h4 {margin-top : .6em ;font-weight : bold}@media (min-width : 200ex ){# index .two-column {column-count : 2 }}@media (min-width : 300ex ){# index .two-column {column-count : 3 }}dl {margin-bottom : 2em }dl dl : last-child {margin-bottom : 4em }dd {margin : 0 0 1em 3em }# header-classes + dl > dd {margin-bottom : 3em }dd dd {margin-left : 2em }dd p {margin : 10px 0 }.name {background : # eee ;font-weight : bold;font-size : .85em ;padding : 5px 10px ;display : inline-block;min-width : 40% }.name : hover {background : # e0e0e0 }dt : target .name {background : var (--highlight-color )}.name > span : first-child {white-space : nowrap}.name .class > span : nth-child (2 ){margin-left : .4em }.inherited {color : # 999 ;border-left : 5px solid # eee ;padding-left : 1em }.inheritance em {font-style : normal;font-weight : bold}.desc h2 {font-weight : 400 ;font-size : 1.25em }.desc h3 {font-size : 1em }.desc dt code {background : inherit}.source summary , .git-link-div {color : # 666 ;text-align : right;font-weight : 400 ;font-size : .8em ;text-transform : uppercase}.source summary > * {white-space : nowrap;cursor : pointer}.git-link {color : inherit;margin-left : 1em }.source pre {max-height : 500px ;overflow : auto;margin : 0 }.source pre code {font-size : 12px ;overflow : visible}.hlist {list-style : none}.hlist li {display : inline}.hlist li : after {content : ',\2002' }.hlist li : last-child : after {content : none}.hlist .hlist {display : inline;padding-left : 1em }img {max-width : 100% }td {padding : 0 .5em }.admonition {padding : .1em .5em ;margin-bottom : 1em }.admonition-title {font-weight : bold}.admonition .note , .admonition .info , .admonition .important {background : # aef }.admonition .todo , .admonition .versionadded , .admonition .tip , .admonition .hint {background : # dfd }.admonition .warning , .admonition .versionchanged , .admonition .deprecated {background : # fd4 }.admonition .error , .admonition .danger , .admonition .caution {background : lightpink}</ style >
13+ < style media ="screen and (min-width: 700px) "> @media screen and (min-width : 700px ){# sidebar {width : 30% ;height : 100vh ;overflow : auto;position : sticky;top : 0 }# content {width : 70% ;max-width : 100ch ;padding : 3em 4em ;border-left : 1px solid # ddd }pre code {font-size : 1em }.item .name {font-size : 1em }main {display : flex;flex-direction : row-reverse;justify-content : flex-end}.toc ul ul , # index ul {padding-left : 1.5em }.toc > ul > li {margin-top : .5em }}</ style >
14+ < style media ="print "> @media print{# sidebar h1 {page-break-before : always}.source {display : none}}@media print{* {background : transparent !important ;color : # 000 !important ;box-shadow : none !important ;text-shadow : none !important }a [href ]: after {content : " (" attr (href) ")" ;font-size : 90% }a [href ][title ]: after {content : none}abbr [title ]: after {content : " (" attr (title) ")" }.ir a : after , a [href ^= "javascript:" ]: after , a [href ^= "#" ]: after {content : "" }pre , blockquote {border : 1px solid # 999 ;page-break-inside : avoid}thead {display : table-header-group}tr , img {page-break-inside : avoid}img {max-width : 100% !important }@page {margin : 0.5cm }p , h2 , h3 {orphans : 3 ;widows : 3 }h1 , h2 , h3 , h4 , h5 , h6 {page-break-after : avoid}}</ style >
15+ < script defer src ="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js " integrity ="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8= " crossorigin > </ script >
16+ < script > window . addEventListener ( 'DOMContentLoaded' , ( ) => hljs . initHighlighting ( ) ) </ script >
17+ </ head >
18+ < body >
19+ < main >
20+ < article id ="content ">
21+ < header >
22+ < h1 class ="title "> Module < code > supertokens_python.recipe.dashboard.api.analytics</ code > </ h1 >
23+ </ header >
24+ < section id ="section-intro ">
25+ < details class ="source ">
26+ < summary >
27+ < span > Expand source code</ span >
28+ </ summary >
29+ < pre > < code class ="python "> # Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.
30+ #
31+ # This software is licensed under the Apache License, Version 2.0 (the
32+ # "License") as published by the Apache Software Foundation.
33+ #
34+ # You may not use this file except in compliance with the License. You may
35+ # obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
36+ #
37+ # Unless required by applicable law or agreed to in writing, software
38+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
39+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
40+ # License for the specific language governing permissions and limitations
41+ # under the License.
42+
43+ from __future__ import annotations
44+
45+ from typing import TYPE_CHECKING
46+
47+ from httpx import AsyncClient
48+
49+ from supertokens_python import Supertokens
50+ from supertokens_python.constants import (
51+ TELEMETRY_SUPERTOKENS_API_URL,
52+ TELEMETRY_SUPERTOKENS_API_VERSION,
53+ )
54+ from supertokens_python.constants import VERSION as SDKVersion
55+ from supertokens_python.exceptions import raise_bad_input_exception
56+ from supertokens_python.normalised_url_path import NormalisedURLPath
57+ from supertokens_python.querier import Querier
58+
59+ from ..interfaces import AnalyticsResponse
60+
61+ if TYPE_CHECKING:
62+ from supertokens_python.recipe.dashboard.interfaces import APIInterface, APIOptions
63+
64+
65+ async def handle_analytics_post(
66+ _: APIInterface, api_options: APIOptions
67+ ) -> AnalyticsResponse:
68+ if not Supertokens.get_instance().telemetry:
69+ return AnalyticsResponse()
70+ body = await api_options.request.json()
71+ if body is None:
72+ raise_bad_input_exception("Please send body")
73+ email = body.get("email")
74+ dashboard_version = body.get("dashboardVersion")
75+
76+ if email is None:
77+ raise_bad_input_exception("Missing required property 'email'")
78+ if dashboard_version is None:
79+ raise_bad_input_exception("Missing required property 'dashboardVersion'")
80+
81+ telemetry_id = None
82+
83+ try:
84+ response = await Querier.get_instance().send_get_request(
85+ NormalisedURLPath("/telemetry")
86+ )
87+ if response is not None:
88+ if (
89+ "exists" in response
90+ and response["exists"]
91+ and "telemetryId" in response
92+ ):
93+ telemetry_id = response["telemetryId"]
94+
95+ number_of_users = await Supertokens.get_instance().get_user_count(
96+ include_recipe_ids=None
97+ )
98+
99+ except Exception as __:
100+ # If either telemetry id API or user count fetch fails, no event should be sent
101+ return AnalyticsResponse()
102+
103+ apiDomain, websiteDomain, appName = (
104+ api_options.app_info.api_domain,
105+ api_options.app_info.website_domain,
106+ api_options.app_info.app_name,
107+ )
108+
109+ data = {
110+ "websiteDomain": websiteDomain.get_as_string_dangerous(),
111+ "apiDomain": apiDomain.get_as_string_dangerous(),
112+ "appName": appName,
113+ "sdk": "python",
114+ "sdkVersion": SDKVersion,
115+ "numberOfUsers": number_of_users,
116+ "email": email,
117+ "dashboardVersion": dashboard_version,
118+ }
119+
120+ if telemetry_id is not None:
121+ data["telemetryId"] = telemetry_id
122+
123+ try:
124+ async with AsyncClient() as client:
125+ await client.post( # type: ignore
126+ url=TELEMETRY_SUPERTOKENS_API_URL,
127+ json=data,
128+ headers={"api-version": TELEMETRY_SUPERTOKENS_API_VERSION},
129+ )
130+ except Exception as __:
131+ # If telemetry event fails, no error should be thrown
132+ pass
133+
134+ return AnalyticsResponse()</ code > </ pre >
135+ </ details >
136+ </ section >
137+ < section >
138+ </ section >
139+ < section >
140+ </ section >
141+ < section >
142+ < h2 class ="section-title " id ="header-functions "> Functions</ h2 >
143+ < dl >
144+ < dt id ="supertokens_python.recipe.dashboard.api.analytics.handle_analytics_post "> < code class ="name flex ">
145+ < span > async def < span class ="ident "> handle_analytics_post</ span > </ span > (< span > _: APIInterface, api_options: APIOptions) ‑> AnalyticsResponse</ span >
146+ </ code > </ dt >
147+ < dd >
148+ < div class ="desc "> </ div >
149+ < details class ="source ">
150+ < summary >
151+ < span > Expand source code</ span >
152+ </ summary >
153+ < pre > < code class ="python "> async def handle_analytics_post(
154+ _: APIInterface, api_options: APIOptions
155+ ) -> AnalyticsResponse:
156+ if not Supertokens.get_instance().telemetry:
157+ return AnalyticsResponse()
158+ body = await api_options.request.json()
159+ if body is None:
160+ raise_bad_input_exception("Please send body")
161+ email = body.get("email")
162+ dashboard_version = body.get("dashboardVersion")
163+
164+ if email is None:
165+ raise_bad_input_exception("Missing required property 'email'")
166+ if dashboard_version is None:
167+ raise_bad_input_exception("Missing required property 'dashboardVersion'")
168+
169+ telemetry_id = None
170+
171+ try:
172+ response = await Querier.get_instance().send_get_request(
173+ NormalisedURLPath("/telemetry")
174+ )
175+ if response is not None:
176+ if (
177+ "exists" in response
178+ and response["exists"]
179+ and "telemetryId" in response
180+ ):
181+ telemetry_id = response["telemetryId"]
182+
183+ number_of_users = await Supertokens.get_instance().get_user_count(
184+ include_recipe_ids=None
185+ )
186+
187+ except Exception as __:
188+ # If either telemetry id API or user count fetch fails, no event should be sent
189+ return AnalyticsResponse()
190+
191+ apiDomain, websiteDomain, appName = (
192+ api_options.app_info.api_domain,
193+ api_options.app_info.website_domain,
194+ api_options.app_info.app_name,
195+ )
196+
197+ data = {
198+ "websiteDomain": websiteDomain.get_as_string_dangerous(),
199+ "apiDomain": apiDomain.get_as_string_dangerous(),
200+ "appName": appName,
201+ "sdk": "python",
202+ "sdkVersion": SDKVersion,
203+ "numberOfUsers": number_of_users,
204+ "email": email,
205+ "dashboardVersion": dashboard_version,
206+ }
207+
208+ if telemetry_id is not None:
209+ data["telemetryId"] = telemetry_id
210+
211+ try:
212+ async with AsyncClient() as client:
213+ await client.post( # type: ignore
214+ url=TELEMETRY_SUPERTOKENS_API_URL,
215+ json=data,
216+ headers={"api-version": TELEMETRY_SUPERTOKENS_API_VERSION},
217+ )
218+ except Exception as __:
219+ # If telemetry event fails, no error should be thrown
220+ pass
221+
222+ return AnalyticsResponse()</ code > </ pre >
223+ </ details >
224+ </ dd >
225+ </ dl >
226+ </ section >
227+ < section >
228+ </ section >
229+ </ article >
230+ < nav id ="sidebar ">
231+ < h2 > Index</ h2 >
232+ < div class ="toc ">
233+ < ul > </ ul >
234+ </ div >
235+ < ul id ="index ">
236+ < li > < h3 > Super-module</ h3 >
237+ < ul >
238+ < li > < code > < a title ="supertokens_python.recipe.dashboard.api " href ="index.html "> supertokens_python.recipe.dashboard.api</ a > </ code > </ li >
239+ </ ul >
240+ </ li >
241+ < li > < h3 > < a href ="#header-functions "> Functions</ a > </ h3 >
242+ < ul class ="">
243+ < li > < code > < a title ="supertokens_python.recipe.dashboard.api.analytics.handle_analytics_post " href ="#supertokens_python.recipe.dashboard.api.analytics.handle_analytics_post "> handle_analytics_post</ a > </ code > </ li >
244+ </ ul >
245+ </ li >
246+ </ ul >
247+ </ nav >
248+ </ main >
249+ < footer id ="footer ">
250+ < p > Generated by < a href ="https://pdoc3.github.io/pdoc " title ="pdoc: Python API documentation generator "> < cite > pdoc</ cite > 0.10.0</ a > .</ p >
251+ </ footer >
252+ </ body >
253+ </ html >
0 commit comments