diff --git a/apps/api/plane/api/serializers/base.py b/apps/api/plane/api/serializers/base.py index 46bd398bc..6ef2b1582 100644 --- a/apps/api/plane/api/serializers/base.py +++ b/apps/api/plane/api/serializers/base.py @@ -29,7 +29,8 @@ class BaseSerializer(serializers.ModelSerializer): """ Adjust the serializer's fields based on the provided 'fields' list. - :param fields: List or dictionary specifying which fields to include in the serializer. + :param fields: List or dictionary specifying which + fields to include in the serializer. :return: The updated fields for the serializer. """ # Check each field_name in the provided fields. diff --git a/apps/api/plane/api/serializers/issue.py b/apps/api/plane/api/serializers/issue.py index 075823cbf..2bd0d884b 100644 --- a/apps/api/plane/api/serializers/issue.py +++ b/apps/api/plane/api/serializers/issue.py @@ -43,7 +43,8 @@ class IssueSerializer(BaseSerializer): Comprehensive work item serializer with full relationship management. Handles complete work item lifecycle including assignees, labels, validation, - and related model updates. Supports dynamic field expansion and HTML content processing. + and related model updates. Supports dynamic field expansion and HTML content + processing. """ assignees = serializers.ListField( diff --git a/apps/api/plane/api/serializers/module.py b/apps/api/plane/api/serializers/module.py index 167386997..2cdd4c78f 100644 --- a/apps/api/plane/api/serializers/module.py +++ b/apps/api/plane/api/serializers/module.py @@ -17,8 +17,9 @@ class ModuleCreateSerializer(BaseSerializer): """ Serializer for creating modules with member validation and date checking. - Handles module creation including member assignment validation, date range verification, - and duplicate name prevention for feature-based project organization setup. + Handles module creation including member assignment validation, date range + verification, and duplicate name prevention for feature-based + project organization setup. """ members = serializers.ListField( @@ -105,8 +106,9 @@ class ModuleUpdateSerializer(ModuleCreateSerializer): """ Serializer for updating modules with enhanced validation and member management. - Extends module creation with update-specific validations including member reassignment, - name conflict checking, and relationship management for module modifications. + Extends module creation with update-specific validations including + member reassignment, name conflict checking, + and relationship management for module modifications. """ class Meta(ModuleCreateSerializer.Meta): @@ -155,8 +157,8 @@ class ModuleSerializer(BaseSerializer): """ Comprehensive module serializer with work item metrics and member management. - Provides complete module data including work item counts by status, member relationships, - and progress tracking for feature-based project organization. + Provides complete module data including work item counts by status, member + relationships, and progress tracking for feature-based project organization. """ members = serializers.ListField( diff --git a/apps/api/plane/api/views/asset.py b/apps/api/plane/api/views/asset.py index 2e668c15d..815aa4503 100644 --- a/apps/api/plane/api/views/asset.py +++ b/apps/api/plane/api/views/asset.py @@ -8,7 +8,7 @@ from django.conf import settings # Third party imports from rest_framework import status from rest_framework.response import Response -from drf_spectacular.utils import OpenApiExample, OpenApiRequest, OpenApiTypes +from drf_spectacular.utils import OpenApiExample, OpenApiRequest # Module Imports from plane.bgtasks.storage_metadata_task import get_asset_object_metadata @@ -282,8 +282,9 @@ class UserServerAssetEndpoint(BaseAPIView): def post(self, request): """Generate presigned URL for user server asset upload. - Create a presigned URL for uploading user profile assets (avatar or cover image) using server credentials. - This endpoint generates the necessary credentials for direct S3 upload with server-side authentication. + Create a presigned URL for uploading user profile assets + (avatar or cover image) using server credentials. This endpoint generates the + necessary credentials for direct S3 upload with server-side authentication. """ # get the asset key name = request.data.get("name") diff --git a/apps/api/plane/api/views/issue.py b/apps/api/plane/api/views/issue.py index 489fa4a08..6b7bd7a90 100644 --- a/apps/api/plane/api/views/issue.py +++ b/apps/api/plane/api/views/issue.py @@ -30,12 +30,10 @@ from rest_framework.response import Response # drf-spectacular imports from drf_spectacular.utils import ( extend_schema, - OpenApiParameter, OpenApiResponse, OpenApiExample, OpenApiRequest, ) -from drf_spectacular.types import OpenApiTypes # Module imports from plane.api.serializers import ( @@ -99,7 +97,6 @@ from plane.utils.openapi import ( EXTERNAL_ID_PARAMETER, EXTERNAL_SOURCE_PARAMETER, ORDER_BY_PARAMETER, - SEARCH_PARAMETER, SEARCH_PARAMETER_REQUIRED, LIMIT_PARAMETER, WORKSPACE_SEARCH_PARAMETER, diff --git a/apps/api/plane/api/views/module.py b/apps/api/plane/api/views/module.py index 63112cd66..e00a624c7 100644 --- a/apps/api/plane/api/views/module.py +++ b/apps/api/plane/api/views/module.py @@ -10,7 +10,7 @@ from django.core.serializers.json import DjangoJSONEncoder # Third party imports from rest_framework import status from rest_framework.response import Response -from drf_spectacular.utils import OpenApiResponse, OpenApiExample, OpenApiRequest +from drf_spectacular.utils import OpenApiResponse, OpenApiRequest # Module imports from plane.api.serializers import ( @@ -41,8 +41,6 @@ from plane.utils.host import base_host from plane.utils.openapi import ( module_docs, module_issue_docs, - WORKSPACE_SLUG_PARAMETER, - PROJECT_ID_PARAMETER, MODULE_ID_PARAMETER, MODULE_PK_PARAMETER, ISSUE_ID_PARAMETER, diff --git a/apps/api/plane/api/views/project.py b/apps/api/plane/api/views/project.py index da946e3c3..4508aaaee 100644 --- a/apps/api/plane/api/views/project.py +++ b/apps/api/plane/api/views/project.py @@ -11,7 +11,7 @@ from django.core.serializers.json import DjangoJSONEncoder from rest_framework import status from rest_framework.response import Response from rest_framework.serializers import ValidationError -from drf_spectacular.utils import OpenApiResponse, OpenApiExample, OpenApiRequest +from drf_spectacular.utils import OpenApiResponse, OpenApiRequest # Module imports diff --git a/apps/api/plane/api/views/state.py b/apps/api/plane/api/views/state.py index 7b5d842de..8ab61506c 100644 --- a/apps/api/plane/api/views/state.py +++ b/apps/api/plane/api/views/state.py @@ -4,7 +4,7 @@ from django.db import IntegrityError # Third party imports from rest_framework import status from rest_framework.response import Response -from drf_spectacular.utils import OpenApiResponse, OpenApiExample, OpenApiRequest +from drf_spectacular.utils import OpenApiResponse, OpenApiRequest # Module imports from plane.api.serializers import StateSerializer diff --git a/apps/api/plane/app/serializers/draft.py b/apps/api/plane/app/serializers/draft.py index 852caf8bf..1de584cf8 100644 --- a/apps/api/plane/app/serializers/draft.py +++ b/apps/api/plane/app/serializers/draft.py @@ -1,4 +1,3 @@ -from lxml import html # Django imports from django.utils import timezone diff --git a/apps/api/plane/app/serializers/issue.py b/apps/api/plane/app/serializers/issue.py index 8a643ce4d..367b5ce69 100644 --- a/apps/api/plane/app/serializers/issue.py +++ b/apps/api/plane/app/serializers/issue.py @@ -1,4 +1,3 @@ -from lxml import html # Django imports from django.utils import timezone diff --git a/apps/api/plane/app/views/page/base.py b/apps/api/plane/app/views/page/base.py index 39547489a..07394f0c7 100644 --- a/apps/api/plane/app/views/page/base.py +++ b/apps/api/plane/app/views/page/base.py @@ -1,6 +1,5 @@ # Python imports import json -import base64 from datetime import datetime from django.core.serializers.json import DjangoJSONEncoder diff --git a/apps/api/plane/app/views/workspace/base.py b/apps/api/plane/app/views/workspace/base.py index a37624d2a..027d829a9 100644 --- a/apps/api/plane/app/views/workspace/base.py +++ b/apps/api/plane/app/views/workspace/base.py @@ -39,9 +39,6 @@ from plane.db.models import ( Profile, ) from plane.app.permissions import ROLE, allow_permission -from django.utils.decorators import method_decorator -from django.views.decorators.cache import cache_control -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 diff --git a/apps/api/plane/tests/contract/api/test_labels.py b/apps/api/plane/tests/contract/api/test_labels.py index a27bc31dc..7837823f9 100644 --- a/apps/api/plane/tests/contract/api/test_labels.py +++ b/apps/api/plane/tests/contract/api/test_labels.py @@ -1,6 +1,5 @@ import pytest from rest_framework import status -from django.db import IntegrityError from uuid import uuid4 from plane.db.models import Label, Project, ProjectMember diff --git a/apps/api/plane/tests/unit/bg_tasks/test_copy_s3_objects.py b/apps/api/plane/tests/unit/bg_tasks/test_copy_s3_objects.py index bbb98e6b1..a7c178b0e 100644 --- a/apps/api/plane/tests/unit/bg_tasks/test_copy_s3_objects.py +++ b/apps/api/plane/tests/unit/bg_tasks/test_copy_s3_objects.py @@ -27,7 +27,7 @@ class TestCopyS3Objects: name="Test Issue", workspace=workspace, project_id=project.id, - description_html=f'
', + description_html='
', ) @pytest.fixture diff --git a/apps/api/plane/tests/unit/utils/test_url.py b/apps/api/plane/tests/unit/utils/test_url.py index ec3ef7a73..440211eb0 100644 --- a/apps/api/plane/tests/unit/utils/test_url.py +++ b/apps/api/plane/tests/unit/utils/test_url.py @@ -2,7 +2,6 @@ import pytest from plane.utils.url import ( contains_url, is_valid_url, - get_url_components, normalize_url_path, ) diff --git a/apps/api/plane/utils/openapi/examples.py b/apps/api/plane/utils/openapi/examples.py index 136669159..db7ee50c4 100644 --- a/apps/api/plane/utils/openapi/examples.py +++ b/apps/api/plane/utils/openapi/examples.py @@ -499,7 +499,7 @@ ISSUE_COMMENT_EXAMPLE = OpenApiExample( name="IssueComment", value={ "id": "550e8400-e29b-41d4-a716-446655440000", - "comment_html": "

This issue has been resolved by implementing OAuth 2.0 flow.

", + "comment_html": "

This issue has been resolved by implementing OAuth 2.0 flow.

", # noqa: E501 "comment_json": { "type": "doc", "content": [ @@ -508,7 +508,7 @@ ISSUE_COMMENT_EXAMPLE = OpenApiExample( "content": [ { "type": "text", - "text": "This issue has been resolved by implementing OAuth 2.0 flow.", + "text": "This issue has been resolved by implementing OAuth 2.0 flow.", # noqa: E501 } ], } @@ -551,7 +551,7 @@ ISSUE_ATTACHMENT_NOT_UPLOADED_EXAMPLE = OpenApiExample( "error": "The asset is not uploaded.", "status": False, }, - description="Error when trying to download an attachment that hasn't been uploaded yet", + description="Error when trying to download an attachment that hasn't been uploaded yet", # noqa: E501 ) # Intake Issue Response Examples @@ -733,7 +733,7 @@ SAMPLE_STATE = { SAMPLE_COMMENT = { "id": "550e8400-e29b-41d4-a716-446655440000", - "comment_html": "

This issue needs more investigation. I'll look into the database connection timeout.

", + "comment_html": "

This issue needs more investigation. I'll look into the database connection timeout.

", # noqa: E501 "created_at": "2024-01-15T14:20:00Z", "actor": {"id": "550e8400-e29b-41d4-a716-446655440002", "display_name": "John Doe"}, } diff --git a/apps/api/plane/utils/openapi/parameters.py b/apps/api/plane/utils/openapi/parameters.py index 0d7f3a3d1..47db747ac 100644 --- a/apps/api/plane/utils/openapi/parameters.py +++ b/apps/api/plane/utils/openapi/parameters.py @@ -336,7 +336,7 @@ ORDER_BY_PARAMETER = OpenApiParameter( OpenApiExample( name="State group", value="state__group", - description="Order by state group (backlog, unstarted, started, completed, cancelled)", + description="Order by state group (backlog, unstarted, started, completed, cancelled)", # noqa: E501 ), OpenApiExample( name="Assignee name", diff --git a/apps/api/plane/utils/openapi/responses.py b/apps/api/plane/utils/openapi/responses.py index a70a749f3..a812cd307 100644 --- a/apps/api/plane/utils/openapi/responses.py +++ b/apps/api/plane/utils/openapi/responses.py @@ -221,7 +221,7 @@ EXTERNAL_ID_EXISTS_RESPONSE = OpenApiResponse( OpenApiExample( name="External ID Exists", value={ - "error": "Resource with the same external id and external source already exists", + "error": "Resource with the same external id and external source already exists", # noqa: E501 "id": "550e8400-e29b-41d4-a716-446655440000", }, ) diff --git a/apps/api/plane/utils/paginator.py b/apps/api/plane/utils/paginator.py index 0d065e253..8f18e40eb 100644 --- a/apps/api/plane/utils/paginator.py +++ b/apps/api/plane/utils/paginator.py @@ -221,7 +221,8 @@ class GroupedOffsetPaginator(OffsetPaginator): self.group_by_field_name = group_by_field_name # Set the group by fields self.group_by_fields = group_by_fields - # Set the count filter - this are extra filters that need to be passed to calculate the counts with the filters + # Set the count filter - this are extra filters that need to be passed + # to calculate the counts with the filters self.count_filter = count_filter def get_result(self, limit=50, cursor=None): @@ -434,7 +435,8 @@ class SubGroupedOffsetPaginator(OffsetPaginator): self.sub_group_by_field_name = sub_group_by_field_name self.sub_group_by_fields = sub_group_by_fields - # Set the count filter - this are extra filters that need to be passed to calculate the counts with the filters + # Set the count filter - this are extra filters that need + # to be passed to calculate the counts with the filters self.count_filter = count_filter def get_result(self, limit=30, cursor=None): diff --git a/apps/api/plane/utils/url.py b/apps/api/plane/utils/url.py index 6c196c298..773608bd3 100644 --- a/apps/api/plane/utils/url.py +++ b/apps/api/plane/utils/url.py @@ -10,11 +10,11 @@ URL_PATTERN = re.compile( r"(?:" # Non-capturing group for alternatives r"https?://[^\s]+" # http:// or https:// followed by non-whitespace r"|" - r"www\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*" # www.domain with proper length limits + r"www\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*" # noqa: E501 r"|" - r"(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}" # domain.tld with length limits + r"(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}" # noqa: E501 r"|" - r"(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" # IP address with proper validation + r"(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" # noqa: E501 r")" ) @@ -85,7 +85,10 @@ def get_url_components(url: str) -> Optional[dict]: Example: >>> get_url_components("https://example.com/path?query=1") - {'scheme': 'https', 'netloc': 'example.com', 'path': '/path', 'params': '', 'query': 'query=1', 'fragment': ''} + { + 'scheme': 'https', 'netloc': 'example.com', + 'path': '/path', 'params': '', + 'query': 'query=1', 'fragment': ''} """ if not is_valid_url(url): return None @@ -102,9 +105,11 @@ def get_url_components(url: str) -> Optional[dict]: def normalize_url_path(url: str) -> str: """ - Normalize the path component of a URL by replacing multiple consecutive slashes with a single slash. + Normalize the path component of a URL by + replacing multiple consecutive slashes with a single slash. - This function preserves the protocol, domain, query parameters, and fragments of the URL, + This function preserves the protocol, domain, + query parameters, and fragments of the URL, only modifying the path portion to ensure there are no duplicate slashes. Args: diff --git a/apps/api/requirements/base.txt b/apps/api/requirements/base.txt index 28fede97f..7829fdc01 100644 --- a/apps/api/requirements/base.txt +++ b/apps/api/requirements/base.txt @@ -5,9 +5,9 @@ Django==4.2.24 # rest framework djangorestframework==3.15.2 # postgres -psycopg==3.1.18 -psycopg-binary==3.1.18 -psycopg-c==3.1.18 +psycopg==3.2.9 +psycopg-binary==3.2.9 +psycopg-c==3.2.9 dj-database-url==2.1.0 # mongo pymongo==4.6.3 @@ -53,7 +53,7 @@ posthog==3.5.0 # crypto cryptography==44.0.1 # html validator -lxml==5.2.1 +lxml==6.0.0 # s3 boto3==1.34.96 # password validator