mirror of
https://github.com/fosrl/pangolin.git
synced 2026-08-23 12:40:25 +02:00
standardize permissions in api
This commit is contained in:
@@ -1401,6 +1401,7 @@
|
|||||||
"actionApplyBlueprint": "Apply Blueprint",
|
"actionApplyBlueprint": "Apply Blueprint",
|
||||||
"actionListBlueprints": "List Blueprints",
|
"actionListBlueprints": "List Blueprints",
|
||||||
"actionGetBlueprint": "Get Blueprint",
|
"actionGetBlueprint": "Get Blueprint",
|
||||||
|
"actionCreateOrgWideLauncherView": "Create Org-Wide Launcher View",
|
||||||
"setupToken": "Setup Token",
|
"setupToken": "Setup Token",
|
||||||
"setupTokenDescription": "Enter the setup token from the server console.",
|
"setupTokenDescription": "Enter the setup token from the server console.",
|
||||||
"setupTokenRequired": "Setup token is required",
|
"setupTokenRequired": "Setup token is required",
|
||||||
|
|||||||
@@ -178,7 +178,8 @@ export enum ActionsEnum {
|
|||||||
setResourcePolicyPincode = "setResourcePolicyPincode",
|
setResourcePolicyPincode = "setResourcePolicyPincode",
|
||||||
setResourcePolicyHeaderAuth = "setResourcePolicyHeaderAuth",
|
setResourcePolicyHeaderAuth = "setResourcePolicyHeaderAuth",
|
||||||
setResourcePolicyWhitelist = "setResourcePolicyWhitelist",
|
setResourcePolicyWhitelist = "setResourcePolicyWhitelist",
|
||||||
setResourcePolicyRules = "setResourcePolicyRules"
|
setResourcePolicyRules = "setResourcePolicyRules",
|
||||||
|
createOrgWideLauncherView = "createOrgWideLauncherView"
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function checkUserActionPermission(
|
export async function checkUserActionPermission(
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import * as apiKeys from "./apiKeys";
|
|||||||
import * as idp from "./idp";
|
import * as idp from "./idp";
|
||||||
import * as logs from "./auditLogs";
|
import * as logs from "./auditLogs";
|
||||||
import * as siteResource from "./siteResource";
|
import * as siteResource from "./siteResource";
|
||||||
import * as launcher from "./launcher";
|
|
||||||
import {
|
import {
|
||||||
verifyApiKey,
|
verifyApiKey,
|
||||||
verifyApiKeyOrgAccess,
|
verifyApiKeyOrgAccess,
|
||||||
@@ -161,41 +160,6 @@ authenticated.get(
|
|||||||
resource.getUserResources
|
resource.getUserResources
|
||||||
);
|
);
|
||||||
|
|
||||||
authenticated.get(
|
|
||||||
"/org/:orgId/launcher/groups",
|
|
||||||
verifyApiKeyOrgAccess,
|
|
||||||
launcher.listLauncherGroups
|
|
||||||
);
|
|
||||||
|
|
||||||
authenticated.get(
|
|
||||||
"/org/:orgId/launcher/resources",
|
|
||||||
verifyApiKeyOrgAccess,
|
|
||||||
launcher.listLauncherResources
|
|
||||||
);
|
|
||||||
|
|
||||||
authenticated.get(
|
|
||||||
"/org/:orgId/launcher/views",
|
|
||||||
verifyApiKeyOrgAccess,
|
|
||||||
launcher.listLauncherViews
|
|
||||||
);
|
|
||||||
|
|
||||||
authenticated.post(
|
|
||||||
"/org/:orgId/launcher/views",
|
|
||||||
verifyApiKeyOrgAccess,
|
|
||||||
launcher.createLauncherView
|
|
||||||
);
|
|
||||||
|
|
||||||
authenticated.put(
|
|
||||||
"/org/:orgId/launcher/views/:viewId",
|
|
||||||
verifyApiKeyOrgAccess,
|
|
||||||
launcher.updateLauncherView
|
|
||||||
);
|
|
||||||
|
|
||||||
authenticated.delete(
|
|
||||||
"/org/:orgId/launcher/views/:viewId",
|
|
||||||
verifyApiKeyOrgAccess,
|
|
||||||
launcher.deleteLauncherView
|
|
||||||
);
|
|
||||||
// Site Resource endpoints
|
// Site Resource endpoints
|
||||||
authenticated.put(
|
authenticated.put(
|
||||||
"/org/:orgId/site-resource",
|
"/org/:orgId/site-resource",
|
||||||
|
|||||||
@@ -1,17 +1,12 @@
|
|||||||
import { db, launcherViews } from "@server/db";
|
import { db, launcherViews } from "@server/db";
|
||||||
import { response } from "@server/lib/response";
|
import { response } from "@server/lib/response";
|
||||||
import { getFirstString } from "@server/lib/requestParams";
|
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
import { and, eq } from "drizzle-orm";
|
|
||||||
import { NextFunction, Request, Response } from "express";
|
import { NextFunction, Request, Response } from "express";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { fromZodError } from "zod-validation-error";
|
import { fromZodError } from "zod-validation-error";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import {
|
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
|
||||||
isOrgAdminOrOwner,
|
|
||||||
verifyLauncherOrgMembership
|
|
||||||
} from "./launcherResourceAccess";
|
|
||||||
import { launcherViewConfigSchema } from "./types";
|
import { launcherViewConfigSchema } from "./types";
|
||||||
|
|
||||||
const createLauncherViewBodySchema = z.strictObject({
|
const createLauncherViewBodySchema = z.strictObject({
|
||||||
@@ -26,14 +21,8 @@ export async function createLauncherView(
|
|||||||
next: NextFunction
|
next: NextFunction
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
try {
|
try {
|
||||||
const orgId = getFirstString(req.params.orgId);
|
const orgId = req.userOrgId;
|
||||||
const userId = req.user?.userId;
|
const userId = req.user!.userId;
|
||||||
|
|
||||||
if (!userId) {
|
|
||||||
return next(
|
|
||||||
createHttpError(HttpCode.UNAUTHORIZED, "User not authenticated")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!orgId) {
|
if (!orgId) {
|
||||||
return next(
|
return next(
|
||||||
@@ -51,22 +40,16 @@ export async function createLauncherView(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { userRoleIds } = await verifyLauncherOrgMembership(
|
|
||||||
orgId,
|
|
||||||
userId
|
|
||||||
);
|
|
||||||
|
|
||||||
if (parsed.data.orgWide) {
|
if (parsed.data.orgWide) {
|
||||||
const canManageOrgWide = await isOrgAdminOrOwner(
|
const canCreateOrgWide = await checkUserActionPermission(
|
||||||
orgId,
|
ActionsEnum.createOrgWideLauncherView,
|
||||||
userId,
|
req
|
||||||
userRoleIds
|
|
||||||
);
|
);
|
||||||
if (!canManageOrgWide) {
|
if (!canCreateOrgWide) {
|
||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
"Only administrators can create org-wide views"
|
"User does not have permission perform this action"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,7 @@ import HttpCode from "@server/types/HttpCode";
|
|||||||
import { and, eq } from "drizzle-orm";
|
import { and, eq } from "drizzle-orm";
|
||||||
import { NextFunction, Request, Response } from "express";
|
import { NextFunction, Request, Response } from "express";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
import {
|
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
|
||||||
isOrgAdminOrOwner,
|
|
||||||
verifyLauncherOrgMembership
|
|
||||||
} from "./launcherResourceAccess";
|
|
||||||
|
|
||||||
export async function deleteLauncherView(
|
export async function deleteLauncherView(
|
||||||
req: Request,
|
req: Request,
|
||||||
@@ -16,18 +13,12 @@ export async function deleteLauncherView(
|
|||||||
next: NextFunction
|
next: NextFunction
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
try {
|
try {
|
||||||
const orgId = getFirstString(req.params.orgId);
|
const orgId = req.userOrgId;
|
||||||
|
const userId = req.user!.userId;
|
||||||
const viewId = Number.parseInt(
|
const viewId = Number.parseInt(
|
||||||
getFirstString(req.params.viewId) ?? "",
|
getFirstString(req.params.viewId) ?? "",
|
||||||
10
|
10
|
||||||
);
|
);
|
||||||
const userId = req.user?.userId;
|
|
||||||
|
|
||||||
if (!userId) {
|
|
||||||
return next(
|
|
||||||
createHttpError(HttpCode.UNAUTHORIZED, "User not authenticated")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!orgId || !Number.isFinite(viewId)) {
|
if (!orgId || !Number.isFinite(viewId)) {
|
||||||
return next(
|
return next(
|
||||||
@@ -38,11 +29,6 @@ export async function deleteLauncherView(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { userRoleIds } = await verifyLauncherOrgMembership(
|
|
||||||
orgId,
|
|
||||||
userId
|
|
||||||
);
|
|
||||||
|
|
||||||
const [existing] = await db
|
const [existing] = await db
|
||||||
.select()
|
.select()
|
||||||
.from(launcherViews)
|
.from(launcherViews)
|
||||||
@@ -62,9 +48,12 @@ export async function deleteLauncherView(
|
|||||||
|
|
||||||
const isPersonalView = existing.userId === userId;
|
const isPersonalView = existing.userId === userId;
|
||||||
const isOrgWideView = existing.userId == null;
|
const isOrgWideView = existing.userId == null;
|
||||||
const isAdmin = await isOrgAdminOrOwner(orgId, userId, userRoleIds);
|
const canManageOrgWide = await checkUserActionPermission(
|
||||||
|
ActionsEnum.createOrgWideLauncherView,
|
||||||
|
req
|
||||||
|
);
|
||||||
|
|
||||||
if (!isPersonalView && !(isOrgWideView && isAdmin)) {
|
if (!isPersonalView && !(isOrgWideView && canManageOrgWide)) {
|
||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import {
|
|||||||
sites,
|
sites,
|
||||||
targets,
|
targets,
|
||||||
userOrgRoles,
|
userOrgRoles,
|
||||||
userOrgs,
|
|
||||||
userPolicies,
|
userPolicies,
|
||||||
userResources,
|
userResources,
|
||||||
userSiteResources
|
userSiteResources
|
||||||
@@ -33,8 +32,6 @@ import {
|
|||||||
or,
|
or,
|
||||||
sql
|
sql
|
||||||
} from "drizzle-orm";
|
} from "drizzle-orm";
|
||||||
import createHttpError from "http-errors";
|
|
||||||
import HttpCode from "@server/types/HttpCode";
|
|
||||||
import {
|
import {
|
||||||
formatPublicResourceAccess,
|
formatPublicResourceAccess,
|
||||||
formatSiteResourceAccess
|
formatSiteResourceAccess
|
||||||
@@ -58,65 +55,6 @@ export type AccessibleIds = {
|
|||||||
siteResourceIds: number[];
|
siteResourceIds: number[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function verifyLauncherOrgMembership(
|
|
||||||
orgId: string,
|
|
||||||
userId: string
|
|
||||||
): Promise<{ userRoleIds: number[] }> {
|
|
||||||
const [userOrg] = await db
|
|
||||||
.select()
|
|
||||||
.from(userOrgs)
|
|
||||||
.where(and(eq(userOrgs.userId, userId), eq(userOrgs.orgId, orgId)))
|
|
||||||
.limit(1);
|
|
||||||
|
|
||||||
if (!userOrg) {
|
|
||||||
throw createHttpError(HttpCode.FORBIDDEN, "User not in organization");
|
|
||||||
}
|
|
||||||
|
|
||||||
const userRoleIds = await db
|
|
||||||
.select({ roleId: userOrgRoles.roleId })
|
|
||||||
.from(userOrgRoles)
|
|
||||||
.where(
|
|
||||||
and(eq(userOrgRoles.userId, userId), eq(userOrgRoles.orgId, orgId))
|
|
||||||
)
|
|
||||||
.then((rows) => rows.map((r) => r.roleId));
|
|
||||||
|
|
||||||
return { userRoleIds };
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function isOrgAdminOrOwner(
|
|
||||||
orgId: string,
|
|
||||||
userId: string,
|
|
||||||
userRoleIds: number[]
|
|
||||||
): Promise<boolean> {
|
|
||||||
const [membership] = await db
|
|
||||||
.select({ isOwner: userOrgs.isOwner })
|
|
||||||
.from(userOrgs)
|
|
||||||
.where(and(eq(userOrgs.userId, userId), eq(userOrgs.orgId, orgId)))
|
|
||||||
.limit(1);
|
|
||||||
|
|
||||||
if (membership?.isOwner) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userRoleIds.length === 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const adminRoles = await db
|
|
||||||
.select({ roleId: roles.roleId })
|
|
||||||
.from(roles)
|
|
||||||
.where(
|
|
||||||
and(
|
|
||||||
eq(roles.orgId, orgId),
|
|
||||||
eq(roles.isAdmin, true),
|
|
||||||
inArray(roles.roleId, userRoleIds)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.limit(1);
|
|
||||||
|
|
||||||
return adminRoles.length > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function resolveAccessibleIds(
|
export async function resolveAccessibleIds(
|
||||||
orgId: string,
|
orgId: string,
|
||||||
userId: string,
|
userId: string,
|
||||||
@@ -826,9 +764,9 @@ async function listLabelGroups(
|
|||||||
export async function listLauncherGroupsForUser(
|
export async function listLauncherGroupsForUser(
|
||||||
orgId: string,
|
orgId: string,
|
||||||
userId: string,
|
userId: string,
|
||||||
|
userRoleIds: number[],
|
||||||
query: LauncherListQuery
|
query: LauncherListQuery
|
||||||
): Promise<{ groups: LauncherGroup[]; total: number }> {
|
): Promise<{ groups: LauncherGroup[]; total: number }> {
|
||||||
const { userRoleIds } = await verifyLauncherOrgMembership(orgId, userId);
|
|
||||||
const accessible = await resolveAccessibleIds(orgId, userId, userRoleIds);
|
const accessible = await resolveAccessibleIds(orgId, userId, userRoleIds);
|
||||||
|
|
||||||
if (query.groupBy === "label") {
|
if (query.groupBy === "label") {
|
||||||
@@ -1077,9 +1015,9 @@ function sortLauncherResources(
|
|||||||
export async function listLauncherResourcesForUser(
|
export async function listLauncherResourcesForUser(
|
||||||
orgId: string,
|
orgId: string,
|
||||||
userId: string,
|
userId: string,
|
||||||
|
userRoleIds: number[],
|
||||||
query: LauncherListQuery & { groupKey: string }
|
query: LauncherListQuery & { groupKey: string }
|
||||||
): Promise<{ resources: LauncherResource[]; total: number }> {
|
): Promise<{ resources: LauncherResource[]; total: number }> {
|
||||||
const { userRoleIds } = await verifyLauncherOrgMembership(orgId, userId);
|
|
||||||
const accessible = await resolveAccessibleIds(orgId, userId, userRoleIds);
|
const accessible = await resolveAccessibleIds(orgId, userId, userRoleIds);
|
||||||
|
|
||||||
const siteFilterIds = parseIdListParam(query.siteIds);
|
const siteFilterIds = parseIdListParam(query.siteIds);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { response } from "@server/lib/response";
|
import { response } from "@server/lib/response";
|
||||||
import { getFirstString } from "@server/lib/requestParams";
|
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
import { NextFunction, Request, Response } from "express";
|
import { NextFunction, Request, Response } from "express";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
@@ -13,14 +12,8 @@ export async function listLauncherGroups(
|
|||||||
next: NextFunction
|
next: NextFunction
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
try {
|
try {
|
||||||
const orgId = getFirstString(req.params.orgId);
|
const orgId = req.userOrgId;
|
||||||
const userId = req.user?.userId;
|
const userId = req.user!.userId;
|
||||||
|
|
||||||
if (!userId) {
|
|
||||||
return next(
|
|
||||||
createHttpError(HttpCode.UNAUTHORIZED, "User not authenticated")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!orgId) {
|
if (!orgId) {
|
||||||
return next(
|
return next(
|
||||||
@@ -41,6 +34,7 @@ export async function listLauncherGroups(
|
|||||||
const { groups, total } = await listLauncherGroupsForUser(
|
const { groups, total } = await listLauncherGroupsForUser(
|
||||||
orgId,
|
orgId,
|
||||||
userId,
|
userId,
|
||||||
|
req.userOrgRoleIds ?? [],
|
||||||
parsed.data
|
parsed.data
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { response } from "@server/lib/response";
|
import { response } from "@server/lib/response";
|
||||||
import { getFirstString } from "@server/lib/requestParams";
|
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
import { NextFunction, Request, Response } from "express";
|
import { NextFunction, Request, Response } from "express";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
@@ -18,14 +17,8 @@ export async function listLauncherResources(
|
|||||||
next: NextFunction
|
next: NextFunction
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
try {
|
try {
|
||||||
const orgId = getFirstString(req.params.orgId);
|
const orgId = req.userOrgId;
|
||||||
const userId = req.user?.userId;
|
const userId = req.user!.userId;
|
||||||
|
|
||||||
if (!userId) {
|
|
||||||
return next(
|
|
||||||
createHttpError(HttpCode.UNAUTHORIZED, "User not authenticated")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!orgId) {
|
if (!orgId) {
|
||||||
return next(
|
return next(
|
||||||
@@ -46,6 +39,7 @@ export async function listLauncherResources(
|
|||||||
const { resources, total } = await listLauncherResourcesForUser(
|
const { resources, total } = await listLauncherResourcesForUser(
|
||||||
orgId,
|
orgId,
|
||||||
userId,
|
userId,
|
||||||
|
req.userOrgRoleIds ?? [],
|
||||||
parsed.data
|
parsed.data
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
import { db, launcherViews } from "@server/db";
|
import { db, launcherViews } from "@server/db";
|
||||||
import { response } from "@server/lib/response";
|
import { response } from "@server/lib/response";
|
||||||
import { getFirstString } from "@server/lib/requestParams";
|
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
import { and, eq, isNull, or } from "drizzle-orm";
|
import { and, eq, isNull, or } from "drizzle-orm";
|
||||||
import { NextFunction, Request, Response } from "express";
|
import { NextFunction, Request, Response } from "express";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
import { launcherViewConfigSchema, type LauncherViewRecord } from "./types";
|
import { launcherViewConfigSchema, type LauncherViewRecord } from "./types";
|
||||||
import { verifyLauncherOrgMembership } from "./launcherResourceAccess";
|
|
||||||
|
|
||||||
function mapViewRow(
|
function mapViewRow(
|
||||||
row: typeof launcherViews.$inferSelect
|
row: typeof launcherViews.$inferSelect
|
||||||
@@ -29,14 +27,8 @@ export async function listLauncherViews(
|
|||||||
next: NextFunction
|
next: NextFunction
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
try {
|
try {
|
||||||
const orgId = getFirstString(req.params.orgId);
|
const orgId = req.userOrgId;
|
||||||
const userId = req.user?.userId;
|
const userId = req.user!.userId;
|
||||||
|
|
||||||
if (!userId) {
|
|
||||||
return next(
|
|
||||||
createHttpError(HttpCode.UNAUTHORIZED, "User not authenticated")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!orgId) {
|
if (!orgId) {
|
||||||
return next(
|
return next(
|
||||||
@@ -44,8 +36,6 @@ export async function listLauncherViews(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await verifyLauncherOrgMembership(orgId, userId);
|
|
||||||
|
|
||||||
const rows = await db
|
const rows = await db
|
||||||
.select()
|
.select()
|
||||||
.from(launcherViews)
|
.from(launcherViews)
|
||||||
|
|||||||
@@ -8,10 +8,7 @@ import createHttpError from "http-errors";
|
|||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { fromZodError } from "zod-validation-error";
|
import { fromZodError } from "zod-validation-error";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import {
|
import { ActionsEnum, checkUserActionPermission } from "@server/auth/actions";
|
||||||
isOrgAdminOrOwner,
|
|
||||||
verifyLauncherOrgMembership
|
|
||||||
} from "./launcherResourceAccess";
|
|
||||||
import { launcherViewConfigSchema } from "./types";
|
import { launcherViewConfigSchema } from "./types";
|
||||||
|
|
||||||
const updateLauncherViewBodySchema = z.strictObject({
|
const updateLauncherViewBodySchema = z.strictObject({
|
||||||
@@ -26,18 +23,12 @@ export async function updateLauncherView(
|
|||||||
next: NextFunction
|
next: NextFunction
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
try {
|
try {
|
||||||
const orgId = getFirstString(req.params.orgId);
|
const orgId = req.userOrgId;
|
||||||
|
const userId = req.user!.userId;
|
||||||
const viewId = Number.parseInt(
|
const viewId = Number.parseInt(
|
||||||
getFirstString(req.params.viewId) ?? "",
|
getFirstString(req.params.viewId) ?? "",
|
||||||
10
|
10
|
||||||
);
|
);
|
||||||
const userId = req.user?.userId;
|
|
||||||
|
|
||||||
if (!userId) {
|
|
||||||
return next(
|
|
||||||
createHttpError(HttpCode.UNAUTHORIZED, "User not authenticated")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!orgId || !Number.isFinite(viewId)) {
|
if (!orgId || !Number.isFinite(viewId)) {
|
||||||
return next(
|
return next(
|
||||||
@@ -58,11 +49,6 @@ export async function updateLauncherView(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { userRoleIds } = await verifyLauncherOrgMembership(
|
|
||||||
orgId,
|
|
||||||
userId
|
|
||||||
);
|
|
||||||
|
|
||||||
const [existing] = await db
|
const [existing] = await db
|
||||||
.select()
|
.select()
|
||||||
.from(launcherViews)
|
.from(launcherViews)
|
||||||
@@ -82,9 +68,12 @@ export async function updateLauncherView(
|
|||||||
|
|
||||||
const isPersonalView = existing.userId === userId;
|
const isPersonalView = existing.userId === userId;
|
||||||
const isOrgWideView = existing.userId == null;
|
const isOrgWideView = existing.userId == null;
|
||||||
const isAdmin = await isOrgAdminOrOwner(orgId, userId, userRoleIds);
|
const canManageOrgWide = await checkUserActionPermission(
|
||||||
|
ActionsEnum.createOrgWideLauncherView,
|
||||||
|
req
|
||||||
|
);
|
||||||
|
|
||||||
if (!isPersonalView && !(isOrgWideView && isAdmin)) {
|
if (!isPersonalView && !(isOrgWideView && canManageOrgWide)) {
|
||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
@@ -93,20 +82,24 @@ export async function updateLauncherView(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parsed.data.orgWide === true && !isAdmin) {
|
if (parsed.data.orgWide === true && !canManageOrgWide) {
|
||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
"Only administrators can make views org-wide"
|
"User does not have permission perform this action"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parsed.data.orgWide === false && isOrgWideView && !isAdmin) {
|
if (
|
||||||
|
parsed.data.orgWide === false &&
|
||||||
|
isOrgWideView &&
|
||||||
|
!canManageOrgWide
|
||||||
|
) {
|
||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.FORBIDDEN,
|
HttpCode.FORBIDDEN,
|
||||||
"Only administrators can change org-wide views"
|
"User does not have permission perform this action"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user