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:
Meier Lukas
2024-10-21 17:23:51 +02:00
committed by GitHub
parent 654880d7e4
commit 2f1c800844
38 changed files with 3900 additions and 139 deletions

View File

@@ -0,0 +1 @@
ALTER TABLE `group` ADD CONSTRAINT `group_name_unique` UNIQUE(`name`);

File diff suppressed because it is too large Load Diff

View File

@@ -92,6 +92,13 @@
"when": 1729348221072,
"tag": "0012_abnormal_wendell_vaughn",
"breakpoints": true
},
{
"idx": 13,
"version": "5",
"when": 1729369383739,
"tag": "0013_youthful_vulture",
"breakpoints": true
}
]
}

View File

@@ -3,25 +3,35 @@ import { drizzle } from "drizzle-orm/mysql2";
import { migrate } from "drizzle-orm/mysql2/migrator";
import mysql from "mysql2";
import type { Database } from "../..";
import * as mysqlSchema from "../../schema/mysql";
import { seedDataAsync } from "../seed";
const migrationsFolder = process.argv[2] ?? ".";
const mysql2 = mysql.createConnection(
process.env.DB_HOST
? {
host: process.env.DB_HOST,
database: process.env.DB_NAME!,
port: Number(process.env.DB_PORT),
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
}
: { uri: process.env.DB_URL },
);
const migrateAsync = async () => {
const mysql2 = mysql.createConnection(
process.env.DB_HOST
? {
host: process.env.DB_HOST,
database: process.env.DB_NAME!,
port: Number(process.env.DB_PORT),
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
}
: { uri: process.env.DB_URL },
);
const db = drizzle(mysql2, {
mode: "default",
});
const db = drizzle(mysql2, {
mode: "default",
schema: mysqlSchema,
});
migrate(db, { migrationsFolder })
await migrate(db, { migrationsFolder });
await seedDataAsync(db as unknown as Database);
};
migrateAsync()
.then(() => {
console.log("Migration complete");
process.exit(0);

View File

@@ -0,0 +1,12 @@
import { database } from "../driver";
import { seedDataAsync } from "./seed";
seedDataAsync(database)
.then(() => {
console.log("Seed complete");
process.exit(0);
})
.catch((err) => {
console.log("Seed failed\n\t", err);
process.exit(1);
});

View File

@@ -0,0 +1,52 @@
import SuperJSON from "superjson";
import { everyoneGroup } from "@homarr/definitions";
import { defaultServerSettings, defaultServerSettingsKeys } from "@homarr/server-settings";
import { createId, eq } from "..";
import type { Database } from "..";
import { groups } from "../schema/mysql";
import { serverSettings } from "../schema/sqlite";
export const seedDataAsync = async (db: Database) => {
await seedEveryoneGroupAsync(db);
await seedServerSettingsAsync(db);
};
const seedEveryoneGroupAsync = async (db: Database) => {
const group = await db.query.groups.findFirst({
where: eq(groups.name, everyoneGroup),
});
if (group) {
console.log("Skipping seeding of group 'everyone' as it already exists");
return;
}
await db.insert(groups).values({
id: createId(),
name: everyoneGroup,
});
console.log("Created group 'everyone' through seed");
};
const seedServerSettingsAsync = async (db: Database) => {
const serverSettingsData = await db.query.serverSettings.findMany();
let insertedSettingsCount = 0;
for (const settingsKey of defaultServerSettingsKeys) {
if (serverSettingsData.some((setting) => setting.settingKey === settingsKey)) {
return;
}
await db.insert(serverSettings).values({
settingKey: settingsKey,
value: SuperJSON.stringify(defaultServerSettings[settingsKey]),
});
insertedSettingsCount++;
}
if (insertedSettingsCount > 0) {
console.info(`Inserted ${insertedSettingsCount} missing settings`);
}
};

View File

@@ -0,0 +1 @@
CREATE UNIQUE INDEX `group_name_unique` ON `group` (`name`);

File diff suppressed because it is too large Load Diff

View File

@@ -92,6 +92,13 @@
"when": 1729348200091,
"tag": "0012_ambiguous_black_panther",
"breakpoints": true
},
{
"idx": 13,
"version": "6",
"when": 1729369389386,
"tag": "0013_faithful_hex",
"breakpoints": true
}
]
}

View File

@@ -2,10 +2,27 @@ import Database from "better-sqlite3";
import { drizzle } from "drizzle-orm/better-sqlite3";
import { migrate } from "drizzle-orm/better-sqlite3/migrator";
import { schema } from "../..";
import { seedDataAsync } from "../seed";
const migrationsFolder = process.argv[2] ?? ".";
const sqlite = new Database(process.env.DB_URL?.replace("file:", ""));
const migrateAsync = async () => {
const sqlite = new Database(process.env.DB_URL?.replace("file:", ""));
const db = drizzle(sqlite);
const db = drizzle(sqlite, { schema });
migrate(db, { migrationsFolder });
migrate(db, { migrationsFolder });
await seedDataAsync(db);
};
migrateAsync()
.then(() => {
console.log("Migration complete");
process.exit(0);
})
.catch((err) => {
console.log("Migration failed", err);
process.exit(1);
});

View File

@@ -21,15 +21,17 @@
"format": "prettier --check . --ignore-path ../../.gitignore",
"lint": "eslint",
"migration:mysql:generate": "drizzle-kit generate --config ./configs/mysql.config.ts",
"migration:mysql:run": "drizzle-kit migrate --config ./configs/mysql.config.ts",
"migration:mysql:run": "drizzle-kit migrate --config ./configs/mysql.config.ts && pnpm run seed",
"migration:mysql:drop": "drizzle-kit drop --config ./configs/mysql.config.ts",
"migration:sqlite:generate": "drizzle-kit generate --config ./configs/sqlite.config.ts",
"migration:sqlite:run": "drizzle-kit migrate --config ./configs/sqlite.config.ts",
"migration:sqlite:run": "drizzle-kit migrate --config ./configs/sqlite.config.ts && pnpm run seed",
"migration:sqlite:drop": "drizzle-kit drop --config ./configs/sqlite.config.ts",
"push:mysql": "drizzle-kit push --config ./configs/mysql.config.ts",
"push:sqlite": "drizzle-kit push --config ./configs/sqlite.config.ts",
"seed": "pnpm with-env tsx ./migrations/run-seed.ts",
"studio": "drizzle-kit studio --config ./configs/sqlite.config.ts",
"typecheck": "tsc --noEmit"
"typecheck": "tsc --noEmit",
"with-env": "dotenv -e ../../.env --"
},
"prettier": "@homarr/prettier-config",
"dependencies": {
@@ -37,6 +39,7 @@
"@homarr/common": "workspace:^0.1.0",
"@homarr/definitions": "workspace:^0.1.0",
"@homarr/log": "workspace:^0.1.0",
"@homarr/server-settings": "workspace:^0.1.0",
"@paralleldrive/cuid2": "^2.2.2",
"@testcontainers/mysql": "^10.13.2",
"better-sqlite3": "^11.4.0",
@@ -53,6 +56,7 @@
"dotenv-cli": "^7.4.2",
"eslint": "^9.13.0",
"prettier": "^3.3.3",
"tsx": "4.19.1",
"typescript": "^5.6.3"
}
}

View File

@@ -120,7 +120,7 @@ export const groupMembers = mysqlTable(
export const groups = mysqlTable("group", {
id: varchar("id", { length: 64 }).notNull().primaryKey(),
name: varchar("name", { length: 64 }).notNull(),
name: varchar("name", { length: 64 }).unique().notNull(),
ownerId: varchar("owner_id", { length: 64 }).references(() => users.id, {
onDelete: "set null",
}),

View File

@@ -121,7 +121,7 @@ export const groupMembers = sqliteTable(
export const groups = sqliteTable("group", {
id: text("id").notNull().primaryKey(),
name: text("name").notNull(),
name: text("name").unique().notNull(),
ownerId: text("owner_id").references(() => users.id, {
onDelete: "set null",
}),