Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a02cef11a6 |
@@ -9,7 +9,6 @@ from rest_framework import serializers
|
||||
# Module imports
|
||||
from plane.db.models import (
|
||||
Issue,
|
||||
IssueType,
|
||||
IssueActivity,
|
||||
IssueAssignee,
|
||||
FileAsset,
|
||||
@@ -58,9 +57,6 @@ class IssueSerializer(BaseSerializer):
|
||||
write_only=True,
|
||||
required=False,
|
||||
)
|
||||
type_id = serializers.PrimaryKeyRelatedField(
|
||||
source="type", queryset=IssueType.objects.all(), required=False, allow_null=True
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Issue
|
||||
@@ -151,14 +147,7 @@ class IssueSerializer(BaseSerializer):
|
||||
workspace_id = self.context["workspace_id"]
|
||||
default_assignee_id = self.context["default_assignee_id"]
|
||||
|
||||
issue_type = validated_data.pop("type", None)
|
||||
|
||||
if not issue_type:
|
||||
# Get default issue type
|
||||
issue_type = IssueType.objects.filter(project_issue_types__project_id=project_id, is_default=True).first()
|
||||
issue_type = issue_type
|
||||
|
||||
issue = Issue.objects.create(**validated_data, project_id=project_id, type=issue_type)
|
||||
issue = Issue.objects.create(**validated_data, project_id=project_id)
|
||||
|
||||
# Issue Audit Users
|
||||
created_by_id = issue.created_by_id
|
||||
|
||||
@@ -15,7 +15,6 @@ from .workspace import (
|
||||
WorkSpaceMemberSerializer,
|
||||
WorkSpaceMemberInviteSerializer,
|
||||
WorkspaceLiteSerializer,
|
||||
WorkspaceThemeSerializer,
|
||||
WorkspaceMemberAdminSerializer,
|
||||
WorkspaceMemberMeSerializer,
|
||||
WorkspaceUserPropertiesSerializer,
|
||||
@@ -89,7 +88,6 @@ from .module import (
|
||||
|
||||
from .api import APITokenSerializer, APITokenReadSerializer
|
||||
|
||||
from .importer import ImporterSerializer
|
||||
|
||||
from .page import (
|
||||
PageSerializer,
|
||||
@@ -114,8 +112,6 @@ from .intake import (
|
||||
IntakeIssueDetailSerializer,
|
||||
)
|
||||
|
||||
from .analytic import AnalyticViewSerializer
|
||||
|
||||
from .notification import NotificationSerializer, UserNotificationPreferenceSerializer
|
||||
|
||||
from .exporter import ExporterHistorySerializer
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
from .base import BaseSerializer
|
||||
from plane.db.models import AnalyticView
|
||||
from plane.utils.issue_filters import issue_filters
|
||||
|
||||
|
||||
class AnalyticViewSerializer(BaseSerializer):
|
||||
class Meta:
|
||||
model = AnalyticView
|
||||
fields = "__all__"
|
||||
read_only_fields = ["workspace", "query"]
|
||||
|
||||
def create(self, validated_data):
|
||||
query_params = validated_data.get("query_dict", {})
|
||||
if bool(query_params):
|
||||
validated_data["query"] = issue_filters(query_params, "POST")
|
||||
else:
|
||||
validated_data["query"] = {}
|
||||
return AnalyticView.objects.create(**validated_data)
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
query_params = validated_data.get("query_data", {})
|
||||
if bool(query_params):
|
||||
validated_data["query"] = issue_filters(query_params, "POST")
|
||||
else:
|
||||
validated_data["query"] = {}
|
||||
validated_data["query"] = issue_filters(query_params, "PATCH")
|
||||
return super().update(instance, validated_data)
|
||||
@@ -1,16 +0,0 @@
|
||||
# Module imports
|
||||
from .base import BaseSerializer
|
||||
from .user import UserLiteSerializer
|
||||
from .project import ProjectLiteSerializer
|
||||
from .workspace import WorkspaceLiteSerializer
|
||||
from plane.db.models import Importer
|
||||
|
||||
|
||||
class ImporterSerializer(BaseSerializer):
|
||||
initiated_by_detail = UserLiteSerializer(source="initiated_by", read_only=True)
|
||||
project_detail = ProjectLiteSerializer(source="project", read_only=True)
|
||||
workspace_detail = WorkspaceLiteSerializer(source="workspace", read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Importer
|
||||
fields = "__all__"
|
||||
@@ -10,7 +10,6 @@ from plane.utils.content_validator import (
|
||||
)
|
||||
from plane.db.models import (
|
||||
Page,
|
||||
PageLabel,
|
||||
Label,
|
||||
ProjectPage,
|
||||
Project,
|
||||
@@ -55,7 +54,6 @@ class PageSerializer(BaseSerializer):
|
||||
read_only_fields = ["workspace", "owned_by"]
|
||||
|
||||
def create(self, validated_data):
|
||||
labels = validated_data.pop("labels", None)
|
||||
project_id = self.context["project_id"]
|
||||
owned_by_id = self.context["owned_by_id"]
|
||||
description = self.context["description"]
|
||||
@@ -84,41 +82,9 @@ class PageSerializer(BaseSerializer):
|
||||
updated_by_id=page.updated_by_id,
|
||||
)
|
||||
|
||||
# Create page labels
|
||||
if labels is not None:
|
||||
PageLabel.objects.bulk_create(
|
||||
[
|
||||
PageLabel(
|
||||
label=label,
|
||||
page=page,
|
||||
workspace_id=page.workspace_id,
|
||||
created_by_id=page.created_by_id,
|
||||
updated_by_id=page.updated_by_id,
|
||||
)
|
||||
for label in labels
|
||||
],
|
||||
batch_size=10,
|
||||
)
|
||||
return page
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
labels = validated_data.pop("labels", None)
|
||||
if labels is not None:
|
||||
PageLabel.objects.filter(page=instance).delete()
|
||||
PageLabel.objects.bulk_create(
|
||||
[
|
||||
PageLabel(
|
||||
label=label,
|
||||
page=instance,
|
||||
workspace_id=instance.workspace_id,
|
||||
created_by_id=instance.created_by_id,
|
||||
updated_by_id=instance.updated_by_id,
|
||||
)
|
||||
for label in labels
|
||||
],
|
||||
batch_size=10,
|
||||
)
|
||||
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ from plane.db.models import (
|
||||
Workspace,
|
||||
WorkspaceMember,
|
||||
WorkspaceMemberInvite,
|
||||
WorkspaceTheme,
|
||||
WorkspaceUserProperties,
|
||||
WorkspaceUserLink,
|
||||
UserRecentVisit,
|
||||
@@ -125,13 +124,6 @@ class WorkSpaceMemberInviteSerializer(BaseSerializer):
|
||||
]
|
||||
|
||||
|
||||
class WorkspaceThemeSerializer(BaseSerializer):
|
||||
class Meta:
|
||||
model = WorkspaceTheme
|
||||
fields = "__all__"
|
||||
read_only_fields = ["workspace", "actor"]
|
||||
|
||||
|
||||
class WorkspaceUserPropertiesSerializer(BaseSerializer):
|
||||
class Meta:
|
||||
model = WorkspaceUserProperties
|
||||
|
||||
@@ -3,8 +3,6 @@ from django.urls import path
|
||||
|
||||
from plane.app.views import (
|
||||
AnalyticsEndpoint,
|
||||
AnalyticViewViewset,
|
||||
SavedAnalyticEndpoint,
|
||||
ExportAnalyticsEndpoint,
|
||||
AdvanceAnalyticsEndpoint,
|
||||
AdvanceAnalyticsStatsEndpoint,
|
||||
@@ -23,21 +21,6 @@ urlpatterns = [
|
||||
AnalyticsEndpoint.as_view(),
|
||||
name="plane-analytics",
|
||||
),
|
||||
path(
|
||||
"workspaces/<str:slug>/analytic-view/",
|
||||
AnalyticViewViewset.as_view({"get": "list", "post": "create"}),
|
||||
name="analytic-view",
|
||||
),
|
||||
path(
|
||||
"workspaces/<str:slug>/analytic-view/<uuid:pk>/",
|
||||
AnalyticViewViewset.as_view({"get": "retrieve", "patch": "partial_update", "delete": "destroy"}),
|
||||
name="analytic-view",
|
||||
),
|
||||
path(
|
||||
"workspaces/<str:slug>/saved-analytic-view/<uuid:analytic_id>/",
|
||||
SavedAnalyticEndpoint.as_view(),
|
||||
name="saved-analytic-view",
|
||||
),
|
||||
path(
|
||||
"workspaces/<str:slug>/export-analytics/",
|
||||
ExportAnalyticsEndpoint.as_view(),
|
||||
|
||||
@@ -11,7 +11,6 @@ from plane.app.views import (
|
||||
WorkspaceMemberUserViewsEndpoint,
|
||||
WorkSpaceAvailabilityCheckEndpoint,
|
||||
UserLastProjectWithWorkspaceEndpoint,
|
||||
WorkspaceThemeViewSet,
|
||||
WorkspaceUserProfileStatsEndpoint,
|
||||
WorkspaceUserActivityEndpoint,
|
||||
WorkspaceUserProfileEndpoint,
|
||||
@@ -115,16 +114,6 @@ urlpatterns = [
|
||||
WorkspaceMemberUserViewsEndpoint.as_view(),
|
||||
name="workspace-member-views-details",
|
||||
),
|
||||
path(
|
||||
"workspaces/<str:slug>/workspace-themes/",
|
||||
WorkspaceThemeViewSet.as_view({"get": "list", "post": "create"}),
|
||||
name="workspace-themes",
|
||||
),
|
||||
path(
|
||||
"workspaces/<str:slug>/workspace-themes/<uuid:pk>/",
|
||||
WorkspaceThemeViewSet.as_view({"get": "retrieve", "patch": "partial_update", "delete": "destroy"}),
|
||||
name="workspace-themes",
|
||||
),
|
||||
path(
|
||||
"workspaces/<str:slug>/user-stats/<uuid:user_id>/",
|
||||
WorkspaceUserProfileStatsEndpoint.as_view(),
|
||||
|
||||
@@ -35,7 +35,6 @@ from .workspace.base import (
|
||||
UserWorkSpacesEndpoint,
|
||||
WorkSpaceAvailabilityCheckEndpoint,
|
||||
UserWorkspaceDashboardEndpoint,
|
||||
WorkspaceThemeViewSet,
|
||||
ExportWorkspaceUserActivityEndpoint,
|
||||
)
|
||||
|
||||
@@ -194,8 +193,6 @@ from .intake.base import (
|
||||
|
||||
from .analytic.base import (
|
||||
AnalyticsEndpoint,
|
||||
AnalyticViewViewset,
|
||||
SavedAnalyticEndpoint,
|
||||
ExportAnalyticsEndpoint,
|
||||
DefaultAnalyticsEndpoint,
|
||||
ProjectStatsEndpoint,
|
||||
|
||||
@@ -11,14 +11,10 @@ from rest_framework import status
|
||||
from rest_framework.response import Response
|
||||
|
||||
# Module imports
|
||||
from plane.app.permissions import WorkSpaceAdminPermission
|
||||
from plane.app.serializers import AnalyticViewSerializer
|
||||
from plane.app.views.base import BaseAPIView, BaseViewSet
|
||||
from plane.app.views.base import BaseAPIView
|
||||
from plane.bgtasks.analytic_plot_export import analytic_export_task
|
||||
from plane.db.models import (
|
||||
AnalyticView,
|
||||
Issue,
|
||||
Workspace,
|
||||
Project,
|
||||
ProjectMember,
|
||||
Cycle,
|
||||
@@ -186,45 +182,6 @@ class AnalyticsEndpoint(BaseAPIView):
|
||||
)
|
||||
|
||||
|
||||
class AnalyticViewViewset(BaseViewSet):
|
||||
permission_classes = [WorkSpaceAdminPermission]
|
||||
model = AnalyticView
|
||||
serializer_class = AnalyticViewSerializer
|
||||
|
||||
def perform_create(self, serializer):
|
||||
workspace = Workspace.objects.get(slug=self.kwargs.get("slug"))
|
||||
serializer.save(workspace_id=workspace.id)
|
||||
|
||||
def get_queryset(self):
|
||||
return self.filter_queryset(super().get_queryset().filter(workspace__slug=self.kwargs.get("slug")))
|
||||
|
||||
|
||||
class SavedAnalyticEndpoint(BaseAPIView):
|
||||
@allow_permission([ROLE.ADMIN, ROLE.MEMBER], level="WORKSPACE")
|
||||
def get(self, request, slug, analytic_id):
|
||||
analytic_view = AnalyticView.objects.get(pk=analytic_id, workspace__slug=slug)
|
||||
|
||||
filter = analytic_view.query
|
||||
queryset = Issue.issue_objects.filter(**filter)
|
||||
|
||||
x_axis = analytic_view.query_dict.get("x_axis", False)
|
||||
y_axis = analytic_view.query_dict.get("y_axis", False)
|
||||
|
||||
if not x_axis or not y_axis:
|
||||
return Response(
|
||||
{"error": "x-axis and y-axis dimensions are required"},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
segment = request.GET.get("segment", False)
|
||||
distribution = build_graph_plot(queryset=queryset, x_axis=x_axis, y_axis=y_axis, segment=segment)
|
||||
total_issues = queryset.count()
|
||||
return Response(
|
||||
{"total": total_issues, "distribution": distribution},
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
|
||||
class ExportAnalyticsEndpoint(BaseAPIView):
|
||||
@allow_permission([ROLE.ADMIN, ROLE.MEMBER], level="WORKSPACE")
|
||||
def post(self, request, slug):
|
||||
|
||||
@@ -28,14 +28,13 @@ from plane.app.permissions import (
|
||||
)
|
||||
|
||||
# Module imports
|
||||
from plane.app.serializers import WorkSpaceSerializer, WorkspaceThemeSerializer
|
||||
from plane.app.serializers import WorkSpaceSerializer
|
||||
from plane.app.views.base import BaseAPIView, BaseViewSet
|
||||
from plane.db.models import (
|
||||
Issue,
|
||||
IssueActivity,
|
||||
Workspace,
|
||||
WorkspaceMember,
|
||||
WorkspaceTheme,
|
||||
Profile,
|
||||
)
|
||||
from plane.app.permissions import ROLE, allow_permission
|
||||
@@ -77,12 +76,14 @@ class WorkSpaceViewSet(BaseViewSet):
|
||||
|
||||
def create(self, request):
|
||||
try:
|
||||
(DISABLE_WORKSPACE_CREATION,) = get_configuration_value([
|
||||
{
|
||||
"key": "DISABLE_WORKSPACE_CREATION",
|
||||
"default": os.environ.get("DISABLE_WORKSPACE_CREATION", "0"),
|
||||
}
|
||||
])
|
||||
(DISABLE_WORKSPACE_CREATION,) = get_configuration_value(
|
||||
[
|
||||
{
|
||||
"key": "DISABLE_WORKSPACE_CREATION",
|
||||
"default": os.environ.get("DISABLE_WORKSPACE_CREATION", "0"),
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
if DISABLE_WORKSPACE_CREATION == "1":
|
||||
return Response(
|
||||
@@ -341,23 +342,6 @@ class UserWorkspaceDashboardEndpoint(BaseAPIView):
|
||||
)
|
||||
|
||||
|
||||
class WorkspaceThemeViewSet(BaseViewSet):
|
||||
permission_classes = [WorkSpaceAdminPermission]
|
||||
model = WorkspaceTheme
|
||||
serializer_class = WorkspaceThemeSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().filter(workspace__slug=self.kwargs.get("slug"))
|
||||
|
||||
def create(self, request, slug):
|
||||
workspace = Workspace.objects.get(slug=slug)
|
||||
serializer = WorkspaceThemeSerializer(data=request.data)
|
||||
if serializer.is_valid():
|
||||
serializer.save(workspace=workspace, actor=request.user)
|
||||
return Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
class ExportWorkspaceUserActivityEndpoint(BaseAPIView):
|
||||
permission_classes = [WorkspaceEntityPermission]
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ from plane.db.models import (
|
||||
ModuleIssue,
|
||||
Page,
|
||||
ProjectPage,
|
||||
PageLabel,
|
||||
Intake,
|
||||
IntakeIssue,
|
||||
)
|
||||
@@ -242,24 +241,6 @@ def create_pages(workspace, project, user_id, pages_count):
|
||||
)
|
||||
|
||||
|
||||
def create_page_labels(workspace, project, user_id, pages_count):
|
||||
# labels
|
||||
labels = Label.objects.filter(project=project).values_list("id", flat=True)
|
||||
pages = random.sample(
|
||||
list(Page.objects.filter(projects__id=project.id).values_list("id", flat=True)),
|
||||
int(pages_count / 2),
|
||||
)
|
||||
|
||||
# Bulk page labels
|
||||
bulk_page_labels = []
|
||||
for page in pages:
|
||||
for label in random.sample(list(labels), random.randint(0, len(labels) - 1)):
|
||||
bulk_page_labels.append(PageLabel(page_id=page, label_id=label, workspace=workspace))
|
||||
|
||||
# Page labels
|
||||
PageLabel.objects.bulk_create(bulk_page_labels, batch_size=1000, ignore_conflicts=True)
|
||||
|
||||
|
||||
def create_issues(workspace, project, user_id, issue_count):
|
||||
fake = Faker()
|
||||
Faker.seed(0)
|
||||
@@ -517,9 +498,6 @@ def create_dummy_data(
|
||||
# create pages
|
||||
create_pages(workspace=workspace, project=project, user_id=user_id, pages_count=pages_count)
|
||||
|
||||
# create page labels
|
||||
create_page_labels(workspace=workspace, project=project, user_id=user_id, pages_count=pages_count)
|
||||
|
||||
# create issues
|
||||
create_issues(workspace=workspace, project=project, user_id=user_id, issue_count=issue_count)
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
from .analytic import AnalyticView
|
||||
from .api import APIActivityLog, APIToken
|
||||
from .asset import FileAsset
|
||||
from .base import BaseModel
|
||||
@@ -13,7 +12,6 @@ from .draft import (
|
||||
)
|
||||
from .estimate import Estimate, EstimatePoint
|
||||
from .exporter import ExporterHistory
|
||||
from .importer import Importer
|
||||
from .intake import Intake, IntakeIssue
|
||||
from .integration import (
|
||||
GithubCommentSync,
|
||||
@@ -29,7 +27,6 @@ from .issue import (
|
||||
Issue,
|
||||
IssueActivity,
|
||||
IssueAssignee,
|
||||
IssueBlocker,
|
||||
IssueComment,
|
||||
IssueLabel,
|
||||
IssueLink,
|
||||
@@ -45,7 +42,7 @@ from .issue import (
|
||||
)
|
||||
from .module import Module, ModuleIssue, ModuleLink, ModuleMember, ModuleUserProperties
|
||||
from .notification import EmailNotificationLog, Notification, UserNotificationPreference
|
||||
from .page import Page, PageLabel, PageLog, ProjectPage, PageVersion
|
||||
from .page import Page, PageLog, ProjectPage, PageVersion
|
||||
from .project import (
|
||||
Project,
|
||||
ProjectBaseModel,
|
||||
@@ -56,7 +53,6 @@ from .project import (
|
||||
ProjectPublicMember,
|
||||
)
|
||||
from .session import Session
|
||||
from .social_connection import SocialLoginConnection
|
||||
from .state import State, StateGroup, DEFAULT_STATES
|
||||
from .user import Account, Profile, User, BotTypeEnum
|
||||
from .view import IssueView
|
||||
@@ -66,7 +62,6 @@ from .workspace import (
|
||||
WorkspaceBaseModel,
|
||||
WorkspaceMember,
|
||||
WorkspaceMemberInvite,
|
||||
WorkspaceTheme,
|
||||
WorkspaceUserProperties,
|
||||
WorkspaceUserLink,
|
||||
WorkspaceHomePreference,
|
||||
@@ -75,8 +70,6 @@ from .workspace import (
|
||||
|
||||
from .favorite import UserFavorite
|
||||
|
||||
from .issue_type import IssueType
|
||||
|
||||
from .recent_visit import UserRecentVisit
|
||||
|
||||
from .label import Label
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
# Django models
|
||||
from django.db import models
|
||||
|
||||
from .base import BaseModel
|
||||
|
||||
|
||||
class AnalyticView(BaseModel):
|
||||
workspace = models.ForeignKey("db.Workspace", related_name="analytics", on_delete=models.CASCADE)
|
||||
name = models.CharField(max_length=255)
|
||||
description = models.TextField(blank=True)
|
||||
query = models.JSONField()
|
||||
query_dict = models.JSONField(default=dict)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Analytic"
|
||||
verbose_name_plural = "Analytics"
|
||||
db_table = "analytic_views"
|
||||
ordering = ("-created_at",)
|
||||
|
||||
def __str__(self):
|
||||
"""Return name of the analytic view"""
|
||||
return f"{self.name} <{self.workspace.name}>"
|
||||
@@ -63,13 +63,6 @@ class DraftIssue(WorkspaceBaseModel):
|
||||
completed_at = models.DateTimeField(null=True)
|
||||
external_source = models.CharField(max_length=255, null=True, blank=True)
|
||||
external_id = models.CharField(max_length=255, blank=True, null=True)
|
||||
type = models.ForeignKey(
|
||||
"db.IssueType",
|
||||
on_delete=models.SET_NULL,
|
||||
related_name="draft_issue_type",
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "DraftIssue"
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
# Django imports
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
|
||||
# Module imports
|
||||
from .project import ProjectBaseModel
|
||||
|
||||
|
||||
class Importer(ProjectBaseModel):
|
||||
service = models.CharField(max_length=50, choices=(("github", "GitHub"), ("jira", "Jira")))
|
||||
status = models.CharField(
|
||||
max_length=50,
|
||||
choices=(
|
||||
("queued", "Queued"),
|
||||
("processing", "Processing"),
|
||||
("completed", "Completed"),
|
||||
("failed", "Failed"),
|
||||
),
|
||||
default="queued",
|
||||
)
|
||||
initiated_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="imports")
|
||||
metadata = models.JSONField(default=dict)
|
||||
config = models.JSONField(default=dict)
|
||||
data = models.JSONField(default=dict)
|
||||
token = models.ForeignKey("db.APIToken", on_delete=models.CASCADE, related_name="importer")
|
||||
imported_data = models.JSONField(null=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Importer"
|
||||
verbose_name_plural = "Importers"
|
||||
db_table = "importers"
|
||||
ordering = ("-created_at",)
|
||||
|
||||
def __str__(self):
|
||||
"""Return name of the service"""
|
||||
return f"{self.service} <{self.project.name}>"
|
||||
@@ -155,13 +155,6 @@ class Issue(ProjectBaseModel):
|
||||
is_draft = models.BooleanField(default=False)
|
||||
external_source = models.CharField(max_length=255, null=True, blank=True)
|
||||
external_id = models.CharField(max_length=255, blank=True, null=True)
|
||||
type = models.ForeignKey(
|
||||
"db.IssueType",
|
||||
on_delete=models.SET_NULL,
|
||||
related_name="issue_type",
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
|
||||
issue_objects = IssueManager()
|
||||
|
||||
@@ -242,20 +235,6 @@ class Issue(ProjectBaseModel):
|
||||
return f"{self.name} <{self.project.name}>"
|
||||
|
||||
|
||||
class IssueBlocker(ProjectBaseModel):
|
||||
block = models.ForeignKey(Issue, related_name="blocker_issues", on_delete=models.CASCADE)
|
||||
blocked_by = models.ForeignKey(Issue, related_name="blocked_issues", on_delete=models.CASCADE)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Issue Blocker"
|
||||
verbose_name_plural = "Issue Blockers"
|
||||
db_table = "issue_blockers"
|
||||
ordering = ("-created_at",)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.block.name} {self.blocked_by.name}"
|
||||
|
||||
|
||||
class IssueRelationChoices(models.TextChoices):
|
||||
DUPLICATE = "duplicate", "Duplicate"
|
||||
RELATES_TO = "relates_to", "Relates To"
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
# Django imports
|
||||
from django.db import models
|
||||
from django.db.models import Q
|
||||
|
||||
# Module imports
|
||||
from .project import ProjectBaseModel
|
||||
from .base import BaseModel
|
||||
|
||||
|
||||
class IssueType(BaseModel):
|
||||
workspace = models.ForeignKey("db.Workspace", related_name="issue_types", on_delete=models.CASCADE)
|
||||
name = models.CharField(max_length=255)
|
||||
description = models.TextField(blank=True)
|
||||
logo_props = models.JSONField(default=dict)
|
||||
is_epic = models.BooleanField(default=False)
|
||||
is_default = models.BooleanField(default=False)
|
||||
is_active = models.BooleanField(default=True)
|
||||
level = models.FloatField(default=0)
|
||||
external_source = models.CharField(max_length=255, null=True, blank=True)
|
||||
external_id = models.CharField(max_length=255, blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Issue Type"
|
||||
verbose_name_plural = "Issue Types"
|
||||
db_table = "issue_types"
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class ProjectIssueType(ProjectBaseModel):
|
||||
issue_type = models.ForeignKey("db.IssueType", related_name="project_issue_types", on_delete=models.CASCADE)
|
||||
level = models.PositiveIntegerField(default=0)
|
||||
is_default = models.BooleanField(default=False)
|
||||
|
||||
class Meta:
|
||||
unique_together = ["project", "issue_type", "deleted_at"]
|
||||
constraints = [
|
||||
models.UniqueConstraint(
|
||||
fields=["project", "issue_type"],
|
||||
condition=Q(deleted_at__isnull=True),
|
||||
name="project_issue_type_unique_project_issue_type_when_deleted_at_null",
|
||||
)
|
||||
]
|
||||
verbose_name = "Project Issue Type"
|
||||
verbose_name_plural = "Project Issue Types"
|
||||
db_table = "project_issue_types"
|
||||
ordering = ("project", "issue_type")
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.project} - {self.issue_type}"
|
||||
@@ -32,7 +32,6 @@ class Page(BaseModel):
|
||||
owned_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="pages")
|
||||
access = models.PositiveSmallIntegerField(choices=((0, "Public"), (1, "Private")), default=0)
|
||||
color = models.CharField(max_length=255, blank=True)
|
||||
labels = models.ManyToManyField("db.Label", blank=True, related_name="pages", through="db.PageLabel")
|
||||
parent = models.ForeignKey(
|
||||
"self",
|
||||
on_delete=models.CASCADE,
|
||||
@@ -113,21 +112,6 @@ class PageLog(BaseModel):
|
||||
return f"{self.page.name} {self.entity_name}"
|
||||
|
||||
|
||||
class PageLabel(BaseModel):
|
||||
label = models.ForeignKey("db.Label", on_delete=models.CASCADE, related_name="page_labels")
|
||||
page = models.ForeignKey("db.Page", on_delete=models.CASCADE, related_name="page_labels")
|
||||
workspace = models.ForeignKey("db.Workspace", on_delete=models.CASCADE, related_name="workspace_page_label")
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Page Label"
|
||||
verbose_name_plural = "Page Labels"
|
||||
db_table = "page_labels"
|
||||
ordering = ("-created_at",)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.page.name} {self.label.name}"
|
||||
|
||||
|
||||
class ProjectPage(BaseModel):
|
||||
project = models.ForeignKey("db.Project", on_delete=models.CASCADE, related_name="project_pages")
|
||||
page = models.ForeignKey("db.Page", on_delete=models.CASCADE, related_name="project_pages")
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
# Django imports
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
|
||||
# Module import
|
||||
from .base import BaseModel
|
||||
|
||||
|
||||
class SocialLoginConnection(BaseModel):
|
||||
medium = models.CharField(
|
||||
max_length=20,
|
||||
choices=(
|
||||
("Google", "google"),
|
||||
("Github", "github"),
|
||||
("GitLab", "gitlab"),
|
||||
("Jira", "jira"),
|
||||
),
|
||||
default=None,
|
||||
)
|
||||
last_login_at = models.DateTimeField(default=timezone.now, null=True)
|
||||
last_received_at = models.DateTimeField(default=timezone.now, null=True)
|
||||
user = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.CASCADE,
|
||||
related_name="user_login_connections",
|
||||
)
|
||||
token_data = models.JSONField(null=True)
|
||||
extra_data = models.JSONField(null=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Social Login Connection"
|
||||
verbose_name_plural = "Social Login Connections"
|
||||
db_table = "social_login_connections"
|
||||
ordering = ("-created_at",)
|
||||
|
||||
def __str__(self):
|
||||
"""Return name of the user and medium"""
|
||||
return f"{self.medium} <{self.user.email}>"
|
||||
@@ -261,55 +261,6 @@ class WorkspaceMemberInvite(BaseModel):
|
||||
return f"{self.workspace.name} {self.email} {self.accepted}"
|
||||
|
||||
|
||||
class Team(BaseModel):
|
||||
name = models.CharField(max_length=255, verbose_name="Team Name")
|
||||
description = models.TextField(verbose_name="Team Description", blank=True)
|
||||
workspace = models.ForeignKey(Workspace, on_delete=models.CASCADE, related_name="workspace_team")
|
||||
logo_props = models.JSONField(default=dict)
|
||||
|
||||
def __str__(self):
|
||||
"""Return name of the team"""
|
||||
return f"{self.name} <{self.workspace.name}>"
|
||||
|
||||
class Meta:
|
||||
unique_together = ["name", "workspace", "deleted_at"]
|
||||
constraints = [
|
||||
models.UniqueConstraint(
|
||||
fields=["name", "workspace"],
|
||||
condition=models.Q(deleted_at__isnull=True),
|
||||
name="team_unique_name_workspace_when_deleted_at_null",
|
||||
)
|
||||
]
|
||||
verbose_name = "Team"
|
||||
verbose_name_plural = "Teams"
|
||||
db_table = "teams"
|
||||
ordering = ("-created_at",)
|
||||
|
||||
|
||||
class WorkspaceTheme(BaseModel):
|
||||
workspace = models.ForeignKey("db.Workspace", on_delete=models.CASCADE, related_name="themes")
|
||||
name = models.CharField(max_length=300)
|
||||
actor = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="themes")
|
||||
colors = models.JSONField(default=dict)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.name) + str(self.actor.email)
|
||||
|
||||
class Meta:
|
||||
unique_together = ["workspace", "name", "deleted_at"]
|
||||
constraints = [
|
||||
models.UniqueConstraint(
|
||||
fields=["workspace", "name"],
|
||||
condition=models.Q(deleted_at__isnull=True),
|
||||
name="workspace_theme_unique_workspace_name_when_deleted_at_null",
|
||||
)
|
||||
]
|
||||
verbose_name = "Workspace Theme"
|
||||
verbose_name_plural = "Workspace Themes"
|
||||
db_table = "workspace_themes"
|
||||
ordering = ("-created_at",)
|
||||
|
||||
|
||||
class WorkspaceUserProperties(BaseModel):
|
||||
class NavigationControlPreference(models.TextChoices):
|
||||
ACCORDION = "ACCORDION", "Accordion"
|
||||
|
||||
Reference in New Issue
Block a user