lint
This commit is contained in:
parent
ed4ea1db40
commit
b9f36b5c2c
12 changed files with 160 additions and 131 deletions
|
@ -1,4 +1,8 @@
|
|||
import globals from "globals";
|
||||
import pluginJs from "@eslint/js";
|
||||
|
||||
export default [{ languageOptions: { globals: globals.node } }, pluginJs.configs.recommended];
|
||||
export default [
|
||||
{ ignores: ["**/dist/*"] },
|
||||
{ languageOptions: { globals: globals.node } },
|
||||
pluginJs.configs.recommended,
|
||||
];
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
},
|
||||
"scripts": {
|
||||
"start": "tsc && node dist/index.js",
|
||||
"lint:fix": "eslint --fix && prettier . --write",
|
||||
"lint": "eslint && prettier . --check"
|
||||
"lint:fix": "eslint . --fix && prettier . --write",
|
||||
"lint": "eslint . && prettier . --check"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.5.0",
|
||||
|
|
|
@ -19,7 +19,7 @@ import Fastify from "fastify";
|
|||
|
||||
let app = Fastify({
|
||||
logger: true,
|
||||
}).withTypeProvider<TypeBoxTypeProvider>()
|
||||
}).withTypeProvider<TypeBoxTypeProvider>();
|
||||
|
||||
export type AppInterface = typeof app;
|
||||
export default app;
|
||||
|
|
|
@ -20,36 +20,35 @@ import * as Jose from "jose";
|
|||
import { JWT_ALG, JWT_SECRET } from "./consts.js";
|
||||
import { DatabaseInterface, toDBList } from "./database.js";
|
||||
|
||||
|
||||
export type AuthInterface = Awaited<ReturnType<typeof startAuth>>;
|
||||
|
||||
export type User = {
|
||||
id: string,
|
||||
createdAt: number,
|
||||
lastConnected: number,
|
||||
name: string,
|
||||
email: string,
|
||||
password: string,
|
||||
limitID: string,
|
||||
}
|
||||
id: string;
|
||||
createdAt: number;
|
||||
lastConnected: number;
|
||||
name: string;
|
||||
email: string;
|
||||
password: string;
|
||||
limitID: string;
|
||||
};
|
||||
|
||||
export type NewUser = {
|
||||
name: string,
|
||||
email: string,
|
||||
password: string,
|
||||
}
|
||||
name: string;
|
||||
email: string;
|
||||
password: string;
|
||||
};
|
||||
|
||||
export type UpdateUser = {
|
||||
name?: string,
|
||||
email?: string,
|
||||
password?: string,
|
||||
assets?: string[],
|
||||
}
|
||||
name?: string;
|
||||
email?: string;
|
||||
password?: string;
|
||||
assets?: string[];
|
||||
};
|
||||
|
||||
export async function startAuth(database: DatabaseInterface) {
|
||||
let funcs = {
|
||||
user: async (uid: string) => await database.user(uid) satisfies User,
|
||||
findUserByEmail: async (email: string) => await database.findUserByEmail(email) satisfies User,
|
||||
user: async (uid: string) => (await database.user(uid)) satisfies User,
|
||||
findUserByEmail: async (email: string) => (await database.findUserByEmail(email)) satisfies User,
|
||||
findUserBySessionKey: async (sessionKey: string) => {
|
||||
let key = await database.sessionKey(sessionKey);
|
||||
return await database.user(key.userID);
|
||||
|
@ -61,21 +60,24 @@ export async function startAuth(database: DatabaseInterface) {
|
|||
return await database.updateUser(uid, user);
|
||||
},
|
||||
addUser: async (user: NewUser) => {
|
||||
let result = await database.insertUser({
|
||||
id: randomUUID(),
|
||||
createdAt: Date.now(),
|
||||
lastConnected: Date.now(),
|
||||
name: user.name,
|
||||
email: user.email,
|
||||
password: await argon2.hash(user.password),
|
||||
assets: toDBList([]),
|
||||
// FIXME: This shouldn't be required, the DB interface overwrites it.
|
||||
limitID: "",
|
||||
}, {
|
||||
id: randomUUID(),
|
||||
currentAssetCount: 0,
|
||||
maxAssetCount: 5,
|
||||
});
|
||||
let result = await database.insertUser(
|
||||
{
|
||||
id: randomUUID(),
|
||||
createdAt: Date.now(),
|
||||
lastConnected: Date.now(),
|
||||
name: user.name,
|
||||
email: user.email,
|
||||
password: await argon2.hash(user.password),
|
||||
assets: toDBList([]),
|
||||
// FIXME: This shouldn't be required, the DB interface overwrites it.
|
||||
limitID: "",
|
||||
},
|
||||
{
|
||||
id: randomUUID(),
|
||||
currentAssetCount: 0,
|
||||
maxAssetCount: 5,
|
||||
},
|
||||
);
|
||||
|
||||
return result satisfies User;
|
||||
},
|
||||
|
@ -103,9 +105,9 @@ export async function startAuth(database: DatabaseInterface) {
|
|||
},
|
||||
verifyJwt: async (jwt) => {
|
||||
return await Jose.jwtVerify<{
|
||||
uid: string,
|
||||
email: string,
|
||||
name: string,
|
||||
uid: string;
|
||||
email: string;
|
||||
name: string;
|
||||
}>(jwt, JWT_SECRET);
|
||||
},
|
||||
cleanUser: (user: User) => {
|
||||
|
@ -114,7 +116,7 @@ export async function startAuth(database: DatabaseInterface) {
|
|||
clean.limitID = undefined;
|
||||
|
||||
return clean;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
return funcs;
|
||||
|
|
|
@ -21,14 +21,14 @@ import { sqliteTable } from "drizzle-orm/sqlite-core";
|
|||
import { text, integer } from "drizzle-orm/sqlite-core";
|
||||
import { asc, desc, eq, sql } from "drizzle-orm";
|
||||
|
||||
export type DatabaseInterface = Awaited<ReturnType<typeof startDatabase>>
|
||||
export type DatabaseInterface = Awaited<ReturnType<typeof startDatabase>>;
|
||||
|
||||
export function toDBList(input: any[]): string {
|
||||
return JSON.stringify(input);
|
||||
return JSON.stringify(input);
|
||||
}
|
||||
|
||||
export function fromDBList<T>(input: string): Array<T> {
|
||||
return JSON.parse(input)
|
||||
return JSON.parse(input);
|
||||
}
|
||||
|
||||
export async function startDatabase() {
|
||||
|
@ -114,10 +114,10 @@ export async function startDatabase() {
|
|||
return result[0].id;
|
||||
},
|
||||
removeHeir: async (id: string) => {
|
||||
await database.delete(heirs).where(eq(heirs.id, id));
|
||||
await database.delete(heirs).where(eq(heirs.id, id));
|
||||
},
|
||||
listHeirs: async (userID: string) => {
|
||||
return await database.select().from(heirs).where(eq(heirs.userID, userID));
|
||||
return await database.select().from(heirs).where(eq(heirs.userID, userID));
|
||||
},
|
||||
insertUser: async (user: typeof users.$inferInsert, limit: typeof limits.$inferInsert) => {
|
||||
let limitsResult = await database.insert(limits).values(limit).returning({ id: limits.id });
|
||||
|
@ -131,14 +131,17 @@ export async function startDatabase() {
|
|||
return result[0];
|
||||
},
|
||||
userLimits: async (limitsID: string) => {
|
||||
let result = await database.select().from(limits).where(eq(limits.id, limitsID));
|
||||
return result[0];
|
||||
let result = await database.select().from(limits).where(eq(limits.id, limitsID));
|
||||
return result[0];
|
||||
},
|
||||
updateUser: async (userID: string, newUser: {
|
||||
name?: string,
|
||||
email?: string,
|
||||
password?: string,
|
||||
}) => {
|
||||
updateUser: async (
|
||||
userID: string,
|
||||
newUser: {
|
||||
name?: string;
|
||||
email?: string;
|
||||
password?: string;
|
||||
},
|
||||
) => {
|
||||
let result = await database.update(users).set(newUser).where(eq(users.id, userID)).returning();
|
||||
return result[0];
|
||||
},
|
||||
|
@ -157,7 +160,12 @@ export async function startDatabase() {
|
|||
findSessionKeyByUserID: async (userID: string) => {
|
||||
return await database.select().from(session_keys).where(eq(session_keys.userID, userID));
|
||||
},
|
||||
insertEntry: async (entry: typeof entries.$inferInsert, musicEntry?: typeof musicEntries.$inferInsert, locationEntry?: typeof locationEntries.$inferInsert, dateEntry?: typeof dateEntries.$inferInsert) => {
|
||||
insertEntry: async (
|
||||
entry: typeof entries.$inferInsert,
|
||||
musicEntry?: typeof musicEntries.$inferInsert,
|
||||
locationEntry?: typeof locationEntries.$inferInsert,
|
||||
dateEntry?: typeof dateEntries.$inferInsert,
|
||||
) => {
|
||||
if (entry.kind === "album" || entry.kind === "song") {
|
||||
let result = await database.insert(musicEntries).values(musicEntry).returning({ id: musicEntries.id });
|
||||
entry.musicEntry = result[0].id;
|
||||
|
@ -176,7 +184,7 @@ export async function startDatabase() {
|
|||
return result[0].id;
|
||||
},
|
||||
removeEntry: async (entryID: string) => {
|
||||
await database.delete(entries).where(eq(entries.id, entryID));
|
||||
await database.delete(entries).where(eq(entries.id, entryID));
|
||||
},
|
||||
entryPage: async (userID: string, offset: number, limit: number) => {
|
||||
let result = await database
|
||||
|
@ -188,46 +196,54 @@ export async function startDatabase() {
|
|||
.orderBy(desc(entries.createdAt));
|
||||
|
||||
for (let key in result) {
|
||||
if (!result.hasOwnProperty(key)) { continue; }
|
||||
|
||||
let entry = structuredClone(result[key]);
|
||||
let base = {};
|
||||
if (entry.musicEntry != null) {
|
||||
let musicDetails = (await database.select().from(musicEntries).where(eq(musicEntries.id, entry.musicEntry)))[0];
|
||||
(musicDetails["link"] as any) = fromDBList(musicDetails.links);
|
||||
(musicDetails["id"] as any) = fromDBList(musicDetails.universalIDs);
|
||||
|
||||
musicDetails["links"] = undefined;
|
||||
musicDetails["universalIDs"] = undefined;
|
||||
base = musicDetails;
|
||||
} else if (entry.locationEntry != null) {
|
||||
let locationDetails = (await database.select().from(locationEntries).where(eq(locationEntries.id, entry.locationEntry)))[0];
|
||||
|
||||
if (locationDetails.locationCoordinates != null) {
|
||||
base = { location: JSON.parse(locationDetails.locationCoordinates) }
|
||||
} else if (locationDetails.locationText != null) {
|
||||
base = { location: locationDetails.locationText }
|
||||
if (!result.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
} else if (entry.dateEntry != null) {
|
||||
let dateDetails = (await database.select().from(dateEntries).where(eq(dateEntries.id, entry.dateEntry)))[0];
|
||||
|
||||
base = {
|
||||
referencedDate: new Date(dateDetails["referencedDate"]).toISOString()
|
||||
};
|
||||
}
|
||||
let entry = structuredClone(result[key]);
|
||||
let base = {};
|
||||
if (entry.musicEntry != null) {
|
||||
let musicDetails = (
|
||||
await database.select().from(musicEntries).where(eq(musicEntries.id, entry.musicEntry))
|
||||
)[0];
|
||||
(musicDetails["link"] as any) = fromDBList(musicDetails.links);
|
||||
(musicDetails["id"] as any) = fromDBList(musicDetails.universalIDs);
|
||||
|
||||
base["kind"] = entry.kind
|
||||
musicDetails["links"] = undefined;
|
||||
musicDetails["universalIDs"] = undefined;
|
||||
base = musicDetails;
|
||||
} else if (entry.locationEntry != null) {
|
||||
let locationDetails = (
|
||||
await database.select().from(locationEntries).where(eq(locationEntries.id, entry.locationEntry))
|
||||
)[0];
|
||||
|
||||
result[key]["creationDate"] = new Date(entry.createdAt).toISOString();
|
||||
(result[key] as any)["feelings"] = fromDBList(entry.feelings);
|
||||
(result[key] as any)["assets"] = fromDBList(entry.assets);
|
||||
result[key]["base"] = base;
|
||||
if (locationDetails.locationCoordinates != null) {
|
||||
base = { location: JSON.parse(locationDetails.locationCoordinates) };
|
||||
} else if (locationDetails.locationText != null) {
|
||||
base = { location: locationDetails.locationText };
|
||||
}
|
||||
} else if (entry.dateEntry != null) {
|
||||
let dateDetails = (
|
||||
await database.select().from(dateEntries).where(eq(dateEntries.id, entry.dateEntry))
|
||||
)[0];
|
||||
|
||||
result[key].kind = undefined;
|
||||
result[key].userID = undefined;
|
||||
result[key].musicEntry = undefined;
|
||||
result[key].locationEntry = undefined;
|
||||
result[key].dateEntry = undefined;
|
||||
base = {
|
||||
referencedDate: new Date(dateDetails["referencedDate"]).toISOString(),
|
||||
};
|
||||
}
|
||||
|
||||
base["kind"] = entry.kind;
|
||||
|
||||
result[key]["creationDate"] = new Date(entry.createdAt).toISOString();
|
||||
(result[key] as any)["feelings"] = fromDBList(entry.feelings);
|
||||
(result[key] as any)["assets"] = fromDBList(entry.assets);
|
||||
result[key]["base"] = base;
|
||||
|
||||
result[key].kind = undefined;
|
||||
result[key].userID = undefined;
|
||||
result[key].musicEntry = undefined;
|
||||
result[key].locationEntry = undefined;
|
||||
result[key].dateEntry = undefined;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -24,7 +24,7 @@ const Body = Type.Object({
|
|||
contactMethod: Type.String(),
|
||||
name: Type.String(),
|
||||
value: Type.String(),
|
||||
})
|
||||
});
|
||||
|
||||
type BodyType = Static<typeof Body>;
|
||||
|
||||
|
@ -53,9 +53,9 @@ export default function register(app: AppInterface, auth: AuthInterface, databas
|
|||
});
|
||||
|
||||
return (await database.listHeirs(payload.uid))
|
||||
.map(v => v["contactMethod"] = "email")
|
||||
.map(v => v["value"] = v["email"])
|
||||
.map(v => v["email"] = undefined);
|
||||
.map((v) => (v["contactMethod"] = "email"))
|
||||
.map((v) => (v["value"] = v["email"]))
|
||||
.map((v) => (v["email"] = undefined));
|
||||
},
|
||||
schema: {
|
||||
headers: { $ref: "schema://identity/authorization" },
|
||||
|
@ -76,9 +76,9 @@ export default function register(app: AppInterface, auth: AuthInterface, databas
|
|||
await database.removeHeir(request.body);
|
||||
|
||||
return (await database.listHeirs(payload.uid))
|
||||
.map(v => v["contactMethod"] = "email")
|
||||
.map(v => v["value"] = v["email"])
|
||||
.map(v => v["email"] = undefined);
|
||||
.map((v) => (v["contactMethod"] = "email"))
|
||||
.map((v) => (v["value"] = v["email"]))
|
||||
.map((v) => (v["email"] = undefined));
|
||||
},
|
||||
schema: {
|
||||
headers: { $ref: "schema://identity/authorization" },
|
||||
|
|
|
@ -24,7 +24,7 @@ const Body = Type.Object({
|
|||
password: Type.String(),
|
||||
});
|
||||
|
||||
type BodyType = Static<typeof Body>;
|
||||
type BodyType = Static<typeof Body>;
|
||||
|
||||
export default function register(app: AppInterface, auth: AuthInterface) {
|
||||
app.post<{ Body: BodyType }>("/auth/register", {
|
||||
|
@ -35,7 +35,7 @@ export default function register(app: AppInterface, auth: AuthInterface) {
|
|||
password: request.body.password,
|
||||
name: request.body.name,
|
||||
});
|
||||
|
||||
|
||||
return { token: await auth.createJwt(user.id) };
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ import { Static, Type } from "@sinclair/typebox";
|
|||
|
||||
const EntryIDQuery = Type.Object({
|
||||
entry_id: Type.String(),
|
||||
})
|
||||
});
|
||||
|
||||
type EntryIDQueryType = Static<typeof EntryIDQuery>;
|
||||
|
||||
|
@ -43,22 +43,23 @@ const PutEntryBody = Type.Object({
|
|||
backgroundColor: Type.String(),
|
||||
textColor: Type.String(),
|
||||
}),
|
||||
])
|
||||
]),
|
||||
),
|
||||
base: Type.Union([
|
||||
Type.Object({
|
||||
kind: Type.String(),
|
||||
|
||||
}),
|
||||
Type.Object({
|
||||
kind: Type.String(),
|
||||
artist: Type.String(),
|
||||
title: Type.String(),
|
||||
link: Type.Array(Type.String()),
|
||||
id: Type.Array(Type.Object({
|
||||
provider: Type.String(),
|
||||
id: Type.String(),
|
||||
})),
|
||||
id: Type.Array(
|
||||
Type.Object({
|
||||
provider: Type.String(),
|
||||
id: Type.String(),
|
||||
}),
|
||||
),
|
||||
}),
|
||||
Type.Object({
|
||||
kind: Type.String(),
|
||||
|
@ -75,7 +76,7 @@ const PutEntryBody = Type.Object({
|
|||
referencedDate: Type.String(),
|
||||
}),
|
||||
]),
|
||||
})
|
||||
}),
|
||||
});
|
||||
|
||||
type PutEntryBodyType = Static<typeof PutEntryBody>;
|
||||
|
@ -105,37 +106,43 @@ export default function registerRoutes(app: AppInterface, auth: AuthInterface, d
|
|||
let entry = request.body.entry;
|
||||
|
||||
let musicEntry, locationEntry, dateEntry;
|
||||
if ((entry.base.kind === "album" || entry.base.kind === "song") && 'artist' in entry.base) {
|
||||
if ((entry.base.kind === "album" || entry.base.kind === "song") && "artist" in entry.base) {
|
||||
musicEntry = {
|
||||
id: randomUUID(),
|
||||
title: entry.base.title,
|
||||
artist: entry.base.artist,
|
||||
links: toDBList(entry.base.link),
|
||||
universalIDs: toDBList(entry.base.id),
|
||||
}
|
||||
} else if (entry.base.kind === "environment" && 'location' in entry.base) {
|
||||
};
|
||||
} else if (entry.base.kind === "environment" && "location" in entry.base) {
|
||||
locationEntry = {
|
||||
id: randomUUID(),
|
||||
locationText: typeof entry.base.location === "string" ? entry.base.location : undefined,
|
||||
locationCoordinates: typeof entry.base.location === "string" ? undefined : JSON.stringify(entry.base.location),
|
||||
}
|
||||
} else if (entry.base.kind === "date" && 'referencedDate' in entry.base) {
|
||||
locationCoordinates:
|
||||
typeof entry.base.location === "string" ? undefined : JSON.stringify(entry.base.location),
|
||||
};
|
||||
} else if (entry.base.kind === "date" && "referencedDate" in entry.base) {
|
||||
dateEntry = {
|
||||
id: randomUUID(),
|
||||
referencedDate: Date.parse(entry.base.referencedDate),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
await database.insertEntry({
|
||||
id: randomUUID(),
|
||||
userID: payload.uid,
|
||||
feelings: toDBList(entry.feelings),
|
||||
assets: toDBList(entry.assets),
|
||||
title: entry.title,
|
||||
description: entry.description,
|
||||
kind: entry.base.kind,
|
||||
createdAt: Date.now(),
|
||||
}, musicEntry, locationEntry, dateEntry);
|
||||
await database.insertEntry(
|
||||
{
|
||||
id: randomUUID(),
|
||||
userID: payload.uid,
|
||||
feelings: toDBList(entry.feelings),
|
||||
assets: toDBList(entry.assets),
|
||||
title: entry.title,
|
||||
description: entry.description,
|
||||
kind: entry.base.kind,
|
||||
createdAt: Date.now(),
|
||||
},
|
||||
musicEntry,
|
||||
locationEntry,
|
||||
dateEntry,
|
||||
);
|
||||
},
|
||||
schema: {
|
||||
headers: { $ref: "schema://identity/authorization" },
|
||||
|
|
|
@ -22,7 +22,7 @@ import type { DatabaseInterface } from "../../database.js";
|
|||
const Query = Type.Object({
|
||||
limit: Type.Number(),
|
||||
offset: Type.Number(),
|
||||
})
|
||||
});
|
||||
|
||||
type QueryType = Static<typeof Query>;
|
||||
|
||||
|
@ -37,7 +37,7 @@ export default function register(app: AppInterface, auth: AuthInterface, databas
|
|||
let jwt = request.headers["authorization"].replace("Bearer", "").trim();
|
||||
let { payload } = await auth.verifyJwt(jwt);
|
||||
|
||||
return await database.entryPage(payload.uid, request.query.offset, request.query.limit)
|
||||
return await database.entryPage(payload.uid, request.query.offset, request.query.limit);
|
||||
},
|
||||
schema: {
|
||||
headers: { $ref: "schema://identity/authorization" },
|
||||
|
|
|
@ -29,7 +29,7 @@ export default function register(app: AppInterface, auth: AuthInterface, databas
|
|||
}
|
||||
|
||||
let body = JSON.parse(contentFromSigned(request.body));
|
||||
|
||||
|
||||
let user = await auth.findUserBySessionKey(body.session_key);
|
||||
let limits = await database.userLimits(user.limitID);
|
||||
(user.assets as any) = fromDBList(user.assets);
|
||||
|
|
|
@ -33,7 +33,7 @@ export default function register(app: AppInterface, auth: AuthInterface) {
|
|||
let user = await auth.findUserBySessionKey(body.session_key);
|
||||
let assets = fromDBList(user.assets) as string[];
|
||||
assets.push(body.asset_id);
|
||||
|
||||
|
||||
await auth.updateUser(user.id, {
|
||||
assets,
|
||||
});
|
||||
|
|
|
@ -10,4 +10,4 @@
|
|||
},
|
||||
"include": ["./src/**/*"],
|
||||
"exclude": ["./node_modules/**/*"]
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue