mirror of
https://github.com/ajnart/homarr.git
synced 2026-02-27 08:50:56 +01:00
feat: add everyone group (#1322)
* feat: add everyone group through seed * feat: add reserved group name check in group router actions * feat: improve user interface for everyone group * fix: reserved group alert is a server component * feat: add all users to everyone group * chore: update lockfile * fix: format issues * fix: lint issues * fix: lint format issues * test: add unit tests for everyone group * refactor: add codegen for documentation urls by sitemap * refactor: change group query to count * chore: remove migrations temporarily * chore: add migrations again * chore: add lint rule to prevent usage of raw documentation links * fix: format issues
This commit is contained in:
@@ -3,6 +3,7 @@ import { TRPCError } from "@trpc/server";
|
||||
import type { Database } from "@homarr/db";
|
||||
import { and, createId, eq, like, not, sql } from "@homarr/db";
|
||||
import { groupMembers, groupPermissions, groups } from "@homarr/db/schema/sqlite";
|
||||
import { everyoneGroup } from "@homarr/definitions";
|
||||
import { validation, z } from "@homarr/validation";
|
||||
|
||||
import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure } from "../trpc";
|
||||
@@ -121,13 +122,12 @@ export const groupRouter = createTRPCRouter({
|
||||
.requiresPermission("admin")
|
||||
.input(validation.group.create)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const normalizedName = normalizeName(input.name);
|
||||
await checkSimilarNameAndThrowAsync(ctx.db, normalizedName);
|
||||
await checkSimilarNameAndThrowAsync(ctx.db, input.name);
|
||||
|
||||
const id = createId();
|
||||
await ctx.db.insert(groups).values({
|
||||
id,
|
||||
name: normalizedName,
|
||||
name: input.name,
|
||||
ownerId: ctx.session.user.id,
|
||||
});
|
||||
|
||||
@@ -138,14 +138,14 @@ export const groupRouter = createTRPCRouter({
|
||||
.input(validation.group.update)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
await throwIfGroupNotFoundAsync(ctx.db, input.id);
|
||||
await throwIfGroupNameIsReservedAsync(ctx.db, input.id);
|
||||
|
||||
const normalizedName = normalizeName(input.name);
|
||||
await checkSimilarNameAndThrowAsync(ctx.db, normalizedName, input.id);
|
||||
await checkSimilarNameAndThrowAsync(ctx.db, input.name, input.id);
|
||||
|
||||
await ctx.db
|
||||
.update(groups)
|
||||
.set({
|
||||
name: normalizedName,
|
||||
name: input.name,
|
||||
})
|
||||
.where(eq(groups.id, input.id));
|
||||
}),
|
||||
@@ -169,6 +169,7 @@ export const groupRouter = createTRPCRouter({
|
||||
.input(validation.group.groupUser)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
await throwIfGroupNotFoundAsync(ctx.db, input.groupId);
|
||||
await throwIfGroupNameIsReservedAsync(ctx.db, input.groupId);
|
||||
|
||||
await ctx.db
|
||||
.update(groups)
|
||||
@@ -182,6 +183,7 @@ export const groupRouter = createTRPCRouter({
|
||||
.input(validation.common.byId)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
await throwIfGroupNotFoundAsync(ctx.db, input.id);
|
||||
await throwIfGroupNameIsReservedAsync(ctx.db, input.id);
|
||||
|
||||
await ctx.db.delete(groups).where(eq(groups.id, input.id));
|
||||
}),
|
||||
@@ -190,6 +192,7 @@ export const groupRouter = createTRPCRouter({
|
||||
.input(validation.group.groupUser)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
await throwIfGroupNotFoundAsync(ctx.db, input.groupId);
|
||||
await throwIfGroupNameIsReservedAsync(ctx.db, input.groupId);
|
||||
throwIfCredentialsDisabled();
|
||||
|
||||
const user = await ctx.db.query.users.findFirst({
|
||||
@@ -213,6 +216,7 @@ export const groupRouter = createTRPCRouter({
|
||||
.input(validation.group.groupUser)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
await throwIfGroupNotFoundAsync(ctx.db, input.groupId);
|
||||
await throwIfGroupNameIsReservedAsync(ctx.db, input.groupId);
|
||||
throwIfCredentialsDisabled();
|
||||
|
||||
await ctx.db
|
||||
@@ -221,8 +225,6 @@ export const groupRouter = createTRPCRouter({
|
||||
}),
|
||||
});
|
||||
|
||||
const normalizeName = (name: string) => name.trim();
|
||||
|
||||
const checkSimilarNameAndThrowAsync = async (db: Database, name: string, ignoreId?: string) => {
|
||||
const similar = await db.query.groups.findFirst({
|
||||
where: and(like(groups.name, `${name}`), not(eq(groups.id, ignoreId ?? ""))),
|
||||
@@ -236,6 +238,17 @@ const checkSimilarNameAndThrowAsync = async (db: Database, name: string, ignoreI
|
||||
}
|
||||
};
|
||||
|
||||
const throwIfGroupNameIsReservedAsync = async (db: Database, id: string) => {
|
||||
const count = await db.$count(groups, and(eq(groups.id, id), eq(groups.name, everyoneGroup)));
|
||||
|
||||
if (count > 0) {
|
||||
throw new TRPCError({
|
||||
code: "FORBIDDEN",
|
||||
message: "Action is forbidden for reserved group names",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const throwIfGroupNotFoundAsync = async (db: Database, id: string) => {
|
||||
const group = await db.query.groups.findFirst({
|
||||
where: eq(groups.id, id),
|
||||
|
||||
Reference in New Issue
Block a user