|
17 | 17 | from dotenv import load_dotenv
|
18 | 18 | from flask import Flask, g, jsonify, make_response, request
|
19 | 19 | from flask_cors import CORS
|
| 20 | + |
20 | 21 | from supertokens_python import (
|
21 | 22 | InputAppInfo,
|
22 | 23 | Supertokens,
|
|
34 | 35 | thirdparty,
|
35 | 36 | thirdpartyemailpassword,
|
36 | 37 | thirdpartypasswordless,
|
| 38 | + userroles, |
37 | 39 | )
|
38 | 40 | from supertokens_python.recipe.emailpassword import EmailPasswordRecipe
|
39 | 41 | from supertokens_python.recipe.emailpassword.interfaces import (
|
|
47 | 49 | InputFormField,
|
48 | 50 | User,
|
49 | 51 | )
|
50 |
| -from supertokens_python.recipe.emailverification import EmailVerificationRecipe |
| 52 | +from supertokens_python.recipe.emailverification import ( |
| 53 | + EmailVerificationRecipe, |
| 54 | + EmailVerificationClaim, |
| 55 | +) |
51 | 56 | from supertokens_python.recipe.emailverification import (
|
52 | 57 | InputOverrideConfig as EVInputOverrideConfig,
|
53 | 58 | )
|
| 59 | +from supertokens_python.recipe.emailverification.asyncio import unverify_email |
54 | 60 | from supertokens_python.recipe.emailverification.interfaces import (
|
55 | 61 | APIInterface as EmailVerificationAPIInterface,
|
56 | 62 | )
|
|
75 | 81 | from supertokens_python.recipe.session.framework.flask import verify_session
|
76 | 82 | from supertokens_python.recipe.session.interfaces import (
|
77 | 83 | APIInterface as SessionAPIInterface,
|
| 84 | + SessionContainer, |
| 85 | + SessionClaimValidator, |
78 | 86 | )
|
79 | 87 | from supertokens_python.recipe.session.interfaces import APIOptions as SAPIOptions
|
80 |
| -from supertokens_python.recipe.session.interfaces import SessionContainer |
81 | 88 | from supertokens_python.recipe.thirdparty import ThirdPartyRecipe
|
82 | 89 | from supertokens_python.recipe.thirdparty.interfaces import (
|
83 | 90 | APIInterface as ThirdpartyAPIInterface,
|
|
105 | 112 | from supertokens_python.recipe.thirdpartypasswordless.interfaces import (
|
106 | 113 | APIInterface as ThirdpartyPasswordlessAPIInterface,
|
107 | 114 | )
|
| 115 | +from supertokens_python.recipe.userroles import ( |
| 116 | + UserRoleClaim, |
| 117 | + PermissionClaim, |
| 118 | + UserRolesRecipe, |
| 119 | +) |
| 120 | +from supertokens_python.recipe.userroles.asyncio import ( |
| 121 | + create_new_role_or_add_permissions, |
| 122 | + add_role_to_user, |
| 123 | +) |
108 | 124 | from supertokens_python.types import GeneralErrorResponse
|
109 | 125 | from typing_extensions import Literal
|
110 | 126 |
|
@@ -264,13 +280,15 @@ def custom_init(
|
264 | 280 | None, Literal["USER_INPUT_CODE", "MAGIC_LINK", "USER_INPUT_CODE_AND_MAGIC_LINK"]
|
265 | 281 | ] = None,
|
266 | 282 | ):
|
| 283 | + UserRolesRecipe.reset() |
267 | 284 | PasswordlessRecipe.reset()
|
268 | 285 | ThirdPartyPasswordlessRecipe.reset()
|
269 | 286 | JWTRecipe.reset()
|
270 | 287 | EmailVerificationRecipe.reset()
|
271 | 288 | SessionRecipe.reset()
|
272 | 289 | ThirdPartyRecipe.reset()
|
273 | 290 | EmailPasswordRecipe.reset()
|
| 291 | + EmailVerificationRecipe.reset() |
274 | 292 | ThirdPartyEmailPasswordRecipe.reset()
|
275 | 293 | Supertokens.reset()
|
276 | 294 |
|
@@ -893,6 +911,7 @@ async def authorisation_url_get(
|
893 | 911 | )
|
894 | 912 |
|
895 | 913 | recipe_list = [
|
| 914 | + userroles.init(), |
896 | 915 | session.init(override=session.InputOverrideConfig(apis=override_session_apis)),
|
897 | 916 | emailverification.init(
|
898 | 917 | mode="OPTIONAL",
|
@@ -1014,10 +1033,59 @@ def test_get_device():
|
1014 | 1033 |
|
1015 | 1034 | @app.get("/test/featureFlags") # type: ignore
|
1016 | 1035 | def test_feature_flags():
|
1017 |
| - available = ["passwordless", "thirdpartypasswordless", "generalerror"] |
| 1036 | + available = ["passwordless", "thirdpartypasswordless", "generalerror", "userroles"] |
1018 | 1037 | return jsonify({"available": available})
|
1019 | 1038 |
|
1020 | 1039 |
|
| 1040 | +@app.get("/unverifyEmail") # type: ignore |
| 1041 | +@verify_session() |
| 1042 | +async def unverify_email_api(): |
| 1043 | + session_: SessionContainer = g.supertokens # type: ignore |
| 1044 | + await unverify_email(session_.get_user_id()) |
| 1045 | + await session_.fetch_and_set_claim(EmailVerificationClaim) |
| 1046 | + return jsonify({"status": "OK"}) |
| 1047 | + |
| 1048 | + |
| 1049 | +@app.route("/setRole", methods=["POST"]) # type: ignore |
| 1050 | +@verify_session() |
| 1051 | +async def verify_email_api(): |
| 1052 | + session_: SessionContainer = g.supertokens # type: ignore |
| 1053 | + body: Dict[str, Any] = request.get_json() # type: ignore |
| 1054 | + await create_new_role_or_add_permissions(body["role"], body["permissions"]) |
| 1055 | + await add_role_to_user(session_.get_user_id(), body["role"]) |
| 1056 | + await session_.fetch_and_set_claim(UserRoleClaim) |
| 1057 | + await session_.fetch_and_set_claim(PermissionClaim) |
| 1058 | + return jsonify({"status": "OK"}) |
| 1059 | + |
| 1060 | + |
| 1061 | +async def override_global_claim_validators( |
| 1062 | + gv: List[SessionClaimValidator], |
| 1063 | + _session: SessionContainer, |
| 1064 | + user_context: Dict[str, Any], |
| 1065 | +): |
| 1066 | + validators = gv.copy() |
| 1067 | + req = user_context["_default"]["request"] |
| 1068 | + body = await req.json() |
| 1069 | + |
| 1070 | + if body.get("role"): |
| 1071 | + info = body["role"] |
| 1072 | + validator = getattr(UserRoleClaim.validators, info["validator"]) |
| 1073 | + validators.append(validator(*info["args"])) |
| 1074 | + |
| 1075 | + if body.get("permission"): |
| 1076 | + info = body["permission"] |
| 1077 | + validator = getattr(PermissionClaim.validators, info["validator"]) |
| 1078 | + validators.append(validator(*info["args"])) |
| 1079 | + |
| 1080 | + return validators |
| 1081 | + |
| 1082 | + |
| 1083 | +@app.route("/checkRole", methods=["POST"]) # type: ignore |
| 1084 | +@verify_session(override_global_claim_validators=override_global_claim_validators) |
| 1085 | +async def check_role_api(): |
| 1086 | + return jsonify({"status": "OK"}) |
| 1087 | + |
| 1088 | + |
1021 | 1089 | @app.route("/", defaults={"path": ""}) # type: ignore
|
1022 | 1090 | @app.route("/<path:path>") # type: ignore
|
1023 | 1091 | def index(_: str):
|
|
0 commit comments