forked from github/plane
Compare commits
2 Commits
preview
...
feat/proje
Author | SHA1 | Date | |
---|---|---|---|
|
1604f4585d | ||
|
03f9ca45d8 |
@ -11,7 +11,9 @@ from .workspace import (
|
||||
)
|
||||
from .project import (
|
||||
ProjectSerializer,
|
||||
ProjectSettingSerializer,
|
||||
ProjectDetailSerializer,
|
||||
ProjectSettingDetailSerializer,
|
||||
ProjectMemberSerializer,
|
||||
ProjectMemberInviteSerializer,
|
||||
ProjectIdentifierSerializer,
|
||||
@ -20,7 +22,7 @@ from .project import (
|
||||
ProjectMemberLiteSerializer,
|
||||
ProjectDeployBoardSerializer,
|
||||
ProjectMemberAdminSerializer,
|
||||
ProjectPublicMemberSerializer
|
||||
ProjectPublicMemberSerializer,
|
||||
)
|
||||
from .state import StateSerializer, StateLiteSerializer
|
||||
from .view import GlobalViewSerializer, IssueViewSerializer, IssueViewFavoriteSerializer
|
||||
|
@ -10,6 +10,7 @@ from plane.api.serializers.workspace import WorkSpaceSerializer, WorkspaceLiteSe
|
||||
from plane.api.serializers.user import UserLiteSerializer, UserAdminLiteSerializer
|
||||
from plane.db.models import (
|
||||
Project,
|
||||
ProjectSetting,
|
||||
ProjectMember,
|
||||
ProjectMemberInvite,
|
||||
ProjectIdentifier,
|
||||
@ -96,8 +97,6 @@ class ProjectLiteSerializer(BaseSerializer):
|
||||
|
||||
class ProjectDetailSerializer(BaseSerializer):
|
||||
workspace = WorkSpaceSerializer(read_only=True)
|
||||
default_assignee = UserLiteSerializer(read_only=True)
|
||||
project_lead = UserLiteSerializer(read_only=True)
|
||||
is_favorite = serializers.BooleanField(read_only=True)
|
||||
total_members = serializers.IntegerField(read_only=True)
|
||||
total_cycles = serializers.IntegerField(read_only=True)
|
||||
@ -178,12 +177,12 @@ class ProjectDeployBoardSerializer(BaseSerializer):
|
||||
fields = "__all__"
|
||||
read_only_fields = [
|
||||
"workspace",
|
||||
"project", "anchor",
|
||||
"project",
|
||||
"anchor",
|
||||
]
|
||||
|
||||
|
||||
class ProjectPublicMemberSerializer(BaseSerializer):
|
||||
|
||||
class Meta:
|
||||
model = ProjectPublicMember
|
||||
fields = "__all__"
|
||||
@ -192,3 +191,26 @@ class ProjectPublicMemberSerializer(BaseSerializer):
|
||||
"project",
|
||||
"member",
|
||||
]
|
||||
|
||||
|
||||
class ProjectSettingSerializer(BaseSerializer):
|
||||
class Meta:
|
||||
model = ProjectSetting
|
||||
fields = "__all__"
|
||||
read_only_fields = [
|
||||
"workspace",
|
||||
"project",
|
||||
]
|
||||
|
||||
|
||||
class ProjectSettingDetailSerializer(BaseSerializer):
|
||||
default_assignee = UserLiteSerializer(read_only=True)
|
||||
project_lead = UserLiteSerializer(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = ProjectSetting
|
||||
fields = "__all__"
|
||||
read_only_fields = [
|
||||
"workspace",
|
||||
"project",
|
||||
]
|
||||
|
@ -59,6 +59,7 @@ from plane.api.views import (
|
||||
## End File Assets
|
||||
# Projects
|
||||
ProjectViewSet,
|
||||
ProjectSettingViewSet,
|
||||
InviteProjectEndpoint,
|
||||
ProjectMemberViewSet,
|
||||
ProjectMemberEndpoint,
|
||||
@ -481,6 +482,26 @@ urlpatterns = [
|
||||
),
|
||||
name="project",
|
||||
),
|
||||
path(
|
||||
"workspaces/<str:slug>/projects/<uuid:project_id>/settings/",
|
||||
ProjectSettingViewSet.as_view(
|
||||
{
|
||||
"get": "list",
|
||||
"post": "create",
|
||||
}
|
||||
),
|
||||
name="project",
|
||||
),
|
||||
path(
|
||||
"workspaces/<str:slug>/projects/<uuid:project_id>/settings/",
|
||||
ProjectSettingViewSet.as_view(
|
||||
{
|
||||
"get": "retrieve",
|
||||
"patch": "partial_update",
|
||||
}
|
||||
),
|
||||
name="project",
|
||||
),
|
||||
path(
|
||||
"workspaces/<str:slug>/project-identifiers/",
|
||||
ProjectIdentifierEndpoint.as_view(),
|
||||
|
@ -1,5 +1,6 @@
|
||||
from .project import (
|
||||
ProjectViewSet,
|
||||
ProjectSettingViewSet,
|
||||
ProjectMemberViewSet,
|
||||
UserProjectInvitationsViewset,
|
||||
InviteProjectEndpoint,
|
||||
|
@ -9,7 +9,7 @@ from sentry_sdk import capture_exception
|
||||
# Module imports
|
||||
from .base import BaseViewSet, BaseAPIView
|
||||
from plane.api.permissions import ProjectEntityPermission
|
||||
from plane.db.models import Project, Estimate, EstimatePoint
|
||||
from plane.db.models import ProjectSetting, Estimate, EstimatePoint
|
||||
from plane.api.serializers import (
|
||||
EstimateSerializer,
|
||||
EstimatePointSerializer,
|
||||
@ -24,10 +24,10 @@ class ProjectEstimatePointEndpoint(BaseAPIView):
|
||||
|
||||
def get(self, request, slug, project_id):
|
||||
try:
|
||||
project = Project.objects.get(workspace__slug=slug, pk=project_id)
|
||||
if project.estimate_id is not None:
|
||||
project_setting = ProjectSetting.objects.get(workspace__slug=slug, pk=project_id)
|
||||
if project_setting.estimate_id is not None:
|
||||
estimate_points = EstimatePoint.objects.filter(
|
||||
estimate_id=project.estimate_id,
|
||||
estimate_id=project_setting.estimate_id,
|
||||
project_id=project_id,
|
||||
workspace__slug=slug,
|
||||
)
|
||||
|
@ -63,6 +63,7 @@ from plane.api.permissions import (
|
||||
)
|
||||
from plane.db.models import (
|
||||
Project,
|
||||
ProjectSetting,
|
||||
Issue,
|
||||
IssueActivity,
|
||||
IssueComment,
|
||||
@ -293,13 +294,14 @@ class IssueViewSet(BaseViewSet):
|
||||
def create(self, request, slug, project_id):
|
||||
try:
|
||||
project = Project.objects.get(pk=project_id)
|
||||
project_setting = ProjectSetting.objects.get(workspace__slug=slug, project_id=project_id)
|
||||
|
||||
serializer = IssueCreateSerializer(
|
||||
data=request.data,
|
||||
context={
|
||||
"project_id": project_id,
|
||||
"workspace_id": project.workspace_id,
|
||||
"default_assignee_id": project.default_assignee_id,
|
||||
"default_assignee_id": project_setting.default_assignee_id,
|
||||
},
|
||||
)
|
||||
|
||||
@ -2565,13 +2567,13 @@ class IssueDraftViewSet(BaseViewSet):
|
||||
def create(self, request, slug, project_id):
|
||||
try:
|
||||
project = Project.objects.get(pk=project_id)
|
||||
|
||||
project_setting = ProjectSetting.objects.get(workspace__slug=slug, project_id=project_id)
|
||||
serializer = IssueCreateSerializer(
|
||||
data=request.data,
|
||||
context={
|
||||
"project_id": project_id,
|
||||
"workspace_id": project.workspace_id,
|
||||
"default_assignee_id": project.default_assignee_id,
|
||||
"default_assignee_id": project_setting.default_assignee_id,
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -29,11 +29,12 @@ from sentry_sdk import capture_exception
|
||||
from .base import BaseViewSet, BaseAPIView
|
||||
from plane.api.serializers import (
|
||||
ProjectSerializer,
|
||||
ProjectSettingDetailSerializer,
|
||||
ProjectSettingSerializer,
|
||||
ProjectMemberSerializer,
|
||||
ProjectDetailSerializer,
|
||||
ProjectMemberInviteSerializer,
|
||||
ProjectFavoriteSerializer,
|
||||
IssueLiteSerializer,
|
||||
ProjectDeployBoardSerializer,
|
||||
ProjectMemberAdminSerializer,
|
||||
)
|
||||
@ -67,6 +68,7 @@ from plane.db.models import (
|
||||
ModuleMember,
|
||||
Inbox,
|
||||
ProjectDeployBoard,
|
||||
ProjectSetting,
|
||||
)
|
||||
|
||||
from plane.bgtasks.project_invitation_task import project_invitation
|
||||
@ -98,7 +100,7 @@ class ProjectViewSet(BaseViewSet):
|
||||
.filter(workspace__slug=self.kwargs.get("slug"))
|
||||
.filter(Q(project_projectmember__member=self.request.user) | Q(network=2))
|
||||
.select_related(
|
||||
"workspace", "workspace__owner", "default_assignee", "project_lead"
|
||||
"workspace", "workspace__owner",
|
||||
)
|
||||
.annotate(is_favorite=Exists(subquery))
|
||||
.annotate(
|
||||
@ -210,20 +212,29 @@ class ProjectViewSet(BaseViewSet):
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
|
||||
project_lead = request.data.get("project_lead", None)
|
||||
|
||||
# Create Project Setting
|
||||
_ = ProjectSetting.objects.create(
|
||||
project_id=serializer.data["id"],
|
||||
project_lead_id=request.data.get("project_lead", None)
|
||||
)
|
||||
|
||||
# Add the user as Administrator to the project
|
||||
project_member = ProjectMember.objects.create(
|
||||
project_id=serializer.data["id"], member=request.user, role=20
|
||||
)
|
||||
|
||||
if serializer.data["project_lead"] is not None and str(
|
||||
serializer.data["project_lead"]
|
||||
if project_lead is not None and str(
|
||||
project_lead
|
||||
) != str(request.user.id):
|
||||
ProjectMember.objects.create(
|
||||
project_id=serializer.data["id"],
|
||||
member_id=serializer.data["project_lead"],
|
||||
member_id=project_lead,
|
||||
role=20,
|
||||
)
|
||||
|
||||
|
||||
# Default states
|
||||
states = [
|
||||
{
|
||||
@ -307,7 +318,7 @@ class ProjectViewSet(BaseViewSet):
|
||||
status=status.HTTP_410_GONE,
|
||||
)
|
||||
except Exception as e:
|
||||
capture_exception(e)
|
||||
print(e)
|
||||
return Response(
|
||||
{"error": "Something went wrong please try again later"},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
@ -973,7 +984,7 @@ class ProjectFavoritesViewSet(BaseViewSet):
|
||||
.filter(workspace__slug=self.kwargs.get("slug"))
|
||||
.filter(user=self.request.user)
|
||||
.select_related(
|
||||
"project", "project__project_lead", "project__default_assignee"
|
||||
"project",
|
||||
)
|
||||
.select_related("workspace", "workspace__owner")
|
||||
)
|
||||
@ -1246,3 +1257,69 @@ class ProjectPublicCoverImagesEndpoint(BaseAPIView):
|
||||
except Exception as e:
|
||||
capture_exception(e)
|
||||
return Response([], status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
class ProjectSettingViewSet(BaseViewSet):
|
||||
model = ProjectSetting
|
||||
permission_classes = [
|
||||
ProjectBasePermission,
|
||||
]
|
||||
|
||||
def get_serializer_class(self, *args, **kwargs):
|
||||
if self.action in ["create", "partial_update"]:
|
||||
return ProjectSettingSerializer
|
||||
return ProjectSettingDetailSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
return (
|
||||
super()
|
||||
.get_queryset()
|
||||
.filter(
|
||||
workspace__slug=self.kwargs.get("slug"),
|
||||
project_id=self.kwargs.get("project_id"),
|
||||
)
|
||||
)
|
||||
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(project_id=self.kwargs.get("project_id"))
|
||||
|
||||
def list(self, request, slug, project_id):
|
||||
try:
|
||||
project_setting = self.get_queryset().first()
|
||||
|
||||
if project_setting is not None:
|
||||
serializer = ProjectSettingDetailSerializer(project_setting)
|
||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||
return Response(
|
||||
{"error": "Project setting does not exists"},
|
||||
status=status.HTTP_404_NOT_FOUND,
|
||||
)
|
||||
except Exception as e:
|
||||
capture_exception(e)
|
||||
return Response(
|
||||
{"error": "Something went wrong please try again later"},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
def partial_update(self, request, slug, project_id):
|
||||
try:
|
||||
project_setting = self.get_queryset().first()
|
||||
|
||||
# Check if it is None
|
||||
if project_setting is not None:
|
||||
serializer = ProjectSettingSerializer(
|
||||
project_setting, data=request.data, partial=True
|
||||
)
|
||||
if serializer.is_valid():
|
||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
return Response(
|
||||
{"error": "Project setting does not exists"},
|
||||
status=status.HTTP_404_NOT_FOUND,
|
||||
)
|
||||
except Exception as e:
|
||||
capture_exception(e)
|
||||
return Response(
|
||||
{"error": "Something went wrong please try again later"},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
@ -12,7 +12,7 @@ from celery import shared_task
|
||||
from sentry_sdk import capture_exception
|
||||
|
||||
# Module imports
|
||||
from plane.db.models import Issue, Project, State
|
||||
from plane.db.models import Issue, ProjectSetting, State
|
||||
from plane.bgtasks.issue_activites_task import issue_activity
|
||||
|
||||
|
||||
@ -25,11 +25,11 @@ def archive_and_close_old_issues():
|
||||
def archive_old_issues():
|
||||
try:
|
||||
# Get all the projects whose archive_in is greater than 0
|
||||
projects = Project.objects.filter(archive_in__gt=0)
|
||||
project_settings = ProjectSetting.objects.filter(archive_in__gt=0)
|
||||
|
||||
for project in projects:
|
||||
project_id = project.id
|
||||
archive_in = project.archive_in
|
||||
for project_setting in project_settings:
|
||||
project_id = project_setting.project_id
|
||||
archive_in = project_setting.archive_in
|
||||
|
||||
# Get all the issues whose updated_at in less that the archive_in month
|
||||
issues = Issue.issue_objects.filter(
|
||||
@ -75,7 +75,7 @@ def archive_old_issues():
|
||||
issue_activity.delay(
|
||||
type="issue.activity.updated",
|
||||
requested_data=json.dumps({"archived_at": str(archive_at)}),
|
||||
actor_id=str(project.created_by_id),
|
||||
actor_id=str(project_setting.created_by_id),
|
||||
issue_id=issue.id,
|
||||
project_id=project_id,
|
||||
current_instance=None,
|
||||
@ -95,13 +95,13 @@ def archive_old_issues():
|
||||
def close_old_issues():
|
||||
try:
|
||||
# Get all the projects whose close_in is greater than 0
|
||||
projects = Project.objects.filter(close_in__gt=0).select_related(
|
||||
"default_state"
|
||||
project_settings = ProjectSetting.objects.filter(close_in__gt=0).select_related(
|
||||
"close_state"
|
||||
)
|
||||
|
||||
for project in projects:
|
||||
project_id = project.id
|
||||
close_in = project.close_in
|
||||
for project_setting in project_settings:
|
||||
project_id = project_setting.project_id
|
||||
close_in = project_setting.close_in
|
||||
|
||||
# Get all the issues whose updated_at in less that the close_in month
|
||||
issues = Issue.issue_objects.filter(
|
||||
@ -130,10 +130,10 @@ def close_old_issues():
|
||||
|
||||
# Check if Issues
|
||||
if issues:
|
||||
if project.default_state is None:
|
||||
if project_setting.close_state is None:
|
||||
close_state = State.objects.filter(group="cancelled").first()
|
||||
else:
|
||||
close_state = project.default_state
|
||||
close_state = project_setting.close_state
|
||||
|
||||
issues_to_update = []
|
||||
for issue in issues:
|
||||
@ -147,7 +147,7 @@ def close_old_issues():
|
||||
issue_activity.delay(
|
||||
type="issue.activity.updated",
|
||||
requested_data=json.dumps({"closed_to": str(issue.state_id)}),
|
||||
actor_id=str(project.created_by_id),
|
||||
actor_id=str(project_setting.created_by_id),
|
||||
issue_id=issue.id,
|
||||
project_id=project_id,
|
||||
current_instance=None,
|
||||
|
124
apiserver/plane/db/migrations/0046_auto_20231011_1334.py
Normal file
124
apiserver/plane/db/migrations/0046_auto_20231011_1334.py
Normal file
@ -0,0 +1,124 @@
|
||||
# Generated by Django 4.2.3 on 2023-10-11 13:34
|
||||
import uuid
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
def create_project_settings(apps, schema_editor):
|
||||
Project = apps.get_model("db", "Project")
|
||||
ProjectSetting = apps.get_model("db", "ProjectSetting")
|
||||
|
||||
ProjectSetting.objects.bulk_create(
|
||||
[
|
||||
ProjectSetting(
|
||||
project=project,
|
||||
workspace_id=project.workspace_id,
|
||||
archive_in=project.archive_in,
|
||||
close_in=project.close_in,
|
||||
cycle_view=project.cycle_view,
|
||||
default_assignee=project.default_assignee,
|
||||
default_state=project.default_state,
|
||||
estimate=project.estimate,
|
||||
inbox_view=project.inbox_view,
|
||||
issue_views_view=project.issue_views_view,
|
||||
module_view=project.module_view,
|
||||
page_view=project.page_view,
|
||||
project_lead=project.project_lead,
|
||||
)
|
||||
for project in Project.objects.all()
|
||||
],
|
||||
batch_size=1000,
|
||||
)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('db', '0045_issueactivity_epoch_workspacemember_issue_props_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ProjectSetting',
|
||||
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)),
|
||||
('module_view', models.BooleanField(default=True)),
|
||||
('cycle_view', models.BooleanField(default=True)),
|
||||
('issue_views_view', models.BooleanField(default=True)),
|
||||
('page_view', models.BooleanField(default=True)),
|
||||
('inbox_view', models.BooleanField(default=False)),
|
||||
('archive_in', models.IntegerField(default=0, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(12)])),
|
||||
('close_in', models.IntegerField(default=0, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(12)])),
|
||||
('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')),
|
||||
('default_assignee', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='default_assignee', to=settings.AUTH_USER_MODEL)),
|
||||
('default_state', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='default_state', to='db.state')),
|
||||
('estimate', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='projects', to='db.estimate')),
|
||||
('project', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='project_settings', to='db.project')),
|
||||
('project_lead', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='project_lead', to=settings.AUTH_USER_MODEL)),
|
||||
('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')),
|
||||
('workspace', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='project_settings', to='db.workspace')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Project Settings',
|
||||
'verbose_name_plural': 'Project Settings',
|
||||
'db_table': 'project_settings',
|
||||
'ordering': ('-created_at',),
|
||||
},
|
||||
),
|
||||
migrations.RunPython(create_project_settings),
|
||||
migrations.RemoveField(
|
||||
model_name='project',
|
||||
name='archive_in',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='project',
|
||||
name='close_in',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='project',
|
||||
name='cycle_view',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='project',
|
||||
name='default_assignee',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='project',
|
||||
name='default_state',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='project',
|
||||
name='description_html',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='project',
|
||||
name='description_text',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='project',
|
||||
name='estimate',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='project',
|
||||
name='inbox_view',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='project',
|
||||
name='issue_views_view',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='project',
|
||||
name='module_view',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='project',
|
||||
name='page_view',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='project',
|
||||
name='project_lead',
|
||||
),
|
||||
]
|
@ -0,0 +1,24 @@
|
||||
# Generated by Django 4.2.3 on 2023-10-12 07:13
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('db', '0046_auto_20231011_1334'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='projectsetting',
|
||||
name='default_state',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='projectsetting',
|
||||
name='close_state',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='close_state', to='db.state'),
|
||||
),
|
||||
]
|
@ -13,6 +13,7 @@ from .workspace import (
|
||||
|
||||
from .project import (
|
||||
Project,
|
||||
ProjectSetting,
|
||||
ProjectMember,
|
||||
ProjectBaseModel,
|
||||
ProjectMemberInvite,
|
||||
|
@ -38,7 +38,7 @@ def get_default_props():
|
||||
},
|
||||
"display_filters": {
|
||||
"group_by": None,
|
||||
"order_by": '-created_at',
|
||||
"order_by": "-created_at",
|
||||
"type": None,
|
||||
"sub_issue": True,
|
||||
"show_empty_groups": True,
|
||||
@ -56,12 +56,6 @@ class Project(BaseModel):
|
||||
NETWORK_CHOICES = ((0, "Secret"), (2, "Public"))
|
||||
name = models.CharField(max_length=255, verbose_name="Project Name")
|
||||
description = models.TextField(verbose_name="Project Description", blank=True)
|
||||
description_text = models.JSONField(
|
||||
verbose_name="Project Description RT", blank=True, null=True
|
||||
)
|
||||
description_html = models.JSONField(
|
||||
verbose_name="Project Description HTML", blank=True, null=True
|
||||
)
|
||||
network = models.PositiveSmallIntegerField(default=2, choices=NETWORK_CHOICES)
|
||||
workspace = models.ForeignKey(
|
||||
"db.WorkSpace", on_delete=models.CASCADE, related_name="workspace_project"
|
||||
@ -70,40 +64,40 @@ class Project(BaseModel):
|
||||
max_length=12,
|
||||
verbose_name="Project Identifier",
|
||||
)
|
||||
default_assignee = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.CASCADE,
|
||||
related_name="default_assignee",
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
project_lead = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.CASCADE,
|
||||
related_name="project_lead",
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
# default_assignee = models.ForeignKey(
|
||||
# settings.AUTH_USER_MODEL,
|
||||
# on_delete=models.CASCADE,
|
||||
# related_name="default_assignee",
|
||||
# null=True,
|
||||
# blank=True,
|
||||
# )
|
||||
# project_lead = models.ForeignKey(
|
||||
# settings.AUTH_USER_MODEL,
|
||||
# on_delete=models.CASCADE,
|
||||
# related_name="project_lead",
|
||||
# null=True,
|
||||
# blank=True,
|
||||
# )
|
||||
emoji = models.CharField(max_length=255, null=True, blank=True)
|
||||
icon_prop = models.JSONField(null=True)
|
||||
module_view = models.BooleanField(default=True)
|
||||
cycle_view = models.BooleanField(default=True)
|
||||
issue_views_view = models.BooleanField(default=True)
|
||||
page_view = models.BooleanField(default=True)
|
||||
inbox_view = models.BooleanField(default=False)
|
||||
# module_view = models.BooleanField(default=True)
|
||||
# cycle_view = models.BooleanField(default=True)
|
||||
# issue_views_view = models.BooleanField(default=True)
|
||||
# page_view = models.BooleanField(default=True)
|
||||
# inbox_view = models.BooleanField(default=False)
|
||||
cover_image = models.URLField(blank=True, null=True, max_length=800)
|
||||
estimate = models.ForeignKey(
|
||||
"db.Estimate", on_delete=models.SET_NULL, related_name="projects", null=True
|
||||
)
|
||||
archive_in = models.IntegerField(
|
||||
default=0, validators=[MinValueValidator(0), MaxValueValidator(12)]
|
||||
)
|
||||
close_in = models.IntegerField(
|
||||
default=0, validators=[MinValueValidator(0), MaxValueValidator(12)]
|
||||
)
|
||||
default_state = models.ForeignKey(
|
||||
"db.State", on_delete=models.SET_NULL, null=True, related_name="default_state"
|
||||
)
|
||||
# estimate = models.ForeignKey(
|
||||
# "db.Estimate", on_delete=models.SET_NULL, related_name="projects", null=True
|
||||
# )
|
||||
# archive_in = models.IntegerField(
|
||||
# default=0, validators=[MinValueValidator(0), MaxValueValidator(12)]
|
||||
# )
|
||||
# close_in = models.IntegerField(
|
||||
# default=0, validators=[MinValueValidator(0), MaxValueValidator(12)]
|
||||
# )
|
||||
# default_state = models.ForeignKey(
|
||||
# "db.State", on_delete=models.SET_NULL, null=True, related_name="default_state"
|
||||
# )
|
||||
|
||||
def __str__(self):
|
||||
"""Return name of the project"""
|
||||
@ -121,6 +115,60 @@ class Project(BaseModel):
|
||||
return super().save(*args, **kwargs)
|
||||
|
||||
|
||||
class ProjectSetting(BaseModel):
|
||||
workspace = models.ForeignKey(
|
||||
"db.Workspace", on_delete=models.CASCADE, related_name="project_settings"
|
||||
)
|
||||
project = models.OneToOneField(
|
||||
"db.Project", on_delete=models.CASCADE, related_name="project_settings"
|
||||
)
|
||||
default_assignee = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.CASCADE,
|
||||
related_name="default_assignee",
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
project_lead = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.CASCADE,
|
||||
related_name="project_lead",
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
module_view = models.BooleanField(default=True)
|
||||
cycle_view = models.BooleanField(default=True)
|
||||
issue_views_view = models.BooleanField(default=True)
|
||||
page_view = models.BooleanField(default=True)
|
||||
inbox_view = models.BooleanField(default=False)
|
||||
estimate = models.ForeignKey(
|
||||
"db.Estimate", on_delete=models.SET_NULL, related_name="projects", null=True
|
||||
)
|
||||
archive_in = models.IntegerField(
|
||||
default=0, validators=[MinValueValidator(0), MaxValueValidator(12)]
|
||||
)
|
||||
close_in = models.IntegerField(
|
||||
default=0, validators=[MinValueValidator(0), MaxValueValidator(12)]
|
||||
)
|
||||
close_state = models.ForeignKey(
|
||||
"db.State", on_delete=models.SET_NULL, null=True, related_name="close_state"
|
||||
)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.workspace = self.project.workspace
|
||||
super(ProjectSetting, self).save(*args, **kwargs)
|
||||
|
||||
def __str__(self):
|
||||
"""Return name of the project"""
|
||||
return f"{self.project.name} <{self.workspace.name}>"
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Project Settings"
|
||||
verbose_name_plural = "Project Settings"
|
||||
db_table = "project_settings"
|
||||
ordering = ("-created_at",)
|
||||
|
||||
|
||||
class ProjectBaseModel(BaseModel):
|
||||
project = models.ForeignKey(
|
||||
Project, on_delete=models.CASCADE, related_name="project_%(class)s"
|
||||
|
Loading…
Reference in New Issue
Block a user