Api changes (#161)

* fix(api): EE set password after invitation

* feat(api): FOS&EE return tracker version with the list of projects

* feat(api): FOS&EE signup changes

* feat(api): EE signup email existance error message
This commit is contained in:
Kraiem Taha Yassine 2021-08-20 18:22:37 +01:00 committed by GitHub
parent 1f3394f508
commit 10629a6b4f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 48 additions and 140 deletions

View file

@ -22,13 +22,6 @@ app = Blueprint(__name__)
_overrides.chalice_app(app)
@app.route('/signedups', methods=['GET'], authorizer=None)
def signed_ups():
return {
'data': tenants.get_tenants()
}
@app.route('/login', methods=['POST'], authorizer=None)
def login():
data = app.current_request.json_body
@ -52,7 +45,7 @@ def login():
c = tenants.get_by_tenant_id(tenant_id)
c.pop("createdAt")
c["projects"] = projects.get_projects(tenant_id=tenant_id, recording_state=True, recorded=True,
stack_integrations=True)
stack_integrations=True, version=True)
c["smtp"] = helper.has_smtp()
return {
'jwt': r.pop('jwt'),
@ -83,7 +76,7 @@ def get_account(context):
@app.route('/projects', methods=['GET'])
def get_projects(context):
return {"data": projects.get_projects(tenant_id=context["tenantId"], recording_state=True, gdpr=True, recorded=True,
stack_integrations=True)}
stack_integrations=True, version=True)}
@app.route('/projects', methods=['POST', 'PUT'])
@ -127,7 +120,7 @@ def get_client(context):
if r is not None:
r.pop("createdAt")
r["projects"] = projects.get_projects(tenant_id=context['tenantId'], recording_state=True, recorded=True,
stack_integrations=True)
stack_integrations=True, version=True)
return {
'data': r
}
@ -148,7 +141,7 @@ def put_client(context):
@app.route('/signup', methods=['GET'], authorizer=None)
def get_all_signup():
return {"data": signup.get_signed_ups()}
return {"data": tenants.tenants_exists()}
@app.route('/signup', methods=['POST', 'PUT'], authorizer=None)

View file

@ -41,7 +41,7 @@ def __create(tenant_id, name):
@dev.timed
def get_projects(tenant_id, recording_state=False, gdpr=None, recorded=False, stack_integrations=False):
def get_projects(tenant_id, recording_state=False, gdpr=None, recorded=False, stack_integrations=False,version=False):
with pg_client.PostgresClient() as cur:
cur.execute(f"""\
SELECT
@ -49,6 +49,7 @@ def get_projects(tenant_id, recording_state=False, gdpr=None, recorded=False, st
{',s.gdpr' if gdpr else ''}
{',COALESCE((SELECT TRUE FROM public.sessions WHERE sessions.project_id = s.project_id LIMIT 1), FALSE) AS recorded' if recorded else ''}
{',stack_integrations.count>0 AS stack_integrations' if stack_integrations else ''}
{',(SELECT tracker_version FROM public.sessions WHERE sessions.project_id = s.project_id ORDER BY start_ts DESC LIMIT 1) AS tracker_version' if version else ''}
FROM public.projects AS s
{'LEFT JOIN LATERAL (SELECT COUNT(*) AS count FROM public.integrations WHERE s.project_id = integrations.project_id LIMIT 1) AS stack_integrations ON TRUE' if stack_integrations else ''}
where s.deleted_at IS NULL

View file

@ -1,39 +1,31 @@
from chalicelib.utils import helper
from chalicelib.utils import pg_client
from chalicelib.core import users, telemetry
from chalicelib.core import users, telemetry, tenants
from chalicelib.utils import captcha
import json
from chalicelib.utils.TimeUTC import TimeUTC
from chalicelib.utils.helper import environ
def get_signed_ups():
with pg_client.PostgresClient() as cur:
cur.execute("SELECT tenant_id, name FROM public.tenants;")
rows = cur.fetchall()
return helper.list_to_camel_case(rows)
def create_step1(data):
print(f"===================== SIGNUP STEP 1 AT {TimeUTC.to_human_readable(TimeUTC.now())} UTC")
errors = []
if tenants.tenants_exists():
return {"errors": ["tenants already registered"]}
email = data.get("email")
print(f"=====================> {email}")
password = data.get("password")
print("Verifying email validity")
email_exists = False
if email is None or len(email) < 5 or not helper.is_valid_email(email):
errors.append("Invalid email address.")
else:
print("Verifying email existance")
if users.email_exists(email):
# errors.append("Email address already in use.")
email_exists = True
errors.append("Email address already in use.")
if users.get_deleted_user_by_email(email) is not None:
# errors.append("Email address previously deleted.")
email_exists = True
errors.append("Email address previously deleted.")
print("Verifying captcha")
if helper.allow_captcha() and not captcha.is_valid(data["g-recaptcha-response"]):
@ -57,12 +49,6 @@ def create_step1(data):
project_name = data.get("projectName")
if project_name is None or len(project_name) < 1:
project_name = "my first project"
signed_ups = get_signed_ups()
if len(signed_ups) > 0 and data.get("tenantId") is None:
errors.append("Tenant already exists, please select it from dropdown")
elif len(signed_ups) == 0 and data.get("tenantId") is not None \
or len(signed_ups) > 0 and data.get("tenantId") not in [t['tenantId'] for t in signed_ups]:
errors.append("Tenant not found")
if len(errors) > 0:
print("==> error")
@ -77,41 +63,7 @@ def create_step1(data):
"organizationName": company_name,
"versionNumber": environ["version_number"]
}
if data.get("tenantId") is not None:
update_user = """
u AS (
UPDATE public.users
SET name = %(fullname)s, deleted_at=NULL
WHERE email=%(email)s
RETURNING user_id,email, role, name
)
UPDATE public.basic_authentication
SET password= crypt(%(password)s, gen_salt('bf', 12))
WHERE user_id = (SELECT user_id FROM u)"""
insert_user = """
a AS (
UPDATE public.users
SET role='admin'
WHERE role ='owner'
),
u AS (
INSERT INTO public.users (email, role, name, data)
VALUES (%(email)s, 'owner', %(fullname)s,%(data)s)
RETURNING user_id,email,role,name
)
INSERT INTO public.basic_authentication (user_id, password, generated_password)
VALUES ((SELECT user_id FROM u), crypt(%(password)s, gen_salt('bf', 12)), FALSE)"""
query = f"""\
WITH t AS (
UPDATE public.tenants
SET name = %(organizationName)s,
version_number = %(versionNumber)s
RETURNING api_key
),
{update_user if email_exists else insert_user}
RETURNING (SELECT api_key FROM t) AS api_key,(SELECT project_id FROM projects LIMIT 1) AS project_id;"""
else:
query = f"""\
query = f"""\
WITH t AS (
INSERT INTO public.tenants (name, version_number, edition)
VALUES (%(organizationName)s, %(versionNumber)s, 'fos')

View file

@ -77,7 +77,7 @@ def update(tenant_id, user_id, data):
return edit_client(tenant_id=tenant_id, changes=changes)
def get_tenants():
def tenants_exists():
with pg_client.PostgresClient() as cur:
cur.execute(f"SELECT name FROM public.tenants")
return helper.list_to_camel_case(cur.fetchall())
cur.execute(f"SELECT EXISTS(SELECT 1 FROM public.tenants)")
return cur.fetchone()["exists"]

View file

@ -22,13 +22,6 @@ app = Blueprint(__name__)
_overrides.chalice_app(app)
@app.route('/signedups', methods=['GET'], authorizer=None)
def signed_ups():
return {
'data': tenants.get_tenants()
}
@app.route('/login', methods=['POST'], authorizer=None)
def login():
data = app.current_request.json_body
@ -54,7 +47,7 @@ def login():
c = tenants.get_by_tenant_id(tenant_id)
c.pop("createdAt")
c["projects"] = projects.get_projects(tenant_id=tenant_id, recording_state=True, recorded=True,
stack_integrations=True)
stack_integrations=True, version=True)
return {
'jwt': r.pop('jwt'),
'data': {
@ -85,7 +78,7 @@ def get_account(context):
@app.route('/projects', methods=['GET'])
def get_projects(context):
return {"data": projects.get_projects(tenant_id=context["tenantId"], recording_state=True, gdpr=True, recorded=True,
stack_integrations=True)}
stack_integrations=True, version=True)}
@app.route('/projects', methods=['POST', 'PUT'])
@ -129,7 +122,7 @@ def get_client(context):
if r is not None:
r.pop("createdAt")
r["projects"] = projects.get_projects(tenant_id=context['tenantId'], recording_state=True, recorded=True,
stack_integrations=True)
stack_integrations=True, version=True)
return {
'data': r
}
@ -148,10 +141,9 @@ def put_client(context):
return tenants.update(tenant_id=context["tenantId"], user_id=context["userId"], data=data)
# TODO: delete this for production; it is used for dev only
@app.route('/signup', methods=['GET'], authorizer=None)
def get_all_signup():
return {"data": signup.get_signed_ups()}
return {"data": tenants.tenants_exists()}
@app.route('/signup', methods=['POST', 'PUT'], authorizer=None)
@ -391,7 +383,8 @@ def change_password_by_invitation():
if user["expiredChange"]:
return {"errors": ["expired change, please re-use the invitation link"]}
return users.set_password_invitation(new_password=data["password"], user_id=user["userId"])
return users.set_password_invitation(new_password=data["password"], user_id=user["userId"],
tenant_id=user["tenantId"])
@app.route('/client/members/{memberId}', methods=['PUT', 'POST'])

View file

@ -40,7 +40,7 @@ def __create(tenant_id, name):
return get_project(tenant_id=tenant_id, project_id=project_id, include_gdpr=True)
def get_projects(tenant_id, recording_state=False, gdpr=None, recorded=False, stack_integrations=False):
def get_projects(tenant_id, recording_state=False, gdpr=None, recorded=False, stack_integrations=False, version=False):
with pg_client.PostgresClient() as cur:
cur.execute(
cur.mogrify(f"""\
@ -49,6 +49,7 @@ def get_projects(tenant_id, recording_state=False, gdpr=None, recorded=False, st
{',s.gdpr' if gdpr else ''}
{',COALESCE((SELECT TRUE FROM public.sessions WHERE sessions.project_id = s.project_id LIMIT 1), FALSE) AS recorded' if recorded else ''}
{',stack_integrations.count>0 AS stack_integrations' if stack_integrations else ''}
{',(SELECT tracker_version FROM public.sessions WHERE sessions.project_id = s.project_id ORDER BY start_ts DESC LIMIT 1) AS tracker_version' if version else ''}
FROM public.projects AS s
{'LEFT JOIN LATERAL (SELECT COUNT(*) AS count FROM public.integrations WHERE s.project_id = integrations.project_id LIMIT 1) AS stack_integrations ON TRUE' if stack_integrations else ''}
where s.tenant_id =%(tenant_id)s

View file

@ -1,22 +1,17 @@
from chalicelib.utils import helper
from chalicelib.utils import pg_client
from chalicelib.core import users, telemetry
from chalicelib.core import users, telemetry, tenants
from chalicelib.utils import captcha
import json
from chalicelib.utils.TimeUTC import TimeUTC
from chalicelib.utils.helper import environ
def get_signed_ups():
with pg_client.PostgresClient() as cur:
cur.execute("SELECT tenant_id, name FROM public.tenants;")
rows = cur.fetchall()
return helper.list_to_camel_case(rows)
def create_step1(data):
print(f"===================== SIGNUP STEP 1 AT {TimeUTC.to_human_readable(TimeUTC.now())} UTC")
errors = []
if tenants.tenants_exists():
return {"errors":["tenants already registered"]}
email = data.get("email")
print(f"=====================> {email}")
@ -54,64 +49,37 @@ def create_step1(data):
project_name = data.get("projectName")
if project_name is None or len(project_name) < 1:
project_name = "my first project"
signed_ups = get_signed_ups()
if len(signed_ups) == 0 and data.get("tenantId") is not None \
or len(signed_ups) > 0 and data.get("tenantId") is not None\
and data.get("tenantId") not in [t['tenantId'] for t in signed_ups]:
errors.append("Tenant not found")
if len(errors) > 0:
print("==> error")
print(errors)
return {"errors": errors}
print("No errors detected")
print("Decomposed infos")
tenant_id = data.get("tenantId")
params = {"email": email, "password": password,
"fullname": fullname, "companyName": company_name,
"projectName": project_name,
"versionNumber": environ["version_number"],
"data": json.dumps({"lastAnnouncementView": TimeUTC.now()})}
if tenant_id is not None:
query = """\
WITH t AS (
UPDATE public.tenants
SET name = %(companyName)s,
version_number = %(versionNumber)s
WHERE tenant_id=%(tenant_id)s
query = """\
WITH t AS (
INSERT INTO public.tenants (name, version_number, edition)
VALUES (%(companyName)s, %(versionNumber)s, 'ee')
RETURNING tenant_id, api_key
),
u AS (
UPDATE public.users
SET email = %(email)s,
name = %(fullname)s,
WHERE role ='owner' AND tenant_id=%(tenant_id)s
RETURNING user_id,email, role, name
)
UPDATE public.basic_authentication
SET password= crypt(%(password)s, gen_salt('bf', 12))
WHERE user_id = (SELECT user_id FROM u)
RETURNING %(tenant_id)s AS tenant_id"""
else:
query = """\
WITH t AS (
INSERT INTO public.tenants (name, version_number, edition)
VALUES (%(companyName)s, %(versionNumber)s, 'ee')
RETURNING tenant_id, api_key
),
u AS (
INSERT INTO public.users (tenant_id, email, role, name, data)
VALUES ((SELECT tenant_id FROM t), %(email)s, 'owner', %(fullname)s,%(data)s)
RETURNING user_id,email,role,name
),
au AS (
INSERT INTO public.basic_authentication (user_id, password, generated_password)
VALUES ((SELECT user_id FROM u), crypt(%(password)s, gen_salt('bf', 12)), FALSE)
)
INSERT INTO public.projects (tenant_id, name, active)
VALUES ((SELECT t.tenant_id FROM t), %(projectName)s, TRUE)
RETURNING tenant_id,project_id, (SELECT api_key FROM t) AS api_key;"""
),
u AS (
INSERT INTO public.users (tenant_id, email, role, name, data)
VALUES ((SELECT tenant_id FROM t), %(email)s, 'owner', %(fullname)s,%(data)s)
RETURNING user_id,email,role,name
),
au AS (
INSERT INTO public.basic_authentication (user_id, password, generated_password)
VALUES ((SELECT user_id FROM u), crypt(%(password)s, gen_salt('bf', 12)), FALSE)
)
INSERT INTO public.projects (tenant_id, name, active)
VALUES ((SELECT t.tenant_id FROM t), %(projectName)s, TRUE)
RETURNING tenant_id,project_id, (SELECT api_key FROM t) AS api_key;"""
with pg_client.PostgresClient() as cur:
cur.execute(cur.mogrify(query, params))

View file

@ -101,7 +101,7 @@ def update(tenant_id, user_id, data):
return edit_client(tenant_id=tenant_id, changes=changes)
def get_tenants():
def tenants_exists():
with pg_client.PostgresClient() as cur:
cur.execute(f"SELECT name FROM public.tenants")
return helper.list_to_camel_case(cur.fetchall())
cur.execute(f"SELECT EXISTS(SELECT 1 FROM public.tenants)")
return cur.fetchone()["exists"]

View file

@ -440,11 +440,11 @@ def change_password(tenant_id, user_id, email, old_password, new_password):
"jwt": authenticate(email, new_password)["jwt"]}
def set_password_invitation(user_id, new_password):
def set_password_invitation(tenant_id, user_id, new_password):
changes = {"password": new_password, "generatedPassword": False,
"invitationToken": None, "invitedAt": None,
"changePwdExpireAt": None, "changePwdToken": None}
user = update(tenant_id=-1, user_id=user_id, changes=changes)
user = update(tenant_id=tenant_id, user_id=user_id, changes=changes)
r = authenticate(user['email'], new_password)
tenant_id = r.pop("tenantId")