diff --git a/api/chalicelib/core/metadata.py b/api/chalicelib/core/metadata.py index b87a9253a..301503162 100644 --- a/api/chalicelib/core/metadata.py +++ b/api/chalicelib/core/metadata.py @@ -1,7 +1,7 @@ -from chalicelib.utils import pg_client, helper, dev +import re from chalicelib.core import projects -import re +from chalicelib.utils import pg_client, dev MAX_INDEXES = 10 @@ -30,6 +30,30 @@ def get(project_id): return results +def get_batch(project_ids): + if project_ids is None or len(project_ids) == 0: + return [] + with pg_client.PostgresClient() as cur: + cur.execute( + cur.mogrify( + f"""\ + SELECT + project_id, {",".join(_get_column_names())} + FROM public.projects + WHERE project_id IN %(project_ids)s + AND deleted_at ISNULL;""", {"project_ids": tuple(project_ids)}) + ) + full_metas = cur.fetchall() + results = {} + if full_metas is not None and len(full_metas) > 0: + for metas in full_metas: + results[str(metas["project_id"])] = [] + for i, k in enumerate(metas.keys()): + if metas[k] is not None and k != "project_id": + results[str(metas["project_id"])].append({"key": metas[k], "index": i + 1}) + return results + + regex = re.compile(r'^[a-z0-9_-]+$', re.IGNORECASE) @@ -253,12 +277,13 @@ def add_edit_delete(tenant_id, project_id, new_metas): def get_remaining_metadata_with_count(tenant_id): all_projects = projects.get_projects(tenant_id=tenant_id) results = [] + used_metas = get_batch([p["projectId"] for p in all_projects]) for p in all_projects: - used_metas = get(p["projectId"]) if MAX_INDEXES < 0: remaining = -1 else: - remaining = MAX_INDEXES - len(used_metas) - results.append({**p, "limit": MAX_INDEXES, "remaining": remaining, "count": len(used_metas)}) + remaining = MAX_INDEXES - len(used_metas[str(p["projectId"])]) + results.append( + {**p, "limit": MAX_INDEXES, "remaining": remaining, "count": len(used_metas[str(p["projectId"])])}) return results diff --git a/api/chalicelib/core/reset_password.py b/api/chalicelib/core/reset_password.py index 1c32cdddb..1baaf82d8 100644 --- a/api/chalicelib/core/reset_password.py +++ b/api/chalicelib/core/reset_password.py @@ -9,8 +9,6 @@ def reset(data: schemas.ForgetPasswordPayloadSchema): if helper.allow_captcha() and not captcha.is_valid(data.g_recaptcha_response): print("error: Invalid captcha.") return {"errors": ["Invalid captcha."]} - if "email" not in data: - return {"errors": ["email not found in body"]} if not helper.has_smtp(): return {"errors": ["no SMTP configuration found, you can ask your admin to reset your password"]} a_users = users.get_by_email_only(data.email) diff --git a/api/schemas.py b/api/schemas.py index e0b1ace55..ec8586cb7 100644 --- a/api/schemas.py +++ b/api/schemas.py @@ -104,9 +104,9 @@ class CreateNotificationSchema(BaseModel): class NotificationsViewSchema(BaseModel): - ids: Optional[List] = Field(...) - startTimestamp: int = Field(...) - endTimestamp: int = Field(...) + ids: Optional[List] = Field(default=[]) + startTimestamp: Optional[int] = Field(default=None) + endTimestamp: Optional[int] = Field(default=None) class JiraGithubSchema(BaseModel): diff --git a/ee/api/.gitignore b/ee/api/.gitignore index 70fc40afc..fbf1958af 100644 --- a/ee/api/.gitignore +++ b/ee/api/.gitignore @@ -204,6 +204,7 @@ Pipfile /chalicelib/core/log_tool_sentry.py /chalicelib/core/log_tool_stackdriver.py /chalicelib/core/log_tool_sumologic.py +/chalicelib/core/metadata.py /chalicelib/core/mobile.py /chalicelib/core/sessions.py /chalicelib/core/sessions_assignments.py diff --git a/ee/api/chalicelib/core/metadata.py b/ee/api/chalicelib/core/metadata.py deleted file mode 100644 index a308a9c7a..000000000 --- a/ee/api/chalicelib/core/metadata.py +++ /dev/null @@ -1,264 +0,0 @@ -from chalicelib.utils import pg_client, helper, dev - -from chalicelib.core import projects - -import re - -MAX_INDEXES = 10 - - -def _get_column_names(): - return [f"metadata_{i}" for i in range(1, MAX_INDEXES + 1)] - - -def get(project_id): - with pg_client.PostgresClient() as cur: - cur.execute( - cur.mogrify( - f"""\ - SELECT - {",".join(_get_column_names())} - FROM public.projects - WHERE project_id = %(project_id)s AND deleted_at ISNULL - LIMIT 1;""", {"project_id": project_id}) - ) - metas = cur.fetchone() - results = [] - if metas is not None: - for i, k in enumerate(metas.keys()): - if metas[k] is not None: - results.append({"key": metas[k], "index": i + 1}) - return results - - -regex = re.compile(r'^[a-z0-9_-]+$', re.IGNORECASE) - - -def index_to_colname(index): - if index <= 0 or index > MAX_INDEXES: - raise Exception("metadata index out or bound") - return f"metadata_{index}" - - -def __get_available_index(project_id): - used_indexs = get(project_id) - used_indexs = [i["index"] for i in used_indexs] - if len(used_indexs) >= MAX_INDEXES: - return -1 - i = 1 - while i in used_indexs: - i += 1 - return i - - -def __edit(project_id, col_index, colname, new_name): - if new_name is None or len(new_name) == 0: - return {"errors": ["key value invalid"]} - old_metas = get(project_id) - old_metas = {k["index"]: k for k in old_metas} - if col_index not in list(old_metas.keys()): - return {"errors": ["custom field not found"]} - - with pg_client.PostgresClient() as cur: - if old_metas[col_index]["key"].lower() != new_name: - cur.execute(cur.mogrify(f"""UPDATE public.projects - SET {colname} = %(value)s - WHERE project_id = %(project_id)s AND deleted_at ISNULL - RETURNING {colname};""", - {"project_id": project_id, "value": new_name})) - new_name = cur.fetchone()[colname] - old_metas[col_index]["key"] = new_name - return {"data": old_metas[col_index]} - - -def edit(tenant_id, project_id, index: int, new_name: str): - return __edit(project_id=project_id, col_index=index, colname=index_to_colname(index), new_name=new_name) - - -def delete(tenant_id, project_id, index: int): - index = int(index) - old_segments = get(project_id) - old_segments = [k["index"] for k in old_segments] - if index not in old_segments: - return {"errors": ["custom field not found"]} - - with pg_client.PostgresClient() as cur: - colname = index_to_colname(index) - query = cur.mogrify(f"""UPDATE public.projects - SET {colname}= NULL - WHERE project_id = %(project_id)s AND deleted_at ISNULL;""", - {"project_id": project_id}) - cur.execute(query=query) - query = cur.mogrify(f"""UPDATE public.sessions - SET {colname}= NULL - WHERE project_id = %(project_id)s - AND {colname} IS NOT NULL""", - {"project_id": project_id}) - cur.execute(query=query) - - return {"data": get(project_id)} - - -def add(tenant_id, project_id, new_name): - index = __get_available_index(project_id=project_id) - if index < 1: - return {"errors": ["maximum allowed metadata reached"]} - with pg_client.PostgresClient() as cur: - colname = index_to_colname(index) - cur.execute( - cur.mogrify( - f"""UPDATE public.projects SET {colname}= %(key)s WHERE project_id =%(project_id)s RETURNING {colname};""", - {"key": new_name, "project_id": project_id})) - col_val = cur.fetchone()[colname] - return {"data": {"key": col_val, "index": index}} - - -def search(tenant_id, project_id, key, value): - value = value + "%" - s_query = [] - for f in _get_column_names(): - s_query.append(f"CASE WHEN {f}=%(key)s THEN TRUE ELSE FALSE END AS {f}") - - with pg_client.PostgresClient() as cur: - cur.execute( - cur.mogrify( - f"""\ - SELECT - {",".join(s_query)} - FROM public.projects - WHERE - project_id = %(project_id)s AND deleted_at ISNULL - LIMIT 1;""", - {"key": key, "project_id": project_id}) - ) - all_metas = cur.fetchone() - key = None - for c in all_metas: - if all_metas[c]: - key = c - break - if key is None: - return {"errors": ["key not found"]} - cur.execute( - cur.mogrify( - f"""\ - SELECT - DISTINCT "{key}" AS "{key}" - FROM public.sessions - {f'WHERE "{key}"::text ILIKE %(value)s' if value is not None and len(value) > 0 else ""} - ORDER BY "{key}" - LIMIT 20;""", - {"value": value, "project_id": project_id}) - ) - value = cur.fetchall() - return {"data": [k[key] for k in value]} - - -def get_available_keys(project_id): - all_metas = get(project_id=project_id) - return [k["key"] for k in all_metas] - - -def get_by_session_id(project_id, session_id): - all_metas = get(project_id=project_id) - if len(all_metas) == 0: - return [] - keys = {index_to_colname(k["index"]): k["key"] for k in all_metas} - with pg_client.PostgresClient() as cur: - cur.execute( - cur.mogrify( - f"""\ - select {",".join(keys.keys())} - FROM public.sessions - WHERE project_id= %(project_id)s AND session_id=%(session_id)s;""", - {"session_id": session_id, "project_id": project_id}) - ) - session_metas = cur.fetchall() - results = [] - for m in session_metas: - r = {} - for k in m.keys(): - r[keys[k]] = m[k] - results.append(r) - return results - - -def get_keys_by_projects(project_ids): - if project_ids is None or len(project_ids) == 0: - return {} - with pg_client.PostgresClient() as cur: - query = cur.mogrify( - f"""\ - SELECT - project_id, - {",".join(_get_column_names())} - FROM public.projects - WHERE project_id IN %(project_ids)s AND deleted_at ISNULL;""", - {"project_ids": tuple(project_ids)}) - - cur.execute(query) - rows = cur.fetchall() - results = {} - for r in rows: - project_id = r.pop("project_id") - results[project_id] = {} - for m in r: - if r[m] is not None: - results[project_id][m] = r[m] - return results - - -def add_edit_delete(tenant_id, project_id, new_metas): - old_metas = get(project_id) - old_indexes = [k["index"] for k in old_metas] - new_indexes = [k["index"] for k in new_metas if "index" in k] - new_keys = [k["key"] for k in new_metas] - - add_metas = [k["key"] for k in new_metas - if "index" not in k] - new_metas = {k["index"]: {"key": k["key"]} for - k in new_metas if - "index" in k} - old_metas = {k["index"]: {"key": k["key"]} for k in old_metas} - - if len(new_keys) > 20: - return {"errors": ["you cannot add more than 20 key"]} - for k in new_metas.keys(): - if re.match(regex, new_metas[k]["key"]) is None: - return {"errors": [f"invalid key {k}"]} - for k in add_metas: - if re.match(regex, k) is None: - return {"errors": [f"invalid key {k}"]} - if len(new_indexes) > len(set(new_indexes)): - return {"errors": ["duplicate indexes"]} - if len(new_keys) > len(set(new_keys)): - return {"errors": ["duplicate keys"]} - to_delete = list(set(old_indexes) - set(new_indexes)) - - with pg_client.PostgresClient() as cur: - for d in to_delete: - delete(tenant_id=tenant_id, project_id=project_id, index=d) - - for k in add_metas: - add(tenant_id=tenant_id, project_id=project_id, new_name=k) - - for k in new_metas.keys(): - if new_metas[k]["key"].lower() != old_metas[k]["key"]: - edit(tenant_id=tenant_id, project_id=project_id, index=k, new_name=new_metas[k]["key"]) - - return {"data": get(project_id)} - - -@dev.timed -def get_remaining_metadata_with_count(tenant_id): - all_projects = projects.get_projects(tenant_id=tenant_id) - results = [] - for p in all_projects: - used_metas = get(p["projectId"]) - if MAX_INDEXES < 0: - remaining = -1 - else: - remaining = MAX_INDEXES - len(used_metas) - results.append({**p, "limit": MAX_INDEXES, "remaining": remaining, "count": len(used_metas)}) - - return results diff --git a/ee/api/chalicelib/core/reset_password.py b/ee/api/chalicelib/core/reset_password.py index d09db8c50..194c37704 100644 --- a/ee/api/chalicelib/core/reset_password.py +++ b/ee/api/chalicelib/core/reset_password.py @@ -9,8 +9,6 @@ def reset(data: schemas.ForgetPasswordPayloadSchema): if helper.allow_captcha() and not captcha.is_valid(data.g_recaptcha_response): print("error: Invalid captcha.") return {"errors": ["Invalid captcha."]} - if "email" not in data: - return {"errors": ["email not found in body"]} if not helper.has_smtp(): return {"errors": ["no SMTP configuration found, you can ask your admin to reset your password"]} a_user = users.get_by_email_only(data.email) diff --git a/frontend/app/components/Client/CustomFields/CustomFields.js b/frontend/app/components/Client/CustomFields/CustomFields.js index 2b875e439..081f11a58 100644 --- a/frontend/app/components/Client/CustomFields/CustomFields.js +++ b/frontend/app/components/Client/CustomFields/CustomFields.js @@ -23,7 +23,7 @@ import { confirm } from 'UI/Confirmation'; }) @withPageTitle('Metadata - OpenReplay Preferences') class CustomFields extends React.Component { - state = { showModal: false, currentSite: this.props.sites.get(0) }; + state = { showModal: false, currentSite: this.props.sites.get(0), deletingItem: null }; componentWillMount() { const activeSite = this.props.sites.get(0); @@ -60,15 +60,15 @@ class CustomFields extends React.Component { confirmation: `Are you sure you want to remove?` })) { const { currentSite } = this.state; - this.props.remove(currentSite.id, field.index).then(() => { - - }); + this.setState({ deletingItem: field.index }); + this.props.remove(currentSite.id, field.index) + .then(() => this.setState({ deletingItem: null })); } } render() { const { fields, field, loading } = this.props; - const { showModal, currentSite } = this.state; + const { showModal, currentSite, deletingItem } = this.state; return (
{ fields.filter(i => i.index).map(field => ( { +const ListItem = ({ field, onEdit, onDelete, disabled }) => { return ( -
field.index != 0 && onEdit(field) } > +
field.index != 0 && onEdit(field) } > { field.key }
{ e.stopPropagation(); onDelete(field) } }> diff --git a/frontend/app/components/Client/CustomFields/listItem.css b/frontend/app/components/Client/CustomFields/listItem.css index a46ac7a73..cc1b0806f 100644 --- a/frontend/app/components/Client/CustomFields/listItem.css +++ b/frontend/app/components/Client/CustomFields/listItem.css @@ -47,4 +47,9 @@ border-radius: 10px; background-color: $gray-lightest; box-shadow: 0 0 0 1px $gray-light inset; +} + +.disabled { + opacity: 0.5; + pointer-events: none; } \ No newline at end of file diff --git a/frontend/app/components/Session_/EventsBlock/Metadata/Metadata.js b/frontend/app/components/Session_/EventsBlock/Metadata/Metadata.js index 9b5d9ce66..b0dca0956 100644 --- a/frontend/app/components/Session_/EventsBlock/Metadata/Metadata.js +++ b/frontend/app/components/Session_/EventsBlock/Metadata/Metadata.js @@ -4,18 +4,19 @@ import { NoContent, IconButton, Popup } from 'UI'; import withToggle from 'HOCs/withToggle'; import MetadataItem from './MetadataItem'; import stl from './metadata.css'; +import cn from 'classnames'; export default connect(state => ({ metadata: state.getIn([ 'sessions', 'current', 'metadata' ]), }))(function Metadata ({ metadata }) { const [ visible, setVisible ] = useState(false); - const toggle = useCallback(() => metadata.size > 0 && setVisible(v => !v), []); + const toggle = useCallback(() => metadata.length > 0 && setVisible(v => !v), []); return ( <> ({ primaryText active={ visible } id="metadata-button" + // disabled={ metadata.length === 0 } /> } content={ diff --git a/frontend/app/components/shared/TrackerUpdateMessage/TrackerUpdateMessage.js b/frontend/app/components/shared/TrackerUpdateMessage/TrackerUpdateMessage.js index 32cabf8d3..a5fe4411c 100644 --- a/frontend/app/components/shared/TrackerUpdateMessage/TrackerUpdateMessage.js +++ b/frontend/app/components/shared/TrackerUpdateMessage/TrackerUpdateMessage.js @@ -12,7 +12,7 @@ const TrackerUpdateMessage= (props) => { const hasSessions = !!activeSite && !activeSite.recorded; const appVersionInt = parseInt(window.ENV.TRACKER_VERSION.split(".").join("")) const trackerVersionInt = site.trackerVersion ? parseInt(site.trackerVersion.split(".").join("")) : 0 - const needUpdate = !hasSessions && trackerVersionInt > appVersionInt; + const needUpdate = !hasSessions && appVersionInt > trackerVersionInt; return needUpdate ? ( <> {( diff --git a/frontend/app/player/MessageDistributor/managers/AssistManager.ts b/frontend/app/player/MessageDistributor/managers/AssistManager.ts index f4947b1a5..2ccea1ad5 100644 --- a/frontend/app/player/MessageDistributor/managers/AssistManager.ts +++ b/frontend/app/player/MessageDistributor/managers/AssistManager.ts @@ -458,7 +458,7 @@ export default class AssistManager { name: store.getState().getIn([ 'user', 'account', 'name']), }); - // this.md.overlay.addEventListener("mousemove", this.onMouseMove) + this.md.overlay.addEventListener("mousemove", this.onMouseMove) // this.md.overlay.addEventListener("click", this.onMouseClick) }); //call.peerConnection.addEventListener("track", e => console.log('newtrack',e.track)) diff --git a/frontend/env.js b/frontend/env.js index ad71e1479..f7c49c874 100644 --- a/frontend/env.js +++ b/frontend/env.js @@ -21,7 +21,7 @@ const oss = { MINIO_ACCESS_KEY: process.env.MINIO_ACCESS_KEY, MINIO_SECRET_KEY: process.env.MINIO_SECRET_KEY, ICE_SERVERS: process.env.ICE_SERVERS, - TRACKER_VERSION: '3.4.12', // trackerInfo.version, + TRACKER_VERSION: '3.4.16', // trackerInfo.version, } module.exports = {