mirror of
https://github.com/makeplane/plane.git
synced 2026-02-25 04:35:21 +01:00
chore: Updated meta information and updated the ssr for intake in space (#1873)
This commit is contained in:
@@ -2,9 +2,17 @@
|
||||
from django.urls import path
|
||||
|
||||
# Module imports
|
||||
from plane.ee.views import IntakePublishedIssueEndpoint
|
||||
from plane.ee.views import (
|
||||
IntakePublishedIssueEndpoint,
|
||||
IntakeMetaPublishedIssueEndpoint,
|
||||
)
|
||||
|
||||
urlpatterns = [
|
||||
path(
|
||||
"anchor/<str:anchor>/intake/meta/",
|
||||
IntakeMetaPublishedIssueEndpoint.as_view(),
|
||||
name="intake-public-meta",
|
||||
),
|
||||
path(
|
||||
"anchor/<str:anchor>/intake/",
|
||||
IntakePublishedIssueEndpoint.as_view(),
|
||||
|
||||
@@ -52,4 +52,7 @@ from plane.ee.views.space.views import (
|
||||
IssueViewsPublicEndpoint,
|
||||
ViewsMetaDataEndpoint,
|
||||
)
|
||||
from plane.ee.views.space.intake import IntakePublishedIssueEndpoint
|
||||
from plane.ee.views.space.intake import (
|
||||
IntakePublishedIssueEndpoint,
|
||||
IntakeMetaPublishedIssueEndpoint,
|
||||
)
|
||||
|
||||
@@ -15,9 +15,8 @@ from plane.db.models import DeployBoard, Intake, IntakeIssue, Project, APIToken
|
||||
from plane.payment.flags.flag import FeatureFlag
|
||||
from plane.payment.flags.flag_decorator import check_workspace_feature_flag
|
||||
from plane.payment.flags.flag_decorator import ErrorCodes
|
||||
from plane.ee.serializers import (
|
||||
IssueCreateSerializer,
|
||||
)
|
||||
from plane.ee.serializers import IssueCreateSerializer
|
||||
from plane.space.serializer.project import ProjectLiteSerializer
|
||||
from plane.bgtasks.issue_activities_task import issue_activity
|
||||
|
||||
## Enterprise imports
|
||||
@@ -25,36 +24,62 @@ from plane.ee.views.base import BaseAPIView
|
||||
from plane.ee.models import IntakeSetting
|
||||
|
||||
|
||||
class IntakeMetaPublishedIssueEndpoint(BaseAPIView):
|
||||
permission_classes = [AllowAny]
|
||||
|
||||
def get(self, request, anchor):
|
||||
try:
|
||||
deploy_board = DeployBoard.objects.get(anchor=anchor, entity_name="intake")
|
||||
except DeployBoard.DoesNotExist:
|
||||
return Response(
|
||||
{"error": "Intake is not published"}, status=status.HTTP_404_NOT_FOUND
|
||||
)
|
||||
|
||||
if check_workspace_feature_flag(
|
||||
feature_key=FeatureFlag.INTAKE_PUBLISH, slug=deploy_board.workspace.slug
|
||||
):
|
||||
try:
|
||||
project_id = deploy_board.project_id
|
||||
project = Project.objects.get(id=project_id)
|
||||
except Project.DoesNotExist:
|
||||
return Response(
|
||||
{"error": "Intake is not published"},
|
||||
status=status.HTTP_404_NOT_FOUND,
|
||||
)
|
||||
|
||||
serializer = ProjectLiteSerializer(project)
|
||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||
else:
|
||||
return Response(
|
||||
{
|
||||
"error": "Payment required",
|
||||
"error_code": ErrorCodes.PAYMENT_REQUIRED.value,
|
||||
},
|
||||
status=status.HTTP_402_PAYMENT_REQUIRED,
|
||||
)
|
||||
|
||||
|
||||
class IntakePublishedIssueEndpoint(BaseAPIView):
|
||||
permission_classes = [
|
||||
AllowAny,
|
||||
]
|
||||
permission_classes = [AllowAny]
|
||||
|
||||
def post(self, request, anchor):
|
||||
# Get the deploy board object
|
||||
deploy_board = DeployBoard.objects.get(
|
||||
anchor=anchor, entity_name="intake"
|
||||
)
|
||||
deploy_board = DeployBoard.objects.get(anchor=anchor, entity_name="intake")
|
||||
project = Project.objects.get(
|
||||
workspace_id=deploy_board.workspace_id,
|
||||
pk=deploy_board.project_id,
|
||||
workspace_id=deploy_board.workspace_id, pk=deploy_board.project_id
|
||||
)
|
||||
intake_settings = IntakeSetting.objects.filter(
|
||||
workspace_id=deploy_board.workspace_id,
|
||||
project_id=deploy_board.project_id,
|
||||
workspace_id=deploy_board.workspace_id, project_id=deploy_board.project_id
|
||||
).first()
|
||||
if not intake_settings.is_form_enabled or not project.intake_view:
|
||||
return Response(
|
||||
{
|
||||
"error": "The current published url is disabled",
|
||||
},
|
||||
{"error": "The current published url is disabled"},
|
||||
status=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
|
||||
# Check if the workspace has access to feature
|
||||
if check_workspace_feature_flag(
|
||||
feature_key=FeatureFlag.INTAKE_PUBLISH,
|
||||
slug=deploy_board.workspace.slug,
|
||||
feature_key=FeatureFlag.INTAKE_PUBLISH, slug=deploy_board.workspace.slug
|
||||
):
|
||||
intake = Intake.objects.filter(
|
||||
workspace_id=deploy_board.workspace_id,
|
||||
@@ -63,10 +88,7 @@ class IntakePublishedIssueEndpoint(BaseAPIView):
|
||||
|
||||
if request.data.get("name") is None:
|
||||
return Response(
|
||||
{
|
||||
"error": "Name is required",
|
||||
},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
{"error": "Name is required"}, status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
api_token = APIToken.objects.filter(
|
||||
@@ -99,16 +121,12 @@ class IntakePublishedIssueEndpoint(BaseAPIView):
|
||||
issue_id=serializer.data["id"],
|
||||
source=request.data.get("source", "FORMS"),
|
||||
source_email=request.data.get("email", None),
|
||||
extra={
|
||||
"username": request.data.get("username", None),
|
||||
},
|
||||
extra={"username": request.data.get("username", None)},
|
||||
)
|
||||
# Create an Issue Activity
|
||||
issue_activity.delay(
|
||||
type="issue.activity.created",
|
||||
requested_data=json.dumps(
|
||||
request.data, cls=DjangoJSONEncoder
|
||||
),
|
||||
requested_data=json.dumps(request.data, cls=DjangoJSONEncoder),
|
||||
actor_id=str(api_token.user_id),
|
||||
issue_id=str(serializer.data["id"]),
|
||||
project_id=str(deploy_board.project_id),
|
||||
@@ -119,9 +137,7 @@ class IntakePublishedIssueEndpoint(BaseAPIView):
|
||||
intake=str(intake_issue.id),
|
||||
)
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
return Response(
|
||||
serializer.errors, status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
else:
|
||||
return Response(
|
||||
{
|
||||
|
||||
43
space/app/intake/[anchor]/client-layout.tsx
Normal file
43
space/app/intake/[anchor]/client-layout.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
"use client";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import useSWR from "swr";
|
||||
// components
|
||||
import { LogoSpinner } from "@/components/common";
|
||||
import { SomethingWentWrongError } from "@/components/issues/issue-layouts/error";
|
||||
// hooks
|
||||
import { usePublish, usePublishList } from "@/hooks/store";
|
||||
|
||||
type Props = {
|
||||
children: React.ReactNode;
|
||||
anchor: string;
|
||||
};
|
||||
|
||||
export const IntakeClientLayout = observer((props: Props) => {
|
||||
const { children, anchor } = props;
|
||||
// store hooks
|
||||
const { fetchPublishSettings } = usePublishList();
|
||||
const publishSettings = usePublish(anchor);
|
||||
|
||||
// fetch publish settings && view details
|
||||
const { error } = useSWR(
|
||||
anchor ? `PUBLISHED_VIEW_SETTINGS_${anchor}` : null,
|
||||
anchor
|
||||
? async () => {
|
||||
const promises = [];
|
||||
promises.push(fetchPublishSettings(anchor));
|
||||
await Promise.all(promises);
|
||||
}
|
||||
: null
|
||||
);
|
||||
|
||||
if (error) return <SomethingWentWrongError />;
|
||||
|
||||
if (!publishSettings) return <LogoSpinner />;
|
||||
|
||||
return (
|
||||
<div className="relative flex h-screen min-h-[500px] w-screen flex-col overflow-hidden">
|
||||
<div className="relative h-full w-full overflow-hidden bg-custom-primary-100/5 flex">{children}</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
@@ -1,12 +1,6 @@
|
||||
"use client";
|
||||
"use server";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import useSWR from "swr";
|
||||
// components
|
||||
import { LogoSpinner } from "@/components/common";
|
||||
import { SomethingWentWrongError } from "@/components/issues/issue-layouts/error";
|
||||
// hooks
|
||||
import { usePublish, usePublishList } from "@/hooks/store";
|
||||
import { IntakeClientLayout } from "./client-layout";
|
||||
|
||||
type Props = {
|
||||
children: React.ReactNode;
|
||||
@@ -15,35 +9,44 @@ type Props = {
|
||||
};
|
||||
};
|
||||
|
||||
const IntakeLayout = observer((props: Props) => {
|
||||
const { children, params } = props;
|
||||
// params
|
||||
export async function generateMetadata({ params }: Props) {
|
||||
const { anchor } = params;
|
||||
// store hooks
|
||||
const { fetchPublishSettings } = usePublishList();
|
||||
const publishSettings = usePublish(anchor);
|
||||
const DEFAULT_TITLE = "Plane";
|
||||
const DEFAULT_DESCRIPTION = "Made with Plane, an AI-powered work management platform with publishing capabilities.";
|
||||
try {
|
||||
const response = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/api/public/anchor/${anchor}/intake/meta/`);
|
||||
const data = await response.json();
|
||||
return {
|
||||
title: `${data?.name} - Intake` || DEFAULT_TITLE,
|
||||
description: DEFAULT_DESCRIPTION,
|
||||
openGraph: {
|
||||
title: `${data?.name} - Intake` || DEFAULT_TITLE,
|
||||
description: DEFAULT_DESCRIPTION,
|
||||
type: "website",
|
||||
images: [
|
||||
{
|
||||
url: data?.cover_image,
|
||||
width: 800,
|
||||
height: 600,
|
||||
alt: data?.name || DEFAULT_TITLE,
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
title: `${data?.name} - Intake` || DEFAULT_TITLE,
|
||||
description: data?.description || DEFAULT_DESCRIPTION,
|
||||
images: [data?.cover_image],
|
||||
},
|
||||
};
|
||||
} catch {
|
||||
return { title: `${DEFAULT_TITLE} - Intake`, description: DEFAULT_DESCRIPTION };
|
||||
}
|
||||
}
|
||||
|
||||
// fetch publish settings && view details
|
||||
const { error } = useSWR(
|
||||
anchor ? `PUBLISHED_VIEW_SETTINGS_${anchor}` : null,
|
||||
anchor
|
||||
? async () => {
|
||||
const promises = [];
|
||||
promises.push(fetchPublishSettings(anchor));
|
||||
await Promise.all(promises);
|
||||
}
|
||||
: null
|
||||
);
|
||||
export default async function IntakeLayout(props: Props) {
|
||||
const { children, params } = props;
|
||||
const { anchor } = params;
|
||||
|
||||
if (error) return <SomethingWentWrongError />;
|
||||
|
||||
if (!publishSettings) return <LogoSpinner />;
|
||||
|
||||
return (
|
||||
<div className="relative flex h-screen min-h-[500px] w-screen flex-col overflow-hidden">
|
||||
<div className="relative h-full w-full overflow-hidden bg-custom-primary-100/5 flex">{children}</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default IntakeLayout;
|
||||
return <IntakeClientLayout anchor={anchor}>{children}</IntakeClientLayout>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user