forked from github/plane
feat: user display name (#1179)
* feat: user display name for the entire system * feat: update issue activity to remove emails * dev: update to display name wherever assignees__email and member__email * dev: update display names on issue activity and the user script * dev: update display_name function to generate display_name from email * dev: add email for test purpose * dev: set default display name for the user * dev: add migration script and default value * dev: annotate with assignees_id * dev: return assignees id * dev: display name for the profile * dev: project members endpoint * dev: url update * dev: trailing / * dev: update workspace member serializer * fix: activity for assignees
This commit is contained in:
parent
9df0ba6e3a
commit
cf306ee605
@ -1,4 +1,4 @@
|
|||||||
import os, sys
|
import os, sys, random, string
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
sys.path.append("/code")
|
sys.path.append("/code")
|
||||||
@ -19,9 +19,9 @@ def populate():
|
|||||||
user = User.objects.create(email=default_email, username=uuid.uuid4().hex)
|
user = User.objects.create(email=default_email, username=uuid.uuid4().hex)
|
||||||
user.set_password(default_password)
|
user.set_password(default_password)
|
||||||
user.save()
|
user.save()
|
||||||
print("User created")
|
print(f"User created with an email: {default_email}")
|
||||||
|
else:
|
||||||
print("Success")
|
print(f"User already exists with the default email: {default_email}")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -1,10 +1,5 @@
|
|||||||
from .base import BaseSerializer
|
from .base import BaseSerializer
|
||||||
from .people import (
|
from .user import UserSerializer, UserLiteSerializer, ChangePasswordSerializer, ResetPasswordSerializer, UserAdminLiteSerializer
|
||||||
ChangePasswordSerializer,
|
|
||||||
ResetPasswordSerializer,
|
|
||||||
TokenSerializer,
|
|
||||||
)
|
|
||||||
from .user import UserSerializer, UserLiteSerializer
|
|
||||||
from .workspace import (
|
from .workspace import (
|
||||||
WorkSpaceSerializer,
|
WorkSpaceSerializer,
|
||||||
WorkSpaceMemberSerializer,
|
WorkSpaceMemberSerializer,
|
||||||
@ -12,6 +7,7 @@ from .workspace import (
|
|||||||
WorkSpaceMemberInviteSerializer,
|
WorkSpaceMemberInviteSerializer,
|
||||||
WorkspaceLiteSerializer,
|
WorkspaceLiteSerializer,
|
||||||
WorkspaceThemeSerializer,
|
WorkspaceThemeSerializer,
|
||||||
|
WorkspaceMemberAdminSerializer,
|
||||||
)
|
)
|
||||||
from .project import (
|
from .project import (
|
||||||
ProjectSerializer,
|
ProjectSerializer,
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
from rest_framework.serializers import (
|
|
||||||
ModelSerializer,
|
|
||||||
Serializer,
|
|
||||||
CharField,
|
|
||||||
SerializerMethodField,
|
|
||||||
)
|
|
||||||
from rest_framework.authtoken.models import Token
|
|
||||||
from rest_framework_simplejwt.tokens import RefreshToken
|
|
||||||
|
|
||||||
|
|
||||||
from plane.db.models import User
|
|
||||||
|
|
||||||
|
|
||||||
class UserSerializer(ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = User
|
|
||||||
fields = "__all__"
|
|
||||||
extra_kwargs = {"password": {"write_only": True}}
|
|
||||||
|
|
||||||
|
|
||||||
class ChangePasswordSerializer(Serializer):
|
|
||||||
model = User
|
|
||||||
|
|
||||||
"""
|
|
||||||
Serializer for password change endpoint.
|
|
||||||
"""
|
|
||||||
old_password = CharField(required=True)
|
|
||||||
new_password = CharField(required=True)
|
|
||||||
|
|
||||||
|
|
||||||
class ResetPasswordSerializer(Serializer):
|
|
||||||
model = User
|
|
||||||
|
|
||||||
"""
|
|
||||||
Serializer for password change endpoint.
|
|
||||||
"""
|
|
||||||
new_password = CharField(required=True)
|
|
||||||
confirm_password = CharField(required=True)
|
|
||||||
|
|
||||||
|
|
||||||
class TokenSerializer(ModelSerializer):
|
|
||||||
|
|
||||||
user = UserSerializer()
|
|
||||||
access_token = SerializerMethodField()
|
|
||||||
refresh_token = SerializerMethodField()
|
|
||||||
|
|
||||||
def get_access_token(self, obj):
|
|
||||||
refresh_token = RefreshToken.for_user(obj.user)
|
|
||||||
return str(refresh_token.access_token)
|
|
||||||
|
|
||||||
def get_refresh_token(self, obj):
|
|
||||||
refresh_token = RefreshToken.for_user(obj.user)
|
|
||||||
return str(refresh_token)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = Token
|
|
||||||
fields = "__all__"
|
|
@ -7,7 +7,7 @@ from rest_framework import serializers
|
|||||||
# Module imports
|
# Module imports
|
||||||
from .base import BaseSerializer
|
from .base import BaseSerializer
|
||||||
from plane.api.serializers.workspace import WorkSpaceSerializer, WorkspaceLiteSerializer
|
from plane.api.serializers.workspace import WorkSpaceSerializer, WorkspaceLiteSerializer
|
||||||
from plane.api.serializers.user import UserLiteSerializer
|
from plane.api.serializers.user import UserLiteSerializer, UserAdminLiteSerializer
|
||||||
from plane.db.models import (
|
from plane.db.models import (
|
||||||
Project,
|
Project,
|
||||||
ProjectMember,
|
ProjectMember,
|
||||||
@ -110,6 +110,17 @@ class ProjectMemberSerializer(BaseSerializer):
|
|||||||
fields = "__all__"
|
fields = "__all__"
|
||||||
|
|
||||||
|
|
||||||
|
class ProjectMemberAdminSerializer(BaseSerializer):
|
||||||
|
workspace = WorkspaceLiteSerializer(read_only=True)
|
||||||
|
project = ProjectLiteSerializer(read_only=True)
|
||||||
|
member = UserAdminLiteSerializer(read_only=True)
|
||||||
|
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = ProjectMember
|
||||||
|
fields = "__all__"
|
||||||
|
|
||||||
|
|
||||||
class ProjectMemberInviteSerializer(BaseSerializer):
|
class ProjectMemberInviteSerializer(BaseSerializer):
|
||||||
project = ProjectLiteSerializer(read_only=True)
|
project = ProjectLiteSerializer(read_only=True)
|
||||||
workspace = WorkspaceLiteSerializer(read_only=True)
|
workspace = WorkspaceLiteSerializer(read_only=True)
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# Third party imports
|
||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
# Module import
|
# Module import
|
||||||
from .base import BaseSerializer
|
from .base import BaseSerializer
|
||||||
from plane.db.models import User
|
from plane.db.models import User
|
||||||
@ -37,11 +40,50 @@ class UserLiteSerializer(BaseSerializer):
|
|||||||
"id",
|
"id",
|
||||||
"first_name",
|
"first_name",
|
||||||
"last_name",
|
"last_name",
|
||||||
"email",
|
|
||||||
"avatar",
|
"avatar",
|
||||||
"is_bot",
|
"is_bot",
|
||||||
|
"display_name",
|
||||||
]
|
]
|
||||||
read_only_fields = [
|
read_only_fields = [
|
||||||
"id",
|
"id",
|
||||||
"is_bot",
|
"is_bot",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class UserAdminLiteSerializer(BaseSerializer):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = User
|
||||||
|
fields = [
|
||||||
|
"id",
|
||||||
|
"first_name",
|
||||||
|
"last_name",
|
||||||
|
"avatar",
|
||||||
|
"is_bot",
|
||||||
|
"display_name",
|
||||||
|
"email",
|
||||||
|
]
|
||||||
|
read_only_fields = [
|
||||||
|
"id",
|
||||||
|
"is_bot",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class ChangePasswordSerializer(serializers.Serializer):
|
||||||
|
model = User
|
||||||
|
|
||||||
|
"""
|
||||||
|
Serializer for password change endpoint.
|
||||||
|
"""
|
||||||
|
old_password = serializers.CharField(required=True)
|
||||||
|
new_password = serializers.CharField(required=True)
|
||||||
|
|
||||||
|
|
||||||
|
class ResetPasswordSerializer(serializers.Serializer):
|
||||||
|
model = User
|
||||||
|
|
||||||
|
"""
|
||||||
|
Serializer for password change endpoint.
|
||||||
|
"""
|
||||||
|
new_password = serializers.CharField(required=True)
|
||||||
|
confirm_password = serializers.CharField(required=True)
|
||||||
|
@ -3,7 +3,7 @@ from rest_framework import serializers
|
|||||||
|
|
||||||
# Module imports
|
# Module imports
|
||||||
from .base import BaseSerializer
|
from .base import BaseSerializer
|
||||||
from .user import UserLiteSerializer
|
from .user import UserLiteSerializer, UserAdminLiteSerializer
|
||||||
|
|
||||||
from plane.db.models import (
|
from plane.db.models import (
|
||||||
User,
|
User,
|
||||||
@ -33,10 +33,30 @@ class WorkSpaceSerializer(BaseSerializer):
|
|||||||
"owner",
|
"owner",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
class WorkspaceLiteSerializer(BaseSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Workspace
|
||||||
|
fields = [
|
||||||
|
"name",
|
||||||
|
"slug",
|
||||||
|
"id",
|
||||||
|
]
|
||||||
|
read_only_fields = fields
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class WorkSpaceMemberSerializer(BaseSerializer):
|
class WorkSpaceMemberSerializer(BaseSerializer):
|
||||||
member = UserLiteSerializer(read_only=True)
|
member = UserLiteSerializer(read_only=True)
|
||||||
workspace = WorkSpaceSerializer(read_only=True)
|
workspace = WorkspaceLiteSerializer(read_only=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = WorkspaceMember
|
||||||
|
fields = "__all__"
|
||||||
|
|
||||||
|
|
||||||
|
class WorkspaceMemberAdminSerializer(BaseSerializer):
|
||||||
|
member = UserAdminLiteSerializer(read_only=True)
|
||||||
|
workspace = WorkspaceLiteSerializer(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = WorkspaceMember
|
model = WorkspaceMember
|
||||||
@ -101,17 +121,6 @@ class TeamSerializer(BaseSerializer):
|
|||||||
return super().update(instance, validated_data)
|
return super().update(instance, validated_data)
|
||||||
|
|
||||||
|
|
||||||
class WorkspaceLiteSerializer(BaseSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = Workspace
|
|
||||||
fields = [
|
|
||||||
"name",
|
|
||||||
"slug",
|
|
||||||
"id",
|
|
||||||
]
|
|
||||||
read_only_fields = fields
|
|
||||||
|
|
||||||
|
|
||||||
class WorkspaceThemeSerializer(BaseSerializer):
|
class WorkspaceThemeSerializer(BaseSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = WorkspaceTheme
|
model = WorkspaceTheme
|
||||||
|
@ -32,6 +32,7 @@ from plane.api.views import (
|
|||||||
InviteWorkspaceEndpoint,
|
InviteWorkspaceEndpoint,
|
||||||
JoinWorkspaceEndpoint,
|
JoinWorkspaceEndpoint,
|
||||||
WorkSpaceMemberViewSet,
|
WorkSpaceMemberViewSet,
|
||||||
|
WorkspaceMembersEndpoint,
|
||||||
WorkspaceInvitationsViewset,
|
WorkspaceInvitationsViewset,
|
||||||
UserWorkspaceInvitationsEndpoint,
|
UserWorkspaceInvitationsEndpoint,
|
||||||
WorkspaceMemberUserEndpoint,
|
WorkspaceMemberUserEndpoint,
|
||||||
@ -59,6 +60,7 @@ from plane.api.views import (
|
|||||||
ProjectViewSet,
|
ProjectViewSet,
|
||||||
InviteProjectEndpoint,
|
InviteProjectEndpoint,
|
||||||
ProjectMemberViewSet,
|
ProjectMemberViewSet,
|
||||||
|
ProjectMemberEndpoint,
|
||||||
ProjectMemberInvitationsViewset,
|
ProjectMemberInvitationsViewset,
|
||||||
ProjectMemberUserEndpoint,
|
ProjectMemberUserEndpoint,
|
||||||
AddMemberToProjectEndpoint,
|
AddMemberToProjectEndpoint,
|
||||||
@ -335,6 +337,11 @@ urlpatterns = [
|
|||||||
),
|
),
|
||||||
name="workspace",
|
name="workspace",
|
||||||
),
|
),
|
||||||
|
path(
|
||||||
|
"workspaces/<str:slug>/workspace-members/",
|
||||||
|
WorkspaceMembersEndpoint.as_view(),
|
||||||
|
name="workspace-members",
|
||||||
|
),
|
||||||
path(
|
path(
|
||||||
"workspaces/<str:slug>/teams/",
|
"workspaces/<str:slug>/teams/",
|
||||||
TeamMemberViewSet.as_view(
|
TeamMemberViewSet.as_view(
|
||||||
@ -468,6 +475,11 @@ urlpatterns = [
|
|||||||
),
|
),
|
||||||
name="project",
|
name="project",
|
||||||
),
|
),
|
||||||
|
path(
|
||||||
|
"workspaces/<str:slug>/projects/<uuid:project_id>/project-members/",
|
||||||
|
ProjectMemberEndpoint.as_view(),
|
||||||
|
name="project",
|
||||||
|
),
|
||||||
path(
|
path(
|
||||||
"workspaces/<str:slug>/projects/<uuid:project_id>/members/add/",
|
"workspaces/<str:slug>/projects/<uuid:project_id>/members/add/",
|
||||||
AddMemberToProjectEndpoint.as_view(),
|
AddMemberToProjectEndpoint.as_view(),
|
||||||
|
@ -12,8 +12,9 @@ from .project import (
|
|||||||
ProjectUserViewsEndpoint,
|
ProjectUserViewsEndpoint,
|
||||||
ProjectMemberUserEndpoint,
|
ProjectMemberUserEndpoint,
|
||||||
ProjectFavoritesViewSet,
|
ProjectFavoritesViewSet,
|
||||||
|
ProjectMemberEndpoint,
|
||||||
)
|
)
|
||||||
from .people import (
|
from .user import (
|
||||||
UserEndpoint,
|
UserEndpoint,
|
||||||
UpdateUserOnBoardedEndpoint,
|
UpdateUserOnBoardedEndpoint,
|
||||||
UpdateUserTourCompletedEndpoint,
|
UpdateUserTourCompletedEndpoint,
|
||||||
@ -47,6 +48,7 @@ from .workspace import (
|
|||||||
WorkspaceUserProfileEndpoint,
|
WorkspaceUserProfileEndpoint,
|
||||||
WorkspaceUserProfileIssuesEndpoint,
|
WorkspaceUserProfileIssuesEndpoint,
|
||||||
WorkspaceLabelsEndpoint,
|
WorkspaceLabelsEndpoint,
|
||||||
|
WorkspaceMembersEndpoint,
|
||||||
)
|
)
|
||||||
from .state import StateViewSet
|
from .state import StateViewSet
|
||||||
from .view import IssueViewViewSet, ViewIssuesEndpoint, IssueViewFavoriteViewSet
|
from .view import IssueViewViewSet, ViewIssuesEndpoint, IssueViewFavoriteViewSet
|
||||||
|
@ -79,12 +79,12 @@ class AnalyticsEndpoint(BaseAPIView):
|
|||||||
)
|
)
|
||||||
|
|
||||||
assignee_details = {}
|
assignee_details = {}
|
||||||
if x_axis in ["assignees__email"] or segment in ["assignees__email"]:
|
if x_axis in ["assignees__id"] or segment in ["assignees__id"]:
|
||||||
assignee_details = (
|
assignee_details = (
|
||||||
Issue.issue_objects.filter(workspace__slug=slug, **filters, assignees__avatar__isnull=False)
|
Issue.issue_objects.filter(workspace__slug=slug, **filters, assignees__avatar__isnull=False)
|
||||||
.order_by("assignees__id")
|
.order_by("assignees__id")
|
||||||
.distinct("assignees__id")
|
.distinct("assignees__id")
|
||||||
.values("assignees__avatar", "assignees__email", "assignees__first_name", "assignees__last_name")
|
.values("assignees__avatar", "assignees__display_name", "assignees__first_name", "assignees__last_name", "assignees__id")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -243,21 +243,21 @@ class DefaultAnalyticsEndpoint(BaseAPIView):
|
|||||||
)
|
)
|
||||||
most_issue_created_user = (
|
most_issue_created_user = (
|
||||||
queryset.exclude(created_by=None)
|
queryset.exclude(created_by=None)
|
||||||
.values("created_by__first_name", "created_by__last_name", "created_by__avatar", "created_by__email")
|
.values("created_by__first_name", "created_by__last_name", "created_by__avatar", "created_by__display_name")
|
||||||
.annotate(count=Count("id"))
|
.annotate(count=Count("id"))
|
||||||
.order_by("-count")
|
.order_by("-count")
|
||||||
)[:5]
|
)[:5]
|
||||||
|
|
||||||
most_issue_closed_user = (
|
most_issue_closed_user = (
|
||||||
queryset.filter(completed_at__isnull=False, assignees__isnull=False)
|
queryset.filter(completed_at__isnull=False, assignees__isnull=False)
|
||||||
.values("assignees__first_name", "assignees__last_name", "assignees__avatar", "assignees__email")
|
.values("assignees__first_name", "assignees__last_name", "assignees__avatar", "assignees__display_name")
|
||||||
.annotate(count=Count("id"))
|
.annotate(count=Count("id"))
|
||||||
.order_by("-count")
|
.order_by("-count")
|
||||||
)[:5]
|
)[:5]
|
||||||
|
|
||||||
pending_issue_user = (
|
pending_issue_user = (
|
||||||
queryset.filter(completed_at__isnull=True)
|
queryset.filter(completed_at__isnull=True)
|
||||||
.values("assignees__first_name", "assignees__last_name", "assignees__avatar", "assignees__email")
|
.values("assignees__first_name", "assignees__last_name", "assignees__avatar", "assignees__display_name")
|
||||||
.annotate(count=Count("id"))
|
.annotate(count=Count("id"))
|
||||||
.order_by("-count")
|
.order_by("-count")
|
||||||
)
|
)
|
||||||
|
@ -22,7 +22,7 @@ from sentry_sdk import capture_exception
|
|||||||
|
|
||||||
## Module imports
|
## Module imports
|
||||||
from . import BaseAPIView
|
from . import BaseAPIView
|
||||||
from plane.api.serializers.people import (
|
from plane.api.serializers import (
|
||||||
ChangePasswordSerializer,
|
ChangePasswordSerializer,
|
||||||
ResetPasswordSerializer,
|
ResetPasswordSerializer,
|
||||||
)
|
)
|
||||||
|
@ -458,7 +458,7 @@ class BulkImportIssuesEndpoint(BaseAPIView):
|
|||||||
actor=request.user,
|
actor=request.user,
|
||||||
project_id=project_id,
|
project_id=project_id,
|
||||||
workspace_id=project.workspace_id,
|
workspace_id=project.workspace_id,
|
||||||
comment=f"{request.user.email} importer the issue from {service}",
|
comment=f"imported the issue from {service}",
|
||||||
verb="created",
|
verb="created",
|
||||||
created_by=request.user,
|
created_by=request.user,
|
||||||
)
|
)
|
||||||
|
@ -301,7 +301,7 @@ class CreateIssueFromPageBlockEndpoint(BaseAPIView):
|
|||||||
issue=issue,
|
issue=issue,
|
||||||
actor=request.user,
|
actor=request.user,
|
||||||
project_id=project_id,
|
project_id=project_id,
|
||||||
comment=f"{request.user.email} created the issue from {page_block.name} block",
|
comment=f"created the issue from {page_block.name} block",
|
||||||
verb="created",
|
verb="created",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ from plane.api.serializers import (
|
|||||||
ProjectFavoriteSerializer,
|
ProjectFavoriteSerializer,
|
||||||
)
|
)
|
||||||
|
|
||||||
from plane.api.permissions import ProjectBasePermission
|
from plane.api.permissions import ProjectBasePermission, ProjectEntityPermission
|
||||||
|
|
||||||
from plane.db.models import (
|
from plane.db.models import (
|
||||||
Project,
|
Project,
|
||||||
@ -458,7 +458,7 @@ class ProjectMemberViewSet(BaseViewSet):
|
|||||||
]
|
]
|
||||||
|
|
||||||
search_fields = [
|
search_fields = [
|
||||||
"member__email",
|
"member__display_name",
|
||||||
"member__first_name",
|
"member__first_name",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -984,3 +984,23 @@ class ProjectFavoritesViewSet(BaseViewSet):
|
|||||||
{"error": "Something went wrong please try again later"},
|
{"error": "Something went wrong please try again later"},
|
||||||
status=status.HTTP_400_BAD_REQUEST,
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ProjectMemberEndpoint(BaseAPIView):
|
||||||
|
permission_classes = [
|
||||||
|
ProjectEntityPermission,
|
||||||
|
]
|
||||||
|
|
||||||
|
def get(self, request, slug, project_id):
|
||||||
|
try:
|
||||||
|
project_members = ProjectMember.objects.filter(
|
||||||
|
project_id=project_id, workspace__slug=slug
|
||||||
|
).select_related("project", "member")
|
||||||
|
serializer = ProjectMemberSerializer(project_members, many=True)
|
||||||
|
return Response(serializer.data, 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,
|
||||||
|
)
|
||||||
|
@ -47,6 +47,7 @@ from plane.api.serializers import (
|
|||||||
WorkspaceThemeSerializer,
|
WorkspaceThemeSerializer,
|
||||||
IssueActivitySerializer,
|
IssueActivitySerializer,
|
||||||
IssueLiteSerializer,
|
IssueLiteSerializer,
|
||||||
|
WorkspaceMemberAdminSerializer
|
||||||
)
|
)
|
||||||
from plane.api.views.base import BaseAPIView
|
from plane.api.views.base import BaseAPIView
|
||||||
from . import BaseViewSet
|
from . import BaseViewSet
|
||||||
@ -537,7 +538,7 @@ class UserWorkspaceInvitationsEndpoint(BaseViewSet):
|
|||||||
|
|
||||||
|
|
||||||
class WorkSpaceMemberViewSet(BaseViewSet):
|
class WorkSpaceMemberViewSet(BaseViewSet):
|
||||||
serializer_class = WorkSpaceMemberSerializer
|
serializer_class = WorkspaceMemberAdminSerializer
|
||||||
model = WorkspaceMember
|
model = WorkspaceMember
|
||||||
|
|
||||||
permission_classes = [
|
permission_classes = [
|
||||||
@ -545,7 +546,7 @@ class WorkSpaceMemberViewSet(BaseViewSet):
|
|||||||
]
|
]
|
||||||
|
|
||||||
search_fields = [
|
search_fields = [
|
||||||
"member__email",
|
"member__display_name",
|
||||||
"member__first_name",
|
"member__first_name",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -690,7 +691,7 @@ class TeamMemberViewSet(BaseViewSet):
|
|||||||
]
|
]
|
||||||
|
|
||||||
search_fields = [
|
search_fields = [
|
||||||
"member__email",
|
"member__display_name",
|
||||||
"member__first_name",
|
"member__first_name",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1048,7 +1049,6 @@ class WorkspaceThemeViewSet(BaseViewSet):
|
|||||||
|
|
||||||
|
|
||||||
class WorkspaceUserProfileStatsEndpoint(BaseAPIView):
|
class WorkspaceUserProfileStatsEndpoint(BaseAPIView):
|
||||||
|
|
||||||
def get(self, request, slug, user_id):
|
def get(self, request, slug, user_id):
|
||||||
try:
|
try:
|
||||||
filters = issue_filters(request.query_params, "GET")
|
filters = issue_filters(request.query_params, "GET")
|
||||||
@ -1146,14 +1146,18 @@ class WorkspaceUserProfileStatsEndpoint(BaseAPIView):
|
|||||||
upcoming_cycles = CycleIssue.objects.filter(
|
upcoming_cycles = CycleIssue.objects.filter(
|
||||||
workspace__slug=slug,
|
workspace__slug=slug,
|
||||||
cycle__start_date__gt=timezone.now().date(),
|
cycle__start_date__gt=timezone.now().date(),
|
||||||
issue__assignees__in=[user_id,]
|
issue__assignees__in=[
|
||||||
|
user_id,
|
||||||
|
],
|
||||||
).values("cycle__name", "cycle__id", "cycle__project_id")
|
).values("cycle__name", "cycle__id", "cycle__project_id")
|
||||||
|
|
||||||
present_cycle = CycleIssue.objects.filter(
|
present_cycle = CycleIssue.objects.filter(
|
||||||
workspace__slug=slug,
|
workspace__slug=slug,
|
||||||
cycle__start_date__lt=timezone.now().date(),
|
cycle__start_date__lt=timezone.now().date(),
|
||||||
cycle__end_date__gt=timezone.now().date(),
|
cycle__end_date__gt=timezone.now().date(),
|
||||||
issue__assignees__in=[user_id,]
|
issue__assignees__in=[
|
||||||
|
user_id,
|
||||||
|
],
|
||||||
).values("cycle__name", "cycle__id", "cycle__project_id")
|
).values("cycle__name", "cycle__id", "cycle__project_id")
|
||||||
|
|
||||||
return Response(
|
return Response(
|
||||||
@ -1166,7 +1170,7 @@ class WorkspaceUserProfileStatsEndpoint(BaseAPIView):
|
|||||||
"pending_issues": pending_issues_count,
|
"pending_issues": pending_issues_count,
|
||||||
"subscribed_issues": subscribed_issues_count,
|
"subscribed_issues": subscribed_issues_count,
|
||||||
"present_cycles": present_cycle,
|
"present_cycles": present_cycle,
|
||||||
"upcoming_cycles": upcoming_cycles,
|
"upcoming_cycles": upcoming_cycles,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -1184,7 +1188,6 @@ class WorkspaceUserActivityEndpoint(BaseAPIView):
|
|||||||
|
|
||||||
def get(self, request, slug, user_id):
|
def get(self, request, slug, user_id):
|
||||||
try:
|
try:
|
||||||
|
|
||||||
projects = request.query_params.getlist("project", [])
|
projects = request.query_params.getlist("project", [])
|
||||||
|
|
||||||
queryset = IssueActivity.objects.filter(
|
queryset = IssueActivity.objects.filter(
|
||||||
@ -1212,12 +1215,13 @@ class WorkspaceUserActivityEndpoint(BaseAPIView):
|
|||||||
|
|
||||||
|
|
||||||
class WorkspaceUserProfileEndpoint(BaseAPIView):
|
class WorkspaceUserProfileEndpoint(BaseAPIView):
|
||||||
|
|
||||||
def get(self, request, slug, user_id):
|
def get(self, request, slug, user_id):
|
||||||
try:
|
try:
|
||||||
user_data = User.objects.get(pk=user_id)
|
user_data = User.objects.get(pk=user_id)
|
||||||
|
|
||||||
requesting_workspace_member = WorkspaceMember.objects.get(workspace__slug=slug, member=request.user)
|
requesting_workspace_member = WorkspaceMember.objects.get(
|
||||||
|
workspace__slug=slug, member=request.user
|
||||||
|
)
|
||||||
projects = []
|
projects = []
|
||||||
if requesting_workspace_member.role >= 10:
|
if requesting_workspace_member.role >= 10:
|
||||||
projects = (
|
projects = (
|
||||||
@ -1227,7 +1231,8 @@ class WorkspaceUserProfileEndpoint(BaseAPIView):
|
|||||||
)
|
)
|
||||||
.annotate(
|
.annotate(
|
||||||
created_issues=Count(
|
created_issues=Count(
|
||||||
"project_issue", filter=Q(project_issue__created_by_id=user_id)
|
"project_issue",
|
||||||
|
filter=Q(project_issue__created_by_id=user_id),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.annotate(
|
.annotate(
|
||||||
@ -1282,6 +1287,7 @@ class WorkspaceUserProfileEndpoint(BaseAPIView):
|
|||||||
"cover_image": user_data.cover_image,
|
"cover_image": user_data.cover_image,
|
||||||
"date_joined": user_data.date_joined,
|
"date_joined": user_data.date_joined,
|
||||||
"user_timezone": user_data.user_timezone,
|
"user_timezone": user_data.user_timezone,
|
||||||
|
"display_name": user_data.display_name,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
status=status.HTTP_200_OK,
|
status=status.HTTP_200_OK,
|
||||||
@ -1439,3 +1445,23 @@ class WorkspaceLabelsEndpoint(BaseAPIView):
|
|||||||
{"error": "Something went wrong please try again later"},
|
{"error": "Something went wrong please try again later"},
|
||||||
status=status.HTTP_400_BAD_REQUEST,
|
status=status.HTTP_400_BAD_REQUEST,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class WorkspaceMembersEndpoint(BaseAPIView):
|
||||||
|
permission_classes = [
|
||||||
|
WorkspaceEntityPermission,
|
||||||
|
]
|
||||||
|
|
||||||
|
def get(self, request, slug):
|
||||||
|
try:
|
||||||
|
workspace_members = WorkspaceMember.objects.filter(
|
||||||
|
workspace__slug=slug
|
||||||
|
).select_related("workspace", "member")
|
||||||
|
serialzier = WorkSpaceMemberSerializer(workspace_members, many=True)
|
||||||
|
return Response(serialzier.data, 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,
|
||||||
|
)
|
||||||
|
@ -21,7 +21,7 @@ row_mapping = {
|
|||||||
"state__name": "State",
|
"state__name": "State",
|
||||||
"state__group": "State Group",
|
"state__group": "State Group",
|
||||||
"labels__name": "Label",
|
"labels__name": "Label",
|
||||||
"assignees__email": "Assignee Name",
|
"assignees__display_name": "Assignee Name",
|
||||||
"start_date": "Start Date",
|
"start_date": "Start Date",
|
||||||
"target_date": "Due Date",
|
"target_date": "Due Date",
|
||||||
"completed_at": "Completed At",
|
"completed_at": "Completed At",
|
||||||
@ -51,12 +51,12 @@ def analytic_export_task(email, data, slug):
|
|||||||
segmented = segment
|
segmented = segment
|
||||||
|
|
||||||
assignee_details = {}
|
assignee_details = {}
|
||||||
if x_axis in ["assignees__email"] or segment in ["assignees__email"]:
|
if x_axis in ["assignees__display_name"] or segment in ["assignees__display_name"]:
|
||||||
assignee_details = (
|
assignee_details = (
|
||||||
Issue.issue_objects.filter(workspace__slug=slug, **filters, assignees__avatar__isnull=False)
|
Issue.issue_objects.filter(workspace__slug=slug, **filters, assignees__avatar__isnull=False)
|
||||||
.order_by("assignees__id")
|
.order_by("assignees__id")
|
||||||
.distinct("assignees__id")
|
.distinct("assignees__id")
|
||||||
.values("assignees__avatar", "assignees__email", "assignees__first_name", "assignees__last_name")
|
.values("assignees__avatar", "assignees__display_name", "assignees__first_name", "assignees__last_name")
|
||||||
)
|
)
|
||||||
|
|
||||||
if segment:
|
if segment:
|
||||||
@ -93,17 +93,17 @@ def analytic_export_task(email, data, slug):
|
|||||||
else:
|
else:
|
||||||
generated_row.append("0")
|
generated_row.append("0")
|
||||||
# x-axis replacement for names
|
# x-axis replacement for names
|
||||||
if x_axis in ["assignees__email"]:
|
if x_axis in ["assignees__display_name"]:
|
||||||
assignee = [user for user in assignee_details if str(user.get("assignees__email")) == str(item)]
|
assignee = [user for user in assignee_details if str(user.get("assignees__display_name")) == str(item)]
|
||||||
if len(assignee):
|
if len(assignee):
|
||||||
generated_row[0] = str(assignee[0].get("assignees__first_name")) + " " + str(assignee[0].get("assignees__last_name"))
|
generated_row[0] = str(assignee[0].get("assignees__first_name")) + " " + str(assignee[0].get("assignees__last_name"))
|
||||||
rows.append(tuple(generated_row))
|
rows.append(tuple(generated_row))
|
||||||
|
|
||||||
# If segment is ["assignees__email"] then replace segment_zero rows with first and last names
|
# If segment is ["assignees__display_name"] then replace segment_zero rows with first and last names
|
||||||
if segmented in ["assignees__email"]:
|
if segmented in ["assignees__display_name"]:
|
||||||
for index, segm in enumerate(row_zero[2:]):
|
for index, segm in enumerate(row_zero[2:]):
|
||||||
# find the name of the user
|
# find the name of the user
|
||||||
assignee = [user for user in assignee_details if str(user.get("assignees__email")) == str(segm)]
|
assignee = [user for user in assignee_details if str(user.get("assignees__display_name")) == str(segm)]
|
||||||
if len(assignee):
|
if len(assignee):
|
||||||
row_zero[index] = str(assignee[0].get("assignees__first_name")) + " " + str(assignee[0].get("assignees__last_name"))
|
row_zero[index] = str(assignee[0].get("assignees__first_name")) + " " + str(assignee[0].get("assignees__last_name"))
|
||||||
|
|
||||||
@ -141,8 +141,8 @@ def analytic_export_task(email, data, slug):
|
|||||||
else distribution.get(item)[0].get("estimate "),
|
else distribution.get(item)[0].get("estimate "),
|
||||||
]
|
]
|
||||||
# x-axis replacement to names
|
# x-axis replacement to names
|
||||||
if x_axis in ["assignees__email"]:
|
if x_axis in ["assignees__display_name"]:
|
||||||
assignee = [user for user in assignee_details if str(user.get("assignees__email")) == str(item)]
|
assignee = [user for user in assignee_details if str(user.get("assignees__display_name")) == str(item)]
|
||||||
if len(assignee):
|
if len(assignee):
|
||||||
row[0] = str(assignee[0].get("assignees__first_name")) + " " + str(assignee[0].get("assignees__last_name"))
|
row[0] = str(assignee[0].get("assignees__first_name")) + " " + str(assignee[0].get("assignees__last_name"))
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ def track_name(
|
|||||||
field="name",
|
field="name",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} updated the name to {requested_data.get('name')}",
|
comment=f"updated the name to {requested_data.get('name')}",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ def track_parent(
|
|||||||
field="parent",
|
field="parent",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} updated the parent issue to None",
|
comment=f"updated the parent issue to None",
|
||||||
old_identifier=old_parent.id,
|
old_identifier=old_parent.id,
|
||||||
new_identifier=None,
|
new_identifier=None,
|
||||||
)
|
)
|
||||||
@ -95,7 +95,7 @@ def track_parent(
|
|||||||
field="parent",
|
field="parent",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} updated the parent issue to {new_parent.name}",
|
comment=f"updated the parent issue to {new_parent.name}",
|
||||||
old_identifier=old_parent.id if old_parent is not None else None,
|
old_identifier=old_parent.id if old_parent is not None else None,
|
||||||
new_identifier=new_parent.id,
|
new_identifier=new_parent.id,
|
||||||
)
|
)
|
||||||
@ -123,7 +123,7 @@ def track_priority(
|
|||||||
field="priority",
|
field="priority",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} updated the priority to None",
|
comment=f"updated the priority to None",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -137,7 +137,7 @@ def track_priority(
|
|||||||
field="priority",
|
field="priority",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} updated the priority to {requested_data.get('priority')}",
|
comment=f"updated the priority to {requested_data.get('priority')}",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -165,7 +165,7 @@ def track_state(
|
|||||||
field="state",
|
field="state",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} updated the state to {new_state.name}",
|
comment=f"updated the state to {new_state.name}",
|
||||||
old_identifier=old_state.id,
|
old_identifier=old_state.id,
|
||||||
new_identifier=new_state.id,
|
new_identifier=new_state.id,
|
||||||
)
|
)
|
||||||
@ -194,7 +194,7 @@ def track_description(
|
|||||||
field="description",
|
field="description",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} updated the description to {requested_data.get('description_html')}",
|
comment=f"updated the description to {requested_data.get('description_html')}",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -220,7 +220,7 @@ def track_target_date(
|
|||||||
field="target_date",
|
field="target_date",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} updated the target date to None",
|
comment=f"updated the target date to None",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -234,7 +234,7 @@ def track_target_date(
|
|||||||
field="target_date",
|
field="target_date",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} updated the target date to {requested_data.get('target_date')}",
|
comment=f"updated the target date to {requested_data.get('target_date')}",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -260,7 +260,7 @@ def track_start_date(
|
|||||||
field="start_date",
|
field="start_date",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} updated the start date to None",
|
comment=f"updated the start date to None",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -274,7 +274,7 @@ def track_start_date(
|
|||||||
field="start_date",
|
field="start_date",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} updated the start date to {requested_data.get('start_date')}",
|
comment=f"updated the start date to {requested_data.get('start_date')}",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -303,7 +303,7 @@ def track_labels(
|
|||||||
field="labels",
|
field="labels",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} added label {label.name}",
|
comment=f"added label {label.name}",
|
||||||
new_identifier=label.id,
|
new_identifier=label.id,
|
||||||
old_identifier=None,
|
old_identifier=None,
|
||||||
)
|
)
|
||||||
@ -324,7 +324,7 @@ def track_labels(
|
|||||||
field="labels",
|
field="labels",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} removed label {label.name}",
|
comment=f"removed label {label.name}",
|
||||||
old_identifier=label.id,
|
old_identifier=label.id,
|
||||||
new_identifier=None,
|
new_identifier=None,
|
||||||
)
|
)
|
||||||
@ -353,12 +353,12 @@ def track_assignees(
|
|||||||
actor=actor,
|
actor=actor,
|
||||||
verb="updated",
|
verb="updated",
|
||||||
old_value="",
|
old_value="",
|
||||||
new_value=assignee.email,
|
new_value=assignee.display_name,
|
||||||
field="assignees",
|
field="assignees",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} added assignee {assignee.email}",
|
comment=f"added assignee {assignee.display_name}",
|
||||||
new_identifier=actor.id,
|
new_identifier=assignee.id,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -374,13 +374,13 @@ def track_assignees(
|
|||||||
issue_id=issue_id,
|
issue_id=issue_id,
|
||||||
actor=actor,
|
actor=actor,
|
||||||
verb="updated",
|
verb="updated",
|
||||||
old_value=assignee.email,
|
old_value=assignee.display_name,
|
||||||
new_value="",
|
new_value="",
|
||||||
field="assignees",
|
field="assignees",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} removed assignee {assignee.email}",
|
comment=f"removed assignee {assignee.display_name}",
|
||||||
old_identifier=actor.id,
|
old_identifier=assignee.id,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -419,7 +419,7 @@ def track_blocks(
|
|||||||
field="blocks",
|
field="blocks",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} added blocking issue {issue.project.identifier}-{issue.sequence_id}",
|
comment=f"added blocking issue {project.identifier}-{issue.sequence_id}",
|
||||||
new_identifier=issue.id,
|
new_identifier=issue.id,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -441,7 +441,7 @@ def track_blocks(
|
|||||||
field="blocks",
|
field="blocks",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} removed blocking issue {issue.project.identifier}-{issue.sequence_id}",
|
comment=f"removed blocking issue {project.identifier}-{issue.sequence_id}",
|
||||||
old_identifier=issue.id,
|
old_identifier=issue.id,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -481,7 +481,7 @@ def track_blockings(
|
|||||||
field="blocking",
|
field="blocking",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} added blocked by issue {issue.project.identifier}-{issue.sequence_id}",
|
comment=f"added blocked by issue {project.identifier}-{issue.sequence_id}",
|
||||||
new_identifier=issue.id,
|
new_identifier=issue.id,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -503,7 +503,7 @@ def track_blockings(
|
|||||||
field="blocking",
|
field="blocking",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} removed blocked by issue {issue.project.identifier}-{issue.sequence_id}",
|
comment=f"removed blocked by issue {project.identifier}-{issue.sequence_id}",
|
||||||
old_identifier=issue.id,
|
old_identifier=issue.id,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -517,7 +517,7 @@ def create_issue_activity(
|
|||||||
issue_id=issue_id,
|
issue_id=issue_id,
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} created the issue",
|
comment=f"created the issue",
|
||||||
verb="created",
|
verb="created",
|
||||||
actor=actor,
|
actor=actor,
|
||||||
)
|
)
|
||||||
@ -539,7 +539,7 @@ def track_estimate_points(
|
|||||||
field="estimate_point",
|
field="estimate_point",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} updated the estimate point to None",
|
comment=f"updated the estimate point to None",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -553,7 +553,7 @@ def track_estimate_points(
|
|||||||
field="estimate_point",
|
field="estimate_point",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} updated the estimate point to {requested_data.get('estimate_point')}",
|
comment=f"updated the estimate point to {requested_data.get('estimate_point')}",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -567,7 +567,7 @@ def track_archive_at(
|
|||||||
issue_id=issue_id,
|
issue_id=issue_id,
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} has restored the issue",
|
comment=f"has restored the issue",
|
||||||
verb="updated",
|
verb="updated",
|
||||||
actor=actor,
|
actor=actor,
|
||||||
field="archived_at",
|
field="archived_at",
|
||||||
@ -661,7 +661,7 @@ def delete_issue_activity(
|
|||||||
IssueActivity(
|
IssueActivity(
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} deleted the issue",
|
comment=f"deleted the issue",
|
||||||
verb="deleted",
|
verb="deleted",
|
||||||
actor=actor,
|
actor=actor,
|
||||||
field="issue",
|
field="issue",
|
||||||
@ -682,7 +682,7 @@ def create_comment_activity(
|
|||||||
issue_id=issue_id,
|
issue_id=issue_id,
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} created a comment",
|
comment=f"created a comment",
|
||||||
verb="created",
|
verb="created",
|
||||||
actor=actor,
|
actor=actor,
|
||||||
field="comment",
|
field="comment",
|
||||||
@ -707,7 +707,7 @@ def update_comment_activity(
|
|||||||
issue_id=issue_id,
|
issue_id=issue_id,
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} updated a comment",
|
comment=f"updated a comment",
|
||||||
verb="updated",
|
verb="updated",
|
||||||
actor=actor,
|
actor=actor,
|
||||||
field="comment",
|
field="comment",
|
||||||
@ -728,7 +728,7 @@ def delete_comment_activity(
|
|||||||
issue_id=issue_id,
|
issue_id=issue_id,
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} deleted the comment",
|
comment=f"deleted the comment",
|
||||||
verb="deleted",
|
verb="deleted",
|
||||||
actor=actor,
|
actor=actor,
|
||||||
field="comment",
|
field="comment",
|
||||||
@ -766,7 +766,7 @@ def create_cycle_issue_activity(
|
|||||||
field="cycles",
|
field="cycles",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} updated cycle from {old_cycle.name} to {new_cycle.name}",
|
comment=f"updated cycle from {old_cycle.name} to {new_cycle.name}",
|
||||||
old_identifier=old_cycle.id,
|
old_identifier=old_cycle.id,
|
||||||
new_identifier=new_cycle.id,
|
new_identifier=new_cycle.id,
|
||||||
)
|
)
|
||||||
@ -787,7 +787,7 @@ def create_cycle_issue_activity(
|
|||||||
field="cycles",
|
field="cycles",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} added cycle {cycle.name}",
|
comment=f"added cycle {cycle.name}",
|
||||||
new_identifier=cycle.id,
|
new_identifier=cycle.id,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -816,7 +816,7 @@ def delete_cycle_issue_activity(
|
|||||||
field="cycles",
|
field="cycles",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} removed this issue from {cycle.name if cycle is not None else None}",
|
comment=f"removed this issue from {cycle.name if cycle is not None else None}",
|
||||||
old_identifier=cycle.id if cycle is not None else None,
|
old_identifier=cycle.id if cycle is not None else None,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -852,7 +852,7 @@ def create_module_issue_activity(
|
|||||||
field="modules",
|
field="modules",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} updated module from {old_module.name} to {new_module.name}",
|
comment=f"updated module from {old_module.name} to {new_module.name}",
|
||||||
old_identifier=old_module.id,
|
old_identifier=old_module.id,
|
||||||
new_identifier=new_module.id,
|
new_identifier=new_module.id,
|
||||||
)
|
)
|
||||||
@ -872,7 +872,7 @@ def create_module_issue_activity(
|
|||||||
field="modules",
|
field="modules",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} added module {module.name}",
|
comment=f"added module {module.name}",
|
||||||
new_identifier=module.id,
|
new_identifier=module.id,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -901,7 +901,7 @@ def delete_module_issue_activity(
|
|||||||
field="modules",
|
field="modules",
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} removed this issue from {module.name if module is not None else None}",
|
comment=f"removed this issue from {module.name if module is not None else None}",
|
||||||
old_identifier=module.id if module is not None else None,
|
old_identifier=module.id if module is not None else None,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -920,7 +920,7 @@ def create_link_activity(
|
|||||||
issue_id=issue_id,
|
issue_id=issue_id,
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} created a link",
|
comment=f"created a link",
|
||||||
verb="created",
|
verb="created",
|
||||||
actor=actor,
|
actor=actor,
|
||||||
field="link",
|
field="link",
|
||||||
@ -944,7 +944,7 @@ def update_link_activity(
|
|||||||
issue_id=issue_id,
|
issue_id=issue_id,
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} updated a link",
|
comment=f"updated a link",
|
||||||
verb="updated",
|
verb="updated",
|
||||||
actor=actor,
|
actor=actor,
|
||||||
field="link",
|
field="link",
|
||||||
@ -969,7 +969,7 @@ def delete_link_activity(
|
|||||||
issue_id=issue_id,
|
issue_id=issue_id,
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} deleted the link",
|
comment=f"deleted the link",
|
||||||
verb="deleted",
|
verb="deleted",
|
||||||
actor=actor,
|
actor=actor,
|
||||||
field="link",
|
field="link",
|
||||||
@ -992,7 +992,7 @@ def create_attachment_activity(
|
|||||||
issue_id=issue_id,
|
issue_id=issue_id,
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} created an attachment",
|
comment=f"created an attachment",
|
||||||
verb="created",
|
verb="created",
|
||||||
actor=actor,
|
actor=actor,
|
||||||
field="attachment",
|
field="attachment",
|
||||||
@ -1010,7 +1010,7 @@ def delete_attachment_activity(
|
|||||||
issue_id=issue_id,
|
issue_id=issue_id,
|
||||||
project=project,
|
project=project,
|
||||||
workspace=project.workspace,
|
workspace=project.workspace,
|
||||||
comment=f"{actor.email} deleted the attachment",
|
comment=f"deleted the attachment",
|
||||||
verb="deleted",
|
verb="deleted",
|
||||||
actor=actor,
|
actor=actor,
|
||||||
field="attachment",
|
field="attachment",
|
||||||
|
@ -0,0 +1,101 @@
|
|||||||
|
# Generated by Django 4.2.3 on 2023-08-04 09:12
|
||||||
|
import string
|
||||||
|
import random
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
def generate_display_name(apps, schema_editor):
|
||||||
|
UserModel = apps.get_model("db", "User")
|
||||||
|
updated_users = []
|
||||||
|
for obj in UserModel.objects.all():
|
||||||
|
obj.display_name = (
|
||||||
|
obj.email.split("@")[0]
|
||||||
|
if len(obj.email.split("@"))
|
||||||
|
else "".join(random.choice(string.ascii_letters) for _ in range(6))
|
||||||
|
)
|
||||||
|
updated_users.append(obj)
|
||||||
|
UserModel.objects.bulk_update(updated_users, ["display_name"], batch_size=100)
|
||||||
|
|
||||||
|
|
||||||
|
def rectify_field_issue_activity(apps, schema_editor):
|
||||||
|
Model = apps.get_model("db", "IssueActivity")
|
||||||
|
updated_activity = []
|
||||||
|
for obj in Model.objects.filter(field="assignee"):
|
||||||
|
obj.field = "assignees"
|
||||||
|
updated_activity.append(obj)
|
||||||
|
|
||||||
|
Model.objects.bulk_update(updated_activity, ["field"], batch_size=100)
|
||||||
|
|
||||||
|
|
||||||
|
def update_assignee_issue_activity(apps, schema_editor):
|
||||||
|
Model = apps.get_model("db", "IssueActivity")
|
||||||
|
updated_activity = []
|
||||||
|
|
||||||
|
# Get all the users
|
||||||
|
User = apps.get_model("db", "User")
|
||||||
|
users = User.objects.values("id", "email", "display_name")
|
||||||
|
|
||||||
|
for obj in Model.objects.filter(field="assignees"):
|
||||||
|
if bool(obj.new_value) and not bool(obj.old_value):
|
||||||
|
# Get user from list
|
||||||
|
assigned_user = [
|
||||||
|
user for user in users if user.get("email") == obj.new_value
|
||||||
|
]
|
||||||
|
if assigned_user:
|
||||||
|
obj.new_value = assigned_user[0].get("display_name")
|
||||||
|
obj.new_identifier = assigned_user[0].get("id")
|
||||||
|
# Update the comment
|
||||||
|
words = obj.comment.split()
|
||||||
|
words[-1] = assigned_user[0].get("display_name")
|
||||||
|
obj.comment = " ".join(words)
|
||||||
|
|
||||||
|
if bool(obj.old_value) and not bool(obj.new_value):
|
||||||
|
# Get user from list
|
||||||
|
assigned_user = [
|
||||||
|
user for user in users if user.get("email") == obj.old_value
|
||||||
|
]
|
||||||
|
if assigned_user:
|
||||||
|
obj.old_value = assigned_user[0].get("display_name")
|
||||||
|
obj.old_identifier = assigned_user[0].get("id")
|
||||||
|
# Update the comment
|
||||||
|
words = obj.comment.split()
|
||||||
|
words[-1] = assigned_user[0].get("display_name")
|
||||||
|
obj.comment = " ".join(words)
|
||||||
|
|
||||||
|
updated_activity.append(obj)
|
||||||
|
|
||||||
|
Model.objects.bulk_update(
|
||||||
|
updated_activity,
|
||||||
|
["old_value", "new_value", "old_identifier", "new_identifier", "comment"],
|
||||||
|
batch_size=200,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def update_name_activity(apps, schema_editor):
|
||||||
|
Model = apps.get_model("db", "IssueActivity")
|
||||||
|
update_activity = []
|
||||||
|
for obj in Model.objects.filter(field="name"):
|
||||||
|
obj.comment = obj.comment.replace("start date", "name")
|
||||||
|
update_activity.append(obj)
|
||||||
|
|
||||||
|
Model.objects.bulk_update(update_activity, ["comment"], batch_size=1000)
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("db", "0040_projectmember_preferences_user_cover_image_and_more"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="user",
|
||||||
|
name="display_name",
|
||||||
|
field=models.CharField(default="", max_length=255),
|
||||||
|
),
|
||||||
|
migrations.RunPython(generate_display_name),
|
||||||
|
migrations.RunPython(rectify_field_issue_activity),
|
||||||
|
migrations.RunPython(update_assignee_issue_activity),
|
||||||
|
migrations.RunPython(update_name_activity),
|
||||||
|
]
|
@ -1,6 +1,7 @@
|
|||||||
# Python imports
|
# Python imports
|
||||||
from enum import unique
|
|
||||||
import uuid
|
import uuid
|
||||||
|
import string
|
||||||
|
import random
|
||||||
|
|
||||||
# Django imports
|
# Django imports
|
||||||
from django.db import models
|
from django.db import models
|
||||||
@ -18,6 +19,7 @@ from sentry_sdk import capture_exception
|
|||||||
from slack_sdk import WebClient
|
from slack_sdk import WebClient
|
||||||
from slack_sdk.errors import SlackApiError
|
from slack_sdk.errors import SlackApiError
|
||||||
|
|
||||||
|
|
||||||
def get_default_onboarding():
|
def get_default_onboarding():
|
||||||
return {
|
return {
|
||||||
"profile_complete": False,
|
"profile_complete": False,
|
||||||
@ -26,6 +28,7 @@ def get_default_onboarding():
|
|||||||
"workspace_join": False,
|
"workspace_join": False,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class User(AbstractBaseUser, PermissionsMixin):
|
class User(AbstractBaseUser, PermissionsMixin):
|
||||||
id = models.UUIDField(
|
id = models.UUIDField(
|
||||||
default=uuid.uuid4, unique=True, editable=False, db_index=True, primary_key=True
|
default=uuid.uuid4, unique=True, editable=False, db_index=True, primary_key=True
|
||||||
@ -81,6 +84,7 @@ class User(AbstractBaseUser, PermissionsMixin):
|
|||||||
role = models.CharField(max_length=300, null=True, blank=True)
|
role = models.CharField(max_length=300, null=True, blank=True)
|
||||||
is_bot = models.BooleanField(default=False)
|
is_bot = models.BooleanField(default=False)
|
||||||
theme = models.JSONField(default=dict)
|
theme = models.JSONField(default=dict)
|
||||||
|
display_name = models.CharField(max_length=255, default="")
|
||||||
is_tour_completed = models.BooleanField(default=False)
|
is_tour_completed = models.BooleanField(default=False)
|
||||||
onboarding_step = models.JSONField(default=get_default_onboarding)
|
onboarding_step = models.JSONField(default=get_default_onboarding)
|
||||||
|
|
||||||
@ -107,6 +111,13 @@ class User(AbstractBaseUser, PermissionsMixin):
|
|||||||
self.token = uuid.uuid4().hex + uuid.uuid4().hex
|
self.token = uuid.uuid4().hex + uuid.uuid4().hex
|
||||||
self.token_updated_at = timezone.now()
|
self.token_updated_at = timezone.now()
|
||||||
|
|
||||||
|
if not self.display_name:
|
||||||
|
self.display_name = (
|
||||||
|
self.email.split("@")[0]
|
||||||
|
if len(self.email.split("@"))
|
||||||
|
else "".join(random.choice(string.ascii_letters) for _ in range(6))
|
||||||
|
)
|
||||||
|
|
||||||
if self.is_superuser:
|
if self.is_superuser:
|
||||||
self.is_staff = True
|
self.is_staff = True
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user