From 7800f98ce9c0fe7fea97d4442af76cdce99b7d6e Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Mon, 4 Nov 2024 20:22:10 +0000 Subject: [PATCH 01/83] ready for oauth --- admin/ce/components/common/upgrade-button.tsx | 9 +- .../components/admin-sidebar/help-section.tsx | 11 -- .../provider/credentials/magic_code.py | 12 +- .../authentication/utils/redirection_path.py | 4 +- .../plane/authentication/views/app/magic.py | 139 ++++++++++++------ docker-compose-local.yml | 16 +- .../constants/project/settings/features.tsx | 4 +- .../workspace/sidebar/help-section.tsx | 109 +------------- web/core/constants/dashboard.ts | 50 +++---- 9 files changed, 138 insertions(+), 216 deletions(-) diff --git a/admin/ce/components/common/upgrade-button.tsx b/admin/ce/components/common/upgrade-button.tsx index aa3c95fdbed..cdbe32a5baf 100644 --- a/admin/ce/components/common/upgrade-button.tsx +++ b/admin/ce/components/common/upgrade-button.tsx @@ -9,8 +9,9 @@ import { getButtonStyling } from "@plane/ui"; import { cn } from "@/helpers/common.helper"; export const UpgradeButton: React.FC = () => ( - - Available on One - - + + // + // Available on One + // + // ); diff --git a/admin/core/components/admin-sidebar/help-section.tsx b/admin/core/components/admin-sidebar/help-section.tsx index abba68e3eae..dcb96d0a512 100644 --- a/admin/core/components/admin-sidebar/help-section.tsx +++ b/admin/core/components/admin-sidebar/help-section.tsx @@ -61,17 +61,6 @@ export const HelpSection: FC = observer(() => { {!isSidebarCollapsed && "Redirect to plane"} - - - - } - customButtonClassName={`relative grid place-items-center rounded-md p-1.5 outline-none ${isCollapsed ? "w-full" : ""}`} - menuButtonOnClick={() => !isNeedHelpOpen && setIsNeedHelpOpen(true)} - onMenuClose={() => setIsNeedHelpOpen(false)} - placement={isCollapsed ? "left-end" : "top-end"} - maxHeight="lg" - closeOnSelect - > - - - - Documentation - - - {config?.intercom_app_id && config?.is_intercom_enabled && ( - - - - )} - - - - Contact sales - - -
- {ENABLE_LOCAL_DB_CACHE && ( - -
{ - e.preventDefault(); - e.stopPropagation(); - }} - className="flex w-full items-center justify-between text-xs hover:bg-custom-background-80" - > - Local Cache - toggleLocalDB(workspaceSlug?.toString(), projectId?.toString())} - /> -
-
- )} - - - - - - - - - Discord - - -
- -
- -
+
boolean; Icon: React.FC; }[] = [ - { - key: "projects", - label: "Projects", - href: `/projects`, - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER, EUserPermissions.GUEST], - highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/projects/`, - Icon: Briefcase, - }, + // { + // key: "projects", + // label: "Projects", + // href: `/projects`, + // access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER, EUserPermissions.GUEST], + // highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/projects/`, + // Icon: Briefcase, + // }, { key: "all-issues", label: "Views", @@ -273,23 +273,23 @@ export const SIDEBAR_WORKSPACE_MENU_ITEMS: { access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER, EUserPermissions.GUEST], highlight: (pathname: string, baseUrl: string) => pathname.includes(`${baseUrl}/workspace-views/`), Icon: Layers, - }, - { - key: "active-cycles", - label: "Cycles", - href: `/active-cycles`, - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/active-cycles/`, - Icon: ContrastIcon, - }, - { - key: "analytics", - label: "Analytics", - href: `/analytics`, - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - highlight: (pathname: string, baseUrl: string) => pathname.includes(`${baseUrl}/analytics/`), - Icon: BarChart2, - }, + } + // { + // key: "active-cycles", + // label: "Cycles", + // href: `/active-cycles`, + // access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], + // highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/active-cycles/`, + // Icon: ContrastIcon, + // }, + // { + // key: "analytics", + // label: "Analytics", + // href: `/analytics`, + // access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], + // highlight: (pathname: string, baseUrl: string) => pathname.includes(`${baseUrl}/analytics/`), + // Icon: BarChart2, + // }, ]; type TLinkOptions = { From dc2514c756ce00b164d48decbd62c6da0784e5ca Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Tue, 12 Nov 2024 13:38:45 +0000 Subject: [PATCH 02/83] intermediate --- .../api/middleware/api_authentication.py | 13 +- apiserver/plane/api/serializers/__init__.py | 2 +- apiserver/plane/api/serializers/issue.py | 60 ++++- apiserver/plane/api/serializers/project.py | 23 ++ apiserver/plane/api/urls/project.py | 10 +- apiserver/plane/api/views/__init__.py | 6 +- apiserver/plane/api/views/base.py | 2 + apiserver/plane/api/views/issue.py | 23 +- apiserver/plane/api/views/project.py | 235 +++++++++++------- apiserver/plane/app/permissions/project.py | 5 + apiserver/plane/app/views/issue/base.py | 2 + .../plane/authentication/views/app/magic.py | 97 ++++++-- ...omproperty_issuecustomproperty_and_more.py | 69 +++++ apiserver/plane/db/models/__init__.py | 2 + apiserver/plane/db/models/issue.py | 22 ++ apiserver/plane/db/models/project.py | 20 ++ .../plane/middleware/api_log_middleware.py | 24 ++ apiserver/plane/settings/common.py | 2 +- apiserver/plane/utils/issue_filters.py | 22 ++ .../components/workspace/sidebar/dropdown.tsx | 9 - 20 files changed, 514 insertions(+), 134 deletions(-) create mode 100644 apiserver/plane/db/migrations/0084_projectcustomproperty_issuecustomproperty_and_more.py diff --git a/apiserver/plane/api/middleware/api_authentication.py b/apiserver/plane/api/middleware/api_authentication.py index 893df7f840d..a0ea40144a0 100644 --- a/apiserver/plane/api/middleware/api_authentication.py +++ b/apiserver/plane/api/middleware/api_authentication.py @@ -8,7 +8,8 @@ # Module imports from plane.db.models import APIToken - +from django.conf import settings +from django.contrib.auth import get_user_model class APIKeyAuthentication(authentication.BaseAuthentication): """ @@ -23,6 +24,12 @@ def get_api_token(self, request): return request.headers.get(self.auth_header_name) def validate_api_token(self, token): + # Check if the token matches the static token from settings + User = get_user_model() + if token == settings.STATIC_API_TOKEN: + user = User.objects.filter(is_superuser=True).first() + self.rewite_project_id_in_url() + return (user, token) try: api_token = APIToken.objects.get( Q( @@ -40,6 +47,10 @@ def validate_api_token(self, token): api_token.save(update_fields=["last_used"]) return (api_token.user, api_token.token) + def rewite_project_id_in_url(self): + pass + # import pdb;pdb.set_trace() + def authenticate(self, request): token = self.get_api_token(request=request) if not token: diff --git a/apiserver/plane/api/serializers/__init__.py b/apiserver/plane/api/serializers/__init__.py index 263be85b85d..9837f03e8cc 100644 --- a/apiserver/plane/api/serializers/__init__.py +++ b/apiserver/plane/api/serializers/__init__.py @@ -1,6 +1,6 @@ from .user import UserLiteSerializer from .workspace import WorkspaceLiteSerializer -from .project import ProjectSerializer, ProjectLiteSerializer +from .project import ProjectSerializer, ProjectLiteSerializer, ProjectCustomPropertySerializer from .issue import ( IssueSerializer, LabelSerializer, diff --git a/apiserver/plane/api/serializers/issue.py b/apiserver/plane/api/serializers/issue.py index 90515733954..701c0c67dc9 100644 --- a/apiserver/plane/api/serializers/issue.py +++ b/apiserver/plane/api/serializers/issue.py @@ -19,8 +19,8 @@ ProjectMember, State, User, + IssueCustomProperty ) - from .base import BaseSerializer from .cycle import CycleLiteSerializer, CycleSerializer from .module import ModuleLiteSerializer, ModuleSerializer @@ -32,6 +32,21 @@ from django.core.validators import URLValidator +class IssueCustomPropertySerializer(BaseSerializer): + class Meta: + model = IssueCustomProperty + fields = ["id", "key", "value", "project_custom_property"] + read_only_fields = [ + "id", + "workspace", + "project", + "issue", + "created_by", + "updated_by", + "created_at", + "updated_at", + ] + class IssueSerializer(BaseSerializer): assignees = serializers.ListField( child=serializers.PrimaryKeyRelatedField( @@ -54,6 +69,7 @@ class IssueSerializer(BaseSerializer): required=False, allow_null=True, ) + custom_properties = IssueCustomPropertySerializer(many=True, required=False) class Meta: model = Issue @@ -132,7 +148,7 @@ def validate(self, data): def create(self, validated_data): assignees = validated_data.pop("assignees", None) labels = validated_data.pop("labels", None) - + custom_properties = validated_data.pop("custom_properties", None) project_id = self.context["project_id"] workspace_id = self.context["workspace_id"] default_assignee_id = self.context["default_assignee_id"] @@ -198,13 +214,31 @@ def create(self, validated_data): ], batch_size=10, ) + if custom_properties is not None and len(custom_properties): + IssueCustomProperty.objects.bulk_create( + [ + IssueCustomProperty( + key=custom_property['key'], + value=custom_property['value'], + project_custom_property=custom_property['project_custom_property'], + issue=issue, + project_id=project_id, + workspace_id=workspace_id, + created_by_id=created_by_id, + updated_by_id=updated_by_id, + ) + for custom_property in custom_properties + ], + batch_size=10, + ) return issue def update(self, instance, validated_data): assignees = validated_data.pop("assignees", None) labels = validated_data.pop("labels", None) - + custom_properties = validated_data.pop("custom_properties", None) + # Related models project_id = instance.project_id workspace_id = instance.workspace_id @@ -244,7 +278,25 @@ def update(self, instance, validated_data): ], batch_size=10, ) - + if custom_properties is not None: + IssueCustomProperty.objects.filter(issue=instance).delete() + IssueCustomProperty.objects.bulk_create( + [ + IssueCustomProperty( + key=custom_property['key'], + value=custom_property['value'], + project_custom_property= custom_property['project_custom_property'], + project_custom_property__project_id= project_id, + issue=issue, + project_id=project_id, + workspace_id=workspace_id, + created_by_id=created_by_id, + updated_by_id=updated_by_id, + ) + for custom_property in custom_properties + ], + batch_size=10, + ) # Time updation occues even when other related models are updated instance.updated_at = timezone.now() return super().update(instance, validated_data) diff --git a/apiserver/plane/api/serializers/project.py b/apiserver/plane/api/serializers/project.py index 591a1203dcc..400de8313ce 100644 --- a/apiserver/plane/api/serializers/project.py +++ b/apiserver/plane/api/serializers/project.py @@ -6,6 +6,7 @@ Project, ProjectIdentifier, WorkspaceMember, + ProjectCustomProperty ) from .base import BaseSerializer @@ -104,3 +105,25 @@ class Meta: "cover_image_url", ] read_only_fields = fields + +class ProjectCustomPropertySerializer(BaseSerializer): + class Meta: + model = ProjectCustomProperty + fields = "__all__" + read_only_fields = [ + "id", + "workspace", + "project", + "created_at", + "updated_at", + "created_by", + "updated_by", + "deleted_at" + ] + + def create(self, validated_data): + return ProjectCustomProperty.objects.create( + **validated_data, + workspace_id=self.context["workspace_id"], + project_id=self.context["project_id"] + ) \ No newline at end of file diff --git a/apiserver/plane/api/urls/project.py b/apiserver/plane/api/urls/project.py index 5efb85bb03e..1f0727ec299 100644 --- a/apiserver/plane/api/urls/project.py +++ b/apiserver/plane/api/urls/project.py @@ -3,6 +3,7 @@ from plane.api.views import ( ProjectAPIEndpoint, ProjectArchiveUnarchiveAPIEndpoint, + ProjectCustomPropertyAPIEndpoint ) urlpatterns = [ @@ -12,12 +13,17 @@ name="project", ), path( - "workspaces//projects//", + "workspaces//projects//", ProjectAPIEndpoint.as_view(), name="project", ), path( - "workspaces//projects//archive/", + "workspaces//projects//custom-properties/", + ProjectCustomPropertyAPIEndpoint.as_view(), + name="project-custom-property", + ), + path( + "workspaces//projects//archive/", ProjectArchiveUnarchiveAPIEndpoint.as_view(), name="project-archive-unarchive", ), diff --git a/apiserver/plane/api/views/__init__.py b/apiserver/plane/api/views/__init__.py index bbec428c053..1a52b178fca 100644 --- a/apiserver/plane/api/views/__init__.py +++ b/apiserver/plane/api/views/__init__.py @@ -1,4 +1,8 @@ -from .project import ProjectAPIEndpoint, ProjectArchiveUnarchiveAPIEndpoint +from .project import ( + ProjectAPIEndpoint, + ProjectArchiveUnarchiveAPIEndpoint, + ProjectCustomPropertyAPIEndpoint +) from .state import StateAPIEndpoint diff --git a/apiserver/plane/api/views/base.py b/apiserver/plane/api/views/base.py index a3241eaf3b5..2765b53cc81 100644 --- a/apiserver/plane/api/views/base.py +++ b/apiserver/plane/api/views/base.py @@ -74,6 +74,7 @@ def handle_exception(self, exc): or re-raising the error. """ try: + print(exc) response = super().handle_exception(exc) return response except Exception as e: @@ -84,6 +85,7 @@ def handle_exception(self, exc): ) if isinstance(e, ValidationError): + print(e) return Response( {"error": "Please provide valid detail"}, status=status.HTTP_400_BAD_REQUEST, diff --git a/apiserver/plane/api/views/issue.py b/apiserver/plane/api/views/issue.py index 26945a7668b..7e65d5115ec 100644 --- a/apiserver/plane/api/views/issue.py +++ b/apiserver/plane/api/views/issue.py @@ -51,7 +51,7 @@ ProjectMember, CycleIssue, ) - +from plane.utils.issue_filters import issue_filters from .base import BaseAPIView @@ -132,26 +132,31 @@ class IssueAPIEndpoint(BaseAPIView): serializer_class = IssueSerializer def get_queryset(self): - return ( - Issue.issue_objects.annotate( + filters = issue_filters(self.request.query_params, "GET") + base_filter = filters.pop('base', None) + query = (Issue.issue_objects.annotate( sub_issues_count=Issue.issue_objects.filter( parent=OuterRef("id") ) .order_by() .annotate(count=Func(F("id"), function="Count")) .values("count") - ) - .filter(project_id=self.kwargs.get("project_id")) - .filter(workspace__slug=self.kwargs.get("slug")) + ).filter(project_id=self.kwargs.get("project_id")) + .filter(workspace__slug=self.kwargs.get("slug"))) + if base_filter: + query = query.filter(base_filter) + + return (query + .filter(**filters) .select_related("project") .select_related("workspace") .select_related("state") .select_related("parent") .prefetch_related("assignees") .prefetch_related("labels") - .order_by(self.kwargs.get("order_by", "-created_at")) - ).distinct() - + .order_by(self.kwargs.get("order_by", "-created_at"))).distinct() + + def get(self, request, slug, project_id, pk=None): external_id = request.GET.get("external_id") external_source = request.GET.get("external_source") diff --git a/apiserver/plane/api/views/project.py b/apiserver/plane/api/views/project.py index 594329a44af..85512b50f5d 100644 --- a/apiserver/plane/api/views/project.py +++ b/apiserver/plane/api/views/project.py @@ -12,7 +12,7 @@ from rest_framework.response import Response from rest_framework.serializers import ValidationError -from plane.api.serializers import ProjectSerializer +from plane.api.serializers import ProjectSerializer, ProjectCustomPropertySerializer from plane.app.permissions import ProjectBasePermission # Module imports @@ -27,10 +27,100 @@ State, Workspace, UserFavorite, + ProjectCustomProperty ) from plane.bgtasks.webhook_task import model_activity from .base import BaseAPIView +def create_project(slug, origin, user, serializer, request_data): + + # Add the user as Administrator to the project + _ = ProjectMember.objects.create( + project_id=serializer.data["id"], + member=user, + role=20, + ) + # Also create the issue property for the user + _ = IssueUserProperty.objects.create( + project_id=serializer.data["id"], + user=user, + ) + + if serializer.data["project_lead"] is not None and str( + serializer.data["project_lead"] + ) != str(user.id): + ProjectMember.objects.create( + project_id=serializer.data["id"], + member_id=serializer.data["project_lead"], + role=20, + ) + # Also create the issue property for the user + IssueUserProperty.objects.create( + project_id=serializer.data["id"], + user_id=serializer.data["project_lead"], + ) + + # Default states + states = [ + { + "name": "Backlog", + "color": "#A3A3A3", + "sequence": 15000, + "group": "backlog", + "default": True, + }, + { + "name": "Todo", + "color": "#3A3A3A", + "sequence": 25000, + "group": "unstarted", + }, + { + "name": "In Progress", + "color": "#F59E0B", + "sequence": 35000, + "group": "started", + }, + { + "name": "Done", + "color": "#16A34A", + "sequence": 45000, + "group": "completed", + }, + { + "name": "Cancelled", + "color": "#EF4444", + "sequence": 55000, + "group": "cancelled", + }, + ] + + State.objects.bulk_create( + [ + State( + name=state["name"], + color=state["color"], + project=serializer.instance, + sequence=state["sequence"], + workspace=serializer.instance.workspace, + group=state["group"], + default=state.get("default", False), + created_by=user, + ) + for state in states + ] + ) + # Model activity + model_activity.delay( + model_name="project", + model_id=str(serializer.data["id"]), + requested_data=request_data, + current_instance=None, + actor_id=user.id, + slug=slug, + origin=origin, + ) + return True class ProjectAPIEndpoint(BaseAPIView): """Project Endpoints to create, update, list, retrieve and delete endpoint""" @@ -150,6 +240,7 @@ def get(self, request, slug, pk=None): ) return Response(serializer.data, status=status.HTTP_200_OK) + def post(self, request, slug): try: workspace = Workspace.objects.get(slug=slug) @@ -158,101 +249,16 @@ def post(self, request, slug): ) if serializer.is_valid(): serializer.save() - - # Add the user as Administrator to the project - _ = ProjectMember.objects.create( - project_id=serializer.data["id"], - member=request.user, - role=20, - ) - # Also create the issue property for the user - _ = IssueUserProperty.objects.create( - project_id=serializer.data["id"], - user=request.user, - ) - - if serializer.data["project_lead"] is not None and str( - serializer.data["project_lead"] - ) != str(request.user.id): - ProjectMember.objects.create( - project_id=serializer.data["id"], - member_id=serializer.data["project_lead"], - role=20, - ) - # Also create the issue property for the user - IssueUserProperty.objects.create( - project_id=serializer.data["id"], - user_id=serializer.data["project_lead"], - ) - - # Default states - states = [ - { - "name": "Backlog", - "color": "#A3A3A3", - "sequence": 15000, - "group": "backlog", - "default": True, - }, - { - "name": "Todo", - "color": "#3A3A3A", - "sequence": 25000, - "group": "unstarted", - }, - { - "name": "In Progress", - "color": "#F59E0B", - "sequence": 35000, - "group": "started", - }, - { - "name": "Done", - "color": "#16A34A", - "sequence": 45000, - "group": "completed", - }, - { - "name": "Cancelled", - "color": "#EF4444", - "sequence": 55000, - "group": "cancelled", - }, - ] - - State.objects.bulk_create( - [ - State( - name=state["name"], - color=state["color"], - project=serializer.instance, - sequence=state["sequence"], - workspace=serializer.instance.workspace, - group=state["group"], - default=state.get("default", False), - created_by=request.user, - ) - for state in states - ] - ) - + self.create_project( + request.META.get("HTTP_ORIGIN"), + user, + serializer + ) project = ( self.get_queryset() .filter(pk=serializer.data["id"]) .first() ) - - # Model activity - model_activity.delay( - model_name="project", - model_id=str(project.id), - requested_data=request.data, - current_instance=None, - actor_id=request.user.id, - slug=slug, - origin=request.META.get("HTTP_ORIGIN"), - ) - serializer = ProjectSerializer(project) return Response( serializer.data, status=status.HTTP_201_CREATED @@ -393,3 +399,50 @@ def delete(self, request, slug, project_id): project.archived_at = None project.save() return Response(status=status.HTTP_204_NO_CONTENT) + + +class ProjectCustomPropertyAPIEndpoint(BaseAPIView): + def get(self, request, slug, project_id): + workspace = Workspace.objects.get(slug=slug) + project = Project.objects.get(pk=project_id, workspace=workspace) + properties = ProjectCustomProperty.objects.filter( + project=project, + ) + serializer = ProjectCustomPropertySerializer(properties, many=True) + return Response(serializer.data, status=status.HTTP_200_OK) + + def post(self, request, slug, project_id): + try: + workspace = Workspace.objects.get(slug=slug) + serializer = ProjectCustomPropertySerializer( + data={**request.data}, context={ + "workspace_id": workspace.id, + "project_id": project_id + } + ) + print(serializer.is_valid()) + if serializer.is_valid(): + serializer.save() + return Response( + serializer.data, status=status.HTTP_201_CREATED + ) + return Response( + serializer.errors, + status=status.HTTP_400_BAD_REQUEST, + ) + except IntegrityError as e: + if "already exists" in str(e): + return Response( + {"name": "The project name is already taken"}, + status=status.HTTP_410_GONE, + ) + except Workspace.DoesNotExist: + return Response( + {"error": "Workspace does not exist"}, + status=status.HTTP_404_NOT_FOUND, + ) + except ValidationError: + return Response( + {"identifier": "The project identifier is already taken"}, + status=status.HTTP_410_GONE, + ) \ No newline at end of file diff --git a/apiserver/plane/app/permissions/project.py b/apiserver/plane/app/permissions/project.py index 11eab008b6a..cc9c0f350cc 100644 --- a/apiserver/plane/app/permissions/project.py +++ b/apiserver/plane/app/permissions/project.py @@ -44,10 +44,14 @@ def has_permission(self, request, view): class ProjectMemberPermission(BasePermission): def has_permission(self, request, view): + print("Project ID:: %s" % view.project_id) if request.user.is_anonymous: return False + if request.user.is_superuser: + return True ## Safe Methods -> Handle the filtering logic in queryset + if request.method in SAFE_METHODS: return ProjectMember.objects.filter( workspace__slug=view.workspace_slug, @@ -64,6 +68,7 @@ def has_permission(self, request, view): ).exists() ## Only Project Admins can update project attributes + return ProjectMember.objects.filter( workspace__slug=view.workspace_slug, member=request.user, diff --git a/apiserver/plane/app/views/issue/base.py b/apiserver/plane/app/views/issue/base.py index d82ae432e9e..1d49fd255c1 100644 --- a/apiserver/plane/app/views/issue/base.py +++ b/apiserver/plane/app/views/issue/base.py @@ -397,6 +397,7 @@ def create(self, request, slug, project_id): if serializer.is_valid(): serializer.save() + print(serializer.data) # Track the issue issue_activity.delay( @@ -451,6 +452,7 @@ def create(self, request, slug, project_id): .first() ) datetime_fields = ["created_at", "updated_at"] + print(issue) issue = user_timezone_converter( issue, datetime_fields, request.user.user_timezone ) diff --git a/apiserver/plane/authentication/views/app/magic.py b/apiserver/plane/authentication/views/app/magic.py index 4010fd50309..84ee6dde689 100644 --- a/apiserver/plane/authentication/views/app/magic.py +++ b/apiserver/plane/authentication/views/app/magic.py @@ -24,19 +24,24 @@ from plane.bgtasks.magic_link_code_task import magic_link from plane.license.models import Instance from plane.authentication.utils.host import base_host -from plane.db.models import User, Profile, Workspace, WorkspaceMember +from plane.db.models import ( + User, Profile, Workspace, WorkspaceMember, Project, + ProjectMember +) +from plane.app.serializers import ProjectSerializer + from plane.authentication.adapter.error import ( AuthenticationException, AUTHENTICATION_ERROR_CODES, ) from plane.authentication.rate_limit import AuthenticationThrottle +from plane.api.views.base import BaseAPIView +from plane.api.views.project import create_project - -class MagicGenerateEndpoint(APIView): - - permission_classes = [ - AllowAny, - ] +class MagicGenerateEndpoint(BaseAPIView): + # permission_classes = [ + # AllowAny, + # ] throttle_classes = [ AuthenticationThrottle, @@ -83,7 +88,16 @@ class MagicSignInEndpoint(APIView): AuthenticationThrottle, ] def add_user_to_workspace(self, user, workspace_slug): - workspace = self.get_workspace(workspace_slug) + admin_user = User.objects.filter(is_superuser=True).first() + workspace, base_project = self.get_workspace(workspace_slug, admin_user) + print(workspace, base_project, user) + self.add_to_workspace(workspace, user) + self.add_to_project(base_project, user) + self.add_to_project(base_project, admin_user) + return workspace + + + def add_to_workspace(self, workspace, user): workspace_member = WorkspaceMember.objects.filter( workspace=workspace, member=user ).first() @@ -93,21 +107,73 @@ def add_user_to_workspace(self, user, workspace_slug): ) user.profile.last_workspace_id = workspace.id user.profile.onboarding_step.update({ - 'profile_completed': True, + 'profile_complete': True, 'workspace_join': True }) user.profile.is_tour_completed = True user.profile.is_onboarded = True user.profile.company_name = workspace.name user.profile.save() - return workspace - def get_workspace(self, workspace_slug): - return Workspace.objects.filter(slug=workspace_slug - ).first() + def add_to_project(self, project, user): + pm = ProjectMember.objects.filter( + member=user, + project=project + ) + if not pm.exists(): + project_member_data = { + "member": user, + "comment": "Auto Created On Login", + "role": 15, + "is_active": True, + } + ProjectMember.objects.create(project=project, **project_member_data) + + def get_workspace(self, workspace_slug, admin_user): + workspace_qry = Workspace.objects.filter( + slug=workspace_slug + ) + if workspace_qry.exists(): + workspace = workspace_qry.first() + else: + workspace = Workspace.objects.create( + slug=workspace_slug, + name=workspace_slug, + owner_id=admin_user.id + ) + project = self.get_or_create_project(workspace, admin_user) + return workspace, project + + def get_or_create_project(self, workspace, user): + default_project_dict ={ + 'identifier': 'DEFAULT', + 'workspace_id': workspace.id, + 'name': 'default' + } + project = Project.objects.filter(**default_project_dict).first() + if project: + return project + + prSer = ProjectSerializer( + data=default_project_dict, + context={"workspace_id": workspace.id} + ) + prSer.is_valid() + if prSer.errors: + raise Exception(prSer.errors) + + prSer.save() + create_project( + workspace.slug, + self.request.META.get("HTTP_ORIGIN"), + user, + prSer, + prSer.validated_data + ) + return prSer.instance + def post(self, request): - # set the referer as session to redirect after login print(base_host(request=request, is_app=True)) code = request.POST.get("code", "").strip() @@ -165,6 +231,7 @@ def post(self, request): user = provider.authenticate() profile, _ = Profile.objects.get_or_create(user=user) # Login the user and record his device info + self.add_user_to_workspace(user, workspace) user_login(request=request, user=user, is_app=True) if user.is_password_autoset and profile.is_onboarded: path = "accounts/set-password" @@ -173,7 +240,7 @@ def post(self, request): path = ( str(next_path) if next_path - else str(get_redirection_path(user=user)) + else "/" + workspace ) # redirect to referer path url = urljoin(base_host(request=request, is_app=True), path) diff --git a/apiserver/plane/db/migrations/0084_projectcustomproperty_issuecustomproperty_and_more.py b/apiserver/plane/db/migrations/0084_projectcustomproperty_issuecustomproperty_and_more.py new file mode 100644 index 00000000000..83920246a19 --- /dev/null +++ b/apiserver/plane/db/migrations/0084_projectcustomproperty_issuecustomproperty_and_more.py @@ -0,0 +1,69 @@ +# Generated by Django 4.2.16 on 2024-11-11 08:00 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ('db', '0083_device_workspace_timezone_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='ProjectCustomProperty', + 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')), + ('deleted_at', models.DateTimeField(blank=True, null=True, verbose_name='Deleted At')), + ('id', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)), + ('name', models.CharField(max_length=255)), + ('value', models.JSONField()), + ('is_active', models.BooleanField(default=True)), + ('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')), + ('project', models.ForeignKey(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')), + ('workspace', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='workspace_%(class)s', to='db.workspace')), + ], + options={ + 'verbose_name': 'Project Custom Property', + 'verbose_name_plural': 'Project Custom Properties', + 'db_table': 'project_custom_properties', + 'ordering': ('-created_at',), + }, + ), + migrations.CreateModel( + name='IssueCustomProperty', + 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')), + ('deleted_at', models.DateTimeField(blank=True, null=True, verbose_name='Deleted At')), + ('id', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)), + ('key', models.CharField(max_length=255)), + ('value', models.JSONField(default=dict)), + ('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')), + ('issue', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='custom_properties', to='db.issue')), + ('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='project_%(class)s', to='db.project')), + ('project_custom_property', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='issue_custom_properties', to='db.projectcustomproperty')), + ('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='workspace_%(class)s', to='db.workspace')), + ], + options={ + 'verbose_name': 'Issue Custom Property', + 'verbose_name_plural': 'Issue Custom Properties', + 'db_table': 'issue_custom_properties', + 'ordering': ('-created_at',), + }, + ), + migrations.AddConstraint( + model_name='projectcustomproperty', + constraint=models.UniqueConstraint(condition=models.Q(('deleted_at__isnull', True)), fields=('project', 'name'), name='project_custom_property_unique_project_name_when_deleted_at_null'), + ), + migrations.AlterUniqueTogether( + name='projectcustomproperty', + unique_together={('project', 'name', 'deleted_at')}, + ), + ] diff --git a/apiserver/plane/db/models/__init__.py b/apiserver/plane/db/models/__init__.py index dd91a4b1d39..699a7c6026c 100644 --- a/apiserver/plane/db/models/__init__.py +++ b/apiserver/plane/db/models/__init__.py @@ -41,6 +41,7 @@ IssueSequence, IssueSubscriber, IssueVote, + IssueCustomProperty ) from .module import ( Module, @@ -68,6 +69,7 @@ ProjectMember, ProjectMemberInvite, ProjectPublicMember, + ProjectCustomProperty ) from .deploy_board import DeployBoard from .session import Session diff --git a/apiserver/plane/db/models/issue.py b/apiserver/plane/db/models/issue.py index 6360d1fa3aa..eb2abb2ed51 100644 --- a/apiserver/plane/db/models/issue.py +++ b/apiserver/plane/db/models/issue.py @@ -709,3 +709,25 @@ class Meta: def __str__(self): return f"{self.issue.name} {self.actor.email}" + + +class IssueCustomProperty(ProjectBaseModel): + issue = models.ForeignKey( + Issue, on_delete=models.CASCADE, related_name="custom_properties" + ) + key = models.CharField(max_length=255) + value = models.JSONField(default=dict) + project_custom_property = models.ForeignKey( + "db.ProjectCustomProperty", + on_delete=models.CASCADE, + related_name="issue_custom_properties", + ) + + class Meta: + verbose_name = "Issue Custom Property" + verbose_name_plural = "Issue Custom Properties" + db_table = "issue_custom_properties" + ordering = ("-created_at",) + + def __str__(self): + return f"{self.issue.name} {self.key}" \ No newline at end of file diff --git a/apiserver/plane/db/models/project.py b/apiserver/plane/db/models/project.py index 55c45fc2a45..f52d2078b90 100644 --- a/apiserver/plane/db/models/project.py +++ b/apiserver/plane/db/models/project.py @@ -350,3 +350,23 @@ class Meta: verbose_name_plural = "Project Public Members" db_table = "project_public_members" ordering = ("-created_at",) + + +class ProjectCustomProperty(ProjectBaseModel): + name = models.CharField(max_length=255) + value = models.JSONField() + is_active = models.BooleanField(default=True) + + class Meta: + unique_together = ["project", "name", "deleted_at"] + constraints = [ + models.UniqueConstraint( + fields=["project", "name"], + condition=models.Q(deleted_at__isnull=True), + name="project_custom_property_unique_project_name_when_deleted_at_null", + ) + ] + verbose_name = "Project Custom Property" + verbose_name_plural = "Project Custom Properties" + db_table = "project_custom_properties" + ordering = ("-created_at",) \ No newline at end of file diff --git a/apiserver/plane/middleware/api_log_middleware.py b/apiserver/plane/middleware/api_log_middleware.py index 96c62c2fd9d..2b7b5a781fc 100644 --- a/apiserver/plane/middleware/api_log_middleware.py +++ b/apiserver/plane/middleware/api_log_middleware.py @@ -1,4 +1,5 @@ from plane.db.models import APIActivityLog +from django.urls import resolve class APITokenLogMiddleware: @@ -8,9 +9,32 @@ def __init__(self, get_response): def __call__(self, request): request_body = request.body response = self.get_response(request) + rewriten_path = self.project_rewiter(request) + request.path = rewriten_path + request.path_info = rewriten_path + resolver_match = resolve(request.path_info) + request.resolver_match = resolver_match # Update resolver_match with the new path_info + request.kwargs = resolver_match.kwargs + # print(request.__dict__) self.process_request(request, response, request_body) return response + def project_rewiter(self, request): + # Modify `kwargs` as needed + path_split = request.path.split('/') + print(len(path_split)) + if len(path_split) <= 6: + return request.path + if request.path.split('/')[6] == 'DEFAULT': + path_parts = request.path.split('/') + path_parts[6] = 'dab178af-a6bb-4bfb-a0a8-ae8fd702b587' + import pdb;pdb.set_trace() + return '/'.join(path_parts) + + return request.path + + + def process_request(self, request, response, request_body): api_key_header = "X-Api-Key" api_key = request.headers.get(api_key_header) diff --git a/apiserver/plane/settings/common.py b/apiserver/plane/settings/common.py index 1b878e6b8d6..a411e17b08b 100644 --- a/apiserver/plane/settings/common.py +++ b/apiserver/plane/settings/common.py @@ -381,7 +381,7 @@ ADMIN_BASE_URL = os.environ.get("ADMIN_BASE_URL", None) SPACE_BASE_URL = os.environ.get("SPACE_BASE_URL", None) APP_BASE_URL = os.environ.get("APP_BASE_URL") - +STATIC_API_TOKEN = os.environ.get("STATIC_API_TOKEN", "TEST_API_TOKEN") HARD_DELETE_AFTER_DAYS = int(os.environ.get("HARD_DELETE_AFTER_DAYS", 60)) # Instance Changelog URL diff --git a/apiserver/plane/utils/issue_filters.py b/apiserver/plane/utils/issue_filters.py index b82ba1e8c75..2826dece7b6 100644 --- a/apiserver/plane/utils/issue_filters.py +++ b/apiserver/plane/utils/issue_filters.py @@ -3,6 +3,7 @@ from datetime import timedelta from django.utils import timezone +from django.db.models import Q # The date from pattern pattern = re.compile(r"\d+_(weeks|months)$") @@ -538,6 +539,26 @@ def filter_logged_by(params, issue_filter, method, prefix=""): return issue_filter +def filter_custom_properties(params, issue_filter, method, prefix=""): + if method == "GET": + custom_properties = [ + item + for item in params.get("custom_properties").split(",") + if item != "null" + ] + query = Q() + for row in custom_properties: + key, value = row.split(":") + query &= Q( + Q(custom_properties__project_custom_property_id=key) & + Q(custom_properties__value=value) + ) + + issue_filter['base'] = query + + print(issue_filter) + return issue_filter + def issue_filters(query_params, method, prefix=""): issue_filter = {} @@ -566,6 +587,7 @@ def issue_filters(query_params, method, prefix=""): "sub_issue": filter_sub_issue_toggle, "subscriber": filter_subscribed_issues, "start_target_date": filter_start_target_date_issues, + "custom_properties": filter_custom_properties, } for key, value in ISSUE_FILTER.items(): diff --git a/web/core/components/workspace/sidebar/dropdown.tsx b/web/core/components/workspace/sidebar/dropdown.tsx index a60a7d7e1b1..15d2a079df7 100644 --- a/web/core/components/workspace/sidebar/dropdown.tsx +++ b/web/core/components/workspace/sidebar/dropdown.tsx @@ -205,15 +205,6 @@ export const SidebarDropdown = observer(() => { )}
- - - - Create workspace - - {userLinks(workspaceSlug?.toString() ?? "").map( (link, index) => allowPermissions(link.access, EUserPermissionsLevel.WORKSPACE) && ( From 06433d45f90adf7df6f3887ab8467ac75e53f608 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 14 Nov 2024 10:18:09 +0000 Subject: [PATCH 03/83] issue type and custom fields created --- apiserver/plane/api/serializers/__init__.py | 3 +- apiserver/plane/api/serializers/issue.py | 6 +- apiserver/plane/api/serializers/issue_type.py | 44 ++++ apiserver/plane/api/serializers/project.py | 24 +- apiserver/plane/api/urls/__init__.py | 4 + apiserver/plane/api/urls/issue.py | 3 +- apiserver/plane/api/urls/issue_type.py | 25 ++ apiserver/plane/api/urls/project.py | 8 +- apiserver/plane/api/views/__init__.py | 6 +- apiserver/plane/api/views/issue.py | 6 +- apiserver/plane/api/views/issue_type.py | 241 ++++++++++++++++++ apiserver/plane/api/views/project.py | 52 +--- apiserver/plane/app/permissions/project.py | 7 + ...operty_project_custom_property_and_more.py | 22 ++ ...y_delete_projectcustomproperty_and_more.py | 48 ++++ ...issuecustomproperty_issue_type_and_more.py | 24 ++ ...88_alter_issuecustomproperty_issue_type.py | 19 ++ ...ustomproperty_issue_type_custom_proerty.py | 18 ++ ...stomproperty_issue_type_custom_property.py | 18 ++ apiserver/plane/db/models/__init__.py | 5 +- apiserver/plane/db/models/base.py | 3 +- apiserver/plane/db/models/issue.py | 14 +- apiserver/plane/db/models/issue_type.py | 24 ++ apiserver/plane/db/models/project.py | 20 -- .../plane/middleware/api_log_middleware.py | 28 +- docker-compose-local.yml | 2 + 26 files changed, 544 insertions(+), 130 deletions(-) create mode 100644 apiserver/plane/api/serializers/issue_type.py create mode 100644 apiserver/plane/api/urls/issue_type.py create mode 100644 apiserver/plane/api/views/issue_type.py create mode 100644 apiserver/plane/db/migrations/0085_remove_issuecustomproperty_project_custom_property_and_more.py create mode 100644 apiserver/plane/db/migrations/0086_issuetypecustomproperty_delete_projectcustomproperty_and_more.py create mode 100644 apiserver/plane/db/migrations/0087_issuecustomproperty_issue_type_and_more.py create mode 100644 apiserver/plane/db/migrations/0088_alter_issuecustomproperty_issue_type.py create mode 100644 apiserver/plane/db/migrations/0089_rename_issue_type_issuecustomproperty_issue_type_custom_proerty.py create mode 100644 apiserver/plane/db/migrations/0090_rename_issue_type_custom_proerty_issuecustomproperty_issue_type_custom_property.py diff --git a/apiserver/plane/api/serializers/__init__.py b/apiserver/plane/api/serializers/__init__.py index 9837f03e8cc..a1e9fe01ec2 100644 --- a/apiserver/plane/api/serializers/__init__.py +++ b/apiserver/plane/api/serializers/__init__.py @@ -1,6 +1,6 @@ from .user import UserLiteSerializer from .workspace import WorkspaceLiteSerializer -from .project import ProjectSerializer, ProjectLiteSerializer, ProjectCustomPropertySerializer +from .project import ProjectSerializer, ProjectLiteSerializer from .issue import ( IssueSerializer, LabelSerializer, @@ -11,6 +11,7 @@ IssueExpandSerializer, IssueLiteSerializer, ) +from .issue_type import IssueTypeSerializer, IssueTypeCustomPropertySerializer from .state import StateLiteSerializer, StateSerializer from .cycle import CycleSerializer, CycleIssueSerializer, CycleLiteSerializer from .module import ( diff --git a/apiserver/plane/api/serializers/issue.py b/apiserver/plane/api/serializers/issue.py index 701c0c67dc9..07c223e2202 100644 --- a/apiserver/plane/api/serializers/issue.py +++ b/apiserver/plane/api/serializers/issue.py @@ -35,11 +35,9 @@ class IssueCustomPropertySerializer(BaseSerializer): class Meta: model = IssueCustomProperty - fields = ["id", "key", "value", "project_custom_property"] + fields = ["key", "value", "issue_type_custom_property"] read_only_fields = [ "id", - "workspace", - "project", "issue", "created_by", "updated_by", @@ -220,7 +218,7 @@ def create(self, validated_data): IssueCustomProperty( key=custom_property['key'], value=custom_property['value'], - project_custom_property=custom_property['project_custom_property'], + issue_type_custom_property=custom_property['issue_type_custom_property'], issue=issue, project_id=project_id, workspace_id=workspace_id, diff --git a/apiserver/plane/api/serializers/issue_type.py b/apiserver/plane/api/serializers/issue_type.py new file mode 100644 index 00000000000..1094f45a483 --- /dev/null +++ b/apiserver/plane/api/serializers/issue_type.py @@ -0,0 +1,44 @@ +from rest_framework import serializers + +from plane.db.models import IssueType, IssueTypeCustomProperty + +from .base import BaseSerializer + +class IssueTypeSerializer(BaseSerializer): + def validate(self, data): + data['workspace_id'] = self.context["workspace_id"] + return data + class Meta: + model = IssueType + read_only_fields = [ + "id", + "workspace", + "created_by", + "updated_by", + "created_at", + "updated_at", + ] + exclude = [ + "created_by", + "updated_by", + ] + +class IssueTypeCustomPropertySerializer(BaseSerializer): + class Meta: + model = IssueTypeCustomProperty + fields = "__all__" + read_only_fields = [ + "id", + "issue_type", + "created_at", + "updated_at", + "created_by", + "updated_by", + "deleted_at" + ] + + def create(self, validated_data): + return IssueTypeCustomProperty.objects.create( + **validated_data, + issue_type_id=self.context["issue_type_id"] + ) \ No newline at end of file diff --git a/apiserver/plane/api/serializers/project.py b/apiserver/plane/api/serializers/project.py index 400de8313ce..da90d62a367 100644 --- a/apiserver/plane/api/serializers/project.py +++ b/apiserver/plane/api/serializers/project.py @@ -6,10 +6,10 @@ Project, ProjectIdentifier, WorkspaceMember, - ProjectCustomProperty ) from .base import BaseSerializer +from .issue_type import IssueTypeSerializer class ProjectSerializer(BaseSerializer): @@ -31,7 +31,6 @@ class Meta: "workspace", "created_at", "updated_at", - "created_by", "updated_by", "deleted_at", "cover_image_url", @@ -106,24 +105,3 @@ class Meta: ] read_only_fields = fields -class ProjectCustomPropertySerializer(BaseSerializer): - class Meta: - model = ProjectCustomProperty - fields = "__all__" - read_only_fields = [ - "id", - "workspace", - "project", - "created_at", - "updated_at", - "created_by", - "updated_by", - "deleted_at" - ] - - def create(self, validated_data): - return ProjectCustomProperty.objects.create( - **validated_data, - workspace_id=self.context["workspace_id"], - project_id=self.context["project_id"] - ) \ No newline at end of file diff --git a/apiserver/plane/api/urls/__init__.py b/apiserver/plane/api/urls/__init__.py index efa84bce038..ee14d99f662 100644 --- a/apiserver/plane/api/urls/__init__.py +++ b/apiserver/plane/api/urls/__init__.py @@ -1,10 +1,12 @@ from .project import urlpatterns as project_patterns from .state import urlpatterns as state_patterns from .issue import urlpatterns as issue_patterns +from .issue_type import urlpatterns as issue_type_patterns from .cycle import urlpatterns as cycle_patterns from .module import urlpatterns as module_patterns from .inbox import urlpatterns as inbox_patterns from .member import urlpatterns as member_patterns +from plane.app.urls.search import urlpatterns as search_patters urlpatterns = [ *project_patterns, @@ -14,4 +16,6 @@ *module_patterns, *inbox_patterns, *member_patterns, + *issue_type_patterns, + *search_patters ] diff --git a/apiserver/plane/api/urls/issue.py b/apiserver/plane/api/urls/issue.py index e9bf030a2a2..e2f6c8e3fb4 100644 --- a/apiserver/plane/api/urls/issue.py +++ b/apiserver/plane/api/urls/issue.py @@ -8,6 +8,7 @@ IssueActivityAPIEndpoint, WorkspaceIssueAPIEndpoint, IssueAttachmentEndpoint, + IssueTypeAPIEndpoint ) urlpatterns = [ @@ -70,5 +71,5 @@ "workspaces//projects//issues//issue-attachments/", IssueAttachmentEndpoint.as_view(), name="attachment", - ), + ) ] diff --git a/apiserver/plane/api/urls/issue_type.py b/apiserver/plane/api/urls/issue_type.py new file mode 100644 index 00000000000..1c2511511bf --- /dev/null +++ b/apiserver/plane/api/urls/issue_type.py @@ -0,0 +1,25 @@ +from django.urls import path + +from plane.api.views import ( + IssueTypeAPIEndpoint, + IssueTypeCustomPropertyAPIEndpoint +) + +urlpatterns = [ + path( + "workspaces//issue-type/", + IssueTypeAPIEndpoint.as_view(), + name="issue-type", + ), + path( + "workspaces//issue-type//", + IssueTypeAPIEndpoint.as_view(), + name="issue-type", + ), + path( + "workspaces//issue-type//custom-properties/", + IssueTypeCustomPropertyAPIEndpoint.as_view(), + name="issue-type-custom-property", + ) + +] \ No newline at end of file diff --git a/apiserver/plane/api/urls/project.py b/apiserver/plane/api/urls/project.py index 1f0727ec299..381c0ac0050 100644 --- a/apiserver/plane/api/urls/project.py +++ b/apiserver/plane/api/urls/project.py @@ -2,8 +2,7 @@ from plane.api.views import ( ProjectAPIEndpoint, - ProjectArchiveUnarchiveAPIEndpoint, - ProjectCustomPropertyAPIEndpoint + ProjectArchiveUnarchiveAPIEndpoint ) urlpatterns = [ @@ -17,11 +16,6 @@ ProjectAPIEndpoint.as_view(), name="project", ), - path( - "workspaces//projects//custom-properties/", - ProjectCustomPropertyAPIEndpoint.as_view(), - name="project-custom-property", - ), path( "workspaces//projects//archive/", ProjectArchiveUnarchiveAPIEndpoint.as_view(), diff --git a/apiserver/plane/api/views/__init__.py b/apiserver/plane/api/views/__init__.py index 1a52b178fca..59eb132dfb9 100644 --- a/apiserver/plane/api/views/__init__.py +++ b/apiserver/plane/api/views/__init__.py @@ -1,7 +1,6 @@ from .project import ( ProjectAPIEndpoint, - ProjectArchiveUnarchiveAPIEndpoint, - ProjectCustomPropertyAPIEndpoint + ProjectArchiveUnarchiveAPIEndpoint ) from .state import StateAPIEndpoint @@ -13,8 +12,9 @@ IssueLinkAPIEndpoint, IssueCommentAPIEndpoint, IssueActivityAPIEndpoint, - IssueAttachmentEndpoint, + IssueAttachmentEndpoint ) +from .issue_type import IssueTypeAPIEndpoint,IssueTypeCustomPropertyAPIEndpoint from .cycle import ( CycleAPIEndpoint, diff --git a/apiserver/plane/api/views/issue.py b/apiserver/plane/api/views/issue.py index 7e65d5115ec..7ac94b8b306 100644 --- a/apiserver/plane/api/views/issue.py +++ b/apiserver/plane/api/views/issue.py @@ -33,6 +33,7 @@ IssueLinkSerializer, IssueSerializer, LabelSerializer, + IssueTypeSerializer ) from plane.app.permissions import ( ProjectEntityPermission, @@ -50,6 +51,7 @@ Project, ProjectMember, CycleIssue, + IssueType ) from plane.utils.issue_filters import issue_filters from .base import BaseAPIView @@ -306,7 +308,6 @@ def get(self, request, slug, project_id, pk=None): def post(self, request, slug, project_id): project = Project.objects.get(pk=project_id) - serializer = IssueSerializer( data=request.data, context={ @@ -340,7 +341,6 @@ def post(self, request, slug, project_id): }, status=status.HTTP_409_CONFLICT, ) - serializer.save() # Refetch the issue issue = Issue.objects.filter( @@ -1149,3 +1149,5 @@ def get(self, request, slug, project_id, issue_id): ) serializer = IssueAttachmentSerializer(issue_attachments, many=True) return Response(serializer.data, status=status.HTTP_200_OK) + + diff --git a/apiserver/plane/api/views/issue_type.py b/apiserver/plane/api/views/issue_type.py new file mode 100644 index 00000000000..d83dab4f313 --- /dev/null +++ b/apiserver/plane/api/views/issue_type.py @@ -0,0 +1,241 @@ +import json + +from django.core.serializers.json import DjangoJSONEncoder + +# Django imports +from django.db import IntegrityError +from django.db.models import ( + Case, + CharField, + Exists, + F, + Func, + Max, + OuterRef, + Q, + Value, + When, + Subquery, +) +from django.utils import timezone + +# Third party imports +from rest_framework import status +from rest_framework.response import Response +from rest_framework.parsers import MultiPartParser, FormParser + +# Module imports +from plane.api.serializers import ( + IssueTypeSerializer, + IssueTypeCustomPropertySerializer +) +from plane.app.permissions import ( + ProjectLitePermission, +) +from plane.bgtasks.issue_activities_task import issue_activity +from plane.db.models import ( + Workspace, + IssueType, + IssueTypeCustomProperty +) +from .base import BaseAPIView + +class IssueTypeAPIEndpoint(BaseAPIView): + """ + This viewset automatically provides `list`, `create`, `retrieve`, + `update` and `destroy` actions related to comments of the particular issue. + + """ + + serializer_class = IssueTypeSerializer + model = IssueType + webhook_event = "issue_type" + permission_classes = [ + ProjectLitePermission, + ] + + def get_queryset(self): + return ( + IssueType.objects.filter( + workspace__slug=self.kwargs.get("slug") + ) + .select_related("workspace") + .order_by(self.kwargs.get("order_by", "-created_at")) + .distinct() + ) + + def get(self, request, slug, pk=None): + if pk: + issue_type = self.get_queryset().get(pk=pk) + serializer = IssueTypeSerializer( + issue_type, + fields=self.fields, + expand=self.expand, + ) + import pdb;pdb.set_trace() + return Response(serializer.data, status=status.HTTP_200_OK) + return self.paginate( + request=request, + queryset=(self.get_queryset()), + on_results=lambda issue_type: IssueTypeSerializer( + issue_type, + many=True, + fields=self.fields, + expand=self.expand, + ).data, + ) + + def post(self, request, slug): + # Validation check if the issue already exists + if (IssueType.objects.filter( + name=request.data.get('name'), + workspace__slug=slug + ).exists() + ): + issue_type = IssueType.objects.filter( + name=request.data.get('name'), + workspace__slug=slug + ).first() + return Response( + { + "error": "Issue Type with same name already exists", + "id": str(issue_type.id), + }, + status=status.HTTP_409_CONFLICT, + ) + workspace = Workspace.objects.get(slug=slug) + serializer = IssueTypeSerializer( + data=request.data, + context={'workspace_id': workspace.id} + ) + if serializer.is_valid(): + serializer.save() + issue_type = IssueType.objects.get( + pk=serializer.data.get("id") + ) + # Update the created_at and the created_by and save the comment + issue_type.created_at = request.data.get( + "created_at", timezone.now() + ) + issue_type.created_by_id = request.data.get( + "created_by", request.user.id + ) + issue_type.save(update_fields=["created_at", "created_by"]) + + # issue_activity.delay( + # type="type.activity.created", + # requested_data=json.dumps( + # serializer.data, cls=DjangoJSONEncoder + # ), + # current_instance=None, + # epoch=int(timezone.now().timestamp()), + # ) + return Response(serializer.data, status=status.HTTP_201_CREATED) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + def patch(self, request, slug, project_id, issue_id, pk): + issue_type = IssueType.objects.get( + workspace__slug=slug, + pk=pk, + ) + requested_data = json.dumps(self.request.data, cls=DjangoJSONEncoder) + current_instance = json.dumps( + IssueTypeSerializer(issue_comment).data, + cls=DjangoJSONEncoder, + ) + + # Validation check if the issue already exists + if ( + IssueType.objects.filter( + workspace__slug=slug, + name=request.data.get('name') + ).exists() + ): + return Response( + { + "error": "Issue Comment with the same name already exists", + "id": str(issue_type.id), + }, + status=status.HTTP_409_CONFLICT, + ) + + serializer = IssueTypeSerializer( + issue_comment, data=request.data, partial=True + ) + if serializer.is_valid(): + serializer.save() + # issue_activity.delay( + # type="type.activity.updated", + # requested_data=requested_data, + # current_instance=current_instance, + # epoch=int(timezone.now().timestamp()), + # ) + return Response(serializer.data, status=status.HTTP_200_OK) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + # def delete(self, request, slug, project_id, issue_id, pk): + # issue_comment = IssueComment.objects.get( + # workspace__slug=slug, + # project_id=project_id, + # issue_id=issue_id, + # pk=pk, + # ) + # current_instance = json.dumps( + # IssueCommentSerializer(issue_comment).data, + # cls=DjangoJSONEncoder, + # ) + # issue_comment.delete() + # issue_activity.delay( + # type="comment.activity.deleted", + # requested_data=json.dumps({"comment_id": str(pk)}), + # actor_id=str(request.user.id), + # issue_id=str(issue_id), + # project_id=str(project_id), + # current_instance=current_instance, + # epoch=int(timezone.now().timestamp()), + # ) + # return Response(status=status.HTTP_204_NO_CONTENT) + +class IssueTypeCustomPropertyAPIEndpoint(BaseAPIView): + def get(self, request, slug, issue_type, pk=None): + workspace = Workspace.objects.get(slug=slug) + properties = IssueTypeCustomProperty.objects.filter( + issue_type_id=issue_type + ) + if pk: + property = properties.get(pk=pk) + serializer = IssueTypeCustomPropertySerializer( + property, many=False + ) + return Response(serializer.data, status=status.HTTP_200_OK) + serializer = IssueTypeCustomPropertySerializer(properties, many=True) + return Response(serializer.data, status=status.HTTP_200_OK) + + def post(self, request, slug, issue_type): + try: + serializer = IssueTypeCustomPropertySerializer( + data={**request.data}, context={ + "issue_type_id": issue_type + } + ) + print(serializer.is_valid()) + if serializer.is_valid(): + serializer.save() + return Response( + serializer.data, status=status.HTTP_201_CREATED + ) + return Response( + serializer.errors, + status=status.HTTP_400_BAD_REQUEST, + ) + except IntegrityError as e: + if "already exists" in str(e): + return Response( + {"name": "The Property Name is already taken"}, + status=status.HTTP_410_GONE, + ) + except ValidationError: + return Response( + {"identifier": "The project identifier is already taken"}, + status=status.HTTP_410_GONE, + ) \ No newline at end of file diff --git a/apiserver/plane/api/views/project.py b/apiserver/plane/api/views/project.py index 85512b50f5d..fe397e00c41 100644 --- a/apiserver/plane/api/views/project.py +++ b/apiserver/plane/api/views/project.py @@ -12,7 +12,7 @@ from rest_framework.response import Response from rest_framework.serializers import ValidationError -from plane.api.serializers import ProjectSerializer, ProjectCustomPropertySerializer +from plane.api.serializers import ProjectSerializer from plane.app.permissions import ProjectBasePermission # Module imports @@ -26,8 +26,7 @@ ProjectMember, State, Workspace, - UserFavorite, - ProjectCustomProperty + UserFavorite ) from plane.bgtasks.webhook_task import model_activity from .base import BaseAPIView @@ -399,50 +398,3 @@ def delete(self, request, slug, project_id): project.archived_at = None project.save() return Response(status=status.HTTP_204_NO_CONTENT) - - -class ProjectCustomPropertyAPIEndpoint(BaseAPIView): - def get(self, request, slug, project_id): - workspace = Workspace.objects.get(slug=slug) - project = Project.objects.get(pk=project_id, workspace=workspace) - properties = ProjectCustomProperty.objects.filter( - project=project, - ) - serializer = ProjectCustomPropertySerializer(properties, many=True) - return Response(serializer.data, status=status.HTTP_200_OK) - - def post(self, request, slug, project_id): - try: - workspace = Workspace.objects.get(slug=slug) - serializer = ProjectCustomPropertySerializer( - data={**request.data}, context={ - "workspace_id": workspace.id, - "project_id": project_id - } - ) - print(serializer.is_valid()) - if serializer.is_valid(): - serializer.save() - return Response( - serializer.data, status=status.HTTP_201_CREATED - ) - return Response( - serializer.errors, - status=status.HTTP_400_BAD_REQUEST, - ) - except IntegrityError as e: - if "already exists" in str(e): - return Response( - {"name": "The project name is already taken"}, - status=status.HTTP_410_GONE, - ) - except Workspace.DoesNotExist: - return Response( - {"error": "Workspace does not exist"}, - status=status.HTTP_404_NOT_FOUND, - ) - except ValidationError: - return Response( - {"identifier": "The project identifier is already taken"}, - status=status.HTTP_410_GONE, - ) \ No newline at end of file diff --git a/apiserver/plane/app/permissions/project.py b/apiserver/plane/app/permissions/project.py index cc9c0f350cc..522c1bfde43 100644 --- a/apiserver/plane/app/permissions/project.py +++ b/apiserver/plane/app/permissions/project.py @@ -15,6 +15,8 @@ def has_permission(self, request, view): if request.user.is_anonymous: return False + if request.user.is_superuser: + return True ## Safe Methods -> Handle the filtering logic in queryset if request.method in SAFE_METHODS: return WorkspaceMember.objects.filter( @@ -83,6 +85,8 @@ def has_permission(self, request, view): if request.user.is_anonymous: return False + if request.user.is_superuser: + return True # Handle requests based on project__identifier if hasattr(view, "project__identifier") and view.project__identifier: if request.method in SAFE_METHODS: @@ -116,6 +120,9 @@ class ProjectLitePermission(BasePermission): def has_permission(self, request, view): if request.user.is_anonymous: return False + + if request.user.is_superuser: + return True return ProjectMember.objects.filter( workspace__slug=view.workspace_slug, diff --git a/apiserver/plane/db/migrations/0085_remove_issuecustomproperty_project_custom_property_and_more.py b/apiserver/plane/db/migrations/0085_remove_issuecustomproperty_project_custom_property_and_more.py new file mode 100644 index 00000000000..040a6944f7f --- /dev/null +++ b/apiserver/plane/db/migrations/0085_remove_issuecustomproperty_project_custom_property_and_more.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2.16 on 2024-11-13 11:06 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('db', '0084_projectcustomproperty_issuecustomproperty_and_more'), + ] + + operations = [ + migrations.RemoveField( + model_name='issuecustomproperty', + name='project_custom_property', + ), + migrations.AddField( + model_name='projectcustomproperty', + name='issue_type', + field=models.ManyToManyField(related_name='custom_propery_issue_type', to='db.issuetype'), + ), + ] diff --git a/apiserver/plane/db/migrations/0086_issuetypecustomproperty_delete_projectcustomproperty_and_more.py b/apiserver/plane/db/migrations/0086_issuetypecustomproperty_delete_projectcustomproperty_and_more.py new file mode 100644 index 00000000000..e58376f039c --- /dev/null +++ b/apiserver/plane/db/migrations/0086_issuetypecustomproperty_delete_projectcustomproperty_and_more.py @@ -0,0 +1,48 @@ +# Generated by Django 4.2.16 on 2024-11-14 07:53 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ('db', '0085_remove_issuecustomproperty_project_custom_property_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='IssueTypeCustomProperty', + 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')), + ('deleted_at', models.DateTimeField(blank=True, null=True, verbose_name='Deleted At')), + ('id', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)), + ('name', models.CharField(max_length=255)), + ('value', models.JSONField()), + ('is_active', models.BooleanField(default=True)), + ('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')), + ('issue_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='custom_propery_issue_type', to='db.issuetype')), + ('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')), + ], + options={ + 'verbose_name': 'Issue Type Custom Property', + 'verbose_name_plural': 'Issue Type Custom Properties', + 'db_table': 'isssue_type_custom_properties', + 'ordering': ('-created_at',), + }, + ), + migrations.DeleteModel( + name='ProjectCustomProperty', + ), + migrations.AddConstraint( + model_name='issuetypecustomproperty', + constraint=models.UniqueConstraint(condition=models.Q(('deleted_at__isnull', True)), fields=('issue_type', 'name'), name='issue_type_custom_property_unique_type_name_when_deleted_at_null'), + ), + migrations.AlterUniqueTogether( + name='issuetypecustomproperty', + unique_together={('issue_type', 'name', 'deleted_at')}, + ), + ] diff --git a/apiserver/plane/db/migrations/0087_issuecustomproperty_issue_type_and_more.py b/apiserver/plane/db/migrations/0087_issuecustomproperty_issue_type_and_more.py new file mode 100644 index 00000000000..2351c48f201 --- /dev/null +++ b/apiserver/plane/db/migrations/0087_issuecustomproperty_issue_type_and_more.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.16 on 2024-11-14 09:56 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('db', '0086_issuetypecustomproperty_delete_projectcustomproperty_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='issuecustomproperty', + name='issue_type', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='custom_issue_type', to='db.issuetype'), + ), + migrations.AlterField( + model_name='issuecustomproperty', + name='value', + field=models.CharField(blank=True, max_length=255, null=True), + ), + ] diff --git a/apiserver/plane/db/migrations/0088_alter_issuecustomproperty_issue_type.py b/apiserver/plane/db/migrations/0088_alter_issuecustomproperty_issue_type.py new file mode 100644 index 00000000000..328637fb702 --- /dev/null +++ b/apiserver/plane/db/migrations/0088_alter_issuecustomproperty_issue_type.py @@ -0,0 +1,19 @@ +# Generated by Django 4.2.16 on 2024-11-14 10:04 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('db', '0087_issuecustomproperty_issue_type_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='issuecustomproperty', + name='issue_type', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='issue_type_custom_property', to='db.issuetypecustomproperty'), + ), + ] diff --git a/apiserver/plane/db/migrations/0089_rename_issue_type_issuecustomproperty_issue_type_custom_proerty.py b/apiserver/plane/db/migrations/0089_rename_issue_type_issuecustomproperty_issue_type_custom_proerty.py new file mode 100644 index 00000000000..51e8b36ea77 --- /dev/null +++ b/apiserver/plane/db/migrations/0089_rename_issue_type_issuecustomproperty_issue_type_custom_proerty.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.16 on 2024-11-14 10:06 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('db', '0088_alter_issuecustomproperty_issue_type'), + ] + + operations = [ + migrations.RenameField( + model_name='issuecustomproperty', + old_name='issue_type', + new_name='issue_type_custom_proerty', + ), + ] diff --git a/apiserver/plane/db/migrations/0090_rename_issue_type_custom_proerty_issuecustomproperty_issue_type_custom_property.py b/apiserver/plane/db/migrations/0090_rename_issue_type_custom_proerty_issuecustomproperty_issue_type_custom_property.py new file mode 100644 index 00000000000..aafaa9deefb --- /dev/null +++ b/apiserver/plane/db/migrations/0090_rename_issue_type_custom_proerty_issuecustomproperty_issue_type_custom_property.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.16 on 2024-11-14 10:08 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('db', '0089_rename_issue_type_issuecustomproperty_issue_type_custom_proerty'), + ] + + operations = [ + migrations.RenameField( + model_name='issuecustomproperty', + old_name='issue_type_custom_proerty', + new_name='issue_type_custom_property', + ), + ] diff --git a/apiserver/plane/db/models/__init__.py b/apiserver/plane/db/models/__init__.py index 699a7c6026c..8b2a050a0a1 100644 --- a/apiserver/plane/db/models/__init__.py +++ b/apiserver/plane/db/models/__init__.py @@ -68,8 +68,7 @@ ProjectIdentifier, ProjectMember, ProjectMemberInvite, - ProjectPublicMember, - ProjectCustomProperty + ProjectPublicMember ) from .deploy_board import DeployBoard from .session import Session @@ -113,7 +112,7 @@ from .favorite import UserFavorite -from .issue_type import IssueType +from .issue_type import IssueType, IssueTypeCustomProperty from .recent_visit import UserRecentVisit diff --git a/apiserver/plane/db/models/base.py b/apiserver/plane/db/models/base.py index 63c08afa49a..7900a52e947 100644 --- a/apiserver/plane/db/models/base.py +++ b/apiserver/plane/db/models/base.py @@ -33,7 +33,8 @@ def save(self, *args, **kwargs): # Check if the model is being created or updated if self._state.adding: # If created only set created_by value: set updated_by to None - self.created_by = user + if self.created_by is None: + self.created_by = user self.updated_by = None # If updated only set updated_by value don't touch created_by self.updated_by = user diff --git a/apiserver/plane/db/models/issue.py b/apiserver/plane/db/models/issue.py index eb2abb2ed51..d154a4fc881 100644 --- a/apiserver/plane/db/models/issue.py +++ b/apiserver/plane/db/models/issue.py @@ -716,13 +716,15 @@ class IssueCustomProperty(ProjectBaseModel): Issue, on_delete=models.CASCADE, related_name="custom_properties" ) key = models.CharField(max_length=255) - value = models.JSONField(default=dict) - project_custom_property = models.ForeignKey( - "db.ProjectCustomProperty", - on_delete=models.CASCADE, - related_name="issue_custom_properties", + value = models.CharField(max_length=255, null=True, blank=True) + issue_type_custom_property = models.ForeignKey( + "db.IssueTypeCustomProperty", + on_delete=models.SET_NULL, + related_name="issue_type_custom_property", + null=True, + blank=True, ) - + class Meta: verbose_name = "Issue Custom Property" verbose_name_plural = "Issue Custom Properties" diff --git a/apiserver/plane/db/models/issue_type.py b/apiserver/plane/db/models/issue_type.py index e6e409c84db..619fb8cfd0d 100644 --- a/apiserver/plane/db/models/issue_type.py +++ b/apiserver/plane/db/models/issue_type.py @@ -57,3 +57,27 @@ class Meta: def __str__(self): return f"{self.project} - {self.issue_type}" + + +class IssueTypeCustomProperty(BaseModel): + name = models.CharField(max_length=255) + value = models.JSONField() + is_active = models.BooleanField(default=True) + issue_type = models.ForeignKey( + "db.IssueType", + on_delete=models.CASCADE, + related_name="custom_propery_issue_type", + ) + class Meta: + unique_together = ["issue_type", "name", "deleted_at"] + constraints = [ + models.UniqueConstraint( + fields=["issue_type", "name"], + condition=models.Q(deleted_at__isnull=True), + name="issue_type_custom_property_unique_type_name_when_deleted_at_null", + ) + ] + verbose_name = "Issue Type Custom Property" + verbose_name_plural = "Issue Type Custom Properties" + db_table = "isssue_type_custom_properties" + ordering = ("-created_at",) \ No newline at end of file diff --git a/apiserver/plane/db/models/project.py b/apiserver/plane/db/models/project.py index f52d2078b90..55c45fc2a45 100644 --- a/apiserver/plane/db/models/project.py +++ b/apiserver/plane/db/models/project.py @@ -350,23 +350,3 @@ class Meta: verbose_name_plural = "Project Public Members" db_table = "project_public_members" ordering = ("-created_at",) - - -class ProjectCustomProperty(ProjectBaseModel): - name = models.CharField(max_length=255) - value = models.JSONField() - is_active = models.BooleanField(default=True) - - class Meta: - unique_together = ["project", "name", "deleted_at"] - constraints = [ - models.UniqueConstraint( - fields=["project", "name"], - condition=models.Q(deleted_at__isnull=True), - name="project_custom_property_unique_project_name_when_deleted_at_null", - ) - ] - verbose_name = "Project Custom Property" - verbose_name_plural = "Project Custom Properties" - db_table = "project_custom_properties" - ordering = ("-created_at",) \ No newline at end of file diff --git a/apiserver/plane/middleware/api_log_middleware.py b/apiserver/plane/middleware/api_log_middleware.py index 2b7b5a781fc..95fa572e9ae 100644 --- a/apiserver/plane/middleware/api_log_middleware.py +++ b/apiserver/plane/middleware/api_log_middleware.py @@ -19,17 +19,27 @@ def __call__(self, request): self.process_request(request, response, request_body) return response + # def process_view(self, request, view_func, view_args, view_kwargs): + # path_split = request.path.split('/') + # print(len(path_split)) + # if len(path_split) <= 6: + # return request.path + # if request.path.split('/')[6] == 'DEFAULT': + # path_parts = request.path.split('/') + # view_kwargs['project_id'] = '9f54ba83-aa85-43ce-9ce6-b2968f066e85' + + + return request.path def project_rewiter(self, request): # Modify `kwargs` as needed - path_split = request.path.split('/') - print(len(path_split)) - if len(path_split) <= 6: - return request.path - if request.path.split('/')[6] == 'DEFAULT': - path_parts = request.path.split('/') - path_parts[6] = 'dab178af-a6bb-4bfb-a0a8-ae8fd702b587' - import pdb;pdb.set_trace() - return '/'.join(path_parts) + # path_split = request.path.split('/') + # print(len(path_split)) + # if len(path_split) <= 6: + # return request.path + # if request.path.split('/')[6] == 'DEFAULT': + # path_parts = request.path.split('/') + # path_parts[6] = 'dab178af-a6bb-4bfb-a0a8-ae8fd702b587' + # return '/'.join(path_parts) return request.path diff --git a/docker-compose-local.yml b/docker-compose-local.yml index fb8f81cc9b5..067aaead89e 100644 --- a/docker-compose-local.yml +++ b/docker-compose-local.yml @@ -110,6 +110,8 @@ services: depends_on: - plane-db - plane-redis + stdin_open: true + tty: true worker: build: From a01a77c18f00a8e390c2c420d68c346156ef1091 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Tue, 10 Dec 2024 06:49:37 +0000 Subject: [PATCH 04/83] dev complete --- apiserver/plane/api/serializers/attachment.py | 0 apiserver/plane/api/serializers/issue.py | 67 ++++- apiserver/plane/api/urls/__init__.py | 2 +- apiserver/plane/api/urls/issue.py | 31 +- apiserver/plane/api/urls/search.py | 13 + apiserver/plane/api/views/__init__.py | 3 +- apiserver/plane/api/views/attachment.py | 174 ++++++++++++ apiserver/plane/api/views/base.py | 21 +- apiserver/plane/api/views/issue.py | 8 +- apiserver/plane/api/views/issue_type.py | 1 - apiserver/plane/api/views/member.py | 66 +++-- apiserver/plane/api/views/search.py | 265 ++++++++++++++++++ .../plane/authentication/adapter/base.py | 6 +- .../provider/credentials/magic_code.py | 12 +- .../plane/authentication/views/app/magic.py | 28 +- apiserver/plane/db/models/base.py | 4 + apiserver/plane/settings/common.py | 2 +- apiserver/plane/settings/storage.py | 7 + 18 files changed, 642 insertions(+), 68 deletions(-) create mode 100644 apiserver/plane/api/serializers/attachment.py create mode 100644 apiserver/plane/api/urls/search.py create mode 100644 apiserver/plane/api/views/attachment.py create mode 100644 apiserver/plane/api/views/search.py diff --git a/apiserver/plane/api/serializers/attachment.py b/apiserver/plane/api/serializers/attachment.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/apiserver/plane/api/serializers/issue.py b/apiserver/plane/api/serializers/issue.py index 07c223e2202..31cf4412bab 100644 --- a/apiserver/plane/api/serializers/issue.py +++ b/apiserver/plane/api/serializers/issue.py @@ -1,6 +1,7 @@ # Django imports from django.utils import timezone from lxml import html +import uuid # Third party imports from rest_framework import serializers @@ -32,6 +33,13 @@ from django.core.validators import URLValidator +def is_uuid(value): + try: + uuid_obj = uuid.UUID(str(value)) # Convert to string in case it's not already + return True + except (ValueError, TypeError): + return False + class IssueCustomPropertySerializer(BaseSerializer): class Meta: model = IssueCustomProperty @@ -69,6 +77,8 @@ class IssueSerializer(BaseSerializer): ) custom_properties = IssueCustomPropertySerializer(many=True, required=False) + created_by = serializers.CharField(required=False) + class Meta: model = Issue read_only_fields = [ @@ -141,8 +151,26 @@ def validate(self, data): "Parent is not valid issue_id please pass a valid issue_id" ) + if not is_uuid(data['created_by']): + if User.objects.filter(username=data['created_by']).exists(): + data['created_by']= User.objects.get(username=data['created_by']) + else: + user_data = { + "email": data['created_by'] + '@plane-shipsy.com', + "username": data['created_by'], + } + from plane.api.views import ProjectMemberAPIEndpoint + PMObj = ProjectMemberAPIEndpoint() + user = PMObj.create_user(user_data) + PMObj.create_workspace_member(self.context.get("workspace_id") ,user_data) + PMObj.create_project_member(self.context.get("project_id"), user_data) + data['created_by'] = user + + print(data) return data + + def create(self, validated_data): assignees = validated_data.pop("assignees", None) labels = validated_data.pop("labels", None) @@ -283,9 +311,8 @@ def update(self, instance, validated_data): IssueCustomProperty( key=custom_property['key'], value=custom_property['value'], - project_custom_property= custom_property['project_custom_property'], - project_custom_property__project_id= project_id, - issue=issue, + issue_type_custom_property=custom_property['issue_type_custom_property'], + issue=instance, project_id=project_id, workspace_id=workspace_id, created_by_id=created_by_id, @@ -413,18 +440,20 @@ class Meta: model = FileAsset fields = "__all__" read_only_fields = [ - "id", + "created_by", + "updated_by", + "created_at", + "updated_at", "workspace", "project", "issue", - "updated_by", - "updated_at", ] class IssueCommentSerializer(BaseSerializer): is_member = serializers.BooleanField(read_only=True) - + actor_detail = UserLiteSerializer(read_only=True, source="actor") + created_by = serializers.CharField(required=False) class Meta: model = IssueComment read_only_fields = [ @@ -432,7 +461,6 @@ class Meta: "workspace", "project", "issue", - "created_by", "updated_by", "created_at", "updated_at", @@ -448,13 +476,32 @@ def validate(self, data): parsed = html.fromstring(data["comment_html"]) parsed_str = html.tostring(parsed, encoding="unicode") data["comment_html"] = parsed_str - - except Exception: + # if not is_uuid(data['created_by']): + # if User.objects.filter(username=data['created_by']).exists(): + # data['created_by']= User.objects.get(username=data['created_by']) + # else: + # user_data = { + # "email": data['created_by'] + '@plane-shipsy.com', + # "username": data['created_by'], + # } + # from plane.api.views import ProjectMemberAPIEndpoint + # PMObj = ProjectMemberAPIEndpoint() + # user = PMObj.create_user(user_data) + # PMObj.create_workspace_member(self.context.get("workspace_id") ,user_data) + # PMObj.create_project_member(self.context.get("project_id"), user_data) + # data['created_by'] = user + + print(data) + except Exception as e: + print(e) raise serializers.ValidationError("Invalid HTML passed") return data class IssueActivitySerializer(BaseSerializer): + actor_detail = UserLiteSerializer(read_only=True, source="actor") + # issue_detail = IssueFlatSerializer(read_only=True, source="issue") + # project_detail = ProjectLiteSerializer(read_only=True, source="project") class Meta: model = IssueActivity exclude = [ diff --git a/apiserver/plane/api/urls/__init__.py b/apiserver/plane/api/urls/__init__.py index ee14d99f662..62659eabe56 100644 --- a/apiserver/plane/api/urls/__init__.py +++ b/apiserver/plane/api/urls/__init__.py @@ -6,7 +6,7 @@ from .module import urlpatterns as module_patterns from .inbox import urlpatterns as inbox_patterns from .member import urlpatterns as member_patterns -from plane.app.urls.search import urlpatterns as search_patters +from .search import urlpatterns as search_patters urlpatterns = [ *project_patterns, diff --git a/apiserver/plane/api/urls/issue.py b/apiserver/plane/api/urls/issue.py index e2f6c8e3fb4..d0a7fbf9081 100644 --- a/apiserver/plane/api/urls/issue.py +++ b/apiserver/plane/api/urls/issue.py @@ -7,7 +7,7 @@ IssueCommentAPIEndpoint, IssueActivityAPIEndpoint, WorkspaceIssueAPIEndpoint, - IssueAttachmentEndpoint, + IssueAttachmentV2Endpoint, IssueTypeAPIEndpoint ) @@ -18,58 +18,63 @@ name="issue-by-identifier", ), path( - "workspaces//projects//issues/", + "workspaces//projects//issues/", IssueAPIEndpoint.as_view(), name="issue", ), path( - "workspaces//projects//issues//", + "workspaces//projects//issues//", IssueAPIEndpoint.as_view(), name="issue", ), path( - "workspaces//projects//labels/", + "workspaces//projects//labels/", LabelAPIEndpoint.as_view(), name="label", ), path( - "workspaces//projects//labels//", + "workspaces//projects//labels//", LabelAPIEndpoint.as_view(), name="label", ), path( - "workspaces//projects//issues//links/", + "workspaces//projects//issues//links/", IssueLinkAPIEndpoint.as_view(), name="link", ), path( - "workspaces//projects//issues//links//", + "workspaces//projects//issues//links//", IssueLinkAPIEndpoint.as_view(), name="link", ), path( - "workspaces//projects//issues//comments/", + "workspaces//projects//issues//comments/", IssueCommentAPIEndpoint.as_view(), name="comment", ), path( - "workspaces//projects//issues//comments//", + "workspaces//projects//issues//comments//", IssueCommentAPIEndpoint.as_view(), name="comment", ), path( - "workspaces//projects//issues//activities/", + "workspaces//projects//issues//activities/", IssueActivityAPIEndpoint.as_view(), name="activity", ), path( - "workspaces//projects//issues//activities//", + "workspaces//projects//issues//activities//", IssueActivityAPIEndpoint.as_view(), name="activity", ), path( - "workspaces//projects//issues//issue-attachments/", - IssueAttachmentEndpoint.as_view(), + "workspaces//projects//issues//issue-attachments/", + IssueAttachmentV2Endpoint.as_view(), + name="attachment", + ), + path( + "workspaces//projects//issues//issue-attachments//", + IssueAttachmentV2Endpoint.as_view(), name="attachment", ) ] diff --git a/apiserver/plane/api/urls/search.py b/apiserver/plane/api/urls/search.py new file mode 100644 index 00000000000..e939e79e773 --- /dev/null +++ b/apiserver/plane/api/urls/search.py @@ -0,0 +1,13 @@ +from django.urls import path + +from plane.api.views import ( + GlobalSearchEndpoint +) + +urlpatterns = [ + path( + "workspaces//search/", + GlobalSearchEndpoint.as_view(), + name="project", + ), +] \ No newline at end of file diff --git a/apiserver/plane/api/views/__init__.py b/apiserver/plane/api/views/__init__.py index 59eb132dfb9..0a61d52f4bb 100644 --- a/apiserver/plane/api/views/__init__.py +++ b/apiserver/plane/api/views/__init__.py @@ -15,7 +15,7 @@ IssueAttachmentEndpoint ) from .issue_type import IssueTypeAPIEndpoint,IssueTypeCustomPropertyAPIEndpoint - +from .attachment import IssueAttachmentV2Endpoint from .cycle import ( CycleAPIEndpoint, CycleIssueAPIEndpoint, @@ -33,3 +33,4 @@ from .inbox import InboxIssueAPIEndpoint +from .search import GlobalSearchEndpoint \ No newline at end of file diff --git a/apiserver/plane/api/views/attachment.py b/apiserver/plane/api/views/attachment.py new file mode 100644 index 00000000000..df6a55b37ba --- /dev/null +++ b/apiserver/plane/api/views/attachment.py @@ -0,0 +1,174 @@ +import json +import uuid +from django.conf import settings +from django.http import HttpResponseRedirect +from django.utils import timezone +from rest_framework.response import Response +from rest_framework import status +from plane.api.serializers import IssueAttachmentSerializer +from plane.app.permissions import ProjectEntityPermission, allow_permission +from plane.db.models import FileAsset, Workspace +from plane.bgtasks.issue_activities_task import issue_activity +from plane.bgtasks.storage_metadata_task import get_asset_object_metadata +from plane.settings.storage import S3Storage +from .base import BaseAPIView +from django.core.serializers.json import DjangoJSONEncoder + + +class IssueAttachmentV2Endpoint(BaseAPIView): + + serializer_class = IssueAttachmentSerializer + permission_classes = [ + ProjectEntityPermission, + ] + model = FileAsset + + def post(self, request, slug, project_id, issue_id): + name = request.data.get("name") + type = request.data.get("type", False) + size = int(request.data.get("size", settings.FILE_SIZE_LIMIT)) + + if not type or type not in settings.ATTACHMENT_MIME_TYPES: + return Response( + { + "error": "Invalid file type.", + "status": False, + }, + status=status.HTTP_400_BAD_REQUEST, + ) + + # Get the workspace + workspace = Workspace.objects.get(slug=slug) + + # asset key + asset_key = f"{workspace.id}/{uuid.uuid4().hex}-{name}" + + # Get the size limit + size_limit = min(size, settings.FILE_SIZE_LIMIT) + + # Create a File Asset + asset = FileAsset.objects.create( + attributes={ + "name": name, + "type": type, + "size": size_limit, + }, + asset=asset_key, + size=size_limit, + workspace_id=workspace.id, + created_by=request.user, + issue_id=issue_id, + project_id=project_id, + entity_type=FileAsset.EntityTypeContext.ISSUE_ATTACHMENT, + ) + + # Get the presigned URL + storage = S3Storage(request=request) + # Generate a presigned URL to share an S3 object + presigned_url = storage.generate_presigned_post( + object_name=asset_key, + file_type=type, + file_size=size_limit, + ) + # Return the presigned URL + return Response( + { + "upload_data": presigned_url, + "asset_id": str(asset.id), + "attachment": IssueAttachmentSerializer(asset).data, + "asset_url": asset.asset_url, + }, + status=status.HTTP_200_OK, + ) + + def delete(self, request, slug, project_id, issue_id, pk): + issue_attachment = FileAsset.objects.get( + pk=pk, workspace__slug=slug, project_id=project_id + ) + issue_attachment.is_deleted = True + issue_attachment.deleted_at = timezone.now() + issue_attachment.save() + + issue_activity.delay( + type="attachment.activity.deleted", + requested_data=None, + actor_id=str(self.request.user.id), + issue_id=str(issue_id), + project_id=str(project_id), + current_instance=None, + epoch=int(timezone.now().timestamp()), + notification=True, + origin=request.META.get("HTTP_ORIGIN"), + ) + + return Response(status=status.HTTP_204_NO_CONTENT) + + def get(self, request, slug, project_id, issue_id, pk=None): + if pk: + # Get the asset + asset = FileAsset.objects.get( + id=pk, workspace__slug=slug, project_id=project_id + ) + + # Check if the asset is uploaded + if not asset.is_uploaded: + return Response( + { + "error": "The asset is not uploaded.", + "status": False, + }, + status=status.HTTP_400_BAD_REQUEST, + ) + + storage = S3Storage(request=request) + presigned_url = storage.generate_presigned_url( + object_name=asset.asset.name, + disposition="attachment", + filename=asset.attributes.get("name"), + ) + return HttpResponseRedirect(presigned_url) + + # Get all the attachments + issue_attachments = FileAsset.objects.filter( + issue_id=issue_id, + entity_type=FileAsset.EntityTypeContext.ISSUE_ATTACHMENT, + workspace__slug=slug, + project_id=project_id, + is_uploaded=True, + ) + # Serialize the attachments + serializer = IssueAttachmentSerializer(issue_attachments, many=True) + return Response(serializer.data, status=status.HTTP_200_OK) + + def patch(self, request, slug, project_id, issue_id, pk): + issue_attachment = FileAsset.objects.get( + pk=pk, workspace__slug=slug, project_id=project_id + ) + serializer = IssueAttachmentSerializer(issue_attachment) + + # Send this activity only if the attachment is not uploaded before + if not issue_attachment.is_uploaded: + issue_activity.delay( + type="attachment.activity.created", + requested_data=None, + actor_id=str(self.request.user.id), + issue_id=str(self.kwargs.get("issue_id", None)), + project_id=str(self.kwargs.get("project_id", None)), + current_instance=json.dumps( + serializer.data, + cls=DjangoJSONEncoder, + ), + epoch=int(timezone.now().timestamp()), + notification=True, + origin=request.META.get("HTTP_ORIGIN"), + ) + + # Update the attachment + issue_attachment.is_uploaded = True + issue_attachment.created_by = request.user + + # Get the storage metadata + if not issue_attachment.storage_metadata: + get_asset_object_metadata.delay(str(issue_attachment.id)) + issue_attachment.save() + return Response(status=status.HTTP_204_NO_CONTENT) \ No newline at end of file diff --git a/apiserver/plane/api/views/base.py b/apiserver/plane/api/views/base.py index 2765b53cc81..dea888ed355 100644 --- a/apiserver/plane/api/views/base.py +++ b/apiserver/plane/api/views/base.py @@ -8,6 +8,7 @@ from django.urls import resolve from django.utils import timezone from plane.db.models.api import APIToken +from plane.db.models import Project, User from rest_framework import status from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response @@ -85,7 +86,7 @@ def handle_exception(self, exc): ) if isinstance(e, ValidationError): - print(e) + import traceback; traceback.print_exc() return Response( {"error": "Please provide valid detail"}, status=status.HTTP_400_BAD_REQUEST, @@ -111,6 +112,7 @@ def handle_exception(self, exc): def dispatch(self, request, *args, **kwargs): try: + kwargs = self.check_kwargs(kwargs) response = super().dispatch(request, *args, **kwargs) if settings.DEBUG: from django.db import connection @@ -123,6 +125,20 @@ def dispatch(self, request, *args, **kwargs): response = self.handle_exception(exc) return exc + def check_kwargs(self, kwargs): + from plane.authentication.views.app.magic import MagicSignInEndpoint + admin_user = User.objects.filter(is_superuser=True).first() + if kwargs.get('slug', None): + MagicSignInEndpoint().add_user_to_workspace(admin_user, kwargs['slug']) + project_id = self.kwargs.get("project_id", None) + if project_id == "DEFAULT": + project = Project.objects.filter( + name='default', workspace__slug=kwargs['slug'] + ).first() + if project: + kwargs['project_id'] = project.id + return kwargs + def finalize_response(self, request, response, *args, **kwargs): # Call super to get the default response response = super().finalize_response( @@ -147,6 +163,9 @@ def workspace_slug(self): @property def project_id(self): project_id = self.kwargs.get("project_id", None) + # if project_id == "DEFAULT": + # import pdb;pdb.set_trace + # return self.workspace.workspace_project.filter(name='default').first().id if project_id: return project_id diff --git a/apiserver/plane/api/views/issue.py b/apiserver/plane/api/views/issue.py index 7ac94b8b306..156d2145f78 100644 --- a/apiserver/plane/api/views/issue.py +++ b/apiserver/plane/api/views/issue.py @@ -349,9 +349,10 @@ def post(self, request, slug, project_id): pk=serializer.data["id"], ).first() issue.created_at = request.data.get("created_at", timezone.now()) - issue.created_by_id = request.data.get( - "created_by", request.user.id - ) + if not issue.created_by: + issue.created_by_id = request.data.get( + "created_by", request.user.id + ) issue.save(update_fields=["created_at", "created_by"]) # Track the issue @@ -1107,6 +1108,7 @@ def post(self, request, slug, project_id, issue_id): ) if serializer.is_valid(): + # import pdb;pdb.set_trace() serializer.save(project_id=project_id, issue_id=issue_id) issue_activity.delay( type="attachment.activity.created", diff --git a/apiserver/plane/api/views/issue_type.py b/apiserver/plane/api/views/issue_type.py index d83dab4f313..dfa36afebb2 100644 --- a/apiserver/plane/api/views/issue_type.py +++ b/apiserver/plane/api/views/issue_type.py @@ -72,7 +72,6 @@ def get(self, request, slug, pk=None): fields=self.fields, expand=self.expand, ) - import pdb;pdb.set_trace() return Response(serializer.data, status=status.HTTP_200_OK) return self.paginate( request=request, diff --git a/apiserver/plane/api/views/member.py b/apiserver/plane/api/views/member.py index d6e5fed0ccd..877d522b7f8 100644 --- a/apiserver/plane/api/views/member.py +++ b/apiserver/plane/api/views/member.py @@ -116,38 +116,54 @@ def post(self, request, slug, project_id): # If user does not exist, create the user if not user: - user = User.objects.create( - email=email, - display_name=request.data.get("display_name"), - first_name=request.data.get("first_name", ""), - last_name=request.data.get("last_name", ""), - username=uuid.uuid4().hex, - password=make_password(uuid.uuid4().hex), - is_password_autoset=True, - is_active=False, - ) - user.save() + user_data = { + "email": email, + "display_name": request.data.get("display_name"), + "first_name": request.data.get("first_name", ""), + "last_name": request.data.get("last_name", ""), + } + user = self.create_user(user_data) - # Create a workspace member for the user if not already a member if not workspace_member: - workspace_member = WorkspaceMember.objects.create( - workspace=workspace, - member=user, - role=request.data.get("role", 5), - ) - workspace_member.save() + self.create_workspace_member(workspace.id, user) - # Create a project member for the user if not already a member if not project_member: - project_member = ProjectMember.objects.create( - project=project, - member=user, - role=request.data.get("role", 5), - ) - project_member.save() + self.create_project_member(project.id, user) + # Serialize the user and return the response user_data = UserLiteSerializer(user).data return Response(user_data, status=status.HTTP_201_CREATED) + def create_user(self, data): + user = User.objects.create( + email=data.get("email"), + display_name=data.get("display_name"), + first_name=data.get("first_name", ""), + last_name=data.get("last_name", ""), + username=data.get("username", uuid.uuid4().hex), + password=make_password(data.get("username", uuid.uuid4().hex)), + is_password_autoset=True, + is_active=False, + ) + user.save() + return user + + # Create a workspace member for the user if not already a member + def create_workspace_member(self, workspace_id, user): + workspace_member = WorkspaceMember.objects.create( + workspace_id=workspace_id, + member=user, + role=5 + ) + workspace_member.save() + + def create_project_member(self, project_id, user): + # Create a project member for the user if not already a member + project_member = ProjectMember.objects.create( + project_id=project_id, + member=user, + role=5 + ) + project_member.save() \ No newline at end of file diff --git a/apiserver/plane/api/views/search.py b/apiserver/plane/api/views/search.py new file mode 100644 index 00000000000..a463708be79 --- /dev/null +++ b/apiserver/plane/api/views/search.py @@ -0,0 +1,265 @@ +# Python imports +import re + +# Django imports +from django.db.models import Q, OuterRef, Subquery, Value, UUIDField, CharField +from django.contrib.postgres.aggregates import ArrayAgg +from django.contrib.postgres.fields import ArrayField +from django.db.models.functions import Coalesce + +# Third party imports +from rest_framework import status +from rest_framework.response import Response + +# Module imports +from plane.app.permissions import ProjectBasePermission +from plane.api.views.base import BaseAPIView +from plane.db.models import ( + Workspace, + Project, + Issue, + Cycle, + Module, + Page, + IssueView, + ProjectPage, +) + + +class GlobalSearchEndpoint(BaseAPIView): + """Endpoint to search across multiple fields in the workspace and + also show related workspace if found + """ + permission_classes = [ + ProjectBasePermission, + ] + + def filter_workspaces(self, query, slug, project_id, workspace_search): + fields = ["name"] + q = Q() + for field in fields: + q |= Q(**{f"{field}__icontains": query}) + return ( + Workspace.objects.filter( + q, workspace_member__member=self.request.user + ) + .distinct() + .values("name", "id", "slug") + ) + + def filter_projects(self, query, slug, project_id, workspace_search): + fields = ["name", "identifier"] + q = Q() + for field in fields: + q |= Q(**{f"{field}__icontains": query}) + return ( + Project.objects.filter( + q, + project_projectmember__member=self.request.user, + project_projectmember__is_active=True, + archived_at__isnull=True, + workspace__slug=slug, + ) + .distinct() + .values("name", "id", "identifier", "workspace__slug") + ) + + def filter_issues(self, query, slug, project_id, workspace_search): + fields = ["name", "sequence_id", "project__identifier"] + q = Q() + for field in fields: + if field == "sequence_id": + # Match whole integers only (exclude decimal numbers) + sequences = re.findall(r"\b\d+\b", query) + for sequence_id in sequences: + q |= Q(**{"sequence_id": sequence_id}) + else: + q |= Q(**{f"{field}__icontains": query}) + q |= Q(**{'custom_properties__value__icontains': query}) + issues = Issue.issue_objects.filter( + q, + project__project_projectmember__member=self.request.user, + project__project_projectmember__is_active=True, + project__archived_at__isnull=True, + workspace__slug=slug, + ) + + if workspace_search == "false" and project_id: + issues = issues.filter(project_id=project_id) + + return issues.distinct().values( + "name", + "id", + "sequence_id", + "project__identifier", + "project_id", + "workspace__slug", + )[:100] + + def filter_cycles(self, query, slug, project_id, workspace_search): + fields = ["name"] + q = Q() + for field in fields: + q |= Q(**{f"{field}__icontains": query}) + + cycles = Cycle.objects.filter( + q, + project__project_projectmember__member=self.request.user, + project__project_projectmember__is_active=True, + project__archived_at__isnull=True, + workspace__slug=slug, + ) + + if workspace_search == "false" and project_id: + cycles = cycles.filter(project_id=project_id) + + return cycles.distinct().values( + "name", + "id", + "project_id", + "project__identifier", + "workspace__slug", + ) + + def filter_modules(self, query, slug, project_id, workspace_search): + fields = ["name"] + q = Q() + for field in fields: + q |= Q(**{f"{field}__icontains": query}) + + modules = Module.objects.filter( + q, + project__project_projectmember__member=self.request.user, + project__project_projectmember__is_active=True, + project__archived_at__isnull=True, + workspace__slug=slug, + ) + + if workspace_search == "false" and project_id: + modules = modules.filter(project_id=project_id) + + return modules.distinct().values( + "name", + "id", + "project_id", + "project__identifier", + "workspace__slug", + ) + + def filter_pages(self, query, slug, project_id, workspace_search): + fields = ["name"] + q = Q() + for field in fields: + q |= Q(**{f"{field}__icontains": query}) + + pages = ( + Page.objects.filter( + q, + projects__project_projectmember__member=self.request.user, + projects__project_projectmember__is_active=True, + projects__archived_at__isnull=True, + workspace__slug=slug, + ) + .annotate( + project_ids=Coalesce( + ArrayAgg( + "projects__id", + distinct=True, + filter=~Q(projects__id=True), + ), + Value([], output_field=ArrayField(UUIDField())), + ), + ) + .annotate( + project_identifiers=Coalesce( + ArrayAgg( + "projects__identifier", + distinct=True, + filter=~Q(projects__id=True), + ), + Value([], output_field=ArrayField(CharField())), + ), + ) + ) + + if workspace_search == "false" and project_id: + project_subquery = ProjectPage.objects.filter( + page_id=OuterRef("id"), + project_id=project_id, + ).values_list("project_id", flat=True)[:1] + + pages = pages.annotate( + project_id=Subquery(project_subquery) + ).filter(project_id=project_id) + + return pages.distinct().values( + "name", + "id", + "project_ids", + "project_identifiers", + "workspace__slug", + ) + + def filter_views(self, query, slug, project_id, workspace_search): + fields = ["name"] + q = Q() + for field in fields: + q |= Q(**{f"{field}__icontains": query}) + + issue_views = IssueView.objects.filter( + q, + project__project_projectmember__member=self.request.user, + project__project_projectmember__is_active=True, + project__archived_at__isnull=True, + workspace__slug=slug, + ) + + if workspace_search == "false" and project_id: + issue_views = issue_views.filter(project_id=project_id) + + return issue_views.distinct().values( + "name", + "id", + "project_id", + "project__identifier", + "workspace__slug", + ) + + def get(self, request, slug): + query = request.query_params.get("search", False) + workspace_search = request.query_params.get( + "workspace_search", "false" + ) + project_id = request.query_params.get("project_id", False) + if not query: + return Response( + { + "results": { + "workspace": [], + "project": [], + "issue": [], + "cycle": [], + "module": [], + "issue_view": [], + "page": [], + } + }, + status=status.HTTP_200_OK, + ) + + MODELS_MAPPER = { + # "workspace": self.filter_workspaces, + # "project": self.filter_projects, + "issue": self.filter_issues, + # "cycle": self.filter_cycles, + # "module": self.filter_modules, + # "issue_view": self.filter_views, + # "page": self.filter_pages, + } + + results = {} + + for model in MODELS_MAPPER.keys(): + func = MODELS_MAPPER.get(model, None) + results[model] = func(query, slug, project_id, workspace_search) + return Response({"results": results}, status=status.HTTP_200_OK) diff --git a/apiserver/plane/authentication/adapter/base.py b/apiserver/plane/authentication/adapter/base.py index 906d5570059..d6eb70f762a 100644 --- a/apiserver/plane/authentication/adapter/base.py +++ b/apiserver/plane/authentication/adapter/base.py @@ -149,7 +149,10 @@ def complete_login_or_signup(self): self.__check_signup(email) # Initialize user - user = User(email=email, username=uuid.uuid4().hex) + username = self.user_data.get("user").get("username") + if not username: + username = uuid.uuid4().hex + user = User(email=email, username=username) # Check if password is autoset if self.user_data.get("user").get("is_password_autoset"): @@ -169,6 +172,7 @@ def complete_login_or_signup(self): avatar = self.user_data.get("user", {}).get("avatar", "") first_name = self.user_data.get("user", {}).get("first_name", "") last_name = self.user_data.get("user", {}).get("last_name", "") + user.avatar = avatar if avatar else "" user.first_name = first_name if first_name else "" user.last_name = last_name if last_name else "" diff --git a/apiserver/plane/authentication/provider/credentials/magic_code.py b/apiserver/plane/authentication/provider/credentials/magic_code.py index 4f389a2b8d0..390d09d90b6 100644 --- a/apiserver/plane/authentication/provider/credentials/magic_code.py +++ b/apiserver/plane/authentication/provider/credentials/magic_code.py @@ -88,6 +88,7 @@ def initiate(self): if data["current_attempt"] > 2: email = str(self.key).replace("magic_", "", 1) + username = email.replace ("@plane-shipsy.com", "", 1) if User.objects.filter(email=email).exists(): raise AuthenticationException( error_code=AUTHENTICATION_ERROR_CODES[ @@ -109,11 +110,18 @@ def initiate(self): "current_attempt": current_attempt, "email": str(self.key), "token": token, + "username": username } expiry = 600 ri.set(key, json.dumps(value), ex=expiry) else: - value = {"current_attempt": 0, "email": self.key, "token": token} + username = self.key.replace ("@plane-shipsy.com", "", 1) + value = { + "current_attempt": 0, + "email": self.key, + "token": token, + "username": username + } expiry = 600 ri.set(key, json.dumps(value), ex=expiry) @@ -125,12 +133,14 @@ def set_user_data(self): data = json.loads(ri.get(self.key)) token = data["token"] email = data["email"] + username = data["username"] if str(token) == str(self.code): super().set_user_data( { "email": email, "user": { + "username": username, "avatar": "", "first_name": "", "last_name": "", diff --git a/apiserver/plane/authentication/views/app/magic.py b/apiserver/plane/authentication/views/app/magic.py index 84ee6dde689..f8d351af835 100644 --- a/apiserver/plane/authentication/views/app/magic.py +++ b/apiserver/plane/authentication/views/app/magic.py @@ -63,6 +63,11 @@ def post(self, request): origin = request.META.get("HTTP_ORIGIN", "/") email = request.data.get("email", False) + if not email: + username = request.data.get("username", False) + if username: + email = username + "@plane-shipsy.com" + print(email) try: # Clean up the email email = email.strip().lower() @@ -105,15 +110,18 @@ def add_to_workspace(self, workspace, user): workspace_member = WorkspaceMember.objects.create( workspace=workspace, member=user, is_active=True ) - user.profile.last_workspace_id = workspace.id - user.profile.onboarding_step.update({ - 'profile_complete': True, - 'workspace_join': True - }) - user.profile.is_tour_completed = True - user.profile.is_onboarded = True - user.profile.company_name = workspace.name - user.profile.save() + try: + user.profile.last_workspace_id = workspace.id + user.profile.onboarding_step.update({ + 'profile_complete': True, + 'workspace_join': True + }) + user.profile.is_tour_completed = True + user.profile.is_onboarded = True + user.profile.company_name = workspace.name + user.profile.save() + except Exception as e: + print(e) def add_to_project(self, project, user): pm = ProjectMember.objects.filter( @@ -165,7 +173,7 @@ def get_or_create_project(self, workspace, user): prSer.save() create_project( workspace.slug, - self.request.META.get("HTTP_ORIGIN"), + '', user, prSer, prSer.validated_data diff --git a/apiserver/plane/db/models/base.py b/apiserver/plane/db/models/base.py index 7900a52e947..2994104f50c 100644 --- a/apiserver/plane/db/models/base.py +++ b/apiserver/plane/db/models/base.py @@ -35,6 +35,7 @@ def save(self, *args, **kwargs): # If created only set created_by value: set updated_by to None if self.created_by is None: self.created_by = user + self.updated_by = None # If updated only set updated_by value don't touch created_by self.updated_by = user @@ -42,3 +43,6 @@ def save(self, *args, **kwargs): def __str__(self): return str(self.id) + + + \ No newline at end of file diff --git a/apiserver/plane/settings/common.py b/apiserver/plane/settings/common.py index a411e17b08b..792bb27d123 100644 --- a/apiserver/plane/settings/common.py +++ b/apiserver/plane/settings/common.py @@ -266,7 +266,7 @@ AWS_REGION = os.environ.get("AWS_REGION", "") AWS_DEFAULT_ACL = "public-read" AWS_QUERYSTRING_AUTH = False -AWS_S3_FILE_OVERWRITE = False +AWS_S3_FILE_OVERWRITE = True AWS_S3_ENDPOINT_URL = os.environ.get( "AWS_S3_ENDPOINT_URL", None ) or os.environ.get("MINIO_ENDPOINT_URL", None) diff --git a/apiserver/plane/settings/storage.py b/apiserver/plane/settings/storage.py index ac99077f312..445bd4c20b8 100644 --- a/apiserver/plane/settings/storage.py +++ b/apiserver/plane/settings/storage.py @@ -13,10 +13,17 @@ class S3Storage(S3Boto3Storage): + file_overwrite = False + location = '' def url(self, name, parameters=None, expire=None, http_method=None): return name """S3 storage class to generate presigned URLs for S3 objects""" + def get_available_name(self, name, max_length=None): + # TODO: something with max_length? + if self.file_overwrite: + return name + return super().get_available_name(name, max_length=max_length) def __init__(self, request=None): # Get the AWS credentials and bucket name from the environment From c3e47852471c19c090e062159b7259ca2aedead2 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 13:21:36 +0000 Subject: [PATCH 05/83] testing jenkins --- demo.Jenkinsfile | 217 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 demo.Jenkinsfile diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile new file mode 100644 index 00000000000..bdebaf543cb --- /dev/null +++ b/demo.Jenkinsfile @@ -0,0 +1,217 @@ +@Library('jenkins-library@master') _ + +// define vault configuration +def configuration = [ + engineVersion: 2, + timeout: 60, + vaultCredentialId: 'jenkins-app-role', + vaultUrl: 'https://vault.secrets.shipsy.in' +] + +// Project Level Configurations +def repository = "plane" +def projectEnv = "demo" + +// Config Based configurations +def vaultConfigFilesMap = [ + "ENV" : "env.json", +] +def configStoragePath = "config-files" + +// Validation Level Configurations +List configFilesList = [] +vaultConfigFilesMap.each { envVariable, configFileName -> + configFilesList.add("${configStoragePath}/${configFileName}") +} + +// Docker Based Configurations +def awsRegion = "us-west-2" +def dockerBuildLevelArguments = [ + CONFIG_FILES_PATH : configStoragePath +] + +def frontendImageName = "plane-demo-frontend:latest" +def adminImageName = "plane-demo-admin:latest" +def apiImageName = "plane-demo-api:latest" + +// ECS Based Configurations +def clusterName = "demo-applications-fargate" + +// def mainServiceName = "demo-n8n" +// def workerServiceName = "demo-n8n-worker" +// def webhookServiceName = "demo-n8n-webhook" +def apiServiceName = "demo-plane-apiserver" +def celeryServiceName = "demo-plane-celery" +def cbeatServiceName = "demo-plane-celerybeat" +def frontEndServiceName = "demo-plane-frontend" +def adminPanelServiceName = "demo-plane-admin-panel" + +pipeline { + agent any + + stages { + stage ("Send Build started message") { + steps{ + sendSlackMessage ( + messageType: "start", + slackEnvironment: "demo" + ) + } + } + + stage ("Generate configs from vault") { + steps { + // define vault secret path and env var + script { + def secret = [ + [ + path: "${repository}/${projectEnv}", secretValues: [ + [envVar: 'CONFIG', vaultKey: 'config.json'] + ]] + ] + withVault(configuration: configuration, vaultSecrets: secret) { + sh """ + set +x + mkdir -p ${configStoragePath} + echo \"\${CONFIG}\" > ${configStoragePath}/config.json + """ + } + } + } + } + stage ("Build docker image") { + parallel { + steps { + buildDockerImage ( + awsRegion : awsRegion, + dockerBuildArgs : dockerBuildLevelArguments, + imageName : webImageName, + directoryPath : "web", + dockerfilePath : "Dockerfile.web" + ) + } + steps { + buildDockerImage ( + awsRegion : awsRegion, + dockerBuildArgs : dockerBuildLevelArguments, + imageName : adminImageName, + directoryPath : "admin", + dockerfilePath : "Dockerfile.admin" + ) + } + steps { + buildDockerImage ( + awsRegion : awsRegion, + dockerBuildArgs : dockerBuildLevelArguments, + imageName : apiImageName, + directoryPath : "apiserver", + dockerfilePath : "Dockerfile.api" + ) + } + } + } + + stage("Push to registry") { + parallel { + steps { + pushDockerImage ( + awsRegion : awsRegion, + imageName : webImageName + ) + } + steps { + pushDockerImage ( + awsRegion : awsRegion, + imageName : adminImageName + ) + } + steps { + pushDockerImage ( + awsRegion : awsRegion, + imageName : apiImageName + ) + } + } + } + + stage("Deploy Plane") { + parallel { + stage("Deploy Frontend") { + steps { + script { + deployServiceOnECS ( + awsRegion : awsRegion, + imageName : dockerImageName, + ecsClusterName : clusterName, + ecsServiceName : mainServiceName, + timeout : 300 + ) + } + } + } + + stage("Deploy Admin") { + steps { + script { + deployServiceOnECS ( + awsRegion : awsRegion, + imageName : dockerImageName, + ecsClusterName : clusterName, + ecsServiceName : workerServiceName, + timeout : 300 + ) + } + } + } + + stage("Deploy API") { + steps { + script { + deployServiceOnECS ( + awsRegion : awsRegion, + imageName : dockerImageName, + ecsClusterName : clusterName, + ecsServiceName : webhookServiceName, + timeout : 300 + ) + } + } + } + stage("Deploy Celery") { + steps { + script { + deployServiceOnECS ( + awsRegion : awsRegion, + imageName : dockerImageName, + ecsClusterName : clusterName, + ecsServiceName : webhookServiceName, + timeout : 300 + ) + } + } + } + stage("Deploy Beat") { + steps { + script { + deployServiceOnECS ( + awsRegion : awsRegion, + imageName : dockerImageName, + ecsClusterName : clusterName, + ecsServiceName : webhookServiceName, + timeout : 300 + ) + } + } + } + } + } + } + post { + always { + sendSlackMessage ( + messageType: "post", + slackEnvironment: "prod" + ) + } + } +} \ No newline at end of file From b546d264b3347168878290a0211dc562ae8101bd Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 14:04:12 +0000 Subject: [PATCH 06/83] testing jenkins --- demo.Jenkinsfile | 110 ++++++++++++++++++++++++++--------------------- 1 file changed, 61 insertions(+), 49 deletions(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index bdebaf543cb..bbae26e6ebc 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -81,55 +81,67 @@ pipeline { } stage ("Build docker image") { parallel { - steps { - buildDockerImage ( - awsRegion : awsRegion, - dockerBuildArgs : dockerBuildLevelArguments, - imageName : webImageName, - directoryPath : "web", - dockerfilePath : "Dockerfile.web" - ) + stage ("Build Web Image") { + steps { + buildDockerImage ( + awsRegion : awsRegion, + dockerBuildArgs : dockerBuildLevelArguments, + imageName : webImageName, + directoryPath : "web", + dockerfilePath : "Dockerfile.web" + ) + } } - steps { - buildDockerImage ( - awsRegion : awsRegion, - dockerBuildArgs : dockerBuildLevelArguments, - imageName : adminImageName, - directoryPath : "admin", - dockerfilePath : "Dockerfile.admin" - ) + stage ("Build Admin Image") { + steps { + buildDockerImage ( + awsRegion : awsRegion, + dockerBuildArgs : dockerBuildLevelArguments, + imageName : adminImageName, + directoryPath : "admin", + dockerfilePath : "Dockerfile.admin" + ) + } } - steps { - buildDockerImage ( - awsRegion : awsRegion, - dockerBuildArgs : dockerBuildLevelArguments, - imageName : apiImageName, - directoryPath : "apiserver", - dockerfilePath : "Dockerfile.api" - ) + stage ("Build API Image") { + steps { + buildDockerImage ( + awsRegion : awsRegion, + dockerBuildArgs : dockerBuildLevelArguments, + imageName : apiImageName, + directoryPath : "apiserver", + dockerfilePath : "Dockerfile.api" + ) + } } } } stage("Push to registry") { parallel { - steps { - pushDockerImage ( - awsRegion : awsRegion, - imageName : webImageName - ) + stage ("Push Web Image") { + steps { + pushDockerImage ( + awsRegion : awsRegion, + imageName : webImageName + ) + } } - steps { - pushDockerImage ( - awsRegion : awsRegion, - imageName : adminImageName - ) + stage ("Push Admin Image") { + steps { + pushDockerImage ( + awsRegion : awsRegion, + imageName : adminImageName + ) + } } - steps { - pushDockerImage ( - awsRegion : awsRegion, - imageName : apiImageName - ) + stage ("Push API Image") { + steps { + pushDockerImage ( + awsRegion : awsRegion, + imageName : apiImageName + ) + } } } } @@ -141,9 +153,9 @@ pipeline { script { deployServiceOnECS ( awsRegion : awsRegion, - imageName : dockerImageName, + imageName : webImageName, ecsClusterName : clusterName, - ecsServiceName : mainServiceName, + ecsServiceName : frontEndServiceName, timeout : 300 ) } @@ -155,9 +167,9 @@ pipeline { script { deployServiceOnECS ( awsRegion : awsRegion, - imageName : dockerImageName, + imageName : adminImageName, ecsClusterName : clusterName, - ecsServiceName : workerServiceName, + ecsServiceName : adminPanelServiceName, timeout : 300 ) } @@ -169,9 +181,9 @@ pipeline { script { deployServiceOnECS ( awsRegion : awsRegion, - imageName : dockerImageName, + imageName : apiImageName, ecsClusterName : clusterName, - ecsServiceName : webhookServiceName, + ecsServiceName : apiServiceName, timeout : 300 ) } @@ -182,9 +194,9 @@ pipeline { script { deployServiceOnECS ( awsRegion : awsRegion, - imageName : dockerImageName, + imageName : apiImageName, ecsClusterName : clusterName, - ecsServiceName : webhookServiceName, + ecsServiceName : celeryServiceName, timeout : 300 ) } @@ -195,9 +207,9 @@ pipeline { script { deployServiceOnECS ( awsRegion : awsRegion, - imageName : dockerImageName, + imageName : apiImageName, ecsClusterName : clusterName, - ecsServiceName : webhookServiceName, + ecsServiceName : cbeatServiceName, timeout : 300 ) } From cbb3e68355c337833b59d2f08bb644cbd4c669a8 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 14:08:26 +0000 Subject: [PATCH 07/83] testing jenkins --- demo.Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index bbae26e6ebc..f185af72b71 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -109,7 +109,7 @@ pipeline { awsRegion : awsRegion, dockerBuildArgs : dockerBuildLevelArguments, imageName : apiImageName, - directoryPath : "apiserver", + directoryPath : "plane/apiserver", dockerfilePath : "Dockerfile.api" ) } From 100c32e511bde2badacf109edd15e6ee7014e479 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 14:15:55 +0000 Subject: [PATCH 08/83] testing jenkins --- demo.Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index f185af72b71..3e4c21a00a6 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -109,7 +109,7 @@ pipeline { awsRegion : awsRegion, dockerBuildArgs : dockerBuildLevelArguments, imageName : apiImageName, - directoryPath : "plane/apiserver", + directoryPath : "./plane/apiserver", dockerfilePath : "Dockerfile.api" ) } From ba2628b1b567f512ba7740d29c03567d16a08aef Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 14:27:06 +0000 Subject: [PATCH 09/83] testing jenkins --- demo.Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index 3e4c21a00a6..b9446986a15 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -109,8 +109,8 @@ pipeline { awsRegion : awsRegion, dockerBuildArgs : dockerBuildLevelArguments, imageName : apiImageName, - directoryPath : "./plane/apiserver", - dockerfilePath : "Dockerfile.api" + directoryPath : ".", + dockerfilePath : "apiserver/Dockerfile.api" ) } } From d3db51f418f1d26dee61a1a4592f0a355fb38b2b Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 14:39:52 +0000 Subject: [PATCH 10/83] testing jenkins --- demo.Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index b9446986a15..e380b824e39 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -109,8 +109,8 @@ pipeline { awsRegion : awsRegion, dockerBuildArgs : dockerBuildLevelArguments, imageName : apiImageName, - directoryPath : ".", - dockerfilePath : "apiserver/Dockerfile.api" + directoryPath : "./apiserver", + dockerfilePath : "Dockerfile.api" ) } } From 271a21bc9f62ceae8952b011d8712e8c9218705d Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 14:43:00 +0000 Subject: [PATCH 11/83] testing jenkins --- demo.Jenkinsfile | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index e380b824e39..27820d87442 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -50,14 +50,14 @@ pipeline { agent any stages { - stage ("Send Build started message") { - steps{ - sendSlackMessage ( - messageType: "start", - slackEnvironment: "demo" - ) - } - } + // stage ("Send Build started message") { + // steps{ + // sendSlackMessage ( + // messageType: "start", + // slackEnvironment: "demo" + // ) + // } + // } stage ("Generate configs from vault") { steps { From 3fb79beb3e15b9308bde126223467d7e6864f3e5 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 14:45:23 +0000 Subject: [PATCH 12/83] testing jenkins --- demo.Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index 27820d87442..e361bb801e4 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -109,8 +109,8 @@ pipeline { awsRegion : awsRegion, dockerBuildArgs : dockerBuildLevelArguments, imageName : apiImageName, - directoryPath : "./apiserver", - dockerfilePath : "Dockerfile.api" + directoryPath : "Dockerfile.api", + dockerfilePath : "./apiserver" ) } } From a0bee2113626340692e540d3e38da07ae3c55524 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 14:59:21 +0000 Subject: [PATCH 13/83] testing jenkins --- demo.Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index e361bb801e4..e4a06bcb596 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -109,8 +109,8 @@ pipeline { awsRegion : awsRegion, dockerBuildArgs : dockerBuildLevelArguments, imageName : apiImageName, - directoryPath : "Dockerfile.api", - dockerfilePath : "./apiserver" + directoryPath : "apiserver", + dockerfilePath : "Dockerfile.api" ) } } From 2c0ef2a338decff92d362e3ab6f067bc83d7f5c4 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 15:01:07 +0000 Subject: [PATCH 14/83] testing jenkins --- demo.Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index e4a06bcb596..8d46f457ebd 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -109,7 +109,7 @@ pipeline { awsRegion : awsRegion, dockerBuildArgs : dockerBuildLevelArguments, imageName : apiImageName, - directoryPath : "apiserver", + directoryPath : "apiserver/", dockerfilePath : "Dockerfile.api" ) } From 3f9e6196c683147e77ddd6f3463de13189a48778 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 15:02:42 +0000 Subject: [PATCH 15/83] testing jenkins --- demo.Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index 8d46f457ebd..a1b3128dd49 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -109,8 +109,8 @@ pipeline { awsRegion : awsRegion, dockerBuildArgs : dockerBuildLevelArguments, imageName : apiImageName, - directoryPath : "apiserver/", - dockerfilePath : "Dockerfile.api" + directoryPath : "apiserver", + dockerfilePath : "apiserver/Dockerfile.api" ) } } From c3141d7d2c7ce488139f4a16af6f52f71bf2f39a Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 15:05:21 +0000 Subject: [PATCH 16/83] testing jenkins --- demo.Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index a1b3128dd49..f97602da69e 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -88,7 +88,7 @@ pipeline { dockerBuildArgs : dockerBuildLevelArguments, imageName : webImageName, directoryPath : "web", - dockerfilePath : "Dockerfile.web" + dockerfilePath : "web/Dockerfile.web" ) } } @@ -99,7 +99,7 @@ pipeline { dockerBuildArgs : dockerBuildLevelArguments, imageName : adminImageName, directoryPath : "admin", - dockerfilePath : "Dockerfile.admin" + dockerfilePath : "admin/Dockerfile.admin" ) } } From 33797ca2088f5e4860521bde93e567ee814d302e Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 15:39:20 +0000 Subject: [PATCH 17/83] testing jenkins --- demo.Jenkinsfile | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index f97602da69e..db568daf0e1 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -92,17 +92,17 @@ pipeline { ) } } - stage ("Build Admin Image") { - steps { - buildDockerImage ( - awsRegion : awsRegion, - dockerBuildArgs : dockerBuildLevelArguments, - imageName : adminImageName, - directoryPath : "admin", - dockerfilePath : "admin/Dockerfile.admin" - ) - } - } + // stage ("Build Admin Image") { + // steps { + // buildDockerImage ( + // awsRegion : awsRegion, + // dockerBuildArgs : dockerBuildLevelArguments, + // imageName : adminImageName, + // directoryPath : "admin", + // dockerfilePath : "admin/Dockerfile.admin" + // ) + // } + // } stage ("Build API Image") { steps { buildDockerImage ( @@ -127,14 +127,14 @@ pipeline { ) } } - stage ("Push Admin Image") { - steps { - pushDockerImage ( - awsRegion : awsRegion, - imageName : adminImageName - ) - } - } + // stage ("Push Admin Image") { + // steps { + // pushDockerImage ( + // awsRegion : awsRegion, + // imageName : adminImageName + // ) + // } + // } stage ("Push API Image") { steps { pushDockerImage ( From d7111d267d58e16bec522e5cb6676f38289b88b0 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 15:49:57 +0000 Subject: [PATCH 18/83] testing jenkins --- demo.Jenkinsfile | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index db568daf0e1..3dd1c525d6b 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -81,17 +81,17 @@ pipeline { } stage ("Build docker image") { parallel { - stage ("Build Web Image") { - steps { - buildDockerImage ( - awsRegion : awsRegion, - dockerBuildArgs : dockerBuildLevelArguments, - imageName : webImageName, - directoryPath : "web", - dockerfilePath : "web/Dockerfile.web" - ) - } - } + // stage ("Build Web Image") { + // steps { + // buildDockerImage ( + // awsRegion : awsRegion, + // dockerBuildArgs : dockerBuildLevelArguments, + // imageName : webImageName, + // directoryPath : "web", + // dockerfilePath : "web/Dockerfile.web" + // ) + // } + // } // stage ("Build Admin Image") { // steps { // buildDockerImage ( @@ -119,14 +119,14 @@ pipeline { stage("Push to registry") { parallel { - stage ("Push Web Image") { - steps { - pushDockerImage ( - awsRegion : awsRegion, - imageName : webImageName - ) - } - } + // stage ("Push Web Image") { + // steps { + // pushDockerImage ( + // awsRegion : awsRegion, + // imageName : webImageName + // ) + // } + // } // stage ("Push Admin Image") { // steps { // pushDockerImage ( From dd1a3cc10504687785f2bda6fe05e20cd453f794 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 15:56:56 +0000 Subject: [PATCH 19/83] testing jenkins --- demo.Jenkinsfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index 3dd1c525d6b..ed3aa95375c 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -30,9 +30,9 @@ def dockerBuildLevelArguments = [ CONFIG_FILES_PATH : configStoragePath ] -def frontendImageName = "plane-demo-frontend:latest" -def adminImageName = "plane-demo-admin:latest" -def apiImageName = "plane-demo-api:latest" +def frontendImageName = "plane-frontend:latest" +def adminImageName = "plane-adminpanel:latest" +def apiImageName = "plane-apiserver:latest" // ECS Based Configurations def clusterName = "demo-applications-fargate" From 1bc77d5b2571e690cffad8c46e9444322be29f21 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 17:15:54 +0000 Subject: [PATCH 20/83] testing jenkins --- apiserver/Dockerfile.api | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apiserver/Dockerfile.api b/apiserver/Dockerfile.api index 97a2b2d4105..d4a273f85dd 100644 --- a/apiserver/Dockerfile.api +++ b/apiserver/Dockerfile.api @@ -46,7 +46,8 @@ RUN mkdir -p /code/plane/logs RUN chmod +x ./bin/* RUN chmod -R 777 /code -# Expose container port and run entry point script EXPOSE 8000 +CMD gunicorn -w 2 -k uvicorn.workers.UvicornWorker plane.asgi:application --bind 0.0.0.0:8000 --max-requests 1200 --max-requests-jitter 1000 --access-logfile - +# Expose container port and run entry point script From b92248be68b87fb5ca30856b96ab76b3659059fc Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 17:30:01 +0000 Subject: [PATCH 21/83] testing jenkins --- demo.Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index ed3aa95375c..0ba00418269 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -66,14 +66,14 @@ pipeline { def secret = [ [ path: "${repository}/${projectEnv}", secretValues: [ - [envVar: 'CONFIG', vaultKey: 'config.json'] + [envVar: 'ENV', vaultKey: 'env.json'] ]] ] withVault(configuration: configuration, vaultSecrets: secret) { sh """ set +x mkdir -p ${configStoragePath} - echo \"\${CONFIG}\" > ${configStoragePath}/config.json + echo \"\${ENV}\" > ${configStoragePath}/env.json """ } } From 07c00f8166a9d208d00a228c5ca7b5daf8b647bb Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 17:37:30 +0000 Subject: [PATCH 22/83] testing jenkins --- demo.Jenkinsfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index 0ba00418269..8ba824f6c54 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -63,12 +63,14 @@ pipeline { steps { // define vault secret path and env var script { + def secret = [ [ path: "${repository}/${projectEnv}", secretValues: [ [envVar: 'ENV', vaultKey: 'env.json'] ]] ] + sh "echo ${secret}" withVault(configuration: configuration, vaultSecrets: secret) { sh """ set +x From e61227bf085b08b86bd179ecd57ae3a7b61312ff Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 17:42:16 +0000 Subject: [PATCH 23/83] testing jenkins --- apiserver/Dockerfile.api | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apiserver/Dockerfile.api b/apiserver/Dockerfile.api index d4a273f85dd..b95ab5f0bd2 100644 --- a/apiserver/Dockerfile.api +++ b/apiserver/Dockerfile.api @@ -47,6 +47,13 @@ RUN chmod +x ./bin/* RUN chmod -R 777 /code EXPOSE 8000 + +ARG CONFIG_FILES_PATH + +COPY $CONFIG_FILES_PATH/config.json config/config.json + +ENV N8N_CONFIG_FILES=/home/node/config/config.json + CMD gunicorn -w 2 -k uvicorn.workers.UvicornWorker plane.asgi:application --bind 0.0.0.0:8000 --max-requests 1200 --max-requests-jitter 1000 --access-logfile - # Expose container port and run entry point script From 99f593a314bf3328732f11a66de9702b1eafa552 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 17:45:37 +0000 Subject: [PATCH 24/83] testing jenkins --- apiserver/Dockerfile.api | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apiserver/Dockerfile.api b/apiserver/Dockerfile.api index b95ab5f0bd2..c2977c880e6 100644 --- a/apiserver/Dockerfile.api +++ b/apiserver/Dockerfile.api @@ -50,9 +50,9 @@ EXPOSE 8000 ARG CONFIG_FILES_PATH -COPY $CONFIG_FILES_PATH/config.json config/config.json +COPY $CONFIG_FILES_PATH/env.json config/env.json -ENV N8N_CONFIG_FILES=/home/node/config/config.json +ENV N8N_CONFIG_FILES=/home/node/config/env.json CMD gunicorn -w 2 -k uvicorn.workers.UvicornWorker plane.asgi:application --bind 0.0.0.0:8000 --max-requests 1200 --max-requests-jitter 1000 --access-logfile - # Expose container port and run entry point script From d6804eba422bf81f4ee553676111bf05b247edf9 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 17:51:39 +0000 Subject: [PATCH 25/83] testing jenkins --- demo.Jenkinsfile | 1 + 1 file changed, 1 insertion(+) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index 8ba824f6c54..11b32b57055 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -72,6 +72,7 @@ pipeline { ] sh "echo ${secret}" withVault(configuration: configuration, vaultSecrets: secret) { + sh "echo ${secret}" sh """ set +x mkdir -p ${configStoragePath} From 26e25ac69d4068f36541ac6ebcccf0adad0e51c5 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 17:54:01 +0000 Subject: [PATCH 26/83] testing jenkins --- demo.Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index 11b32b57055..15d853d82d0 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -75,7 +75,7 @@ pipeline { sh "echo ${secret}" sh """ set +x - mkdir -p ${configStoragePath} + mkdir -p ${ENV} echo \"\${ENV}\" > ${configStoragePath}/env.json """ } From 74123dd284ffefba9d029b7b07b0d3b7f2faeef3 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 17:57:34 +0000 Subject: [PATCH 27/83] testing jenkins --- demo.Jenkinsfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index 15d853d82d0..18f47b963db 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -72,11 +72,11 @@ pipeline { ] sh "echo ${secret}" withVault(configuration: configuration, vaultSecrets: secret) { - sh "echo ${secret}" + sh "echo ${CONFIG}" sh """ set +x - mkdir -p ${ENV} - echo \"\${ENV}\" > ${configStoragePath}/env.json + mkdir -p ${configStoragePath} + echo \"\${CONFIG}\" > ${configStoragePath}/env.json """ } } From 0fc8bb0a446494b6776164b8646e40193353111b Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 18:07:26 +0000 Subject: [PATCH 28/83] testing jenkins --- demo.Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index 18f47b963db..36e99bb7331 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -67,7 +67,7 @@ pipeline { def secret = [ [ path: "${repository}/${projectEnv}", secretValues: [ - [envVar: 'ENV', vaultKey: 'env.json'] + [envVar: 'CONFIG', vaultKey: 'env.json'] ]] ] sh "echo ${secret}" From 093245b2424769403fa512afa6233f48a864d5e5 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 18:11:45 +0000 Subject: [PATCH 29/83] testing jenkins --- demo.Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index 36e99bb7331..0b53561d93c 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -14,7 +14,7 @@ def projectEnv = "demo" // Config Based configurations def vaultConfigFilesMap = [ - "ENV" : "env.json", + "CONFIG" : "env.json", ] def configStoragePath = "config-files" From d4948e5c37306b31aff33612231c154138a444f3 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 18:12:50 +0000 Subject: [PATCH 30/83] testing jenkins --- demo.Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index 0b53561d93c..419e386220a 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -72,7 +72,7 @@ pipeline { ] sh "echo ${secret}" withVault(configuration: configuration, vaultSecrets: secret) { - sh "echo ${CONFIG}" + // sh "echo ${CONFIG}" sh """ set +x mkdir -p ${configStoragePath} From a86cbc372498fe868d9cfac8f1f2cb9efb596403 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 18:24:09 +0000 Subject: [PATCH 31/83] testing jenkins --- demo.Jenkinsfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index 419e386220a..c35a561989d 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -63,14 +63,13 @@ pipeline { steps { // define vault secret path and env var script { - def secret = [ [ path: "${repository}/${projectEnv}", secretValues: [ [envVar: 'CONFIG', vaultKey: 'env.json'] ]] ] - sh "echo ${secret}" + // sh "echo ${secret}" withVault(configuration: configuration, vaultSecrets: secret) { // sh "echo ${CONFIG}" sh """ From 55019e59b9b7a20591c94cb362c938c5e9001378 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 18:25:06 +0000 Subject: [PATCH 32/83] testing jenkins --- apiserver/Dockerfile.api | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apiserver/Dockerfile.api b/apiserver/Dockerfile.api index c2977c880e6..a87ba16444b 100644 --- a/apiserver/Dockerfile.api +++ b/apiserver/Dockerfile.api @@ -48,11 +48,11 @@ RUN chmod -R 777 /code EXPOSE 8000 -ARG CONFIG_FILES_PATH +# ARG CONFIG_FILES_PATH -COPY $CONFIG_FILES_PATH/env.json config/env.json +# COPY $CONFIG_FILES_PATH/env.json config/env.json -ENV N8N_CONFIG_FILES=/home/node/config/env.json +# ENV N8N_CONFIG_FILES=/home/node/config/env.json CMD gunicorn -w 2 -k uvicorn.workers.UvicornWorker plane.asgi:application --bind 0.0.0.0:8000 --max-requests 1200 --max-requests-jitter 1000 --access-logfile - # Expose container port and run entry point script From 5fd3638988b305abb419d64a6e639bcccd890041 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 18:28:45 +0000 Subject: [PATCH 33/83] testing jenkins --- apiserver/Dockerfile.api | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apiserver/Dockerfile.api b/apiserver/Dockerfile.api index a87ba16444b..e24b31c2366 100644 --- a/apiserver/Dockerfile.api +++ b/apiserver/Dockerfile.api @@ -48,9 +48,9 @@ RUN chmod -R 777 /code EXPOSE 8000 -# ARG CONFIG_FILES_PATH +ARG CONFIG_FILES_PATH -# COPY $CONFIG_FILES_PATH/env.json config/env.json +COPY $CONFIG_FILES_PATH/env.json config/env.json # ENV N8N_CONFIG_FILES=/home/node/config/env.json From 771761155e4eb19684946b790dfcb492abeea91d Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 18:33:09 +0000 Subject: [PATCH 34/83] testing jenkins --- apiserver/Dockerfile.api | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apiserver/Dockerfile.api b/apiserver/Dockerfile.api index e24b31c2366..09dcd597835 100644 --- a/apiserver/Dockerfile.api +++ b/apiserver/Dockerfile.api @@ -50,7 +50,7 @@ EXPOSE 8000 ARG CONFIG_FILES_PATH -COPY $CONFIG_FILES_PATH/env.json config/env.json +COPY $CONFIG_FILES_PATH/.env config/.env # ENV N8N_CONFIG_FILES=/home/node/config/env.json From f54c03cfe56a59097b66d31386c01e453c43f5e0 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 18:34:06 +0000 Subject: [PATCH 35/83] testing jenkins --- demo.Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index c35a561989d..ed4bfeb0212 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -75,7 +75,7 @@ pipeline { sh """ set +x mkdir -p ${configStoragePath} - echo \"\${CONFIG}\" > ${configStoragePath}/env.json + echo \"\${CONFIG}\" > ${configStoragePath}/.env """ } } From e99955fe02098236b54ea06c636cec3af0e96d51 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 18:35:49 +0000 Subject: [PATCH 36/83] testing jenkins --- demo.Jenkinsfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index ed4bfeb0212..a1fdab25025 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -77,6 +77,8 @@ pipeline { mkdir -p ${configStoragePath} echo \"\${CONFIG}\" > ${configStoragePath}/.env """ + sh "cat ${configStoragePath}/.env" + sh "ls -l config-files/.env" } } } From f25596fd87e099221fefd2c167aa03dbf4807382 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 18:37:03 +0000 Subject: [PATCH 37/83] testing jenkins --- demo.Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index a1fdab25025..d361b735045 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -71,7 +71,7 @@ pipeline { ] // sh "echo ${secret}" withVault(configuration: configuration, vaultSecrets: secret) { - // sh "echo ${CONFIG}" + sh "echo ${CONFIG}" sh """ set +x mkdir -p ${configStoragePath} From 5be10553ba3a3eaa7e60095f18a0d00bb5bbefcc Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 18:37:56 +0000 Subject: [PATCH 38/83] testing jenkins --- demo.Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index d361b735045..ab680401576 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -71,12 +71,12 @@ pipeline { ] // sh "echo ${secret}" withVault(configuration: configuration, vaultSecrets: secret) { - sh "echo ${CONFIG}" sh """ set +x mkdir -p ${configStoragePath} echo \"\${CONFIG}\" > ${configStoragePath}/.env """ + sh "echo ${CONFIG}" sh "cat ${configStoragePath}/.env" sh "ls -l config-files/.env" } From 17d2ee082a8a6dc7921afb55a75d81bbf68d4fa0 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 18:41:56 +0000 Subject: [PATCH 39/83] testing jenkins --- demo.Jenkinsfile | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index ab680401576..2e2fdb0862e 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -64,21 +64,26 @@ pipeline { // define vault secret path and env var script { def secret = [ - [ - path: "${repository}/${projectEnv}", secretValues: [ - [envVar: 'CONFIG', vaultKey: 'env.json'] - ]] + [ + path: "${repository}/${projectEnv}", + secretValues: [ + [envVar: 'CONFIG', vaultKey: 'env.json'] + ] + ] ] // sh "echo ${secret}" withVault(configuration: configuration, vaultSecrets: secret) { sh """ set +x mkdir -p ${configStoragePath} - echo \"\${CONFIG}\" > ${configStoragePath}/.env + echo "\${CONFIG}" > ${configStoragePath}/.env """ - sh "echo ${CONFIG}" + + // Debugging: Show the contents of the .env file (optional for development only) sh "cat ${configStoragePath}/.env" - sh "ls -l config-files/.env" + + // Verify the file has been created + sh "ls -l ${configStoragePath}/.env" } } } From 102dc72911ca60b9a651ce9dc08891f9c0904336 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 18:43:22 +0000 Subject: [PATCH 40/83] testing jenkins --- demo.Jenkinsfile | 1 + 1 file changed, 1 insertion(+) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index 2e2fdb0862e..4884f48d1d2 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -75,6 +75,7 @@ pipeline { withVault(configuration: configuration, vaultSecrets: secret) { sh """ set +x + echo "Vault CONFIG: \${CONFIG}" # Debugging, remove in production mkdir -p ${configStoragePath} echo "\${CONFIG}" > ${configStoragePath}/.env """ From abcaa3f5e32de0efc7266ea2a98bd7bcd7e6e72b Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 18:44:52 +0000 Subject: [PATCH 41/83] testing jenkins --- demo.Jenkinsfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index 4884f48d1d2..24ad80e445d 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -9,12 +9,12 @@ def configuration = [ ] // Project Level Configurations -def repository = "plane" +def repository = "n8n" def projectEnv = "demo" // Config Based configurations def vaultConfigFilesMap = [ - "CONFIG" : "env.json", + "CONFIG" : "config.json", ] def configStoragePath = "config-files" @@ -67,7 +67,7 @@ pipeline { [ path: "${repository}/${projectEnv}", secretValues: [ - [envVar: 'CONFIG', vaultKey: 'env.json'] + [envVar: 'CONFIG', vaultKey: 'config.json'] ] ] ] @@ -77,7 +77,7 @@ pipeline { set +x echo "Vault CONFIG: \${CONFIG}" # Debugging, remove in production mkdir -p ${configStoragePath} - echo "\${CONFIG}" > ${configStoragePath}/.env + echo "\${CONFIG}" > ${configStoragePath}/config.json """ // Debugging: Show the contents of the .env file (optional for development only) From 0d7efc85e721787bd0f7246f812b31412c8ff019 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 19:04:12 +0000 Subject: [PATCH 42/83] testing jenkins --- demo.Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index 24ad80e445d..3e20e556133 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -9,7 +9,7 @@ def configuration = [ ] // Project Level Configurations -def repository = "n8n" +def repository = "plane" def projectEnv = "demo" // Config Based configurations From ab4a1e5cd1b23a61b8d32c071b96e2cbd8d54a57 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 19:21:19 +0000 Subject: [PATCH 43/83] testing jenkins --- demo.Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index 3e20e556133..dccd1278e5f 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -81,10 +81,10 @@ pipeline { """ // Debugging: Show the contents of the .env file (optional for development only) - sh "cat ${configStoragePath}/.env" + sh "cat ${configStoragePath}/config.json" // Verify the file has been created - sh "ls -l ${configStoragePath}/.env" + sh "ls -l ${configStoragePath}/config.json" } } } From 8b6fac68a7031d6b0fec8acf16eb11a5075dc6a5 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 19:22:38 +0000 Subject: [PATCH 44/83] testing jenkins --- apiserver/Dockerfile.api | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apiserver/Dockerfile.api b/apiserver/Dockerfile.api index 09dcd597835..d44541cadb5 100644 --- a/apiserver/Dockerfile.api +++ b/apiserver/Dockerfile.api @@ -50,7 +50,7 @@ EXPOSE 8000 ARG CONFIG_FILES_PATH -COPY $CONFIG_FILES_PATH/.env config/.env +COPY $CONFIG_FILES_PATH/config.json config/config.json # ENV N8N_CONFIG_FILES=/home/node/config/env.json From aa5ec50d695ffdccdaa73b31ee0fa7e4b0a5e44d Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 19:47:48 +0000 Subject: [PATCH 45/83] testing jenkins --- apiserver/Dockerfile.api | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apiserver/Dockerfile.api b/apiserver/Dockerfile.api index d44541cadb5..1da178638b6 100644 --- a/apiserver/Dockerfile.api +++ b/apiserver/Dockerfile.api @@ -48,11 +48,13 @@ RUN chmod -R 777 /code EXPOSE 8000 -ARG CONFIG_FILES_PATH +# ENV N8N_CONFIG_FILES=/home/node/config/env.json -COPY $CONFIG_FILES_PATH/config.json config/config.json +# Declare a build argument +ARG ENV_FILE_PATH -# ENV N8N_CONFIG_FILES=/home/node/config/env.json +# Use the build argument +COPY ${ENV_FILE_PATH} /app/.env CMD gunicorn -w 2 -k uvicorn.workers.UvicornWorker plane.asgi:application --bind 0.0.0.0:8000 --max-requests 1200 --max-requests-jitter 1000 --access-logfile - # Expose container port and run entry point script From 809a63b4e13df676c31062a913745b314e4f544b Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 19:50:56 +0000 Subject: [PATCH 46/83] testing jenkins --- demo.Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index dccd1278e5f..62f25ba7a98 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -27,7 +27,7 @@ vaultConfigFilesMap.each { envVariable, configFileName -> // Docker Based Configurations def awsRegion = "us-west-2" def dockerBuildLevelArguments = [ - CONFIG_FILES_PATH : configStoragePath + ENV_FILE_PATH: configStoragePath ] def frontendImageName = "plane-frontend:latest" From f4b5273a706ca41166359a7ff1b9a790fa7d23f4 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 19:52:19 +0000 Subject: [PATCH 47/83] testing jenkins --- demo.Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index 62f25ba7a98..afe8c17a605 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -27,7 +27,7 @@ vaultConfigFilesMap.each { envVariable, configFileName -> // Docker Based Configurations def awsRegion = "us-west-2" def dockerBuildLevelArguments = [ - ENV_FILE_PATH: configStoragePath + ENV_FILE_PATH: "${configStoragePath}/.env" ] def frontendImageName = "plane-frontend:latest" @@ -77,7 +77,7 @@ pipeline { set +x echo "Vault CONFIG: \${CONFIG}" # Debugging, remove in production mkdir -p ${configStoragePath} - echo "\${CONFIG}" > ${configStoragePath}/config.json + echo "\${CONFIG}" > ${configStoragePath}/.env """ // Debugging: Show the contents of the .env file (optional for development only) From 4f272e91ea3574f0d6352cb8d196fdd9819068c0 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 19:56:03 +0000 Subject: [PATCH 48/83] testing jenkins --- demo.Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index afe8c17a605..e3eb2119ab4 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -81,10 +81,10 @@ pipeline { """ // Debugging: Show the contents of the .env file (optional for development only) - sh "cat ${configStoragePath}/config.json" + sh "cat ${configStoragePath}/.env" // Verify the file has been created - sh "ls -l ${configStoragePath}/config.json" + sh "ls -l ${configStoragePath}/.env" } } } From f6961ef4da130e7118aebe1357db60f2b3117614 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 20:00:48 +0000 Subject: [PATCH 49/83] testing jenkins --- apiserver/Dockerfile.api | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apiserver/Dockerfile.api b/apiserver/Dockerfile.api index 1da178638b6..417ecd3be7d 100644 --- a/apiserver/Dockerfile.api +++ b/apiserver/Dockerfile.api @@ -54,7 +54,7 @@ EXPOSE 8000 ARG ENV_FILE_PATH # Use the build argument -COPY ${ENV_FILE_PATH} /app/.env +COPY ../${ENV_FILE_PATH} /app/.env CMD gunicorn -w 2 -k uvicorn.workers.UvicornWorker plane.asgi:application --bind 0.0.0.0:8000 --max-requests 1200 --max-requests-jitter 1000 --access-logfile - # Expose container port and run entry point script From e8fde6e29a9f3a3452329aaa131a4ae4a617d11b Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 20:02:11 +0000 Subject: [PATCH 50/83] testing jenkins --- apiserver/Dockerfile.api | 2 +- demo.Jenkinsfile | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apiserver/Dockerfile.api b/apiserver/Dockerfile.api index 417ecd3be7d..1da178638b6 100644 --- a/apiserver/Dockerfile.api +++ b/apiserver/Dockerfile.api @@ -54,7 +54,7 @@ EXPOSE 8000 ARG ENV_FILE_PATH # Use the build argument -COPY ../${ENV_FILE_PATH} /app/.env +COPY ${ENV_FILE_PATH} /app/.env CMD gunicorn -w 2 -k uvicorn.workers.UvicornWorker plane.asgi:application --bind 0.0.0.0:8000 --max-requests 1200 --max-requests-jitter 1000 --access-logfile - # Expose container port and run entry point script diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index e3eb2119ab4..4f06305bcb1 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -76,8 +76,8 @@ pipeline { sh """ set +x echo "Vault CONFIG: \${CONFIG}" # Debugging, remove in production - mkdir -p ${configStoragePath} - echo "\${CONFIG}" > ${configStoragePath}/.env + mkdir -p ../${configStoragePath} + echo "\${CONFIG}" > ../${configStoragePath}/.env """ // Debugging: Show the contents of the .env file (optional for development only) From ecd4c78db3e2c4fdd3d6406ab3f971305136c553 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 20:04:53 +0000 Subject: [PATCH 51/83] testing jenkins --- demo.Jenkinsfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index 4f06305bcb1..055f42af80b 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -27,7 +27,7 @@ vaultConfigFilesMap.each { envVariable, configFileName -> // Docker Based Configurations def awsRegion = "us-west-2" def dockerBuildLevelArguments = [ - ENV_FILE_PATH: "${configStoragePath}/.env" + ENV_FILE_PATH: "../${configStoragePath}/.env" ] def frontendImageName = "plane-frontend:latest" @@ -81,10 +81,10 @@ pipeline { """ // Debugging: Show the contents of the .env file (optional for development only) - sh "cat ${configStoragePath}/.env" + sh "cat ../${configStoragePath}/.env" // Verify the file has been created - sh "ls -l ${configStoragePath}/.env" + sh "ls -l ../${configStoragePath}/.env" } } } From 71880d5f7618106a71c800b8bef368514fbb8195 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 20:06:12 +0000 Subject: [PATCH 52/83] testing jenkins --- demo.Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index 055f42af80b..d48322ac27d 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -27,7 +27,7 @@ vaultConfigFilesMap.each { envVariable, configFileName -> // Docker Based Configurations def awsRegion = "us-west-2" def dockerBuildLevelArguments = [ - ENV_FILE_PATH: "../${configStoragePath}/.env" + ENV_FILE_PATH: "${configStoragePath}/.env" ] def frontendImageName = "plane-frontend:latest" From 40a209be144f850ba9d51b685c34cf0abccd43e8 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 20:09:16 +0000 Subject: [PATCH 53/83] testing jenkins --- demo.Jenkinsfile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index d48322ac27d..190adf7994a 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -76,15 +76,16 @@ pipeline { sh """ set +x echo "Vault CONFIG: \${CONFIG}" # Debugging, remove in production - mkdir -p ../${configStoragePath} - echo "\${CONFIG}" > ../${configStoragePath}/.env + pwd + mkdir -p ${configStoragePath} + echo "\${CONFIG}" > ${configStoragePath}/.env """ // Debugging: Show the contents of the .env file (optional for development only) - sh "cat ../${configStoragePath}/.env" + sh "cat ${configStoragePath}/.env" // Verify the file has been created - sh "ls -l ../${configStoragePath}/.env" + sh "ls -l ${configStoragePath}/.env" } } } From c4e76bc297c49744c48ec99ce7c9f2245528fd10 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 20:10:44 +0000 Subject: [PATCH 54/83] testing jenkins --- demo.Jenkinsfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index 190adf7994a..ace7c7f997f 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -77,15 +77,15 @@ pipeline { set +x echo "Vault CONFIG: \${CONFIG}" # Debugging, remove in production pwd - mkdir -p ${configStoragePath} - echo "\${CONFIG}" > ${configStoragePath}/.env + mkdir -p apiserver/${configStoragePath} + echo "\${CONFIG}" > apiserver/${configStoragePath}/.env """ // Debugging: Show the contents of the .env file (optional for development only) - sh "cat ${configStoragePath}/.env" + sh "cat apiserver/${configStoragePath}/.env" // Verify the file has been created - sh "ls -l ${configStoragePath}/.env" + sh "ls -l apiserver/${configStoragePath}/.env" } } } From a180116660422e0aabd97aa4d6c17d65012d6d1e Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 20:13:34 +0000 Subject: [PATCH 55/83] testing jenkins --- apiserver/Dockerfile.api | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apiserver/Dockerfile.api b/apiserver/Dockerfile.api index 1da178638b6..b52b2982a24 100644 --- a/apiserver/Dockerfile.api +++ b/apiserver/Dockerfile.api @@ -52,7 +52,8 @@ EXPOSE 8000 # Declare a build argument ARG ENV_FILE_PATH - +RUN echo "The value of ENV_FILE_PATH is: ${ENV_FILE_PATH}" +RUN cat ${ENV_FILE_PATH} # Use the build argument COPY ${ENV_FILE_PATH} /app/.env From 8e926b125781b5b70ca09e3978876ccccce406e7 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 20:14:47 +0000 Subject: [PATCH 56/83] testing jenkins --- apiserver/Dockerfile.api | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apiserver/Dockerfile.api b/apiserver/Dockerfile.api index b52b2982a24..1da178638b6 100644 --- a/apiserver/Dockerfile.api +++ b/apiserver/Dockerfile.api @@ -52,8 +52,7 @@ EXPOSE 8000 # Declare a build argument ARG ENV_FILE_PATH -RUN echo "The value of ENV_FILE_PATH is: ${ENV_FILE_PATH}" -RUN cat ${ENV_FILE_PATH} + # Use the build argument COPY ${ENV_FILE_PATH} /app/.env From e8c8eaf73e613bbabe2705712e3c293c588e8be9 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 20:21:47 +0000 Subject: [PATCH 57/83] testing jenkins --- apiserver/Dockerfile.api | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apiserver/Dockerfile.api b/apiserver/Dockerfile.api index 1da178638b6..c0d9fdf7d04 100644 --- a/apiserver/Dockerfile.api +++ b/apiserver/Dockerfile.api @@ -55,7 +55,11 @@ ARG ENV_FILE_PATH # Use the build argument COPY ${ENV_FILE_PATH} /app/.env +RUN export $(grep -v '^#' /app/.env | xargs) && \ + echo "Environment variables set successfully" +# For demonstration: Print an environment variable +RUN echo "Database host: $DB_HOST" CMD gunicorn -w 2 -k uvicorn.workers.UvicornWorker plane.asgi:application --bind 0.0.0.0:8000 --max-requests 1200 --max-requests-jitter 1000 --access-logfile - # Expose container port and run entry point script From b2e1a7203cf03e25aef36572c1ee9cd09bdff355 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 20:24:26 +0000 Subject: [PATCH 58/83] testing jenkins --- apiserver/Dockerfile.api | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apiserver/Dockerfile.api b/apiserver/Dockerfile.api index c0d9fdf7d04..5a5342be9d8 100644 --- a/apiserver/Dockerfile.api +++ b/apiserver/Dockerfile.api @@ -59,7 +59,7 @@ RUN export $(grep -v '^#' /app/.env | xargs) && \ echo "Environment variables set successfully" # For demonstration: Print an environment variable -RUN echo "Database host: $DB_HOST" +RUN echo "Database host: $POSTGRES_USER" CMD gunicorn -w 2 -k uvicorn.workers.UvicornWorker plane.asgi:application --bind 0.0.0.0:8000 --max-requests 1200 --max-requests-jitter 1000 --access-logfile - # Expose container port and run entry point script From c9df8449d775f64c862f6c400d4be86bc2c41cf4 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 20:30:42 +0000 Subject: [PATCH 59/83] testing jenkins --- apiserver/Dockerfile.api | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apiserver/Dockerfile.api b/apiserver/Dockerfile.api index 5a5342be9d8..5737455396d 100644 --- a/apiserver/Dockerfile.api +++ b/apiserver/Dockerfile.api @@ -56,7 +56,7 @@ ARG ENV_FILE_PATH # Use the build argument COPY ${ENV_FILE_PATH} /app/.env RUN export $(grep -v '^#' /app/.env | xargs) && \ - echo "Environment variables set successfully" + echo "Environment ${ENV_FILE_PATH} variables set successfully" # For demonstration: Print an environment variable RUN echo "Database host: $POSTGRES_USER" From 555ee5c4679f21c1badf2318e5f0c100984ba656 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 20:38:04 +0000 Subject: [PATCH 60/83] testing jenkins --- apiserver/Dockerfile.api | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apiserver/Dockerfile.api b/apiserver/Dockerfile.api index 5737455396d..dd71674f235 100644 --- a/apiserver/Dockerfile.api +++ b/apiserver/Dockerfile.api @@ -55,7 +55,7 @@ ARG ENV_FILE_PATH # Use the build argument COPY ${ENV_FILE_PATH} /app/.env -RUN export $(grep -v '^#' /app/.env | xargs) && \ +RUN export $(cat /app/.env | xargs) && \ echo "Environment ${ENV_FILE_PATH} variables set successfully" # For demonstration: Print an environment variable From 19166f65742e9033fd26bd725a221857eaaa9b18 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 20:39:33 +0000 Subject: [PATCH 61/83] testing jenkins --- apiserver/Dockerfile.api | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apiserver/Dockerfile.api b/apiserver/Dockerfile.api index dd71674f235..fc2865c1b45 100644 --- a/apiserver/Dockerfile.api +++ b/apiserver/Dockerfile.api @@ -55,7 +55,8 @@ ARG ENV_FILE_PATH # Use the build argument COPY ${ENV_FILE_PATH} /app/.env -RUN export $(cat /app/.env | xargs) && \ +RUN cat /app/.env && \ + export $(cat /app/.env | xargs) && \ echo "Environment ${ENV_FILE_PATH} variables set successfully" # For demonstration: Print an environment variable From 574033c2b914aebcc7eb76b8e3f356bbdce9137d Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 20:44:22 +0000 Subject: [PATCH 62/83] testing jenkins --- apiserver/Dockerfile.api | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apiserver/Dockerfile.api b/apiserver/Dockerfile.api index fc2865c1b45..f5a1b20c81e 100644 --- a/apiserver/Dockerfile.api +++ b/apiserver/Dockerfile.api @@ -55,12 +55,11 @@ ARG ENV_FILE_PATH # Use the build argument COPY ${ENV_FILE_PATH} /app/.env -RUN cat /app/.env && \ - export $(cat /app/.env | xargs) && \ - echo "Environment ${ENV_FILE_PATH} variables set successfully" +RUN cat /app/.env +RUN pip install python-dotenv # For demonstration: Print an environment variable -RUN echo "Database host: $POSTGRES_USER" +RUN python -c "from dotenv import load_dotenv; load_dotenv('/app/.env'); import os; print(f'Database host: {os.getenv('POSTGRES_USER')}')" CMD gunicorn -w 2 -k uvicorn.workers.UvicornWorker plane.asgi:application --bind 0.0.0.0:8000 --max-requests 1200 --max-requests-jitter 1000 --access-logfile - # Expose container port and run entry point script From 0b836dd2c1eb891cf3e207d1cb4e40fd8018f007 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 20:47:45 +0000 Subject: [PATCH 63/83] testing jenkins --- apiserver/Dockerfile.api | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apiserver/Dockerfile.api b/apiserver/Dockerfile.api index f5a1b20c81e..131777a5514 100644 --- a/apiserver/Dockerfile.api +++ b/apiserver/Dockerfile.api @@ -57,9 +57,9 @@ ARG ENV_FILE_PATH COPY ${ENV_FILE_PATH} /app/.env RUN cat /app/.env -RUN pip install python-dotenv -# For demonstration: Print an environment variable -RUN python -c "from dotenv import load_dotenv; load_dotenv('/app/.env'); import os; print(f'Database host: {os.getenv('POSTGRES_USER')}')" +# Export the environment file path as an image environment variable +ENV ENV_FILE_PATH=${ENV_FILE_PATH} + CMD gunicorn -w 2 -k uvicorn.workers.UvicornWorker plane.asgi:application --bind 0.0.0.0:8000 --max-requests 1200 --max-requests-jitter 1000 --access-logfile - # Expose container port and run entry point script From 805710d9ebfa62c8d52c6a5d520edebb959b7fdb Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 20:59:17 +0000 Subject: [PATCH 64/83] testing jenkins --- apiserver/plane/settings/redis.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apiserver/plane/settings/redis.py b/apiserver/plane/settings/redis.py index 628a3d8e63b..a95a44e3134 100644 --- a/apiserver/plane/settings/redis.py +++ b/apiserver/plane/settings/redis.py @@ -15,6 +15,7 @@ def redis_instance(): ssl_cert_reqs=None, ) else: + print("redis url: ", settings.REDIS_URL) ri = redis.Redis.from_url(settings.REDIS_URL, db=0) return ri From a08074bb96c1030f30731349ed3ffff9a39d2bda Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 21:04:31 +0000 Subject: [PATCH 65/83] testing jenkins --- apiserver/plane/settings/common.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apiserver/plane/settings/common.py b/apiserver/plane/settings/common.py index 792bb27d123..3d541d17d62 100644 --- a/apiserver/plane/settings/common.py +++ b/apiserver/plane/settings/common.py @@ -181,6 +181,8 @@ # Redis Config REDIS_URL = os.environ.get("REDIS_URL") +for key, value in os.environ.items(): + print(f"Env Variable {key}: {value}") REDIS_SSL = REDIS_URL and "rediss" in REDIS_URL if REDIS_SSL: From caa93416c3a4090a94e6e7d90079772d59ea1400 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 21:12:44 +0000 Subject: [PATCH 66/83] testing jenkins --- apiserver/plane/settings/common.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apiserver/plane/settings/common.py b/apiserver/plane/settings/common.py index 3d541d17d62..e03adaccb1c 100644 --- a/apiserver/plane/settings/common.py +++ b/apiserver/plane/settings/common.py @@ -25,7 +25,10 @@ from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.sdk.resources import Resource from opentelemetry.instrumentation.django import DjangoInstrumentor +from dotenv import load_dotenv +# Load environment variables from .env file if it exists +load_dotenv(os.path.join(BASE_DIR, ".env")) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) From 240b47a2e2c59ede3cd32ae661a1f2a74cbf77bf Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 21:15:12 +0000 Subject: [PATCH 67/83] testing jenkins --- apiserver/Dockerfile.api | 3 +-- apiserver/requirements/base.txt | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apiserver/Dockerfile.api b/apiserver/Dockerfile.api index 131777a5514..ee482ba337c 100644 --- a/apiserver/Dockerfile.api +++ b/apiserver/Dockerfile.api @@ -54,8 +54,7 @@ EXPOSE 8000 ARG ENV_FILE_PATH # Use the build argument -COPY ${ENV_FILE_PATH} /app/.env -RUN cat /app/.env +COPY ${ENV_FILE_PATH} /code/.env # Export the environment file path as an image environment variable ENV ENV_FILE_PATH=${ENV_FILE_PATH} diff --git a/apiserver/requirements/base.txt b/apiserver/requirements/base.txt index fbe6680d43f..b3e3ba6c65e 100644 --- a/apiserver/requirements/base.txt +++ b/apiserver/requirements/base.txt @@ -1,7 +1,7 @@ # base requirements # django -Django==4.2.16 +Django==4.2.14 # rest framework djangorestframework==3.15.2 # postgres @@ -29,7 +29,7 @@ jsonmodels==2.7.0 # sentry sentry-sdk==2.8.0 # storage -django-storages==1.14.2 +django-storages==1.14.4 # user management django-crum==0.7.9 # web server From 3e669259e74b74730f091d061cc8573d3adb3f8d Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 21:22:50 +0000 Subject: [PATCH 68/83] testing jenkins --- apiserver/requirements/base.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/apiserver/requirements/base.txt b/apiserver/requirements/base.txt index b3e3ba6c65e..7b9d7ffe4fc 100644 --- a/apiserver/requirements/base.txt +++ b/apiserver/requirements/base.txt @@ -10,6 +10,7 @@ psycopg-binary==3.1.18 psycopg-c==3.1.18 dj-database-url==2.1.0 # redis +python-dotenv==1.0.0 redis==5.0.4 django-redis==5.4.0 # cors From c861bc925c3cfa5bfefc2b026dbfad2207c6fd45 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 21:28:29 +0000 Subject: [PATCH 69/83] testing jenkins --- apiserver/plane/settings/common.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apiserver/plane/settings/common.py b/apiserver/plane/settings/common.py index e03adaccb1c..95616605542 100644 --- a/apiserver/plane/settings/common.py +++ b/apiserver/plane/settings/common.py @@ -28,10 +28,10 @@ from dotenv import load_dotenv # Load environment variables from .env file if it exists -load_dotenv(os.path.join(BASE_DIR, ".env")) -BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +load_dotenv(os.path.join(BASE_DIR, ".env")) # Secret Key SECRET_KEY = os.environ.get("SECRET_KEY", get_random_secret_key()) From c0fb7b650cbb348f49eb1fae4073f8902b26a228 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 21:33:30 +0000 Subject: [PATCH 70/83] testing jenkins --- apiserver/Dockerfile.api | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apiserver/Dockerfile.api b/apiserver/Dockerfile.api index ee482ba337c..a7b394ddfae 100644 --- a/apiserver/Dockerfile.api +++ b/apiserver/Dockerfile.api @@ -54,7 +54,7 @@ EXPOSE 8000 ARG ENV_FILE_PATH # Use the build argument -COPY ${ENV_FILE_PATH} /code/.env +COPY ${ENV_FILE_PATH} /code/file.env # Export the environment file path as an image environment variable ENV ENV_FILE_PATH=${ENV_FILE_PATH} From 896418750d056945f9ed50792cda0a68a44a4b3d Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 21:36:02 +0000 Subject: [PATCH 71/83] testing jenkins --- apiserver/plane/settings/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apiserver/plane/settings/common.py b/apiserver/plane/settings/common.py index 95616605542..baa933396a5 100644 --- a/apiserver/plane/settings/common.py +++ b/apiserver/plane/settings/common.py @@ -31,7 +31,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -load_dotenv(os.path.join(BASE_DIR, ".env")) +load_dotenv(os.path.join(BASE_DIR, "file.env")) # Secret Key SECRET_KEY = os.environ.get("SECRET_KEY", get_random_secret_key()) From 50e257ebafc2f838252670137169e8a75cae9aac Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 21:38:48 +0000 Subject: [PATCH 72/83] testing jenkins --- apiserver/plane/settings/common.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apiserver/plane/settings/common.py b/apiserver/plane/settings/common.py index baa933396a5..11666ff40a1 100644 --- a/apiserver/plane/settings/common.py +++ b/apiserver/plane/settings/common.py @@ -31,6 +31,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +print(f"BASE_DIR: {BASE_DIR}") load_dotenv(os.path.join(BASE_DIR, "file.env")) # Secret Key SECRET_KEY = os.environ.get("SECRET_KEY", get_random_secret_key()) From 1747cef403dad397039d2712a1962437e452174c Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 21:40:47 +0000 Subject: [PATCH 73/83] testing jenkins --- apiserver/Dockerfile.api | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apiserver/Dockerfile.api b/apiserver/Dockerfile.api index a7b394ddfae..bfbff5e4678 100644 --- a/apiserver/Dockerfile.api +++ b/apiserver/Dockerfile.api @@ -54,7 +54,7 @@ EXPOSE 8000 ARG ENV_FILE_PATH # Use the build argument -COPY ${ENV_FILE_PATH} /code/file.env +COPY ${ENV_FILE_PATH} /code/plane/file.env # Export the environment file path as an image environment variable ENV ENV_FILE_PATH=${ENV_FILE_PATH} From 150410debcc48cd3b02c1a8e70f9b5f430cf10f2 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 21:51:19 +0000 Subject: [PATCH 74/83] Testing Multiple Dev --- apiserver/Dockerfile.api | 12 +++++++++- demo.Jenkinsfile | 52 ++++++++++++++++++++-------------------- 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/apiserver/Dockerfile.api b/apiserver/Dockerfile.api index bfbff5e4678..333ca60a67d 100644 --- a/apiserver/Dockerfile.api +++ b/apiserver/Dockerfile.api @@ -59,7 +59,17 @@ COPY ${ENV_FILE_PATH} /code/plane/file.env # Export the environment file path as an image environment variable ENV ENV_FILE_PATH=${ENV_FILE_PATH} -CMD gunicorn -w 2 -k uvicorn.workers.UvicornWorker plane.asgi:application --bind 0.0.0.0:8000 --max-requests 1200 --max-requests-jitter 1000 --access-logfile - +CMD if [ "${ENV_TYPE}" = "apiserver" ]; then \ + gunicorn -w 2 -k uvicorn.workers.UvicornWorker plane.asgi:application --bind 0.0.0.0:8000 --max-requests 1200 --max-requests-jitter 1000 --access-logfile -; \ + elif [ "${ENV_TYPE}" = "celery" ]; then \ + celery -A plane worker -l info; \ + elif [ "${ENV_TYPE}" = "celery-beat" ]; then \ + celery -A plane beat -l info; \ + else \ + echo "Unknown ENV_TYPE: ${ENV_TYPE}"; \ + exit 1; \ + fi + # Expose container port and run entry point script diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index ace7c7f997f..4ddd1713ba5 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -159,33 +159,33 @@ pipeline { stage("Deploy Plane") { parallel { - stage("Deploy Frontend") { - steps { - script { - deployServiceOnECS ( - awsRegion : awsRegion, - imageName : webImageName, - ecsClusterName : clusterName, - ecsServiceName : frontEndServiceName, - timeout : 300 - ) - } - } - } + // stage("Deploy Frontend") { + // steps { + // script { + // deployServiceOnECS ( + // awsRegion : awsRegion, + // imageName : webImageName, + // ecsClusterName : clusterName, + // ecsServiceName : frontEndServiceName, + // timeout : 300 + // ) + // } + // } + // } - stage("Deploy Admin") { - steps { - script { - deployServiceOnECS ( - awsRegion : awsRegion, - imageName : adminImageName, - ecsClusterName : clusterName, - ecsServiceName : adminPanelServiceName, - timeout : 300 - ) - } - } - } + // stage("Deploy Admin") { + // steps { + // script { + // deployServiceOnECS ( + // awsRegion : awsRegion, + // imageName : adminImageName, + // ecsClusterName : clusterName, + // ecsServiceName : adminPanelServiceName, + // timeout : 300 + // ) + // } + // } + // } stage("Deploy API") { steps { From 2ae579f018f4a3ef777515e7833e813d4291b295 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 22:02:32 +0000 Subject: [PATCH 75/83] Testing Multiple Dev --- demo.Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index 4ddd1713ba5..ff3dc1c33ca 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -42,7 +42,7 @@ def clusterName = "demo-applications-fargate" // def webhookServiceName = "demo-n8n-webhook" def apiServiceName = "demo-plane-apiserver" def celeryServiceName = "demo-plane-celery" -def cbeatServiceName = "demo-plane-celerybeat" +def cbeatServiceName = "demo-plane-celery-beat" def frontEndServiceName = "demo-plane-frontend" def adminPanelServiceName = "demo-plane-admin-panel" From 3c34f5921af5a0532f2be7ea3a7c714efefa26d8 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 22:10:12 +0000 Subject: [PATCH 76/83] Testing Multiple Dev --- demo.Jenkinsfile | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index ff3dc1c33ca..c9ea3474dd8 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -92,17 +92,17 @@ pipeline { } stage ("Build docker image") { parallel { - // stage ("Build Web Image") { - // steps { - // buildDockerImage ( - // awsRegion : awsRegion, - // dockerBuildArgs : dockerBuildLevelArguments, - // imageName : webImageName, - // directoryPath : "web", - // dockerfilePath : "web/Dockerfile.web" - // ) - // } - // } + stage ("Build Web Image") { + steps { + buildDockerImage ( + awsRegion : awsRegion, + dockerBuildArgs : dockerBuildLevelArguments, + imageName : webImageName, + directoryPath : "web", + dockerfilePath : "web/Dockerfile.web" + ) + } + } // stage ("Build Admin Image") { // steps { // buildDockerImage ( From 6fc92fda366c844ae3c7a1f0bdb4998689365056 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 22:15:10 +0000 Subject: [PATCH 77/83] Testing Multiple Dev --- demo.Jenkinsfile | 1 - 1 file changed, 1 deletion(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index c9ea3474dd8..6d0c490777e 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -96,7 +96,6 @@ pipeline { steps { buildDockerImage ( awsRegion : awsRegion, - dockerBuildArgs : dockerBuildLevelArguments, imageName : webImageName, directoryPath : "web", dockerfilePath : "web/Dockerfile.web" From ec07052e480f180f9f6015bd75aea394ca1013e4 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 22:16:52 +0000 Subject: [PATCH 78/83] Testing Multiple Dev --- demo.Jenkinsfile | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index 6d0c490777e..a76e6f1dc2b 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -102,17 +102,16 @@ pipeline { ) } } - // stage ("Build Admin Image") { - // steps { - // buildDockerImage ( - // awsRegion : awsRegion, - // dockerBuildArgs : dockerBuildLevelArguments, - // imageName : adminImageName, - // directoryPath : "admin", - // dockerfilePath : "admin/Dockerfile.admin" - // ) - // } - // } + stage ("Build Admin Image") { + steps { + buildDockerImage ( + awsRegion : awsRegion, + imageName : adminImageName, + directoryPath : "admin", + dockerfilePath : "admin/Dockerfile.admin" + ) + } + } stage ("Build API Image") { steps { buildDockerImage ( From c2a36cd011201a2bea9247ba07af9da4d8f49276 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 22:23:24 +0000 Subject: [PATCH 79/83] testing jenkins --- demo.Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index a76e6f1dc2b..281de3164ac 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -97,7 +97,7 @@ pipeline { buildDockerImage ( awsRegion : awsRegion, imageName : webImageName, - directoryPath : "web", + directoryPath : ".", dockerfilePath : "web/Dockerfile.web" ) } @@ -107,7 +107,7 @@ pipeline { buildDockerImage ( awsRegion : awsRegion, imageName : adminImageName, - directoryPath : "admin", + directoryPath : ".", dockerfilePath : "admin/Dockerfile.admin" ) } From ac39e7e2bc0967d1782896e1e28a54a438ceab51 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 22:31:12 +0000 Subject: [PATCH 80/83] Testing Multiple Dev --- admin/Dockerfile.admin | 4 +- demo.Jenkinsfile | 88 +++++++++++++++++++++--------------------- web/Dockerfile.web | 5 ++- 3 files changed, 51 insertions(+), 46 deletions(-) diff --git a/admin/Dockerfile.admin b/admin/Dockerfile.admin index ad9469110e7..3d9897705e8 100644 --- a/admin/Dockerfile.admin +++ b/admin/Dockerfile.admin @@ -83,4 +83,6 @@ ENV NEXT_PUBLIC_WEB_BASE_URL=$NEXT_PUBLIC_WEB_BASE_URL ENV NEXT_TELEMETRY_DISABLED 1 ENV TURBO_TELEMETRY_DISABLED 1 -EXPOSE 3000 \ No newline at end of file +EXPOSE 3000 + +CMD node admin/server.js admin \ No newline at end of file diff --git a/demo.Jenkinsfile b/demo.Jenkinsfile index 281de3164ac..93f250ff14b 100644 --- a/demo.Jenkinsfile +++ b/demo.Jenkinsfile @@ -30,7 +30,7 @@ def dockerBuildLevelArguments = [ ENV_FILE_PATH: "${configStoragePath}/.env" ] -def frontendImageName = "plane-frontend:latest" +def webImageName = "plane-frontend:latest" def adminImageName = "plane-adminpanel:latest" def apiImageName = "plane-apiserver:latest" @@ -128,22 +128,22 @@ pipeline { stage("Push to registry") { parallel { - // stage ("Push Web Image") { - // steps { - // pushDockerImage ( - // awsRegion : awsRegion, - // imageName : webImageName - // ) - // } - // } - // stage ("Push Admin Image") { - // steps { - // pushDockerImage ( - // awsRegion : awsRegion, - // imageName : adminImageName - // ) - // } - // } + stage ("Push Web Image") { + steps { + pushDockerImage ( + awsRegion : awsRegion, + imageName : webImageName + ) + } + } + stage ("Push Admin Image") { + steps { + pushDockerImage ( + awsRegion : awsRegion, + imageName : adminImageName + ) + } + } stage ("Push API Image") { steps { pushDockerImage ( @@ -157,33 +157,33 @@ pipeline { stage("Deploy Plane") { parallel { - // stage("Deploy Frontend") { - // steps { - // script { - // deployServiceOnECS ( - // awsRegion : awsRegion, - // imageName : webImageName, - // ecsClusterName : clusterName, - // ecsServiceName : frontEndServiceName, - // timeout : 300 - // ) - // } - // } - // } - - // stage("Deploy Admin") { - // steps { - // script { - // deployServiceOnECS ( - // awsRegion : awsRegion, - // imageName : adminImageName, - // ecsClusterName : clusterName, - // ecsServiceName : adminPanelServiceName, - // timeout : 300 - // ) - // } - // } - // } + stage("Deploy Frontend") { + steps { + script { + deployServiceOnECS ( + awsRegion : awsRegion, + imageName : webImageName, + ecsClusterName : clusterName, + ecsServiceName : frontEndServiceName, + timeout : 300 + ) + } + } + } + + stage("Deploy Admin") { + steps { + script { + deployServiceOnECS ( + awsRegion : awsRegion, + imageName : adminImageName, + ecsClusterName : clusterName, + ecsServiceName : adminPanelServiceName, + timeout : 300 + ) + } + } + } stage("Deploy API") { steps { diff --git a/web/Dockerfile.web b/web/Dockerfile.web index d7d924d7a47..2c09674faef 100644 --- a/web/Dockerfile.web +++ b/web/Dockerfile.web @@ -70,7 +70,7 @@ COPY --from=installer /app/web/package.json . # Automatically leverage output traces to reduce image size # https://nextjs.org/docs/advanced-features/output-file-tracing -COPY --from=installer /app/web/.next/standalone ./ +COPY --from=installer /app/web/.next/export ./ COPY --from=installer /app/web/.next ./web/.next COPY --from=installer /app/web/public ./web/public @@ -101,4 +101,7 @@ ENV NEXT_PUBLIC_WEB_BASE_URL=$NEXT_PUBLIC_WEB_BASE_URL ENV NEXT_TELEMETRY_DISABLED 1 ENV TURBO_TELEMETRY_DISABLED 1 + EXPOSE 3000 + +CMD node web/server.js web From 7c5f5eaca744767c29f3873d5bdf0cc6a2576722 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 22:47:06 +0000 Subject: [PATCH 81/83] Testing Multiple Dev --- web/Dockerfile.web | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/Dockerfile.web b/web/Dockerfile.web index 2c09674faef..cc5464c7713 100644 --- a/web/Dockerfile.web +++ b/web/Dockerfile.web @@ -71,7 +71,7 @@ COPY --from=installer /app/web/package.json . # Automatically leverage output traces to reduce image size # https://nextjs.org/docs/advanced-features/output-file-tracing COPY --from=installer /app/web/.next/export ./ -COPY --from=installer /app/web/.next ./web/.next +COPY --from=installer /app/web/.next ./.next COPY --from=installer /app/web/public ./web/public ARG NEXT_PUBLIC_API_BASE_URL="" From 9bec624d65aca536ad9883caa94a476bbbc96a54 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 23:17:12 +0000 Subject: [PATCH 82/83] Testing Multiple Dev --- web/Dockerfile.web | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/Dockerfile.web b/web/Dockerfile.web index cc5464c7713..45b31eda3a1 100644 --- a/web/Dockerfile.web +++ b/web/Dockerfile.web @@ -70,8 +70,8 @@ COPY --from=installer /app/web/package.json . # Automatically leverage output traces to reduce image size # https://nextjs.org/docs/advanced-features/output-file-tracing -COPY --from=installer /app/web/.next/export ./ -COPY --from=installer /app/web/.next ./.next +# COPY --from=installer /app/web/.next/export ./ +# COPY --from=installer /app/web/.next ./.next COPY --from=installer /app/web/public ./web/public ARG NEXT_PUBLIC_API_BASE_URL="" From 2c5c9b779a9c282865a22e9f8efa373f617c1af2 Mon Sep 17 00:00:00 2001 From: abu-siddique-shipsy Date: Thu, 19 Dec 2024 23:52:26 +0000 Subject: [PATCH 83/83] Testing Multiple Dev --- web/Dockerfile.web | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/Dockerfile.web b/web/Dockerfile.web index 45b31eda3a1..8cbfd75a276 100644 --- a/web/Dockerfile.web +++ b/web/Dockerfile.web @@ -70,8 +70,8 @@ COPY --from=installer /app/web/package.json . # Automatically leverage output traces to reduce image size # https://nextjs.org/docs/advanced-features/output-file-tracing -# COPY --from=installer /app/web/.next/export ./ -# COPY --from=installer /app/web/.next ./.next +COPY --from=installer /app/web/.next/standalone ./ +COPY --from=installer /app/web/.next ./.next COPY --from=installer /app/web/public ./web/public ARG NEXT_PUBLIC_API_BASE_URL=""