feat(chalice): session notes
This commit is contained in:
parent
8baf050a00
commit
976bf7713e
7 changed files with 252 additions and 4 deletions
|
|
@ -17,8 +17,8 @@ class ProjectAuthorizer:
|
|||
current_user: schemas.CurrentContext = await OR_context(request)
|
||||
value = request.path_params[self.project_identifier]
|
||||
if (self.project_identifier == "projectId" \
|
||||
and not (isinstance(value, int) or isinstance(value, str) and value.isnumeric())
|
||||
and projects.get_project(project_id=value, tenant_id=current_user.tenant_id) is None) \
|
||||
and (not (isinstance(value, int) or isinstance(value, str) and value.isnumeric())
|
||||
or projects.get_project(project_id=value, tenant_id=current_user.tenant_id) is None)) \
|
||||
or (self.project_identifier == "projectKey" \
|
||||
and projects.get_internal_project_id(project_key=value) is None):
|
||||
print("project not found")
|
||||
|
|
|
|||
105
api/chalicelib/core/sessions_notes.py
Normal file
105
api/chalicelib/core/sessions_notes.py
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
import json
|
||||
|
||||
import schemas
|
||||
from chalicelib.core import users
|
||||
from chalicelib.utils import pg_client, helper, dev
|
||||
from chalicelib.utils.TimeUTC import TimeUTC
|
||||
|
||||
|
||||
def get_session_notes(tenant_id, project_id, session_id, user_id):
|
||||
with pg_client.PostgresClient() as cur:
|
||||
query = cur.mogrify(f"""SELECT sessions_notes.*
|
||||
FROM sessions_notes
|
||||
INNER JOIN users USING (user_id)
|
||||
WHERE sessions_notes.project_id = %(project_id)s
|
||||
AND sessions_notes.deleted_at IS NULL
|
||||
AND sessions_notes.session_id = %(session_id)s
|
||||
AND (sessions_notes.user_id = %(user_id)s
|
||||
OR sessions_notes.is_public AND users.tenant_id = %(tenant_id)s)
|
||||
ORDER BY created_at DESC;""",
|
||||
{"project_id": project_id, "user_id": user_id,
|
||||
"tenant_id": tenant_id, "session_id": session_id})
|
||||
|
||||
rows = cur.fetchall()
|
||||
rows = helper.list_to_camel_case(rows)
|
||||
for row in rows:
|
||||
row["createdAt"] = TimeUTC.datetime_to_timestamp(row["createdAt"])
|
||||
return rows
|
||||
|
||||
|
||||
def get_all_notes(tenant_id, project_id, user_id):
|
||||
with pg_client.PostgresClient() as cur:
|
||||
query = cur.mogrify(f"""SELECT sessions_notes.*
|
||||
FROM sessions_notes
|
||||
INNER JOIN users USING (user_id)
|
||||
WHERE sessions_notes.project_id = %(project_id)s
|
||||
AND sessions_notes.deleted_at IS NULL
|
||||
AND (sessions_notes.user_id = %(user_id)s
|
||||
OR sessions_notes.is_public AND users.tenant_id = %(tenant_id)s)
|
||||
ORDER BY created_at DESC;""",
|
||||
{"project_id": project_id, "user_id": user_id, "tenant_id": tenant_id})
|
||||
|
||||
cur.execute(query=query)
|
||||
rows = cur.fetchall()
|
||||
rows = helper.list_to_camel_case(rows)
|
||||
for row in rows:
|
||||
row["createdAt"] = TimeUTC.datetime_to_timestamp(row["createdAt"])
|
||||
return rows
|
||||
|
||||
|
||||
def create(tenant_id, user_id, project_id, session_id, data: schemas.SessionNoteSchema):
|
||||
with pg_client.PostgresClient() as cur:
|
||||
query = cur.mogrify(f"""INSERT INTO public.sessions_notes (message, user_id, tags, session_id, project_id, timestamp, is_public)
|
||||
VALUES (%(message)s, %(user_id)s, %(tags)s, %(session_id)s, %(project_id)s, %(timestamp)s, %(is_public)s)
|
||||
RETURNING *;""",
|
||||
{"user_id": user_id, "project_id": project_id, "session_id": session_id, **data.dict()})
|
||||
cur.execute(query)
|
||||
result = cur.fetchone()
|
||||
return helper.dict_to_camel_case(result)
|
||||
|
||||
|
||||
def edit(tenant_id, user_id, project_id, note_id, data: schemas.SessionUpdateNoteSchema):
|
||||
sub_query = []
|
||||
if data.message is not None:
|
||||
sub_query.append("message = %(message)s")
|
||||
if data.tags is not None:
|
||||
sub_query.append("tags = %(tags)s")
|
||||
if data.is_public is not None:
|
||||
sub_query.append("is_public = %(is_public)s")
|
||||
if data.timestamp is not None:
|
||||
sub_query.append("timestamp = %(timestamp)s")
|
||||
with pg_client.PostgresClient() as cur:
|
||||
cur.execute(
|
||||
cur.mogrify(f"""\
|
||||
UPDATE public.sessions_notes
|
||||
SET
|
||||
{" ,".join(sub_query)}
|
||||
WHERE
|
||||
project_id = %(project_id)s
|
||||
AND user_id = %(user_id)s
|
||||
AND note_id = %(note_id)s
|
||||
AND deleted_at ISNULL
|
||||
RETURNING *;""",
|
||||
{"project_id": project_id, "user_id": user_id, "note_id": note_id, **data.dict()})
|
||||
)
|
||||
row = helper.dict_to_camel_case(cur.fetchone())
|
||||
if row:
|
||||
row["createdAt"] = TimeUTC.datetime_to_timestamp(row["createdAt"])
|
||||
return row
|
||||
|
||||
|
||||
def delete(tenant_id, user_id, project_id, note_id):
|
||||
with pg_client.PostgresClient() as cur:
|
||||
cur.execute(
|
||||
cur.mogrify("""\
|
||||
UPDATE public.sessions_notes
|
||||
SET
|
||||
deleted_at = timezone('utc'::text, now())
|
||||
WHERE
|
||||
note_id = %(note_id)s
|
||||
AND project_id = %(project_id)s\
|
||||
AND user_id = %(user_id)s
|
||||
AND deleted_at ISNULL;""",
|
||||
{"project_id": project_id, "user_id": user_id, "note_id": note_id})
|
||||
)
|
||||
return {"data": {"state": "success"}}
|
||||
|
|
@ -6,7 +6,7 @@ from starlette.responses import RedirectResponse, FileResponse
|
|||
|
||||
import schemas
|
||||
from chalicelib.core import sessions, errors, errors_viewed, errors_favorite, sessions_assignments, heatmaps, \
|
||||
sessions_favorite, assist
|
||||
sessions_favorite, assist, sessions_notes
|
||||
from chalicelib.core import sessions_viewed
|
||||
from chalicelib.core import tenants, users, projects, license
|
||||
from chalicelib.core import webhook
|
||||
|
|
@ -372,3 +372,57 @@ def comment_assignment(projectId: int, sessionId: int, issueId: str, data: schem
|
|||
return {
|
||||
'data': data
|
||||
}
|
||||
|
||||
|
||||
@app.post('/{projectId}/sessions/{sessionId}/notes', tags=["sessions", "notes"])
|
||||
@app.put('/{projectId}/sessions/{sessionId}/notes', tags=["sessions", "notes"])
|
||||
def create_note(projectId: int, sessionId: int, data: schemas.SessionNoteSchema = Body(...),
|
||||
context: schemas.CurrentContext = Depends(OR_context)):
|
||||
data = sessions_notes.create(tenant_id=context.tenant_id, project_id=projectId,
|
||||
session_id=sessionId, user_id=context.user_id, data=data)
|
||||
if "errors" in data.keys():
|
||||
return data
|
||||
return {
|
||||
'data': data
|
||||
}
|
||||
|
||||
|
||||
@app.get('/{projectId}/sessions/{sessionId}/notes', tags=["sessions", "notes"])
|
||||
def get_session_notes(projectId: int, sessionId: int, context: schemas.CurrentContext = Depends(OR_context)):
|
||||
data = sessions_notes.get_session_notes(tenant_id=context.tenant_id, project_id=projectId,
|
||||
session_id=sessionId, user_id=context.user_id)
|
||||
if "errors" in data:
|
||||
return data
|
||||
return {
|
||||
'data': data
|
||||
}
|
||||
|
||||
|
||||
@app.post('/{projectId}/notes/{noteId}', tags=["sessions", "notes"])
|
||||
@app.put('/{projectId}/notes/{noteId}', tags=["sessions", "notes"])
|
||||
def edit_note(projectId: int, noteId: int, data: schemas.SessionUpdateNoteSchema = Body(...),
|
||||
context: schemas.CurrentContext = Depends(OR_context)):
|
||||
data = sessions_notes.edit(tenant_id=context.tenant_id, project_id=projectId, user_id=context.user_id,
|
||||
note_id=noteId, data=data)
|
||||
if "errors" in data.keys():
|
||||
return data
|
||||
return {
|
||||
'data': data
|
||||
}
|
||||
|
||||
|
||||
@app.delete('/{projectId}/notes/{noteId}', tags=["sessions", "notes"])
|
||||
def delete_note(projectId: int, noteId: int, context: schemas.CurrentContext = Depends(OR_context)):
|
||||
data = sessions_notes.delete(tenant_id=context.tenant_id, project_id=projectId, user_id=context.user_id,
|
||||
note_id=noteId)
|
||||
return data
|
||||
|
||||
|
||||
@app.get('/{projectId}/notes', tags=["sessions", "notes"])
|
||||
def get_all_notes(projectId: int, context: schemas.CurrentContext = Depends(OR_context)):
|
||||
data = sessions_notes.get_all_notes(tenant_id=context.tenant_id, project_id=projectId, user_id=context.user_id)
|
||||
if "errors" in data:
|
||||
return data
|
||||
return {
|
||||
'data': data
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1084,3 +1084,31 @@ class IntegrationType(str, Enum):
|
|||
stackdriver = "STACKDRIVER"
|
||||
cloudwatch = "CLOUDWATCH"
|
||||
newrelic = "NEWRELIC"
|
||||
|
||||
|
||||
class SessionNoteSchema(BaseModel):
|
||||
message: str = Field(..., min_length=2)
|
||||
tags: List[str] = Field(default=[])
|
||||
timestamp: int = Field(default=-1)
|
||||
is_public: bool = Field(default=False)
|
||||
|
||||
class Config:
|
||||
alias_generator = attribute_to_camel_case
|
||||
|
||||
|
||||
class SessionUpdateNoteSchema(SessionNoteSchema):
|
||||
message: Optional[str] = Field(default=None, min_length=2)
|
||||
tags: Optional[List[str]] = Field(default=None)
|
||||
timestamp: Optional[int] = Field(default=None, ge=-1)
|
||||
is_public: Optional[bool] = Field(default=None)
|
||||
|
||||
@root_validator
|
||||
def validator(cls, values):
|
||||
assert len(values.keys()) > 0, "at least 1 attribute should be provided for update"
|
||||
c = 0
|
||||
for v in values.values():
|
||||
if v is not None and (not isinstance(v, str) or len(v) > 0):
|
||||
c += 1
|
||||
break
|
||||
assert c > 0, "at least 1 value should be provided for update"
|
||||
return values
|
||||
|
|
|
|||
1
ee/api/.gitignore
vendored
1
ee/api/.gitignore
vendored
|
|
@ -213,6 +213,7 @@ Pipfile
|
|||
/chalicelib/core/sessions_assignments.py
|
||||
/chalicelib/core/sessions_metas.py
|
||||
/chalicelib/core/sessions_mobs.py
|
||||
/chalicelib/core/sessions_notes.py
|
||||
#exp /chalicelib/core/significance.py
|
||||
/chalicelib/core/slack.py
|
||||
/chalicelib/core/socket_ios.py
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ rm -rf ./chalicelib/core/mobile.py
|
|||
rm -rf ./chalicelib/core/sessions_assignments.py
|
||||
rm -rf ./chalicelib/core/sessions_metas.py
|
||||
rm -rf ./chalicelib/core/sessions_mobs.py
|
||||
rm -rf ./chalicelib/core/sessions_notes.py
|
||||
#exp rm -rf ./chalicelib/core/significance.py
|
||||
rm -rf ./chalicelib/core/slack.py
|
||||
rm -rf ./chalicelib/core/socket_ios.py
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from starlette.responses import RedirectResponse, FileResponse
|
|||
import schemas
|
||||
import schemas_ee
|
||||
from chalicelib.core import sessions, assist, heatmaps, sessions_favorite, sessions_assignments, errors, errors_viewed, \
|
||||
errors_favorite
|
||||
errors_favorite, sessions_notes
|
||||
from chalicelib.core import sessions_viewed
|
||||
from chalicelib.core import tenants, users, projects, license
|
||||
from chalicelib.core import webhook
|
||||
|
|
@ -396,3 +396,62 @@ def comment_assignment(projectId: int, sessionId: int, issueId: str, data: schem
|
|||
return {
|
||||
'data': data
|
||||
}
|
||||
|
||||
|
||||
@app.post('/{projectId}/sessions/{sessionId}/notes', tags=["sessions", "notes"],
|
||||
dependencies=[OR_scope(Permissions.session_replay)])
|
||||
@app.put('/{projectId}/sessions/{sessionId}/notes', tags=["sessions", "notes"],
|
||||
dependencies=[OR_scope(Permissions.session_replay)])
|
||||
def create_note(projectId: int, sessionId: int, data: schemas.SessionNoteSchema = Body(...),
|
||||
context: schemas.CurrentContext = Depends(OR_context)):
|
||||
data = sessions_notes.create(tenant_id=context.tenant_id, project_id=projectId,
|
||||
session_id=sessionId, user_id=context.user_id, data=data)
|
||||
if "errors" in data.keys():
|
||||
return data
|
||||
return {
|
||||
'data': data
|
||||
}
|
||||
|
||||
|
||||
@app.get('/{projectId}/sessions/{sessionId}/notes', tags=["sessions", "notes"],
|
||||
dependencies=[OR_scope(Permissions.session_replay)])
|
||||
def get_session_notes(projectId: int, sessionId: int, context: schemas.CurrentContext = Depends(OR_context)):
|
||||
data = sessions_notes.get_session_notes(tenant_id=context.tenant_id, project_id=projectId,
|
||||
session_id=sessionId, user_id=context.user_id)
|
||||
if "errors" in data:
|
||||
return data
|
||||
return {
|
||||
'data': data
|
||||
}
|
||||
|
||||
|
||||
@app.post('/{projectId}/notes/{noteId}', tags=["sessions", "notes"],
|
||||
dependencies=[OR_scope(Permissions.session_replay)])
|
||||
@app.put('/{projectId}/notes/{noteId}', tags=["sessions", "notes"], dependencies=[OR_scope(Permissions.session_replay)])
|
||||
def edit_note(projectId: int, noteId: int, data: schemas.SessionUpdateNoteSchema = Body(...),
|
||||
context: schemas.CurrentContext = Depends(OR_context)):
|
||||
data = sessions_notes.edit(tenant_id=context.tenant_id, project_id=projectId, user_id=context.user_id,
|
||||
note_id=noteId, data=data)
|
||||
if "errors" in data.keys():
|
||||
return data
|
||||
return {
|
||||
'data': data
|
||||
}
|
||||
|
||||
|
||||
@app.delete('/{projectId}/notes/{noteId}', tags=["sessions", "notes"],
|
||||
dependencies=[OR_scope(Permissions.session_replay)])
|
||||
def delete_note(projectId: int, noteId: int, context: schemas.CurrentContext = Depends(OR_context)):
|
||||
data = sessions_notes.delete(tenant_id=context.tenant_id, project_id=projectId, user_id=context.user_id,
|
||||
note_id=noteId)
|
||||
return data
|
||||
|
||||
|
||||
@app.get('/{projectId}/notes', tags=["sessions", "notes"], dependencies=[OR_scope(Permissions.session_replay)])
|
||||
def get_all_notes(projectId: int, context: schemas.CurrentContext = Depends(OR_context)):
|
||||
data = sessions_notes.get_all_notes(tenant_id=context.tenant_id, project_id=projectId, user_id=context.user_id)
|
||||
if "errors" in data:
|
||||
return data
|
||||
return {
|
||||
'data': data
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue