mirror of
https://github.com/fosrl/pangolin.git
synced 2026-02-08 05:56:38 +00:00
🚧 WIP
This commit is contained in:
@@ -150,7 +150,6 @@
|
||||
"resourceAdd": "Add Resource",
|
||||
"resourceErrorDelte": "Error deleting resource",
|
||||
"authentication": "Authentication",
|
||||
"authPages": "Auth Page",
|
||||
"protected": "Protected",
|
||||
"notProtected": "Not Protected",
|
||||
"resourceMessageRemove": "Once removed, the resource will no longer be accessible. All targets associated with the resource will also be removed.",
|
||||
|
||||
@@ -123,7 +123,9 @@ export enum ActionsEnum {
|
||||
getBlueprint = "getBlueprint",
|
||||
applyBlueprint = "applyBlueprint",
|
||||
viewLogs = "viewLogs",
|
||||
exportLogs = "exportLogs"
|
||||
exportLogs = "exportLogs",
|
||||
updateOrgAuthPage = "updateOrgAuthPage",
|
||||
getOrgAuthPage = "getOrgAuthPage"
|
||||
}
|
||||
|
||||
export async function checkUserActionPermission(
|
||||
|
||||
13
server/lib/createResponseBodySchema.ts
Normal file
13
server/lib/createResponseBodySchema.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import z, { type ZodSchema } from "zod";
|
||||
|
||||
export function createResponseBodySchema<T extends ZodSchema>(dataSchema: T) {
|
||||
return z.object({
|
||||
data: dataSchema.nullable(),
|
||||
success: z.boolean(),
|
||||
error: z.boolean(),
|
||||
message: z.string(),
|
||||
status: z.number()
|
||||
});
|
||||
}
|
||||
|
||||
export default createResponseBodySchema;
|
||||
107
server/private/routers/authPage/getOrgAuthPage.ts
Normal file
107
server/private/routers/authPage/getOrgAuthPage.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import { eq } from "drizzle-orm";
|
||||
/*
|
||||
* This file is part of a proprietary work.
|
||||
*
|
||||
* Copyright (c) 2025 Fossorial, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This file is licensed under the Fossorial Commercial License.
|
||||
* You may not use this file except in compliance with the License.
|
||||
* Unauthorized use, copying, modification, or distribution is strictly prohibited.
|
||||
*
|
||||
* This file is not licensed under the AGPLv3.
|
||||
*/
|
||||
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { z } from "zod";
|
||||
import { db, orgAuthPages } from "@server/db";
|
||||
import { orgs } from "@server/db";
|
||||
import response from "@server/lib/response";
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
import createHttpError from "http-errors";
|
||||
import logger from "@server/logger";
|
||||
import { fromError } from "zod-validation-error";
|
||||
import { OpenAPITags, registry } from "@server/openApi";
|
||||
import createResponseBodySchema from "@server/lib/createResponseBodySchema";
|
||||
|
||||
const getOrgAuthPageParamsSchema = z
|
||||
.object({
|
||||
orgId: z.string()
|
||||
})
|
||||
.strict();
|
||||
|
||||
const reponseSchema = createResponseBodySchema(
|
||||
z
|
||||
.object({
|
||||
logoUrl: z.string().url(),
|
||||
logoWidth: z.number().min(1),
|
||||
logoHeight: z.number().min(1),
|
||||
title: z.string(),
|
||||
subtitle: z.string().optional(),
|
||||
resourceTitle: z.string(),
|
||||
resourceSubtitle: z.string().optional()
|
||||
})
|
||||
.strict()
|
||||
);
|
||||
|
||||
export type GetOrgAuthPageResponse = z.infer<typeof reponseSchema>;
|
||||
|
||||
registry.registerPath({
|
||||
method: "get",
|
||||
path: "/org/{orgId}/auth-page",
|
||||
description: "Get an organization auth page",
|
||||
tags: [OpenAPITags.Org],
|
||||
request: {
|
||||
params: getOrgAuthPageParamsSchema
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: "",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: reponseSchema
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export async function getOrgAuthPage(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
): Promise<any> {
|
||||
try {
|
||||
const parsedParams = getOrgAuthPageParamsSchema.safeParse(req.params);
|
||||
if (!parsedParams.success) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
fromError(parsedParams.error).toString()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const { orgId } = parsedParams.data;
|
||||
|
||||
const [orgAuthPage] = await db
|
||||
.select()
|
||||
.from(orgAuthPages)
|
||||
.leftJoin(orgs, eq(orgs.orgId, orgAuthPages.orgId))
|
||||
.where(eq(orgs.orgId, orgId))
|
||||
.limit(1);
|
||||
|
||||
return response(res, {
|
||||
data: orgAuthPage?.orgAuthPages ?? null,
|
||||
success: true,
|
||||
error: false,
|
||||
message: "Organization auth page retrieved successfully",
|
||||
status: HttpCode.OK
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
return next(
|
||||
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
|
||||
);
|
||||
}
|
||||
}
|
||||
15
server/private/routers/authPage/index.ts
Normal file
15
server/private/routers/authPage/index.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* This file is part of a proprietary work.
|
||||
*
|
||||
* Copyright (c) 2025 Fossorial, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This file is licensed under the Fossorial Commercial License.
|
||||
* You may not use this file except in compliance with the License.
|
||||
* Unauthorized use, copying, modification, or distribution is strictly prohibited.
|
||||
*
|
||||
* This file is not licensed under the AGPLv3.
|
||||
*/
|
||||
|
||||
export * from "./updateOrgAuthPage";
|
||||
export * from "./getOrgAuthPage";
|
||||
141
server/private/routers/authPage/updateOrgAuthPage.ts
Normal file
141
server/private/routers/authPage/updateOrgAuthPage.ts
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* This file is part of a proprietary work.
|
||||
*
|
||||
* Copyright (c) 2025 Fossorial, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This file is licensed under the Fossorial Commercial License.
|
||||
* You may not use this file except in compliance with the License.
|
||||
* Unauthorized use, copying, modification, or distribution is strictly prohibited.
|
||||
*
|
||||
* This file is not licensed under the AGPLv3.
|
||||
*/
|
||||
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { z } from "zod";
|
||||
import { db, orgAuthPages } from "@server/db";
|
||||
import response from "@server/lib/response";
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
import createHttpError from "http-errors";
|
||||
import logger from "@server/logger";
|
||||
import { fromError } from "zod-validation-error";
|
||||
import { OpenAPITags, registry } from "@server/openApi";
|
||||
import createResponseBodySchema from "@server/lib/createResponseBodySchema";
|
||||
|
||||
const updateOrgAuthPageParamsSchema = z
|
||||
.object({
|
||||
orgId: z.string()
|
||||
})
|
||||
.strict();
|
||||
|
||||
const updateOrgAuthPageBodySchema = z
|
||||
.object({
|
||||
logoUrl: z.string().url(),
|
||||
logoWidth: z.number().min(1),
|
||||
logoHeight: z.number().min(1),
|
||||
title: z.string(),
|
||||
subtitle: z.string().optional(),
|
||||
resourceTitle: z.string(),
|
||||
resourceSubtitle: z.string().optional()
|
||||
})
|
||||
.strict();
|
||||
|
||||
const reponseSchema = createResponseBodySchema(updateOrgAuthPageBodySchema);
|
||||
|
||||
export type UpdateOrgAuthPageResponse = z.infer<typeof reponseSchema>;
|
||||
|
||||
registry.registerPath({
|
||||
method: "put",
|
||||
path: "/org/{orgId}/auth-page",
|
||||
description: "Update an organization auth page",
|
||||
tags: [OpenAPITags.Org],
|
||||
request: {
|
||||
params: updateOrgAuthPageParamsSchema,
|
||||
body: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: updateOrgAuthPageBodySchema
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: "",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: reponseSchema
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export async function updateOrgAuthPage(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
): Promise<any> {
|
||||
try {
|
||||
const parsedParams = updateOrgAuthPageParamsSchema.safeParse(
|
||||
req.params
|
||||
);
|
||||
if (!parsedParams.success) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
fromError(parsedParams.error).toString()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const parsedBody = updateOrgAuthPageBodySchema.safeParse(req.body);
|
||||
if (!parsedBody.success) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
fromError(parsedBody.error).toString()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const { orgId } = parsedParams.data;
|
||||
const body = parsedBody.data;
|
||||
|
||||
const updatedOrgAuthPages = await db
|
||||
.insert(orgAuthPages)
|
||||
.values({
|
||||
...body,
|
||||
orgId
|
||||
})
|
||||
.onConflictDoUpdate({
|
||||
target: orgAuthPages.orgId,
|
||||
set: {
|
||||
...body
|
||||
}
|
||||
})
|
||||
.returning();
|
||||
|
||||
if (updatedOrgAuthPages.length === 0) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.NOT_FOUND,
|
||||
`Organization with ID ${orgId} not found`
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return response(res, {
|
||||
data: updatedOrgAuthPages[0],
|
||||
success: true,
|
||||
error: false,
|
||||
message: "Organization auth page updated successfully",
|
||||
status: HttpCode.OK
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
return next(
|
||||
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import * as billing from "#private/routers/billing";
|
||||
import * as remoteExitNode from "#private/routers/remoteExitNode";
|
||||
import * as loginPage from "#private/routers/loginPage";
|
||||
import * as orgIdp from "#private/routers/orgIdp";
|
||||
import * as authPage from "#private/routers/authPage";
|
||||
import * as domain from "#private/routers/domain";
|
||||
import * as auth from "#private/routers/auth";
|
||||
import * as license from "#private/routers/license";
|
||||
@@ -403,3 +404,23 @@ authenticated.get(
|
||||
logActionAudit(ActionsEnum.exportLogs),
|
||||
logs.exportAccessAuditLogs
|
||||
);
|
||||
|
||||
authenticated.put(
|
||||
"/org/:orgId/auth-page",
|
||||
verifyValidLicense,
|
||||
verifyValidSubscription,
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.updateOrgAuthPage),
|
||||
logActionAudit(ActionsEnum.updateOrgAuthPage),
|
||||
authPage.updateOrgAuthPage
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
"/org/:orgId/auth-page",
|
||||
verifyValidLicense,
|
||||
verifyValidSubscription,
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.getOrgAuthPage),
|
||||
logActionAudit(ActionsEnum.getOrgAuthPage),
|
||||
authPage.getOrgAuthPage
|
||||
);
|
||||
|
||||
@@ -80,7 +80,7 @@ authenticated.post(
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.updateOrg),
|
||||
logActionAudit(ActionsEnum.updateOrg),
|
||||
org.updateOrg,
|
||||
org.updateOrg
|
||||
);
|
||||
|
||||
if (build !== "saas") {
|
||||
@@ -90,7 +90,7 @@ if (build !== "saas") {
|
||||
verifyUserIsOrgOwner,
|
||||
verifyUserHasAction(ActionsEnum.deleteOrg),
|
||||
logActionAudit(ActionsEnum.deleteOrg),
|
||||
org.deleteOrg,
|
||||
org.deleteOrg
|
||||
);
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ authenticated.put(
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.createClient),
|
||||
logActionAudit(ActionsEnum.createClient),
|
||||
client.createClient,
|
||||
client.createClient
|
||||
);
|
||||
|
||||
authenticated.delete(
|
||||
@@ -166,7 +166,7 @@ authenticated.delete(
|
||||
verifyClientAccess,
|
||||
verifyUserHasAction(ActionsEnum.deleteClient),
|
||||
logActionAudit(ActionsEnum.deleteClient),
|
||||
client.deleteClient,
|
||||
client.deleteClient
|
||||
);
|
||||
|
||||
authenticated.post(
|
||||
@@ -175,7 +175,7 @@ authenticated.post(
|
||||
verifyClientAccess, // this will check if the user has access to the client
|
||||
verifyUserHasAction(ActionsEnum.updateClient), // this will check if the user has permission to update the client
|
||||
logActionAudit(ActionsEnum.updateClient),
|
||||
client.updateClient,
|
||||
client.updateClient
|
||||
);
|
||||
|
||||
// authenticated.get(
|
||||
@@ -189,14 +189,14 @@ authenticated.post(
|
||||
verifySiteAccess,
|
||||
verifyUserHasAction(ActionsEnum.updateSite),
|
||||
logActionAudit(ActionsEnum.updateSite),
|
||||
site.updateSite,
|
||||
site.updateSite
|
||||
);
|
||||
authenticated.delete(
|
||||
"/site/:siteId",
|
||||
verifySiteAccess,
|
||||
verifyUserHasAction(ActionsEnum.deleteSite),
|
||||
logActionAudit(ActionsEnum.deleteSite),
|
||||
site.deleteSite,
|
||||
site.deleteSite
|
||||
);
|
||||
|
||||
// TODO: BREAK OUT THESE ACTIONS SO THEY ARE NOT ALL "getSite"
|
||||
@@ -216,13 +216,13 @@ authenticated.post(
|
||||
"/site/:siteId/docker/check",
|
||||
verifySiteAccess,
|
||||
verifyUserHasAction(ActionsEnum.getSite),
|
||||
site.checkDockerSocket,
|
||||
site.checkDockerSocket
|
||||
);
|
||||
authenticated.post(
|
||||
"/site/:siteId/docker/trigger",
|
||||
verifySiteAccess,
|
||||
verifyUserHasAction(ActionsEnum.getSite),
|
||||
site.triggerFetchContainers,
|
||||
site.triggerFetchContainers
|
||||
);
|
||||
authenticated.get(
|
||||
"/site/:siteId/docker/containers",
|
||||
@@ -238,7 +238,7 @@ authenticated.put(
|
||||
verifySiteAccess,
|
||||
verifyUserHasAction(ActionsEnum.createSiteResource),
|
||||
logActionAudit(ActionsEnum.createSiteResource),
|
||||
siteResource.createSiteResource,
|
||||
siteResource.createSiteResource
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
@@ -272,7 +272,7 @@ authenticated.post(
|
||||
verifySiteResourceAccess,
|
||||
verifyUserHasAction(ActionsEnum.updateSiteResource),
|
||||
logActionAudit(ActionsEnum.updateSiteResource),
|
||||
siteResource.updateSiteResource,
|
||||
siteResource.updateSiteResource
|
||||
);
|
||||
|
||||
authenticated.delete(
|
||||
@@ -282,7 +282,7 @@ authenticated.delete(
|
||||
verifySiteResourceAccess,
|
||||
verifyUserHasAction(ActionsEnum.deleteSiteResource),
|
||||
logActionAudit(ActionsEnum.deleteSiteResource),
|
||||
siteResource.deleteSiteResource,
|
||||
siteResource.deleteSiteResource
|
||||
);
|
||||
|
||||
authenticated.put(
|
||||
@@ -290,7 +290,7 @@ authenticated.put(
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.createResource),
|
||||
logActionAudit(ActionsEnum.createResource),
|
||||
resource.createResource,
|
||||
resource.createResource
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
@@ -352,7 +352,7 @@ authenticated.delete(
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.removeInvitation),
|
||||
logActionAudit(ActionsEnum.removeInvitation),
|
||||
user.removeInvitation,
|
||||
user.removeInvitation
|
||||
);
|
||||
|
||||
authenticated.post(
|
||||
@@ -360,7 +360,7 @@ authenticated.post(
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.inviteUser),
|
||||
logActionAudit(ActionsEnum.inviteUser),
|
||||
user.inviteUser,
|
||||
user.inviteUser
|
||||
); // maybe make this /invite/create instead
|
||||
|
||||
unauthenticated.post("/invite/accept", user.acceptInvite); // this is supposed to be unauthenticated
|
||||
@@ -396,14 +396,14 @@ authenticated.post(
|
||||
verifyResourceAccess,
|
||||
verifyUserHasAction(ActionsEnum.updateResource),
|
||||
logActionAudit(ActionsEnum.updateResource),
|
||||
resource.updateResource,
|
||||
resource.updateResource
|
||||
);
|
||||
authenticated.delete(
|
||||
"/resource/:resourceId",
|
||||
verifyResourceAccess,
|
||||
verifyUserHasAction(ActionsEnum.deleteResource),
|
||||
logActionAudit(ActionsEnum.deleteResource),
|
||||
resource.deleteResource,
|
||||
resource.deleteResource
|
||||
);
|
||||
|
||||
authenticated.put(
|
||||
@@ -411,7 +411,7 @@ authenticated.put(
|
||||
verifyResourceAccess,
|
||||
verifyUserHasAction(ActionsEnum.createTarget),
|
||||
logActionAudit(ActionsEnum.createTarget),
|
||||
target.createTarget,
|
||||
target.createTarget
|
||||
);
|
||||
authenticated.get(
|
||||
"/resource/:resourceId/targets",
|
||||
@@ -425,7 +425,7 @@ authenticated.put(
|
||||
verifyResourceAccess,
|
||||
verifyUserHasAction(ActionsEnum.createResourceRule),
|
||||
logActionAudit(ActionsEnum.createResourceRule),
|
||||
resource.createResourceRule,
|
||||
resource.createResourceRule
|
||||
);
|
||||
authenticated.get(
|
||||
"/resource/:resourceId/rules",
|
||||
@@ -438,14 +438,14 @@ authenticated.post(
|
||||
verifyResourceAccess,
|
||||
verifyUserHasAction(ActionsEnum.updateResourceRule),
|
||||
logActionAudit(ActionsEnum.updateResourceRule),
|
||||
resource.updateResourceRule,
|
||||
resource.updateResourceRule
|
||||
);
|
||||
authenticated.delete(
|
||||
"/resource/:resourceId/rule/:ruleId",
|
||||
verifyResourceAccess,
|
||||
verifyUserHasAction(ActionsEnum.deleteResourceRule),
|
||||
logActionAudit(ActionsEnum.deleteResourceRule),
|
||||
resource.deleteResourceRule,
|
||||
resource.deleteResourceRule
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
@@ -459,14 +459,14 @@ authenticated.post(
|
||||
verifyTargetAccess,
|
||||
verifyUserHasAction(ActionsEnum.updateTarget),
|
||||
logActionAudit(ActionsEnum.updateTarget),
|
||||
target.updateTarget,
|
||||
target.updateTarget
|
||||
);
|
||||
authenticated.delete(
|
||||
"/target/:targetId",
|
||||
verifyTargetAccess,
|
||||
verifyUserHasAction(ActionsEnum.deleteTarget),
|
||||
logActionAudit(ActionsEnum.deleteTarget),
|
||||
target.deleteTarget,
|
||||
target.deleteTarget
|
||||
);
|
||||
|
||||
authenticated.put(
|
||||
@@ -474,7 +474,7 @@ authenticated.put(
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.createRole),
|
||||
logActionAudit(ActionsEnum.createRole),
|
||||
role.createRole,
|
||||
role.createRole
|
||||
);
|
||||
authenticated.get(
|
||||
"/org/:orgId/roles",
|
||||
@@ -500,7 +500,7 @@ authenticated.delete(
|
||||
verifyRoleAccess,
|
||||
verifyUserHasAction(ActionsEnum.deleteRole),
|
||||
logActionAudit(ActionsEnum.deleteRole),
|
||||
role.deleteRole,
|
||||
role.deleteRole
|
||||
);
|
||||
authenticated.post(
|
||||
"/role/:roleId/add/:userId",
|
||||
@@ -508,7 +508,7 @@ authenticated.post(
|
||||
verifyUserAccess,
|
||||
verifyUserHasAction(ActionsEnum.addUserRole),
|
||||
logActionAudit(ActionsEnum.addUserRole),
|
||||
user.addUserRole,
|
||||
user.addUserRole
|
||||
);
|
||||
|
||||
authenticated.post(
|
||||
@@ -517,7 +517,7 @@ authenticated.post(
|
||||
verifyRoleAccess,
|
||||
verifyUserHasAction(ActionsEnum.setResourceRoles),
|
||||
logActionAudit(ActionsEnum.setResourceRoles),
|
||||
resource.setResourceRoles,
|
||||
resource.setResourceRoles
|
||||
);
|
||||
|
||||
authenticated.post(
|
||||
@@ -526,7 +526,7 @@ authenticated.post(
|
||||
verifySetResourceUsers,
|
||||
verifyUserHasAction(ActionsEnum.setResourceUsers),
|
||||
logActionAudit(ActionsEnum.setResourceUsers),
|
||||
resource.setResourceUsers,
|
||||
resource.setResourceUsers
|
||||
);
|
||||
|
||||
authenticated.post(
|
||||
@@ -534,7 +534,7 @@ authenticated.post(
|
||||
verifyResourceAccess,
|
||||
verifyUserHasAction(ActionsEnum.setResourcePassword),
|
||||
logActionAudit(ActionsEnum.setResourcePassword),
|
||||
resource.setResourcePassword,
|
||||
resource.setResourcePassword
|
||||
);
|
||||
|
||||
authenticated.post(
|
||||
@@ -542,7 +542,7 @@ authenticated.post(
|
||||
verifyResourceAccess,
|
||||
verifyUserHasAction(ActionsEnum.setResourcePincode),
|
||||
logActionAudit(ActionsEnum.setResourcePincode),
|
||||
resource.setResourcePincode,
|
||||
resource.setResourcePincode
|
||||
);
|
||||
|
||||
authenticated.post(
|
||||
@@ -550,7 +550,7 @@ authenticated.post(
|
||||
verifyResourceAccess,
|
||||
verifyUserHasAction(ActionsEnum.setResourceHeaderAuth),
|
||||
logActionAudit(ActionsEnum.setResourceHeaderAuth),
|
||||
resource.setResourceHeaderAuth,
|
||||
resource.setResourceHeaderAuth
|
||||
);
|
||||
|
||||
authenticated.post(
|
||||
@@ -558,7 +558,7 @@ authenticated.post(
|
||||
verifyResourceAccess,
|
||||
verifyUserHasAction(ActionsEnum.setResourceWhitelist),
|
||||
logActionAudit(ActionsEnum.setResourceWhitelist),
|
||||
resource.setResourceWhitelist,
|
||||
resource.setResourceWhitelist
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
@@ -573,7 +573,7 @@ authenticated.post(
|
||||
verifyResourceAccess,
|
||||
verifyUserHasAction(ActionsEnum.generateAccessToken),
|
||||
logActionAudit(ActionsEnum.generateAccessToken),
|
||||
accessToken.generateAccessToken,
|
||||
accessToken.generateAccessToken
|
||||
);
|
||||
|
||||
authenticated.delete(
|
||||
@@ -581,7 +581,7 @@ authenticated.delete(
|
||||
verifyAccessTokenAccess,
|
||||
verifyUserHasAction(ActionsEnum.deleteAcessToken),
|
||||
logActionAudit(ActionsEnum.deleteAcessToken),
|
||||
accessToken.deleteAccessToken,
|
||||
accessToken.deleteAccessToken
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
@@ -655,7 +655,7 @@ authenticated.put(
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.createOrgUser),
|
||||
logActionAudit(ActionsEnum.createOrgUser),
|
||||
user.createOrgUser,
|
||||
user.createOrgUser
|
||||
);
|
||||
|
||||
authenticated.post(
|
||||
@@ -664,7 +664,7 @@ authenticated.post(
|
||||
verifyUserAccess,
|
||||
verifyUserHasAction(ActionsEnum.updateOrgUser),
|
||||
logActionAudit(ActionsEnum.updateOrgUser),
|
||||
user.updateOrgUser,
|
||||
user.updateOrgUser
|
||||
);
|
||||
|
||||
authenticated.get("/org/:orgId/user/:userId", verifyOrgAccess, user.getOrgUser);
|
||||
@@ -688,7 +688,7 @@ authenticated.delete(
|
||||
verifyUserAccess,
|
||||
verifyUserHasAction(ActionsEnum.removeUser),
|
||||
logActionAudit(ActionsEnum.removeUser),
|
||||
user.removeUserOrg,
|
||||
user.removeUserOrg
|
||||
);
|
||||
|
||||
// authenticated.put(
|
||||
@@ -819,7 +819,7 @@ authenticated.post(
|
||||
verifyApiKeyAccess,
|
||||
verifyUserHasAction(ActionsEnum.setApiKeyActions),
|
||||
logActionAudit(ActionsEnum.setApiKeyActions),
|
||||
apiKeys.setApiKeyActions,
|
||||
apiKeys.setApiKeyActions
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
@@ -835,7 +835,7 @@ authenticated.put(
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.createApiKey),
|
||||
logActionAudit(ActionsEnum.createApiKey),
|
||||
apiKeys.createOrgApiKey,
|
||||
apiKeys.createOrgApiKey
|
||||
);
|
||||
|
||||
authenticated.delete(
|
||||
@@ -844,7 +844,7 @@ authenticated.delete(
|
||||
verifyApiKeyAccess,
|
||||
verifyUserHasAction(ActionsEnum.deleteApiKey),
|
||||
logActionAudit(ActionsEnum.deleteApiKey),
|
||||
apiKeys.deleteOrgApiKey,
|
||||
apiKeys.deleteOrgApiKey
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
@@ -860,7 +860,7 @@ authenticated.put(
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.createOrgDomain),
|
||||
logActionAudit(ActionsEnum.createOrgDomain),
|
||||
domain.createOrgDomain,
|
||||
domain.createOrgDomain
|
||||
);
|
||||
|
||||
authenticated.post(
|
||||
@@ -869,7 +869,7 @@ authenticated.post(
|
||||
verifyDomainAccess,
|
||||
verifyUserHasAction(ActionsEnum.restartOrgDomain),
|
||||
logActionAudit(ActionsEnum.restartOrgDomain),
|
||||
domain.restartOrgDomain,
|
||||
domain.restartOrgDomain
|
||||
);
|
||||
|
||||
authenticated.delete(
|
||||
@@ -878,7 +878,7 @@ authenticated.delete(
|
||||
verifyDomainAccess,
|
||||
verifyUserHasAction(ActionsEnum.deleteOrgDomain),
|
||||
logActionAudit(ActionsEnum.deleteOrgDomain),
|
||||
domain.deleteAccountDomain,
|
||||
domain.deleteAccountDomain
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
@@ -1237,4 +1237,4 @@ authRouter.delete(
|
||||
store: createStore()
|
||||
}),
|
||||
auth.deleteSecurityKey
|
||||
);
|
||||
);
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
import { internal } from "@app/lib/api";
|
||||
import { authCookieHeader } from "@app/lib/api/cookies";
|
||||
import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
|
||||
import { HorizontalTabs } from "@app/components/HorizontalTabs";
|
||||
import { verifySession } from "@app/lib/auth/verifySession";
|
||||
import OrgProvider from "@app/providers/OrgProvider";
|
||||
import OrgUserProvider from "@app/providers/OrgUserProvider";
|
||||
import { GetOrgResponse } from "@server/routers/org";
|
||||
import { GetOrgUserResponse } from "@server/routers/user";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { redirect } from "next/navigation";
|
||||
import { cache } from "react";
|
||||
import { getTranslations } from 'next-intl/server';
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { getCachedOrgUser } from "@app/lib/api/getCachedOrgUser";
|
||||
import { getCachedOrg } from "@app/lib/api/getCachedOrg";
|
||||
|
||||
type BillingSettingsProps = {
|
||||
children: React.ReactNode;
|
||||
@@ -19,12 +14,11 @@ type BillingSettingsProps = {
|
||||
|
||||
export default async function BillingSettingsPage({
|
||||
children,
|
||||
params,
|
||||
params
|
||||
}: BillingSettingsProps) {
|
||||
const { orgId } = await params;
|
||||
|
||||
const getUser = cache(verifySession);
|
||||
const user = await getUser();
|
||||
const user = await verifySession();
|
||||
|
||||
if (!user) {
|
||||
redirect(`/`);
|
||||
@@ -32,13 +26,7 @@ export default async function BillingSettingsPage({
|
||||
|
||||
let orgUser = null;
|
||||
try {
|
||||
const getOrgUser = cache(async () =>
|
||||
internal.get<AxiosResponse<GetOrgUserResponse>>(
|
||||
`/org/${orgId}/user/${user.userId}`,
|
||||
await authCookieHeader(),
|
||||
),
|
||||
);
|
||||
const res = await getOrgUser();
|
||||
const res = await getCachedOrgUser(orgId, user.userId);
|
||||
orgUser = res.data.data;
|
||||
} catch {
|
||||
redirect(`/${orgId}`);
|
||||
@@ -46,13 +34,7 @@ export default async function BillingSettingsPage({
|
||||
|
||||
let org = null;
|
||||
try {
|
||||
const getOrg = cache(async () =>
|
||||
internal.get<AxiosResponse<GetOrgResponse>>(
|
||||
`/org/${orgId}`,
|
||||
await authCookieHeader(),
|
||||
),
|
||||
);
|
||||
const res = await getOrg();
|
||||
const res = await getCachedOrg(orgId);
|
||||
org = res.data.data;
|
||||
} catch {
|
||||
redirect(`/${orgId}`);
|
||||
@@ -65,11 +47,11 @@ export default async function BillingSettingsPage({
|
||||
<OrgProvider org={org}>
|
||||
<OrgUserProvider orgUser={orgUser}>
|
||||
<SettingsSectionTitle
|
||||
title={t('billing')}
|
||||
description={t('orgBillingDescription')}
|
||||
title={t("billing")}
|
||||
description={t("orgBillingDescription")}
|
||||
/>
|
||||
|
||||
{children}
|
||||
{children}
|
||||
</OrgUserProvider>
|
||||
</OrgProvider>
|
||||
</>
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import AuthPageCustomizationForm from "@app/components/AuthPagesCustomizationForm";
|
||||
import { SettingsContainer } from "@app/components/Settings";
|
||||
import { getCachedSubscription } from "@app/lib/api/getCachedSubscription";
|
||||
import { pullEnv } from "@app/lib/pullEnv";
|
||||
import { build } from "@server/build";
|
||||
import { TierId } from "@server/lib/billing/tiers";
|
||||
import type { GetOrgTierResponse } from "@server/routers/billing/types";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export interface AuthPageProps {
|
||||
params: Promise<{ orgId: string }>;
|
||||
@@ -7,6 +13,21 @@ export interface AuthPageProps {
|
||||
|
||||
export default async function AuthPage(props: AuthPageProps) {
|
||||
const orgId = (await props.params).orgId;
|
||||
const env = pullEnv();
|
||||
let subscriptionStatus: GetOrgTierResponse | null = null;
|
||||
try {
|
||||
const subRes = await getCachedSubscription(orgId);
|
||||
subscriptionStatus = subRes.data.data;
|
||||
} catch {}
|
||||
const subscribed =
|
||||
build === "enterprise"
|
||||
? true
|
||||
: subscriptionStatus?.tier === TierId.STANDARD;
|
||||
|
||||
if (!subscribed) {
|
||||
redirect(env.app.dashboardUrl);
|
||||
}
|
||||
|
||||
return (
|
||||
<SettingsContainer>
|
||||
<AuthPageCustomizationForm orgId={orgId} />
|
||||
|
||||
@@ -9,8 +9,14 @@ import { GetOrgResponse } from "@server/routers/org";
|
||||
import { GetOrgUserResponse } from "@server/routers/user";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { redirect } from "next/navigation";
|
||||
import { cache } from "react";
|
||||
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { getCachedOrg } from "@app/lib/api/getCachedOrg";
|
||||
import { getCachedOrgUser } from "@app/lib/api/getCachedOrgUser";
|
||||
import { GetOrgTierResponse } from "@server/routers/billing/types";
|
||||
import { getCachedSubscription } from "@app/lib/api/getCachedSubscription";
|
||||
import { build } from "@server/build";
|
||||
import { TierId } from "@server/lib/billing/tiers";
|
||||
|
||||
type GeneralSettingsProps = {
|
||||
children: React.ReactNode;
|
||||
@@ -23,8 +29,7 @@ export default async function GeneralSettingsPage({
|
||||
}: GeneralSettingsProps) {
|
||||
const { orgId } = await params;
|
||||
|
||||
const getUser = cache(verifySession);
|
||||
const user = await getUser();
|
||||
const user = await verifySession();
|
||||
|
||||
if (!user) {
|
||||
redirect(`/`);
|
||||
@@ -32,13 +37,7 @@ export default async function GeneralSettingsPage({
|
||||
|
||||
let orgUser = null;
|
||||
try {
|
||||
const getOrgUser = cache(async () =>
|
||||
internal.get<AxiosResponse<GetOrgUserResponse>>(
|
||||
`/org/${orgId}/user/${user.userId}`,
|
||||
await authCookieHeader()
|
||||
)
|
||||
);
|
||||
const res = await getOrgUser();
|
||||
const res = await getCachedOrgUser(orgId, user.userId);
|
||||
orgUser = res.data.data;
|
||||
} catch {
|
||||
redirect(`/${orgId}`);
|
||||
@@ -46,18 +45,22 @@ export default async function GeneralSettingsPage({
|
||||
|
||||
let org = null;
|
||||
try {
|
||||
const getOrg = cache(async () =>
|
||||
internal.get<AxiosResponse<GetOrgResponse>>(
|
||||
`/org/${orgId}`,
|
||||
await authCookieHeader()
|
||||
)
|
||||
);
|
||||
const res = await getOrg();
|
||||
const res = await getCachedOrg(orgId);
|
||||
org = res.data.data;
|
||||
} catch {
|
||||
redirect(`/${orgId}`);
|
||||
}
|
||||
|
||||
let subscriptionStatus: GetOrgTierResponse | null = null;
|
||||
try {
|
||||
const subRes = await getCachedSubscription(orgId);
|
||||
subscriptionStatus = subRes.data.data;
|
||||
} catch {}
|
||||
const subscribed =
|
||||
build === "enterprise"
|
||||
? true
|
||||
: subscriptionStatus?.tier === TierId.STANDARD;
|
||||
|
||||
const t = await getTranslations();
|
||||
|
||||
const navItems: TabItem[] = [
|
||||
@@ -65,12 +68,14 @@ export default async function GeneralSettingsPage({
|
||||
title: t("general"),
|
||||
href: `/{orgId}/settings/general`,
|
||||
exact: true
|
||||
},
|
||||
{
|
||||
title: t("authPages"),
|
||||
href: `/{orgId}/settings/general/auth-pages`
|
||||
}
|
||||
];
|
||||
if (subscribed) {
|
||||
navItems.push({
|
||||
title: t("authPage"),
|
||||
href: `/{orgId}/settings/general/auth-pages`
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
13
src/lib/api/getCachedOrgUser.ts
Normal file
13
src/lib/api/getCachedOrgUser.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { GetOrgResponse } from "@server/routers/org";
|
||||
import type { AxiosResponse } from "axios";
|
||||
import { cache } from "react";
|
||||
import { authCookieHeader } from "./cookies";
|
||||
import { internal } from ".";
|
||||
import type { GetOrgUserResponse } from "@server/routers/user";
|
||||
|
||||
export const getCachedOrgUser = cache(async (orgId: string, userId: string) =>
|
||||
internal.get<AxiosResponse<GetOrgUserResponse>>(
|
||||
`/org/${orgId}/user/${userId}`,
|
||||
await authCookieHeader()
|
||||
)
|
||||
);
|
||||
8
src/lib/api/getCachedSubscription.ts
Normal file
8
src/lib/api/getCachedSubscription.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import type { AxiosResponse } from "axios";
|
||||
import { cache } from "react";
|
||||
import { priv } from ".";
|
||||
import type { GetOrgTierResponse } from "@server/routers/billing/types";
|
||||
|
||||
export const getCachedSubscription = cache(async (orgId: string) =>
|
||||
priv.get<AxiosResponse<GetOrgTierResponse>>(`/org/${orgId}/billing/tier`)
|
||||
);
|
||||
@@ -60,4 +60,3 @@ export const priv = axios.create({
|
||||
});
|
||||
|
||||
export * from "./formatAxiosError";
|
||||
|
||||
|
||||
@@ -3,9 +3,10 @@ import { authCookieHeader } from "@app/lib/api/cookies";
|
||||
import { GetUserResponse } from "@server/routers/user";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { pullEnv } from "../pullEnv";
|
||||
import { cache } from "react";
|
||||
|
||||
export async function verifySession({
|
||||
skipCheckVerifyEmail,
|
||||
export const verifySession = cache(async function ({
|
||||
skipCheckVerifyEmail
|
||||
}: {
|
||||
skipCheckVerifyEmail?: boolean;
|
||||
} = {}): Promise<GetUserResponse | null> {
|
||||
@@ -14,7 +15,7 @@ export async function verifySession({
|
||||
try {
|
||||
const res = await internal.get<AxiosResponse<GetUserResponse>>(
|
||||
"/user",
|
||||
await authCookieHeader(),
|
||||
await authCookieHeader()
|
||||
);
|
||||
|
||||
const user = res.data.data;
|
||||
@@ -35,4 +36,4 @@ export async function verifySession({
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user