Compare commits

..
Author SHA1 Message Date
sriram veeraghanta fc97921195 chore: adding work item urls form issues views 2025-05-29 17:25:32 +05:30
9 changed files with 85 additions and 69 deletions
+2
View File
@@ -5,6 +5,7 @@ from .cycle import urlpatterns as cycle_patterns
from .module import urlpatterns as module_patterns
from .intake import urlpatterns as intake_patterns
from .member import urlpatterns as member_patterns
from .workitem import urlpatterns as workitem_patterns
urlpatterns = [
*project_patterns,
@@ -14,4 +15,5 @@ urlpatterns = [
*module_patterns,
*intake_patterns,
*member_patterns,
*workitem_patterns,
]
+79
View File
@@ -0,0 +1,79 @@
from django.urls import path
from plane.api.views import (
IssueAPIEndpoint,
LabelAPIEndpoint,
IssueLinkAPIEndpoint,
IssueCommentAPIEndpoint,
IssueActivityAPIEndpoint,
WorkspaceIssueAPIEndpoint,
IssueAttachmentEndpoint,
)
urlpatterns = [
path(
"workspaces/<str:slug>/workitems/<str:project__identifier>-<str:issue__identifier>/",
WorkspaceIssueAPIEndpoint.as_view(),
name="workitem-by-identifier",
),
path(
"workspaces/<str:slug>/projects/<uuid:project_id>/workitems/",
IssueAPIEndpoint.as_view(),
name="workitem",
),
path(
"workspaces/<str:slug>/projects/<uuid:project_id>/workitems/<uuid:pk>/",
IssueAPIEndpoint.as_view(),
name="workitem",
),
path(
"workspaces/<str:slug>/projects/<uuid:project_id>/labels/",
LabelAPIEndpoint.as_view(),
name="workitem-label",
),
path(
"workspaces/<str:slug>/projects/<uuid:project_id>/labels/<uuid:pk>/",
LabelAPIEndpoint.as_view(),
name="workitem-label",
),
path(
"workspaces/<str:slug>/projects/<uuid:project_id>/workitems/<uuid:issue_id>/links/",
IssueLinkAPIEndpoint.as_view(),
name="workitem-link",
),
path(
"workspaces/<str:slug>/projects/<uuid:project_id>/workitems/<uuid:issue_id>/links/<uuid:pk>/",
IssueLinkAPIEndpoint.as_view(),
name="workitem-link",
),
path(
"workspaces/<str:slug>/projects/<uuid:project_id>/workitems/<uuid:issue_id>/comments/",
IssueCommentAPIEndpoint.as_view(),
name="workitem-comment",
),
path(
"workspaces/<str:slug>/projects/<uuid:project_id>/workitems/<uuid:issue_id>/comments/<uuid:pk>/",
IssueCommentAPIEndpoint.as_view(),
name="workitem-comment",
),
path(
"workspaces/<str:slug>/projects/<uuid:project_id>/workitems/<uuid:issue_id>/activities/",
IssueActivityAPIEndpoint.as_view(),
name="workitem-activity",
),
path(
"workspaces/<str:slug>/projects/<uuid:project_id>/workitems/<uuid:issue_id>/activities/<uuid:pk>/",
IssueActivityAPIEndpoint.as_view(),
name="workitem-activity",
),
path(
"workspaces/<str:slug>/projects/<uuid:project_id>/workitems/<uuid:issue_id>/issue-attachments/",
IssueAttachmentEndpoint.as_view(),
name="workitem-attachment",
),
path(
"workspaces/<str:slug>/projects/<uuid:project_id>/workitems/<uuid:issue_id>/issue-attachments/<uuid:pk>/",
IssueAttachmentEndpoint.as_view(),
name="workitem-attachment",
),
]
-11
View File
@@ -3,22 +3,11 @@ from rest_framework import serializers
# Module import
from plane.db.models import Account, Profile, User, Workspace, WorkspaceMemberInvite
from plane.utils.url import contains_url
from .base import BaseSerializer
class UserSerializer(BaseSerializer):
def validate_first_name(self, value):
if contains_url(value):
raise serializers.ValidationError("First name cannot contain a URL.")
return value
def validate_last_name(self, value):
if contains_url(value):
raise serializers.ValidationError("Last name cannot contain a URL.")
return value
class Meta:
model = User
# Exclude password field from the serializer
@@ -25,12 +25,10 @@ from plane.db.models import (
WorkspaceUserPreference,
)
from plane.utils.constants import RESTRICTED_WORKSPACE_SLUGS
from plane.utils.url import contains_url
# Django imports
from django.core.validators import URLValidator
from django.core.exceptions import ValidationError
import re
class WorkSpaceSerializer(DynamicBaseSerializer):
@@ -38,21 +36,10 @@ class WorkSpaceSerializer(DynamicBaseSerializer):
logo_url = serializers.CharField(read_only=True)
role = serializers.IntegerField(read_only=True)
def validate_name(self, value):
# Check if the name contains a URL
if contains_url(value):
raise serializers.ValidationError("Name must not contain URLs")
return value
def validate_slug(self, value):
# Check if the slug is restricted
if value in RESTRICTED_WORKSPACE_SLUGS:
raise serializers.ValidationError("Slug is not valid")
# Slug should only contain alphanumeric characters, hyphens, and underscores
if not re.match(r"^[a-zA-Z0-9_-]+$", value):
raise serializers.ValidationError(
"Slug can only contain letters, numbers, hyphens (-), and underscores (_)"
)
return value
class Meta:
@@ -43,7 +43,6 @@ from django.views.decorators.vary import vary_on_cookie
from plane.utils.constants import RESTRICTED_WORKSPACE_SLUGS
from plane.license.utils.instance_value import get_configuration_value
from plane.bgtasks.workspace_seed_task import workspace_seed
from plane.utils.url import contains_url
class WorkSpaceViewSet(BaseViewSet):
@@ -110,12 +109,6 @@ class WorkSpaceViewSet(BaseViewSet):
status=status.HTTP_400_BAD_REQUEST,
)
if contains_url(name):
return Response(
{"error": "Name cannot contain a URL"},
status=status.HTTP_400_BAD_REQUEST,
)
if serializer.is_valid(raise_exception=True):
serializer.save(owner=request.user)
# Create Workspace member
+3 -23
View File
@@ -10,7 +10,6 @@ from celery.schedules import crontab
# Module imports
from plane.settings.redis import redis_instance
from plane.celery_task_routes import task_routes
# Set the default Django settings module for the 'celery' program.
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "plane.settings.production")
@@ -19,28 +18,6 @@ ri = redis_instance()
app = Celery("plane")
# Load task modules from all registered Django app configs.
app.autodiscover_tasks()
app.conf.update(
task_routes,
task_default_queue="default",
task_queues={
"high": {
"exchange": "high",
"routing_key": "high",
},
"default": {
"exchange": "default",
"routing_key": "default",
},
"low": {
"exchange": "low",
"routing_key": "low",
},
},
)
# Using a string here means the worker will not have to
# pickle the object when using Windows.
app.config_from_object("django.conf:settings", namespace="CELERY")
@@ -100,4 +77,7 @@ def setup_task_loggers(logger, *args, **kwargs):
logger.addHandler(handler)
# Load task modules from all registered Django app configs.
app.autodiscover_tasks()
app.conf.beat_scheduler = "django_celery_beat.schedulers.DatabaseScheduler"
-5
View File
@@ -1,5 +0,0 @@
task_routes = {
"plane.bgtasks.email_notification_task.stack_email_notification": {
"queue": "low",
},
}
+1 -2
View File
@@ -247,13 +247,12 @@ if AMQP_URL:
else:
CELERY_BROKER_URL = f"amqp://{RABBITMQ_USER}:{RABBITMQ_PASSWORD}@{RABBITMQ_HOST}:{RABBITMQ_PORT}/{RABBITMQ_VHOST}"
CELERY_CACHE_BACKEND = "django-cache"
CELERY_RESULT_BACKEND = "django-db"
CELERY_TIMEZONE = TIME_ZONE
CELERY_TASK_SERIALIZER = "json"
CELERY_RESULT_SERIALIZER = "json"
CELERY_ACCEPT_CONTENT = ["application/json"]
CELERY_IMPORTS = (
# scheduled tasks
"plane.bgtasks.issue_automation_task",
-8
View File
@@ -4,14 +4,6 @@ from typing import Optional
from urllib.parse import urlparse, urlunparse
def contains_url(value: str) -> bool:
"""
Check if the value contains a URL.
"""
url_pattern = re.compile(r"https?://|www\\.")
return bool(url_pattern.search(value))
def is_valid_url(url: str) -> bool:
"""
Validates whether the given string is a well-formed URL.