Compare commits

..

2 commits

Author SHA1 Message Date
ad341d4208
add delete + split out UserService 2024-09-23 23:55:00 +01:00
9c43486406
update depends 2024-09-23 23:54:40 +01:00
11 changed files with 142 additions and 97 deletions

View file

@ -1,7 +1,7 @@
import { FastifyReply, FastifyRequest } from "fastify";
import Controller from "./Controller"; import Controller from "./Controller";
import UserService from "../services/UserService"; import UserService from "../services/UserService";
import HomeViewModel from "../models/home/HomeViewModel"; import HomeViewModel from "../models/home/HomeViewModel";
import PartyService from "../services/PartyService";
export default class HomeController extends Controller { export default class HomeController extends Controller {
public async Index_Get_AllowAnonymous() { public async Index_Get_AllowAnonymous() {
@ -11,7 +11,7 @@ export default class HomeController extends Controller {
return this.unauthorised(); return this.unauthorised();
} }
const parties = await UserService.GetUserParties(this.session.userId); const parties = await PartyService.GetUserParties(this.session.userId);
const activeUserParty = await UserService.GetActiveParty(this.session.userId); const activeUserParty = await UserService.GetActiveParty(this.session.userId);
const homeViewModel: HomeViewModel = { const homeViewModel: HomeViewModel = {

View file

@ -1,7 +1,9 @@
import CreateEditPartyViewModel from "../models/party/CreateEditPartyViewModel"; import CreateEditPartyViewModel from "../models/party/CreateEditPartyViewModel";
import DeletePartyModel from "../models/party/DeletePartyModel";
import JoinPartyViewModel from "../models/party/JoinPartyViewModel"; import JoinPartyViewModel from "../models/party/JoinPartyViewModel";
import LeavePartyModel from "../models/party/LeavePartyModel"; import LeavePartyModel from "../models/party/LeavePartyModel";
import SetActivePartyModel from "../models/party/SetActivePartyModel"; import SetActivePartyModel from "../models/party/SetActivePartyModel";
import PartyService from "../services/PartyService";
import UserService from "../services/UserService"; import UserService from "../services/UserService";
import Controller from "./Controller"; import Controller from "./Controller";
@ -15,13 +17,13 @@ export default class PartyController extends Controller {
return this.badRequest(); return this.badRequest();
} }
const party = await UserService.GetPartyByPartyRef(createEditPartyViewModel.partyRef); const party = await PartyService.GetPartyByPartyRef(createEditPartyViewModel.partyRef);
if (party) { if (party) {
createEditPartyViewModel.message = "That Party ID is already taken!"; createEditPartyViewModel.message = "That Party ID is already taken!";
return this.view("createEdit", createEditPartyViewModel); return this.view("createEdit", createEditPartyViewModel);
} }
await UserService.CreateParty(this.session.userId, createEditPartyViewModel.name, createEditPartyViewModel.partyRef); await PartyService.CreateParty(this.session.userId, createEditPartyViewModel.name, createEditPartyViewModel.partyRef);
return this.redirectToAction("index", "home"); return this.redirectToAction("index", "home");
} }
@ -35,7 +37,7 @@ export default class PartyController extends Controller {
return this.badRequest(); return this.badRequest();
} }
const party = await UserService.GetPartyByPartyRef(joinPartyViewModel.partyRef); const party = await PartyService.GetPartyByPartyRef(joinPartyViewModel.partyRef);
if (!party) { if (!party) {
joinPartyViewModel.message = "That Join Code / Party ID is invalid."; joinPartyViewModel.message = "That Join Code / Party ID is invalid.";
return this.view(joinPartyViewModel); return this.view(joinPartyViewModel);
@ -79,4 +81,15 @@ export default class PartyController extends Controller {
return this.redirectToAction("index", "home"); return this.redirectToAction("index", "home");
} }
public async Delete_Get(deletePartyModel:DeletePartyModel) {
const partyId = parseInt(deletePartyModel.id ?? "-1");
if (typeof(deletePartyModel.id) !== "string" || isNaN(partyId)) {
return this.badRequest();
}
await PartyService.DeleteParty(this.session.userId, partyId);
return this.redirectToAction("index", "home");
}
} }

View file

@ -39,6 +39,7 @@ import HomeController from "./controller/HomeController";
import AccountController from "./controller/AccountController"; import AccountController from "./controller/AccountController";
import PartyController from "./controller/PartyController"; import PartyController from "./controller/PartyController";
import ApiController from "./controller/ApiController"; import ApiController from "./controller/ApiController";
import PartyService from "./services/PartyService";
Console.customHeader(`MultiProbe server started at ${new Date()}`); Console.customHeader(`MultiProbe server started at ${new Date()}`);
@ -214,7 +215,7 @@ websocketServer.on("connection", (socket) => {
const dbUserParty = await UserService.GetActiveParty(dbUser.Id); const dbUserParty = await UserService.GetActiveParty(dbUser.Id);
let dbParty: Party | null = null; let dbParty: Party | null = null;
if (dbUserParty) { if (dbUserParty) {
dbParty = await UserService.GetParty(dbUserParty.PartyId); dbParty = await PartyService.GetParty(dbUserParty.PartyId);
} }
let page = rawURL.toLowerCase().replace(".htm", "").replace(".html", ""); let page = rawURL.toLowerCase().replace(".htm", "").replace(".html", "");

View file

@ -0,0 +1,3 @@
export default interface DeletePartyModel {
id: string
}

View file

@ -9,9 +9,9 @@
"version": "1.0.0", "version": "1.0.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@fastify/cookie": "^10.0.0", "@fastify/cookie": "^10.0.1",
"@fastify/formbody": "^8.0.0", "@fastify/formbody": "^8.0.1",
"@fastify/view": "^10.0.0", "@fastify/view": "^10.0.1",
"bufferstuff": "^1.5.1", "bufferstuff": "^1.5.1",
"ejs": "^3.1.10", "ejs": "^3.1.10",
"fastify": "^5.0.0", "fastify": "^5.0.0",
@ -22,11 +22,11 @@
}, },
"devDependencies": { "devDependencies": {
"@types/ejs": "^3.1.5", "@types/ejs": "^3.1.5",
"@types/node": "^22.5.5", "@types/node": "^22.6.0",
"@types/ws": "^8.5.12", "@types/ws": "^8.5.12",
"@vercel/ncc": "^0.38.1", "@vercel/ncc": "^0.38.2",
"check-outdated": "^2.12.0", "check-outdated": "^2.12.0",
"nodemon": "^3.1.6", "nodemon": "^3.1.7",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"terser": "^5.33.0", "terser": "^5.33.0",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
@ -57,9 +57,9 @@
} }
}, },
"node_modules/@fastify/cookie": { "node_modules/@fastify/cookie": {
"version": "10.0.0", "version": "10.0.1",
"resolved": "https://registry.npmjs.org/@fastify/cookie/-/cookie-10.0.0.tgz", "resolved": "https://registry.npmjs.org/@fastify/cookie/-/cookie-10.0.1.tgz",
"integrity": "sha512-S43spazwAfzm5nKlqq/spAGW+O6r+WQzg5vXXI1ArCXXFa8KBA/tiU3XRVQUehSNtbN5PA6+g183hzh5/dZ6Iw==", "integrity": "sha512-NV/wbCUv4ETJ5KM1KMu0fLx0nSCm9idIxwg66NZnNbfPQH3rdbx6k0qRs5uy0y+MhBgvDudYRA30KlK659chyw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"cookie-signature": "^1.2.1", "cookie-signature": "^1.2.1",
@ -82,9 +82,9 @@
} }
}, },
"node_modules/@fastify/formbody": { "node_modules/@fastify/formbody": {
"version": "8.0.0", "version": "8.0.1",
"resolved": "https://registry.npmjs.org/@fastify/formbody/-/formbody-8.0.0.tgz", "resolved": "https://registry.npmjs.org/@fastify/formbody/-/formbody-8.0.1.tgz",
"integrity": "sha512-iM9DLCwMnPx2gUu5HaPLylQox9ApPMFksf4Yw+1d2mWe7uvRDzg4/1BB1T19OjZK+UWZOQ7Q4o2FnoBQ973UMQ==", "integrity": "sha512-LPrcadSIK8TrQk510Zdj56fnw7cyHq0/PW0YHGGM8ycGL4X7XAex+FKcwpzB4i5lF9eykc71a4EtcO9AEoByqw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"fast-querystring": "^1.1.2", "fast-querystring": "^1.1.2",
@ -101,9 +101,9 @@
} }
}, },
"node_modules/@fastify/view": { "node_modules/@fastify/view": {
"version": "10.0.0", "version": "10.0.1",
"resolved": "https://registry.npmjs.org/@fastify/view/-/view-10.0.0.tgz", "resolved": "https://registry.npmjs.org/@fastify/view/-/view-10.0.1.tgz",
"integrity": "sha512-2KnfgpSbAImKV5kKdNAkSyjV+9kYUYLvgDLx/wlzgqel92bN9Z520cwG3g3bAkr0yVnEJu62dIm2qAL9FASS1w==", "integrity": "sha512-rXtBN0oVDmoRZAS7lelrCIahf+qFtlMOOas8VPdA7JvrJ9ChcF7e36pIUPU0Vbs3KmHxESUb7XatavUZEe/k5Q==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"fastify-plugin": "^5.0.0", "fastify-plugin": "^5.0.0",
@ -219,9 +219,9 @@
"dev": true "dev": true
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "22.5.5", "version": "22.6.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.6.0.tgz",
"integrity": "sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==", "integrity": "sha512-QyR8d5bmq+eR72TwQDfujwShHMcIrWIYsaQFtXRE58MHPTEKUNxjxvl0yS0qPMds5xbSDWtp7ZpvGFtd7dfMdQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -239,10 +239,11 @@
} }
}, },
"node_modules/@vercel/ncc": { "node_modules/@vercel/ncc": {
"version": "0.38.1", "version": "0.38.2",
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.38.1.tgz", "resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.38.2.tgz",
"integrity": "sha512-IBBb+iI2NLu4VQn3Vwldyi2QwaXt5+hTyh58ggAMoCGE6DJmPvwL3KPBWcJl1m9LYPChBLE980Jw+CS4Wokqxw==", "integrity": "sha512-3yel3jaxUg9pHBv4+KeC9qlbdZPug+UMtUOlhvpDYCMSgcNSrS2Hv1LoqMsOV7hf2lYscx+BESfJOIla1WsmMQ==",
"dev": true, "dev": true,
"license": "MIT",
"bin": { "bin": {
"ncc": "dist/ncc/cli.js" "ncc": "dist/ncc/cli.js"
} }
@ -1965,9 +1966,9 @@
"dev": true "dev": true
}, },
"node_modules/nodemon": { "node_modules/nodemon": {
"version": "3.1.6", "version": "3.1.7",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.6.tgz", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.7.tgz",
"integrity": "sha512-C8ymJbXpTTinxjWuMfMxw0rZhTn/r7ypSGldQyqPEgDEaVwAthqC0aodsMwontnAInN9TuPwRLeBoyhmfv+iSA==", "integrity": "sha512-hLj7fuMow6f0lbB0cD14Lz2xNjwsyruH251Pk4t/yIitCFJbmY1myuLlHm/q06aST4jg6EgAh74PIBBrRqpVAQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {

View file

@ -15,9 +15,9 @@
"author": "tgpholly", "author": "tgpholly",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@fastify/cookie": "^10.0.0", "@fastify/cookie": "^10.0.1",
"@fastify/formbody": "^8.0.0", "@fastify/formbody": "^8.0.1",
"@fastify/view": "^10.0.0", "@fastify/view": "^10.0.1",
"bufferstuff": "^1.5.1", "bufferstuff": "^1.5.1",
"ejs": "^3.1.10", "ejs": "^3.1.10",
"fastify": "^5.0.0", "fastify": "^5.0.0",
@ -28,11 +28,11 @@
}, },
"devDependencies": { "devDependencies": {
"@types/ejs": "^3.1.5", "@types/ejs": "^3.1.5",
"@types/node": "^22.5.5", "@types/node": "^22.6.0",
"@types/ws": "^8.5.12", "@types/ws": "^8.5.12",
"@vercel/ncc": "^0.38.1", "@vercel/ncc": "^0.38.2",
"check-outdated": "^2.12.0", "check-outdated": "^2.12.0",
"nodemon": "^3.1.6", "nodemon": "^3.1.7",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"terser": "^5.33.0", "terser": "^5.33.0",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",

View file

@ -48,7 +48,7 @@ export default class PartyRepo {
party.Name, party.PartyRef, party.CreatedByUserId, party.CreatedDatetime.getTime(), party.LastModifiedByUserId ?? null, party.LastModifiedDatetime?.getTime() ?? null, party.DeletedByUserId ?? null, party.DeletedDatetime?.getTime() ?? null, Number(party.IsDeleted) party.Name, party.PartyRef, party.CreatedByUserId, party.CreatedDatetime.getTime(), party.LastModifiedByUserId ?? null, party.LastModifiedDatetime?.getTime() ?? null, party.DeletedByUserId ?? null, party.DeletedDatetime?.getTime() ?? null, Number(party.IsDeleted)
]); ]);
} else { } else {
await Database.Instance.query(`UPDATE Party SET Name = ?, PartyRef = ?, CreatedByUserId = ?, CreatedDatetime = ?, LastModifiedByUserId = ?, LastModifiedDatetime = ?, DeletedByUserId = ?, DeletedDatetime = ?, IsDeleted = ?, WHERE Id = ?`, [ await Database.Instance.query("UPDATE Party SET Name = ?, PartyRef = ?, CreatedByUserId = ?, CreatedDatetime = ?, LastModifiedByUserId = ?, LastModifiedDatetime = ?, DeletedByUserId = ?, DeletedDatetime = ?, IsDeleted = ? WHERE Id = ?", [
party.Name, party.PartyRef, party.CreatedByUserId, party.CreatedDatetime.getTime(), party.LastModifiedByUserId ?? null, party.LastModifiedDatetime?.getTime() ?? null, party.DeletedByUserId ?? null, party.DeletedDatetime?.getTime() ?? null, Number(party.IsDeleted), party.Id party.Name, party.PartyRef, party.CreatedByUserId, party.CreatedDatetime.getTime(), party.LastModifiedByUserId ?? null, party.LastModifiedDatetime?.getTime() ?? null, party.DeletedByUserId ?? null, party.DeletedDatetime?.getTime() ?? null, Number(party.IsDeleted), party.Id
]); ]);
} }
@ -60,7 +60,7 @@ function populatePartyFromDB(party:Party, dbParty:any) {
party.PartyRef = dbParty.PartyRef; party.PartyRef = dbParty.PartyRef;
party.Name = dbParty.Name; party.Name = dbParty.Name;
party.CreatedByUserId = dbParty.CreatedByUserId; party.CreatedByUserId = dbParty.CreatedByUserId;
party.CreatedDatetime = dbParty.CreatedDatetime; party.CreatedDatetime = new Date(dbParty.CreatedDatetime);
party.LastModifiedByUserId = dbParty.LastModifiedByUserId; party.LastModifiedByUserId = dbParty.LastModifiedByUserId;
party.LastModifiedDatetime = RepoBase.convertNullableDatetimeIntToDate(dbParty.LastModifiedDatetime); party.LastModifiedDatetime = RepoBase.convertNullableDatetimeIntToDate(dbParty.LastModifiedDatetime);
party.DeletedByUserId = dbParty.DeletedByUserId; party.DeletedByUserId = dbParty.DeletedByUserId;

View file

@ -56,7 +56,7 @@ function populateUserFromDB(user:User, dbUser:any) {
user.PasswordSalt = dbUser.PasswordSalt; user.PasswordSalt = dbUser.PasswordSalt;
user.APIKey = dbUser.APIKey; user.APIKey = dbUser.APIKey;
user.CreatedByUserId = dbUser.CreatedByUserId; user.CreatedByUserId = dbUser.CreatedByUserId;
user.CreatedDatetime = dbUser.CreatedDatetime; user.CreatedDatetime = new Date(dbUser.CreatedDatetime);
user.LastModifiedByUserId = dbUser.LastModifiedByUserId; user.LastModifiedByUserId = dbUser.LastModifiedByUserId;
user.LastModifiedDatetime = RepoBase.convertNullableDatetimeIntToDate(dbUser.LastModifiedDatetime); user.LastModifiedDatetime = RepoBase.convertNullableDatetimeIntToDate(dbUser.LastModifiedDatetime);
user.DeletedByUserId = dbUser.DeletedByUserId; user.DeletedByUserId = dbUser.DeletedByUserId;

View file

@ -0,0 +1,84 @@
import { Console } from "hsconsole";
import PartyRepo from "../repos/PartyRepo";
import Party from "../entities/Party";
import UserParty from "../entities/UserParty";
import UserPartyRepo from "../repos/UserPartyRepo";
export default abstract class PartyService {
public static async CreateParty(currentUserId:number, name:string, partyRef:string) {
try {
const party = new Party();
party.Name = name;
party.PartyRef = partyRef;
party.CreatedByUserId = currentUserId;
party.CreatedDatetime = new Date();
await PartyRepo.insertUpdate(party);
const newParty = await PartyRepo.selectByPartyRef(partyRef);
if (!newParty) {
throw "This shouldn't happen";
}
const userParty = new UserParty();
userParty.UserId = currentUserId;
userParty.PartyId = newParty.Id;
userParty.CreatedByUserId = currentUserId;
userParty.CreatedDatetime = new Date();
await UserPartyRepo.insertUpdate(userParty);
} catch (e) {
Console.printError(`MultiProbe server service error:\n${e}`);
throw e;
}
}
public static async GetParty(id:number) {
try {
return await PartyRepo.selectById(id);
} catch (e) {
Console.printError(`MultiProbe server service error:\n${e}`);
throw e;
}
}
public static async GetPartyByPartyRef(partyRef:string) {
try {
return await PartyRepo.selectByPartyRef(partyRef);
} catch (e) {
Console.printError(`MultiProbe server service error:\n${e}`);
throw e;
}
}
public static async GetUserParties(userId:number) {
try {
return await PartyRepo.selectByUserId(userId);
} catch (e) {
Console.printError(`MultiProbe server service error:\n${e}`);
throw e;
}
}
public static async DeleteParty(currentUserId:number, partyId:number) {
try {
const party = await PartyRepo.selectById(partyId);
if (!party || party.CreatedByUserId !== currentUserId) {
return null;
}
console.log(party);
party.DeletedByUserId = currentUserId;
party.DeletedDatetime = new Date();
party.IsDeleted = true;
await PartyRepo.insertUpdate(party);
return party;
} catch (e) {
Console.printError(`MultiProbe server service error:\n${e}`);
throw e;
}
}
}

View file

@ -1,9 +1,7 @@
import { Console } from "hsconsole"; import { Console } from "hsconsole";
import User from "../entities/User"; import User from "../entities/User";
import PartyRepo from "../repos/PartyRepo";
import UserRepo from "../repos/UserRepo"; import UserRepo from "../repos/UserRepo";
import PasswordUtility from "../utilities/PasswordUtility"; import PasswordUtility from "../utilities/PasswordUtility";
import Party from "../entities/Party";
import UserParty from "../entities/UserParty"; import UserParty from "../entities/UserParty";
import UserPartyRepo from "../repos/UserPartyRepo"; import UserPartyRepo from "../repos/UserPartyRepo";
@ -53,15 +51,6 @@ export default class UserService {
} }
} }
public static async GetUserParties(userId:number) {
try {
return await PartyRepo.selectByUserId(userId);
} catch (e) {
Console.printError(`MultiProbe server service error:\n${e}`);
throw e;
}
}
public static async GetUserPartyForUser(userId:number, partyId:number) { public static async GetUserPartyForUser(userId:number, partyId:number) {
try { try {
return await UserPartyRepo.selectByUserIdPartyId(userId, partyId); return await UserPartyRepo.selectByUserIdPartyId(userId, partyId);
@ -71,24 +60,6 @@ export default class UserService {
} }
} }
public static async GetParty(id:number) {
try {
return await PartyRepo.selectById(id);
} catch (e) {
Console.printError(`MultiProbe server service error:\n${e}`);
throw e;
}
}
public static async GetPartyByPartyRef(partyRef:string) {
try {
return await PartyRepo.selectByPartyRef(partyRef);
} catch (e) {
Console.printError(`MultiProbe server service error:\n${e}`);
throw e;
}
}
public static async CreateUser(currentUserId:number, username:string, password:string) { public static async CreateUser(currentUserId:number, username:string, password:string) {
try { try {
const user = new User(); const user = new User();
@ -105,34 +76,6 @@ export default class UserService {
} }
} }
public static async CreateParty(currentUserId:number, name:string, partyRef:string) {
try {
const party = new Party();
party.Name = name;
party.PartyRef = partyRef;
party.CreatedByUserId = currentUserId;
party.CreatedDatetime = new Date();
await PartyRepo.insertUpdate(party);
const newParty = await PartyRepo.selectByPartyRef(partyRef);
if (!newParty) {
throw "This shouldn't happen";
}
const userParty = new UserParty();
userParty.UserId = currentUserId;
userParty.PartyId = newParty.Id;
userParty.CreatedByUserId = currentUserId;
userParty.CreatedDatetime = new Date();
await UserPartyRepo.insertUpdate(userParty);
} catch (e) {
Console.printError(`MultiProbe server service error:\n${e}`);
throw e;
}
}
public static async AddUserToParty(userId:number, partyId:number) { public static async AddUserToParty(userId:number, partyId:number) {
try { try {
const userParty = new UserParty(); const userParty = new UserParty();

View file

@ -37,7 +37,7 @@
<a href="/party/setactive?id=<%= party.Id %>" class="btn btn-sm btn-success me-2">Set Current</a> <a href="/party/setactive?id=<%= party.Id %>" class="btn btn-sm btn-success me-2">Set Current</a>
<% } %> <% } %>
<% if (party.CreatedByUserId === user.Id) { %> <% if (party.CreatedByUserId === user.Id) { %>
<a class="btn btn-sm btn-danger disabled" title="You may not leave a party if you created it." onclick="alert('You may not leave a party if you created it.')">Leave</a> <a href="/party/delete?id=<%= party.Id %>" class="btn btn-sm btn-danger" onclick="return confirm(`Are you sure you want to delete '<%= party.Name %>'?\nThis will remove all users in this party from it.\nThis action cannot be undone.`)">Delete</a>
<% } else { %> <% } else { %>
<a href="/party/leave?id=<%= party.Id %>" class="btn btn-sm btn-danger" onclick="return confirm(`Are you sure you want to leave '<%= party.Name %>'?`)">Leave</a> <a href="/party/leave?id=<%= party.Id %>" class="btn btn-sm btn-danger" onclick="return confirm(`Are you sure you want to leave '<%= party.Name %>'?`)">Leave</a>
<% } %> <% } %>