From 8796dc436eefca9068a7734e2115b14e91b95df8 Mon Sep 17 00:00:00 2001 From: Christopher Renaud Oelerich Date: Fri, 2 Feb 2024 00:38:45 -0600 Subject: [PATCH] 5e 3.0 verified --- .github/workflows/foundry_release.py | 30 ++++++++++----------- module.json | 2 +- src/constants.mjs | 2 +- src/module.mjs | 8 +++--- src/settings-form-application.mjs | 24 ++++++++--------- src/settings.mjs | 8 +++--- src/sync.mjs | 40 +++++++++++++++------------- src/util.mjs | 20 +++++++------- 8 files changed, 68 insertions(+), 66 deletions(-) diff --git a/.github/workflows/foundry_release.py b/.github/workflows/foundry_release.py index a77e05e..ec08419 100644 --- a/.github/workflows/foundry_release.py +++ b/.github/workflows/foundry_release.py @@ -21,7 +21,7 @@ CHANGES = os.environ['CHANGES'] -def push_release(module): +def push_release(module: dict) -> None: conn = http.client.HTTPSConnection("api.foundryvtt.com") conn.request( "POST", "/_api/packages/release_version/", @@ -44,14 +44,14 @@ def push_release(module): raise Exception(pprint.pformat(response_json['errors'])) -def get_readme_as_html(): +def get_readme_as_html() -> str: md = MarkdownIt('commonmark', {'html': True}).enable('table') with open('./README.md', 'r') as readme_file: readme = readme_file.read() return md.render(readme) -def get_root(): +def get_tokens() -> (str, str): conn = http.client.HTTPSConnection('foundryvtt.com') conn.request('GET', '/', headers={}) response = conn.getresponse() @@ -62,7 +62,7 @@ def get_root(): return csrf_token, csrf_middleware_token -def post_auth_login(csrf_token, csrf_middleware_token): +def get_session_id(csrf_token: str, csrf_middleware_token: str) -> str: body = urlencode({ 'csrfmiddlewaretoken': csrf_middleware_token, 'username': FOUNDRY_USERNAME, @@ -85,7 +85,7 @@ def post_auth_login(csrf_token, csrf_middleware_token): return session_id -def extract_errorlist_text(html_string): +def extract_errorlist_text(html_string: str) -> str: class ErrorListParser(HTMLParser): in_errorlist = False errorlist_content = [] @@ -109,7 +109,7 @@ def handle_data(self, data): return parser.errorlist_content -def post_packages_oronder_edit(csrf_token, csrf_middleware_token, session_id, description, module): +def post_packages_oronder_edit(csrf_token, csrf_middleware_token, session_id, description, module) -> None: conn = http.client.HTTPSConnection('foundryvtt.com') headers = { 'Referer': 'https://foundryvtt.com/packages/oronder/edit', @@ -132,11 +132,10 @@ def post_packages_oronder_edit(csrf_token, csrf_middleware_token, session_id, de response = conn.getresponse() if response.status != 302: content = response.read().decode() - err_msg = f'Update Description Failed\n{extract_errorlist_text(content)}' - raise Exception(err_msg) + raise Exception(f'Update Description Failed\n{extract_errorlist_text(content)}') -def post_update(version): +def post_update(version) -> None: conn = http.client.HTTPSConnection("api.oronder.com") conn.request( "POST", '/update_discord', @@ -150,25 +149,24 @@ def post_update(version): if response.status != 200: content = response.read().decode() headers = response.headers.as_string() - err_msg = f'Failed to send Update Message to Discord\n{content=}\n{headers=}' - raise Exception(err_msg) + raise Exception(f'Failed to send Update Message to Discord\n{content=}\n{headers=}') def main(): with open('./module.json', 'r') as file: module_json = json.load(file) - csrf_token, csrf_middleware_token = get_root() - session_id = post_auth_login(csrf_token, csrf_middleware_token) + csrf_token, csrf_middleware_token = get_tokens() + session_id = get_session_id(csrf_token, csrf_middleware_token) readme = get_readme_as_html() post_packages_oronder_edit(csrf_token, csrf_middleware_token, session_id, readme, module_json) - print('REPO DESCRIPTION UPDATED') + print('\n__REPO DESCRIPTION UPDATED__\n') push_release(module_json) - print('MODULE POSTED TO REPO') + print('\n__MODULE POSTED TO REPO__\n') post_update(module_json['version']) - print('DISCORD NOTIFIED OF NEW RELEASE') + print('\n__DISCORD NOTIFIED OF NEW RELEASE__\n') if __name__ == '__main__': diff --git a/module.json b/module.json index 514da69..62b2596 100644 --- a/module.json +++ b/module.json @@ -22,7 +22,7 @@ "manifest": "https://raw.githubusercontent.com/foundryvtt/dnd5e/master/system.json", "compatibility": { "minimum": "2.4.0", - "verified": "2.4.1" + "verified": "3.0.0" } } ] diff --git a/src/constants.mjs b/src/constants.mjs index 4119d5f..6e3eb84 100644 --- a/src/constants.mjs +++ b/src/constants.mjs @@ -4,7 +4,7 @@ export const MODULE_DEBUG_TAG = [ `%c${MODULE_NAME}`, `color: #66023c; font-weight: bold;`, `|`, -]; +] export const GUILD_NAME = "guild_name" export const AUTH = "auth" diff --git a/src/module.mjs b/src/module.mjs index 269dad8..5a1f577 100644 --- a/src/module.mjs +++ b/src/module.mjs @@ -78,20 +78,20 @@ export function open_socket_with_oronder(update = false) { }) socket.on('connect_error', (error) => { - Logger.warn(`Oronder Websocket connection failed: ${error.message}`); + Logger.warn(`Oronder Websocket connection failed: ${error.message}`) }) socket.on('connect', () => { Logger.info('Oronder Websocket connection established.') }) - socket.on('xp', data => { + socket.on('xp', async data => { for (const [actor_id, xp] of Object.entries(data)) { const actor = game.actors.get(actor_id) if (actor === undefined) { Logger.warn(`Failed to update XP. No Actor with ID ${actor_id} found!`) } else { Logger.info(`${actor.name} xp: ${actor.system.details.xp.value} -> ${xp}`) - actor.update({"system.details.xp.value": xp}) + await actor.update({"system.details.xp.value": xp}) } } }) @@ -106,7 +106,7 @@ game.socket.on(SOCKET_NAME, data => { case 'session': { set_session(data.session) } - break; + break } }) diff --git a/src/settings-form-application.mjs b/src/settings-form-application.mjs index 5766ed8..d39af0f 100644 --- a/src/settings-form-application.mjs +++ b/src/settings-form-application.mjs @@ -1,7 +1,7 @@ -import {Logger} from "./util.mjs"; -import {AUTH, GUILD_NAME, ID_MAP, MODULE_ID, ORONDER_BASE_URL, VALID_CONFIG} from "./constants.mjs"; -import {full_sync} from "./sync.mjs"; -import {open_socket_with_oronder} from "./module.mjs"; +import {Logger} from "./util.mjs" +import {AUTH, GUILD_NAME, ID_MAP, MODULE_ID, ORONDER_BASE_URL, VALID_CONFIG} from "./constants.mjs" +import {full_sync} from "./sync.mjs" +import {open_socket_with_oronder} from "./module.mjs" export class OronderSettingsFormApplication extends FormApplication { @@ -22,8 +22,8 @@ export class OronderSettingsFormApplication extends FormApplication { foundry_id: user.id, discord_id: id_map[user.id] ?? '' })) - }); - super(object, options); + }) + super(object, options) } static get defaultOptions() { @@ -32,13 +32,13 @@ export class OronderSettingsFormApplication extends FormApplication { template: `modules/${MODULE_ID}/templates/settings-form-application.hbs`, width: 580, resizable: true - }); + }) } /** @override */ get title() { - return game.i18n.localize("oronder.Oronder-Bot-Config"); + return game.i18n.localize("oronder.Oronder-Bot-Config") } /** @override */ @@ -48,14 +48,14 @@ export class OronderSettingsFormApplication extends FormApplication { /** @override */ activateListeners(html) { - super.activateListeners(html); - html.find(".control").on("click", this._onClickControl.bind(this)); + super.activateListeners(html) + html.find(".control").on("click", this._onClickControl.bind(this)) } _onClickControl(event) { switch (event.currentTarget.dataset.action) { case "fetch": - return this._fetch_discord_ids(); + return this._fetch_discord_ids() case "sync-all": return this._full_sync() @@ -71,7 +71,7 @@ export class OronderSettingsFormApplication extends FormApplication { }), redirect: 'follow' } - }; + } /** @override */ async _updateObject(event, formData) { diff --git a/src/settings.mjs b/src/settings.mjs index 2c0cede..b285243 100644 --- a/src/settings.mjs +++ b/src/settings.mjs @@ -1,6 +1,6 @@ -import {AUTH, GUILD_NAME, ID_MAP, MODULE_ID, ORONDER_CONFIGURATION_FORM, VALID_CONFIG} from "./constants.mjs"; -import {Logger} from "./util.mjs"; -import {OronderSettingsFormApplication} from "./settings-form-application.mjs"; +import {AUTH, GUILD_NAME, ID_MAP, MODULE_ID, ORONDER_CONFIGURATION_FORM, VALID_CONFIG} from "./constants.mjs" +import {Logger} from "./util.mjs" +import {OronderSettingsFormApplication} from "./settings-form-application.mjs" export const registerSettings = async () => { game.settings.register(MODULE_ID, GUILD_NAME, { @@ -31,7 +31,7 @@ export const registerSettings = async () => { config: true, type: OronderSettingsFormApplication, restricted: true - }); + }) game.settings.register(MODULE_ID, VALID_CONFIG, { scope: "world", diff --git a/src/sync.mjs b/src/sync.mjs index 9a1a6b8..46c75a5 100644 --- a/src/sync.mjs +++ b/src/sync.mjs @@ -1,5 +1,5 @@ -import {ACTORS, AUTH, ID_MAP, MODULE_ID, ORONDER_BASE_URL} from "./constants.mjs"; -import {hash, Logger} from "./util.mjs"; +import {ACTORS, AUTH, ID_MAP, MODULE_ID, ORONDER_BASE_URL} from "./constants.mjs" +import {hash, Logger} from "./util.mjs" function prune_roll_data( { @@ -116,7 +116,7 @@ export function enrich_actor(actor) { let currency = actor.system['currency'] for (const key in currency) { if (currency.hasOwnProperty(key) && !currency[key]) { - currency[key] = 0; + currency[key] = 0 } } @@ -166,7 +166,7 @@ async function upload(pc) { headers: headers(), body: JSON.stringify(pc), redirect: 'follow' - }; + } return await fetch(`${ORONDER_BASE_URL}/actor`, requestOptions) } @@ -176,7 +176,7 @@ export async function del_actor(pc_id) { method: 'DELETE', headers: headers(), redirect: 'follow' - }; + } return await fetch(`${ORONDER_BASE_URL}/actor/${pc_id}`, requestOptions) } @@ -192,7 +192,7 @@ const actor_to_discord_ids = actor => export async function full_sync() { game.actors .filter(_ => localStorage.getItem(`${ACTORS}.${_.id}`)) - .forEach(_ => localStorage.removeItem(`${ACTORS}${_.id}`)) + .forEach(_ => localStorage.removeItem(`${ACTORS}.${_.id}`)) return Promise.all(game.actors.map(sync_actor)) } @@ -200,13 +200,13 @@ export async function sync_actor(actor) { if (actor.type !== "character") { Logger.info( `${game.i18n.localize("oronder.Skipping-Sync-For")} ${actor.name}. ${game.i18n.localize("oronder.NPC")}` - ); + ) return Promise.resolve() } if (!actor_to_discord_ids(actor).length) { Logger.info( `${game.i18n.localize("oronder.Skipping-Sync-For")} ${actor.name}. ${game.i18n.localize("oronder.No-Owner")}` - ); + ) return Promise.resolve() } @@ -215,41 +215,45 @@ export async function sync_actor(actor) { const new_hash = hash(actor_obj) if (old_hash && old_hash === new_hash) { - Logger.info(`${game.i18n.localize("oronder.Skipping-Sync-For")} ${actor_obj.name}. ${game.i18n.localize("oronder.No-Change")}`); + Logger.info(`${game.i18n.localize("oronder.Skipping-Sync-For")} ${actor_obj.name}. ${game.i18n.localize("oronder.No-Change")}`) return Promise.resolve() } if (!actor_obj.details.level) { - Logger.info(`${game.i18n.localize("oronder.Skipping-Sync-For")} ${actor_obj.name}. ${game.i18n.localize("oronder.No-Level")}`); + Logger.info(`${game.i18n.localize("oronder.Skipping-Sync-For")} ${actor_obj.name}. ${game.i18n.localize("oronder.No-Level")}`) return Promise.resolve() } if (!actor_obj.details.race) { - Logger.info(`${game.i18n.localize("oronder.Skipping-Sync-For")} ${actor_obj.name}. ${game.i18n.localize("oronder.No-Race")}`); + Logger.info(`${game.i18n.localize("oronder.Skipping-Sync-For")} ${actor_obj.name}. ${game.i18n.localize("oronder.No-Race")}`) return Promise.resolve() } if (!actor_obj.details.background) { - Logger.info(`${game.i18n.localize("oronder.Skipping-Sync-For")} ${actor_obj.name}. ${game.i18n.localize("oronder.No-Background")}`); + Logger.info(`${game.i18n.localize("oronder.Skipping-Sync-For")} ${actor_obj.name}. ${game.i18n.localize("oronder.No-Background")}`) return Promise.resolve() } if (!Object.keys(actor_obj.classes).length) { - Logger.info(`${game.i18n.localize("oronder.Skipping-Sync-For")} ${actor_obj.name}. ${game.i18n.localize("oronder.No-Class")}`); + Logger.info(`${game.i18n.localize("oronder.Skipping-Sync-For")} ${actor_obj.name}. ${game.i18n.localize("oronder.No-Class")}`) return Promise.resolve() } return upload(actor_obj).then(response => { if (response.ok) { localStorage.setItem(`${ACTORS}.${actor.id}`, new_hash) - Logger.info(`${game.i18n.localize("oronder.Synced")} ${actor_obj.name}`); + Logger.info(`${game.i18n.localize("oronder.Synced")} ${actor_obj.name}`) } else if (response.status === 422) { response .json() .then(({detail}) => Logger.error( - `${actor_obj.name} ${game.i18n.localize("oronder.Failed-To-Sync")}: ` + + `${actor_obj.name} ${game.i18n.localize("oronder.Failed-To-Sync")} ` + detail.flat().map(({loc, input, msg}) => - `${loc.filter(_ => _ !== 'body').join('->')}->${input} | ${msg}` - ).join(' ') + `❌ ${loc.filter(_ => _ !== 'body').join('>')}>${input} ${msg}` + ).join(' '), + {permanent: true} )) } else { - Logger.error(`${actor_obj.name} ${game.i18n.localize("oronder.Failed-To-Sync")}: ${response.status} ${response.statusText}`); + Logger.error( + `${actor_obj.name} ${game.i18n.localize("oronder.Failed-To-Sync")}: ${response.status} ${response.statusText}`, + {permanent: true} + ) } }).catch(Logger.error) } \ No newline at end of file diff --git a/src/util.mjs b/src/util.mjs index b3428b7..3d5c204 100644 --- a/src/util.mjs +++ b/src/util.mjs @@ -1,5 +1,5 @@ -import {MODULE_DEBUG_TAG} from "./constants.mjs"; -import objectHash from 'object-hash'; +import {MODULE_DEBUG_TAG} from "./constants.mjs" +import objectHash from 'object-hash' /** * Utility class to handle logging to console with an attached debug tag to identify module logs. @@ -7,25 +7,25 @@ import objectHash from 'object-hash'; export class Logger { static debug(logString) { - console.debug(..._processLog(logString)); + console.debug(..._processLog(logString)) } static info(logString) { - console.info(..._processLog(logString)); + console.info(..._processLog(logString)) } static log(logString) { - console.log(..._processLog(logString)); + console.log(..._processLog(logString)) } static warn(logString, options = {}) { - if (options.ui ?? true) ui.notifications.warn(logString, {console: false}); - if (options.console ?? true) console.warn(..._processLog(logString)); + if (options.ui ?? true) ui.notifications.warn(logString, {...options, console: false}) + if (options.console ?? true) console.warn(..._processLog(logString)) } static error(logString, options = {}) { - if (options.ui ?? true) ui.notifications.error(logString, {console: false}); - if (options.console ?? true) console.error(..._processLog(logString)); + if (options.ui ?? true) ui.notifications.error(logString, {...options, console: false}) + if (options.console ?? true) console.error(..._processLog(logString)) } } @@ -36,7 +36,7 @@ export class Logger { * @private */ function _processLog(logString) { - return [...MODULE_DEBUG_TAG, logString]; + return [...MODULE_DEBUG_TAG, logString] } const hash_options = {unorderedArrays: true, respectType: false}