# Third party imports from rest_framework import status from rest_framework.response import Response from sentry_sdk import capture_exception # Module imports from plane.app.views import BaseViewSet, BaseAPIView from plane.db.models import ( GithubIssueSync, GithubRepositorySync, GithubRepository, WorkspaceIntegration, ProjectMember, Label, GithubCommentSync, Project, ) from plane.app.serializers import ( GithubIssueSyncSerializer, GithubRepositorySyncSerializer, GithubCommentSyncSerializer, ) from plane.utils.integrations.github import get_github_repos from plane.app.permissions import ( ProjectBasePermission, ProjectEntityPermission, ) class GithubRepositoriesEndpoint(BaseAPIView): permission_classes = [ ProjectBasePermission, ] def get(self, request, slug, workspace_integration_id): page = request.GET.get("page", 1) workspace_integration = WorkspaceIntegration.objects.get( workspace__slug=slug, pk=workspace_integration_id ) if workspace_integration.integration.provider != "github": return Response( {"error": "Not a github integration"}, status=status.HTTP_400_BAD_REQUEST, ) access_tokens_url = workspace_integration.metadata["access_tokens_url"] repositories_url = ( workspace_integration.metadata["repositories_url"] + f"?per_page=100&page={page}" ) repositories = get_github_repos(access_tokens_url, repositories_url) return Response(repositories, status=status.HTTP_200_OK) class GithubRepositorySyncViewSet(BaseViewSet): permission_classes = [ ProjectBasePermission, ] serializer_class = GithubRepositorySyncSerializer model = GithubRepositorySync def perform_create(self, serializer): serializer.save(project_id=self.kwargs.get("project_id")) def get_queryset(self): return ( super() .get_queryset() .filter(workspace__slug=self.kwargs.get("slug")) .filter(project_id=self.kwargs.get("project_id")) ) def create(self, request, slug, project_id, workspace_integration_id): name = request.data.get("name", False) url = request.data.get("url", False) config = request.data.get("config", {}) repository_id = request.data.get("repository_id", False) owner = request.data.get("owner", False) if not name or not url or not repository_id or not owner: return Response( {"error": "Name, url, repository_id and owner are required"}, status=status.HTTP_400_BAD_REQUEST, ) # Get the workspace integration workspace_integration = WorkspaceIntegration.objects.get( pk=workspace_integration_id ) # Delete the old repository object GithubRepositorySync.objects.filter( project_id=project_id, workspace__slug=slug ).delete() GithubRepository.objects.filter( project_id=project_id, workspace__slug=slug ).delete() # Create repository repo = GithubRepository.objects.create( name=name, url=url, config=config, repository_id=repository_id, owner=owner, project_id=project_id, ) # Create a Label for github label = Label.objects.filter( name="GitHub", project_id=project_id, ).first() if label is None: label = Label.objects.create( name="GitHub", project_id=project_id, description="Label to sync Plane issues with GitHub issues", color="#003773", ) # Create repo sync repo_sync = GithubRepositorySync.objects.create( repository=repo, workspace_integration=workspace_integration, actor=workspace_integration.actor, credentials=request.data.get("credentials", {}), project_id=project_id, label=label, ) # Add bot as a member in the project _ = ProjectMember.objects.get_or_create( member=workspace_integration.actor, role=20, project_id=project_id ) # Return Response return Response( GithubRepositorySyncSerializer(repo_sync).data, status=status.HTTP_201_CREATED, ) class GithubIssueSyncViewSet(BaseViewSet): permission_classes = [ ProjectEntityPermission, ] serializer_class = GithubIssueSyncSerializer model = GithubIssueSync def perform_create(self, serializer): serializer.save( project_id=self.kwargs.get("project_id"), repository_sync_id=self.kwargs.get("repo_sync_id"), ) class BulkCreateGithubIssueSyncEndpoint(BaseAPIView): def post(self, request, slug, project_id, repo_sync_id): project = Project.objects.get(pk=project_id, workspace__slug=slug) github_issue_syncs = request.data.get("github_issue_syncs", []) github_issue_syncs = GithubIssueSync.objects.bulk_create( [ GithubIssueSync( issue_id=github_issue_sync.get("issue"), repo_issue_id=github_issue_sync.get("repo_issue_id"), issue_url=github_issue_sync.get("issue_url"), github_issue_id=github_issue_sync.get("github_issue_id"), repository_sync_id=repo_sync_id, project_id=project_id, workspace_id=project.workspace_id, created_by=request.user, updated_by=request.user, ) for github_issue_sync in github_issue_syncs ], batch_size=100, ignore_conflicts=True, ) serializer = GithubIssueSyncSerializer(github_issue_syncs, many=True) return Response(serializer.data, status=status.HTTP_201_CREATED) class GithubCommentSyncViewSet(BaseViewSet): permission_classes = [ ProjectEntityPermission, ] serializer_class = GithubCommentSyncSerializer model = GithubCommentSync def perform_create(self, serializer): serializer.save( project_id=self.kwargs.get("project_id"), issue_sync_id=self.kwargs.get("issue_sync_id"), )