This commit is contained in:
45
src/actions/admin.ts
Normal file
45
src/actions/admin.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { defineAction } from 'astro:actions';
|
||||
import { db } from '@db/database.ts';
|
||||
import { z } from 'astro:schema';
|
||||
import { Session } from '@util/session.ts';
|
||||
import { Permissions } from '@util/permissions.ts';
|
||||
|
||||
export const admin = {
|
||||
addAdmin: defineAction({
|
||||
input: z.object({
|
||||
username: z.string(),
|
||||
password: z.string(),
|
||||
permissions: z.number()
|
||||
}),
|
||||
handler: async (input, context) => {
|
||||
Session.actionSessionFromCookies(context.cookies, Permissions.Admin);
|
||||
const { id } = await db.addAdmin(input);
|
||||
|
||||
return {
|
||||
id: id
|
||||
};
|
||||
}
|
||||
}),
|
||||
editAdmin: defineAction({
|
||||
input: z.object({
|
||||
id: z.number(),
|
||||
username: z.string(),
|
||||
password: z.string(),
|
||||
permissions: z.number()
|
||||
}),
|
||||
handler: async (input, context) => {
|
||||
Session.actionSessionFromCookies(context.cookies, Permissions.Admin);
|
||||
|
||||
await db.editAdmin(input);
|
||||
}
|
||||
}),
|
||||
admins: defineAction({
|
||||
handler: async (_, context) => {
|
||||
Session.actionSessionFromCookies(context.cookies, Permissions.Admin);
|
||||
|
||||
return {
|
||||
admins: await db.getAdmins({})
|
||||
};
|
||||
}
|
||||
})
|
||||
};
|
||||
40
src/actions/feedback.ts
Normal file
40
src/actions/feedback.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { defineAction } from 'astro:actions';
|
||||
import { db } from '@db/database.ts';
|
||||
import { Session } from '@util/session.ts';
|
||||
import { Permissions } from '@util/permissions.ts';
|
||||
import { z } from 'astro:schema';
|
||||
|
||||
export const feedback = {
|
||||
addWebsiteFeedback: defineAction({
|
||||
input: z.object({
|
||||
content: z.string()
|
||||
}),
|
||||
handler: async (input) => {
|
||||
await db.addFeedback({
|
||||
event: 'website-feedback',
|
||||
content: input.content
|
||||
});
|
||||
}
|
||||
}),
|
||||
addWebsiteContact: defineAction({
|
||||
input: z.object({
|
||||
content: z.string(),
|
||||
email: z.string().email()
|
||||
}),
|
||||
handler: async (input) => {
|
||||
await db.addFeedback({
|
||||
event: 'website-contact',
|
||||
content: `${input.content}\n\nEmail: ${input.email}`
|
||||
});
|
||||
}
|
||||
}),
|
||||
feedbacks: defineAction({
|
||||
handler: async (_, context) => {
|
||||
Session.actionSessionFromCookies(context.cookies, Permissions.Feedback);
|
||||
|
||||
return {
|
||||
feedbacks: await db.getFeedbacks({})
|
||||
};
|
||||
}
|
||||
})
|
||||
};
|
||||
19
src/actions/index.ts
Normal file
19
src/actions/index.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { session } from './session.ts';
|
||||
import { signup } from './signup.ts';
|
||||
import { user } from './user.ts';
|
||||
import { admin } from './admin.ts';
|
||||
import { team } from './team.ts';
|
||||
import { settings } from './settings.ts';
|
||||
import { feedback } from './feedback.ts';
|
||||
import { report } from './report.ts';
|
||||
|
||||
export const server = {
|
||||
admin,
|
||||
session,
|
||||
signup,
|
||||
team,
|
||||
user,
|
||||
report,
|
||||
feedback,
|
||||
settings
|
||||
};
|
||||
80
src/actions/report.ts
Normal file
80
src/actions/report.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { defineAction } from 'astro:actions';
|
||||
import { Session } from '@util/session.ts';
|
||||
import { Permissions } from '@util/permissions.ts';
|
||||
import { db } from '@db/database.ts';
|
||||
import { z } from 'astro:schema';
|
||||
|
||||
export const report = {
|
||||
addReport: defineAction({
|
||||
input: z.object({
|
||||
reason: z.string(),
|
||||
body: z.string().nullable(),
|
||||
createdAt: z.string().datetime().nullable(),
|
||||
reporter: z.number(),
|
||||
reported: z.number().nullable()
|
||||
}),
|
||||
handler: async (input, context) => {
|
||||
Session.actionSessionFromCookies(context.cookies, Permissions.Reports);
|
||||
|
||||
const { id } = await db.addReport({
|
||||
reason: input.reason,
|
||||
body: input.body,
|
||||
createdAt: input.createdAt,
|
||||
reporterTeamId: input.reporter,
|
||||
reportedTeamId: input.reported
|
||||
});
|
||||
|
||||
return {
|
||||
id: id
|
||||
};
|
||||
}
|
||||
}),
|
||||
reportStatus: defineAction({
|
||||
input: z.object({
|
||||
reportId: z.number()
|
||||
}),
|
||||
handler: async (input, context) => {
|
||||
Session.actionSessionFromCookies(context.cookies, Permissions.Reports);
|
||||
|
||||
return {
|
||||
reportStatus: await db.getReportStatus(input)
|
||||
};
|
||||
}
|
||||
}),
|
||||
editReportStatus: defineAction({
|
||||
input: z.object({
|
||||
reportId: z.number(),
|
||||
status: z.enum(['open', 'closed']).nullable(),
|
||||
notice: z.string().nullable(),
|
||||
statement: z.string().nullable(),
|
||||
strikeId: z.number().nullable()
|
||||
}),
|
||||
handler: async (input, context) => {
|
||||
Session.actionSessionFromCookies(context.cookies, Permissions.Reports);
|
||||
|
||||
await db.editReportStatus(input);
|
||||
}
|
||||
}),
|
||||
reports: defineAction({
|
||||
input: z.object({
|
||||
reporter: z.string().nullish(),
|
||||
reported: z.string().nullish()
|
||||
}),
|
||||
handler: async (input, context) => {
|
||||
Session.actionSessionFromCookies(context.cookies, Permissions.Reports);
|
||||
|
||||
return {
|
||||
reports: await db.getReports(input)
|
||||
};
|
||||
}
|
||||
}),
|
||||
strikeReasons: defineAction({
|
||||
handler: async (_, context) => {
|
||||
Session.actionSessionFromCookies(context.cookies, Permissions.Reports);
|
||||
|
||||
return {
|
||||
strikeReasons: await db.getStrikeReasons({})
|
||||
};
|
||||
}
|
||||
})
|
||||
};
|
||||
49
src/actions/session.ts
Normal file
49
src/actions/session.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { ActionError, defineAction } from 'astro:actions';
|
||||
import { z } from 'astro:schema';
|
||||
import { db } from '@db/database.ts';
|
||||
import { ADMIN_USER, ADMIN_PASSWORD } from 'astro:env/server';
|
||||
import { Session } from '@util/session.ts';
|
||||
import { Permissions } from '@util/permissions.ts';
|
||||
|
||||
export const session = {
|
||||
login: defineAction({
|
||||
input: z.object({
|
||||
username: z.string(),
|
||||
password: z.string()
|
||||
}),
|
||||
handler: async (input, context) => {
|
||||
let admin;
|
||||
if (input.username === ADMIN_USER && input.password === ADMIN_PASSWORD) {
|
||||
admin = {
|
||||
id: -1,
|
||||
username: ADMIN_USER,
|
||||
permissions: new Permissions(Permissions.allPermissions())
|
||||
};
|
||||
} else {
|
||||
admin = await db.existsAdmin(input);
|
||||
}
|
||||
|
||||
if (!admin) {
|
||||
throw new ActionError({
|
||||
code: 'UNAUTHORIZED',
|
||||
message: 'Nutzername und Passwort stimmen nicht überein'
|
||||
});
|
||||
}
|
||||
|
||||
Session.newSession(admin.id, admin.permissions, context.cookies);
|
||||
|
||||
return {
|
||||
id: admin.id,
|
||||
username: admin.username,
|
||||
permissions: admin.permissions.value
|
||||
};
|
||||
}
|
||||
}),
|
||||
logout: defineAction({
|
||||
handler: async (_, context) => {
|
||||
const session = Session.actionSessionFromCookies(context.cookies);
|
||||
|
||||
session.invalidate(context.cookies);
|
||||
}
|
||||
})
|
||||
};
|
||||
23
src/actions/settings.ts
Normal file
23
src/actions/settings.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { defineAction } from 'astro:actions';
|
||||
import { z } from 'astro:schema';
|
||||
import { Session } from '@util/session.ts';
|
||||
import { Permissions } from '@util/permissions.ts';
|
||||
import { db } from '@db/database.ts';
|
||||
|
||||
export const settings = {
|
||||
setSettings: defineAction({
|
||||
input: z.object({
|
||||
settings: z.array(
|
||||
z.object({
|
||||
name: z.string(),
|
||||
value: z.string().nullable()
|
||||
})
|
||||
)
|
||||
}),
|
||||
handler: async (input, context) => {
|
||||
Session.actionSessionFromCookies(context.cookies, Permissions.Settings);
|
||||
|
||||
await db.setSettings(input);
|
||||
}
|
||||
})
|
||||
};
|
||||
119
src/actions/signup.ts
Normal file
119
src/actions/signup.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
import { ActionError, defineAction } from 'astro:actions';
|
||||
import { z } from 'astro:schema';
|
||||
import { db } from '@db/database.ts';
|
||||
import { getJavaUuid } from '@util/minecraft.ts';
|
||||
import { getSetting, SettingKey } from '@util/settings.ts';
|
||||
|
||||
export const signup = {
|
||||
signup: defineAction({
|
||||
input: z.object({
|
||||
firstname: z.string().min(2),
|
||||
lastname: z.string().min(2),
|
||||
// this will be inaccurate as it is evaluated only once
|
||||
birthday: z
|
||||
.string()
|
||||
.date()
|
||||
.max(Date.now() - 1000 * 60 * 60 * 24 * 365 * 6),
|
||||
phone: z.string().nullable(),
|
||||
username: z.string(),
|
||||
|
||||
teamMember: z.string(),
|
||||
teamName: z.string().nullable()
|
||||
}),
|
||||
handler: async (input) => {
|
||||
// check if signup is allowed
|
||||
if (!(await getSetting(db, SettingKey.SignupEnabled))) {
|
||||
throw new ActionError({
|
||||
code: 'FORBIDDEN',
|
||||
message: 'Die Anmeldung ist derzeit deaktiviert'
|
||||
});
|
||||
}
|
||||
|
||||
// check if username and team member is equal
|
||||
if (input.username.toLowerCase() === input.teamMember.toLowerCase()) {
|
||||
throw new ActionError({
|
||||
code: 'BAD_REQUEST',
|
||||
message: 'Du kannst nicht mit dir selber in einem Team sein'
|
||||
});
|
||||
}
|
||||
|
||||
// check if the user were already signed up
|
||||
if (await db.getUserByUsername({ username: input.username })) {
|
||||
throw new ActionError({
|
||||
code: 'CONFLICT',
|
||||
message: 'Du hast dich bereits registriert'
|
||||
});
|
||||
}
|
||||
|
||||
const teamMember = await db.getUserByUsername({ username: input.teamMember });
|
||||
const teamDraft = await db.getTeamDraftByMemberOne({ memberOneName: input.teamMember });
|
||||
|
||||
// check if the team member already signed up but is in another team already
|
||||
if (teamMember && (!teamDraft || teamDraft.memberTwoName.toLowerCase() != input.username.toLowerCase())) {
|
||||
throw new ActionError({
|
||||
code: 'FORBIDDEN',
|
||||
message: 'Dein Teampartner ist bereits in einem anderen Team'
|
||||
});
|
||||
}
|
||||
|
||||
let uuid;
|
||||
try {
|
||||
uuid = await getJavaUuid(input.username);
|
||||
} catch (_) {
|
||||
throw new ActionError({
|
||||
code: 'NOT_FOUND',
|
||||
message: `Es wurde kein Minecraft Java Account mit dem Username ${input.username} gefunden`
|
||||
});
|
||||
}
|
||||
|
||||
if (!teamDraft) {
|
||||
// check if a team with the same name already exists
|
||||
if (input.teamName) {
|
||||
if (await db.getTeamByName({ name: input.teamName })) {
|
||||
throw new ActionError({
|
||||
code: 'CONFLICT',
|
||||
message: 'Es gibt bereits ein Team mit diesem Namen'
|
||||
});
|
||||
}
|
||||
// no team draft is present and `input.teamName` is not present
|
||||
} else {
|
||||
throw new ActionError({
|
||||
code: 'BAD_REQUEST',
|
||||
message: 'Es ist noch kein Team auf dich und deinen Teampartner registriert'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const team = await db.transaction(async (tx) => {
|
||||
const user = await tx.addUser({
|
||||
firstname: input.firstname,
|
||||
lastname: input.lastname,
|
||||
birthday: input.birthday,
|
||||
telephone: input.phone,
|
||||
username: input.username,
|
||||
uuid: uuid
|
||||
});
|
||||
|
||||
let team;
|
||||
if (teamDraft) {
|
||||
team = await tx.getTeamById({ id: teamDraft.teamId });
|
||||
} else {
|
||||
team = await tx.addTeam({ name: input.teamName! });
|
||||
|
||||
await tx.addTeamDraft({ memberOneName: input.username, memberTwoName: input.teamMember, teamId: team.id });
|
||||
}
|
||||
|
||||
await tx.addTeamMember({ teamId: team.id, userId: user.id });
|
||||
|
||||
return team;
|
||||
});
|
||||
|
||||
return {
|
||||
team: {
|
||||
name: team.name,
|
||||
color: team.color
|
||||
}
|
||||
};
|
||||
}
|
||||
})
|
||||
};
|
||||
122
src/actions/team.ts
Normal file
122
src/actions/team.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
import { defineAction } from 'astro:actions';
|
||||
import { Session } from '@util/session.ts';
|
||||
import { Permissions } from '@util/permissions.ts';
|
||||
import { db } from '@db/database.ts';
|
||||
import { z } from 'astro:schema';
|
||||
|
||||
export const team = {
|
||||
addTeam: defineAction({
|
||||
input: z.object({
|
||||
name: z.string(),
|
||||
color: z.string(),
|
||||
lastJoined: z.string().datetime().nullable(),
|
||||
memberOne: z.object({
|
||||
id: z.number().nullish(),
|
||||
username: z.string()
|
||||
}),
|
||||
memberTwo: z.object({
|
||||
id: z.number().nullish(),
|
||||
username: z.string()
|
||||
})
|
||||
}),
|
||||
handler: async (input, context) => {
|
||||
Session.actionSessionFromCookies(context.cookies, Permissions.Users);
|
||||
|
||||
const teamId = await db.transaction(async (tx) => {
|
||||
const team = await tx.addTeam({
|
||||
name: input.name,
|
||||
color: input.color
|
||||
});
|
||||
|
||||
await tx.addTeamDraft({
|
||||
memberOneName: input.memberOne.username,
|
||||
memberTwoName: input.memberTwo.username,
|
||||
teamId: team.id
|
||||
});
|
||||
|
||||
if (input.memberOne.id) {
|
||||
await tx.addTeamMember({
|
||||
teamId: team.id,
|
||||
userId: input.memberOne.id
|
||||
});
|
||||
}
|
||||
|
||||
if (input.memberTwo.id) {
|
||||
await tx.addTeamMember({
|
||||
teamId: team.id,
|
||||
userId: input.memberTwo.id
|
||||
});
|
||||
}
|
||||
|
||||
return team.id;
|
||||
});
|
||||
|
||||
return Object.assign(input, { id: teamId });
|
||||
}
|
||||
}),
|
||||
editTeam: defineAction({
|
||||
input: z.object({
|
||||
id: z.number(),
|
||||
name: z.string(),
|
||||
color: z.string(),
|
||||
lastJoined: z.string().datetime().nullable(),
|
||||
memberOne: z.object({
|
||||
id: z.number().nullable(),
|
||||
username: z.string()
|
||||
}),
|
||||
memberTwo: z.object({
|
||||
id: z.number().nullable(),
|
||||
username: z.string()
|
||||
})
|
||||
}),
|
||||
handler: async (input, context) => {
|
||||
Session.actionSessionFromCookies(context.cookies, Permissions.Users);
|
||||
|
||||
await db.transaction(async (tx) => {
|
||||
await tx.editTeam({
|
||||
id: input.id,
|
||||
name: input.name,
|
||||
color: input.color,
|
||||
lastJoined: input.lastJoined
|
||||
});
|
||||
|
||||
await tx.deleteTeamDraft({ teamId: input.id });
|
||||
await tx.deleteTeamMemberByTeamId({ teamId: input.id });
|
||||
|
||||
await tx.addTeamDraft({
|
||||
memberOneName: input.memberOne.username,
|
||||
memberTwoName: input.memberTwo.username,
|
||||
teamId: input.id
|
||||
});
|
||||
|
||||
if (input.memberOne.id) {
|
||||
await tx.addTeamMember({
|
||||
teamId: input.id,
|
||||
userId: input.memberOne.id
|
||||
});
|
||||
}
|
||||
|
||||
if (input.memberTwo.id) {
|
||||
await tx.addTeamMember({
|
||||
teamId: input.id,
|
||||
userId: input.memberTwo.id
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}),
|
||||
teams: defineAction({
|
||||
input: z.object({
|
||||
name: z.string().nullish(),
|
||||
username: z.string().nullish(),
|
||||
limit: z.number().optional()
|
||||
}),
|
||||
handler: async (input, context) => {
|
||||
Session.actionSessionFromCookies(context.cookies, Permissions.Users);
|
||||
|
||||
return {
|
||||
teams: await db.getTeams(input)
|
||||
};
|
||||
}
|
||||
})
|
||||
};
|
||||
88
src/actions/user.ts
Normal file
88
src/actions/user.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import { ActionError, defineAction } from 'astro:actions';
|
||||
import { z } from 'astro:schema';
|
||||
import { db } from '@db/database.ts';
|
||||
import { Session } from '@util/session.ts';
|
||||
import { Permissions } from '@util/permissions.ts';
|
||||
|
||||
export const user = {
|
||||
addUser: defineAction({
|
||||
input: z.object({
|
||||
firstname: z.string(),
|
||||
lastname: z.string(),
|
||||
birthday: z.string().date(),
|
||||
telephone: z.string().nullable(),
|
||||
username: z.string(),
|
||||
uuid: z.string().nullable()
|
||||
}),
|
||||
handler: async (input, context) => {
|
||||
Session.actionSessionFromCookies(context.cookies, Permissions.Users);
|
||||
|
||||
if (await db.existsUser({ username: input.username })) {
|
||||
throw new ActionError({
|
||||
code: 'CONFLICT',
|
||||
message: 'Der Benutzername ist bereits registriert'
|
||||
});
|
||||
}
|
||||
|
||||
const { id } = await db.addUser({
|
||||
firstname: input.firstname,
|
||||
lastname: input.lastname,
|
||||
birthday: input.birthday,
|
||||
telephone: input.telephone,
|
||||
username: input.username,
|
||||
uuid: input.uuid
|
||||
});
|
||||
|
||||
return {
|
||||
id: id
|
||||
};
|
||||
}
|
||||
}),
|
||||
editUser: defineAction({
|
||||
input: z.object({
|
||||
id: z.number(),
|
||||
firstname: z.string(),
|
||||
lastname: z.string(),
|
||||
birthday: z.string().date(),
|
||||
telephone: z.string().nullable(),
|
||||
username: z.string(),
|
||||
uuid: z.string().nullable()
|
||||
}),
|
||||
handler: async (input, context) => {
|
||||
Session.actionSessionFromCookies(context.cookies, Permissions.Users);
|
||||
|
||||
const user = await db.existsUser({ username: input.username });
|
||||
if (user && user.id !== input.id) {
|
||||
throw new ActionError({
|
||||
code: 'CONFLICT',
|
||||
message: 'Ein Spieler mit dem Benutzernamen existiert bereits'
|
||||
});
|
||||
}
|
||||
|
||||
await db.editUser({
|
||||
id: input.id,
|
||||
firstname: input.firstname,
|
||||
lastname: input.lastname,
|
||||
birthday: input.birthday,
|
||||
telephone: input.telephone,
|
||||
username: input.username,
|
||||
uuid: input.uuid
|
||||
});
|
||||
}
|
||||
}),
|
||||
users: defineAction({
|
||||
input: z.object({
|
||||
username: z.string().nullish(),
|
||||
limit: z.number().optional()
|
||||
}),
|
||||
handler: async (input, context) => {
|
||||
Session.actionSessionFromCookies(context.cookies, Permissions.Users);
|
||||
|
||||
const users = await db.getUsers(input);
|
||||
|
||||
return {
|
||||
users: users
|
||||
};
|
||||
}
|
||||
})
|
||||
};
|
||||
Reference in New Issue
Block a user