diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 64b391b..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,44 +0,0 @@ -# Changelog - -## Version 0.2.1, 2021-04-24 - -Features: N/A - -Fixes: -1. Bot no longer crashes when a mod marks a deleted submission as solved -2. Bot no longer crashes for solutions whose comment has already been stored in the db - -Miscellaneous: N/A - -## Version 0.2.0, 2021-03-07 - -Features: -1. Points can now be awarded to multiple comments on the same post -2. The bot summoning keyword has been changed from "solved" to "helped" - -Fixes: N/A - -Miscellaneous: -1. Introduced versioning for the bot and database - -## 2020-08-21 - -Features: N/A - -Fixes: -1. Removed freezing to comply with r/RequestABot guidelines - -Miscellaneous: N/A - -## 2020-05-10 - -Features: -1. Adding basic initial logging - * Logs both to a file and to the command prompt - -Fixes: N/A - -Miscellaneous: -1. Moved feedback & scoreboard links for bot reply into configuration -2. Changed program entry point to `PointsBot.py` -3. Added ability to freeze the app as a simple executable diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..410a5f3 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,20 @@ +FROM python:3.7-slim + +WORKDIR /app + + +# Install dependencies +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt && \ + rm requirements.txt + +# Copy application code +COPY pointsbot ./pointsbot +COPY pointsbot.py . + + +# Set environment to use unbuffered Python output +ENV PYTHONUNBUFFERED=1 + +# Run the bot +CMD ["python", "pointsbot.py"] diff --git a/Pipfile b/Pipfile deleted file mode 100644 index 949eca0..0000000 --- a/Pipfile +++ /dev/null @@ -1,14 +0,0 @@ -[[source]] -name = "pypi" -url = "https://pypi.org/simple" -verify_ssl = true - -[dev-packages] -pylint = "*" - -[packages] -toml = "*" -praw = "*" - -[requires] -python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index 1e23fdd..0000000 --- a/Pipfile.lock +++ /dev/null @@ -1,217 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "eb0083fecb64a3387eba2a1da2fb9fd3600b34c11989342104f415e9c2568676" - }, - "pipfile-spec": 6, - "requires": { - "python_version": "3.7" - }, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "certifi": { - "hashes": [ - "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c", - "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830" - ], - "version": "==2020.12.5" - }, - "chardet": { - "hashes": [ - "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa", - "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5" - ], - "version": "==4.0.0" - }, - "idna": { - "hashes": [ - "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", - "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" - ], - "version": "==2.10" - }, - "praw": { - "hashes": [ - "sha256:068a01c19834e1f748a8c220c6aa62ae9f0f8e211504ab8ef19883d09bed3430", - "sha256:87166a77ec31a1d9686ccdac97b5b72ba277ce436976eb3baf467c593f15bb26" - ], - "index": "pypi", - "version": "==7.1.4" - }, - "prawcore": { - "hashes": [ - "sha256:1f1eafc8a65d671f9892354f73142014fbb5d3a9ee621568c662d0a354e0578b", - "sha256:672d8a2faa12b44307874b2acfdd27f9cbaa5fa37bada4b34e36277224e6d8ed" - ], - "version": "==1.5.0" - }, - "requests": { - "hashes": [ - "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804", - "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e" - ], - "version": "==2.25.1" - }, - "six": { - "hashes": [ - "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259", - "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced" - ], - "version": "==1.15.0" - }, - "toml": { - "hashes": [ - "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", - "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" - ], - "index": "pypi", - "version": "==0.10.2" - }, - "update-checker": { - "hashes": [ - "sha256:6a2d45bb4ac585884a6b03f9eade9161cedd9e8111545141e9aa9058932acb13", - "sha256:cbba64760a36fe2640d80d85306e8fe82b6816659190993b7bdabadee4d4bbfd" - ], - "version": "==0.18.0" - }, - "urllib3": { - "hashes": [ - "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80", - "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73" - ], - "version": "==1.26.3" - }, - "websocket-client": { - "hashes": [ - "sha256:0fc45c961324d79c781bab301359d5a1b00b13ad1b10415a4780229ef71a5549", - "sha256:d735b91d6d1692a6a181f2a8c9e0238e5f6373356f561bb9dc4c7af36f452010" - ], - "version": "==0.57.0" - } - }, - "develop": { - "astroid": { - "hashes": [ - "sha256:87ae7f2398b8a0ae5638ddecf9987f081b756e0e9fc071aeebdca525671fc4dc", - "sha256:b31c92f545517dcc452f284bc9c044050862fbe6d93d2b3de4a215a6b384bf0d" - ], - "version": "==2.5" - }, - "colorama": { - "hashes": [ - "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b", - "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2" - ], - "markers": "sys_platform == 'win32'", - "version": "==0.4.4" - }, - "isort": { - "hashes": [ - "sha256:c729845434366216d320e936b8ad6f9d681aab72dc7cbc2d51bedc3582f3ad1e", - "sha256:fff4f0c04e1825522ce6949973e83110a6e907750cd92d128b0d14aaaadbffdc" - ], - "version": "==5.7.0" - }, - "lazy-object-proxy": { - "hashes": [ - "sha256:1d33d6f789697f401b75ce08e73b1de567b947740f768376631079290118ad39", - "sha256:2f2de8f8ac0be3e40d17730e0600619d35c78c13a099ea91ef7fb4ad944ce694", - "sha256:3782931963dc89e0e9a0ae4348b44762e868ea280e4f8c233b537852a8996ab9", - "sha256:37d9c34b96cca6787fe014aeb651217944a967a5b165e2cacb6b858d2997ab84", - "sha256:38c3865bd220bd983fcaa9aa11462619e84a71233bafd9c880f7b1cb753ca7fa", - "sha256:429c4d1862f3fc37cd56304d880f2eae5bd0da83bdef889f3bd66458aac49128", - "sha256:522b7c94b524389f4a4094c4bf04c2b02228454ddd17c1a9b2801fac1d754871", - "sha256:57fb5c5504ddd45ed420b5b6461a78f58cbb0c1b0cbd9cd5a43ad30a4a3ee4d0", - "sha256:5944a9b95e97de1980c65f03b79b356f30a43de48682b8bdd90aa5089f0ec1f4", - "sha256:6f4e5e68b7af950ed7fdb594b3f19a0014a3ace0fedb86acb896e140ffb24302", - "sha256:71a1ef23f22fa8437974b2d60fedb947c99a957ad625f83f43fd3de70f77f458", - "sha256:8a44e9901c0555f95ac401377032f6e6af66d8fc1fbfad77a7a8b1a826e0b93c", - "sha256:b6577f15d5516d7d209c1a8cde23062c0f10625f19e8dc9fb59268859778d7d7", - "sha256:c8fe2d6ff0ff583784039d0255ea7da076efd08507f2be6f68583b0da32e3afb", - "sha256:cadfa2c2cf54d35d13dc8d231253b7985b97d629ab9ca6e7d672c35539d38163", - "sha256:cd1bdace1a8762534e9a36c073cd54e97d517a17d69a17985961265be6d22847", - "sha256:ddbdcd10eb999d7ab292677f588b658372aadb9a52790f82484a37127a390108", - "sha256:e7273c64bccfd9310e9601b8f4511d84730239516bada26a0c9846c9697617ef", - "sha256:e7428977763150b4cf83255625a80a23dfdc94d43be7791ce90799d446b4e26f", - "sha256:e960e8be509e8d6d618300a6c189555c24efde63e85acaf0b14b2cd1ac743315", - "sha256:ecb5dd5990cec6e7f5c9c1124a37cb2c710c6d69b0c1a5c4aa4b35eba0ada068", - "sha256:ef3f5e288aa57b73b034ce9c1f1ac753d968f9069cd0742d1d69c698a0167166", - "sha256:fa5b2dee0e231fa4ad117be114251bdfe6afe39213bd629d43deb117b6a6c40a", - "sha256:fa7fb7973c622b9e725bee1db569d2c2ee64d2f9a089201c5e8185d482c7352d" - ], - "version": "==1.5.2" - }, - "mccabe": { - "hashes": [ - "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", - "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" - ], - "version": "==0.6.1" - }, - "pylint": { - "hashes": [ - "sha256:bb4a908c9dadbc3aac18860550e870f58e1a02c9f2c204fdf5693d73be061210", - "sha256:bfe68f020f8a0fece830a22dd4d5dddb4ecc6137db04face4c3420a46a52239f" - ], - "index": "pypi", - "version": "==2.6.0" - }, - "toml": { - "hashes": [ - "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", - "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" - ], - "index": "pypi", - "version": "==0.10.2" - }, - "typed-ast": { - "hashes": [ - "sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1", - "sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d", - "sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6", - "sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd", - "sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37", - "sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151", - "sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07", - "sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440", - "sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70", - "sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496", - "sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea", - "sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400", - "sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc", - "sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606", - "sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc", - "sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581", - "sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412", - "sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a", - "sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2", - "sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787", - "sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f", - "sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937", - "sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64", - "sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487", - "sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b", - "sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41", - "sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a", - "sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3", - "sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166", - "sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10" - ], - "markers": "implementation_name == 'cpython' and python_version < '3.8'", - "version": "==1.4.2" - }, - "wrapt": { - "hashes": [ - "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7" - ], - "version": "==1.12.1" - } - } -} diff --git a/docs/DONE.md b/docs/DONE.md deleted file mode 100644 index a882ff9..0000000 --- a/docs/DONE.md +++ /dev/null @@ -1,66 +0,0 @@ -# DONE - -## General - -* [X] Initial/Basic Logging - * Especially when unable to handle a comment -* [X] Change commands from !solved and /solved to !helped and /helped -* [X] Allow multiple users to be awarded points on a single post - * So just check whether each user is already awarded a point for a given post - -## Bugs -* [X] mod /helped command doesn't work on one post (some posts?) - * the problem here seems to be the fact that when the bot adds a point for a solution comment, it - also adds the comment to the comments table without first checking whether it already exists - * while it is the case that we should only have one one `solution` row for each comment, it is potentially - possible that a comment could already be in the db when we add a solution for it, e.g. if the solution was - deleted (meaning the point was removed) and then we want to add it back, or something?? -* [X] bot crashes when a mod is trying to award a point to a solution on a deleted post - * the problem is that the new schema had the submission_id as a required foreign key, but a - deleted post will not have one - * according to them, since only mods will award points on deleted posts, it's fine if the fix is limited to mods - -## File-Specific - -### bot.py - -* [X] Allow mods to mark a post as solved with "/[Ss]olved" -* [X] Allow mods to use "/[Ss]olved" in any context -* [X] When replying to solution, the bot should... - - [X] Reply to the comment containing the "![Ss]olved" string - - [X] Tag the solver so they will be notified - - ~~Delete the automod message~~ -* ~~Add a star to the user flair for every 100 points~~ -* ~~Add a way to look up user points~~ - - i.e. summon bot by tagging it and provide a username to look up - - the bot will reply with the last message that the user received - -### config.py - -* [X] Change from `ini` to `toml ` -* [X] Consolidate `pointsbot.ini` and `praw.ini` into a single config file. -* [X] Add option for flair_template_id -* [X] Check for config file in a well-known location, e.g. `~` directory - - Probably named `~/.pointsbot` or something similar - - Could do something similar to packages like PRAW: - 1. Look in current working directory first. - 2. Look in OS-dependent location next. - 3. (Maybe) Finally, could look in the directory containing the source files - (using `__file__`). -* [X] Add interactive config scipt -* ~~Fix titlecase problem with roman numerals~~ - - Only an issue with `ini` format -* ~~Separate the development-handy config items into separate section~~ - - Don't really have any right now - -### database.py - -### reply.py - -* [X] Fix progress bar -* ~~For the footer section of the reply comment regarding the bot, could have the - bot make a post on its account explaining itself, and link to that (and then - also link to the source code separately, and perhaps in that post, too). - Could even have the bot make this post automatically if it doesn't have a - link to the post in its config, and then store the link for future use.~~ - diff --git a/docs/IDEAS.md b/docs/IDEAS.md deleted file mode 100644 index 39fd3bb..0000000 --- a/docs/IDEAS.md +++ /dev/null @@ -1,41 +0,0 @@ -# IDEAS - -## Determining when to award points - -To ensure that points are only awarded for the first comment marked as a -solution: - -* This approach could also make it simpler to check whether a solution comment - has been edited. Instead of having to do a daily search for edits, it could - just check the original solution comment to ensure that it still contains - the "!solved" string. If not, it can remove points from that author and - award points to the new author. - -To ensure that a point is awarded to the correct user: - -* We could expand the "!solved" bot summons to include an optional username - argument. Without the argument, the bot will award the point to either the - top-level comment or the parent comment of the "!solved" comment, whichever - is decided upon. However, if the username argument is provided, the bot - could simple check that one of the comments in the comment tree belongs to - that user, and then award them the point. - - Honestly, this is probably overcomplicated and unnecessary, though. - -## Multiple behaviors - -Implement the concept of actions, with a mapping between trigger keywords/patterns and actions. This will allow for multiple behaviors (eg mark as solved for one behavior, and just show points when summoned for another). - -Maybe allow chains of actions. For example: -1. OP comments "!solved" -2. Bot receives comment -3. Action 1: Determine whether is "!solved" comment -4. Action 2: Determine solver -5. Action 3: Add points -6. Action 4: Reply - -## Making the bot easier to configure - -Allow bot user to just specify a list of strings to recognize to trigger the bot's response. Allow user to specify whether case-sensitive. Ways to do this, with varying performance: -* Just search each text for each keyword; -* Use `re.compile()` for each keyword before searching (*may* be faster?); or -* Build a binary search tree for all keywords for each action \ No newline at end of file diff --git a/docs/TESTS.md b/docs/TESTS.md deleted file mode 100644 index 51316a5..0000000 --- a/docs/TESTS.md +++ /dev/null @@ -1,4 +0,0 @@ -# TESTS - -## End-to-end Testing Scenarios - diff --git a/docs/TODO.md b/docs/TODO.md deleted file mode 100644 index aa321c9..0000000 --- a/docs/TODO.md +++ /dev/null @@ -1,91 +0,0 @@ -# TODO - -File-specific lists are in loose descending order of priority. - -## Current - -N/A - -## Bugs - -* [ ] For some posts, the bot adds a point to the database, but crashes before being able to reply - -## General - -* [ ] Make "!Solved" command text (or all command texts?) configurable by user -* [ ] Make flair usage configurable - * New user suggested that it could be helpful to have point totals in flair -* [ ] Notifications - * Let admins know if a comment can't be properly handled - * Email preferable; could do Reddit message, too - * Maybe have both and make into a config option -* [ ] Testing - - Any PRAW model that inherits from `praw.PRAWBase` has a `parse` method - that could perhaps be used to make fake objects for testing - - Add regression tests for comments, etc.? -* [ ] GUI - - [ ] Create a GUI for configuring and running the bot, and performing other jobs - like adding or subtracting points for specific redditors - - [ ] Check for updates in the Github repo and prompt user to update - - Github API overview: - - https://developer.github.com/v3/ - - https://developer.github.com/v4/ - - It turns out that v4 might only be possible with a Github user - account to authenticate with the API. - - Useful links: - - https://developer.github.com/v3/repos/branches/#get-branch - - https://developer.github.com/v3/repos/contents/#get-archive-link - - https://developer.github.com/v3/repos/commits/ - - https://developer.github.com/v3/repos/releases/ - - https://developer.github.com/v3/#timezones - - Webhooks: - - https://developer.github.com/webhooks/ - - https://developer.github.com/v3/repos/hooks/ - - https://developer.github.com/v3/activity/events/types/#pushevent -* [ ] Determine whether and how to check "![Ss]olved" comments have been later - edited to remove the "![Ss]olved" string, and whether and how to remove or - reassign points - - If so, it could do that daily or something. - - This will be especially important if a "recovery mode" is implemented that - crawls through the whole subreddit to rebuild the database, since the - bot would only be able to see comments that haven't been removed, or - the newest version of edited comments. - - This could also just be encouraged through sub rules; e.g. "don't mark as - solved until you've actually tried the proposed solution" -* [ ] As mentioned in the previous section, implement a recovery mode - -## File-Specific - -### bot.py - -* [ ] (Maybe) sanitize input text? -* [ ] Now that the date of each solution is being stored, can check for missed - submissions each time the bot is run by searching subreddit history until - last solution found -* [ ] Allow mods and/or bot owner to add or remove points from specific users -* [ ] Make the algorithm for determining the problem solver more sophisticated - - e.g. check entire comment tree instead of just ignoring if the OP also - authored the parent comment - - Ask OP for clarification only if solver cannot be sufficiently determined - - Again, this behavior could also perhaps be better enforced through - subreddit rules rather than algorithmically - -### config.py - -* [ ] Add list of emails to which notifications should be sent -* [ ] Switch from `toml` package to `tomlkit` package - - Preserves style, comments, etc. - -### database.py - -* [ ] For each solved submission, store: - - submission id - - solution comment id - - solved comment id - - date - - solver id -* [ ] Possibly refactor for a datastore type thing instead of database - - Maybe even make models like Redditor to combine data storage/access with - logic, e.g. determining current level - - Seems like overkill, though - diff --git a/docs/run.cmd b/docs/run.cmd deleted file mode 100644 index 98e202b..0000000 --- a/docs/run.cmd +++ /dev/null @@ -1,17 +0,0 @@ -@echo off - -REM wsl run.sh -REM start "" chrome.exe TODO.html - -REM pandoc.exe -s -f gfm -t html TODO.md -o TODO.html --metadata pagetitle="TODO.html" -REM .\TODO.html - -call :makedoc DONE -call :makedoc IDEAS -call :makedoc TODO -call :makedoc TESTS -goto :eof - -:makedoc -pandoc.exe -s -f gfm -t html %1.md -o %1.html --metadata pagetitle="%1.html" -goto :eof diff --git a/docs/run.sh b/docs/run.sh deleted file mode 100755 index bf76bcb..0000000 --- a/docs/run.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash - -# If files specified, only make them; otherwise, make all -if [[ $# -gt 0 ]]; then - docfiles=( "$@" ) -else - docfiles=( $(ls *.md) ) -fi - -for fname in "${docfiles[@]}"; do - outname="_${fname/%md/html}" - echo $fname "->" $outname - pandoc -s -f gfm -t html $fname -o $outname --metadata pagetitle="$outname" - open $outname -done diff --git a/PointsBot.py b/pointsbot.py similarity index 100% rename from PointsBot.py rename to pointsbot.py diff --git a/pointsbot.sample.toml b/pointsbot.sample.toml deleted file mode 100644 index 56b47af..0000000 --- a/pointsbot.sample.toml +++ /dev/null @@ -1,93 +0,0 @@ -################################################################################ -# Core -# -# These are the primary fields needed to run the bot. -################################################################################ - -[core] -# The name of the subreddit to monitor, without the "r/" prefix. -subreddit = "" -valid_tags = "Java,Bedrock,Dungeons,Earth,Education,Legacy" - - -################################################################################ -# Reddit Credentials -# -# See the bot documentation for more information about these fields. - -# Some of these fields are sensitive, so once these fields are provided, take -# care not to upload or distribute this file through insecure channels, or to -# public sites. -################################################################################ - -[credentials] -client_id = "REDACTED" -client_secret = "REDACTED" -username = "REDACTED" -password = "REDACTED" - - -################################################################################ -# Filepaths -# -# Any filepaths needed by the bot. Can be relative or absolute paths, or just -# filenames. -################################################################################ - -[filepaths] -# The name/path of the SQLite database file to use. This value is optional; if not -# specified, a default filepath will be used. -database = "" -# The name/path of the log file to use. This value is optional; if not specified, -# a default filepath will be used. -log = "" - - -################################################################################ -# Links -# -# Any links used in the bot's reply. If you do not need to use these links, -# leave these fields blank. -################################################################################ - -[links] -feedback = "" -scoreboard = "" - - -################################################################################ -# User Levels -# -# These items represent the levels that contributors to the subreddit can -# attain. To add a level, add another section with the format: -# -# [[levels]] -# name = "" -# points = -# flair_template_id = "" -# -# These fields are case-sensitive, so enter the level name exactly as you want -# it to appear. -# -# The flair_template_id field is optional, so it may be omitted or left as the -# empty string, "". -# -# Furthermore, the order of these levels does not matter: they will be sorted by -# point values when the bot is run. However, it may be preferable to order them -# by point values for readability. -################################################################################ - -[[levels]] -name = "Level One" -points = 1 -flair_template_id = "" - -[[levels]] -name = "Level Two" -points = 25 -flair_template_id = "" - -[[levels]] -name = "Level Three" -points = 100 -flair_template_id = "" diff --git a/pointsbot/reply.py b/pointsbot/reply.py index a621a4d..1ed81ad 100644 --- a/pointsbot/reply.py +++ b/pointsbot/reply.py @@ -151,14 +151,14 @@ def divider(): def footer(feedback_url=None, scoreboard_url=None): - footer_sections = ['^(Bot maintained by GlipGlorp7)'] + footer_sections = ['^(Official MinecraftHelp Bot)'] if scoreboard_url: # https://points.minecrafthelp.co.uk - footer_sections.append(f'[^Scoreboard]({scoreboard_url})') + footer_sections.append(f'^[Scoreboard]({scoreboard_url})') if feedback_url: # https://forms.gle/m94aGjFQwGopqQ836 - footer_sections.append(f'[^Feedback]({feedback_url})') - footer_sections.append('[^Source Code](https://github.com/cur33/PointsBot)') + footer_sections.append(f'^[Feedback]({feedback_url})') + footer_sections.append('^[Source](https://github.com/cur33/PointsBot)') return ' ^| '.join(footer_sections) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..9bbb5fb --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +toml==0.10.2 +praw==7.7.0 diff --git a/tests/context.py b/tests/context.py deleted file mode 100644 index 60f4a52..0000000 --- a/tests/context.py +++ /dev/null @@ -1,6 +0,0 @@ -import sys -from os.path import abspath, dirname, join - -sys.path.insert(0, abspath(join(dirname(__file__), '..'))) - -import pointsbot diff --git a/tests/test_level.py b/tests/test_level.py deleted file mode 100644 index 771d53e..0000000 --- a/tests/test_level.py +++ /dev/null @@ -1,40 +0,0 @@ -import level - -levels = [ - ('Helper', 5), - ('Trusted Helper', 15), - ('Super Helper', 45), -] - - -### Test user_level_info ### - - -pastlvls, curlvl, nextlvl = user_level_info(1, levels) -assert (pastlevels == [] and curlvl is None and nextlvl == levels[0]) - -pastlvls, curlvl, nextlvl = user_level_info(5, levels) -assert (pastlevels == [] and curlvl == levels[0] and nextlvl == levels[1]) - -pastlvls, curlvl, nextlvl = user_level_info(15, levels) -assert (pastlvls == levels[:1] and curlvl == levels[1] and nextlvl == levels[2]) - -pastlvls, curlvl, nextlvl = user_level_info(45, levels) -assert (pastlvls == levels[:2] and curlvl == levels[2] and nextlvl is None) - - -### Test is_max_level ### - - -# TODO I mean, this could be tested exhaustively with positive numbers, even if -# the number of points for the max level is decently large -assert not level.is_max_level(-1, levels) -assert not level.is_max_level(0, levels) -assert not level.is_max_level(4, levels) -assert not level.is_max_level(5, levels) -assert not level.is_max_level(14, levels) -assert not level.is_max_level(15, levels) -assert not level.is_max_level(16, levels) -assert not level.is_max_level(44, levels) -assert level.is_max_level(45, levels) -assert level.is_max_level(46, levels) diff --git a/tests/test_reply.py b/tests/test_reply.py deleted file mode 100644 index d6e3ef9..0000000 --- a/tests/test_reply.py +++ /dev/null @@ -1,63 +0,0 @@ -from collections import namedtuple - -from context import pointsbot - -### Data Structures ### - -MockRedditor = namedtuple('MockRedditor', 'id name') - -### Functions ### - - -def leftpad(msg, num_indents=1): - return '\n'.join([('\t' * num_indents + l) for l in msg.split('\n')]) - - -def make_comments(subreddit, levels): - testpoints = [1, 3, 5, 10, 15, 30, 45, 75] + list(range(100, 551, 50)) - - for sub in subreddit.new(): - if sub.title == 'Testing comment scenarios': - redditor = sub.author - for points in testpoints: - body = f'Solver: {redditor}\n\nTotal points after solving: {points}' - print_level(0, body) - comm = sub.reply(body) - if comm: - level_info = level.user_level_info(points, levels) - body = reply.make(redditor, points, level_info) - comm.reply(body) - else: - print_level(1, 'ERROR: Unable to comment') - break - - -### Tests ### - -levels = [ - pointsbot.level.Level('Novice', 1, ''), - pointsbot.level.Level('Apprentice', 5, ''), - pointsbot.level.Level('Journeyman', 15, ''), - pointsbot.level.Level('Expert', 45, ''), - pointsbot.level.Level('Master I', 100, ''), - pointsbot.level.Level('Master II', 200, ''), - pointsbot.level.Level('Master III', 300, ''), - pointsbot.level.Level('Master IV', 400, ''), - pointsbot.level.Level('Master V', 500, ''), -] - -testredditors = [MockRedditor('1', 'Tim_the_Sorcerer')] -testpoints = [1, 3, 5, 10, 15, 30, 45, 75] + list(range(100, 551, 50)) - -for redditor in testredditors: - for points in testpoints: - level_info = pointsbot.level.user_level_info(points, levels) - body = pointsbot.reply.make(redditor, points, level_info) - print('*' * 80) - print() - print(f'Name: {redditor.name}') - print(f'Points: {points}') - print(f'Body:') - print(leftpad(body, num_indents=1)) - print() -print('*' * 80)