Skip to content

Commit

Permalink
feat: added edit/delete user;
Browse files Browse the repository at this point in the history
  • Loading branch information
ncoonrod committed Jan 22, 2024
1 parent b180ce5 commit 21c140c
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 22 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@hotstaq/userroute",
"description": "A user route for HotStaq. Allows users to be created/edited/deleted securely.",
"version": "0.4.3",
"version": "0.4.4",
"main": "build/src/index.js",
"scripts": {
"test": "hotstaq --dev --env-file .env run --server-type api --api-test",
Expand Down
87 changes: 71 additions & 16 deletions src/AdminRoute.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { HotRoute, ServerRequest, HotTestDriver, HotStaq, HotServerType, HotDBMySQL, ConnectionStatus, HotAPI } from "hotstaq";
import { IJWTToken, IUser, User } from "./User";
import { UserRoute } from "./UserRoute";
import { PassType } from "hotstaq/build/src/HotRouteMethod";
import { HotRouteMethodParameter, PassType } from "hotstaq/build/src/HotRouteMethod";

/**
* Admin route.
Expand All @@ -17,6 +17,43 @@ export class AdminRoute extends UserRoute
{
super (api, "admins");

let userObjectDesc: HotRouteMethodParameter = {
"type": "object",
"description": "The user object.",
// @ts-ignore
"parameters": await HotStaq.convertInterfaceToRouteParameters (ppath.normalize (`${__dirname}/../../src/User.ts`), "IUser")
};

this.addMethod ({
"name": "editUser",
"onServerExecute": this.editUser,
"description": `Edit a user. The id set in the user object that is passed will be the id of the user that is edited.`,
"parameters": {
"user": userObjectDesc
},
"returns": "Returns true if the user was edited.",
"testCases": [
"editUserTest",
async (driver: HotTestDriver): Promise<any> =>
{
}
]
});
this.addMethod ({
"name": "deleteUser",
"onServerExecute": this.deleteUser,
"description": `Delete a user. The id set in the user object that is passed will be the id of the user that is deleted.`,
"parameters": {
"user": userObjectDesc
},
"returns": "Returns true if the user was deleted.",
"testCases": [
"deleteUserTest",
async (driver: HotTestDriver): Promise<any> =>
{
}
]
});
this.addMethod ({
"name": "listUsers",
"onServerExecute": this.listUsers,
Expand Down Expand Up @@ -68,27 +105,45 @@ export class AdminRoute extends UserRoute
}

/**
* List users.
* Edit a user.
*
* **WARNING:** By default, this method can be used by anyone. To
* prevent this, use "onServerPreExecute" to check the user's permissions.
* For better performance, be sure to use User.decodeJWTToken in onServerPreExecute
* to decode the JWT token and store the user in req.passObject.jsonObj. Without
* this, the user will be decoded twice.
* prevent this, use "onServerPreExecute" to check the user's permissions.
*/
protected async listUsers (req: ServerRequest): Promise<any>
protected async editUser (req: ServerRequest): Promise<boolean>
{
let user: IUser = null;
const userObj: IUser = HotStaq.getParam ("user", req.jsonObj);
const user: User = new User (userObj);

if (req.passObject.passType === PassType.Update)
user = req.passObject.jsonObj;
else
{
const jwtToken: string = HotStaq.getParam ("jwtToken", req.jsonObj);
let decoded: IJWTToken = await User.decodeJWTToken (jwtToken);
user = decoded.user;
}
await User.editUser (this.db, user);

return (true);
}

/**
* Delete a user.
*
* **WARNING:** By default, this method can be used by anyone. To
* prevent this, use "onServerPreExecute" to check the user's permissions.
*/
protected async deleteUser (req: ServerRequest): Promise<boolean>
{
const userObj: IUser = HotStaq.getParam ("user", req.jsonObj);
const user: User = new User (userObj);

await User.deleteUser (this.db, user);

return (true);
}

/**
* List users.
*
* **WARNING:** By default, this method can be used by anyone. To
* prevent this, use "onServerPreExecute" to check the user's permissions.
*/
protected async listUsers (req: ServerRequest): Promise<any>
{
const search: string = HotStaq.getParamDefault ("search", req.jsonObj, null);
const offset: number = HotStaq.getParamDefault ("offset", req.jsonObj, 0);
const limit: number = HotStaq.getParamDefault ("limit", req.jsonObj, 20);
Expand Down
25 changes: 20 additions & 5 deletions src/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ export interface IUser
* The user type.
*/
userType?: string;
/**
* The user's display name.
*/
displayName?: string;
/**
* The user's first name.
*/
Expand Down Expand Up @@ -127,6 +131,10 @@ export class User implements IUser
* The user type.
*/
userType: string;
/**
* The user's display name.
*/
displayName: string;
/**
* The user's first name.
*/
Expand Down Expand Up @@ -235,6 +243,7 @@ export class User implements IUser
this.enabled = user.enabled || true;
this.id = user.id || "";
this.userType = user.userType || "user";
this.displayName = user.displayName || "";
this.firstName = user.firstName || "";
this.lastName = user.lastName || "";
this.email = user.email || "";
Expand All @@ -260,6 +269,7 @@ export class User implements IUser
`create table if not exists users (
id BINARY(16) NOT NULL,
userType VARCHAR(256) DEFAULT 'user',
displayName VARCHAR(256) DEFAULT '',
firstName VARCHAR(256) DEFAULT '',
lastName VARCHAR(256) DEFAULT '',
email VARCHAR(256) DEFAULT '',
Expand All @@ -268,6 +278,7 @@ export class User implements IUser
verifyCode VARCHAR(256) DEFAULT '',
verified TINYINT(1) DEFAULT '0',
registeredDate DATETIME DEFAULT NOW(),
deletionDate DATETIME DEFAULT NULL,
enabled TINYINT(1) DEFAULT '1',
PRIMARY KEY (id)
)`);
Expand All @@ -291,20 +302,23 @@ export class User implements IUser
new User ({
firstName: "John",
lastName: "Doe",
displayName: "Test1",
email: "test1@freelight.org",
password: "a867h398jdg",
verified: true
}),
new User ({
firstName: "Jane",
lastName: "Smith",
displayName: "Test2",
email: "test2@freelight.org",
password: "ai97w3a98w3498",
verified: true }),
new User ({
userType: "admin",
firstName: "Bob",
lastName: "Derp",
displayName: "Admin1",
email: "admin1@freelight.org",
password: "a98j3w987aw3h47u",
verified: true })
Expand Down Expand Up @@ -391,9 +405,9 @@ export class User implements IUser
}

let result: any = await db.queryOne (
`INSERT INTO users (id, userType, firstName, lastName, email, password, passwordSalt, verifyCode, verified)
VALUES (UNHEX(REPLACE(UUID(),'-','')), ?, ?, ?, ?, ?, ?, ?, ?) returning id;`,
[this.userType, this.firstName, this.lastName, this.email, hash, salt, verificationCode, verified]);
`INSERT INTO users (id, userType, displayName, firstName, lastName, email, password, passwordSalt, verifyCode, verified)
VALUES (UNHEX(REPLACE(UUID(),'-','')), ?, ?, ?, ?, ?, ?, ?, ?, ?) returning id;`,
[this.userType, this.displayName, this.firstName, this.lastName, this.email, hash, salt, verificationCode, verified]);

if (result.error != null)
throw new Error (result.error);
Expand Down Expand Up @@ -431,8 +445,8 @@ export class User implements IUser
static async editUser (db: HotDBMySQL, user: User): Promise<void>
{
let result: any = await db.queryOne (
`UPDATE users SET userType = ?, firstName = ?, lastName = ?, email = ?, verified = ? WHERE id = UNHEX(REPLACE(?, '-', ''));`,
[user.userType, user.firstName, user.lastName, user.email, user.verified, user.id]);
`UPDATE users SET userType = ?, displayName = ?, firstName = ?, lastName = ?, email = ?, verified = ? WHERE id = UNHEX(REPLACE(?, '-', ''));`,
[user.userType, user.displayName, user.firstName, user.lastName, user.email, user.verified, user.id]);

if (result.error != null)
throw new Error (result.error);
Expand Down Expand Up @@ -721,6 +735,7 @@ export class User implements IUser
let user: User = new User ({
id: userId,
userType: result["userType"],
displayName: result["displayName"],
firstName: result["firstName"],
lastName: result["lastName"],
email: result["email"],
Expand Down

0 comments on commit 21c140c

Please sign in to comment.