From 882e0b3ab8e328765837724e760b753667bf44aa Mon Sep 17 00:00:00 2001 From: Vivek Santayana Date: Sat, 24 Jul 2021 01:01:48 +0100 Subject: [PATCH] Updated Readme. Refreshed requirements. Purged guild. Ready for further testing. --- .vscode/settings.json | 3 +- README.md | 213 +++++++++++++--------- TODO.md | 9 +- app/cogs/slashcommands/secondary/pitch.py | 6 +- app/data/categories.yml | 3 +- app/data/data.yml | 15 +- app/data/gm.yml | 4 +- app/data/lookup.yml | 8 +- app/requirements.txt | Bin 650 -> 365 bytes 9 files changed, 146 insertions(+), 115 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 3a35d10..f95bc4b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,5 @@ { - "editor.insertSpaces": false, - "editor.detectIndentation": false, + "editor.insertSpaces": false, "python.pythonPath": "./app/Scripts/python", "python.autoComplete.extraPaths": ["./app"] } \ No newline at end of file diff --git a/README.md b/README.md index be211f6..ec279db 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,5 @@ # Geas Server Bot -``` -(Currently a work in progress. The bot is still not in a state to run, and none of its features have been programmed.) -``` - This is a bot I wrote to manage the Discord server for Geas, the Edinburgh University Table-Top Role-Playing Society, during our move to an on-line format. The bot is designed to create and manage channels and roles for gaming groups in order to replicate our in-person pitch events on a Discord space as far as possible. The bot is written in Python, and was the first Python coding project I wrote, so it has a special place in my heart. @@ -26,7 +22,8 @@ The specific username and password don't matter as the bot refers back to the en The following is the template for the `.env` file, with the variable names as are referenced in the bot's code: `.env` file: -``` + +```DotENV BOT_TOKEN=(API token for the production version of the bot.) TEST_TOKEN=(API token for any test instance.) CONFIG=(Path to config file. The bot defaults to './data/config.yml' if not provided.) @@ -37,66 +34,82 @@ CATEGORIES=(Path to the channel category lookup file. The bot defaults to './dat BOT_VERSION=(verson string) BOT_MAINTAINER_ID=(Discord user ID of the person maintaining the bot to enable debug features.) ``` + The correct API keys need to be entered in the environment variables in the `.env` file, and for a copy of this file to be placed in the root and the `app` directories. **N.B.**: When the bot is first run, it is configured to log in as the Test Bot, and not the main Geas Server Bot, as a safety measure. To change this, navigate to the last line of the file `bot.py` and change the line: -``` + +```py client.run(os.getenv('TEST_TOKEN')) ``` + to -``` + +```py client.run(os.getenv('BOT_TOKEN')) ``` + in order for to authenticate as the correct bot. ## File Structure ``` -|-- app -| |-- bot.py -| |-- Dockerfile -| |-- requirements.txt -| |-- cogs -| | |-- botcommands -| | | `-- prefix.py -| | |-- dev -| | |-- events -| | | |-- on_connect.py -| | | |-- on_guild_channel_delete.py -| | | |-- on_guild_join.py -| | | |-- on_guild_remove.py -| | | |-- on_guild_role_create.py -| | | |-- on_guild_role_delete.py -| | | |-- on_guild_role_update.py -| | | |-- on_guild_update.py -| | | `-- on_ready.py -| | `-- slashcommands -| | | |-- -| | | `-- -| |-- data -| | |-- .gitkeep -| | |-- config.yml -| | `-- data.yml -| -| -|-- .env -|-- .gitignore -|-- CHANGELOG.md -|-- COMMANDS.md -|-- docker-compse.yml -|-- LICENSE -|-- README.md -|-- resources.md -`-- TODO.md - -GameManagement.py -- adding or kicking players -HelpNotifier.py -- notifications for Help channel -MembershipRestriction.py -- restrictions unverified users -MembershipVerification.py -- membership verification system -PitchMenu.py -- automation for generating menus for game pitches +|-- app +| |-- .env +| |-- bot.py +| |-- cogs +| | |-- botcommands +| | | `-- prefix.py +| | |-- controlcommands +| | | `-- control.py +| | |-- events +| | | |-- on_command_error.py +| | | |-- on_connect.py +| | | |-- on_guild_channel_delete.py +| | | |-- on_guild_join.py +| | | |-- on_guild_remove.py +| | | |-- on_guild_role_create.py +| | | |-- on_guild_role_delete.py +| | | |-- on_guild_role_update.py +| | | |-- on_guild_update.py +| | | |-- on_message.py +| | | `-- on_ready.py +| | |-- membership +| | | |-- membership_verification.py +| | | `-- restriction_listener.py +| | `-- slashcommands +| | |-- config.py +| | `-- secondary +| | |-- edit_membership.py +| | |-- game_create.py +| | |-- game_management.py +| | |-- manipulate_timeslots.py +| | |-- pitch.py +| | `-- player_commands.py +| |-- data +| | |-- .gitkeep +| | |-- categories.yml +| | |-- config_blueprint.yml +| | |-- config.yml +| | |-- data.yml +| | |-- gm.yml +| | `-- lookup.yml +| |-- debug +| | `-- debug.py +| |-- Dockerfile +| `-- requirements.txt +|-- CHANGELOG.md +|-- COMMANDS.md +|-- docker-compse.yml +|-- LICENSE +|-- README.md +|-- resources.md +`-- TODO.md ``` +The `COMMANDS.md` file gives a list of all the commands the Bot uses, as well as a reference to the various cogs or base commands that are associated with them. The code for the command should be housed in the respective files within the file tree. + ## Data Structure The bot holds data in two `.yml` files, `config.yml` for client configurations for each guild it is in and `data.yml` to hold the actual data regarding game and channel set-up. @@ -109,28 +122,32 @@ This tree gives the list of various keys for the `.yml` dictionary as well as th The entire configuration file is essentially a dictionary with other dictionaries, strings, integers, and lists as values. All values in the dictionary are referenced first by a string of the guild id integer. Remember to convert the guild ID to strings during several operations, and be careful to compare like for like in any logics. -``` -(guild id string): - channels: - help: (id integer) - mod: (id integer) - signup: (id integer) - configured: (boolean) - membership: - (type string): (id integer) - name: (string) - owner: (id integer) - prefix: (string) - roles: - admin: (list) - - (id integer) - committee: (id integer) - bots: (id integer) - newcomer: (id integer) - returning: (id integer) - student: (id integer) - timeslots: (list) - - (string) + +```yml +guild id string: + channels: + help: int + mod: int + signup: int + configured: bool + membership: + - role id int + name: str + notifications: + help: bool + signup: bpp; + owner: owner id int + prefix: '-' by default + roles: + admin: + - role id int + bot: + committee: + newcomer: + returning_player: + student: + timeslots: + key: name ``` ### `data.yml` Structure @@ -138,15 +155,47 @@ Remember to convert the guild ID to strings during several operations, and be ca Just like above, the `data.yml` file is also a dictionary of dictionaries that is indexed by a string of the guild id. It stores only the relevant data necessary for the code to function. It only holds, for instance, ID numbers rather than user handles, Discord discriminators, or names. + +```yml +guild id string: + timeslot: + role: + category: category id int + current_players: int + header_message: message id int + game_title: str + gm: gm role id int + max_players: int + min_players: int + platform: str + role: role id int + system: str + text_channel: channel id int ``` -(guild id string): - (timeslot string): - role: (role id integer) - gm: (user id integer) - name: (string) - players: - current: (integer) - max: (integer) - min: (integer) - system: (string) -``` \ No newline at end of file + +### Other Data Files + +In addition to the above data file, the bot also uses storage in additional reference files to quickly look up values when needed for its various functions. +The purpose of these lookup files is more to act as dictionaries facilitating arbitrary look-ups of key information when required. +They are not intended to act as storage. +Most of these lookup files are not particularly readable because they have raw values without informative keys. +They are constructed and manipulated in tandem with the core data files. + +## In the Future + +### Restructure command execution using global event listeners + +As it stands, there is a conundrum with the Bot: +any kind of manual interaction to manipulate roles or categories will cause conflicts to emerge between the Bot's data and the guild settings. +In order for the bot to be adaptable, and to respond to user interactions, it will need event listeners for things like channel, role, or category changes/creation/depetion, etc. +Having such listeners will cause a circularity between the Bot's edit actions, which would then trigger the listener. +There is currently no way of having an exception for the Bot's edits. + +To reconcile this, the bot would need to work such that the command process that modified games only acted upon the roles, which would then trigger the event listeners to synchronise these changes with the categories, and subsequently the data. +Having the bot edit the data in the main command process would mean that there would be conflicts with the simuntaneous execution of parallel threads. + +### Membership sign up performance issues + +The way the membership signup prompt works is that it creates a new instance of the process executing for each member who submits a verification request, and the command runs until the verification is complete (either by verifying it or rejecting it). +This means that there is a risk that several active instances of the command will run simultaneously if a lot of members submit membership confirmation at once. +This should probably also be changed to being a global event listener, with the requisite inforation being passed to the function in the event listener via the custom values of the buttons and drop-down menu options. \ No newline at end of file diff --git a/TODO.md b/TODO.md index 0ad1c8b..ec32d73 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,10 @@ # To Do +- [ ] Testing +- [ ] Dockerise +- [ ] Infer/Transfer data from old bot +- [ ] Deploy + ## Bot Architecture - [x] Simplify directory tree @@ -121,9 +126,9 @@ Do the opposite: block deleting timeslots with existing games. ## Misc -- [ ] Review documentation +- [x] Review documentation -> - [ ] Finalise README.md +> - [x] Finalise README.md > - [x] CHANGELOG.md > - [x] COMMANDS.md > - [x] resources.md diff --git a/app/cogs/slashcommands/secondary/pitch.py b/app/cogs/slashcommands/secondary/pitch.py index 97915ab..32cf3a4 100644 --- a/app/cogs/slashcommands/secondary/pitch.py +++ b/app/cogs/slashcommands/secondary/pitch.py @@ -182,10 +182,10 @@ class Pitch(commands.Cog, name='Pitch Command'): await ctx.channel.set_permissions(reason=f'/pitch command issued by {ctx.author.display_name}', target=returning_player, read_messages=True) await button_ctx.send(f'```Returning Players have now been allowed access to the pitch menu.```', hidden=True) if button_ctx.custom_id == 'allow_newcomers': - ctx.channel.set_permissions(reason=f'/pitch command issued by {ctx.author.display_name}', target=newcomer, read_messages=True) + await ctx.channel.set_permissions(reason=f'/pitch command issued by {ctx.author.display_name}', target=newcomer, read_messages=True) await button_ctx.send(f'```Newcomers have now been allowed access to the pitch menu.```', hidden=True) if button_ctx.custom_id == 'allow_all': - await ctx.channel.edit(reason=f'/pitch command issued by {ctx.author.display_name}', target=ctx.guild.default_role, read_messages= True, send_messages=False) + await ctx.channel.set_permissions(reason=f'/pitch command issued by {ctx.author.display_name}', target=ctx.guild.default_role, read_messages= True, send_messages=False) await button_ctx.send(f'```All members have now been allowed access to the pitch menu.```', hidden=True) if button_ctx.custom_id == 'close_pitches': break else: @@ -282,7 +282,7 @@ class Pitch(commands.Cog, name='Pitch Command'): for message in pitches[guildStr][timeslot]['messages']: await message.delete() await control.delete() await ctx.channel.edit(reason=f'/pitch command issued by {ctx.author.display_name}', overwrites={}) - await button_ctx.send('```Pitch menu cleared. Pitches have now been concluded.```') + await button_ctx.send('```Pitch menu cleared. Pitches have now concluded.```') def setup(client): client.add_cog(Pitch(client)) \ No newline at end of file diff --git a/app/data/categories.yml b/app/data/categories.yml index c9281f9..104d380 100644 --- a/app/data/categories.yml +++ b/app/data/categories.yml @@ -1,2 +1 @@ -'864651943820525609': - '867789192527478800': 867789191156203550 +'864651943820525609': {} diff --git a/app/data/data.yml b/app/data/data.yml index e7c246d..104d380 100644 --- a/app/data/data.yml +++ b/app/data/data.yml @@ -1,14 +1 @@ -'864651943820525609': - avatar: - '867789191156203550': - category: 867789192527478800 - current_players: 0 - game_title: Masks - gm: 864649599671205914 - header_message: 867789196534349826 - max_players: 5 - min_players: null - platform: null - role: 867789191156203550 - system: null - text_channel: 867789194784407552 +'864651943820525609': {} diff --git a/app/data/gm.yml b/app/data/gm.yml index 923c2c7..104d380 100644 --- a/app/data/gm.yml +++ b/app/data/gm.yml @@ -1,3 +1 @@ -'864651943820525609': - '864649599671205914': - - 867789191156203550 +'864651943820525609': {} diff --git a/app/data/lookup.yml b/app/data/lookup.yml index 354dcc9..104d380 100644 --- a/app/data/lookup.yml +++ b/app/data/lookup.yml @@ -1,7 +1 @@ -'864651943820525609': - '867789191156203550': - category: 867789192527478800 - game_title: Masks - gm: 864649599671205914 - text_channel: 867789194784407552 - time: avatar +'864651943820525609': {} diff --git a/app/requirements.txt b/app/requirements.txt index 2b481406161edc317c5a9162b8b42b787f7bc664..c496d9774cf494611c6afc2ddd142dee267f6c1b 100644 GIT binary patch literal 365 zcmXv~yG{im5bgOFCa@2+p)j%3#KOjs0M{ki1p>21?$>+B&6a1*W9E#Fd1Efd%=AnP zmE2ef+j?@6;}P=7gHog)!~TYZ3bfmVq(%i#<5foI`EC_dh9 z#;ml0^|85Jy)ha)K|i1@UAEn}O}cy>Hi4gLrs?9T^ve-_vg3|P9Our_M~BTTX=Ece z)Zk^ij+sR1yyYZ)=8%4kL6;W@F}-7hLIEv4`}ga|`^Z>;8uuNigMf~EiRnj%Ke$`W l37u!sC<*Q?9z{pwcu==>AFd~Ky5|xoCJyyx9TX#2iGS(cZZiM? literal 650 zcmZ9JO>4qH5QgV0^rs|fwI7!rdaux{$6!JYm`yNR%%87)-kn_`vaGCm=lz(O+h1j^ z^>(l`XRr^>+Dd!lZny*32(q*%TUf<=vS52F_|{ry4fut3<}Kl@9%`kZacQm-F2@s! z!k%H3{FcdSPofI6#=+Ial)5LWaUaRi#~LY!uhgzS$BS6m#cl$M0ZsQ6OLr49J+cP6 zEvP)k&JVoh*l{W}>Xclb%B~5`6*RvoR?XA3)CDy1RGix}$s@^xwm5m;FDaq-Exj|d z>ERdD_54#mzfsGl{|>{ezp38Yr)}*k;?mL_eM8#ogky70sFcnWGLRzJ4?c}ulh4RE idHeL#_bP2AGcWLJdQ&d-=R3=u6UYhAys=jld}IGiQed6{