Skip to content

Commit

Permalink
feat: #1243 add api routes
Browse files Browse the repository at this point in the history
  • Loading branch information
manuel-rw committed Nov 23, 2024
1 parent cdfb61f commit ae661fe
Show file tree
Hide file tree
Showing 19 changed files with 513 additions and 2,485 deletions.
2 changes: 1 addition & 1 deletion apps/nextjs/src/app/api/[...trpc]/route.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { headers } from "next/headers";
import { userAgent } from "next/server";
import type { NextRequest } from "next/server";
import { createOpenApiFetchHandler } from "trpc-swagger/build/index.mjs";
import { createOpenApiFetchHandler } from 'trpc-to-openapi';

import { appRouter, createTRPCContext } from "@homarr/api";
import { hashPasswordAsync } from "@homarr/auth";
Expand Down
5 changes: 0 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,5 @@
"packageManager": "pnpm@9.14.2",
"engines": {
"node": ">=22.11.0"
},
"pnpm": {
"patchedDependencies": {
"trpc-swagger@1.2.6": "patches/trpc-swagger@1.2.6.patch"
}
}
}
2 changes: 1 addition & 1 deletion packages/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"next": "^14.2.18",
"react": "^18.3.1",
"superjson": "2.2.1",
"trpc-swagger": "^1.2.6"
"trpc-to-openapi": "^2.0.2"
},
"devDependencies": {
"@homarr/eslint-config": "workspace:^0.2.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/api/src/open-api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { generateOpenApiDocument } from "trpc-swagger";
import { generateOpenApiDocument } from "trpc-to-openapi";

import { appRouter } from "./root";

Expand Down
38 changes: 9 additions & 29 deletions packages/api/src/router/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,15 @@ import { validation, z } from "@homarr/validation";

import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure, publicProcedure } from "../trpc";
import { canUserSeeAppAsync } from "./app/app-access-control";
import { selectAppSchema } from "@homarr/db/validationSchemas/app";
import { convertIntersectionToZodObject } from "../schema-merger";

export const appRouter = createTRPCRouter({
all: protectedProcedure
.input(z.void())
.output(
z.array(
z.object({
name: z.string(),
id: z.string(),
description: z.string().nullable(),
iconUrl: z.string(),
href: z.string().nullable(),
}),
selectAppSchema
),
)
.meta({ openapi: { method: "GET", path: "/api/apps", tags: ["apps"], protect: true } })
Expand All @@ -31,13 +27,7 @@ export const appRouter = createTRPCRouter({
.input(z.object({ query: z.string(), limit: z.number().min(1).max(100).default(10) }))
.output(
z.array(
z.object({
name: z.string(),
id: z.string(),
description: z.string().nullable(),
iconUrl: z.string(),
href: z.string().nullable(),
}),
selectAppSchema,
),
)
.meta({ openapi: { method: "GET", path: "/api/apps/search", tags: ["apps"], protect: true } })
Expand All @@ -52,13 +42,7 @@ export const appRouter = createTRPCRouter({
.input(z.void())
.output(
z.array(
z.object({
name: z.string(),
id: z.string(),
iconUrl: z.string(),
description: z.string().nullable(),
href: z.string().nullable(),
}),
selectAppSchema.pick({ id: true, name: true, iconUrl: true, href: true, description: true }),
),
)
.meta({
Expand All @@ -84,13 +68,7 @@ export const appRouter = createTRPCRouter({
byId: publicProcedure
.input(validation.common.byId)
.output(
z.object({
name: z.string(),
id: z.string(),
description: z.string().nullable(),
iconUrl: z.string(),
href: z.string().nullable(),
}),
selectAppSchema,
)
.meta({ openapi: { method: "GET", path: "/api/apps/{id}", tags: ["apps"], protect: true } })
.query(async ({ ctx, input }) => {
Expand Down Expand Up @@ -136,7 +114,9 @@ export const appRouter = createTRPCRouter({
}),
update: permissionRequiredProcedure
.requiresPermission("app-modify-all")
.input(validation.app.edit)
.input(convertIntersectionToZodObject(validation.app.edit))
.output(z.void())
.meta({ openapi: { method: "PATCH", path: "/api/apps/{id}", tags: ["apps"], protect: true } })
.mutation(async ({ ctx, input }) => {
const app = await ctx.db.query.apps.findFirst({
where: eq(apps.id, input.id),
Expand Down
43 changes: 27 additions & 16 deletions packages/api/src/router/invite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,41 @@ import { z } from "@homarr/validation";

import { createTRPCRouter, protectedProcedure } from "../trpc";
import { throwIfCredentialsDisabled } from "./invite/checks";
import { selectInviteSchema } from "@homarr/db/validationSchemas/invite";

export const inviteRouter = createTRPCRouter({
getAll: protectedProcedure.query(async ({ ctx }) => {
throwIfCredentialsDisabled();
const dbInvites = await ctx.db.query.invites.findMany({
orderBy: asc(invites.expirationDate),
columns: {
token: false,
},
with: {
creator: {
columns: {
id: true,
name: true,
getAll: protectedProcedure
.output(z.array(selectInviteSchema.pick({
id: true,
expirationDate: true
}).extend({ creator: z.object({ name: z.string().nullable(), id: z.string() }) })))
.input(z.undefined())
.meta({ openapi: { method: "GET", path: "/api/invites", tags: ["invites"], protect: true } })
.query(async ({ ctx }) => {
throwIfCredentialsDisabled();
return await ctx.db.query.invites.findMany({
orderBy: asc(invites.expirationDate),
columns: {
token: false,
},
with: {
creator: {
columns: {
id: true,
name: true,
},
},
},
},
});
return dbInvites;
}),
});
}),
createInvite: protectedProcedure
.input(
z.object({
expirationDate: z.date(),
}),
)
.output(z.object({ id: z.string(), token: z.string() }))
.meta({ openapi: { method: "POST", path: "/api/invites", tags: ["invites"], protect: true } })
.mutation(async ({ ctx, input }) => {
throwIfCredentialsDisabled();
const id = createId();
Expand All @@ -56,6 +65,8 @@ export const inviteRouter = createTRPCRouter({
id: z.string(),
}),
)
.output(z.undefined())
.meta({ openapi: { method: "DELETE", path: "/api/invites/{id}", tags: ["invites"], protect: true } })
.mutation(async ({ ctx, input }) => {
throwIfCredentialsDisabled();
const dbInvite = await ctx.db.query.invites.findFirst({
Expand Down
28 changes: 27 additions & 1 deletion packages/api/src/router/serverSettings.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { getServerSettingByKeyAsync, getServerSettingsAsync, updateServerSettingByKeyAsync } from "@homarr/db/queries";
import type { ServerSettings } from "@homarr/server-settings";
import type { defaultServerSettings, ServerSettings } from "@homarr/server-settings";
import { defaultServerSettingsKeys } from "@homarr/server-settings";
import { z } from "@homarr/validation";

import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc";
import { eq } from "@homarr/db";
import { logger } from "@homarr/log";
import SuperJSON from "superjson";
import { serverSettings } from "@homarr/db/schema/sqlite";

export const serverSettingsRouter = createTRPCRouter({
getCulture: publicProcedure.query(async ({ ctx }) => {
Expand All @@ -12,6 +16,28 @@ export const serverSettingsRouter = createTRPCRouter({
getAll: protectedProcedure.query(async ({ ctx }) => {
return await getServerSettingsAsync(ctx.db);
}),
// this must be public so anonymous users also get analytics
getAnalytics: publicProcedure
.input(z.undefined())
.query(async ({ ctx }) => {
const setting = await ctx.db.query.serverSettings.findFirst({
where: eq(serverSettings.settingKey, "analytics"),
});

if (!setting) {
logger.info(
"Server settings for analytics is currently undefined. Using default values instead. If this persists, there may be an issue with the server settings",
);
return {
enableGeneral: true,
enableIntegrationData: false,
enableUserData: false,
enableWidgetData: false,
} as (typeof defaultServerSettings)["analytics"];
}

return SuperJSON.parse<(typeof defaultServerSettings)["analytics"]>(setting.value);
}),
saveSettings: protectedProcedure
.input(
z.object({
Expand Down
Loading

0 comments on commit ae661fe

Please sign in to comment.