Merge remote-tracking branch 'origin/api-ms-teams' into api-v1.9.5
# Conflicts: # api/routers/core.py
This commit is contained in:
commit
7bb6c25f17
24 changed files with 544 additions and 275 deletions
|
|
@ -1,9 +1,14 @@
|
|||
import json
|
||||
import logging
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
from decouple import config
|
||||
|
||||
import schemas
|
||||
from chalicelib.core import notifications, slack, webhook
|
||||
from chalicelib.core import notifications, webhook
|
||||
from chalicelib.core.collaboration_msteams import MSTeams
|
||||
from chalicelib.core.collaboration_slack import Slack
|
||||
from chalicelib.utils import pg_client, helper, email_helper
|
||||
from chalicelib.utils.TimeUTC import TimeUTC
|
||||
|
||||
|
|
@ -95,7 +100,7 @@ def process_notifications(data):
|
|||
for c in n["options"].pop("message"):
|
||||
if c["type"] not in full:
|
||||
full[c["type"]] = []
|
||||
if c["type"] in ["slack", "email"]:
|
||||
if c["type"] in ["slack", "msteams", "email"]:
|
||||
full[c["type"]].append({
|
||||
"notification": n,
|
||||
"destination": c["value"]
|
||||
|
|
@ -107,13 +112,21 @@ def process_notifications(data):
|
|||
for t in full.keys():
|
||||
for i in range(0, len(full[t]), BATCH_SIZE):
|
||||
notifications_list = full[t][i:i + BATCH_SIZE]
|
||||
if notifications_list is None or len(notifications_list) == 0:
|
||||
break
|
||||
|
||||
if t == "slack":
|
||||
try:
|
||||
slack.send_batch(notifications_list=notifications_list)
|
||||
send_to_slack_batch(notifications_list=notifications_list)
|
||||
except Exception as e:
|
||||
logging.error("!!!Error while sending slack notifications batch")
|
||||
logging.error(str(e))
|
||||
elif t == "msteams":
|
||||
try:
|
||||
send_to_msteams_batch(notifications_list=notifications_list)
|
||||
except Exception as e:
|
||||
logging.error("!!!Error while sending msteams notifications batch")
|
||||
logging.error(str(e))
|
||||
elif t == "email":
|
||||
try:
|
||||
send_by_email_batch(notifications_list=notifications_list)
|
||||
|
|
@ -149,16 +162,60 @@ def send_by_email_batch(notifications_list):
|
|||
time.sleep(1)
|
||||
|
||||
|
||||
def send_to_slack_batch(notifications_list):
|
||||
webhookId_map = {}
|
||||
for n in notifications_list:
|
||||
if n.get("destination") not in webhookId_map:
|
||||
webhookId_map[n.get("destination")] = {"tenantId": n["notification"]["tenantId"], "batch": []}
|
||||
webhookId_map[n.get("destination")]["batch"].append({"text": n["notification"]["description"] \
|
||||
+ f"\n<{config('SITE_URL')}{n['notification']['buttonUrl']}|{n['notification']['buttonText']}>",
|
||||
"title": n["notification"]["title"],
|
||||
"title_link": n["notification"]["buttonUrl"],
|
||||
"ts": datetime.now().timestamp()})
|
||||
for batch in webhookId_map.keys():
|
||||
Slack.send_batch(tenant_id=webhookId_map[batch]["tenantId"], webhook_id=batch,
|
||||
attachments=webhookId_map[batch]["batch"])
|
||||
|
||||
|
||||
def send_to_msteams_batch(notifications_list):
|
||||
webhookId_map = {}
|
||||
for n in notifications_list:
|
||||
if n.get("destination") not in webhookId_map:
|
||||
webhookId_map[n.get("destination")] = {"tenantId": n["notification"]["tenantId"], "batch": []}
|
||||
|
||||
link = f"[{n['notification']['buttonText']}]({config('SITE_URL')}{n['notification']['buttonUrl']})"
|
||||
webhookId_map[n.get("destination")]["batch"].append({"type": "ColumnSet",
|
||||
"style": "emphasis",
|
||||
"separator": True,
|
||||
"bleed": True,
|
||||
"columns": [{
|
||||
"width": "stretch",
|
||||
"items": [
|
||||
{"type": "TextBlock",
|
||||
"text": n["notification"]["title"],
|
||||
"style": "heading",
|
||||
"size": "Large"},
|
||||
{"type": "TextBlock",
|
||||
"spacing": "small",
|
||||
"text": n["notification"]["description"],
|
||||
"wrap": True},
|
||||
{"type": "TextBlock",
|
||||
"spacing": "small",
|
||||
"text": link}
|
||||
]
|
||||
}]})
|
||||
for batch in webhookId_map.keys():
|
||||
MSTeams.send_batch(tenant_id=webhookId_map[batch]["tenantId"], webhook_id=batch,
|
||||
attachments=webhookId_map[batch]["batch"])
|
||||
|
||||
|
||||
def delete(project_id, alert_id):
|
||||
with pg_client.PostgresClient() as cur:
|
||||
cur.execute(
|
||||
cur.mogrify("""\
|
||||
UPDATE public.alerts
|
||||
SET
|
||||
deleted_at = timezone('utc'::text, now()),
|
||||
active = FALSE
|
||||
WHERE
|
||||
alert_id = %(alert_id)s AND project_id=%(project_id)s;""",
|
||||
cur.mogrify(""" UPDATE public.alerts
|
||||
SET deleted_at = timezone('utc'::text, now()),
|
||||
active = FALSE
|
||||
WHERE alert_id = %(alert_id)s AND project_id=%(project_id)s;""",
|
||||
{"alert_id": alert_id, "project_id": project_id})
|
||||
)
|
||||
return {"data": {"state": "success"}}
|
||||
|
|
|
|||
45
api/chalicelib/core/collaboration_base.py
Normal file
45
api/chalicelib/core/collaboration_base.py
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
from abc import ABC, abstractmethod
|
||||
|
||||
import schemas
|
||||
|
||||
|
||||
class BaseCollaboration(ABC):
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def add(cls, tenant_id, data: schemas.AddCollaborationSchema):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def say_hello(cls, url):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def send_raw(cls, tenant_id, webhook_id, body):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def send_batch(cls, tenant_id, webhook_id, attachments):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def __share(cls, tenant_id, integration_id, attachments):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def share_session(cls, tenant_id, project_id, session_id, user, comment, integration_id=None):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def share_error(cls, tenant_id, project_id, error_id, user, comment, integration_id=None):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def __get(cls, tenant_id, integration_id=None):
|
||||
pass
|
||||
190
api/chalicelib/core/collaboration_msteams.py
Normal file
190
api/chalicelib/core/collaboration_msteams.py
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
import json
|
||||
|
||||
import requests
|
||||
from decouple import config
|
||||
|
||||
import schemas
|
||||
from chalicelib.core import webhook
|
||||
from chalicelib.core.collaboration_base import BaseCollaboration
|
||||
|
||||
|
||||
class MSTeams(BaseCollaboration):
|
||||
@classmethod
|
||||
def add(cls, tenant_id, data: schemas.AddCollaborationSchema):
|
||||
if cls.say_hello(data.url):
|
||||
return webhook.add(tenant_id=tenant_id,
|
||||
endpoint=data.url,
|
||||
webhook_type="msteams",
|
||||
name=data.name)
|
||||
return None
|
||||
|
||||
# https://messagecardplayground.azurewebsites.net
|
||||
# https://adaptivecards.io/designer/
|
||||
@classmethod
|
||||
def say_hello(cls, url):
|
||||
r = requests.post(
|
||||
url=url,
|
||||
json={
|
||||
"@type": "MessageCard",
|
||||
"@context": "https://schema.org/extensions",
|
||||
"summary": "Hello message",
|
||||
"title": "Welcome to OpenReplay"
|
||||
})
|
||||
if r.status_code != 200:
|
||||
print("MSTeams integration failed")
|
||||
print(r.text)
|
||||
return False
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def send_raw(cls, tenant_id, webhook_id, body):
|
||||
integration = cls.__get(tenant_id=tenant_id, integration_id=webhook_id)
|
||||
if integration is None:
|
||||
return {"errors": ["slack integration not found"]}
|
||||
try:
|
||||
r = requests.post(
|
||||
url=integration["endpoint"],
|
||||
json=body,
|
||||
timeout=5)
|
||||
if r.status_code != 200:
|
||||
print(f"!! issue sending slack raw; webhookId:{webhook_id} code:{r.status_code}")
|
||||
print(r.text)
|
||||
return None
|
||||
except requests.exceptions.Timeout:
|
||||
print(f"!! Timeout sending slack raw webhookId:{webhook_id}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"!! Issue sending slack raw webhookId:{webhook_id}")
|
||||
print(str(e))
|
||||
return None
|
||||
return {"data": r.text}
|
||||
|
||||
@classmethod
|
||||
def send_batch(cls, tenant_id, webhook_id, attachments):
|
||||
integration = cls.__get(tenant_id=tenant_id, integration_id=webhook_id)
|
||||
if integration is None:
|
||||
return {"errors": ["msteams integration not found"]}
|
||||
print(f"====> sending msteams batch notification: {len(attachments)}")
|
||||
for i in range(0, len(attachments), 100):
|
||||
print(json.dumps({"type": "message",
|
||||
"attachments": [
|
||||
{"contentType": "application/vnd.microsoft.card.adaptive",
|
||||
"contentUrl": None,
|
||||
"content": {
|
||||
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
|
||||
"type": "AdaptiveCard",
|
||||
"version": "1.2",
|
||||
"body": attachments[i:i + 100]}}
|
||||
]}))
|
||||
r = requests.post(
|
||||
url=integration["endpoint"],
|
||||
json={"type": "message",
|
||||
"attachments": [
|
||||
{"contentType": "application/vnd.microsoft.card.adaptive",
|
||||
"contentUrl": None,
|
||||
"content": {
|
||||
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
|
||||
"type": "AdaptiveCard",
|
||||
"version": "1.2",
|
||||
"body": attachments[i:i + 100]}}
|
||||
]})
|
||||
if r.status_code != 200:
|
||||
print("!!!! something went wrong")
|
||||
print(r)
|
||||
print(r.text)
|
||||
|
||||
@classmethod
|
||||
def __share(cls, tenant_id, integration_id, attachement):
|
||||
integration = cls.__get(tenant_id=tenant_id, integration_id=integration_id)
|
||||
if integration is None:
|
||||
return {"errors": ["Microsoft Teams integration not found"]}
|
||||
r = requests.post(
|
||||
url=integration["endpoint"],
|
||||
json={"type": "message",
|
||||
"attachments": [
|
||||
{"contentType": "application/vnd.microsoft.card.adaptive",
|
||||
"contentUrl": None,
|
||||
"content": {
|
||||
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
|
||||
"type": "AdaptiveCard",
|
||||
"version": "1.5",
|
||||
"body": [attachement]}}
|
||||
]
|
||||
})
|
||||
|
||||
return r.text
|
||||
|
||||
@classmethod
|
||||
def share_session(cls, tenant_id, project_id, session_id, user, comment, integration_id=None):
|
||||
title = f"[{user}](mailto:{user}) has shared the below session!"
|
||||
link = f"{config('SITE_URL')}/{project_id}/session/{session_id}"
|
||||
link = f"[{link}]({link})"
|
||||
args = {"type": "ColumnSet",
|
||||
"style": "emphasis",
|
||||
"separator": True,
|
||||
"bleed": True,
|
||||
"columns": [{
|
||||
"width": "stretch",
|
||||
"items": [
|
||||
{"type": "TextBlock",
|
||||
"text": title,
|
||||
"style": "heading",
|
||||
"size": "Large"},
|
||||
{"type": "TextBlock",
|
||||
"spacing": "small",
|
||||
"text": link}
|
||||
]
|
||||
}]}
|
||||
if comment and len(comment) > 0:
|
||||
args["columns"][0]["items"].append({
|
||||
"type": "TextBlock",
|
||||
"spacing": "small",
|
||||
"text": comment
|
||||
})
|
||||
data = cls.__share(tenant_id, integration_id, attachement=args)
|
||||
if "errors" in data:
|
||||
return data
|
||||
return {"data": data}
|
||||
|
||||
@classmethod
|
||||
def share_error(cls, tenant_id, project_id, error_id, user, comment, integration_id=None):
|
||||
title = f"[{user}](mailto:{user}) has shared the below error!"
|
||||
link = f"{config('SITE_URL')}/{project_id}/errors/{error_id}"
|
||||
link = f"[{link}]({link})"
|
||||
args = {"type": "ColumnSet",
|
||||
"style": "emphasis",
|
||||
"separator": True,
|
||||
"bleed": True,
|
||||
"columns": [{
|
||||
"width": "stretch",
|
||||
"items": [
|
||||
{"type": "TextBlock",
|
||||
"text": title,
|
||||
"style": "heading",
|
||||
"size": "Large"},
|
||||
{"type": "TextBlock",
|
||||
"spacing": "small",
|
||||
"text": link}
|
||||
]
|
||||
}]}
|
||||
if comment and len(comment) > 0:
|
||||
args["columns"][0]["items"].append({
|
||||
"type": "TextBlock",
|
||||
"spacing": "small",
|
||||
"text": comment
|
||||
})
|
||||
data = cls.__share(tenant_id, integration_id, attachement=args)
|
||||
if "errors" in data:
|
||||
return data
|
||||
return {"data": data}
|
||||
|
||||
@classmethod
|
||||
def __get(cls, tenant_id, integration_id=None):
|
||||
if integration_id is not None:
|
||||
return webhook.get_webhook(tenant_id=tenant_id, webhook_id=integration_id,
|
||||
webhook_type=schemas.WebhookType.msteams)
|
||||
|
||||
integrations = webhook.get_by_type(tenant_id=tenant_id, webhook_type=schemas.WebhookType.msteams)
|
||||
if integrations is None or len(integrations) == 0:
|
||||
return None
|
||||
return integrations[0]
|
||||
|
|
@ -1,19 +1,20 @@
|
|||
import requests
|
||||
from decouple import config
|
||||
from datetime import datetime
|
||||
|
||||
import schemas
|
||||
from chalicelib.core import webhook
|
||||
from chalicelib.core.collaboration_base import BaseCollaboration
|
||||
|
||||
|
||||
class Slack:
|
||||
class Slack(BaseCollaboration):
|
||||
@classmethod
|
||||
def add_channel(cls, tenant_id, **args):
|
||||
url = args["url"]
|
||||
name = args["name"]
|
||||
if cls.say_hello(url):
|
||||
def add(cls, tenant_id, data: schemas.AddCollaborationSchema):
|
||||
if cls.say_hello(data.url):
|
||||
return webhook.add(tenant_id=tenant_id,
|
||||
endpoint=url,
|
||||
endpoint=data.url,
|
||||
webhook_type="slack",
|
||||
name=name)
|
||||
name=data.name)
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
|
|
@ -34,37 +35,6 @@ class Slack:
|
|||
return False
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def send_text_attachments(cls, tenant_id, webhook_id, text, **args):
|
||||
integration = cls.__get(tenant_id=tenant_id, integration_id=webhook_id)
|
||||
if integration is None:
|
||||
return {"errors": ["slack integration not found"]}
|
||||
try:
|
||||
r = requests.post(
|
||||
url=integration["endpoint"],
|
||||
json={
|
||||
"attachments": [
|
||||
{
|
||||
"text": text,
|
||||
"ts": datetime.now().timestamp(),
|
||||
**args
|
||||
}
|
||||
]
|
||||
},
|
||||
timeout=5)
|
||||
if r.status_code != 200:
|
||||
print(f"!! issue sending slack text attachments; webhookId:{webhook_id} code:{r.status_code}")
|
||||
print(r.text)
|
||||
return None
|
||||
except requests.exceptions.Timeout:
|
||||
print(f"!! Timeout sending slack text attachments webhookId:{webhook_id}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"!! Issue sending slack text attachments webhookId:{webhook_id}")
|
||||
print(str(e))
|
||||
return None
|
||||
return {"data": r.text}
|
||||
|
||||
@classmethod
|
||||
def send_raw(cls, tenant_id, webhook_id, body):
|
||||
integration = cls.__get(tenant_id=tenant_id, integration_id=webhook_id)
|
||||
|
|
@ -105,24 +75,12 @@ class Slack:
|
|||
print(r.text)
|
||||
|
||||
@classmethod
|
||||
def __share_to_slack(cls, tenant_id, integration_id, fallback, pretext, title, title_link, text):
|
||||
def __share(cls, tenant_id, integration_id, attachement):
|
||||
integration = cls.__get(tenant_id=tenant_id, integration_id=integration_id)
|
||||
if integration is None:
|
||||
return {"errors": ["slack integration not found"]}
|
||||
r = requests.post(
|
||||
url=integration["endpoint"],
|
||||
json={
|
||||
"attachments": [
|
||||
{
|
||||
"fallback": fallback,
|
||||
"pretext": pretext,
|
||||
"title": title,
|
||||
"title_link": title_link,
|
||||
"text": text,
|
||||
"ts": datetime.now().timestamp()
|
||||
}
|
||||
]
|
||||
})
|
||||
attachement["ts"] = datetime.now().timestamp()
|
||||
r = requests.post(url=integration["endpoint"], json={"attachments": [attachement]})
|
||||
return r.text
|
||||
|
||||
@classmethod
|
||||
|
|
@ -132,7 +90,10 @@ class Slack:
|
|||
"title": f"{config('SITE_URL')}/{project_id}/session/{session_id}",
|
||||
"title_link": f"{config('SITE_URL')}/{project_id}/session/{session_id}",
|
||||
"text": comment}
|
||||
return {"data": cls.__share_to_slack(tenant_id, integration_id, **args)}
|
||||
data = cls.__share(tenant_id, integration_id, attachement=args)
|
||||
if "errors" in data:
|
||||
return data
|
||||
return {"data": data}
|
||||
|
||||
@classmethod
|
||||
def share_error(cls, tenant_id, project_id, error_id, user, comment, integration_id=None):
|
||||
|
|
@ -141,19 +102,18 @@ class Slack:
|
|||
"title": f"{config('SITE_URL')}/{project_id}/errors/{error_id}",
|
||||
"title_link": f"{config('SITE_URL')}/{project_id}/errors/{error_id}",
|
||||
"text": comment}
|
||||
return {"data": cls.__share_to_slack(tenant_id, integration_id, **args)}
|
||||
|
||||
@classmethod
|
||||
def has_slack(cls, tenant_id):
|
||||
integration = cls.__get(tenant_id=tenant_id)
|
||||
return not (integration is None or len(integration) == 0)
|
||||
data = cls.__share(tenant_id, integration_id, attachement=args)
|
||||
if "errors" in data:
|
||||
return data
|
||||
return {"data": data}
|
||||
|
||||
@classmethod
|
||||
def __get(cls, tenant_id, integration_id=None):
|
||||
if integration_id is not None:
|
||||
return webhook.get(tenant_id=tenant_id, webhook_id=integration_id)
|
||||
return webhook.get_webhook(tenant_id=tenant_id, webhook_id=integration_id,
|
||||
webhook_type=schemas.WebhookType.slack)
|
||||
|
||||
integrations = webhook.get_by_type(tenant_id=tenant_id, webhook_type="slack")
|
||||
integrations = webhook.get_by_type(tenant_id=tenant_id, webhook_type=schemas.WebhookType.slack)
|
||||
if integrations is None or len(integrations) == 0:
|
||||
return None
|
||||
return integrations[0]
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ def get_project(tenant_id, project_id, include_last_session=False, include_gdpr=
|
|||
{",(SELECT max(ss.start_ts) FROM public.sessions AS ss WHERE ss.project_id = %(project_id)s) AS last_recorded_session_at" if include_last_session else ""}
|
||||
{',s.gdpr' if include_gdpr else ''}
|
||||
FROM public.projects AS s
|
||||
where s.project_id =%(project_id)s
|
||||
WHERE s.project_id =%(project_id)s
|
||||
AND s.deleted_at IS NULL
|
||||
LIMIT 1;""",
|
||||
{"project_id": project_id})
|
||||
|
|
@ -148,7 +148,7 @@ def get_project_by_key(tenant_id, project_key, include_last_session=False, inclu
|
|||
{",(SELECT max(ss.start_ts) FROM public.sessions AS ss WHERE ss.project_key = %(project_key)s) AS last_recorded_session_at" if include_last_session else ""}
|
||||
{',s.gdpr' if include_gdpr else ''}
|
||||
FROM public.projects AS s
|
||||
where s.project_key =%(project_key)s
|
||||
WHERE s.project_key =%(project_key)s
|
||||
AND s.deleted_at IS NULL
|
||||
LIMIT 1;""",
|
||||
{"project_key": project_key})
|
||||
|
|
@ -201,7 +201,7 @@ def count_by_tenant(tenant_id):
|
|||
SELECT
|
||||
count(s.project_id)
|
||||
FROM public.projects AS s
|
||||
where s.deleted_at IS NULL;""")
|
||||
WHERE s.deleted_at IS NULL;""")
|
||||
return cur.fetchone()["count"]
|
||||
|
||||
|
||||
|
|
@ -212,7 +212,7 @@ def get_gdpr(project_id):
|
|||
SELECT
|
||||
gdpr
|
||||
FROM public.projects AS s
|
||||
where s.project_id =%(project_id)s
|
||||
WHERE s.project_id =%(project_id)s
|
||||
AND s.deleted_at IS NULL;""",
|
||||
{"project_id": project_id})
|
||||
)
|
||||
|
|
@ -241,7 +241,7 @@ def get_internal_project_id(project_key):
|
|||
cur.mogrify("""\
|
||||
SELECT project_id
|
||||
FROM public.projects
|
||||
where project_key =%(project_key)s AND deleted_at ISNULL;""",
|
||||
WHERE project_key =%(project_key)s AND deleted_at ISNULL;""",
|
||||
{"project_key": project_key})
|
||||
)
|
||||
row = cur.fetchone()
|
||||
|
|
@ -254,7 +254,7 @@ def get_project_key(project_id):
|
|||
cur.mogrify("""\
|
||||
SELECT project_key
|
||||
FROM public.projects
|
||||
where project_id =%(project_id)s AND deleted_at ISNULL;""",
|
||||
WHERE project_id =%(project_id)s AND deleted_at ISNULL;""",
|
||||
{"project_id": project_id})
|
||||
)
|
||||
project = cur.fetchone()
|
||||
|
|
@ -268,7 +268,7 @@ def get_capture_status(project_id):
|
|||
SELECT
|
||||
sample_rate AS rate, sample_rate=100 AS capture_all
|
||||
FROM public.projects
|
||||
where project_id =%(project_id)s AND deleted_at ISNULL;""",
|
||||
WHERE project_id =%(project_id)s AND deleted_at ISNULL;""",
|
||||
{"project_id": project_id})
|
||||
)
|
||||
return helper.dict_to_camel_case(cur.fetchone())
|
||||
|
|
|
|||
|
|
@ -319,7 +319,7 @@ def get_transitions_and_issues_of_each_type(rows: List[RealDictRow], all_issues,
|
|||
|
||||
transitions ::: if transited from the first stage to the last - 1
|
||||
else - 0
|
||||
errors ::: a dictionary where the keys are all unique issues (currently context-wise)
|
||||
errors ::: a dictionary WHERE the keys are all unique issues (currently context-wise)
|
||||
the values are lists
|
||||
if an issue happened between the first stage to the last - 1
|
||||
else - 0
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
from datetime import datetime
|
||||
from decouple import config
|
||||
|
||||
from chalicelib.core.collaboration_slack import Slack
|
||||
|
||||
|
||||
def send_batch(notifications_list):
|
||||
if notifications_list is None or len(notifications_list) == 0:
|
||||
return
|
||||
webhookId_map = {}
|
||||
for n in notifications_list:
|
||||
if n.get("destination") not in webhookId_map:
|
||||
webhookId_map[n.get("destination")] = {"tenantId": n["notification"]["tenantId"], "batch": []}
|
||||
webhookId_map[n.get("destination")]["batch"].append({"text": n["notification"]["description"] \
|
||||
+ f"\n<{config('SITE_URL')}{n['notification']['buttonUrl']}|{n['notification']['buttonText']}>",
|
||||
"title": n["notification"]["title"],
|
||||
"title_link": n["notification"]["buttonUrl"],
|
||||
"ts": datetime.now().timestamp()})
|
||||
for batch in webhookId_map.keys():
|
||||
Slack.send_batch(tenant_id=webhookId_map[batch]["tenantId"], webhook_id=batch,
|
||||
attachments=webhookId_map[batch]["batch"])
|
||||
|
|
@ -12,7 +12,7 @@ def get_by_id(webhook_id):
|
|||
cur.mogrify("""\
|
||||
SELECT w.*
|
||||
FROM public.webhooks AS w
|
||||
where w.webhook_id =%(webhook_id)s AND deleted_at ISNULL;""",
|
||||
WHERE w.webhook_id =%(webhook_id)s AND deleted_at ISNULL;""",
|
||||
{"webhook_id": webhook_id})
|
||||
)
|
||||
w = helper.dict_to_camel_case(cur.fetchone())
|
||||
|
|
@ -21,15 +21,14 @@ def get_by_id(webhook_id):
|
|||
return w
|
||||
|
||||
|
||||
def get(tenant_id, webhook_id):
|
||||
def get_webhook(tenant_id, webhook_id, webhook_type='webhook'):
|
||||
with pg_client.PostgresClient() as cur:
|
||||
cur.execute(
|
||||
cur.mogrify("""\
|
||||
SELECT
|
||||
webhook_id AS integration_id, webhook_id AS id, w.*
|
||||
FROM public.webhooks AS w
|
||||
where w.webhook_id =%(webhook_id)s AND deleted_at ISNULL;""",
|
||||
{"webhook_id": webhook_id})
|
||||
cur.mogrify("""SELECT w.*
|
||||
FROM public.webhooks AS w
|
||||
WHERE w.webhook_id =%(webhook_id)s
|
||||
AND deleted_at ISNULL AND type=%(webhook_type)s;""",
|
||||
{"webhook_id": webhook_id, "webhook_type": webhook_type})
|
||||
)
|
||||
w = helper.dict_to_camel_case(cur.fetchone())
|
||||
if w:
|
||||
|
|
@ -40,11 +39,9 @@ def get(tenant_id, webhook_id):
|
|||
def get_by_type(tenant_id, webhook_type):
|
||||
with pg_client.PostgresClient() as cur:
|
||||
cur.execute(
|
||||
cur.mogrify("""\
|
||||
SELECT
|
||||
w.webhook_id AS integration_id, w.webhook_id AS id,w.webhook_id,w.endpoint,w.auth_header,w.type,w.index,w.name,w.created_at
|
||||
FROM public.webhooks AS w
|
||||
WHERE w.type =%(type)s AND deleted_at ISNULL;""",
|
||||
cur.mogrify("""SELECT w.webhook_id,w.endpoint,w.auth_header,w.type,w.index,w.name,w.created_at
|
||||
FROM public.webhooks AS w
|
||||
WHERE w.type =%(type)s AND deleted_at ISNULL;""",
|
||||
{"type": webhook_type})
|
||||
)
|
||||
webhooks = helper.list_to_camel_case(cur.fetchall())
|
||||
|
|
@ -55,22 +52,12 @@ def get_by_type(tenant_id, webhook_type):
|
|||
|
||||
def get_by_tenant(tenant_id, replace_none=False):
|
||||
with pg_client.PostgresClient() as cur:
|
||||
cur.execute("""\
|
||||
SELECT
|
||||
webhook_id AS integration_id, webhook_id AS id, w.*
|
||||
FROM public.webhooks AS w
|
||||
WHERE deleted_at ISNULL;"""
|
||||
)
|
||||
cur.execute("""SELECT w.*
|
||||
FROM public.webhooks AS w
|
||||
WHERE deleted_at ISNULL AND type='webhook';""")
|
||||
all = helper.list_to_camel_case(cur.fetchall())
|
||||
if replace_none:
|
||||
for w in all:
|
||||
w["createdAt"] = TimeUTC.datetime_to_timestamp(w["createdAt"])
|
||||
for k in w.keys():
|
||||
if w[k] is None:
|
||||
w[k] = ''
|
||||
else:
|
||||
for w in all:
|
||||
w["createdAt"] = TimeUTC.datetime_to_timestamp(w["createdAt"])
|
||||
for w in all:
|
||||
w["createdAt"] = TimeUTC.datetime_to_timestamp(w["createdAt"])
|
||||
return all
|
||||
|
||||
|
||||
|
|
@ -83,7 +70,7 @@ def update(tenant_id, webhook_id, changes, replace_none=False):
|
|||
UPDATE public.webhooks
|
||||
SET {','.join(sub_query)}
|
||||
WHERE webhook_id =%(id)s AND deleted_at ISNULL
|
||||
RETURNING webhook_id AS integration_id, webhook_id AS id,*;""",
|
||||
RETURNING *;""",
|
||||
{"id": webhook_id, **changes})
|
||||
)
|
||||
w = helper.dict_to_camel_case(cur.fetchone())
|
||||
|
|
@ -100,7 +87,7 @@ def add(tenant_id, endpoint, auth_header=None, webhook_type='webhook', name="",
|
|||
query = cur.mogrify("""\
|
||||
INSERT INTO public.webhooks(endpoint,auth_header,type,name)
|
||||
VALUES (%(endpoint)s, %(auth_header)s, %(type)s,%(name)s)
|
||||
RETURNING webhook_id AS integration_id, webhook_id AS id,*;""",
|
||||
RETURNING *;""",
|
||||
{"endpoint": endpoint, "auth_header": auth_header,
|
||||
"type": webhook_type, "name": name})
|
||||
cur.execute(
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ from chalicelib.core import log_tool_rollbar, sourcemaps, events, sessions_assig
|
|||
log_tool_newrelic, announcements, log_tool_bugsnag, weekly_report, integration_jira_cloud, integration_github, \
|
||||
assist, mobile, signup, tenants, boarding, notifications, webhook, users, \
|
||||
custom_metrics, saved_search, integrations_global
|
||||
from chalicelib.core.collaboration_msteams import MSTeams
|
||||
from chalicelib.core.collaboration_slack import Slack
|
||||
from chalicelib.utils import helper, captcha
|
||||
from or_dependencies import OR_context
|
||||
|
|
@ -104,21 +105,27 @@ def get_integrations_status(projectId: int, context: schemas.CurrentContext = De
|
|||
return {"data": data}
|
||||
|
||||
|
||||
@app.post('/{projectId}/integrations/{integration}/notify/{integrationId}/{source}/{sourceId}', tags=["integrations"])
|
||||
def integration_notify(projectId: int, integration: str, integrationId: int, source: str, sourceId: str,
|
||||
@app.post('/{projectId}/integrations/{integration}/notify/{webhookId}/{source}/{sourceId}', tags=["integrations"])
|
||||
def integration_notify(projectId: int, integration: str, webhookId: int, source: str, sourceId: str,
|
||||
data: schemas.IntegrationNotificationSchema = Body(...),
|
||||
context: schemas.CurrentContext = Depends(OR_context)):
|
||||
comment = None
|
||||
if data.comment:
|
||||
comment = data.comment
|
||||
if integration == "slack":
|
||||
args = {"tenant_id": context.tenant_id,
|
||||
"user": context.email, "comment": comment, "project_id": projectId,
|
||||
"integration_id": integrationId}
|
||||
|
||||
args = {"tenant_id": context.tenant_id,
|
||||
"user": context.email, "comment": comment, "project_id": projectId,
|
||||
"integration_id": webhookId}
|
||||
if integration == schemas.WebhookType.slack:
|
||||
if source == "sessions":
|
||||
return Slack.share_session(session_id=sourceId, **args)
|
||||
elif source == "errors":
|
||||
return Slack.share_error(error_id=sourceId, **args)
|
||||
elif integration == schemas.WebhookType.msteams:
|
||||
if source == "sessions":
|
||||
return MSTeams.share_session(session_id=sourceId, **args)
|
||||
elif source == "errors":
|
||||
return MSTeams.share_error(error_id=sourceId, **args)
|
||||
return {"data": None}
|
||||
|
||||
|
||||
|
|
@ -872,17 +879,18 @@ def get_boarding_state_integrations(context: schemas.CurrentContext = Depends(OR
|
|||
|
||||
@app.get('/integrations/slack/channels', tags=["integrations"])
|
||||
def get_slack_channels(context: schemas.CurrentContext = Depends(OR_context)):
|
||||
return {"data": webhook.get_by_type(tenant_id=context.tenant_id, webhook_type='slack')}
|
||||
return {"data": webhook.get_by_type(tenant_id=context.tenant_id, webhook_type=schemas.WebhookType.slack)}
|
||||
|
||||
|
||||
@app.get('/integrations/slack/{integrationId}', tags=["integrations"])
|
||||
def get_slack_webhook(integrationId: int, context: schemas.CurrentContext = Depends(OR_context)):
|
||||
return {"data": webhook.get(tenant_id=context.tenant_id, webhook_id=integrationId)}
|
||||
@app.get('/integrations/slack/{webhookId}', tags=["integrations"])
|
||||
def get_slack_webhook(webhookId: int, context: schemas.CurrentContext = Depends(OR_context)):
|
||||
return {"data": webhook.get_webhook(tenant_id=context.tenant_id, webhook_id=webhookId,
|
||||
webhook_type=schemas.WebhookType.slack)}
|
||||
|
||||
|
||||
@app.delete('/integrations/slack/{integrationId}', tags=["integrations"])
|
||||
def delete_slack_integration(integrationId: int, context: schemas.CurrentContext = Depends(OR_context)):
|
||||
return webhook.delete(context.tenant_id, integrationId)
|
||||
@app.delete('/integrations/slack/{webhookId}', tags=["integrations"])
|
||||
def delete_slack_integration(webhookId: int, context: schemas.CurrentContext = Depends(OR_context)):
|
||||
return webhook.delete(context.tenant_id, webhookId)
|
||||
|
||||
|
||||
@app.put('/webhooks', tags=["webhooks"])
|
||||
|
|
@ -965,6 +973,38 @@ def get_limits(context: schemas.CurrentContext = Depends(OR_context)):
|
|||
}
|
||||
}
|
||||
|
||||
@app.get('/integrations/msteams/channels', tags=["integrations"])
|
||||
def get_msteams_channels(context: schemas.CurrentContext = Depends(OR_context)):
|
||||
return {"data": webhook.get_by_type(tenant_id=context.tenant_id, webhook_type=schemas.WebhookType.msteams)}
|
||||
|
||||
|
||||
@app.post('/integrations/msteams', tags=['integrations'])
|
||||
def add_msteams_integration(data: schemas.AddCollaborationSchema,
|
||||
context: schemas.CurrentContext = Depends(OR_context)):
|
||||
n = MSTeams.add(tenant_id=context.tenant_id, data=data)
|
||||
if n is None:
|
||||
return {
|
||||
"errors": [
|
||||
"We couldn't send you a test message on your Microsoft Teams channel. Please verify your webhook url."]
|
||||
}
|
||||
return {"data": n}
|
||||
|
||||
|
||||
@app.post('/integrations/msteams/{webhookId}', tags=['integrations'])
|
||||
def edit_msteams_integration(webhookId: int, data: schemas.EditCollaborationSchema = Body(...),
|
||||
context: schemas.CurrentContext = Depends(OR_context)):
|
||||
if len(data.url) > 0:
|
||||
old = webhook.get_webhook(tenant_id=context.tenant_id, webhook_id=webhookId,
|
||||
webhook_type=schemas.WebhookType.msteams)
|
||||
if old["endpoint"] != data.url:
|
||||
if not MSTeams.say_hello(data.url):
|
||||
return {
|
||||
"errors": [
|
||||
"We couldn't send you a test message on your Microsoft Teams channel. Please verify your webhook url."]
|
||||
}
|
||||
return {"data": webhook.update(tenant_id=context.tenant_id, webhook_id=webhookId,
|
||||
changes={"name": data.name, "endpoint": data.url})}
|
||||
|
||||
|
||||
@public_app.get('/general_stats', tags=["private"], include_in_schema=False)
|
||||
def get_general_stats():
|
||||
|
|
|
|||
|
|
@ -62,8 +62,8 @@ def get_projects_limit(context: schemas.CurrentContext = Depends(OR_context)):
|
|||
|
||||
@app.post('/integrations/slack', tags=['integrations'])
|
||||
@app.put('/integrations/slack', tags=['integrations'])
|
||||
def add_slack_client(data: schemas.AddSlackSchema, context: schemas.CurrentContext = Depends(OR_context)):
|
||||
n = Slack.add_channel(tenant_id=context.tenant_id, url=data.url, name=data.name)
|
||||
def add_slack_integration(data: schemas.AddCollaborationSchema, context: schemas.CurrentContext = Depends(OR_context)):
|
||||
n = Slack.add(tenant_id=context.tenant_id, data=data)
|
||||
if n is None:
|
||||
return {
|
||||
"errors": ["We couldn't send you a test message on your Slack channel. Please verify your webhook url."]
|
||||
|
|
@ -72,10 +72,10 @@ def add_slack_client(data: schemas.AddSlackSchema, context: schemas.CurrentConte
|
|||
|
||||
|
||||
@app.post('/integrations/slack/{integrationId}', tags=['integrations'])
|
||||
def edit_slack_integration(integrationId: int, data: schemas.EditSlackSchema = Body(...),
|
||||
def edit_slack_integration(integrationId: int, data: schemas.EditCollaborationSchema = Body(...),
|
||||
context: schemas.CurrentContext = Depends(OR_context)):
|
||||
if len(data.url) > 0:
|
||||
old = webhook.get(tenant_id=context.tenant_id, webhook_id=integrationId)
|
||||
old = webhook.get_webhook(tenant_id=context.tenant_id, webhook_id=integrationId)
|
||||
if old["endpoint"] != data.url:
|
||||
if not Slack.say_hello(data.url):
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -78,14 +78,13 @@ class CurrentContext(CurrentAPIContext):
|
|||
_transform_email = validator('email', pre=True, allow_reuse=True)(transform_email)
|
||||
|
||||
|
||||
class AddSlackSchema(BaseModel):
|
||||
class AddCollaborationSchema(BaseModel):
|
||||
name: str = Field(...)
|
||||
url: HttpUrl = Field(...)
|
||||
|
||||
|
||||
class EditSlackSchema(BaseModel):
|
||||
class EditCollaborationSchema(AddCollaborationSchema):
|
||||
name: Optional[str] = Field(None)
|
||||
url: HttpUrl = Field(...)
|
||||
|
||||
|
||||
class CreateNotificationSchema(BaseModel):
|
||||
|
|
@ -1121,3 +1120,10 @@ class SessionUpdateNoteSchema(SessionNoteSchema):
|
|||
break
|
||||
assert c > 0, "at least 1 value should be provided for update"
|
||||
return values
|
||||
|
||||
|
||||
class WebhookType(str, Enum):
|
||||
webhook = "webhook"
|
||||
slack = "slack"
|
||||
email = "email"
|
||||
msteams = "msteams"
|
||||
|
|
|
|||
3
ee/api/.gitignore
vendored
3
ee/api/.gitignore
vendored
|
|
@ -183,6 +183,8 @@ Pipfile
|
|||
#exp /chalicelib/core/alerts_processor.py
|
||||
/chalicelib/core/announcements.py
|
||||
/chalicelib/core/autocomplete.py
|
||||
/chalicelib/core/collaboration_base.py
|
||||
/chalicelib/core/collaboration_msteams.py
|
||||
/chalicelib/core/collaboration_slack.py
|
||||
/chalicelib/core/countries.py
|
||||
#exp /chalicelib/core/errors.py
|
||||
|
|
@ -214,7 +216,6 @@ Pipfile
|
|||
/chalicelib/core/sessions_metas.py
|
||||
/chalicelib/core/sessions_mobs.py
|
||||
#exp /chalicelib/core/significance.py
|
||||
/chalicelib/core/slack.py
|
||||
/chalicelib/core/socket_ios.py
|
||||
/chalicelib/core/sourcemaps.py
|
||||
/chalicelib/core/sourcemaps_parser.py
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ def get_role_by_name(tenant_id, name):
|
|||
cur.execute(
|
||||
cur.mogrify("""SELECT *
|
||||
FROM public.roles
|
||||
where tenant_id =%(tenant_id)s
|
||||
WHERE tenant_id =%(tenant_id)s
|
||||
AND deleted_at IS NULL
|
||||
AND name ILIKE %(name)s;""",
|
||||
{"tenant_id": tenant_id, "name": name})
|
||||
|
|
|
|||
|
|
@ -326,7 +326,7 @@ def get_transitions_and_issues_of_each_type(rows: List[RealDictRow], all_issues,
|
|||
|
||||
transitions ::: if transited from the first stage to the last - 1
|
||||
else - 0
|
||||
errors ::: a dictionary where the keys are all unique issues (currently context-wise)
|
||||
errors ::: a dictionary WHERE the keys are all unique issues (currently context-wise)
|
||||
the values are lists
|
||||
if an issue happened between the first stage to the last - 1
|
||||
else - 0
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ def get_transitions_and_issues_of_each_type(rows: List[RealDictRow], all_issues_
|
|||
|
||||
transitions ::: if transited from the first stage to the last - 1
|
||||
else - 0
|
||||
errors ::: a dictionary where the keys are all unique issues (currently context-wise)
|
||||
errors ::: a dictionary WHERE the keys are all unique issues (currently context-wise)
|
||||
the values are lists
|
||||
if an issue happened between the first stage to the last - 1
|
||||
else - 0
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ def get_by_id(webhook_id):
|
|||
cur.mogrify("""\
|
||||
SELECT w.*
|
||||
FROM public.webhooks AS w
|
||||
where w.webhook_id =%(webhook_id)s AND deleted_at ISNULL;""",
|
||||
WHERE w.webhook_id =%(webhook_id)s AND deleted_at ISNULL;""",
|
||||
{"webhook_id": webhook_id})
|
||||
)
|
||||
w = helper.dict_to_camel_case(cur.fetchone())
|
||||
|
|
@ -21,15 +21,14 @@ def get_by_id(webhook_id):
|
|||
return w
|
||||
|
||||
|
||||
def get(tenant_id, webhook_id):
|
||||
def get_webhook(tenant_id, webhook_id, webhook_type='webhook'):
|
||||
with pg_client.PostgresClient() as cur:
|
||||
cur.execute(
|
||||
cur.mogrify("""\
|
||||
SELECT
|
||||
webhook_id AS integration_id, webhook_id AS id, w.*
|
||||
FROM public.webhooks AS w
|
||||
where w.webhook_id =%(webhook_id)s AND w.tenant_id =%(tenant_id)s AND deleted_at ISNULL;""",
|
||||
{"webhook_id": webhook_id, "tenant_id": tenant_id})
|
||||
cur.mogrify("""SELECT w.*
|
||||
FROM public.webhooks AS w
|
||||
WHERE w.webhook_id =%(webhook_id)s AND w.tenant_id =%(tenant_id)s
|
||||
AND deleted_at ISNULL AND type=%(webhook_type)s;""",
|
||||
{"webhook_id": webhook_id, "webhook_type": webhook_type, "tenant_id": tenant_id})
|
||||
)
|
||||
w = helper.dict_to_camel_case(cur.fetchone())
|
||||
if w:
|
||||
|
|
@ -40,9 +39,7 @@ def get(tenant_id, webhook_id):
|
|||
def get_by_type(tenant_id, webhook_type):
|
||||
with pg_client.PostgresClient() as cur:
|
||||
cur.execute(
|
||||
cur.mogrify("""\
|
||||
SELECT
|
||||
w.webhook_id AS integration_id, w.webhook_id AS id,w.webhook_id,w.endpoint,w.auth_header,w.type,w.index,w.name,w.created_at
|
||||
cur.mogrify("""SELECT w.webhook_id,w.webhook_id,w.endpoint,w.auth_header,w.type,w.index,w.name,w.created_at
|
||||
FROM public.webhooks AS w
|
||||
WHERE w.tenant_id =%(tenant_id)s
|
||||
AND w.type =%(type)s
|
||||
|
|
@ -58,25 +55,16 @@ def get_by_type(tenant_id, webhook_type):
|
|||
def get_by_tenant(tenant_id, replace_none=False):
|
||||
with pg_client.PostgresClient() as cur:
|
||||
cur.execute(
|
||||
cur.mogrify("""\
|
||||
SELECT
|
||||
webhook_id AS integration_id, webhook_id AS id,w.*
|
||||
FROM public.webhooks AS w
|
||||
where
|
||||
w.tenant_id =%(tenant_id)s
|
||||
AND deleted_at ISNULL;""",
|
||||
cur.mogrify("""SELECT w.*
|
||||
FROM public.webhooks AS w
|
||||
WHERE w.tenant_id =%(tenant_id)s
|
||||
AND deleted_at ISNULL
|
||||
AND type='webhook';""",
|
||||
{"tenant_id": tenant_id})
|
||||
)
|
||||
all = helper.list_to_camel_case(cur.fetchall())
|
||||
if replace_none:
|
||||
for w in all:
|
||||
w["createdAt"] = TimeUTC.datetime_to_timestamp(w["createdAt"])
|
||||
for k in w.keys():
|
||||
if w[k] is None:
|
||||
w[k] = ''
|
||||
else:
|
||||
for w in all:
|
||||
w["createdAt"] = TimeUTC.datetime_to_timestamp(w["createdAt"])
|
||||
for w in all:
|
||||
w["createdAt"] = TimeUTC.datetime_to_timestamp(w["createdAt"])
|
||||
return all
|
||||
|
||||
|
||||
|
|
@ -89,7 +77,7 @@ def update(tenant_id, webhook_id, changes, replace_none=False):
|
|||
UPDATE public.webhooks
|
||||
SET {','.join(sub_query)}
|
||||
WHERE tenant_id =%(tenant_id)s AND webhook_id =%(id)s AND deleted_at ISNULL
|
||||
RETURNING webhook_id AS integration_id, webhook_id AS id,*;""",
|
||||
RETURNING *;""",
|
||||
{"tenant_id": tenant_id, "id": webhook_id, **changes})
|
||||
)
|
||||
w = helper.dict_to_camel_case(cur.fetchone())
|
||||
|
|
@ -106,7 +94,7 @@ def add(tenant_id, endpoint, auth_header=None, webhook_type='webhook', name="",
|
|||
query = cur.mogrify("""\
|
||||
INSERT INTO public.webhooks(tenant_id, endpoint,auth_header,type,name)
|
||||
VALUES (%(tenant_id)s, %(endpoint)s, %(auth_header)s, %(type)s,%(name)s)
|
||||
RETURNING webhook_id AS integration_id, webhook_id AS id,*;""",
|
||||
RETURNING *;""",
|
||||
{"tenant_id": tenant_id, "endpoint": endpoint, "auth_header": auth_header,
|
||||
"type": webhook_type, "name": name})
|
||||
cur.execute(
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ rm -rf ./chalicelib/core/alerts.py
|
|||
#exp rm -rf ./chalicelib/core/alerts_processor.py
|
||||
rm -rf ./chalicelib/core/announcements.py
|
||||
rm -rf ./chalicelib/core/autocomplete.py
|
||||
rm -rf ./chalicelib/core/collaboration_base.py
|
||||
rm -rf ./chalicelib/core/collaboration_msteams.py
|
||||
rm -rf ./chalicelib/core/collaboration_slack.py
|
||||
rm -rf ./chalicelib/core/countries.py
|
||||
#exp rm -rf ./chalicelib/core/errors.py
|
||||
|
|
@ -36,7 +38,6 @@ rm -rf ./chalicelib/core/sessions_assignments.py
|
|||
rm -rf ./chalicelib/core/sessions_metas.py
|
||||
rm -rf ./chalicelib/core/sessions_mobs.py
|
||||
#exp rm -rf ./chalicelib/core/significance.py
|
||||
rm -rf ./chalicelib/core/slack.py
|
||||
rm -rf ./chalicelib/core/socket_ios.py
|
||||
rm -rf ./chalicelib/core/sourcemaps.py
|
||||
rm -rf ./chalicelib/core/sourcemaps_parser.py
|
||||
|
|
|
|||
|
|
@ -66,8 +66,8 @@ def get_projects_limit(context: schemas.CurrentContext = Depends(OR_context)):
|
|||
|
||||
@app.post('/integrations/slack', tags=['integrations'])
|
||||
@app.put('/integrations/slack', tags=['integrations'])
|
||||
def add_slack_client(data: schemas.AddSlackSchema, context: schemas.CurrentContext = Depends(OR_context)):
|
||||
n = Slack.add_channel(tenant_id=context.tenant_id, url=data.url, name=data.name)
|
||||
def add_slack_client(data: schemas.AddCollaborationSchema, context: schemas.CurrentContext = Depends(OR_context)):
|
||||
n = Slack.add(tenant_id=context.tenant_id, data=data)
|
||||
if n is None:
|
||||
return {
|
||||
"errors": ["We couldn't send you a test message on your Slack channel. Please verify your webhook url."]
|
||||
|
|
@ -76,7 +76,7 @@ def add_slack_client(data: schemas.AddSlackSchema, context: schemas.CurrentConte
|
|||
|
||||
|
||||
@app.post('/integrations/slack/{integrationId}', tags=['integrations'])
|
||||
def edit_slack_integration(integrationId: int, data: schemas.EditSlackSchema = Body(...),
|
||||
def edit_slack_integration(integrationId: int, data: schemas.EditCollaborationSchema = Body(...),
|
||||
context: schemas.CurrentContext = Depends(OR_context)):
|
||||
if len(data.url) > 0:
|
||||
old = webhook.get(tenant_id=context.tenant_id, webhook_id=integrationId)
|
||||
|
|
|
|||
13
ee/scripts/helm/db/init_dbs/postgresql/1.8.3/1.8.3.sql
Normal file
13
ee/scripts/helm/db/init_dbs/postgresql/1.8.3/1.8.3.sql
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
BEGIN;
|
||||
CREATE OR REPLACE FUNCTION openreplay_version()
|
||||
RETURNS text AS
|
||||
$$
|
||||
SELECT 'v1.8.3-ee'
|
||||
$$ LANGUAGE sql IMMUTABLE;
|
||||
|
||||
ALTER TABLE IF EXISTS public.webhooks
|
||||
ALTER COLUMN type SET DEFAULT 'webhook';
|
||||
|
||||
ALTER TYPE webhook_type ADD VALUE IF NOT EXISTS 'msteams';
|
||||
|
||||
COMMIT;
|
||||
|
|
@ -18,4 +18,6 @@ CREATE TABLE IF NOT EXISTS assist_records
|
|||
duration integer NOT NULL
|
||||
);
|
||||
|
||||
ALTER TYPE webhook_type ADD VALUE IF NOT EXISTS 'msteams';
|
||||
|
||||
COMMIT;
|
||||
|
|
@ -147,7 +147,7 @@ $$
|
|||
tenant_id integer generated BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
tenant_key text NOT NULL DEFAULT generate_api_key(20),
|
||||
name text NOT NULL,
|
||||
api_key text UNIQUE default generate_api_key(20) not null,
|
||||
api_key text UNIQUE DEFAULT generate_api_key(20) NOT NULL,
|
||||
created_at timestamp without time zone NOT NULL DEFAULT (now() at time zone 'utc'),
|
||||
deleted_at timestamp without time zone NULL DEFAULT NULL,
|
||||
license text NULL,
|
||||
|
|
@ -187,9 +187,9 @@ $$
|
|||
email text NOT NULL UNIQUE,
|
||||
role user_role NOT NULL DEFAULT 'member',
|
||||
name text NOT NULL,
|
||||
created_at timestamp without time zone NOT NULL default (now() at time zone 'utc'),
|
||||
created_at timestamp without time zone NOT NULL DEFAULT (now() at time zone 'utc'),
|
||||
deleted_at timestamp without time zone NULL DEFAULT NULL,
|
||||
api_key text UNIQUE default generate_api_key(20) not null,
|
||||
api_key text UNIQUE DEFAULT generate_api_key(20) NOT NULL,
|
||||
jwt_iat timestamp without time zone NULL DEFAULT NULL,
|
||||
data jsonb NOT NULL DEFAULT'{}'::jsonb,
|
||||
weekly_report boolean NOT NULL DEFAULT TRUE,
|
||||
|
|
@ -284,25 +284,25 @@ $$
|
|||
IF NOT EXISTS(SELECT *
|
||||
FROM pg_type typ
|
||||
WHERE typ.typname = 'webhook_type') THEN
|
||||
create type webhook_type as enum ('webhook','slack','email');
|
||||
CREATE TYPE webhook_type AS ENUM ('webhook','slack','email','msteams');
|
||||
END IF;
|
||||
|
||||
|
||||
create table IF NOT EXISTS webhooks
|
||||
CREATE TABLE IF NOT EXISTS webhooks
|
||||
(
|
||||
webhook_id integer generated by default as identity
|
||||
webhook_id integer generated by DEFAULT as identity
|
||||
constraint webhooks_pkey
|
||||
primary key,
|
||||
tenant_id integer not null
|
||||
tenant_id integer NOT NULL
|
||||
constraint webhooks_tenant_id_fkey
|
||||
references tenants
|
||||
on delete cascade,
|
||||
endpoint text not null,
|
||||
created_at timestamp default timezone('utc'::text, now()) not null,
|
||||
endpoint text NOT NULL,
|
||||
created_at timestamp DEFAULT timezone('utc'::text, now()) NOT NULL,
|
||||
deleted_at timestamp,
|
||||
auth_header text,
|
||||
type webhook_type not null,
|
||||
index integer default 0 not null,
|
||||
type webhook_type NOT NULL DEFAULT 'webhook',
|
||||
index integer DEFAULT 0 NOT NULL,
|
||||
name varchar(100)
|
||||
);
|
||||
|
||||
|
|
@ -340,9 +340,9 @@ $$
|
|||
funnel_id integer generated BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
project_id integer NOT NULL REFERENCES projects (project_id) ON DELETE CASCADE,
|
||||
user_id integer NOT NULL REFERENCES users (user_id) ON DELETE CASCADE,
|
||||
name text not null,
|
||||
filter jsonb not null,
|
||||
created_at timestamp default timezone('utc'::text, now()) not null,
|
||||
name text NOT NULL,
|
||||
filter jsonb NOT NULL,
|
||||
created_at timestamp DEFAULT timezone('utc'::text, now()) NOT NULL,
|
||||
deleted_at timestamp,
|
||||
is_public boolean NOT NULL DEFAULT False
|
||||
);
|
||||
|
|
@ -353,21 +353,21 @@ $$
|
|||
IF NOT EXISTS(SELECT *
|
||||
FROM pg_type typ
|
||||
WHERE typ.typname = 'announcement_type') THEN
|
||||
create type announcement_type as enum ('notification','alert');
|
||||
CREATE TYPE announcement_type AS ENUM ('notification','alert');
|
||||
END IF;
|
||||
|
||||
create table IF NOT EXISTS announcements
|
||||
CREATE TABLE IF NOT EXISTS announcements
|
||||
(
|
||||
announcement_id serial not null
|
||||
announcement_id serial NOT NULL
|
||||
constraint announcements_pk
|
||||
primary key,
|
||||
title text not null,
|
||||
description text not null,
|
||||
title text NOT NULL,
|
||||
description text NOT NULL,
|
||||
button_text varchar(30),
|
||||
button_url text,
|
||||
image_url text,
|
||||
created_at timestamp default timezone('utc'::text, now()) not null,
|
||||
type announcement_type default 'notification'::announcement_type not null
|
||||
created_at timestamp DEFAULT timezone('utc'::text, now()) NOT NULL,
|
||||
type announcement_type DEFAULT 'notification'::announcement_type NOT NULL
|
||||
);
|
||||
|
||||
IF NOT EXISTS(SELECT *
|
||||
|
|
@ -396,14 +396,14 @@ $$
|
|||
|
||||
CREATE TABLE IF NOT EXISTS jira_cloud
|
||||
(
|
||||
user_id integer not null
|
||||
user_id integer NOT NULL
|
||||
constraint jira_cloud_pk
|
||||
primary key
|
||||
constraint jira_cloud_users_fkey
|
||||
references users
|
||||
on delete cascade,
|
||||
username text not null,
|
||||
token text not null,
|
||||
username text NOT NULL,
|
||||
token text NOT NULL,
|
||||
url text
|
||||
);
|
||||
|
||||
|
|
@ -653,8 +653,8 @@ $$
|
|||
issue_id text NOT NULL,
|
||||
provider oauth_provider NOT NULL,
|
||||
created_by integer NOT NULL,
|
||||
created_at timestamp default timezone('utc'::text, now()) NOT NULL,
|
||||
provider_data jsonb default'{}'::jsonb NOT NULL
|
||||
created_at timestamp DEFAULT timezone('utc'::text, now()) NOT NULL,
|
||||
provider_data jsonb DEFAULT'{}'::jsonb NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS assigned_sessions_session_id_idx ON assigned_sessions (session_id);
|
||||
|
||||
|
|
@ -707,8 +707,8 @@ $$
|
|||
project_id integer NOT NULL REFERENCES projects (project_id) ON DELETE CASCADE,
|
||||
action job_action NOT NULL,
|
||||
reference_id text NOT NULL,
|
||||
created_at timestamp default timezone('utc'::text, now()) NOT NULL,
|
||||
updated_at timestamp default timezone('utc'::text, now()) NULL,
|
||||
created_at timestamp DEFAULT timezone('utc'::text, now()) NOT NULL,
|
||||
updated_at timestamp DEFAULT timezone('utc'::text, now()) NULL,
|
||||
start_at timestamp NOT NULL,
|
||||
errors text NULL
|
||||
);
|
||||
|
|
@ -810,9 +810,9 @@ $$
|
|||
search_id integer generated BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
project_id integer NOT NULL REFERENCES projects (project_id) ON DELETE CASCADE,
|
||||
user_id integer NOT NULL REFERENCES users (user_id) ON DELETE CASCADE,
|
||||
name text not null,
|
||||
filter jsonb not null,
|
||||
created_at timestamp default timezone('utc'::text, now()) not null,
|
||||
name text NOT NULL,
|
||||
filter jsonb NOT NULL,
|
||||
created_at timestamp DEFAULT timezone('utc'::text, now()) NOT NULL,
|
||||
deleted_at timestamp,
|
||||
is_public boolean NOT NULL DEFAULT False
|
||||
);
|
||||
|
|
@ -864,7 +864,7 @@ $$
|
|||
(
|
||||
note_id integer generated BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
message text NOT NULL,
|
||||
created_at timestamp without time zone NOT NULL default (now() at time zone 'utc'),
|
||||
created_at timestamp without time zone NOT NULL DEFAULT (now() at time zone 'utc'),
|
||||
user_id integer NULL REFERENCES users (user_id) ON DELETE SET NULL,
|
||||
deleted_at timestamp without time zone NULL DEFAULT NULL,
|
||||
tag text NULL,
|
||||
|
|
|
|||
13
scripts/helm/db/init_dbs/postgresql/1.8.3/1.8.3.sql
Normal file
13
scripts/helm/db/init_dbs/postgresql/1.8.3/1.8.3.sql
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
BEGIN;
|
||||
CREATE OR REPLACE FUNCTION openreplay_version()
|
||||
RETURNS text AS
|
||||
$$
|
||||
SELECT 'v1.8.3'
|
||||
$$ LANGUAGE sql IMMUTABLE;
|
||||
|
||||
ALTER TABLE IF EXISTS public.webhooks
|
||||
ALTER COLUMN type SET DEFAULT 'webhook';
|
||||
|
||||
ALTER TYPE webhook_type ADD VALUE IF NOT EXISTS 'msteams';
|
||||
|
||||
COMMIT;
|
||||
10
scripts/schema/db/init_dbs/postgresql/1.9.5/1.9.5.sql
Normal file
10
scripts/schema/db/init_dbs/postgresql/1.9.5/1.9.5.sql
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
BEGIN;
|
||||
CREATE OR REPLACE FUNCTION openreplay_version()
|
||||
RETURNS text AS
|
||||
$$
|
||||
SELECT 'v1.9.5'
|
||||
$$ LANGUAGE sql IMMUTABLE;
|
||||
|
||||
ALTER TYPE webhook_type ADD VALUE IF NOT EXISTS 'msteams';
|
||||
|
||||
COMMIT;
|
||||
|
|
@ -9,7 +9,6 @@ $$
|
|||
SELECT 'v1.9.0'
|
||||
$$ LANGUAGE sql IMMUTABLE;
|
||||
|
||||
-- --- accounts.sql ---
|
||||
|
||||
CREATE OR REPLACE FUNCTION generate_api_key(length integer) RETURNS text AS
|
||||
$$
|
||||
|
|
@ -29,7 +28,6 @@ begin
|
|||
end;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- --- events.sql ---
|
||||
|
||||
CREATE OR REPLACE FUNCTION events.funnel(steps integer[], m integer) RETURNS boolean AS
|
||||
$$
|
||||
|
|
@ -54,7 +52,6 @@ BEGIN
|
|||
END;
|
||||
$$ LANGUAGE plpgsql IMMUTABLE;
|
||||
|
||||
-- --- integrations.sql ---
|
||||
|
||||
CREATE OR REPLACE FUNCTION notify_integration() RETURNS trigger AS
|
||||
$$
|
||||
|
|
@ -70,7 +67,6 @@ BEGIN
|
|||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- --- alerts.sql ---
|
||||
|
||||
CREATE OR REPLACE FUNCTION notify_alert() RETURNS trigger AS
|
||||
$$
|
||||
|
|
@ -87,7 +83,6 @@ BEGIN
|
|||
END ;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- --- projects.sql ---
|
||||
|
||||
CREATE OR REPLACE FUNCTION notify_project() RETURNS trigger AS
|
||||
$$
|
||||
|
|
@ -110,11 +105,9 @@ $$
|
|||
ELSE
|
||||
raise notice 'Creating DB';
|
||||
|
||||
-- --- public.sql ---
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
||||
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||
-- --- accounts.sql ---
|
||||
|
||||
CREATE TABLE tenants
|
||||
(
|
||||
|
|
@ -141,9 +134,9 @@ $$
|
|||
email text NOT NULL UNIQUE,
|
||||
role user_role NOT NULL DEFAULT 'member',
|
||||
name text NOT NULL,
|
||||
created_at timestamp without time zone NOT NULL default (now() at time zone 'utc'),
|
||||
created_at timestamp without time zone NOT NULL DEFAULT (now() at time zone 'utc'),
|
||||
deleted_at timestamp without time zone NULL DEFAULT NULL,
|
||||
api_key text UNIQUE default generate_api_key(20) not null,
|
||||
api_key text UNIQUE DEFAULT generate_api_key(20) NOT NULL,
|
||||
jwt_iat timestamp without time zone NULL DEFAULT NULL,
|
||||
data jsonb NOT NULL DEFAULT '{}'::jsonb,
|
||||
weekly_report boolean NOT NULL DEFAULT TRUE
|
||||
|
|
@ -171,7 +164,6 @@ $$
|
|||
);
|
||||
CREATE UNIQUE INDEX oauth_authentication_unique_user_id_provider_idx ON oauth_authentication (user_id, provider);
|
||||
|
||||
-- --- projects.sql ---
|
||||
|
||||
CREATE TABLE projects
|
||||
(
|
||||
|
|
@ -214,25 +206,22 @@ $$
|
|||
EXECUTE PROCEDURE notify_project();
|
||||
|
||||
|
||||
-- --- webhooks.sql ---
|
||||
CREATE TYPE webhook_type AS ENUM ('webhook', 'slack', 'email', 'msteams');
|
||||
|
||||
create type webhook_type as enum ('webhook', 'slack', 'email');
|
||||
|
||||
create table webhooks
|
||||
CREATE TABLE webhooks
|
||||
(
|
||||
webhook_id integer generated by default as identity
|
||||
webhook_id integer generated by DEFAULT as identity
|
||||
constraint webhooks_pkey
|
||||
primary key,
|
||||
endpoint text not null,
|
||||
created_at timestamp default timezone('utc'::text, now()) not null,
|
||||
endpoint text NOT NULL,
|
||||
created_at timestamp DEFAULT timezone('utc'::text, now()) NOT NULL,
|
||||
deleted_at timestamp,
|
||||
auth_header text,
|
||||
type webhook_type not null,
|
||||
index integer default 0 not null,
|
||||
type webhook_type NOT NULL DEFAULT 'webhook',
|
||||
index integer DEFAULT 0 NOT NULL,
|
||||
name varchar(100)
|
||||
);
|
||||
|
||||
-- --- notifications.sql ---
|
||||
|
||||
CREATE TABLE notifications
|
||||
(
|
||||
|
|
@ -258,16 +247,15 @@ $$
|
|||
constraint user_viewed_notifications_pkey primary key (user_id, notification_id)
|
||||
);
|
||||
|
||||
-- --- funnels.sql ---
|
||||
|
||||
CREATE TABLE funnels
|
||||
(
|
||||
funnel_id integer generated BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
project_id integer NOT NULL REFERENCES projects (project_id) ON DELETE CASCADE,
|
||||
user_id integer NOT NULL REFERENCES users (user_id) ON DELETE CASCADE,
|
||||
name text not null,
|
||||
filter jsonb not null,
|
||||
created_at timestamp default timezone('utc'::text, now()) not null,
|
||||
name text NOT NULL,
|
||||
filter jsonb NOT NULL,
|
||||
created_at timestamp DEFAULT timezone('utc'::text, now()) NOT NULL,
|
||||
deleted_at timestamp,
|
||||
is_public boolean NOT NULL DEFAULT False
|
||||
);
|
||||
|
|
@ -275,25 +263,23 @@ $$
|
|||
CREATE INDEX funnels_user_id_is_public_idx ON public.funnels (user_id, is_public);
|
||||
CREATE INDEX funnels_project_id_idx ON public.funnels (project_id);
|
||||
|
||||
-- --- announcements.sql ---
|
||||
|
||||
create type announcement_type as enum ('notification', 'alert');
|
||||
CREATE TYPE announcement_type AS ENUM ('notification', 'alert');
|
||||
|
||||
create table announcements
|
||||
CREATE TABLE announcements
|
||||
(
|
||||
announcement_id serial not null
|
||||
announcement_id serial NOT NULL
|
||||
constraint announcements_pk
|
||||
primary key,
|
||||
title text not null,
|
||||
description text not null,
|
||||
title text NOT NULL,
|
||||
description text NOT NULL,
|
||||
button_text varchar(30),
|
||||
button_url text,
|
||||
image_url text,
|
||||
created_at timestamp default timezone('utc'::text, now()) not null,
|
||||
type announcement_type default 'notification'::announcement_type not null
|
||||
created_at timestamp DEFAULT timezone('utc'::text, now()) NOT NULL,
|
||||
type announcement_type DEFAULT 'notification'::announcement_type NOT NULL
|
||||
);
|
||||
|
||||
-- --- integrations.sql ---
|
||||
|
||||
CREATE TYPE integration_provider AS ENUM ('bugsnag', 'cloudwatch', 'datadog', 'newrelic', 'rollbar', 'sentry', 'stackdriver', 'sumologic', 'elasticsearch'); --, 'jira', 'github');
|
||||
CREATE TABLE integrations
|
||||
|
|
@ -312,20 +298,19 @@ $$
|
|||
EXECUTE PROCEDURE notify_integration();
|
||||
|
||||
|
||||
create table jira_cloud
|
||||
CREATE TABLE jira_cloud
|
||||
(
|
||||
user_id integer not null
|
||||
user_id integer NOT NULL
|
||||
constraint jira_cloud_pk
|
||||
primary key
|
||||
constraint jira_cloud_users_fkey
|
||||
references users
|
||||
on delete cascade,
|
||||
username text not null,
|
||||
token text not null,
|
||||
username text NOT NULL,
|
||||
token text NOT NULL,
|
||||
url text
|
||||
);
|
||||
|
||||
-- --- issues.sql ---
|
||||
|
||||
CREATE TYPE issue_type AS ENUM (
|
||||
'click_rage',
|
||||
|
|
@ -361,7 +346,6 @@ $$
|
|||
CREATE INDEX issues_context_string_gin_idx ON public.issues USING GIN (context_string gin_trgm_ops);
|
||||
CREATE INDEX issues_project_id_idx ON issues (project_id);
|
||||
|
||||
-- --- errors.sql ---
|
||||
|
||||
CREATE TYPE error_source AS ENUM ('js_exception', 'bugsnag', 'cloudwatch', 'datadog', 'newrelic', 'rollbar', 'sentry', 'stackdriver', 'sumologic', 'elasticsearch');
|
||||
CREATE TYPE error_status AS ENUM ('unresolved', 'resolved', 'ignored');
|
||||
|
|
@ -406,7 +390,6 @@ $$
|
|||
CREATE INDEX user_viewed_errors_error_id_idx ON public.user_viewed_errors (error_id);
|
||||
|
||||
|
||||
-- --- sessions.sql ---
|
||||
CREATE TYPE device_type AS ENUM ('desktop', 'tablet', 'mobile', 'other');
|
||||
CREATE TYPE country AS ENUM ('UN', 'RW', 'SO', 'YE', 'IQ', 'SA', 'IR', 'CY', 'TZ', 'SY', 'AM', 'KE', 'CD', 'DJ', 'UG', 'CF', 'SC', 'JO', 'LB', 'KW', 'OM', 'QA', 'BH', 'AE', 'IL', 'TR', 'ET', 'ER', 'EG', 'SD', 'GR', 'BI', 'EE', 'LV', 'AZ', 'LT', 'SJ', 'GE', 'MD', 'BY', 'FI', 'AX', 'UA', 'MK', 'HU', 'BG', 'AL', 'PL', 'RO', 'XK', 'ZW', 'ZM', 'KM', 'MW', 'LS', 'BW', 'MU', 'SZ', 'RE', 'ZA', 'YT', 'MZ', 'MG', 'AF', 'PK', 'BD', 'TM', 'TJ', 'LK', 'BT', 'IN', 'MV', 'IO', 'NP', 'MM', 'UZ', 'KZ', 'KG', 'TF', 'HM', 'CC', 'PW', 'VN', 'TH', 'ID', 'LA', 'TW', 'PH', 'MY', 'CN', 'HK', 'BN', 'MO', 'KH', 'KR', 'JP', 'KP', 'SG', 'CK', 'TL', 'RU', 'MN', 'AU', 'CX', 'MH', 'FM', 'PG', 'SB', 'TV', 'NR', 'VU', 'NC', 'NF', 'NZ', 'FJ', 'LY', 'CM', 'SN', 'CG', 'PT', 'LR', 'CI', 'GH', 'GQ', 'NG', 'BF', 'TG', 'GW', 'MR', 'BJ', 'GA', 'SL', 'ST', 'GI', 'GM', 'GN', 'TD', 'NE', 'ML', 'EH', 'TN', 'ES', 'MA', 'MT', 'DZ', 'FO', 'DK', 'IS', 'GB', 'CH', 'SE', 'NL', 'AT', 'BE', 'DE', 'LU', 'IE', 'MC', 'FR', 'AD', 'LI', 'JE', 'IM', 'GG', 'SK', 'CZ', 'NO', 'VA', 'SM', 'IT', 'SI', 'ME', 'HR', 'BA', 'AO', 'NA', 'SH', 'BV', 'BB', 'CV', 'GY', 'GF', 'SR', 'PM', 'GL', 'PY', 'UY', 'BR', 'FK', 'GS', 'JM', 'DO', 'CU', 'MQ', 'BS', 'BM', 'AI', 'TT', 'KN', 'DM', 'AG', 'LC', 'TC', 'AW', 'VG', 'VC', 'MS', 'MF', 'BL', 'GP', 'GD', 'KY', 'BZ', 'SV', 'GT', 'HN', 'NI', 'CR', 'VE', 'EC', 'CO', 'PA', 'HT', 'AR', 'CL', 'BO', 'PE', 'MX', 'PF', 'PN', 'KI', 'TK', 'TO', 'WF', 'WS', 'NU', 'MP', 'GU', 'PR', 'VI', 'UM', 'AS', 'CA', 'US', 'PS', 'RS', 'AQ', 'SX', 'CW', 'BQ', 'SS','AC','AN','BU','CP','CS','CT','DD','DG','DY','EA','FQ','FX','HV','IC','JT','MI','NH','NQ','NT','PC','PU','PZ','RH','SU','TA','TP','VD','WK','YD','YU','ZR');
|
||||
CREATE TYPE platform AS ENUM ('web','ios','android');
|
||||
|
|
@ -532,21 +515,18 @@ $$
|
|||
);
|
||||
CREATE INDEX user_favorite_sessions_user_id_session_id_idx ON user_favorite_sessions (user_id, session_id);
|
||||
|
||||
-- --- assignments.sql ---
|
||||
|
||||
create table assigned_sessions
|
||||
CREATE TABLE assigned_sessions
|
||||
(
|
||||
session_id bigint NOT NULL REFERENCES sessions (session_id) ON DELETE CASCADE,
|
||||
issue_id text NOT NULL,
|
||||
provider oauth_provider NOT NULL,
|
||||
created_by integer NOT NULL,
|
||||
created_at timestamp default timezone('utc'::text, now()) NOT NULL,
|
||||
provider_data jsonb default '{}'::jsonb NOT NULL
|
||||
created_at timestamp DEFAULT timezone('utc'::text, now()) NOT NULL,
|
||||
provider_data jsonb DEFAULT '{}'::jsonb NOT NULL
|
||||
);
|
||||
CREATE INDEX assigned_sessions_session_id_idx ON assigned_sessions (session_id);
|
||||
|
||||
-- --- events_common.sql ---
|
||||
|
||||
|
||||
CREATE TYPE events_common.custom_level AS ENUM ('info','error');
|
||||
|
||||
|
|
@ -611,7 +591,6 @@ $$
|
|||
CREATE INDEX requests_query_nn_idx ON events_common.requests (query) WHERE query IS NOT NULL;
|
||||
CREATE INDEX requests_query_nn_gin_idx ON events_common.requests USING GIN (query gin_trgm_ops) WHERE query IS NOT NULL;
|
||||
|
||||
-- --- events.sql ---
|
||||
|
||||
CREATE TABLE events.pages
|
||||
(
|
||||
|
|
@ -847,8 +826,6 @@ $$
|
|||
CREATE INDEX performance_avg_used_js_heap_size_gt0_idx ON events.performance (avg_used_js_heap_size) WHERE avg_used_js_heap_size > 0;
|
||||
|
||||
|
||||
-- --- autocomplete.sql ---
|
||||
|
||||
CREATE TABLE autocomplete
|
||||
(
|
||||
value text NOT NULL,
|
||||
|
|
@ -887,8 +864,8 @@ $$
|
|||
project_id integer NOT NULL REFERENCES projects (project_id) ON DELETE CASCADE,
|
||||
action job_action NOT NULL,
|
||||
reference_id text NOT NULL,
|
||||
created_at timestamp default timezone('utc'::text, now()) NOT NULL,
|
||||
updated_at timestamp default timezone('utc'::text, now()) NULL,
|
||||
created_at timestamp DEFAULT timezone('utc'::text, now()) NOT NULL,
|
||||
updated_at timestamp DEFAULT timezone('utc'::text, now()) NULL,
|
||||
start_at timestamp NOT NULL,
|
||||
errors text NULL
|
||||
);
|
||||
|
|
@ -971,9 +948,9 @@ $$
|
|||
search_id integer generated BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
project_id integer NOT NULL REFERENCES projects (project_id) ON DELETE CASCADE,
|
||||
user_id integer NOT NULL REFERENCES users (user_id) ON DELETE CASCADE,
|
||||
name text not null,
|
||||
filter jsonb not null,
|
||||
created_at timestamp default timezone('utc'::text, now()) not null,
|
||||
name text NOT NULL,
|
||||
filter jsonb NOT NULL,
|
||||
created_at timestamp DEFAULT timezone('utc'::text, now()) NOT NULL,
|
||||
deleted_at timestamp,
|
||||
is_public boolean NOT NULL DEFAULT False
|
||||
);
|
||||
|
|
@ -1013,7 +990,7 @@ $$
|
|||
(
|
||||
note_id integer generated BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
message text NOT NULL,
|
||||
created_at timestamp without time zone NOT NULL default (now() at time zone 'utc'),
|
||||
created_at timestamp without time zone NOT NULL DEFAULT (now() at time zone 'utc'),
|
||||
user_id integer NULL REFERENCES users (user_id) ON DELETE SET NULL,
|
||||
deleted_at timestamp without time zone NULL DEFAULT NULL,
|
||||
tag text NULL,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue