From a98b61b5f047535b696dda2136299f8fd199f123 Mon Sep 17 00:00:00 2001 From: Allen Lantz Date: Tue, 31 Oct 2023 21:32:50 -0500 Subject: [PATCH] Promo codes --- src/BloxAdmin.ts | 2 ++ src/RemoteMessaging.ts | 9 ++++++++ src/consts.ts | 2 +- src/modules/Moderation.ts | 24 ++++++++++---------- src/modules/PromoCodes.ts | 47 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 71 insertions(+), 13 deletions(-) create mode 100644 src/modules/PromoCodes.ts diff --git a/src/BloxAdmin.ts b/src/BloxAdmin.ts index 17e74fe..5eb42f7 100644 --- a/src/BloxAdmin.ts +++ b/src/BloxAdmin.ts @@ -26,6 +26,7 @@ importTime("DebugUI"); import Metrics from "modules/Metrics"; importTime("Metrics"); import Moderation from "modules/Moderation"; +import PromoCodes from "modules/PromoCodes"; importTime("Moderation"); import RemoteConfig from "modules/RemoteConfig"; importTime("RemoteConfig"); @@ -141,6 +142,7 @@ export class BloxAdmin extends EventEmitter<{ ready: [] }> { this.loadModule(() => new Moderation(this)); this.loadModule(() => new Actions(this)); this.loadModule(() => new Metrics(this)); + this.loadModule(() => new PromoCodes(this)); this.logger.debug(`Loaded modules in ${os.clock() - loadStart}s`); this.messenger.on("message", (message) => { diff --git a/src/RemoteMessaging.ts b/src/RemoteMessaging.ts index 9294ec7..3d9f229 100644 --- a/src/RemoteMessaging.ts +++ b/src/RemoteMessaging.ts @@ -165,6 +165,15 @@ export default class RemoteMessaging extends EventEmitter<{ }); } + public put(url: string, body: unknown) { + return HttpService.RequestAsync({ + Method: "PUT", + Headers: this.reqHeaders(), + Url: url, + Body: HttpService.JSONEncode(body), + }); + } + public async setup(): Promise { const result = this.get(this.url); diff --git a/src/consts.ts b/src/consts.ts index f60bc76..4836ab4 100644 --- a/src/consts.ts +++ b/src/consts.ts @@ -1,6 +1,6 @@ import { Config } from "types"; -export const BLOXADMIN_VERSION = 123; +export const BLOXADMIN_VERSION = 124; export const DEFAULT_CONFIG: Config = { api: { diff --git a/src/modules/Moderation.ts b/src/modules/Moderation.ts index e00d1f4..c977d10 100644 --- a/src/modules/Moderation.ts +++ b/src/modules/Moderation.ts @@ -115,10 +115,10 @@ export default class Moderation extends Module<{ switch (moderationType) { case ModerationType.Kick: - this.kick(player, reason); + this._kick(player, reason); break; case ModerationType.Mute: - this.mute(player, untilTime, reason, realDuration); + this._mute(player, untilTime, reason, realDuration); break; case ModerationType.Unmute: this.unmute(player, reason); @@ -161,7 +161,7 @@ export default class Moderation extends Module<{ spawn(() => { delay(1, () => { - this.unmuteCheck(true) + this._unmuteCheck(true) }); }) } @@ -185,12 +185,12 @@ export default class Moderation extends Module<{ return ChatService; } - kick(player: Player, reason?: string) { + private _kick(player: Player, reason?: string) { this.logger.info(`Kicking ${player.Name} for ${reason}`); player.Kick(reason); } - private muteLegacy(player: Player, seconds?: number, reason?: string) { + private _muteLegacy(player: Player, seconds?: number, reason?: string) { const ChatService = this.chatService() if (!ChatService) return; @@ -209,7 +209,7 @@ export default class Moderation extends Module<{ // Chat - unmuteCheck(loop = false) { + private _unmuteCheck(loop = false) { for (const [playerId, untilTime] of pairs(this.playersMutedUntil)) { if (untilTime !== -1 && untilTime < os.time()) { const player = Players.GetPlayerByUserId(playerId); @@ -220,11 +220,11 @@ export default class Moderation extends Module<{ if (loop) delay(1, () => { - this.unmuteCheck(true) + this._unmuteCheck(true) }); } - isPlayerMuted(player: Player | number) { + private _isPlayerMuted(player: Player | number) { const playerId = typeIs(player, "number") ? player : player.UserId; return this.playersMutedUntil[playerId] && (this.playersMutedUntil[playerId] === -1 || this.playersMutedUntil[playerId] > os.time()); } @@ -237,7 +237,7 @@ export default class Moderation extends Module<{ const player = Players.GetPlayerByUserId(playerId); if (!player) return true; - const isMuted = this.isPlayerMuted(player); + const isMuted = this._isPlayerMuted(player); if (isMuted && (!this.lastNotifiedMuted[playerId] || this.lastNotifiedMuted[playerId] + NOTIFICATION_COOLDOWN < os.time())) { this.lastNotifiedMuted[playerId] = os.time(); @@ -245,7 +245,7 @@ export default class Moderation extends Module<{ } else if (!isMuted && message.TextChannel && message.TextChannel.Name.sub(1, 10) === "RBXWhisper") { const destinationPlayer = Players.GetPlayerByUserId(destination.UserId); if (destinationPlayer) { - const destinationIsMuted = this.isPlayerMuted(destinationPlayer); + const destinationIsMuted = this._isPlayerMuted(destinationPlayer); if (destinationIsMuted) { this.systemMessageEvent.FireClient(player, "The player you are trying to whisper is muted and cannot respond."); @@ -257,14 +257,14 @@ export default class Moderation extends Module<{ } } - mute(player: Player, untilTime?: number, reason?: string, realDuration?: number) { + private _mute(player: Player, untilTime?: number, reason?: string, realDuration?: number) { this.logger.info(`Muting ${player.Name} for ${reason} until ${untilTime}`); this.playersMutedUntil[player.UserId] = untilTime || -1; const seconds = untilTime ? untilTime - os.time() : undefined; if (TextChatService.ChatVersion === Enum.ChatVersion.LegacyChatService) { - this.muteLegacy(player, seconds, reason); + this._muteLegacy(player, seconds, reason); return; } const r = reason ? ` for ${reason}` : ""; diff --git a/src/modules/PromoCodes.ts b/src/modules/PromoCodes.ts new file mode 100644 index 0000000..f768a4d --- /dev/null +++ b/src/modules/PromoCodes.ts @@ -0,0 +1,47 @@ +import { BloxAdmin } from "BloxAdmin"; +import { Module } from "Module"; + +const HttpService = game.GetService("HttpService"); + +export interface CreatePromoCode { + attributes: Record; + uses?: number; + active: boolean; + starts?: string; + expires?: string; +} + +export interface PromoCode extends CreatePromoCode { + code: string; + used: number; + created: string; +} + + +export default class PromoCodes extends Module { + constructor(admin: BloxAdmin) { + super("PromoCodes", admin); + } + + enable(): void { } + + ClaimCode(player: Player | number, code: string): Promise { + return new Promise((resolve, reject) => { + const playerId = typeIs(player, "number") ? player : player.UserId; + + const url = `${this.admin.config.api.base}/games/${game.GameId}/codes/${code}/uses/${playerId}` + + this.logger.debug("PUT to " + url); + + const response = this.admin.messenger.put(url, { + serverId: this.admin.serverId(), + }); + + if (!response.Success) { + return reject(response.Body); + } + + return resolve(HttpService.JSONDecode(response.Body) as PromoCode); + }); + } +}