-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add console logs for permissions
- Loading branch information
1 parent
82e693b
commit 3928982
Showing
10 changed files
with
376 additions
and
71 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import {PermissionCollector, PermissionController, PermissionError, Reason} from "../src/lib/PermissionController"; | ||
import {Config} from "../src/lib/Config"; | ||
import CooldownPermission from "../src/lib/permissions/CooldownPermission"; | ||
import ModeratorPermission from "../src/lib/permissions/ModeratorPermission"; | ||
import OwnerPermission from "../src/lib/permissions/OwnerPermission"; | ||
import {RuntimeInformation} from "../src/lib/RuntimeInformation"; | ||
import TwitchPrivateMessage from "twitch-chat-client/lib/StandardCommands/TwitchPrivateMessage"; | ||
|
||
const Fs = require("fs"); | ||
const _ = require("lodash"); | ||
|
||
let config: Config; | ||
let permissionController: PermissionController; | ||
|
||
beforeAll(() => { | ||
config = loadConfig(); | ||
permissionController = new PermissionController() | ||
.withPermissionInstance(new CooldownPermission()) | ||
.withPermissionInstance(new ModeratorPermission()) | ||
.withPermissionInstance(new OwnerPermission()); | ||
}) | ||
|
||
test("Permission collector denies permission", () => { | ||
|
||
let permissionCollector = new PermissionCollector(); | ||
permissionCollector.denyPermission("test", "i want to"); | ||
|
||
expect(permissionCollector.permissionDenied).toBe(true); | ||
expect(permissionCollector.godMode).toBe(false); | ||
expect(permissionCollector.permissionDeniedReasons).toContainEqual(new Reason("test", "i want to")); | ||
expect(permissionCollector.godModeReasons.length).toBe(0); | ||
}); | ||
|
||
test("Permission collector grants permission b/c of godMode", () => { | ||
|
||
let permissionCollector = new PermissionCollector(); | ||
permissionCollector.denyPermission("test", "i want to"); | ||
permissionCollector.enableGodMode("i know why"); | ||
|
||
expect(permissionCollector.permissionDenied).toBe(false); | ||
expect(permissionCollector.godMode).toBe(true); | ||
expect(permissionCollector.permissionDeniedReasons).toContainEqual(new Reason("test", "i want to")); | ||
expect(permissionCollector.godModeReasons).toContainEqual("i know why"); | ||
}); | ||
|
||
test("Permission collector's god mode cannot be overwritten", () => { | ||
let permissionCollector = new PermissionCollector(); | ||
permissionCollector.denyPermission("test", "i want to"); | ||
|
||
expect(permissionCollector.permissionDenied).toBe(true); | ||
expect(permissionCollector.godMode).toBe(false); | ||
|
||
permissionCollector.enableGodMode("i know why"); | ||
|
||
expect(permissionCollector.permissionDenied).toBe(false); | ||
expect(permissionCollector.godMode).toBe(true); | ||
|
||
permissionCollector.denyPermission("test2", "i still want to!"); | ||
|
||
expect(permissionCollector.permissionDenied).toBe(false); | ||
expect(permissionCollector.godMode).toBe(true); | ||
|
||
expect(permissionCollector.permissionDeniedReasons).toContainEqual(new Reason("test", "i want to")); | ||
expect(permissionCollector.permissionDeniedReasons).toContainEqual(new Reason("test2", "i still want to!")); | ||
|
||
expect(permissionCollector.godModeReasons).toContainEqual("i know why"); | ||
}); | ||
|
||
test("Permission denied b/c of active cooldown", () => { | ||
|
||
permissionController.setAdditionalRuntimeInformation("lastCall", new Date().getTime() - 10000); | ||
|
||
let rawMessage = new TwitchPrivateMessage("doesNotMatter", null, null, {nick: "Alice"}); | ||
|
||
return expect(permissionController.checkPermissions(new RuntimeInformation(config, "Alice", | ||
rawMessage))).rejects.toBeInstanceOf(PermissionError); | ||
}); | ||
|
||
test("Permission granted b/c user is moderator", async () => { | ||
|
||
permissionController.setAdditionalRuntimeInformation("lastCall", new Date().getTime() - 10000); | ||
|
||
let rawMessage = new TwitchPrivateMessage("doesNotMatter", null, new Map([["badges", "moderator"]]), {nick: "Alice"}); | ||
let permissionCollector = await permissionController.checkPermissions(new RuntimeInformation(config, "Alice", rawMessage)); | ||
|
||
expect(permissionCollector.godModeReasons).toContain("user is moderator"); | ||
}); | ||
|
||
test("Permission granted b/c user is owner", async () => { | ||
|
||
permissionController.setAdditionalRuntimeInformation("lastCall", new Date().getTime() - 10000); | ||
|
||
let rawMessage = new TwitchPrivateMessage("doesNotMatter", null, null, {nick: "Alice"}); | ||
let permissionCollector = await permissionController.checkPermissions(new RuntimeInformation( | ||
loadConfig({twitch: {channel: "Alice", clientId: "clientId", accessToken: "accessToken"}}), | ||
"Alice", rawMessage)) | ||
|
||
expect(permissionCollector.godModeReasons).toContain("user is channel owner"); | ||
}); | ||
|
||
function loadConfig(overrideConfigValues?: any): Config { | ||
return new Config(_.assign({}, JSON.parse(Fs.readFileSync("config.json.sample", {encoding: "utf-8"})), overrideConfigValues)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import {RuntimeInformation} from "./RuntimeInformation"; | ||
|
||
export interface PermissionInstance { | ||
check(permissionCollector: PermissionCollector, | ||
runtimeInformation: RuntimeInformation, | ||
additionalRuntimeInformation: Map<String, any>): void; | ||
} | ||
|
||
export class PermissionError extends Error { | ||
|
||
readonly permissionCollector: PermissionCollector; | ||
|
||
constructor(permissionCollector: PermissionCollector) { | ||
super(); | ||
this.permissionCollector = permissionCollector; | ||
Object.setPrototypeOf(this, PermissionError.prototype); | ||
this.name = PermissionError.name; | ||
} | ||
} | ||
|
||
export class Reason { | ||
public readonly name: string; | ||
public readonly viewerMessage: string; | ||
|
||
constructor(name: string, viewerMessage: string) { | ||
this.name = name; | ||
this.viewerMessage = viewerMessage; | ||
} | ||
} | ||
|
||
export class PermissionController { | ||
|
||
private readonly permissionInstances: Array<PermissionInstance>; | ||
private readonly additionalRuntimeInformation: Map<String, any>; | ||
|
||
constructor() { | ||
this.permissionInstances = []; | ||
this.additionalRuntimeInformation = new Map(); | ||
} | ||
|
||
withPermissionInstance(instance: PermissionInstance): PermissionController { | ||
this.permissionInstances.push(instance); | ||
return this; | ||
} | ||
|
||
async checkPermissions(runtimeInformation: RuntimeInformation) { | ||
|
||
let permissionCollector = new PermissionCollector(); | ||
for (const permissionInstance of this.permissionInstances) { | ||
permissionInstance.check(permissionCollector, runtimeInformation, this.additionalRuntimeInformation); | ||
} | ||
|
||
if (permissionCollector.permissionDenied) { | ||
throw new PermissionError(permissionCollector); | ||
} | ||
|
||
return permissionCollector; | ||
} | ||
|
||
setAdditionalRuntimeInformation(name: string, value: any) { | ||
this.additionalRuntimeInformation.set(name, value); | ||
} | ||
} | ||
|
||
export class PermissionCollector { | ||
|
||
private _permissionDenied: boolean; | ||
private _godMode: boolean; | ||
|
||
private readonly _godModeReasons: Array<String>; | ||
private readonly _permissionDeniedReasons: Array<Reason>; | ||
|
||
constructor() { | ||
this._permissionDenied = false; | ||
this._godMode = false; | ||
this._godModeReasons = []; | ||
this._permissionDeniedReasons = []; | ||
} | ||
|
||
denyPermission(reason: string, message: string) { | ||
this._permissionDenied = !this._godMode; | ||
this._permissionDeniedReasons.push(new Reason(reason, message)); | ||
} | ||
|
||
enableGodMode(reason: string) { | ||
this._permissionDenied = false; | ||
this._godMode = true; | ||
this._godModeReasons.push(reason); | ||
} | ||
|
||
get permissionDenied(): boolean { | ||
return this._permissionDenied; | ||
} | ||
|
||
get permissionDeniedReasons(): Array<Reason> { | ||
return this._permissionDeniedReasons; | ||
} | ||
|
||
get godMode(): boolean { | ||
return this._godMode; | ||
} | ||
|
||
get godModeReasons(): Array<String> { | ||
return this._godModeReasons; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import {Config} from "./Config"; | ||
import TwitchPrivateMessage from "twitch-chat-client/lib/StandardCommands/TwitchPrivateMessage"; | ||
|
||
export class RuntimeInformation { | ||
|
||
public readonly config: Config; | ||
public readonly userName: string; | ||
public readonly rawMessage: TwitchPrivateMessage; | ||
|
||
constructor(config: Config, userName: string, rawMessage: TwitchPrivateMessage) { | ||
this.config = config; | ||
this.userName = userName; | ||
this.rawMessage = rawMessage; | ||
} | ||
} |
Oops, something went wrong.