diff --git a/apiserver/plane/api/urls.py b/apiserver/plane/api/urls.py index 1958f5c18..55b14baa8 100644 --- a/apiserver/plane/api/urls.py +++ b/apiserver/plane/api/urls.py @@ -22,6 +22,7 @@ from plane.api.views import ( # User UserEndpoint, UpdateUserOnBoardedEndpoint, + UpdateUserTourCompletedEndpoint, UserActivityEndpoint, ## End User # Workspaces @@ -202,7 +203,12 @@ urlpatterns = [ path( "users/me/onboard/", UpdateUserOnBoardedEndpoint.as_view(), - name="change-password", + name="user-onboard", + ), + path( + "users/me/tour-completed/", + UpdateUserTourCompletedEndpoint.as_view(), + name="user-tour", ), path("users/activities/", UserActivityEndpoint.as_view(), name="user-activities"), # user workspaces diff --git a/apiserver/plane/api/views/__init__.py b/apiserver/plane/api/views/__init__.py index 9eba0868a..2f0a54c1d 100644 --- a/apiserver/plane/api/views/__init__.py +++ b/apiserver/plane/api/views/__init__.py @@ -16,6 +16,7 @@ from .project import ( from .people import ( UserEndpoint, UpdateUserOnBoardedEndpoint, + UpdateUserTourCompletedEndpoint, UserActivityEndpoint, ) diff --git a/apiserver/plane/api/views/people.py b/apiserver/plane/api/views/people.py index 8e19fea1a..705f5c96e 100644 --- a/apiserver/plane/api/views/people.py +++ b/apiserver/plane/api/views/people.py @@ -37,7 +37,9 @@ class UserEndpoint(BaseViewSet): workspace_invites = WorkspaceMemberInvite.objects.filter( email=request.user.email ).count() - assigned_issues = Issue.issue_objects.filter(assignees__in=[request.user]).count() + assigned_issues = Issue.issue_objects.filter( + assignees__in=[request.user] + ).count() serialized_data = UserSerializer(request.user).data serialized_data["workspace"] = { @@ -47,7 +49,9 @@ class UserEndpoint(BaseViewSet): "fallback_workspace_slug": workspace.slug, "invites": workspace_invites, } - serialized_data.setdefault("issues", {})["assigned_issues"] = assigned_issues + serialized_data.setdefault("issues", {})[ + "assigned_issues" + ] = assigned_issues return Response( serialized_data, @@ -59,11 +63,15 @@ class UserEndpoint(BaseViewSet): workspace_invites = WorkspaceMemberInvite.objects.filter( email=request.user.email ).count() - assigned_issues = Issue.issue_objects.filter(assignees__in=[request.user]).count() + assigned_issues = Issue.issue_objects.filter( + assignees__in=[request.user] + ).count() - fallback_workspace = Workspace.objects.filter( - workspace_member__member=request.user - ).order_by("created_at").first() + fallback_workspace = ( + Workspace.objects.filter(workspace_member__member=request.user) + .order_by("created_at") + .first() + ) serialized_data = UserSerializer(request.user).data @@ -78,7 +86,9 @@ class UserEndpoint(BaseViewSet): else None, "invites": workspace_invites, } - serialized_data.setdefault("issues", {})["assigned_issues"] = assigned_issues + serialized_data.setdefault("issues", {})[ + "assigned_issues" + ] = assigned_issues return Response( serialized_data, @@ -109,6 +119,23 @@ class UpdateUserOnBoardedEndpoint(BaseAPIView): ) +class UpdateUserTourCompletedEndpoint(BaseAPIView): + def patch(self, request): + try: + user = User.objects.get(pk=request.user.id) + user.is_tour_completed = request.data.get("is_tour_completed", False) + user.save() + return Response( + {"message": "Updated successfully"}, status=status.HTTP_200_OK + ) + except Exception as e: + capture_exception(e) + return Response( + {"error": "Something went wrong please try again later"}, + status=status.HTTP_400_BAD_REQUEST, + ) + + class UserActivityEndpoint(BaseAPIView, BasePaginator): def get(self, request): try: diff --git a/apiserver/plane/db/models/user.py b/apiserver/plane/db/models/user.py index b0ab72159..36b3a1f6b 100644 --- a/apiserver/plane/db/models/user.py +++ b/apiserver/plane/db/models/user.py @@ -18,6 +18,13 @@ from sentry_sdk import capture_exception from slack_sdk import WebClient from slack_sdk.errors import SlackApiError +def get_default_onboarding(): + return { + "profile_complete": False, + "workspace_create": False, + "workspace_invite": False, + "workspace_join": False, + } class User(AbstractBaseUser, PermissionsMixin): id = models.UUIDField( @@ -73,6 +80,8 @@ class User(AbstractBaseUser, PermissionsMixin): role = models.CharField(max_length=300, null=True, blank=True) is_bot = models.BooleanField(default=False) theme = models.JSONField(default=dict) + is_tour_completed = models.BooleanField(default=False) + onboarding_step = models.JSONField(default=get_default_onboarding) USERNAME_FIELD = "email"