diff --git a/Dockerfile b/Dockerfile index 1fd0099..2fdade9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,18 @@ -FROM python:3 +FROM python:3.10 -COPY post_updater.py /bin/post_updater -COPY requirements.txt /tmp/requirements.txt -RUN chmod +x /bin/post_updater && pip install -r /tmp/requirements.txt +# Set Poetry Version +ENV POETRY_VERSION=1.1.13 +# Install Poetry +RUN curl -sSL https://install.python-poetry.org | python3 - --version $POETRY_VERSION +# Add poetry install location to PATH +ENV PATH=/root/.local/bin:$PATH -CMD ["/bin/post_updater"] \ No newline at end of file +RUN poetry config virtualenvs.create false +COPY poetry.lock pyproject.toml ./ +RUN poetry install --no-root --no-dev + +COPY post_updater.py /bin/post_updater.py + +RUN chmod +x /bin/post_updater.py + +CMD ["post_updater.py"] diff --git a/action.yml b/action.yml index 32f2e91..1619440 100644 --- a/action.yml +++ b/action.yml @@ -7,8 +7,11 @@ inputs: description: Discord Bot Token for Authentication required: true post_file: - description: Path to the file containing the post - required: true + description: Path to the file containing the raw post + required: false + post_xml: + description: Path to the file containing the XML specification for the post + required: false discord_channel: description: Discord Channel ID required: true diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..3f94853 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,207 @@ +[[package]] +name = "aiohttp" +version = "3.8.1" +description = "Async http client/server framework (asyncio)" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +aiosignal = ">=1.1.2" +async-timeout = ">=4.0.0a3,<5.0" +attrs = ">=17.3.0" +charset-normalizer = ">=2.0,<3.0" +frozenlist = ">=1.1.1" +multidict = ">=4.5,<7.0" +yarl = ">=1.0,<2.0" + +[package.extras] +speedups = ["cchardet", "brotli", "aiodns"] + +[[package]] +name = "aiosignal" +version = "1.2.0" +description = "aiosignal: a list of registered asynchronous callbacks" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +frozenlist = ">=1.1.0" + +[[package]] +name = "async-timeout" +version = "4.0.2" +description = "Timeout context manager for asyncio programs" +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "attrs" +version = "22.1.0" +description = "Classes Without Boilerplate" +category = "main" +optional = false +python-versions = ">=3.5" + +[package.extras] +tests_no_zope = ["cloudpickle", "pytest-mypy-plugins", "mypy (>=0.900,!=0.940)", "pytest (>=4.3.0)", "pympler", "hypothesis", "coverage[toml] (>=5.0.2)"] +tests = ["cloudpickle", "zope.interface", "pytest-mypy-plugins", "mypy (>=0.900,!=0.940)", "pytest (>=4.3.0)", "pympler", "hypothesis", "coverage[toml] (>=5.0.2)"] +docs = ["sphinx-notfound-page", "zope.interface", "sphinx", "furo"] +dev = ["cloudpickle", "pre-commit", "sphinx-notfound-page", "sphinx", "furo", "zope.interface", "pytest-mypy-plugins", "mypy (>=0.900,!=0.940)", "pytest (>=4.3.0)", "pympler", "hypothesis", "coverage[toml] (>=5.0.2)"] + +[[package]] +name = "charset-normalizer" +version = "2.1.0" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "main" +optional = false +python-versions = ">=3.6.0" + +[package.extras] +unicode_backport = ["unicodedata2"] + +[[package]] +name = "frozenlist" +version = "1.3.1" +description = "A list-like structure which implements collections.abc.MutableSequence" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "idna" +version = "3.3" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "multidict" +version = "6.0.2" +description = "multidict implementation" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "py-cord" +version = "2.0.0" +description = "A Python wrapper for the Discord API" +category = "main" +optional = false +python-versions = ">=3.8.0" + +[package.dependencies] +aiohttp = ">=3.6.0,<3.9.0" + +[package.extras] +voice = ["PyNaCl (>=1.3.0,<1.6)"] +speed = ["cchardet", "brotlipy", "aiodns (>=1.1)", "orjson (>=3.5.4)"] +docs = ["myst-parser", "sphinxcontrib-websupport", "sphinxcontrib-trio (==1.1.2)", "sphinx (==4.5.0)"] + +[[package]] +name = "pytz" +version = "2022.1" +description = "World timezone definitions, modern and historical" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "yarl" +version = "1.8.1" +description = "Yet another URL library" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +idna = ">=2.0" +multidict = ">=4.0" + +[metadata] +lock-version = "1.1" +python-versions = "^3.8" +content-hash = "0e5f42650ec15196cce76cab994199274decb5e987f5fc06bf016abf137f3806" + +[metadata.files] +aiohttp = [] +aiosignal = [] +async-timeout = [] +attrs = [] +charset-normalizer = [] +frozenlist = [] +idna = [ + {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, + {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, +] +multidict = [ + {file = "multidict-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b9e95a740109c6047602f4db4da9949e6c5945cefbad34a1299775ddc9a62e2"}, + {file = "multidict-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac0e27844758d7177989ce406acc6a83c16ed4524ebc363c1f748cba184d89d3"}, + {file = "multidict-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:041b81a5f6b38244b34dc18c7b6aba91f9cdaf854d9a39e5ff0b58e2b5773b9c"}, + {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fdda29a3c7e76a064f2477c9aab1ba96fd94e02e386f1e665bca1807fc5386f"}, + {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3368bf2398b0e0fcbf46d85795adc4c259299fec50c1416d0f77c0a843a3eed9"}, + {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4f052ee022928d34fe1f4d2bc743f32609fb79ed9c49a1710a5ad6b2198db20"}, + {file = "multidict-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:225383a6603c086e6cef0f2f05564acb4f4d5f019a4e3e983f572b8530f70c88"}, + {file = "multidict-6.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50bd442726e288e884f7be9071016c15a8742eb689a593a0cac49ea093eef0a7"}, + {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:47e6a7e923e9cada7c139531feac59448f1f47727a79076c0b1ee80274cd8eee"}, + {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0556a1d4ea2d949efe5fd76a09b4a82e3a4a30700553a6725535098d8d9fb672"}, + {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:626fe10ac87851f4cffecee161fc6f8f9853f0f6f1035b59337a51d29ff3b4f9"}, + {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:8064b7c6f0af936a741ea1efd18690bacfbae4078c0c385d7c3f611d11f0cf87"}, + {file = "multidict-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2d36e929d7f6a16d4eb11b250719c39560dd70545356365b494249e2186bc389"}, + {file = "multidict-6.0.2-cp310-cp310-win32.whl", hash = "sha256:fcb91630817aa8b9bc4a74023e4198480587269c272c58b3279875ed7235c293"}, + {file = "multidict-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:8cbf0132f3de7cc6c6ce00147cc78e6439ea736cee6bca4f068bcf892b0fd658"}, + {file = "multidict-6.0.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:05f6949d6169878a03e607a21e3b862eaf8e356590e8bdae4227eedadacf6e51"}, + {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2c2e459f7050aeb7c1b1276763364884595d47000c1cddb51764c0d8976e608"}, + {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d0509e469d48940147e1235d994cd849a8f8195e0bca65f8f5439c56e17872a3"}, + {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:514fe2b8d750d6cdb4712346a2c5084a80220821a3e91f3f71eec11cf8d28fd4"}, + {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19adcfc2a7197cdc3987044e3f415168fc5dc1f720c932eb1ef4f71a2067e08b"}, + {file = "multidict-6.0.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9d153e7f1f9ba0b23ad1568b3b9e17301e23b042c23870f9ee0522dc5cc79e8"}, + {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:aef9cc3d9c7d63d924adac329c33835e0243b5052a6dfcbf7732a921c6e918ba"}, + {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4571f1beddff25f3e925eea34268422622963cd8dc395bb8778eb28418248e43"}, + {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:d48b8ee1d4068561ce8033d2c344cf5232cb29ee1a0206a7b828c79cbc5982b8"}, + {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:45183c96ddf61bf96d2684d9fbaf6f3564d86b34cb125761f9a0ef9e36c1d55b"}, + {file = "multidict-6.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:75bdf08716edde767b09e76829db8c1e5ca9d8bb0a8d4bd94ae1eafe3dac5e15"}, + {file = "multidict-6.0.2-cp37-cp37m-win32.whl", hash = "sha256:a45e1135cb07086833ce969555df39149680e5471c04dfd6a915abd2fc3f6dbc"}, + {file = "multidict-6.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6f3cdef8a247d1eafa649085812f8a310e728bdf3900ff6c434eafb2d443b23a"}, + {file = "multidict-6.0.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0327292e745a880459ef71be14e709aaea2f783f3537588fb4ed09b6c01bca60"}, + {file = "multidict-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e875b6086e325bab7e680e4316d667fc0e5e174bb5611eb16b3ea121c8951b86"}, + {file = "multidict-6.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:feea820722e69451743a3d56ad74948b68bf456984d63c1a92e8347b7b88452d"}, + {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cc57c68cb9139c7cd6fc39f211b02198e69fb90ce4bc4a094cf5fe0d20fd8b0"}, + {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:497988d6b6ec6ed6f87030ec03280b696ca47dbf0648045e4e1d28b80346560d"}, + {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:89171b2c769e03a953d5969b2f272efa931426355b6c0cb508022976a17fd376"}, + {file = "multidict-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:684133b1e1fe91eda8fa7447f137c9490a064c6b7f392aa857bba83a28cfb693"}, + {file = "multidict-6.0.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd9fc9c4849a07f3635ccffa895d57abce554b467d611a5009ba4f39b78a8849"}, + {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e07c8e79d6e6fd37b42f3250dba122053fddb319e84b55dd3a8d6446e1a7ee49"}, + {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4070613ea2227da2bfb2c35a6041e4371b0af6b0be57f424fe2318b42a748516"}, + {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:47fbeedbf94bed6547d3aa632075d804867a352d86688c04e606971595460227"}, + {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:5774d9218d77befa7b70d836004a768fb9aa4fdb53c97498f4d8d3f67bb9cfa9"}, + {file = "multidict-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2957489cba47c2539a8eb7ab32ff49101439ccf78eab724c828c1a54ff3ff98d"}, + {file = "multidict-6.0.2-cp38-cp38-win32.whl", hash = "sha256:e5b20e9599ba74391ca0cfbd7b328fcc20976823ba19bc573983a25b32e92b57"}, + {file = "multidict-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:8004dca28e15b86d1b1372515f32eb6f814bdf6f00952699bdeb541691091f96"}, + {file = "multidict-6.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2e4a0785b84fb59e43c18a015ffc575ba93f7d1dbd272b4cdad9f5134b8a006c"}, + {file = "multidict-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6701bf8a5d03a43375909ac91b6980aea74b0f5402fbe9428fc3f6edf5d9677e"}, + {file = "multidict-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a007b1638e148c3cfb6bf0bdc4f82776cef0ac487191d093cdc316905e504071"}, + {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07a017cfa00c9890011628eab2503bee5872f27144936a52eaab449be5eaf032"}, + {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c207fff63adcdf5a485969131dc70e4b194327666b7e8a87a97fbc4fd80a53b2"}, + {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:373ba9d1d061c76462d74e7de1c0c8e267e9791ee8cfefcf6b0b2495762c370c"}, + {file = "multidict-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfba7c6d5d7c9099ba21f84662b037a0ffd4a5e6b26ac07d19e423e6fdf965a9"}, + {file = "multidict-6.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19d9bad105dfb34eb539c97b132057a4e709919ec4dd883ece5838bcbf262b80"}, + {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:de989b195c3d636ba000ee4281cd03bb1234635b124bf4cd89eeee9ca8fcb09d"}, + {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7c40b7bbece294ae3a87c1bc2abff0ff9beef41d14188cda94ada7bcea99b0fb"}, + {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:d16cce709ebfadc91278a1c005e3c17dd5f71f5098bfae1035149785ea6e9c68"}, + {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:a2c34a93e1d2aa35fbf1485e5010337c72c6791407d03aa5f4eed920343dd360"}, + {file = "multidict-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:feba80698173761cddd814fa22e88b0661e98cb810f9f986c54aa34d281e4937"}, + {file = "multidict-6.0.2-cp39-cp39-win32.whl", hash = "sha256:23b616fdc3c74c9fe01d76ce0d1ce872d2d396d8fa8e4899398ad64fb5aa214a"}, + {file = "multidict-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:4bae31803d708f6f15fd98be6a6ac0b6958fcf68fda3c77a048a4f9073704aae"}, + {file = "multidict-6.0.2.tar.gz", hash = "sha256:5ff3bd75f38e4c43f1f470f2df7a4d430b821c4ce22be384e1459cb57d6bb013"}, +] +py-cord = [] +pytz = [ + {file = "pytz-2022.1-py2.py3-none-any.whl", hash = "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c"}, + {file = "pytz-2022.1.tar.gz", hash = "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7"}, +] +yarl = [] diff --git a/post_updater.py b/post_updater.py index 5e07ece..642f12f 100644 --- a/post_updater.py +++ b/post_updater.py @@ -1,6 +1,8 @@ #!/usr/bin/env python import datetime import os +import sys +import xml.etree.ElementTree as ElementTree from typing import Any @@ -13,6 +15,14 @@ def get_actions_environ( key: str, default_value: Any = None, required: bool = False ) -> Any: + """ + Get the specified enivironment variable. If it does not exist, try appending + INPUT_ to match any GitHub Action-created ones. + + :param str key: The environment variable to retrieve. + :param Any default_value: The default value if this is an optional key. + :param bool required: Whether to raise an exception if the key doesn't exist. + """ if key in os.environ: return os.environ[key] elif f"INPUT_{key.upper()}" in os.environ: @@ -24,46 +34,108 @@ def get_actions_environ( async def post_or_update(): + """ + Main function. Read a file from the POST_FILE or POST_XML environment vars, + construct a message and send it to a specified channel, or otherwise edit + an existing message. + """ + + # Fetch the channel to which to send the message to channel = client.get_channel( int(get_actions_environ("DISCORD_CHANNEL", required=True)) ) if channel is None: print("Channel could not be found! Aborting") return + + # If there is no specific message ID (or the string "new") specified, use + # the last message in the channel. This can fail if anyone can post messages + # in this channel, since the bot can only edit its own messages. message_id = get_actions_environ("DISCORD_MESSAGE", channel.last_message_id) - post_file_path = get_actions_environ("POST_FILE", "/etc/discord-post-updater/post") - with open(post_file_path) as post_file: - post = post_file.read() - - use_embed = bool(get_actions_environ("USE_EMBED", False)) - - args = {} - if use_embed: - args["content"] = "" - args["embed"] = discord.Embed( - title=post.split("\n")[0].split("#")[1].strip(), - description="\n".join(post.split("\n")[1:]).strip(), - colour=int(get_actions_environ("EMBED_COLOR", '0')) - ) - current_uk_time = datetime.datetime.now(tz=pytz.timezone('Europe/London')) - args["embed"].set_footer( - text=f"Last updated: {current_uk_time.strftime('%a, %d %b %Y %H:%M:%S %Z')}" - ) + # Read either the raw markdown or the XML, but not both. + post_file_path = get_actions_environ("POST_FILE", None) + post_xml_path = get_actions_environ("POST_XML", None) + if not post_file_path and not post_xml_path: + print("Neither POST_FILE nor POST_XML was supplied to the action.") + sys.exit(1) + + if post_file_path and post_xml_path: + print("Both POST_FILE and POST_XML was supplied: use one only.") + sys.exit(1) + + # Construcct the arguments to pass to channel.send() + message_args = {} + if post_file_path: + # If we're using raw markdown + with open(post_file_path) as post_file: + post = post_file.read() + + message_args["content"] = post else: - args["content"] = post - + # If we're using XML: + tree = ElementTree.parse(post_xml_path) + message_tag = tree.getroot() + + # Make sure to use getattr with XML since the tag may not be there + message_args["content"] = getattr(message_tag.find("./content"), "text", "") + message_args["embeds"] = [] + + # There can be up to 10 embeds + for embed_tag in message_tag.findall("./embed"): + embed = discord.Embed( + title=getattr(embed_tag.find("./title"), "text", ""), + description=getattr(embed_tag.find("./content"), "text", ""), + colour=int(embed_tag.attrib.get("colour", 0)) + ) + + # An embed can have multiple fields + for field_tag in embed_tag.findall("./field"): + field = discord.EmbedField( + name=getattr(field_tag.find("./title"), "text", ""), + value=getattr(field_tag.find("./content"), "text", ""), + inline=False + ) + embed.append_field(field) + + # Set a time footer unconditionally to indicate this was an auto- + # generated message. + current_uk_time = datetime.datetime.now(tz=pytz.timezone('Europe/London')) + embed.set_footer( + text=f"Last updated: {current_uk_time.strftime('%a, %d %b %Y %H:%M:%S %Z')}" + ) + message_args["embeds"].append(embed) + + # Set up a view for any buttons. If there are no buttons, this will do nothing. + message_args["view"] = discord.ui.View(timeout=None) + # There can be up to 25 buttons, max 5 rows and max 5 cols + for button_tag in message_tag.findall("./button"): + button = discord.ui.Button( + style=getattr(discord.ButtonStyle, button_tag.attrib.get("style", "secondary"), discord.ButtonStyle.secondary), + custom_id=button_tag.attrib.get("id", None), + url=button_tag.attrib.get("url", None), + disabled=button_tag.attrib.get("disabled", None) == "true", + label=getattr(button_tag.find("./label"), "text", ""), + emoji=getattr(button_tag.find("./emoji"), "text", None), + row=int(button_tag.attrib.get("row", 0)) + ) + message_args["view"].add_item(button) + + # Edit existing message if an ID was specified, otherwise create anew. if message_id and message_id != "new": message = await channel.fetch_message(message_id) - await message.edit(**args) + await message.edit(**message_args) else: - await channel.send(**args) + await channel.send(**message_args) @client.event async def on_ready(): print(f"Logged in as {client.user}") - await post_or_update() + try: + await post_or_update() + except Exception: + sys.exit(1) await client.close() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..3ee3c60 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,16 @@ +[tool.poetry] +name = "discord-post-updater" +version = "0.1.0" +description = "" +authors = ["Your Name "] + +[tool.poetry.dependencies] +python = "^3.8" +pytz = "^2022.1" +py-cord = "^2.0.0" + +[tool.poetry.dev-dependencies] + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index a429d81..0000000 --- a/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -discord.py>=1.7.3 -pytz>=2022.1 diff --git a/schema.xsd b/schema.xsd new file mode 100644 index 0000000..6294a67 --- /dev/null +++ b/schema.xsd @@ -0,0 +1,85 @@ + + + + + + + The content tag is for the actual message contents + + + + + The embed tag is for any embeds. Usually, one embed per message is best visually. + + + + + + The embed title + + + + + The embed body + + + + + Fields have titles and contents too but are less pronounced + + + + + + + + + + + + + + + + Buttons can have as attributes: + - "style" (one of Discord button styles), + - "id" (arbitrary but required so bot can choose action based on it) + - "action" (the action performed, either toggle-role:<ID> for roles, toggle-role:<GROUP><ID> for exclusive roles, or toggle-channel-access:<ID>) + - "url" (if it's an external link. "action" cannot co-exist with "url") + - "disabled" (set to true to disable the button) + - "row" (optionally, 0 to 4 row information) + + Buttons can have as inner tags: + - "label" (for the actual text in the button) + - "emoji" (if any emoji should be in the button) + + + + + + + + The button emoji can be the unicode symbol for the emoji, or the <:name:ID> format for custom emojis + + + + + + One of primary, secondary, success, danger, or link. + + + + + + + + + + + + +