dev: migrations (#4489)

* dev: estimates and pages migrations

* dev: favorite and user migrations

* chore: workspace base model

* chore: workspace user properties

* chore: removed unused variables

* chore: favorite view set changes

* chore: default sequence id

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
This commit is contained in:
Nikhil 2024-05-17 15:59:55 +05:30 committed by GitHub
parent 38f5ecbdf2
commit 85b54d2490
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 338 additions and 154 deletions

View File

@ -28,7 +28,6 @@ from .project import (
ProjectMemberSerializer, ProjectMemberSerializer,
ProjectMemberInviteSerializer, ProjectMemberInviteSerializer,
ProjectIdentifierSerializer, ProjectIdentifierSerializer,
ProjectFavoriteSerializer,
ProjectLiteSerializer, ProjectLiteSerializer,
ProjectMemberLiteSerializer, ProjectMemberLiteSerializer,
ProjectDeployBoardSerializer, ProjectDeployBoardSerializer,
@ -40,12 +39,10 @@ from .state import StateSerializer, StateLiteSerializer
from .view import ( from .view import (
GlobalViewSerializer, GlobalViewSerializer,
IssueViewSerializer, IssueViewSerializer,
IssueViewFavoriteSerializer,
) )
from .cycle import ( from .cycle import (
CycleSerializer, CycleSerializer,
CycleIssueSerializer, CycleIssueSerializer,
CycleFavoriteSerializer,
CycleWriteSerializer, CycleWriteSerializer,
CycleUserPropertiesSerializer, CycleUserPropertiesSerializer,
) )
@ -83,7 +80,6 @@ from .module import (
ModuleSerializer, ModuleSerializer,
ModuleIssueSerializer, ModuleIssueSerializer,
ModuleLinkSerializer, ModuleLinkSerializer,
ModuleFavoriteSerializer,
ModuleUserPropertiesSerializer, ModuleUserPropertiesSerializer,
) )
@ -96,7 +92,6 @@ from .page import (
PageLogSerializer, PageLogSerializer,
SubPageSerializer, SubPageSerializer,
PageDetailSerializer, PageDetailSerializer,
PageFavoriteSerializer,
) )
from .estimate import ( from .estimate import (

View File

@ -7,7 +7,6 @@ from .issue import IssueStateSerializer
from plane.db.models import ( from plane.db.models import (
Cycle, Cycle,
CycleIssue, CycleIssue,
CycleFavorite,
CycleUserProperties, CycleUserProperties,
) )
@ -93,20 +92,6 @@ class CycleIssueSerializer(BaseSerializer):
"cycle", "cycle",
] ]
class CycleFavoriteSerializer(BaseSerializer):
cycle_detail = CycleSerializer(source="cycle", read_only=True)
class Meta:
model = CycleFavorite
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"user",
]
class CycleUserPropertiesSerializer(BaseSerializer): class CycleUserPropertiesSerializer(BaseSerializer):
class Meta: class Meta:
model = CycleUserProperties model = CycleUserProperties

View File

@ -11,7 +11,6 @@ from plane.db.models import (
ModuleMember, ModuleMember,
ModuleIssue, ModuleIssue,
ModuleLink, ModuleLink,
ModuleFavorite,
ModuleUserProperties, ModuleUserProperties,
) )
@ -223,19 +222,6 @@ class ModuleDetailSerializer(ModuleSerializer):
fields = ModuleSerializer.Meta.fields + ["link_module", "sub_issues"] fields = ModuleSerializer.Meta.fields + ["link_module", "sub_issues"]
class ModuleFavoriteSerializer(BaseSerializer):
module_detail = ModuleFlatSerializer(source="module", read_only=True)
class Meta:
model = ModuleFavorite
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"user",
]
class ModuleUserPropertiesSerializer(BaseSerializer): class ModuleUserPropertiesSerializer(BaseSerializer):
class Meta: class Meta:
model = ModuleUserProperties model = ModuleUserProperties

View File

@ -6,7 +6,6 @@ from .base import BaseSerializer
from plane.db.models import ( from plane.db.models import (
Page, Page,
PageLog, PageLog,
PageFavorite,
PageLabel, PageLabel,
Label, Label,
) )
@ -141,17 +140,4 @@ class PageLogSerializer(BaseSerializer):
"workspace", "workspace",
"project", "project",
"page", "page",
] ]
class PageFavoriteSerializer(BaseSerializer):
page_detail = PageSerializer(source="page", read_only=True)
class Meta:
model = PageFavorite
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"user",
]

View File

@ -13,7 +13,6 @@ from plane.db.models import (
ProjectMember, ProjectMember,
ProjectMemberInvite, ProjectMemberInvite,
ProjectIdentifier, ProjectIdentifier,
ProjectFavorite,
ProjectDeployBoard, ProjectDeployBoard,
ProjectPublicMember, ProjectPublicMember,
) )
@ -197,16 +196,6 @@ class ProjectIdentifierSerializer(BaseSerializer):
fields = "__all__" fields = "__all__"
class ProjectFavoriteSerializer(BaseSerializer):
class Meta:
model = ProjectFavorite
fields = "__all__"
read_only_fields = [
"workspace",
"user",
]
class ProjectMemberLiteSerializer(BaseSerializer): class ProjectMemberLiteSerializer(BaseSerializer):
member = UserLiteSerializer(read_only=True) member = UserLiteSerializer(read_only=True)
is_subscribed = serializers.BooleanField(read_only=True) is_subscribed = serializers.BooleanField(read_only=True)

View File

@ -5,7 +5,7 @@ from rest_framework import serializers
from .base import BaseSerializer, DynamicBaseSerializer from .base import BaseSerializer, DynamicBaseSerializer
from .workspace import WorkspaceLiteSerializer from .workspace import WorkspaceLiteSerializer
from .project import ProjectLiteSerializer from .project import ProjectLiteSerializer
from plane.db.models import GlobalView, IssueView, IssueViewFavorite from plane.db.models import GlobalView, IssueView
from plane.utils.issue_filters import issue_filters from plane.utils.issue_filters import issue_filters
@ -72,16 +72,3 @@ class IssueViewSerializer(DynamicBaseSerializer):
validated_data["query"] = {} validated_data["query"] = {}
validated_data["query"] = issue_filters(query_params, "PATCH") validated_data["query"] = issue_filters(query_params, "PATCH")
return super().update(instance, validated_data) return super().update(instance, validated_data)
class IssueViewFavoriteSerializer(BaseSerializer):
view_detail = IssueViewSerializer(source="issue_view", read_only=True)
class Meta:
model = IssueViewFavorite
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"user",
]

View File

@ -24,7 +24,7 @@ from rest_framework.response import Response
from plane.app.permissions import ProjectEntityPermission from plane.app.permissions import ProjectEntityPermission
from plane.db.models import ( from plane.db.models import (
Cycle, Cycle,
CycleFavorite, UserFavorite,
Issue, Issue,
Label, Label,
User, User,
@ -42,9 +42,10 @@ class CycleArchiveUnarchiveEndpoint(BaseAPIView):
] ]
def get_queryset(self): def get_queryset(self):
favorite_subquery = CycleFavorite.objects.filter( favorite_subquery = UserFavorite.objects.filter(
user=self.request.user, user=self.request.user,
cycle_id=OuterRef("pk"), entity_type="cycle",
entity_identifier=OuterRef("pk"),
project_id=self.kwargs.get("project_id"), project_id=self.kwargs.get("project_id"),
workspace__slug=self.kwargs.get("slug"), workspace__slug=self.kwargs.get("slug"),
) )

View File

@ -30,7 +30,6 @@ from plane.app.permissions import (
ProjectLitePermission, ProjectLitePermission,
) )
from plane.app.serializers import ( from plane.app.serializers import (
CycleFavoriteSerializer,
CycleSerializer, CycleSerializer,
CycleUserPropertiesSerializer, CycleUserPropertiesSerializer,
CycleWriteSerializer, CycleWriteSerializer,
@ -38,8 +37,8 @@ from plane.app.serializers import (
from plane.bgtasks.issue_activites_task import issue_activity from plane.bgtasks.issue_activites_task import issue_activity
from plane.db.models import ( from plane.db.models import (
Cycle, Cycle,
CycleFavorite,
CycleIssue, CycleIssue,
UserFavorite,
CycleUserProperties, CycleUserProperties,
Issue, Issue,
Label, Label,
@ -67,9 +66,10 @@ class CycleViewSet(BaseViewSet):
) )
def get_queryset(self): def get_queryset(self):
favorite_subquery = CycleFavorite.objects.filter( favorite_subquery = UserFavorite.objects.filter(
user=self.request.user, user=self.request.user,
cycle_id=OuterRef("pk"), entity_identifier=OuterRef("pk"),
entity_type="cycle",
project_id=self.kwargs.get("project_id"), project_id=self.kwargs.get("project_id"),
workspace__slug=self.kwargs.get("slug"), workspace__slug=self.kwargs.get("slug"),
) )
@ -241,7 +241,7 @@ class CycleViewSet(BaseViewSet):
"backlog_issues", "backlog_issues",
"assignee_ids", "assignee_ids",
"status", "status",
"created_by" "created_by",
) )
if data: if data:
@ -754,8 +754,7 @@ class CycleDateCheckEndpoint(BaseAPIView):
class CycleFavoriteViewSet(BaseViewSet): class CycleFavoriteViewSet(BaseViewSet):
serializer_class = CycleFavoriteSerializer model = UserFavorite
model = CycleFavorite
def get_queryset(self): def get_queryset(self):
return self.filter_queryset( return self.filter_queryset(
@ -767,18 +766,21 @@ class CycleFavoriteViewSet(BaseViewSet):
) )
def create(self, request, slug, project_id): def create(self, request, slug, project_id):
serializer = CycleFavoriteSerializer(data=request.data) _ = UserFavorite.objects.create(
if serializer.is_valid(): project_id=project_id,
serializer.save(user=request.user, project_id=project_id) user=request.user,
return Response(serializer.data, status=status.HTTP_201_CREATED) entity_type="cycle",
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) entity_identifier=request.data.get("cycle"),
)
return Response(status=status.HTTP_204_NO_CONTENT)
def destroy(self, request, slug, project_id, cycle_id): def destroy(self, request, slug, project_id, cycle_id):
cycle_favorite = CycleFavorite.objects.get( cycle_favorite = UserFavorite.objects.get(
project=project_id, project=project_id,
entity_type="cycle",
user=request.user, user=request.user,
workspace__slug=slug, workspace__slug=slug,
cycle_id=cycle_id, entity_identifier=cycle_id,
) )
cycle_favorite.delete() cycle_favorite.delete()
return Response(status=status.HTTP_204_NO_CONTENT) return Response(status=status.HTTP_204_NO_CONTENT)

View File

@ -25,12 +25,7 @@ from plane.app.permissions import (
from plane.app.serializers import ( from plane.app.serializers import (
ModuleDetailSerializer, ModuleDetailSerializer,
) )
from plane.db.models import ( from plane.db.models import Issue, Module, ModuleLink, UserFavorite
Issue,
Module,
ModuleFavorite,
ModuleLink,
)
from plane.utils.analytics_plot import burndown_plot from plane.utils.analytics_plot import burndown_plot
from plane.utils.user_timezone_converter import user_timezone_converter from plane.utils.user_timezone_converter import user_timezone_converter
@ -46,9 +41,10 @@ class ModuleArchiveUnarchiveEndpoint(BaseAPIView):
] ]
def get_queryset(self): def get_queryset(self):
favorite_subquery = ModuleFavorite.objects.filter( favorite_subquery = UserFavorite.objects.filter(
user=self.request.user, user=self.request.user,
module_id=OuterRef("pk"), entity_identifier=OuterRef("pk"),
entity_type="module",
project_id=self.kwargs.get("project_id"), project_id=self.kwargs.get("project_id"),
workspace__slug=self.kwargs.get("slug"), workspace__slug=self.kwargs.get("slug"),
) )

View File

@ -32,7 +32,6 @@ from plane.app.permissions import (
) )
from plane.app.serializers import ( from plane.app.serializers import (
ModuleDetailSerializer, ModuleDetailSerializer,
ModuleFavoriteSerializer,
ModuleLinkSerializer, ModuleLinkSerializer,
ModuleSerializer, ModuleSerializer,
ModuleUserPropertiesSerializer, ModuleUserPropertiesSerializer,
@ -42,7 +41,7 @@ from plane.bgtasks.issue_activites_task import issue_activity
from plane.db.models import ( from plane.db.models import (
Issue, Issue,
Module, Module,
ModuleFavorite, UserFavorite,
ModuleIssue, ModuleIssue,
ModuleLink, ModuleLink,
ModuleUserProperties, ModuleUserProperties,
@ -69,9 +68,10 @@ class ModuleViewSet(BaseViewSet):
) )
def get_queryset(self): def get_queryset(self):
favorite_subquery = ModuleFavorite.objects.filter( favorite_subquery = UserFavorite.objects.filter(
user=self.request.user, user=self.request.user,
module_id=OuterRef("pk"), entity_type="module",
entity_identifier=OuterRef("pk"),
project_id=self.kwargs.get("project_id"), project_id=self.kwargs.get("project_id"),
workspace__slug=self.kwargs.get("slug"), workspace__slug=self.kwargs.get("slug"),
) )
@ -554,8 +554,7 @@ class ModuleLinkViewSet(BaseViewSet):
class ModuleFavoriteViewSet(BaseViewSet): class ModuleFavoriteViewSet(BaseViewSet):
serializer_class = ModuleFavoriteSerializer model = UserFavorite
model = ModuleFavorite
def get_queryset(self): def get_queryset(self):
return self.filter_queryset( return self.filter_queryset(
@ -567,18 +566,21 @@ class ModuleFavoriteViewSet(BaseViewSet):
) )
def create(self, request, slug, project_id): def create(self, request, slug, project_id):
serializer = ModuleFavoriteSerializer(data=request.data) _ = UserFavorite.objects.create(
if serializer.is_valid(): project_id=project_id,
serializer.save(user=request.user, project_id=project_id) user=request.user,
return Response(serializer.data, status=status.HTTP_201_CREATED) entity_type="module",
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) entity_identifier=request.data.get("module"),
)
return Response(status=status.HTTP_204_NO_CONTENT)
def destroy(self, request, slug, project_id, module_id): def destroy(self, request, slug, project_id, module_id):
module_favorite = ModuleFavorite.objects.get( module_favorite = UserFavorite.objects.get(
project=project_id, project_id=project_id,
user=request.user, user=request.user,
workspace__slug=slug, workspace__slug=slug,
module_id=module_id, entity_type="module",
entity_identifier=module_id,
) )
module_favorite.delete() module_favorite.delete()
return Response(status=status.HTTP_204_NO_CONTENT) return Response(status=status.HTTP_204_NO_CONTENT)

View File

@ -15,7 +15,6 @@ from rest_framework.response import Response
from plane.app.permissions import ProjectEntityPermission from plane.app.permissions import ProjectEntityPermission
from plane.app.serializers import ( from plane.app.serializers import (
PageFavoriteSerializer,
PageLogSerializer, PageLogSerializer,
PageSerializer, PageSerializer,
SubPageSerializer, SubPageSerializer,
@ -23,8 +22,8 @@ from plane.app.serializers import (
) )
from plane.db.models import ( from plane.db.models import (
Page, Page,
PageFavorite,
PageLog, PageLog,
UserFavorite,
ProjectMember, ProjectMember,
) )
@ -61,9 +60,10 @@ class PageViewSet(BaseViewSet):
] ]
def get_queryset(self): def get_queryset(self):
subquery = PageFavorite.objects.filter( subquery = UserFavorite.objects.filter(
user=self.request.user, user=self.request.user,
page_id=OuterRef("pk"), entity_type="page",
entity_identifier=OuterRef("pk"),
project_id=self.kwargs.get("project_id"), project_id=self.kwargs.get("project_id"),
workspace__slug=self.kwargs.get("slug"), workspace__slug=self.kwargs.get("slug"),
) )
@ -303,23 +303,24 @@ class PageFavoriteViewSet(BaseViewSet):
ProjectEntityPermission, ProjectEntityPermission,
] ]
serializer_class = PageFavoriteSerializer model = UserFavorite
model = PageFavorite
def create(self, request, slug, project_id, pk): def create(self, request, slug, project_id, pk):
_ = PageFavorite.objects.create( _ = UserFavorite.objects.create(
project_id=project_id, project_id=project_id,
page_id=pk, entity_identifier=pk,
entity_type="page",
user=request.user, user=request.user,
) )
return Response(status=status.HTTP_204_NO_CONTENT) return Response(status=status.HTTP_204_NO_CONTENT)
def destroy(self, request, slug, project_id, pk): def destroy(self, request, slug, project_id, pk):
page_favorite = PageFavorite.objects.get( page_favorite = UserFavorite.objects.get(
project=project_id, project=project_id,
user=request.user, user=request.user,
workspace__slug=slug, workspace__slug=slug,
page_id=pk, entity_identifier=pk,
entity_type="page",
) )
page_favorite.delete() page_favorite.delete()
return Response(status=status.HTTP_204_NO_CONTENT) return Response(status=status.HTTP_204_NO_CONTENT)

View File

@ -28,7 +28,6 @@ from plane.app.views.base import BaseViewSet, BaseAPIView
from plane.app.serializers import ( from plane.app.serializers import (
ProjectSerializer, ProjectSerializer,
ProjectListSerializer, ProjectListSerializer,
ProjectFavoriteSerializer,
ProjectDeployBoardSerializer, ProjectDeployBoardSerializer,
) )
@ -42,7 +41,7 @@ from plane.db.models import (
ProjectMember, ProjectMember,
Workspace, Workspace,
State, State,
ProjectFavorite, UserFavorite,
ProjectIdentifier, ProjectIdentifier,
Module, Module,
Cycle, Cycle,
@ -90,10 +89,11 @@ class ProjectViewSet(BaseViewSet):
) )
.annotate( .annotate(
is_favorite=Exists( is_favorite=Exists(
ProjectFavorite.objects.filter( UserFavorite.objects.filter(
user=self.request.user, user=self.request.user,
entity_identifier=OuterRef("pk"),
entity_type="project",
project_id=OuterRef("pk"), project_id=OuterRef("pk"),
workspace__slug=self.kwargs.get("slug"),
) )
) )
) )
@ -560,8 +560,7 @@ class ProjectUserViewsEndpoint(BaseAPIView):
class ProjectFavoritesViewSet(BaseViewSet): class ProjectFavoritesViewSet(BaseViewSet):
serializer_class = ProjectFavoriteSerializer model = UserFavorite
model = ProjectFavorite
def get_queryset(self): def get_queryset(self):
return self.filter_queryset( return self.filter_queryset(
@ -579,15 +578,21 @@ class ProjectFavoritesViewSet(BaseViewSet):
serializer.save(user=self.request.user) serializer.save(user=self.request.user)
def create(self, request, slug): def create(self, request, slug):
serializer = ProjectFavoriteSerializer(data=request.data) _ = UserFavorite.objects.create(
if serializer.is_valid(): user=request.user,
serializer.save(user=request.user) entity_type="project",
return Response(serializer.data, status=status.HTTP_201_CREATED) entity_identifier=request.data.get("project"),
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) project_id=request.data.get("project"),
)
return Response(status=status.HTTP_204_NO_CONTENT)
def destroy(self, request, slug, project_id): def destroy(self, request, slug, project_id):
project_favorite = ProjectFavorite.objects.get( project_favorite = UserFavorite.objects.get(
project=project_id, user=request.user, workspace__slug=slug entity_identifier=project_id,
entity_type="project",
project=project_id,
user=request.user,
workspace__slug=slug,
) )
project_favorite.delete() project_favorite.delete()
return Response(status=status.HTTP_204_NO_CONTENT) return Response(status=status.HTTP_204_NO_CONTENT)

View File

@ -27,7 +27,6 @@ from .. import BaseViewSet
from plane.app.serializers import ( from plane.app.serializers import (
IssueViewSerializer, IssueViewSerializer,
IssueSerializer, IssueSerializer,
IssueViewFavoriteSerializer,
) )
from plane.app.permissions import ( from plane.app.permissions import (
WorkspaceEntityPermission, WorkspaceEntityPermission,
@ -37,7 +36,7 @@ from plane.db.models import (
Workspace, Workspace,
IssueView, IssueView,
Issue, Issue,
IssueViewFavorite, UserFavorite,
IssueLink, IssueLink,
IssueAttachment, IssueAttachment,
) )
@ -273,9 +272,10 @@ class IssueViewViewSet(BaseViewSet):
serializer.save(project_id=self.kwargs.get("project_id")) serializer.save(project_id=self.kwargs.get("project_id"))
def get_queryset(self): def get_queryset(self):
subquery = IssueViewFavorite.objects.filter( subquery = UserFavorite.objects.filter(
user=self.request.user, user=self.request.user,
view_id=OuterRef("pk"), entity_identifier=OuterRef("pk"),
entity_type="view",
project_id=self.kwargs.get("project_id"), project_id=self.kwargs.get("project_id"),
workspace__slug=self.kwargs.get("slug"), workspace__slug=self.kwargs.get("slug"),
) )
@ -310,8 +310,7 @@ class IssueViewViewSet(BaseViewSet):
class IssueViewFavoriteViewSet(BaseViewSet): class IssueViewFavoriteViewSet(BaseViewSet):
serializer_class = IssueViewFavoriteSerializer model = UserFavorite
model = IssueViewFavorite
def get_queryset(self): def get_queryset(self):
return self.filter_queryset( return self.filter_queryset(
@ -323,18 +322,21 @@ class IssueViewFavoriteViewSet(BaseViewSet):
) )
def create(self, request, slug, project_id): def create(self, request, slug, project_id):
serializer = IssueViewFavoriteSerializer(data=request.data) _ = UserFavorite.objects.create(
if serializer.is_valid(): user=request.user,
serializer.save(user=request.user, project_id=project_id) entity_identifier=request.data.get("view"),
return Response(serializer.data, status=status.HTTP_201_CREATED) entity_type="view",
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) project_id=project_id,
)
return Response(status=status.HTTP_204_NO_CONTENT)
def destroy(self, request, slug, project_id, view_id): def destroy(self, request, slug, project_id, view_id):
view_favorite = IssueViewFavorite.objects.get( view_favorite = UserFavorite.objects.get(
project=project_id, project=project_id,
user=request.user, user=request.user,
workspace__slug=slug, workspace__slug=slug,
view_id=view_id, entity_type="view",
entity_identifier=view_id,
) )
view_favorite.delete() view_favorite.delete()
return Response(status=status.HTTP_204_NO_CONTENT) return Response(status=status.HTTP_204_NO_CONTENT)

View File

@ -7,7 +7,6 @@ from zxcvbn import zxcvbn
## Module imports ## Module imports
from plane.app.serializers import ( from plane.app.serializers import (
ChangePasswordSerializer,
UserSerializer, UserSerializer,
) )
from plane.authentication.utils.login import user_login from plane.authentication.utils.login import user_login

View File

@ -45,6 +45,51 @@ def migrate_user_profile(apps, schema_editor):
) )
def user_favorite_migration(apps, schema_editor):
# Import the models
CycleFavorite = apps.get_model("db", "CycleFavorite")
ModuleFavorite = apps.get_model("db", "ModuleFavorite")
ProjectFavorite = apps.get_model("db", "ProjectFavorite")
PageFavorite = apps.get_model("db", "PageFavorite")
IssueViewFavorite = apps.get_model("db", "IssueViewFavorite")
UserFavorite = apps.get_model("db", "UserFavorite")
# List of source models
source_models = [
CycleFavorite,
ModuleFavorite,
ProjectFavorite,
PageFavorite,
IssueViewFavorite,
]
entity_mapper = {
"CycleFavorite": "cycle",
"ModuleFavorite": "module",
"ProjectFavorite": "project",
"PageFavorite": "page",
"IssueViewFavorite": "view",
}
for source_model in source_models:
entity_type = entity_mapper[source_model.__name__]
UserFavorite.objects.bulk_create(
[
UserFavorite(
user_id=obj.user_id,
entity_type=entity_type,
entity_identifier=str(getattr(obj, entity_type).id),
project_id=obj.project_id,
workspace_id=obj.workspace_id,
created_by_id=obj.created_by_id,
updated_by_id=obj.updated_by_id,
)
for obj in source_model.objects.all().iterator()
],
batch_size=1000,
)
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
@ -262,9 +307,156 @@ class Migration(migrations.Migration):
name="logo_props", name="logo_props",
field=models.JSONField(default=dict), field=models.JSONField(default=dict),
), ),
# Pages
migrations.AddField( migrations.AddField(
model_name="page", model_name="page",
name="logo_props", name="logo_props",
field=models.JSONField(default=dict), field=models.JSONField(default=dict),
), ),
migrations.AddField(
model_name="page",
name="description_binary",
field=models.BinaryField(null=True),
),
migrations.AlterField(
model_name="page",
name="name",
field=models.CharField(blank=True, max_length=255),
),
# Estimates
migrations.AddField(
model_name="estimate",
name="type",
field=models.CharField(default="Categories", max_length=255),
),
migrations.AlterField(
model_name="estimatepoint",
name="key",
field=models.IntegerField(
default=0,
validators=[
django.core.validators.MinValueValidator(0),
django.core.validators.MaxValueValidator(12),
],
),
),
migrations.AlterField(
model_name="issue",
name="estimate_point",
field=models.IntegerField(
blank=True,
null=True,
validators=[
django.core.validators.MinValueValidator(0),
django.core.validators.MaxValueValidator(12),
],
),
),
# workspace user properties
migrations.AlterModelTable(
name="workspaceuserproperties",
table="workspace_user_properties",
),
# Favorites
migrations.CreateModel(
name="UserFavorite",
fields=[
(
"created_at",
models.DateTimeField(
auto_now_add=True, verbose_name="Created At"
),
),
(
"updated_at",
models.DateTimeField(
auto_now=True, verbose_name="Last Modified At"
),
),
(
"id",
models.UUIDField(
db_index=True,
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
unique=True,
),
),
("entity_type", models.CharField(max_length=100)),
("entity_identifier", models.UUIDField(blank=True, null=True)),
(
"name",
models.CharField(blank=True, max_length=255, null=True),
),
("is_folder", models.BooleanField(default=False)),
("sequence", models.IntegerField(default=65535)),
(
"created_by",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="%(class)s_created_by",
to=settings.AUTH_USER_MODEL,
verbose_name="Created By",
),
),
(
"parent",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="parent_folder",
to="db.userfavorite",
),
),
(
"project",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="project_%(class)s",
to="db.project",
),
),
(
"updated_by",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="%(class)s_updated_by",
to=settings.AUTH_USER_MODEL,
verbose_name="Last Modified By",
),
),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="favorites",
to=settings.AUTH_USER_MODEL,
),
),
(
"workspace",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="workspace_%(class)s",
to="db.workspace",
),
),
],
options={
"verbose_name": "User Favorite",
"verbose_name_plural": "User Favorites",
"db_table": "user_favorites",
"ordering": ("-created_at",),
"unique_together": {
("entity_type", "user", "entity_identifier")
},
},
),
migrations.RunPython(user_favorite_migration),
] ]

View File

@ -98,3 +98,5 @@ from .exporter import ExporterHistory
from .webhook import Webhook, WebhookLog from .webhook import Webhook, WebhookLog
from .dashboard import Dashboard, DashboardWidget, Widget from .dashboard import Dashboard, DashboardWidget, Widget
from .favorite import UserFavorite

View File

@ -11,6 +11,7 @@ class Estimate(ProjectBaseModel):
description = models.TextField( description = models.TextField(
verbose_name="Estimate Description", blank=True verbose_name="Estimate Description", blank=True
) )
type = models.CharField(max_length=255, default="Categories")
def __str__(self): def __str__(self):
"""Return name of the estimate""" """Return name of the estimate"""
@ -31,7 +32,7 @@ class EstimatePoint(ProjectBaseModel):
related_name="points", related_name="points",
) )
key = models.IntegerField( key = models.IntegerField(
default=0, validators=[MinValueValidator(0), MaxValueValidator(7)] default=0, validators=[MinValueValidator(0), MaxValueValidator(12)]
) )
description = models.TextField(blank=True) description = models.TextField(blank=True)
value = models.CharField(max_length=20) value = models.CharField(max_length=20)

View File

@ -0,0 +1,52 @@
from django.conf import settings
# Django imports
from django.db import models
# Module imports
from .workspace import WorkspaceBaseModel
class UserFavorite(WorkspaceBaseModel):
"""_summary_
UserFavorite (model): To store all the favorites of the user
"""
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="favorites",
)
entity_type = models.CharField(max_length=100)
entity_identifier = models.UUIDField(null=True, blank=True)
name = models.CharField(max_length=255, blank=True, null=True)
is_folder = models.BooleanField(default=False)
sequence = models.IntegerField(default=65535)
parent = models.ForeignKey(
"self",
on_delete=models.CASCADE,
null=True,
blank=True,
related_name="parent_folder",
)
class Meta:
unique_together = ["entity_type", "user", "entity_identifier"]
verbose_name = "User Favorite"
verbose_name_plural = "User Favorites"
db_table = "user_favorites"
ordering = ("-created_at",)
def save(self, *args, **kwargs):
if self._state.adding:
largest_sort_order = UserFavorite.objects.filter(
workspace=self.workspace
).aggregate(largest=models.Max("sort_order"))["largest"]
if largest_sort_order is not None:
self.sort_order = largest_sort_order + 10000
super(UserFavorite, self).save(*args, **kwargs)
def __str__(self):
"""Return user and the entity type"""
return f"{self.user.email} <{self.entity_type}>"

View File

@ -120,7 +120,7 @@ class Issue(ProjectBaseModel):
related_name="state_issue", related_name="state_issue",
) )
estimate_point = models.IntegerField( estimate_point = models.IntegerField(
validators=[MinValueValidator(0), MaxValueValidator(7)], validators=[MinValueValidator(0), MaxValueValidator(12)],
null=True, null=True,
blank=True, blank=True,
) )

View File

@ -16,7 +16,7 @@ def get_view_props():
class Page(ProjectBaseModel): class Page(ProjectBaseModel):
name = models.CharField(max_length=255) name = models.CharField(max_length=255, blank=True)
description = models.JSONField(default=dict, blank=True) description = models.JSONField(default=dict, blank=True)
description_html = models.TextField(blank=True, default="<p></p>") description_html = models.TextField(blank=True, default="<p></p>")
description_stripped = models.TextField(blank=True, null=True) description_stripped = models.TextField(blank=True, null=True)
@ -43,6 +43,7 @@ class Page(ProjectBaseModel):
is_locked = models.BooleanField(default=False) is_locked = models.BooleanField(default=False)
view_props = models.JSONField(default=get_view_props) view_props = models.JSONField(default=get_view_props)
logo_props = models.JSONField(default=dict) logo_props = models.JSONField(default=dict)
description_binary = models.BinaryField(null=True)
class Meta: class Meta:
verbose_name = "Page" verbose_name = "Page"

View File

@ -325,7 +325,7 @@ class WorkspaceUserProperties(BaseModel):
unique_together = ["workspace", "user"] unique_together = ["workspace", "user"]
verbose_name = "Workspace User Property" verbose_name = "Workspace User Property"
verbose_name_plural = "Workspace User Property" verbose_name_plural = "Workspace User Property"
db_table = "Workspace_user_properties" db_table = "workspace_user_properties"
ordering = ("-created_at",) ordering = ("-created_at",)
def __str__(self): def __str__(self):