Merge branch 'main' of github.com:openreplay/openreplay into main
|
|
@ -14,15 +14,15 @@
|
|||
"isFOS": "true",
|
||||
"isEE": "false",
|
||||
"stage": "default-fos",
|
||||
"jwt_issuer": "asayer-default-fos",
|
||||
"jwt_issuer": "openreplay-default-fos",
|
||||
"allowCron": "true",
|
||||
"sentry": "false",
|
||||
"sentryURL": "",
|
||||
"pg_host": "",
|
||||
"pg_host": "postgresql.db.svc.cluster.local",
|
||||
"pg_port": "5432",
|
||||
"pg_dbname": "",
|
||||
"pg_user": "",
|
||||
"pg_password": "",
|
||||
"pg_dbname": "postgres",
|
||||
"pg_user": "postgres",
|
||||
"pg_password": "asayerPostgres",
|
||||
"alert_ntf": "http://127.0.0.1:8000/async/alerts/notifications/%s",
|
||||
"email_signup": "http://127.0.0.1:8000/async/email_signup/%s",
|
||||
"email_funnel": "http://127.0.0.1:8000/async/funnel/%s",
|
||||
|
|
@ -44,7 +44,6 @@
|
|||
"sourcemaps_bucket_secret": "",
|
||||
"sourcemaps_bucket_region": "",
|
||||
"js_cache_bucket": "",
|
||||
"web_mobs": "https://mobs-staging.asayer.io",
|
||||
"async_Token": "",
|
||||
"EMAIL_HOST": "",
|
||||
"EMAIL_PORT": "587",
|
||||
|
|
@ -56,10 +55,13 @@
|
|||
"EMAIL_SSL_CERT": "",
|
||||
"EMAIL_FROM": "OpenReplay<do-not-reply@openreplay.com>",
|
||||
"SITE_URL": "",
|
||||
"announcement_bucket": "",
|
||||
"announcement_url": "",
|
||||
"jwt_secret": "",
|
||||
"jwt_algorithm": "HS512",
|
||||
"jwt_exp_delta_seconds": "2592000"
|
||||
"jwt_exp_delta_seconds": "2592000",
|
||||
"S3_HOST": "",
|
||||
"S3_KEY": "",
|
||||
"S3_SECRET": ""
|
||||
},
|
||||
"lambda_timeout": 150,
|
||||
"lambda_memory_size": 400,
|
||||
|
|
|
|||
|
|
@ -13,4 +13,4 @@ ENV ENTERPRISE_BUILD ${envarg}
|
|||
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
|
||||
RUN chmod +x /tini
|
||||
ENTRYPOINT ["/tini", "--"]
|
||||
CMD chalice local --no-autoreload --host 0.0.0.0 --stage ${ENTERPRISE_BUILD}
|
||||
CMD python env_handler.py && chalice local --no-autoreload --host 0.0.0.0 --stage ${ENTERPRISE_BUILD}
|
||||
|
|
@ -55,7 +55,7 @@ sys.stderr = F()
|
|||
|
||||
_overrides.chalice_app(app)
|
||||
|
||||
# v0505
|
||||
# v0905
|
||||
@app.middleware('http')
|
||||
def asayer_middleware(event, get_response):
|
||||
global ASAYER_SESSION_ID
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ base_time = datetime.now(pytz.utc)
|
|||
|
||||
cors_config = CORSConfig(
|
||||
allow_origin='*',
|
||||
allow_headers=['vnd.asayer.io.sid'],
|
||||
allow_headers=['vnd.openreplay.com.sid'],
|
||||
# max_age=600,
|
||||
# expose_headers=['X-Special-Header'],
|
||||
allow_credentials=True
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ def get_all(user_id):
|
|||
for a in announcements:
|
||||
a["createdAt"] = TimeUTC.datetime_to_timestamp(a["createdAt"])
|
||||
if a["imageUrl"] is not None and len(a["imageUrl"]) > 0:
|
||||
a["imageUrl"] = environ["announcement_bucket"] + a["imageUrl"]
|
||||
a["imageUrl"] = environ["announcement_url"] + a["imageUrl"]
|
||||
return announcements
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -40,20 +40,20 @@ def get_state(tenant_id):
|
|||
meta = cur.fetchone()["sum"] > 0
|
||||
|
||||
return [
|
||||
{"task": "Install Asayer",
|
||||
{"task": "Install OpenReplay",
|
||||
"done": recorded,
|
||||
"URL": "https://docs.asayer.io/getting-started/quick-start"},
|
||||
"URL": "https://docs.openreplay.com/getting-started/quick-start"},
|
||||
{"task": "Identify Users",
|
||||
"done": meta,
|
||||
"URL": "https://docs.asayer.io/data-privacy-security/metadata"},
|
||||
"URL": "https://docs.openreplay.com/data-privacy-security/metadata"},
|
||||
{"task": "Invite Team Members",
|
||||
"done": len(users.get_members(tenant_id=tenant_id)) > 1,
|
||||
"URL": "https://app.asayer.io/client/manage-users"},
|
||||
"URL": "https://app.openreplay.com/client/manage-users"},
|
||||
{"task": "Integrations",
|
||||
"done": len(log_tool_datadog.get_all(tenant_id=tenant_id)) > 0 \
|
||||
or len(log_tool_sentry.get_all(tenant_id=tenant_id)) > 0 \
|
||||
or len(log_tool_stackdriver.get_all(tenant_id=tenant_id)) > 0,
|
||||
"URL": "https://docs.asayer.io/integrations"}
|
||||
"URL": "https://docs.openreplay.com/integrations"}
|
||||
]
|
||||
|
||||
|
||||
|
|
@ -75,9 +75,9 @@ def get_state_installing(tenant_id):
|
|||
)
|
||||
recorded = cur.fetchone()["count"] > 0
|
||||
|
||||
return {"task": "Install Asayer",
|
||||
return {"task": "Install OpenReplay",
|
||||
"done": recorded,
|
||||
"URL": "https://docs.asayer.io/getting-started/quick-start"}
|
||||
"URL": "https://docs.openreplay.com/getting-started/quick-start"}
|
||||
|
||||
|
||||
def get_state_identify_users(tenant_id):
|
||||
|
|
@ -99,13 +99,13 @@ def get_state_identify_users(tenant_id):
|
|||
|
||||
return {"task": "Identify Users",
|
||||
"done": meta,
|
||||
"URL": "https://docs.asayer.io/data-privacy-security/metadata"}
|
||||
"URL": "https://docs.openreplay.com/data-privacy-security/metadata"}
|
||||
|
||||
|
||||
def get_state_manage_users(tenant_id):
|
||||
return {"task": "Invite Team Members",
|
||||
"done": len(users.get_members(tenant_id=tenant_id)) > 1,
|
||||
"URL": "https://app.asayer.io/client/manage-users"}
|
||||
"URL": "https://app.openreplay.com/client/manage-users"}
|
||||
|
||||
|
||||
def get_state_integrations(tenant_id):
|
||||
|
|
@ -113,4 +113,4 @@ def get_state_integrations(tenant_id):
|
|||
"done": len(log_tool_datadog.get_all(tenant_id=tenant_id)) > 0 \
|
||||
or len(log_tool_sentry.get_all(tenant_id=tenant_id)) > 0 \
|
||||
or len(log_tool_stackdriver.get_all(tenant_id=tenant_id)) > 0,
|
||||
"URL": "https://docs.asayer.io/integrations"}
|
||||
"URL": "https://docs.openreplay.com/integrations"}
|
||||
|
|
|
|||
|
|
@ -503,8 +503,8 @@ def search(data, project_id, user_id, flows=False, status="ALL", favorite_only=F
|
|||
GROUP BY timestamp
|
||||
ORDER BY timestamp) AS chart_details) AS chart_details ON (TRUE);"""
|
||||
|
||||
print("--------------------")
|
||||
print(cur.mogrify(main_pg_query, params))
|
||||
# print("--------------------")
|
||||
# print(cur.mogrify(main_pg_query, params))
|
||||
cur.execute(cur.mogrify(main_pg_query, params))
|
||||
total = cur.rowcount
|
||||
if flows:
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class GithubIntegrationIssue(BaseIntegrationIssue):
|
|||
if a == str(u["id"]):
|
||||
real_assignees.append(u["login"])
|
||||
break
|
||||
real_labels = ["Asayer"]
|
||||
real_labels = ["OpenReplay"]
|
||||
for l in labels:
|
||||
found = False
|
||||
for ll in metas["issueTypes"]:
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ class JIRACloudIntegrationIssue(BaseIntegrationIssue):
|
|||
'description': description,
|
||||
'issuetype': {'id': issue_type},
|
||||
'assignee': {"id": assignee},
|
||||
"labels": ["Asayer"]
|
||||
"labels": ["OpenReplay"]
|
||||
}
|
||||
return self._client.create_issue(data)
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ class JIRACloudIntegrationIssue(BaseIntegrationIssue):
|
|||
results = []
|
||||
for integration_project_id in projects_map:
|
||||
self._client.set_jira_project_id(integration_project_id)
|
||||
jql = 'labels = Asayer'
|
||||
jql = 'labels = OpenReplay'
|
||||
if len(projects_map[integration_project_id]) > 0:
|
||||
jql += f" AND ID IN ({','.join(projects_map[integration_project_id])})"
|
||||
issues = self._client.get_issues(jql, offset=0)
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ def __find_events(client, log_group, streams, last_token, start_time, end_time):
|
|||
"startTime": start_time,
|
||||
"endTime": end_time,
|
||||
"limit": 10000,
|
||||
"filterPattern": "asayer_session_id"
|
||||
"filterPattern": "openreplay_session_id"
|
||||
}
|
||||
if last_token is not None:
|
||||
f_args["nextToken"] = last_token
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
from chalicelib.utils import pg_client, helper
|
||||
from chalicelib.core import events, sessions_metas, socket_ios, metadata, events_ios, \
|
||||
sessions_mobs
|
||||
from chalicelib.utils import dev
|
||||
from chalicelib.core import events, sessions_metas, socket_ios, metadata, events_ios, sessions_mobs
|
||||
|
||||
if helper.is_free_open_source_edition():
|
||||
from chalicelib.core import projects, errors
|
||||
else:
|
||||
from chalicelib.ee import projects, errors
|
||||
from chalicelib.core import projects, errors
|
||||
|
||||
from chalicelib.core import resources
|
||||
|
||||
|
|
|
|||
|
|
@ -56,8 +56,13 @@ def create_step1(data):
|
|||
project_name = data.get("projectName")
|
||||
if project_name is None or len(project_name) < 1:
|
||||
project_name = "my first project"
|
||||
if len(get_signed_ups()) > 0 and data.get("tenantId") is None:
|
||||
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 does not exist")
|
||||
|
||||
if len(errors) > 0:
|
||||
print("==> error")
|
||||
print(errors)
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ def compute():
|
|||
RETURNING *,(SELECT email FROM public.users WHERE role='owner' LIMIT 1);"""
|
||||
)
|
||||
data = cur.fetchone()
|
||||
requests.post('https://parrot.asayer.io/os/telemetry', json=process_data(data))
|
||||
requests.post('https://parrot.openreplay.com/os/telemetry', json=process_data(data))
|
||||
|
||||
|
||||
def new_client():
|
||||
|
|
@ -40,4 +40,4 @@ def new_client():
|
|||
(SELECT email FROM public.users WHERE role='owner' LIMIT 1) AS email
|
||||
FROM public.tenants;""")
|
||||
data = cur.fetchone()
|
||||
requests.post('https://parrot.asayer.io/os/signup', json=process_data(data))
|
||||
requests.post('https://parrot.openreplay.com/os/signup', json=process_data(data))
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ def timed(f):
|
|||
'handle_request', '_generic_handle', 'handle', '_bootstrap_inner', 'run',
|
||||
'_bootstrap', '_main_rest_api_handler', '_user_handler',
|
||||
'_get_view_function_response', 'wrapped_event', 'handle_one_request',
|
||||
'_global_error_handler', 'asayer_middleware']]
|
||||
'_global_error_handler', 'openreplay_middleware']]
|
||||
print("DEBUG: %s > %s took %d s to finish" % (" > ".join(call_stack), f.__name__, elapsed))
|
||||
return result
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ def send_team_invitation(recipient, user_name, temp_password, client_id, sender_
|
|||
formatting_variables={"userName": __escape_text_html(user_name),
|
||||
"password": temp_password, "clientId": client_id,
|
||||
"sender": sender_name})
|
||||
SUBJECT = "Welcome to Asayer"
|
||||
SUBJECT = "Welcome to OpenReplay"
|
||||
send_html(BODY_HTML, SUBJECT, recipient)
|
||||
|
||||
|
||||
|
|
@ -115,5 +115,5 @@ def weekly_report2(recipients, data):
|
|||
</table>
|
||||
</td>"""
|
||||
BODY_HTML = __get_html_from_file("chalicelib/utils/html/Project-Weekly-Report.html", formatting_variables=data)
|
||||
SUBJECT = "Asayer Project Weekly Report"
|
||||
SUBJECT = "OpenReplay Project Weekly Report"
|
||||
send_html(BODY_HTML=BODY_HTML, SUBJECT=SUBJECT, recipient=recipients)
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ class github_formatters:
|
|||
'createdAt': github_formatters.get_timestamp(issue["created_at"]),
|
||||
'closed': issue["closed_at"] is not None,
|
||||
'commentsCount': issue["comments"],
|
||||
'issueType': [str(l["id"]) for l in labels if l["name"].lower() != "asayer"],
|
||||
'issueType': [str(l["id"]) for l in labels if l["name"].lower() != "openreplay"],
|
||||
'labels': [l["name"] for l in labels]
|
||||
}
|
||||
return result
|
||||
|
|
|
|||
|
|
@ -40,17 +40,6 @@ def generate_salt():
|
|||
return "".join(random.choices(string.hexdigits, k=36))
|
||||
|
||||
|
||||
def remove_empty_none_values(dictionary):
|
||||
aux = {}
|
||||
for key in dictionary.keys():
|
||||
if dictionary[key] is not None:
|
||||
if isinstance(dictionary[key], dict):
|
||||
aux[key] = remove_empty_none_values(dictionary[key])
|
||||
elif not isinstance(dictionary[key], str) or len(dictionary[key]) > 0:
|
||||
aux[key] = dictionary[key]
|
||||
return aux
|
||||
|
||||
|
||||
def unique_ordered_list(array):
|
||||
uniq = []
|
||||
[uniq.append(x) for x in array if x not in uniq]
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<table style="width:100%;font-weight:300;margin-bottom:0;border-collapse:collapse">
|
||||
<tbody><tr style="font-weight:300">
|
||||
<td width="125px" style="font-size:14px;padding:0;font-weight:300;margin:0;text-align:left">
|
||||
<a href="%(frontend_url)s" style="color:#394EFF;font-weight:300;text-decoration:none" target="_blank" data-saferedirecturl="" width="125px" height="29px" alt="asayer" style="font-weight:300"><img src="img/weekly/asayer-logo.png" style="width: 160px;"></a>
|
||||
<a href="%(frontend_url)s" style="color:#394EFF;font-weight:300;text-decoration:none" target="_blank" data-saferedirecturl="" width="125px" height="29px" alt="openreplay" style="font-weight:300"><img src="img/weekly/logo.png" style="width: 160px;"></a>
|
||||
</td>
|
||||
<td style="font-size:14px;padding:0;font-weight:300;margin:0;text-align:right">
|
||||
<table style="width:100%;font-weight:300;margin-bottom:0;border-collapse:collapse">
|
||||
|
|
@ -154,7 +154,7 @@
|
|||
<div style="padding:10px 20px;max-width:600px;font-weight:300;margin:0 auto;text-align:left">
|
||||
<div style="padding:35px 0;border-top:1px solid #e7ebee;font-weight:300; font-size: 13px;">
|
||||
|
||||
<a href="%(frontend_url)s/%(project_id)s/metrics" style="color:#394EFF;float:right;font-weight:300;text-decoration:none" target="_blank" data-saferedirecturl="#">Asayer Metrics</a>
|
||||
<a href="%(frontend_url)s/%(project_id)s/metrics" style="color:#394EFF;float:right;font-weight:300;text-decoration:none" target="_blank" data-saferedirecturl="#">OpenReplay Metrics</a>
|
||||
|
||||
<a href="%(frontend_url)s/client/notifications" style="color:#394EFF;font-weight:300;text-decoration:none" target="_blank" data-saferedirecturl="#">Manage Notifications</a>
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<tr>
|
||||
<td style="padding:10px 30px;">
|
||||
<center>
|
||||
<img src="img/asayer-logo.png" alt="Asayer" width="100%" style="max-width: 120px;">
|
||||
<img src="img/logo.png" alt="OpenReplay" width="100%" style="max-width: 120px;">
|
||||
</center>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
@ -38,9 +38,9 @@
|
|||
<div style="border-top:1px dotted rgba(0,0,0,0.2); display: block; margin-top: 20px"></div>
|
||||
<center>
|
||||
<p style="font-size: 12px; font-family: -apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,'Helvetica Neue',sans-serif; color: #6c757d">
|
||||
Sent with ♡ from Asayer © 2021 - All rights reserved.<br><br>
|
||||
<a href="https://asayer.io" target="_blank"
|
||||
style="text-decoration: none; color: #6c757d">https://asayer.io/</a>
|
||||
Sent with ♡ from OpenReplay © 2021 - All rights reserved.<br><br>
|
||||
<a href="https://openreplay.com" target="_blank"
|
||||
style="text-decoration: none; color: #6c757d">https://openreplay.com/</a>
|
||||
</p>
|
||||
|
||||
</center>
|
||||
|
|
|
|||
|
|
@ -385,7 +385,7 @@ width: 25%!important
|
|||
<td style="padding-right: 0px;padding-left: 0px;" align="center">
|
||||
<![endif]-->
|
||||
<img style="width=124px; height=35px;" width="124px" height="35px"
|
||||
src="img/asayer-logo.png"/>
|
||||
src="img/logo.png"/>
|
||||
|
||||
<!--[if mso]></td></tr></table><![endif]-->
|
||||
</div>
|
||||
|
|
@ -401,7 +401,7 @@ width: 25%!important
|
|||
<div style="color:#555555;font-family:'Helvetica Neue', Helvetica, Arial, sans-serif;line-height:120%;padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:10px;">
|
||||
<div style="font-size: 12px; line-height: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; color: #555555;">
|
||||
<!-- <p style="font-size: 18px; line-height: 21px; text-align: center; margin: 0;">
|
||||
<span style="font-size: 18px;">Welcome to Asayer!</span>
|
||||
<span style="font-size: 18px;">Welcome to OpenReplay!</span>
|
||||
</p>-->
|
||||
<h1 style="text-align: center; margin-top: 30px; line-height: 30px">Assigned session</h1>
|
||||
|
||||
|
|
@ -514,10 +514,10 @@ width: 25%!important
|
|||
<div style="color:#555555;font-family:-apple-system,BlinkMacSystemFont,'Helvetica Neue','Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,sans-serif;line-height:120%;padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:10px;">
|
||||
<div style="font-size: 12px; line-height: 14px; color: #555555; font-family: -apple-system,BlinkMacSystemFont,'Helvetica Neue','Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,sans-serif;">
|
||||
<p style="font-size: 14px; line-height: 16px; text-align: center; margin: 0;">
|
||||
<a href="mailto:support@asayer.io?subject=[User Invite] - Reporting issue"
|
||||
<a href="mailto:support@openreplay.com?subject=[User Invite] - Reporting issue"
|
||||
style="text-decoration: underline; color: #009193;"
|
||||
title="support@asayer.io">Report an issue</a> | <a
|
||||
href="https://asayer.io/" rel="noopener"
|
||||
title="support@openreplay.com">Report an issue</a> | <a
|
||||
href="https://openreplay.com/" rel="noopener"
|
||||
style="text-decoration: underline; color: #009193;" target="_blank">Take
|
||||
a tour</a></p>
|
||||
</div>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
|
@ -378,7 +378,7 @@ width: 25%!important
|
|||
<tr style="line-height:0px">
|
||||
<td style="padding-right: 0px;padding-left: 0px;" align="center">
|
||||
<![endif]-->
|
||||
<img style="width=124px; height=35px;" width="124px" height="35px" src="img/asayer-logo.png"/>
|
||||
<img style="width=124px; height=35px;" width="124px" height="35px" src="img/logo.png"/>
|
||||
|
||||
<!--[if mso]></td></tr></table><![endif]-->
|
||||
</div>
|
||||
|
|
@ -394,7 +394,7 @@ width: 25%!important
|
|||
<div style="color:#555555;font-family:'Helvetica Neue', Helvetica, Arial, sans-serif;line-height:120%;padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:10px;">
|
||||
<div style="font-size: 12px; line-height: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; color: #555555;">
|
||||
<p style="font-size: 14px; line-height: 21px; text-align: center; margin: 0;">
|
||||
<span style="font-size: 18px;"><strong>Welcome to Asayer!</strong></span>
|
||||
<span style="font-size: 18px;"><strong>Welcome to OpenReplay!</strong></span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -407,7 +407,7 @@ width: 25%!important
|
|||
<div style="color:#555555;font-family:-apple-system,BlinkMacSystemFont,'Helvetica Neue','Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,sans-serif;line-height:120%;padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:10px;">
|
||||
<div style="font-size: 12px; line-height: 14px; color: #555555; font-family: -apple-system,BlinkMacSystemFont,'Helvetica Neue','Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,sans-serif;">
|
||||
<p style="font-size: 12px; line-height: 16px; text-align: center; margin: 0;">
|
||||
<span style="font-size: 14px;">You have been invited by %(sender)s to join %(clientId)s team on Asayer.</span>
|
||||
<span style="font-size: 14px;">You have been invited by %(sender)s to join %(clientId)s team on OpenReplay.</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -450,7 +450,7 @@ width: 25%!important
|
|||
<span style="font-size: 18px;"><a href="%(frontend_url)s"
|
||||
rel="noopener"
|
||||
style="text-decoration: underline; color: #009193;"
|
||||
target="_blank" title="Asayer Login">%(frontend_url)s</a></span><span
|
||||
target="_blank" title="OpenReplay Login">%(frontend_url)s</a></span><span
|
||||
style="font-size: 18px; line-height: 21px;"></span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -553,10 +553,10 @@ width: 25%!important
|
|||
<div style="color:#555555;font-family:-apple-system,BlinkMacSystemFont,'Helvetica Neue','Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,sans-serif;line-height:120%;padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:10px;">
|
||||
<div style="font-size: 12px; line-height: 14px; color: #555555; font-family: -apple-system,BlinkMacSystemFont,'Helvetica Neue','Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,sans-serif;">
|
||||
<p style="font-size: 14px; line-height: 16px; text-align: center; margin: 0;">
|
||||
<a href="mailto:support@asayer.io?subject=[User Invite] - Reporting issue"
|
||||
<a href="mailto:support@openreplay.com?subject=[User Invite] - Reporting issue"
|
||||
style="text-decoration: underline; color: #009193;"
|
||||
title="support@asayer.io">Report an issue</a> | <a
|
||||
href="https://asayer.io/" rel="noopener"
|
||||
title="support@openreplay.com">Report an issue</a> | <a
|
||||
href="https://openreplay.com/" rel="noopener"
|
||||
style="text-decoration: underline; color: #009193;" target="_blank">Take
|
||||
a tour</a></p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -385,7 +385,7 @@ width: 25%!important
|
|||
<td style="padding-right: 0px;padding-left: 0px;" align="center">
|
||||
<![endif]-->
|
||||
<img style="width=124px; height=35px;" width="124px" height="35px"
|
||||
src="img/asayer-logo.png"/>
|
||||
src="img/logo.png"/>
|
||||
|
||||
<!--[if mso]></td></tr></table><![endif]-->
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,15 @@
|
|||
from botocore.exceptions import ClientError
|
||||
from chalicelib.utils.helper import environ
|
||||
|
||||
import boto3
|
||||
|
||||
client = boto3.client('s3')
|
||||
sts_client = boto3.client('sts')
|
||||
from botocore.client import Config
|
||||
|
||||
client = boto3.client('s3', endpoint_url=environ["S3_HOST"],
|
||||
aws_access_key_id=environ["S3_KEY"],
|
||||
aws_secret_access_key=environ["S3_SECRET"],
|
||||
config=Config(signature_version='s3v4'),
|
||||
region_name='us-east-1')
|
||||
|
||||
|
||||
def exists(bucket, key):
|
||||
|
|
|
|||
17
api/env_handler.py
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
from os import environ
|
||||
import json
|
||||
|
||||
with open('.chalice/config.json') as json_file:
|
||||
data = json.load(json_file)
|
||||
stages = data.get("stages", {})
|
||||
for s in stages.keys():
|
||||
target = f'chalicelib/.configs/{stages[s].get("environment_variables", {}).get("stage", s)}.json'
|
||||
data = {}
|
||||
try:
|
||||
with open(target) as stage_vars:
|
||||
data = json.load(stage_vars)
|
||||
except IOError:
|
||||
pass
|
||||
with open(target, 'w') as outfile:
|
||||
json.dump({**data, **environ}, outfile, indent=2, sort_keys=True)
|
||||
print(f"injected env-vars to {target}")
|
||||
|
|
@ -6,7 +6,7 @@ With regard to the OpenReplay Software:
|
|||
This software and associated documentation files (the "Software") may only be
|
||||
used in production, if you (and any entity that you represent) have agreed to,
|
||||
and are in compliance with, the OpenReplay Subscription Terms of Service, available
|
||||
at https://openreplay.com/terms.html (the “Enterprise Terms”), or other
|
||||
at https://openreplay.com/terms.html (the “Enterprise Edition”), or other
|
||||
agreement governing the use of the Software, as agreed by you and OpenReplay,
|
||||
and otherwise have a valid OpenReplay Enterprise license for the
|
||||
correct volume and number of seats. Subject to the foregoing sentence, you are free to
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
"isFOS": "false",
|
||||
"isEE": "true",
|
||||
"stage": "default-ee",
|
||||
"jwt_issuer": "asayer-default-ee",
|
||||
"jwt_issuer": "openreplay-default-ee",
|
||||
"allowCron": "true",
|
||||
"sentry": "false",
|
||||
"sentryURL": "",
|
||||
|
|
@ -49,7 +49,6 @@
|
|||
"js_cache_bucket": "",
|
||||
"SIGN_ID": "",
|
||||
"SIGN_KEY": "",
|
||||
"web_mobs": "https://mobs-staging.asayer.io",
|
||||
"async_Token": "",
|
||||
"EMAIL_HOST": "",
|
||||
"EMAIL_PORT": "587",
|
||||
|
|
@ -61,10 +60,13 @@
|
|||
"EMAIL_SSL_CERT": "",
|
||||
"EMAIL_FROM": "OpenReplay<do-not-reply@openreplay.com>",
|
||||
"SITE_URL": "",
|
||||
"announcement_bucket": "",
|
||||
"announcement_url": "",
|
||||
"jwt_secret": "",
|
||||
"jwt_algorithm": "",
|
||||
"jwt_exp_delta_seconds": ""
|
||||
"jwt_exp_delta_seconds": "",
|
||||
"S3_HOST": "",
|
||||
"S3_KEY": "",
|
||||
"S3_SECRET": ""
|
||||
},
|
||||
"lambda_timeout": 150,
|
||||
"lambda_memory_size": 400,
|
||||
|
|
|
|||
|
|
@ -60,6 +60,9 @@ _overrides.chalice_app(app)
|
|||
|
||||
@app.middleware('http')
|
||||
def asayer_middleware(event, get_response):
|
||||
from chalicelib.ee import unlock
|
||||
if not unlock.is_valid():
|
||||
return Response(body={"errors": ["expired license"]}, status_code=403)
|
||||
if "{projectid}" in event.path.lower():
|
||||
from chalicelib.ee import projects
|
||||
if not projects.is_authorized(project_id=event.uri_params["projectId"],
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ base_time = datetime.now(pytz.utc)
|
|||
|
||||
cors_config = CORSConfig(
|
||||
allow_origin='*',
|
||||
allow_headers=['vnd.asayer.io.sid'],
|
||||
allow_headers=['vnd.openreplay.com.sid'],
|
||||
# max_age=600,
|
||||
# expose_headers=['X-Special-Header'],
|
||||
allow_credentials=True
|
||||
|
|
|
|||
|
|
@ -5,9 +5,14 @@ from chalicelib.utils import helper
|
|||
app = Blueprint(__name__)
|
||||
_overrides.chalice_app(app)
|
||||
from chalicelib.ee import telemetry
|
||||
|
||||
from chalicelib.ee import unlock
|
||||
|
||||
# Run every day.
|
||||
@app.schedule(Cron('0', '0', '?', '*', '*', '*'))
|
||||
def telemetry_cron(event):
|
||||
telemetry.compute()
|
||||
|
||||
|
||||
@app.schedule(Cron('0/60', '*', '*', '*', '?', '*'))
|
||||
def unlock_cron(event):
|
||||
unlock.check()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
from chalice import Blueprint
|
||||
|
||||
from chalicelib import _overrides
|
||||
from chalicelib.ee import unlock
|
||||
|
||||
app = Blueprint(__name__)
|
||||
_overrides.chalice_app(app)
|
||||
|
||||
unlock.check()
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ def get_all(user_id):
|
|||
for a in announcements:
|
||||
a["createdAt"] = TimeUTC.datetime_to_timestamp(a["createdAt"])
|
||||
if a["imageUrl"] is not None and len(a["imageUrl"]) > 0:
|
||||
a["imageUrl"] = environ["announcement_bucket"] + a["imageUrl"]
|
||||
a["imageUrl"] = environ["announcement_url"] + a["imageUrl"]
|
||||
return announcements
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class GithubIntegrationIssue(BaseIntegrationIssue):
|
|||
if a == str(u["id"]):
|
||||
real_assignees.append(u["login"])
|
||||
break
|
||||
real_labels = ["Asayer"]
|
||||
real_labels = ["OpenReplay"]
|
||||
for l in labels:
|
||||
found = False
|
||||
for ll in metas["issueTypes"]:
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ class JIRACloudIntegrationIssue(BaseIntegrationIssue):
|
|||
'description': description,
|
||||
'issuetype': {'id': issue_type},
|
||||
'assignee': {"id": assignee},
|
||||
"labels": ["Asayer"]
|
||||
"labels": ["OpenReplay"]
|
||||
}
|
||||
return self._client.create_issue(data)
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ class JIRACloudIntegrationIssue(BaseIntegrationIssue):
|
|||
results = []
|
||||
for integration_project_id in projects_map:
|
||||
self._client.set_jira_project_id(integration_project_id)
|
||||
jql = 'labels = Asayer'
|
||||
jql = 'labels = OpenReplay'
|
||||
if len(projects_map[integration_project_id]) > 0:
|
||||
jql += f" AND ID IN ({','.join(projects_map[integration_project_id])})"
|
||||
issues = self._client.get_issues(jql, offset=0)
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ def __find_events(client, log_group, streams, last_token, start_time, end_time):
|
|||
"startTime": start_time,
|
||||
"endTime": end_time,
|
||||
"limit": 10000,
|
||||
"filterPattern": "asayer_session_id"
|
||||
"filterPattern": "openreplay_session_id"
|
||||
}
|
||||
if last_token is not None:
|
||||
f_args["nextToken"] = last_token
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
from chalicelib.utils import pg_client
|
||||
import requests
|
||||
|
||||
|
||||
def process_data(data, edition='fos'):
|
||||
return {
|
||||
'edition': edition,
|
||||
'tracking': data["opt_out"],
|
||||
'version': data["version_number"],
|
||||
'user_id': data["user_id"],
|
||||
'owner_email': None if data["opt_out"] else data["email"],
|
||||
'organization_name': None if data["opt_out"] else data["name"],
|
||||
'users_count': data["t_users"],
|
||||
'projects_count': data["t_projects"],
|
||||
'sessions_count': data["t_sessions"],
|
||||
'integrations_count': data["t_integrations"]
|
||||
}
|
||||
|
||||
|
||||
def compute():
|
||||
with pg_client.PostgresClient() as cur:
|
||||
cur.execute(
|
||||
f"""UPDATE public.tenants
|
||||
SET t_integrations = COALESCE((SELECT COUNT(DISTINCT provider) FROM public.integrations) +
|
||||
(SELECT COUNT(*) FROM public.webhooks WHERE type = 'slack') +
|
||||
(SELECT COUNT(*) FROM public.jira_cloud), 0),
|
||||
t_projects=COALESCE((SELECT COUNT(*) FROM public.projects WHERE deleted_at ISNULL), 0),
|
||||
t_sessions=COALESCE((SELECT COUNT(*) FROM public.sessions), 0),
|
||||
t_users=COALESCE((SELECT COUNT(*) FROM public.users WHERE deleted_at ISNULL), 0)
|
||||
RETURNING *,(SELECT email FROM public.users WHERE role='owner' LIMIT 1);"""
|
||||
)
|
||||
data = cur.fetchone()
|
||||
requests.post('https://parrot.asayer.io/os/telemetry', json=process_data(data))
|
||||
|
||||
|
||||
def new_client():
|
||||
with pg_client.PostgresClient() as cur:
|
||||
cur.execute(
|
||||
f"""SELECT *,
|
||||
(SELECT email FROM public.users WHERE role='owner' LIMIT 1) AS email
|
||||
FROM public.tenants;""")
|
||||
data = cur.fetchone()
|
||||
requests.post('https://parrot.asayer.io/os/signup', json=process_data(data))
|
||||
|
|
@ -43,20 +43,20 @@ def get_state(tenant_id):
|
|||
meta = cur.fetchone()["sum"] > 0
|
||||
|
||||
return [
|
||||
{"task": "Install Asayer",
|
||||
{"task": "Install OpenReplay",
|
||||
"done": recorded,
|
||||
"URL": "https://docs.asayer.io/getting-started/quick-start"},
|
||||
"URL": "https://docs.openreplay.com/getting-started/quick-start"},
|
||||
{"task": "Identify Users",
|
||||
"done": meta,
|
||||
"URL": "https://docs.asayer.io/data-privacy-security/metadata"},
|
||||
"URL": "https://docs.openreplay.com/data-privacy-security/metadata"},
|
||||
{"task": "Invite Team Members",
|
||||
"done": len(users.get_members(tenant_id=tenant_id)) > 1,
|
||||
"URL": "https://app.asayer.io/client/manage-users"},
|
||||
"URL": "https://app.openreplay.com/client/manage-users"},
|
||||
{"task": "Integrations",
|
||||
"done": len(log_tool_datadog.get_all(tenant_id=tenant_id)) > 0 \
|
||||
or len(log_tool_sentry.get_all(tenant_id=tenant_id)) > 0 \
|
||||
or len(log_tool_stackdriver.get_all(tenant_id=tenant_id)) > 0,
|
||||
"URL": "https://docs.asayer.io/integrations"}
|
||||
"URL": "https://docs.openreplay.com/integrations"}
|
||||
]
|
||||
|
||||
|
||||
|
|
@ -78,9 +78,9 @@ def get_state_installing(tenant_id):
|
|||
)
|
||||
recorded = cur.fetchone()["count"] > 0
|
||||
|
||||
return {"task": "Install Asayer",
|
||||
return {"task": "Install OpenReplay",
|
||||
"done": recorded,
|
||||
"URL": "https://docs.asayer.io/getting-started/quick-start"}
|
||||
"URL": "https://docs.openreplay.com/getting-started/quick-start"}
|
||||
|
||||
|
||||
def get_state_identify_users(tenant_id):
|
||||
|
|
@ -104,13 +104,13 @@ def get_state_identify_users(tenant_id):
|
|||
|
||||
return {"task": "Identify Users",
|
||||
"done": meta,
|
||||
"URL": "https://docs.asayer.io/data-privacy-security/metadata"}
|
||||
"URL": "https://docs.openreplay.com/data-privacy-security/metadata"}
|
||||
|
||||
|
||||
def get_state_manage_users(tenant_id):
|
||||
return {"task": "Invite Team Members",
|
||||
"done": len(users.get_members(tenant_id=tenant_id)) > 1,
|
||||
"URL": "https://app.asayer.io/client/manage-users"}
|
||||
"URL": "https://app.openreplay.com/client/manage-users"}
|
||||
|
||||
|
||||
def get_state_integrations(tenant_id):
|
||||
|
|
@ -118,4 +118,4 @@ def get_state_integrations(tenant_id):
|
|||
"done": len(log_tool_datadog.get_all(tenant_id=tenant_id)) > 0 \
|
||||
or len(log_tool_sentry.get_all(tenant_id=tenant_id)) > 0 \
|
||||
or len(log_tool_stackdriver.get_all(tenant_id=tenant_id)) > 0,
|
||||
"URL": "https://docs.asayer.io/integrations"}
|
||||
"URL": "https://docs.openreplay.com/integrations"}
|
||||
|
|
|
|||
|
|
@ -8,12 +8,9 @@ from chalicelib.utils.TimeUTC import TimeUTC
|
|||
|
||||
def get_signed_ups():
|
||||
with pg_client.PostgresClient() as cur:
|
||||
query = cur.mogrify(f"SELECT tenant_id, name FROM public.tenants;")
|
||||
cur.execute(
|
||||
query
|
||||
)
|
||||
cur.execute("SELECT tenant_id, name FROM public.tenants;")
|
||||
rows = cur.fetchall()
|
||||
return {"data": helper.list_to_camel_case(rows)}
|
||||
return helper.list_to_camel_case(rows)
|
||||
|
||||
|
||||
def create_step1(data):
|
||||
|
|
@ -48,15 +45,19 @@ def create_step1(data):
|
|||
errors.append("Invalid full name.")
|
||||
|
||||
print("Verifying company's name validity")
|
||||
company_name = data.get("companyName")
|
||||
company_name = data.get("organizationName")
|
||||
if company_name is None or len(company_name) < 1 or not helper.is_alphanumeric_space(company_name):
|
||||
errors.append("invalid company's name")
|
||||
errors.append("invalid organization's name")
|
||||
|
||||
print("Verifying project's name validity")
|
||||
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") not in [t['tenantId'] for t in signed_ups]:
|
||||
errors.append("Tenant does not exist")
|
||||
if len(errors) > 0:
|
||||
print("==> error")
|
||||
print(errors)
|
||||
|
|
@ -64,64 +65,95 @@ def create_step1(data):
|
|||
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": "0.0.0",
|
||||
"data": json.dumps({"lastAnnouncementView": TimeUTC.now()})}
|
||||
if tenant_id is not None:
|
||||
with pg_client.PostgresClient() as cur:
|
||||
print("Starting ACID insert")
|
||||
query = cur.mogrify(f"""\
|
||||
WITH t AS (
|
||||
UPDATE public.tenants
|
||||
SET name = %(companyName)s,
|
||||
version_number = %(versionNumber)s,
|
||||
licence = %(licence)s
|
||||
WHERE tenant_id=%(tenant_id)s
|
||||
),
|
||||
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""",
|
||||
{"email": email, "password": password,
|
||||
"fullname": fullname, "companyName": company_name,
|
||||
"projectName": project_name,
|
||||
"tenant_id": tenant_id})
|
||||
cur.execute(
|
||||
query
|
||||
)
|
||||
data = cur.fetchone()
|
||||
query = """\
|
||||
WITH t AS (
|
||||
UPDATE public.tenants
|
||||
SET name = %(companyName)s,
|
||||
version_number = %(versionNumber)s,
|
||||
licence = %(licence)s
|
||||
WHERE tenant_id=%(tenant_id)s
|
||||
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:
|
||||
with pg_client.PostgresClient() as cur:
|
||||
print("Starting ACID insert")
|
||||
query = cur.mogrify(f"""\
|
||||
WITH t AS (
|
||||
INSERT INTO public.tenants (name, version_number, licence)
|
||||
VALUES (%(companyName)s, %(versionNumber)s, %(licence)s)
|
||||
RETURNING tenant_id
|
||||
),
|
||||
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;""",
|
||||
{"email": email, "password": password,
|
||||
"fullname": fullname, "companyName": company_name,
|
||||
"projectName": project_name,
|
||||
"data": json.dumps({"lastAnnouncementView": TimeUTC.now()})})
|
||||
cur.execute(
|
||||
query
|
||||
)
|
||||
data = cur.fetchone()
|
||||
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;"""
|
||||
|
||||
with pg_client.PostgresClient() as cur:
|
||||
cur.execute(cur.mogrify(query, params))
|
||||
cur = cur.fetchone()
|
||||
project_id = cur["project_id"]
|
||||
api_key = cur["api_key"]
|
||||
telemetry.new_client(tenant_id=data["tenant_id"])
|
||||
return {"data": {"state": "success"}}
|
||||
created_at = TimeUTC.now()
|
||||
r = users.authenticate(email, password)
|
||||
r["banner"] = False
|
||||
r["limits"] = {
|
||||
"teamMember": {"limit": 99, "remaining": 98, "count": 1},
|
||||
"projects": {"limit": 99, "remaining": 98, "count": 1},
|
||||
"metadata": [{
|
||||
"projectId": project_id,
|
||||
"name": project_name,
|
||||
"limit": 10,
|
||||
"remaining": 10,
|
||||
"count": 0
|
||||
}]
|
||||
}
|
||||
c = {
|
||||
"tenantId": 1,
|
||||
"name": company_name,
|
||||
"apiKey": api_key,
|
||||
"remainingTrial": 14,
|
||||
"trialEnded": False,
|
||||
"billingPeriodStartDate": created_at,
|
||||
"hasActivePlan": True,
|
||||
"projects": [
|
||||
{
|
||||
"projectId": project_id,
|
||||
"name": project_name,
|
||||
"recorded": False,
|
||||
"stackIntegrations": False,
|
||||
"status": "red"
|
||||
}
|
||||
]
|
||||
}
|
||||
return {
|
||||
'jwt': r.pop('jwt'),
|
||||
'data': {
|
||||
"user": r,
|
||||
"client": c,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ def compute():
|
|||
RETURNING *,(SELECT email FROM users_ee WHERE role = 'owner' AND users_ee.tenant_id = tenants.tenant_id LIMIT 1);"""
|
||||
)
|
||||
data = cur.fetchall()
|
||||
requests.post('https://parrot.asayer.io/os/telemetry',
|
||||
requests.post('https://parrot.openreplay.com/os/telemetry',
|
||||
json={"stats": [process_data(d, edition='ee') for d in data]})
|
||||
|
||||
|
||||
|
|
@ -51,4 +51,4 @@ def new_client(tenant_id):
|
|||
FROM public.tenants
|
||||
WHERE tenant_id=%(tenant_id)s;""", {"tenant_id": tenant_id}))
|
||||
data = cur.fetchone()
|
||||
requests.post('https://parrot.asayer.io/os/signup', json=process_data(data, edition='ee'))
|
||||
requests.post('https://parrot.openreplay.com/os/signup', json=process_data(data, edition='ee'))
|
||||
|
|
|
|||
25
ee/api/chalicelib/ee/unlock.py
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
from chalicelib.utils.helper import environ
|
||||
from chalicelib.utils.TimeUTC import TimeUTC
|
||||
import requests
|
||||
import uuid
|
||||
|
||||
|
||||
def __get_mid():
|
||||
return str(uuid.UUID(int=uuid.getnode()))
|
||||
|
||||
|
||||
def __get_license():
|
||||
return
|
||||
|
||||
|
||||
def check():
|
||||
r = requests.post('https://parrot.openreplay.com/os/license', json={"mid": __get_mid(), "license": __get_license()})
|
||||
if r.status_code != 200 or not r.json().get("valid"):
|
||||
environ["expiration"] = "-1"
|
||||
else:
|
||||
environ["expiration"] = r.json().get("expiration")
|
||||
environ["lastCheck"] = TimeUTC.now()
|
||||
|
||||
|
||||
def is_valid():
|
||||
return int(environ["lastCheck"]) + int(environ["expiration"]) - TimeUTC.now() > 0
|
||||
|
|
@ -21,7 +21,7 @@ def timed(f):
|
|||
'handle_request', '_generic_handle', 'handle', '_bootstrap_inner', 'run',
|
||||
'_bootstrap', '_main_rest_api_handler', '_user_handler',
|
||||
'_get_view_function_response', 'wrapped_event', 'handle_one_request',
|
||||
'_global_error_handler', 'asayer_middleware']]
|
||||
'_global_error_handler', 'openreplay_middleware']]
|
||||
print("DEBUG: %s > %s took %d s to finish" % (" > ".join(call_stack), f.__name__, elapsed))
|
||||
return result
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ def send_team_invitation(recipient, user_name, temp_password, client_id, sender_
|
|||
formatting_variables={"userName": __escape_text_html(user_name),
|
||||
"password": temp_password, "clientId": client_id,
|
||||
"sender": sender_name})
|
||||
SUBJECT = "Welcome to Asayer"
|
||||
SUBJECT = "Welcome to OpenReplay"
|
||||
send_html(BODY_HTML, SUBJECT, recipient)
|
||||
|
||||
|
||||
|
|
@ -115,5 +115,5 @@ def weekly_report2(recipients, data):
|
|||
</table>
|
||||
</td>"""
|
||||
BODY_HTML = __get_html_from_file("chalicelib/utils/html/Project-Weekly-Report.html", formatting_variables=data)
|
||||
SUBJECT = "Asayer Project Weekly Report"
|
||||
SUBJECT = "OpenReplay Project Weekly Report"
|
||||
send_html(BODY_HTML=BODY_HTML, SUBJECT=SUBJECT, recipient=recipients)
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ class github_formatters:
|
|||
'createdAt': github_formatters.get_timestamp(issue["created_at"]),
|
||||
'closed': issue["closed_at"] is not None,
|
||||
'commentsCount': issue["comments"],
|
||||
'issueType': [str(l["id"]) for l in labels if l["name"].lower() != "asayer"],
|
||||
'issueType': [str(l["id"]) for l in labels if l["name"].lower() != "openreplay"],
|
||||
'labels': [l["name"] for l in labels]
|
||||
}
|
||||
return result
|
||||
|
|
|
|||
|
|
@ -40,17 +40,6 @@ def generate_salt():
|
|||
return "".join(random.choices(string.hexdigits, k=36))
|
||||
|
||||
|
||||
def remove_empty_none_values(dictionary):
|
||||
aux = {}
|
||||
for key in dictionary.keys():
|
||||
if dictionary[key] is not None:
|
||||
if isinstance(dictionary[key], dict):
|
||||
aux[key] = remove_empty_none_values(dictionary[key])
|
||||
elif not isinstance(dictionary[key], str) or len(dictionary[key]) > 0:
|
||||
aux[key] = dictionary[key]
|
||||
return aux
|
||||
|
||||
|
||||
def unique_ordered_list(array):
|
||||
uniq = []
|
||||
[uniq.append(x) for x in array if x not in uniq]
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<table style="width:100%;font-weight:300;margin-bottom:0;border-collapse:collapse">
|
||||
<tbody><tr style="font-weight:300">
|
||||
<td width="125px" style="font-size:14px;padding:0;font-weight:300;margin:0;text-align:left">
|
||||
<a href="%(frontend_url)s" style="color:#394EFF;font-weight:300;text-decoration:none" target="_blank" data-saferedirecturl="" width="125px" height="29px" alt="asayer" style="font-weight:300"><img src="img/weekly/asayer-logo.png" style="width: 160px;"></a>
|
||||
<a href="%(frontend_url)s" style="color:#394EFF;font-weight:300;text-decoration:none" target="_blank" data-saferedirecturl="" width="125px" height="29px" alt="openreplay" style="font-weight:300"><img src="img/weekly/logo.png" style="width: 160px;"></a>
|
||||
</td>
|
||||
<td style="font-size:14px;padding:0;font-weight:300;margin:0;text-align:right">
|
||||
<table style="width:100%;font-weight:300;margin-bottom:0;border-collapse:collapse">
|
||||
|
|
@ -154,7 +154,7 @@
|
|||
<div style="padding:10px 20px;max-width:600px;font-weight:300;margin:0 auto;text-align:left">
|
||||
<div style="padding:35px 0;border-top:1px solid #e7ebee;font-weight:300; font-size: 13px;">
|
||||
|
||||
<a href="%(frontend_url)s/%(project_id)s/metrics" style="color:#394EFF;float:right;font-weight:300;text-decoration:none" target="_blank" data-saferedirecturl="#">Asayer Metrics</a>
|
||||
<a href="%(frontend_url)s/%(project_id)s/metrics" style="color:#394EFF;float:right;font-weight:300;text-decoration:none" target="_blank" data-saferedirecturl="#">OpenReplay Metrics</a>
|
||||
|
||||
<a href="%(frontend_url)s/client/notifications" style="color:#394EFF;font-weight:300;text-decoration:none" target="_blank" data-saferedirecturl="#">Manage Notifications</a>
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<tr>
|
||||
<td style="padding:10px 30px;">
|
||||
<center>
|
||||
<img src="img/asayer-logo.png" alt="Asayer" width="100%" style="max-width: 120px;">
|
||||
<img src="img/logo.png" alt="OpenReplay" width="100%" style="max-width: 120px;">
|
||||
</center>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
@ -38,9 +38,9 @@
|
|||
<div style="border-top:1px dotted rgba(0,0,0,0.2); display: block; margin-top: 20px"></div>
|
||||
<center>
|
||||
<p style="font-size: 12px; font-family: -apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,'Helvetica Neue',sans-serif; color: #6c757d">
|
||||
Sent with ♡ from Asayer © 2021 - All rights reserved.<br><br>
|
||||
<a href="https://asayer.io" target="_blank"
|
||||
style="text-decoration: none; color: #6c757d">https://asayer.io/</a>
|
||||
Sent with ♡ from OpenReplay © 2021 - All rights reserved.<br><br>
|
||||
<a href="https://openreplay.com" target="_blank"
|
||||
style="text-decoration: none; color: #6c757d">https://openreplay.com/</a>
|
||||
</p>
|
||||
|
||||
</center>
|
||||
|
|
|
|||
|
|
@ -385,7 +385,7 @@ width: 25%!important
|
|||
<td style="padding-right: 0px;padding-left: 0px;" align="center">
|
||||
<![endif]-->
|
||||
<img style="width=124px; height=35px;" width="124px" height="35px"
|
||||
src="img/asayer-logo.png"/>
|
||||
src="img/logo.png"/>
|
||||
|
||||
<!--[if mso]></td></tr></table><![endif]-->
|
||||
</div>
|
||||
|
|
@ -401,7 +401,7 @@ width: 25%!important
|
|||
<div style="color:#555555;font-family:'Helvetica Neue', Helvetica, Arial, sans-serif;line-height:120%;padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:10px;">
|
||||
<div style="font-size: 12px; line-height: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; color: #555555;">
|
||||
<!-- <p style="font-size: 18px; line-height: 21px; text-align: center; margin: 0;">
|
||||
<span style="font-size: 18px;">Welcome to Asayer!</span>
|
||||
<span style="font-size: 18px;">Welcome to OpenReplay!</span>
|
||||
</p>-->
|
||||
<h1 style="text-align: center; margin-top: 30px; line-height: 30px">Assigned session</h1>
|
||||
|
||||
|
|
@ -514,10 +514,10 @@ width: 25%!important
|
|||
<div style="color:#555555;font-family:-apple-system,BlinkMacSystemFont,'Helvetica Neue','Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,sans-serif;line-height:120%;padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:10px;">
|
||||
<div style="font-size: 12px; line-height: 14px; color: #555555; font-family: -apple-system,BlinkMacSystemFont,'Helvetica Neue','Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,sans-serif;">
|
||||
<p style="font-size: 14px; line-height: 16px; text-align: center; margin: 0;">
|
||||
<a href="mailto:support@asayer.io?subject=[User Invite] - Reporting issue"
|
||||
<a href="mailto:support@openreplay.com?subject=[User Invite] - Reporting issue"
|
||||
style="text-decoration: underline; color: #009193;"
|
||||
title="support@asayer.io">Report an issue</a> | <a
|
||||
href="https://asayer.io/" rel="noopener"
|
||||
title="support@openreplay.com">Report an issue</a> | <a
|
||||
href="https://openreplay.com/" rel="noopener"
|
||||
style="text-decoration: underline; color: #009193;" target="_blank">Take
|
||||
a tour</a></p>
|
||||
</div>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
|
@ -378,7 +378,7 @@ width: 25%!important
|
|||
<tr style="line-height:0px">
|
||||
<td style="padding-right: 0px;padding-left: 0px;" align="center">
|
||||
<![endif]-->
|
||||
<img style="width=124px; height=35px;" width="124px" height="35px" src="img/asayer-logo.png"/>
|
||||
<img style="width=124px; height=35px;" width="124px" height="35px" src="img/logo.png"/>
|
||||
|
||||
<!--[if mso]></td></tr></table><![endif]-->
|
||||
</div>
|
||||
|
|
@ -394,7 +394,7 @@ width: 25%!important
|
|||
<div style="color:#555555;font-family:'Helvetica Neue', Helvetica, Arial, sans-serif;line-height:120%;padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:10px;">
|
||||
<div style="font-size: 12px; line-height: 14px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; color: #555555;">
|
||||
<p style="font-size: 14px; line-height: 21px; text-align: center; margin: 0;">
|
||||
<span style="font-size: 18px;"><strong>Welcome to Asayer!</strong></span>
|
||||
<span style="font-size: 18px;"><strong>Welcome to OpenReplay!</strong></span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -407,7 +407,7 @@ width: 25%!important
|
|||
<div style="color:#555555;font-family:-apple-system,BlinkMacSystemFont,'Helvetica Neue','Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,sans-serif;line-height:120%;padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:10px;">
|
||||
<div style="font-size: 12px; line-height: 14px; color: #555555; font-family: -apple-system,BlinkMacSystemFont,'Helvetica Neue','Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,sans-serif;">
|
||||
<p style="font-size: 12px; line-height: 16px; text-align: center; margin: 0;">
|
||||
<span style="font-size: 14px;">You have been invited by %(sender)s to join %(clientId)s team on Asayer.</span>
|
||||
<span style="font-size: 14px;">You have been invited by %(sender)s to join %(clientId)s team on OpenReplay.</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -450,7 +450,7 @@ width: 25%!important
|
|||
<span style="font-size: 18px;"><a href="%(frontend_url)s"
|
||||
rel="noopener"
|
||||
style="text-decoration: underline; color: #009193;"
|
||||
target="_blank" title="Asayer Login">%(frontend_url)s</a></span><span
|
||||
target="_blank" title="OpenReplay Login">%(frontend_url)s</a></span><span
|
||||
style="font-size: 18px; line-height: 21px;"></span></p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -553,10 +553,10 @@ width: 25%!important
|
|||
<div style="color:#555555;font-family:-apple-system,BlinkMacSystemFont,'Helvetica Neue','Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,sans-serif;line-height:120%;padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:10px;">
|
||||
<div style="font-size: 12px; line-height: 14px; color: #555555; font-family: -apple-system,BlinkMacSystemFont,'Helvetica Neue','Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,sans-serif;">
|
||||
<p style="font-size: 14px; line-height: 16px; text-align: center; margin: 0;">
|
||||
<a href="mailto:support@asayer.io?subject=[User Invite] - Reporting issue"
|
||||
<a href="mailto:support@openreplay.com?subject=[User Invite] - Reporting issue"
|
||||
style="text-decoration: underline; color: #009193;"
|
||||
title="support@asayer.io">Report an issue</a> | <a
|
||||
href="https://asayer.io/" rel="noopener"
|
||||
title="support@openreplay.com">Report an issue</a> | <a
|
||||
href="https://openreplay.com/" rel="noopener"
|
||||
style="text-decoration: underline; color: #009193;" target="_blank">Take
|
||||
a tour</a></p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -385,7 +385,7 @@ width: 25%!important
|
|||
<td style="padding-right: 0px;padding-left: 0px;" align="center">
|
||||
<![endif]-->
|
||||
<img style="width=124px; height=35px;" width="124px" height="35px"
|
||||
src="img/asayer-logo.png"/>
|
||||
src="img/logo.png"/>
|
||||
|
||||
<!--[if mso]></td></tr></table><![endif]-->
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,19 @@
|
|||
from botocore.exceptions import ClientError
|
||||
from chalicelib.utils.helper import environ
|
||||
from chalicelib.utils import helper
|
||||
|
||||
import boto3
|
||||
|
||||
client = boto3.client('s3')
|
||||
sts_client = boto3.client('sts')
|
||||
if helper.is_free_open_source_edition() or helper.is_enterprise_edition():
|
||||
from botocore.client import Config
|
||||
|
||||
client = boto3.client('s3', endpoint_url=environ["S3_HOST"],
|
||||
aws_access_key_id=environ["S3_KEY"],
|
||||
aws_secret_access_key=environ["S3_SECRET"],
|
||||
config=Config(signature_version='s3v4'),
|
||||
region_name='us-east-1')
|
||||
else:
|
||||
client = boto3.client('s3')
|
||||
|
||||
|
||||
def exists(bucket, key):
|
||||
|
|
|
|||
17
ee/api/env_handler.py
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
from os import environ
|
||||
import json
|
||||
|
||||
with open('.chalice/config.json') as json_file:
|
||||
data = json.load(json_file)
|
||||
stages = data.get("stages", {})
|
||||
for s in stages.keys():
|
||||
target = f'chalicelib/.configs/{stages[s].get("environment_variables", {}).get("stage", s)}.json'
|
||||
data = {}
|
||||
try:
|
||||
with open(target) as stage_vars:
|
||||
data = json.load(stage_vars)
|
||||
except IOError:
|
||||
pass
|
||||
with open(target, 'w') as outfile:
|
||||
json.dump({**data, **environ}, outfile, indent=2, sort_keys=True)
|
||||
print(f"injected env-vars to {target}")
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import React from 'react'
|
||||
import React, { useState } from 'react'
|
||||
import { Input, Slider, Button, Popup, CircularLoader } from 'UI';
|
||||
import { saveCaptureRate, editCaptureRate } from 'Duck/watchdogs';
|
||||
import { connect } from 'react-redux';
|
||||
|
|
@ -12,8 +12,10 @@ function isPercent(val) {
|
|||
|
||||
const SessionCaptureRate = props => {
|
||||
const { captureRate, saveCaptureRate, editCaptureRate, loading, onClose } = props;
|
||||
const sampleRate = captureRate.get('rate');
|
||||
if (sampleRate == null) return null;
|
||||
const _sampleRate = captureRate.get('rate');
|
||||
if (_sampleRate == null) return null;
|
||||
|
||||
const [sampleRate, setSampleRate] = useState(_sampleRate)
|
||||
|
||||
const captureAll = captureRate.get('captureAll');
|
||||
|
||||
|
|
@ -46,7 +48,7 @@ const SessionCaptureRate = props => {
|
|||
name="sampleRate"
|
||||
disabled={ captureAll }
|
||||
value={ captureAll ? '100' : sampleRate }
|
||||
onChange={ ({ target: { value }}) => isPercent(value) && editCaptureRate(+value) }
|
||||
onChange={ ({ target: { value }}) => isPercent(value) && setSampleRate(+value) }
|
||||
size="small"
|
||||
className={stl.inputField}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ const RehydrateSlidePanel = props => {
|
|||
onClose={ onClose }
|
||||
size="small"
|
||||
content={
|
||||
isModalDisplayed && (
|
||||
<div className="px-4">
|
||||
<hr className="mb-3" />
|
||||
<div>
|
||||
|
|
@ -33,6 +34,7 @@ const RehydrateSlidePanel = props => {
|
|||
<SessionCaptureRate onClose={ onClose } />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ export default class IntegrationForm extends React.PureComponent {
|
|||
<Form>
|
||||
{!ignoreProject &&
|
||||
<Form.Field>
|
||||
<label>{ 'Site' }</label>
|
||||
<label>{ 'OpenReplay Project' }</label>
|
||||
<SiteDropdown
|
||||
value={ currentSiteId }
|
||||
onChange={ this.onChangeSelect }
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { hasSiteId, siteChangeAvaliable } from 'App/routes';
|
|||
import { STATUS_COLOR_MAP, GREEN } from 'Types/site';
|
||||
import { Icon, SlideModal } from 'UI';
|
||||
import { pushNewSite } from 'Duck/user'
|
||||
import { init } from 'Duck/site';
|
||||
import styles from './siteDropdown.css';
|
||||
import cn from 'classnames';
|
||||
import NewSiteForm from '../Client/Sites/NewSiteForm';
|
||||
|
|
@ -15,7 +16,8 @@ import NewSiteForm from '../Client/Sites/NewSiteForm';
|
|||
siteId: state.getIn([ 'user', 'siteId' ]),
|
||||
}), {
|
||||
setSiteId,
|
||||
pushNewSite
|
||||
pushNewSite,
|
||||
init
|
||||
})
|
||||
export default class SiteDropdown extends React.PureComponent {
|
||||
state = { showProductModal: false }
|
||||
|
|
@ -28,6 +30,11 @@ export default class SiteDropdown extends React.PureComponent {
|
|||
}
|
||||
};
|
||||
|
||||
newSite = () => {
|
||||
this.props.init({})
|
||||
this.setState({showProductModal: true})
|
||||
}
|
||||
|
||||
render() {
|
||||
const { sites, siteId, location: { pathname } } = this.props;
|
||||
const { showProductModal } = this.state;
|
||||
|
|
@ -62,7 +69,7 @@ export default class SiteDropdown extends React.PureComponent {
|
|||
</ul>
|
||||
<div
|
||||
className={cn(styles.btnNew, 'flex items-center justify-center py-3 cursor-pointer')}
|
||||
onClick={() => this.setState({showProductModal: true})}
|
||||
onClick={this.newSite}
|
||||
>
|
||||
<Icon
|
||||
name="plus"
|
||||
|
|
@ -78,7 +85,7 @@ export default class SiteDropdown extends React.PureComponent {
|
|||
title="New Project"
|
||||
size="small"
|
||||
isDisplayed={ showProductModal }
|
||||
content={ <NewSiteForm onClose={ this.closeModal } /> }
|
||||
content={ showProductModal && <NewSiteForm onClose={ this.closeModal } /> }
|
||||
onClose={ this.closeModal }
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ export default function EventSearch(props) {
|
|||
value={value}
|
||||
onChange={onChange}
|
||||
style={{ height: '32px' }}
|
||||
autocomplete="off"
|
||||
/>
|
||||
<div
|
||||
onClick={() => { setShowSearch(!showSearch); clearSearch() }}
|
||||
|
|
|
|||
|
|
@ -112,7 +112,6 @@ export default class Timeline extends React.PureComponent {
|
|||
style={ {
|
||||
left: `${ interval.start * scale }%`,
|
||||
width: `${ (interval.end - interval.start) * scale }%`,
|
||||
top: '-30px'
|
||||
} }
|
||||
/>))
|
||||
}
|
||||
|
|
@ -121,7 +120,7 @@ export default class Timeline extends React.PureComponent {
|
|||
<div
|
||||
key={ e.key }
|
||||
className={ stl.event }
|
||||
style={ { left: `${ e.time * scale }%`, top: '-30px' } }
|
||||
style={ { left: `${ e.time * scale }%` } }
|
||||
/>
|
||||
))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ const tracker = new Tracker({
|
|||
tracker.start();`
|
||||
|
||||
function InstallDocs({ site }) {
|
||||
const _usageCode = usageCode.replace('PROJECT_ID', site.projectKeKey)
|
||||
const _usageCode = usageCode.replace('PROJECT_ID', site.projectKey)
|
||||
return (
|
||||
<div>
|
||||
<div className="mb-3">
|
||||
|
|
|
|||