From 138ab6f17dee41df10e45ab51bbc974d9f641970 Mon Sep 17 00:00:00 2001 From: deepakdinesh1123 Date: Thu, 19 Jun 2025 15:13:29 +0530 Subject: [PATCH 1/8] add ztoast function --- .../tenancy/templatetags/zango_filters.py | 10 +++++ backend/src/zango/core/toast.py | 41 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 backend/src/zango/core/toast.py diff --git a/backend/src/zango/apps/shared/tenancy/templatetags/zango_filters.py b/backend/src/zango/apps/shared/tenancy/templatetags/zango_filters.py index dbd86d051..bf0e1664b 100644 --- a/backend/src/zango/apps/shared/tenancy/templatetags/zango_filters.py +++ b/backend/src/zango/apps/shared/tenancy/templatetags/zango_filters.py @@ -2,6 +2,7 @@ Module containing custom template filters """ +import json import os import re @@ -70,3 +71,12 @@ def use_latest(build_path): if re.match(filep, filename): return os.path.join(buildir, filename) return build_path + + +@register.filter +def parse_json(value): + """Parse JSON string and return dictionary""" + try: + return json.loads(value) + except (json.JSONDecodeError, TypeError): + return {} diff --git a/backend/src/zango/core/toast.py b/backend/src/zango/core/toast.py new file mode 100644 index 000000000..daf0157cb --- /dev/null +++ b/backend/src/zango/core/toast.py @@ -0,0 +1,41 @@ +import json + +from typing import Optional, TypedDict + +from django.contrib import messages + + +class ActionSchema(TypedDict, total=False): + text: str + url: Optional[str] + + +def ztoast( + request, + message, + title="", + level="success", + primary_action: ActionSchema | None = None, + secondary_action: ActionSchema | None = None, + placement="bottomRight", +): + if title == "": + title = level.capitalize() + + if level == "success": + level = messages.SUCCESS + elif level == "error": + level = messages.ERROR + elif level == "warning": + level = messages.WARNING + else: + raise ValueError("Invalid level: %s" % level) + + msg = { + "message": message, + "title": title, + "primary_action": primary_action, + "secondary_action": secondary_action, + "placement": placement, + } + messages.add_message(request, level, json.dumps(msg)) From 75f5793e169c78f56822eaa693c23900e21e5237 Mon Sep 17 00:00:00 2001 From: deepakdinesh1123 Date: Thu, 19 Jun 2025 18:11:32 +0530 Subject: [PATCH 2/8] specify color and extra_tags --- backend/src/zango/core/toast.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/backend/src/zango/core/toast.py b/backend/src/zango/core/toast.py index daf0157cb..f2ccbb734 100644 --- a/backend/src/zango/core/toast.py +++ b/backend/src/zango/core/toast.py @@ -18,6 +18,8 @@ def ztoast( primary_action: ActionSchema | None = None, secondary_action: ActionSchema | None = None, placement="bottomRight", + color="default", + extra_tags="", ): if title == "": title = level.capitalize() @@ -38,4 +40,10 @@ def ztoast( "secondary_action": secondary_action, "placement": placement, } - messages.add_message(request, level, json.dumps(msg)) + if color != "default": + msg["color"] = color + if extra_tags: + extra_tags = f"{extra_tags} zango" + else: + extra_tags = "zango" + messages.add_message(request, level, json.dumps(msg), extra_tags=extra_tags) From 3153d87efc85be2cd8a8d87359ee7de9a515e29c Mon Sep 17 00:00:00 2001 From: deepakdinesh1123 Date: Mon, 23 Jun 2025 10:43:09 +0530 Subject: [PATCH 3/8] default toast placement will be defined in generic frame config --- backend/src/zango/core/toast.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/src/zango/core/toast.py b/backend/src/zango/core/toast.py index f2ccbb734..61fff5be3 100644 --- a/backend/src/zango/core/toast.py +++ b/backend/src/zango/core/toast.py @@ -17,7 +17,7 @@ def ztoast( level="success", primary_action: ActionSchema | None = None, secondary_action: ActionSchema | None = None, - placement="bottomRight", + placement="default", color="default", extra_tags="", ): @@ -38,10 +38,11 @@ def ztoast( "title": title, "primary_action": primary_action, "secondary_action": secondary_action, - "placement": placement, } if color != "default": msg["color"] = color + if placement != "default": + msg["placement"] = placement if extra_tags: extra_tags = f"{extra_tags} zango" else: From fb9efd3de7da7b6aeb4248ead70c7a6eb07a918a Mon Sep 17 00:00:00 2001 From: deepakdinesh1123 Date: Mon, 23 Jun 2025 11:04:37 +0530 Subject: [PATCH 4/8] add level info --- backend/src/zango/core/toast.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/src/zango/core/toast.py b/backend/src/zango/core/toast.py index 61fff5be3..c99bb2ba4 100644 --- a/backend/src/zango/core/toast.py +++ b/backend/src/zango/core/toast.py @@ -30,6 +30,8 @@ def ztoast( level = messages.ERROR elif level == "warning": level = messages.WARNING + elif level == "info": + level = messages.INFO else: raise ValueError("Invalid level: %s" % level) From e4da37f9249502776c3b12ff480fdb1f4e9ca849 Mon Sep 17 00:00:00 2001 From: deepakdinesh1123 Date: Tue, 24 Jun 2025 15:37:05 +0530 Subject: [PATCH 5/8] add duration --- backend/src/zango/core/toast.py | 70 ++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 14 deletions(-) diff --git a/backend/src/zango/core/toast.py b/backend/src/zango/core/toast.py index c99bb2ba4..eddfb9137 100644 --- a/backend/src/zango/core/toast.py +++ b/backend/src/zango/core/toast.py @@ -1,8 +1,9 @@ import json -from typing import Optional, TypedDict +from typing import Dict, Literal, Optional, TypedDict from django.contrib import messages +from django.http import request class ActionSchema(TypedDict, total=False): @@ -10,32 +11,71 @@ class ActionSchema(TypedDict, total=False): url: Optional[str] +Placement = Literal[ + "top-left", + "top-center", + "top-right", + "bottom-left", + "bottom-center", + "bottom-right", + "center", + "default", +] + + def ztoast( - request, - message, - title="", - level="success", + request: request.HttpRequest, + message: str, + title: str = "", + level: Literal["success", "error", "warning", "info"] = "success", primary_action: ActionSchema | None = None, secondary_action: ActionSchema | None = None, - placement="default", - color="default", - extra_tags="", + placement: Placement = "default", + duration: int | None = None, + color: str = "default", + extra_tags: str = "", ): + """ + Displays a toast notification with the specified parameters. + + Args: + request: The HTTP request object. + message: The message content of the toast notification. + title: The title of the toast notification. Defaults to an empty string, + which will result in the title being set to the capitalized `level`. + level: The severity level of the toast notification. Defaults to "success". + Accepted values are "success", "error", "warning", and "info". + primary_action: An optional primary action for the toast, defined by an + ActionSchema dictionary with 'text' and 'url' keys. + secondary_action: An optional secondary action for the toast, defined by an + ActionSchema dictionary with 'text' and 'url' keys. + placement: The placement of the toast notification on the screen. Defaults to "default". + duration: The duration the toast should be visible, in milliseconds. Defaults to None. + color: The color style of the toast. Defaults to "default". + extra_tags: Additional tags to categorize the toast notification. Defaults to "". + + Raises: + ValueError: If `level` is not one of the accepted values. + + """ + if title == "": title = level.capitalize() + msg_level = messages.SUCCESS + if level == "success": - level = messages.SUCCESS + msg_level = messages.SUCCESS elif level == "error": - level = messages.ERROR + msg_level = messages.ERROR elif level == "warning": - level = messages.WARNING + msg_level = messages.WARNING elif level == "info": - level = messages.INFO + msg_level = messages.INFO else: raise ValueError("Invalid level: %s" % level) - msg = { + msg: Dict[str, str | ActionSchema | None | int] = { "message": message, "title": title, "primary_action": primary_action, @@ -45,8 +85,10 @@ def ztoast( msg["color"] = color if placement != "default": msg["placement"] = placement + if duration is not None: + msg["duration"] = duration if extra_tags: extra_tags = f"{extra_tags} zango" else: extra_tags = "zango" - messages.add_message(request, level, json.dumps(msg), extra_tags=extra_tags) + messages.add_message(request, msg_level, json.dumps(msg), extra_tags=extra_tags) From 4c29afef298b7dda1df31cfed2590387c71b708f Mon Sep 17 00:00:00 2001 From: deepakdinesh1123 Date: Wed, 25 Jun 2025 15:25:14 +0530 Subject: [PATCH 6/8] color and placement removed --- backend/src/zango/core/toast.py | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/backend/src/zango/core/toast.py b/backend/src/zango/core/toast.py index eddfb9137..4cc3995d9 100644 --- a/backend/src/zango/core/toast.py +++ b/backend/src/zango/core/toast.py @@ -11,18 +11,6 @@ class ActionSchema(TypedDict, total=False): url: Optional[str] -Placement = Literal[ - "top-left", - "top-center", - "top-right", - "bottom-left", - "bottom-center", - "bottom-right", - "center", - "default", -] - - def ztoast( request: request.HttpRequest, message: str, @@ -30,9 +18,7 @@ def ztoast( level: Literal["success", "error", "warning", "info"] = "success", primary_action: ActionSchema | None = None, secondary_action: ActionSchema | None = None, - placement: Placement = "default", duration: int | None = None, - color: str = "default", extra_tags: str = "", ): """ @@ -49,9 +35,7 @@ def ztoast( ActionSchema dictionary with 'text' and 'url' keys. secondary_action: An optional secondary action for the toast, defined by an ActionSchema dictionary with 'text' and 'url' keys. - placement: The placement of the toast notification on the screen. Defaults to "default". duration: The duration the toast should be visible, in milliseconds. Defaults to None. - color: The color style of the toast. Defaults to "default". extra_tags: Additional tags to categorize the toast notification. Defaults to "". Raises: @@ -81,10 +65,6 @@ def ztoast( "primary_action": primary_action, "secondary_action": secondary_action, } - if color != "default": - msg["color"] = color - if placement != "default": - msg["placement"] = placement if duration is not None: msg["duration"] = duration if extra_tags: From 0a4beb81aac08c4d4b80b8130a89603df7b3f2cd Mon Sep 17 00:00:00 2001 From: deepakdinesh1123 Date: Fri, 27 Jun 2025 16:53:24 +0530 Subject: [PATCH 7/8] fix update password api --- backend/src/zango/api/app_auth/profile/v1/views.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/backend/src/zango/api/app_auth/profile/v1/views.py b/backend/src/zango/api/app_auth/profile/v1/views.py index 5059c5a94..98f1a43a0 100644 --- a/backend/src/zango/api/app_auth/profile/v1/views.py +++ b/backend/src/zango/api/app_auth/profile/v1/views.py @@ -31,12 +31,14 @@ def put(self, request, *args, **kwargs): class PasswordChangeViewAPIV1(ZangoSessionAppAPIView, PasswordValidationMixin): - def clean_password(self, email, password): + def clean_password(self, request, password): """ Validates that the email is not already in use. """ try: - user = authenticate(username=email, password=password) + user = authenticate( + username=request.user.email, password=password, request=request + ) except Exception: raise ValidationError( "The current password you have entered is wrong. Please try again!" @@ -57,7 +59,7 @@ def put(self, request, *args, **kwargs): new_password = request.data.get("new_password") success = False try: - self.clean_password(request.user.email, current_password) + self.clean_password(request, current_password) self.clean_password2(request.user, current_password, new_password) request.user.set_password(new_password) request.user.save() From 93c5ad1d9f1650a53316293426d10ece3c2a71dc Mon Sep 17 00:00:00 2001 From: deepakdinesh1123 Date: Mon, 30 Jun 2025 14:43:28 +0530 Subject: [PATCH 8/8] persist session after updating password --- backend/src/zango/api/app_auth/profile/v1/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/src/zango/api/app_auth/profile/v1/views.py b/backend/src/zango/api/app_auth/profile/v1/views.py index 98f1a43a0..276a8ecf6 100644 --- a/backend/src/zango/api/app_auth/profile/v1/views.py +++ b/backend/src/zango/api/app_auth/profile/v1/views.py @@ -1,4 +1,4 @@ -from django.contrib.auth import authenticate +from django.contrib.auth import authenticate, update_session_auth_hash from django.core.exceptions import ValidationError from zango.api.app_auth.profile.v1.utils import PasswordValidationMixin @@ -69,6 +69,7 @@ def put(self, request, *args, **kwargs): success = True response = {} status = 200 + update_session_auth_hash(request, request.user) return get_api_response(success, response, status) except ValidationError as e: response = {"message": e.message}