Merge branch 'main' of https://github.com/fosrl/pangolin
This commit is contained in:
commit
b67e03677c
19 changed files with 49 additions and 49 deletions
|
@ -14,24 +14,26 @@ async function insertDummyData() {
|
||||||
const org1 = db
|
const org1 = db
|
||||||
.insert(orgs)
|
.insert(orgs)
|
||||||
.values({
|
.values({
|
||||||
|
orgId: "default",
|
||||||
name: "Default",
|
name: "Default",
|
||||||
domain: "fosrl.io",
|
domain: "fosrl.io",
|
||||||
})
|
})
|
||||||
.returning()
|
.returning()
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
await createSuperuserRole(org1.orgId);
|
await createSuperuserRole(org1.orgId!);
|
||||||
|
|
||||||
const org2 = db
|
const org2 = db
|
||||||
.insert(orgs)
|
.insert(orgs)
|
||||||
.values({
|
.values({
|
||||||
|
orgId: "fossorial",
|
||||||
name: "Fossorial",
|
name: "Fossorial",
|
||||||
domain: "fossorial.io",
|
domain: "fossorial.io",
|
||||||
})
|
})
|
||||||
.returning()
|
.returning()
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
await createSuperuserRole(org2.orgId);
|
await createSuperuserRole(org2.orgId!);
|
||||||
|
|
||||||
// Insert dummy exit nodes
|
// Insert dummy exit nodes
|
||||||
const exitNode1 = db
|
const exitNode1 = db
|
||||||
|
|
|
@ -5,7 +5,7 @@ import createHttpError from 'http-errors';
|
||||||
import HttpCode from '@server/types/HttpCode';
|
import HttpCode from '@server/types/HttpCode';
|
||||||
|
|
||||||
interface CheckLimitOptions {
|
interface CheckLimitOptions {
|
||||||
orgId: number;
|
orgId: string;
|
||||||
limitName: string;
|
limitName: string;
|
||||||
currentValue: number;
|
currentValue: number;
|
||||||
increment?: number;
|
increment?: number;
|
||||||
|
|
|
@ -39,7 +39,7 @@ export async function ensureActions() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createSuperuserRole(orgId: number) {
|
export async function createSuperuserRole(orgId: string) {
|
||||||
// Create the Default role if it doesn't exist
|
// Create the Default role if it doesn't exist
|
||||||
const [insertedRole] = await db
|
const [insertedRole] = await db
|
||||||
.insert(roles)
|
.insert(roles)
|
||||||
|
|
|
@ -2,14 +2,14 @@ import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
|
||||||
import { InferSelectModel } from "drizzle-orm";
|
import { InferSelectModel } from "drizzle-orm";
|
||||||
|
|
||||||
export const orgs = sqliteTable("orgs", {
|
export const orgs = sqliteTable("orgs", {
|
||||||
orgId: integer("orgId").primaryKey({ autoIncrement: true }),
|
orgId: text("orgId").primaryKey(),
|
||||||
name: text("name").notNull(),
|
name: text("name").notNull(),
|
||||||
domain: text("domain").notNull(),
|
domain: text("domain").notNull(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const sites = sqliteTable("sites", {
|
export const sites = sqliteTable("sites", {
|
||||||
siteId: integer("siteId").primaryKey({ autoIncrement: true }),
|
siteId: integer("siteId").primaryKey({ autoIncrement: true }),
|
||||||
orgId: integer("orgId").references(() => orgs.orgId, {
|
orgId: text("orgId").references(() => orgs.orgId, {
|
||||||
onDelete: "cascade",
|
onDelete: "cascade",
|
||||||
}),
|
}),
|
||||||
exitNode: integer("exitNode").references(() => exitNodes.exitNodeId, {
|
exitNode: integer("exitNode").references(() => exitNodes.exitNodeId, {
|
||||||
|
@ -28,7 +28,7 @@ export const resources = sqliteTable("resources", {
|
||||||
siteId: integer("siteId").references(() => sites.siteId, {
|
siteId: integer("siteId").references(() => sites.siteId, {
|
||||||
onDelete: "cascade",
|
onDelete: "cascade",
|
||||||
}),
|
}),
|
||||||
orgId: integer("orgId").references(() => orgs.orgId, {
|
orgId: text("orgId").references(() => orgs.orgId, {
|
||||||
onDelete: "cascade",
|
onDelete: "cascade",
|
||||||
}),
|
}),
|
||||||
name: text("name").notNull(),
|
name: text("name").notNull(),
|
||||||
|
@ -97,7 +97,7 @@ export const userOrgs = sqliteTable("userOrgs", {
|
||||||
userId: text("userId")
|
userId: text("userId")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => users.userId),
|
.references(() => users.userId),
|
||||||
orgId: integer("orgId")
|
orgId: text("orgId")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => orgs.orgId),
|
.references(() => orgs.orgId),
|
||||||
roleId: integer("roleId")
|
roleId: integer("roleId")
|
||||||
|
@ -132,7 +132,7 @@ export const actions = sqliteTable("actions", {
|
||||||
|
|
||||||
export const roles = sqliteTable("roles", {
|
export const roles = sqliteTable("roles", {
|
||||||
roleId: integer("roleId").primaryKey({ autoIncrement: true }),
|
roleId: integer("roleId").primaryKey({ autoIncrement: true }),
|
||||||
orgId: integer("orgId").references(() => orgs.orgId, {
|
orgId: text("orgId").references(() => orgs.orgId, {
|
||||||
onDelete: "cascade",
|
onDelete: "cascade",
|
||||||
}),
|
}),
|
||||||
isSuperuserRole: integer("isSuperuserRole", { mode: "boolean" }),
|
isSuperuserRole: integer("isSuperuserRole", { mode: "boolean" }),
|
||||||
|
@ -147,7 +147,7 @@ export const roleActions = sqliteTable("roleActions", {
|
||||||
actionId: text("actionId")
|
actionId: text("actionId")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => actions.actionId, { onDelete: "cascade" }),
|
.references(() => actions.actionId, { onDelete: "cascade" }),
|
||||||
orgId: integer("orgId")
|
orgId: text("orgId")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => orgs.orgId, { onDelete: "cascade" }),
|
.references(() => orgs.orgId, { onDelete: "cascade" }),
|
||||||
});
|
});
|
||||||
|
@ -159,7 +159,7 @@ export const userActions = sqliteTable("userActions", {
|
||||||
actionId: text("actionId")
|
actionId: text("actionId")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => actions.actionId, { onDelete: "cascade" }),
|
.references(() => actions.actionId, { onDelete: "cascade" }),
|
||||||
orgId: integer("orgId")
|
orgId: text("orgId")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => orgs.orgId, { onDelete: "cascade" }),
|
.references(() => orgs.orgId, { onDelete: "cascade" }),
|
||||||
});
|
});
|
||||||
|
@ -202,7 +202,7 @@ export const userResources = sqliteTable("userResources", {
|
||||||
|
|
||||||
export const limitsTable = sqliteTable("limits", {
|
export const limitsTable = sqliteTable("limits", {
|
||||||
limitId: integer("limitId").primaryKey({ autoIncrement: true }),
|
limitId: integer("limitId").primaryKey({ autoIncrement: true }),
|
||||||
orgId: integer("orgId").references(() => orgs.orgId, {
|
orgId: text("orgId").references(() => orgs.orgId, {
|
||||||
onDelete: "cascade",
|
onDelete: "cascade",
|
||||||
}),
|
}),
|
||||||
name: text("name").notNull(),
|
name: text("name").notNull(),
|
||||||
|
|
|
@ -91,8 +91,8 @@ declare global {
|
||||||
interface Request {
|
interface Request {
|
||||||
user?: User;
|
user?: User;
|
||||||
userOrgRoleId?: number;
|
userOrgRoleId?: number;
|
||||||
userOrgId?: number;
|
userOrgId?: string;
|
||||||
userOrgIds?: number[];
|
userOrgIds?: string[];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,13 +8,13 @@ import { AuthenticatedRequest } from '@server/types/Auth';
|
||||||
|
|
||||||
export function verifyOrgAccess(req: Request, res: Response, next: NextFunction) {
|
export function verifyOrgAccess(req: Request, res: Response, next: NextFunction) {
|
||||||
const userId = req.user!.userId; // Assuming you have user information in the request
|
const userId = req.user!.userId; // Assuming you have user information in the request
|
||||||
const orgId = parseInt(req.params.orgId);
|
const orgId = req.params.orgId;
|
||||||
|
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
return next(createHttpError(HttpCode.UNAUTHORIZED, 'User not authenticated'));
|
return next(createHttpError(HttpCode.UNAUTHORIZED, 'User not authenticated'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNaN(orgId)) {
|
if (!orgId) {
|
||||||
return next(createHttpError(HttpCode.BAD_REQUEST, 'Invalid organization ID'));
|
return next(createHttpError(HttpCode.BAD_REQUEST, 'Invalid organization ID'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
|
||||||
import logger from '@server/logger';
|
import logger from '@server/logger';
|
||||||
|
|
||||||
const deleteOrgSchema = z.object({
|
const deleteOrgSchema = z.object({
|
||||||
orgId: z.string().transform(Number).pipe(z.number().int().positive())
|
orgId: z.string()
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function deleteOrg(req: Request, res: Response, next: NextFunction): Promise<any> {
|
export async function deleteOrg(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
|
||||||
import logger from '@server/logger';
|
import logger from '@server/logger';
|
||||||
|
|
||||||
const getOrgSchema = z.object({
|
const getOrgSchema = z.object({
|
||||||
orgId: z.string().transform(Number).pipe(z.number().int().positive())
|
orgId: z.string()
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function getOrg(req: Request, res: Response, next: NextFunction): Promise<any> {
|
export async function getOrg(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { ActionsEnum, checkUserActionPermission } from '@server/auth/actions';
|
||||||
import logger from '@server/logger';
|
import logger from '@server/logger';
|
||||||
|
|
||||||
const updateOrgParamsSchema = z.object({
|
const updateOrgParamsSchema = z.object({
|
||||||
orgId: z.string().transform(Number).pipe(z.number().int().positive())
|
orgId: z.string()
|
||||||
});
|
});
|
||||||
|
|
||||||
const updateOrgBodySchema = z.object({
|
const updateOrgBodySchema = z.object({
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { eq, and } from 'drizzle-orm';
|
||||||
|
|
||||||
const createResourceParamsSchema = z.object({
|
const createResourceParamsSchema = z.object({
|
||||||
siteId: z.number().int().positive(),
|
siteId: z.number().int().positive(),
|
||||||
orgId: z.string().transform(Number).pipe(z.number().int().positive())
|
orgId: z.string()
|
||||||
});
|
});
|
||||||
|
|
||||||
// Define Zod schema for request body validation
|
// Define Zod schema for request body validation
|
||||||
|
|
|
@ -13,7 +13,7 @@ import { eq, and } from 'drizzle-orm';
|
||||||
const API_BASE_URL = "http://localhost:3000";
|
const API_BASE_URL = "http://localhost:3000";
|
||||||
|
|
||||||
const createSiteParamsSchema = z.object({
|
const createSiteParamsSchema = z.object({
|
||||||
orgId: z.string().transform(Number).pipe(z.number().int().positive())
|
orgId: z.string()
|
||||||
});
|
});
|
||||||
|
|
||||||
// Define Zod schema for request body validation
|
// Define Zod schema for request body validation
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { eq } from 'drizzle-orm';
|
||||||
const addUserActionSchema = z.object({
|
const addUserActionSchema = z.object({
|
||||||
userId: z.string(),
|
userId: z.string(),
|
||||||
actionId: z.string(),
|
actionId: z.string(),
|
||||||
orgId: z.string().transform(Number).pipe(z.number().int().positive()),
|
orgId: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function addUserAction(req: Request, res: Response, next: NextFunction): Promise<any> {
|
export async function addUserAction(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import logger from '@server/logger';
|
||||||
|
|
||||||
const addUserParamsSchema = z.object({
|
const addUserParamsSchema = z.object({
|
||||||
userId: z.string().uuid(),
|
userId: z.string().uuid(),
|
||||||
orgId: z.string().transform(Number).pipe(z.number().int().positive())
|
orgId: z.string()
|
||||||
});
|
});
|
||||||
|
|
||||||
const addUserSchema = z.object({
|
const addUserSchema = z.object({
|
||||||
|
|
|
@ -15,7 +15,7 @@ const removeUserActionParamsSchema = z.object({
|
||||||
|
|
||||||
const removeUserActionSchema = z.object({
|
const removeUserActionSchema = z.object({
|
||||||
actionId: z.string(),
|
actionId: z.string(),
|
||||||
orgId: z.string().transform(Number).pipe(z.number().int().positive())
|
orgId: z.string()
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function removeUserAction(req: Request, res: Response, next: NextFunction): Promise<any> {
|
export async function removeUserAction(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import logger from '@server/logger';
|
||||||
|
|
||||||
const removeUserSchema = z.object({
|
const removeUserSchema = z.object({
|
||||||
userId: z.string().uuid(),
|
userId: z.string().uuid(),
|
||||||
orgId: z.string().transform(Number).pipe(z.number().int().positive())
|
orgId: z.string()
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function removeUserOrg(req: Request, res: Response, next: NextFunction): Promise<any> {
|
export async function removeUserOrg(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
|
|
|
@ -12,7 +12,7 @@ import logger from '@server/logger';
|
||||||
const addUserRoleSchema = z.object({
|
const addUserRoleSchema = z.object({
|
||||||
userId: z.string(),
|
userId: z.string(),
|
||||||
roleId: z.number().int().positive(),
|
roleId: z.number().int().positive(),
|
||||||
orgId: z.string().transform(Number).pipe(z.number().int().positive())
|
orgId: z.string()
|
||||||
});
|
});
|
||||||
|
|
||||||
export async function addUserRole(req: Request, res: Response, next: NextFunction): Promise<any> {
|
export async function addUserRole(req: Request, res: Response, next: NextFunction): Promise<any> {
|
||||||
|
|
10
src/api/cookies.ts
Normal file
10
src/api/cookies.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import { cookies } from "next/headers";
|
||||||
|
|
||||||
|
export function authCookieHeader() {
|
||||||
|
const sessionId = cookies().get("session")?.value ?? null;
|
||||||
|
return {
|
||||||
|
headers: {
|
||||||
|
Cookie: `session=${sessionId}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,9 +5,10 @@ import { Separator } from "@/components/ui/separator"
|
||||||
import { SidebarNav } from "@/components/sidebar-nav"
|
import { SidebarNav } from "@/components/sidebar-nav"
|
||||||
import SiteProvider from "@app/providers/SiteProvider"
|
import SiteProvider from "@app/providers/SiteProvider"
|
||||||
import { internal } from "@app/api"
|
import { internal } from "@app/api"
|
||||||
import { cookies } from "next/headers"
|
|
||||||
import { GetSiteResponse } from "@server/routers/site"
|
import { GetSiteResponse } from "@server/routers/site"
|
||||||
import { AxiosResponse } from "axios"
|
import { AxiosResponse } from "axios"
|
||||||
|
import { redirect } from "next/navigation"
|
||||||
|
import { authCookieHeader } from "@app/api/cookies"
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Forms",
|
title: "Forms",
|
||||||
|
@ -42,17 +43,10 @@ export default async function SettingsLayout({ children, params }: SettingsLayou
|
||||||
let site = null;
|
let site = null;
|
||||||
if (params.siteId !== "create") {
|
if (params.siteId !== "create") {
|
||||||
try {
|
try {
|
||||||
const sessionId = cookies().get("session")?.value ?? null;
|
const res = await internal.get<AxiosResponse<GetSiteResponse>>(`/site/${params.siteId}`, authCookieHeader());
|
||||||
const res = await internal
|
|
||||||
.get<AxiosResponse<GetSiteResponse>>(`/site/${params.siteId}`, {
|
|
||||||
headers: {
|
|
||||||
Cookie: `session=${sessionId}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
site = res.data.data;
|
site = res.data.data;
|
||||||
} catch {
|
} catch {
|
||||||
return null;
|
redirect(`/${params.orgId}/sites`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +72,7 @@ export default async function SettingsLayout({ children, params }: SettingsLayou
|
||||||
<div className="space-y-0.5">
|
<div className="space-y-0.5">
|
||||||
<h2 className="text-2xl font-bold tracking-tight">Settings</h2>
|
<h2 className="text-2xl font-bold tracking-tight">Settings</h2>
|
||||||
<p className="text-muted-foreground">
|
<p className="text-muted-foreground">
|
||||||
{ params.siteId == "create" ? "Create site..." : "Manage settings on " + site?.name || ""}.
|
{params.siteId == "create" ? "Create site..." : "Manage settings on " + site?.name || ""}.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<Separator className="my-6" />
|
<Separator className="my-6" />
|
||||||
|
@ -87,10 +81,10 @@ export default async function SettingsLayout({ children, params }: SettingsLayou
|
||||||
<SidebarNav items={sidebarNavItems} disabled={params.siteId == "create"} />
|
<SidebarNav items={sidebarNavItems} disabled={params.siteId == "create"} />
|
||||||
</aside>
|
</aside>
|
||||||
<div className="flex-1 lg:max-w-2xl">
|
<div className="flex-1 lg:max-w-2xl">
|
||||||
<SiteProvider site={site}>
|
<SiteProvider site={site}>
|
||||||
{children}
|
{children}
|
||||||
</SiteProvider>
|
</SiteProvider>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { internal } from "@app/api";
|
import { internal } from "@app/api";
|
||||||
|
import { authCookieHeader } from "@app/api/cookies";
|
||||||
import { GetUserResponse } from "@server/routers/user";
|
import { GetUserResponse } from "@server/routers/user";
|
||||||
import { AxiosResponse } from "axios";
|
import { AxiosResponse } from "axios";
|
||||||
import { cookies } from "next/headers";
|
import { cookies } from "next/headers";
|
||||||
|
@ -7,14 +8,7 @@ export async function verifySession(): Promise<GetUserResponse | null> {
|
||||||
const sessionId = cookies().get("session")?.value ?? null;
|
const sessionId = cookies().get("session")?.value ?? null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await internal.get<AxiosResponse<GetUserResponse>>(
|
const res = await internal.get<AxiosResponse<GetUserResponse>>("/user", authCookieHeader());
|
||||||
"/user",
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
Cookie: `session=${sessionId}`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
return res.data.data;
|
return res.data.data;
|
||||||
} catch {
|
} catch {
|
||||||
|
|
Loading…
Add table
Reference in a new issue