233 lines
6.9 KiB
Python
233 lines
6.9 KiB
Python
# Copyright (c) 2023, JINGROW
|
|
# For license information, please see license.txt
|
|
|
|
from __future__ import annotations
|
|
|
|
import random
|
|
|
|
import jingrow
|
|
import jingrow.utils
|
|
from jingrow.rate_limiter import rate_limit
|
|
|
|
from jcloude.api.account import get_account_request_from_key
|
|
from jcloude.jcloude.pagetype.team.team import Team
|
|
from jcloude.saas.pagetype.product_trial.product_trial import send_verification_mail_for_login
|
|
from jcloude.utils.telemetry import capture
|
|
|
|
|
|
def _get_active_site(product: str, team: str | None) -> str | None:
|
|
if team is None:
|
|
return None
|
|
product_trial_linked_sites = jingrow.get_all(
|
|
"Product Trial Request",
|
|
{"product_trial": product, "team": team, "status": ["not in", ["Pending", "Error", "Expired"]]},
|
|
pluck="site",
|
|
)
|
|
if not product_trial_linked_sites:
|
|
return None
|
|
existing_sites = jingrow.get_all(
|
|
"Site",
|
|
{
|
|
"name": ["in", product_trial_linked_sites],
|
|
"status": ["!=", "Archived"],
|
|
},
|
|
pluck="name",
|
|
limit=1,
|
|
)
|
|
if len(existing_sites) > 0:
|
|
return existing_sites[0]
|
|
return None
|
|
|
|
|
|
@jingrow.whitelist(allow_guest=True)
|
|
def send_verification_code_for_login(email: str, product: str):
|
|
is_user_exists = jingrow.db.exists("Team", {"user": email}) and _get_active_site(
|
|
product, jingrow.db.get_value("Team", {"user": email}, "name")
|
|
)
|
|
if not is_user_exists:
|
|
jingrow.throw("You have no active sites for this product. Please try signing up.")
|
|
# generate otp and store in redis
|
|
otp = random.randint(100000, 999999)
|
|
jingrow.cache.set_value(
|
|
f"product_trial_login_verification_code:{email}",
|
|
jingrow.utils.sha256_hash(str(otp)),
|
|
expires_in_sec=300,
|
|
)
|
|
|
|
send_verification_mail_for_login(email, product, otp)
|
|
|
|
|
|
@jingrow.whitelist(allow_guest=True)
|
|
@rate_limit(limit=10, seconds=300)
|
|
def login_using_code(email: str, product: str, code: str):
|
|
team_exists = jingrow.db.exists("Team", {"user": email})
|
|
site = _get_active_site(product, jingrow.db.get_value("Team", {"user": email}, "name"))
|
|
if not team_exists:
|
|
jingrow.throw("You have no active sites for this product. Please try signing up.")
|
|
|
|
# check if team has 2fa enabled and active
|
|
team = jingrow.get_value("Team", {"user": email}, ["name", "enforce_2fa", "enabled"], as_dict=True)
|
|
if not team.enabled:
|
|
jingrow.throw("Your account is disabled. Please contact support.")
|
|
if team.enforce_2fa:
|
|
jingrow.throw("Your account has 2FA enabled. Please go to jcloud.jingrow.com to login.")
|
|
|
|
# validate code
|
|
code_hash_from_cache = jingrow.cache.get_value(f"product_trial_login_verification_code:{email}")
|
|
if not code_hash_from_cache:
|
|
jingrow.throw("OTP has expired. Please try again.")
|
|
if jingrow.utils.sha256_hash(str(code)) != code_hash_from_cache:
|
|
jingrow.throw("Invalid OTP. Please try again.")
|
|
|
|
# remove code from cache
|
|
jingrow.cache.delete_value(f"product_trial_login_verification_code:{email}")
|
|
|
|
# login as user
|
|
jingrow.set_user(email)
|
|
jingrow.local.login_manager.login_as(email)
|
|
|
|
# send the product trial request name
|
|
return jingrow.get_value(
|
|
"Product Trial Request",
|
|
{"product_trial": product, "team": team.name, "site": site},
|
|
pluck="name",
|
|
)
|
|
|
|
|
|
@jingrow.whitelist(allow_guest=True)
|
|
@rate_limit(limit=5, seconds=60)
|
|
def get_account_request_for_product_signup():
|
|
return jingrow.db.get_value("Account Request", {"email": jingrow.session.user}, "name")
|
|
|
|
|
|
@jingrow.whitelist(allow_guest=True, methods=["POST"])
|
|
def setup_account(key: str, country: str | None = None):
|
|
ar = get_account_request_from_key(key)
|
|
if not ar:
|
|
jingrow.throw("Invalid or Expired Key")
|
|
if not ar.product_trial:
|
|
jingrow.throw("Invalid Product Trial")
|
|
|
|
if country:
|
|
ar.country = country
|
|
ar.save(ignore_permissions=True)
|
|
|
|
if not ar.country:
|
|
jingrow.throw("Please provide a valid country name")
|
|
|
|
jingrow.set_user("Administrator")
|
|
# check if team already exists
|
|
if jingrow.db.exists("Team", {"user": ar.email}):
|
|
# Update first name and last name
|
|
team = jingrow.get_pg("Team", {"user": ar.email})
|
|
team.first_name = ar.first_name
|
|
team.last_name = ar.last_name
|
|
team.save(ignore_permissions=True)
|
|
# create team
|
|
else:
|
|
# check if user exists
|
|
is_user_exists = jingrow.db.exists("User", ar.email)
|
|
team = Team.create_new(
|
|
account_request=ar,
|
|
first_name=ar.first_name,
|
|
last_name=ar.last_name,
|
|
country=ar.country,
|
|
is_us_eu=ar.is_us_eu,
|
|
user_exists=is_user_exists,
|
|
)
|
|
# Telemetry: Created account
|
|
capture("completed_signup", "fc_product_trial", ar.email)
|
|
# login
|
|
jingrow.set_user(ar.email)
|
|
jingrow.local.login_manager.login_as(ar.email)
|
|
if _get_active_site(ar.product_trial, team.name):
|
|
return {
|
|
"account_request": ar.name,
|
|
"location": f"/dashboard/saas/{ar.product_trial}/login-to-site?account_request={ar.name}",
|
|
}
|
|
|
|
return {
|
|
"account_request": ar.name,
|
|
"location": f"/dashboard/saas/{ar.product_trial}/setup?account_request={ar.name}",
|
|
}
|
|
|
|
|
|
def _get_existing_trial_request(product: str, team: str):
|
|
return jingrow.get_value(
|
|
"Product Trial Request",
|
|
{"team": team, "status": ["not in", ["Error", "Expired", "Site Created"]], "product_trial": product},
|
|
["name", "site"],
|
|
as_dict=True,
|
|
)
|
|
|
|
|
|
@jingrow.whitelist(methods=["POST"])
|
|
def get_request(product: str, account_request: str | None = None) -> dict:
|
|
from jingrow.core.utils import find
|
|
|
|
from jcloude.utils import get_nearest_cluster
|
|
|
|
team = jingrow.local.team()
|
|
cluster = "Default"
|
|
|
|
# validate if there is already a site
|
|
if site := _get_active_site(product, team.name):
|
|
site_request = jingrow.get_pg(
|
|
"Product Trial Request", {"product_trial": product, "team": team, "site": site}
|
|
)
|
|
elif request := _get_existing_trial_request(product, team.name):
|
|
site_request = jingrow.get_pg("Product Trial Request", request.name)
|
|
else:
|
|
site_request = jingrow.new_pg(
|
|
"Product Trial Request",
|
|
product_trial=product,
|
|
team=team.name,
|
|
account_request=account_request,
|
|
).insert(ignore_permissions=True)
|
|
|
|
product_trial = jingrow.get_pg("Product Trial", product)
|
|
if product_trial.enable_hybrid_pooling:
|
|
cluster = None
|
|
fields = [rule.field for rule in product_trial.hybrid_pool_rules]
|
|
acc_req = (
|
|
jingrow.db.get_value(
|
|
"Account Request",
|
|
account_request,
|
|
fields,
|
|
as_dict=True,
|
|
)
|
|
if account_request
|
|
else None
|
|
)
|
|
|
|
for rule in product_trial.hybrid_pool_rules:
|
|
value = acc_req.get(rule.field) if acc_req else None
|
|
if not value:
|
|
break
|
|
|
|
if rule.value == value:
|
|
cluster = rule.preferred_cluster
|
|
break
|
|
|
|
if not cluster:
|
|
cluster = get_nearest_cluster()
|
|
else:
|
|
cluster = get_nearest_cluster()
|
|
domain = jingrow.db.get_value("Product Trial", product, "domain")
|
|
cluster_domains = jingrow.db.get_all(
|
|
"Root Domain", {"name": ("like", f"%.{domain}")}, ["name", "default_cluster as cluster"]
|
|
)
|
|
|
|
cluster_domain = find(
|
|
cluster_domains,
|
|
lambda d: d.cluster == cluster if cluster else False,
|
|
)
|
|
|
|
return {
|
|
"name": site_request.name,
|
|
"site": site_request.site,
|
|
"product_trial": site_request.product_trial,
|
|
"domain": cluster_domain["name"] if cluster_domain else domain,
|
|
"status": site_request.status,
|
|
}
|