--
cgit v1.2.3
From 2d353e93715205d3365730dcc1ae59f61beba87d Mon Sep 17 00:00:00 2001
From: Bluenix
Date: Thu, 14 Jul 2022 03:44:39 +0200
Subject: De-capitalize aiohttp in codejam frameworks
Co-authored-by: Numerlor <25886452+Numerlor@users.noreply.github.com>
---
pydis_site/templates/events/pages/code-jams/9/frameworks.html | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pydis_site/templates/events/pages/code-jams/9/frameworks.html b/pydis_site/templates/events/pages/code-jams/9/frameworks.html
index 57071463..b462c733 100644
--- a/pydis_site/templates/events/pages/code-jams/9/frameworks.html
+++ b/pydis_site/templates/events/pages/code-jams/9/frameworks.html
@@ -71,8 +71,8 @@
-
AioHTTP
-
AioHTTP provides both a client and server WebSocket implementation, while avoiding callback-hell.
+
aiohttp
+
aiohttp provides both a client and server WebSocket implementation, while avoiding callback-hell.
--
cgit v1.2.3
From 124c84b9e4f8195485b6ff9b3896cc87e640e02b Mon Sep 17 00:00:00 2001
From: Hassan Abouelela
Date: Thu, 14 Jul 2022 05:57:05 +0400
Subject: Clean Up Artifact Tests
Signed-off-by: Hassan Abouelela
---
pydis_site/apps/api/tests/test_github_utils.py | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/pydis_site/apps/api/tests/test_github_utils.py b/pydis_site/apps/api/tests/test_github_utils.py
index 78f2979d..a9eab9a5 100644
--- a/pydis_site/apps/api/tests/test_github_utils.py
+++ b/pydis_site/apps/api/tests/test_github_utils.py
@@ -21,7 +21,7 @@ class GeneralUtilityTests(unittest.TestCase):
"""
Intercept the encode method.
- It is performed with an algorithm which does not require a PEM key, as it may
+ The result is encoded with an algorithm which does not require a PEM key, as it may
not be available in testing environments.
"""
self.assertEqual("RS256", algorithm, "The GitHub App JWT must be signed using RS256.")
@@ -39,10 +39,11 @@ class GeneralUtilityTests(unittest.TestCase):
self.assertLess(decoded["exp"], (datetime.datetime.now() + delta).timestamp())
-class WaitForTests(unittest.TestCase):
+class CheckRunTests(unittest.TestCase):
"""Tests the check_run_status utility."""
def test_completed_run(self):
+ """Test that an already completed run returns the correct URL."""
final_url = "some_url_string_1234"
result = github_utils.check_run_status({
@@ -245,20 +246,17 @@ class ArtifactFetcherTests(unittest.TestCase):
class GitHubArtifactViewTests(django.test.TestCase):
"""Test the GitHub artifact fetch API view."""
- @classmethod
- def setUpClass(cls):
- super().setUpClass()
-
- cls.kwargs = {
+ def setUp(self):
+ self.kwargs = {
"owner": "test_owner",
"repo": "test_repo",
"sha": "test_sha",
"action_name": "test_action",
"artifact_name": "test_artifact",
}
- cls.url = reverse("api:github-artifacts", kwargs=cls.kwargs)
+ self.url = reverse("api:github-artifacts", kwargs=self.kwargs)
- def test_successful(self, artifact_mock: mock.Mock):
+ def test_correct_artifact(self, artifact_mock: mock.Mock):
"""Test a proper response is returned with proper input."""
artifact_mock.return_value = "final download url"
result = self.client.get(self.url)
--
cgit v1.2.3
From 675843ea18799da30ca9b01647b55ae2fa7b5ede Mon Sep 17 00:00:00 2001
From: Bluenix
Date: Thu, 14 Jul 2022 04:14:21 +0200
Subject: Strike over passed dates in codejam information
---
pydis_site/templates/events/pages/code-jams/9/_index.html | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pydis_site/templates/events/pages/code-jams/9/_index.html b/pydis_site/templates/events/pages/code-jams/9/_index.html
index 7c57b799..f8d6e88b 100644
--- a/pydis_site/templates/events/pages/code-jams/9/_index.html
+++ b/pydis_site/templates/events/pages/code-jams/9/_index.html
@@ -24,8 +24,8 @@
Saturday, June 18 - Form to submit theme suggestions opens
Wednesday, June 29 - The Qualifier is released
- - Wednesday, July 6 - Voting for the theme opens
- - Wednesday, July 13 - The Qualifier closes
+ Wednesday, July 6 - Voting for the theme opens
+ Wednesday, July 13 - The Qualifier closes
- Thursday, July 21 - Code Jam Begins
- Sunday, July 31 - Coding portion of the jam ends
- Sunday, August 4 - Code Jam submissions are closed
--
cgit v1.2.3
From 0df412364e619b44e1a266b8e372c57fcc8f93ed Mon Sep 17 00:00:00 2001
From: Bluenix
Date: Thu, 14 Jul 2022 04:15:05 +0200
Subject: Remove notification about open codejam qualifier
---
pydis_site/templates/events/index.html | 3 ---
pydis_site/templates/events/pages/code-jams/_index.html | 6 ------
2 files changed, 9 deletions(-)
diff --git a/pydis_site/templates/events/index.html b/pydis_site/templates/events/index.html
index db3e32f7..796a2e34 100644
--- a/pydis_site/templates/events/index.html
+++ b/pydis_site/templates/events/index.html
@@ -9,9 +9,6 @@
{% block event_content %}
-
- The
2022 Summer Code Jam is currently underway and you can still enter!
The qualifier is open until July 13; check out the details
here.
-
Every year we hold a community-wide Summer Code Jam. For this event, members of our community are assigned to teams to collaborate and create something amazing using a technology we picked for them. One such technology that was picked for the Summer 2021 Code Jam was text user interfaces (TUIs), where teams could pick from a pre-approved list of frameworks.
To help fuel the creative process, we provide a specific theme, like Think Inside the Box or Early Internet. At the end of the Code Jam, the projects are judged by Python Discord server staff members and guest judges from the larger Python community. The judges will consider creativity, code quality, teamwork, and adherence to the theme.
If you want to read more about Code Jams, visit our Code Jam info page or watch this video showcasing the best projects created during the Winter Code Jam 2020: Ancient Technology:
diff --git a/pydis_site/templates/events/pages/code-jams/_index.html b/pydis_site/templates/events/pages/code-jams/_index.html
index 74efcfaa..c7975679 100644
--- a/pydis_site/templates/events/pages/code-jams/_index.html
+++ b/pydis_site/templates/events/pages/code-jams/_index.html
@@ -8,12 +8,6 @@
{% block title %}Code Jams{% endblock %}
{% block event_content %}
-
-
- The
2022 Summer Code Jam is currently underway and you can still enter!
The qualifier is open until July 13; check out the details
here.
-
-
-
If you've been around the server for a while, or you just happened to join at the right time,
you may have heard of something known as a Code Jam.
--
cgit v1.2.3
From da38a0cf766e8e9f77d93b8cbda958306b7b980b Mon Sep 17 00:00:00 2001
From: Bluenix
Date: Thu, 14 Jul 2022 18:20:52 +0200
Subject: Update site banner for codejam
---
pydis_site/templates/home/index.html | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pydis_site/templates/home/index.html b/pydis_site/templates/home/index.html
index cdbac830..cf6ff8cd 100644
--- a/pydis_site/templates/home/index.html
+++ b/pydis_site/templates/home/index.html
@@ -12,7 +12,7 @@
@@ -48,7 +48,7 @@
{# Code Jam Banner #}
--
cgit v1.2.3
From e8390858bc8a76dcc3b2c46da02a37860a1dfa84 Mon Sep 17 00:00:00 2001
From: Bluenix
Date: Thu, 14 Jul 2022 19:20:28 +0200
Subject: Remove accidental stray parenthesis in new codejam rule
Co-authored-by: Kieran Siek
---
pydis_site/templates/events/pages/code-jams/9/rules.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pydis_site/templates/events/pages/code-jams/9/rules.html b/pydis_site/templates/events/pages/code-jams/9/rules.html
index a88c795a..e7a85c70 100644
--- a/pydis_site/templates/events/pages/code-jams/9/rules.html
+++ b/pydis_site/templates/events/pages/code-jams/9/rules.html
@@ -18,7 +18,7 @@
Exceptions to this rule are made for resources such as databases and files, albeit excluding usage other than for storage.
For example, you may use PostgreSQL as a database but not its `NOTIFY` command.
- Lastly, working with subprocesses (through stdin/stdout or multiprocessing.Pool()
/concurrent.futures.ProcessPoolExecutor()(
) is also exempted from this rule.
+ Lastly, working with subprocesses (through stdin/stdout or multiprocessing.Pool()
/concurrent.futures.ProcessPoolExecutor()
) is also exempted from this rule.
Your solution should be platform agnostic. For example, if you use filepaths in your submission, use pathlib
to create platform agnostic Path objects instead of hardcoding the paths.
--
cgit v1.2.3
From 974c554da608c0e6c98fbee4beb153b305819c00 Mon Sep 17 00:00:00 2001
From: Bluenix
Date: Fri, 15 Jul 2022 01:26:07 +0200
Subject: Reword new codejam rule exception clause
Co-authored-by: wookie184
---
pydis_site/templates/events/pages/code-jams/9/rules.html | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pydis_site/templates/events/pages/code-jams/9/rules.html b/pydis_site/templates/events/pages/code-jams/9/rules.html
index e7a85c70..cabdd8f4 100644
--- a/pydis_site/templates/events/pages/code-jams/9/rules.html
+++ b/pydis_site/templates/events/pages/code-jams/9/rules.html
@@ -16,9 +16,9 @@
Your solution must only communicate through WebSockets. Any communication between the client and server (or any two server workers), must utilize WebSockets.
- Exceptions to this rule are made for resources such as databases and files, albeit excluding usage other than for storage.
+ An exception to this rule is that communication with databases and files is allowed for accessing resources or for storage purposes.
For example, you may use PostgreSQL as a database but not its `NOTIFY` command.
- Lastly, working with subprocesses (through stdin/stdout or multiprocessing.Pool()
/concurrent.futures.ProcessPoolExecutor()
) is also exempted from this rule.
+ Working with subprocesses (through stdin/stdout or multiprocessing.Pool()
/concurrent.futures.ProcessPoolExecutor()
) is also allowed.
Your solution should be platform agnostic. For example, if you use filepaths in your submission, use pathlib
to create platform agnostic Path objects instead of hardcoding the paths.
--
cgit v1.2.3
From 0d86b4035fbd5ec65620e7680189828971155edb Mon Sep 17 00:00:00 2001
From: Bluenix
Date: Fri, 15 Jul 2022 01:31:29 +0200
Subject: Add note about approval for non-WebSocket communication
---
pydis_site/templates/events/pages/code-jams/9/rules.html | 2 ++
1 file changed, 2 insertions(+)
diff --git a/pydis_site/templates/events/pages/code-jams/9/rules.html b/pydis_site/templates/events/pages/code-jams/9/rules.html
index cabdd8f4..263e84e1 100644
--- a/pydis_site/templates/events/pages/code-jams/9/rules.html
+++ b/pydis_site/templates/events/pages/code-jams/9/rules.html
@@ -20,6 +20,8 @@
For example, you may use PostgreSQL as a database but not its `NOTIFY` command.
Working with subprocesses (through stdin/stdout or multiprocessing.Pool()
/concurrent.futures.ProcessPoolExecutor()
) is also allowed.
+
+ If you're interested in utilizing a particular non-WebSocket method of communication, reach out to the Events Team for discussion and approval
Your solution should be platform agnostic. For example, if you use filepaths in your submission, use pathlib
to create platform agnostic Path objects instead of hardcoding the paths.
-
--
cgit v1.2.3
From 5ad1c2f5e8a5352eebdbb4da996506cbeb0dfc0b Mon Sep 17 00:00:00 2001
From: Bluenix
Date: Fri, 15 Jul 2022 02:43:24 +0200
Subject: Remove trailing space in codejam rules
---
pydis_site/templates/events/pages/code-jams/9/rules.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pydis_site/templates/events/pages/code-jams/9/rules.html b/pydis_site/templates/events/pages/code-jams/9/rules.html
index 263e84e1..5ad75d67 100644
--- a/pydis_site/templates/events/pages/code-jams/9/rules.html
+++ b/pydis_site/templates/events/pages/code-jams/9/rules.html
@@ -16,7 +16,7 @@
Your solution must only communicate through WebSockets. Any communication between the client and server (or any two server workers), must utilize WebSockets.
- An exception to this rule is that communication with databases and files is allowed for accessing resources or for storage purposes.
+ An exception to this rule is that communication with databases and files is allowed for accessing resources or for storage purposes.
For example, you may use PostgreSQL as a database but not its `NOTIFY` command.
Working with subprocesses (through stdin/stdout or multiprocessing.Pool()
/concurrent.futures.ProcessPoolExecutor()
) is also allowed.
--
cgit v1.2.3
From 1a47cc9390bc08f033f677fd1238f5ef437d7071 Mon Sep 17 00:00:00 2001
From: Bluenix
Date: Sun, 17 Jul 2022 18:28:25 +0200
Subject: Copy over qualifier description from codejam 8
---
.../templates/events/pages/code-jams/9/_index.html | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/pydis_site/templates/events/pages/code-jams/9/_index.html b/pydis_site/templates/events/pages/code-jams/9/_index.html
index f8d6e88b..8624bfbb 100644
--- a/pydis_site/templates/events/pages/code-jams/9/_index.html
+++ b/pydis_site/templates/events/pages/code-jams/9/_index.html
@@ -30,12 +30,22 @@
- Sunday, July 31 - Coding portion of the jam ends
- Sunday, August 4 - Code Jam submissions are closed
-
+
+
+
+ The qualifier is a coding challenge that you are required to complete before registering for the code jam.
+ This is meant as a basic assessment of your skills to ensure you have enough python knowledge to effectively contribute in a team environment.
+
+ View the Qualifier
- Before being able to join the code jam, you must complete a qualifier which tests your knowledge in Python.
- The qualifier can be found on our GitHub
- and once completed you should submit your solution using the sign-up form.
+ Please note the requirements for the qualifier.
+
+ - The qualifier must be completed using Python 3.10
+ - No external modules are allowed, only those available through the standard library.
+ - The Qualifier must be submitted through the Code Jam sign-up form.
+
+
The chosen technology/tech stack for this year is WebSockets.
--
cgit v1.2.3
From 473c96a8353e5bea5a639657fac8058d8f44033a Mon Sep 17 00:00:00 2001
From: mina <75038675+minalike@users.noreply.github.com>
Date: Tue, 19 Jul 2022 01:01:44 -0400
Subject: Add back green box link to CJ 9 page
This was the easiest way of navigating to the CJ9 page previously other than the home page. Let's keep it for the duration of the jam
---
pydis_site/templates/events/index.html | 3 +++
1 file changed, 3 insertions(+)
diff --git a/pydis_site/templates/events/index.html b/pydis_site/templates/events/index.html
index 796a2e34..640682d0 100644
--- a/pydis_site/templates/events/index.html
+++ b/pydis_site/templates/events/index.html
@@ -9,6 +9,9 @@
{% block event_content %}
+
Every year we hold a community-wide Summer Code Jam. For this event, members of our community are assigned to teams to collaborate and create something amazing using a technology we picked for them. One such technology that was picked for the Summer 2021 Code Jam was text user interfaces (TUIs), where teams could pick from a pre-approved list of frameworks.
To help fuel the creative process, we provide a specific theme, like Think Inside the Box or Early Internet. At the end of the Code Jam, the projects are judged by Python Discord server staff members and guest judges from the larger Python community. The judges will consider creativity, code quality, teamwork, and adherence to the theme.
If you want to read more about Code Jams, visit our Code Jam info page or watch this video showcasing the best projects created during the Winter Code Jam 2020: Ancient Technology:
--
cgit v1.2.3
From 6a1ab5b856200afc4d98703b07a5aceb74051c1c Mon Sep 17 00:00:00 2001
From: mina <75038675+minalike@users.noreply.github.com>
Date: Tue, 19 Jul 2022 01:03:19 -0400
Subject: Add CJ9 page link to side bar
Technically it's an ongoing jam, not a previous jam. But I think adding this link will help with discoverability if you're already on the CJ Info page. Can be updated once a theme is announced
---
pydis_site/templates/events/sidebar/code-jams/previous-code-jams.html | 1 +
1 file changed, 1 insertion(+)
diff --git a/pydis_site/templates/events/sidebar/code-jams/previous-code-jams.html b/pydis_site/templates/events/sidebar/code-jams/previous-code-jams.html
index 21b2ccb4..4493ed43 100644
--- a/pydis_site/templates/events/sidebar/code-jams/previous-code-jams.html
+++ b/pydis_site/templates/events/sidebar/code-jams/previous-code-jams.html
@@ -1,6 +1,7 @@
--
cgit v1.2.3
From fadda91a5e1733751cc1f68973803d931f2b189f Mon Sep 17 00:00:00 2001
From: Bluenix
Date: Thu, 21 Jul 2022 23:56:15 +0200
Subject: Update codejams sidebar about cj9 theme announcement
---
pydis_site/templates/events/sidebar/code-jams/previous-code-jams.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pydis_site/templates/events/sidebar/code-jams/previous-code-jams.html b/pydis_site/templates/events/sidebar/code-jams/previous-code-jams.html
index 4493ed43..28412c53 100644
--- a/pydis_site/templates/events/sidebar/code-jams/previous-code-jams.html
+++ b/pydis_site/templates/events/sidebar/code-jams/previous-code-jams.html
@@ -1,7 +1,7 @@
{% endblock %}
-
-{% block page_content %}
- {{ block.super }}
-{% endblock %}
--
cgit v1.2.3
From 9d73247694e3a97b357b506f83493e96ecf2c4de Mon Sep 17 00:00:00 2001
From: Hassan Abouelela
Date: Sun, 14 Aug 2022 05:43:22 +0200
Subject: Change Hyperlink Color On Hover
Signed-off-by: Hassan Abouelela
---
pydis_site/static/css/content/tag.css | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/pydis_site/static/css/content/tag.css b/pydis_site/static/css/content/tag.css
index ec45bfc7..32a605a8 100644
--- a/pydis_site/static/css/content/tag.css
+++ b/pydis_site/static/css/content/tag.css
@@ -3,3 +3,7 @@
/* which allows for elements inside links, such as codeblocks */
color: #7289DA;
}
+
+.content a *:hover {
+ color: black;
+}
--
cgit v1.2.3
From 5aeffa5ab4dd8b251d2ae742d1a1e2bf3ba461c7 Mon Sep 17 00:00:00 2001
From: Hassan Abouelela
Date: Sun, 14 Aug 2022 07:14:50 +0200
Subject: Update Tests For Tag Groups
Signed-off-by: Hassan Abouelela
---
pydis_site/apps/content/tests/test_utils.py | 110 +++++++++++++++++++++++-----
pydis_site/apps/content/tests/test_views.py | 68 ++++++++++++++++-
pydis_site/apps/content/utils.py | 3 +-
3 files changed, 157 insertions(+), 24 deletions(-)
diff --git a/pydis_site/apps/content/tests/test_utils.py b/pydis_site/apps/content/tests/test_utils.py
index a5d5dcb4..556f633c 100644
--- a/pydis_site/apps/content/tests/test_utils.py
+++ b/pydis_site/apps/content/tests/test_utils.py
@@ -132,6 +132,7 @@ class TagUtilsTests(TestCase):
---
This tag has frontmatter!
"""),
+ "This is a grouped tag!",
)
# Generate a tar archive with a few tags
@@ -146,6 +147,10 @@ class TagUtilsTests(TestCase):
(tags_folder / "first_tag.md").write_text(bodies[0])
(tags_folder / "second_tag.md").write_text(bodies[1])
+ group_folder = tags_folder / "some_group"
+ group_folder.mkdir()
+ (group_folder / "grouped_tag.md").write_text(bodies[2])
+
with tarfile.open(tar_folder / "temp.tar", "w") as file:
file.add(folder, recursive=True)
@@ -158,10 +163,15 @@ class TagUtilsTests(TestCase):
)
result = utils.fetch_tags()
- self.assertEqual([
+
+ def sort(_tag: models.Tag) -> str:
+ return _tag.name
+
+ self.assertEqual(sorted([
models.Tag(name="first_tag", body=bodies[0]),
models.Tag(name="second_tag", body=bodies[1]),
- ], sorted(result, key=lambda tag: tag.name))
+ models.Tag(name="grouped_tag", body=bodies[2], group=group_folder.name),
+ ], key=sort), sorted(result, key=sort))
def test_get_real_tag(self):
"""Test that a single tag is returned if it exists."""
@@ -170,30 +180,92 @@ class TagUtilsTests(TestCase):
self.assertEqual(tag, result)
+ def test_get_grouped_tag(self):
+ """Test fetching a tag from a group."""
+ tag = models.Tag.objects.create(name="real-tag", group="real-group")
+ result = utils.get_tag("real-group/real-tag")
+
+ self.assertEqual(tag, result)
+
+ def test_get_group(self):
+ """Test fetching a group of tags."""
+ included = [
+ models.Tag.objects.create(name="tag-1", group="real-group"),
+ models.Tag.objects.create(name="tag-2", group="real-group"),
+ models.Tag.objects.create(name="tag-3", group="real-group"),
+ ]
+
+ models.Tag.objects.create(name="not-included-1")
+ models.Tag.objects.create(name="not-included-2", group="other-group")
+
+ result = utils.get_tag("real-group")
+ self.assertListEqual(included, result)
+
def test_get_tag_404(self):
"""Test that an error is raised when we fetch a non-existing tag."""
models.Tag.objects.create(name="real-tag")
with self.assertRaises(models.Tag.DoesNotExist):
utils.get_tag("fake")
- def test_category_pages(self):
- """Test that the category pages function returns the correct records for tags."""
- models.Tag.objects.create(name="second-tag", body="Normal body")
- models.Tag.objects.create(name="first-tag", body="Normal body")
- tag_body = {"description": markdown.markdown("Normal body"), "icon": "fas fa-tag"}
-
+ @mock.patch.object(utils, "get_tag_category")
+ def test_category_pages(self, get_mock: mock.Mock):
+ """Test that the category pages function calls the correct method for tags."""
+ tag = models.Tag.objects.create(name="tag")
+ get_mock.return_value = tag
result = utils.get_category_pages(settings.CONTENT_PAGES_PATH / "tags")
+ self.assertEqual(tag, result)
+ get_mock.assert_called_once_with(collapse_groups=True)
+
+ def test_get_category_root(self):
+ """Test that all tags are returned and formatted properly for the tag root page."""
+ body = "normal body"
+ base = {"description": markdown.markdown(body), "icon": "fas fa-tag"}
+
+ models.Tag.objects.create(name="tag-1", body=body),
+ models.Tag.objects.create(name="tag-2", body=body),
+ models.Tag.objects.create(name="tag-3", body=body),
+
+ models.Tag.objects.create(name="tag-4", body=body, group="tag-group")
+ models.Tag.objects.create(name="tag-5", body=body, group="tag-group")
+
+ result = utils.get_tag_category(collapse_groups=True)
+
self.assertDictEqual({
- "first-tag": {**tag_body, "title": "first-tag"},
- "second-tag": {**tag_body, "title": "second-tag"},
+ "tag-1": {**base, "title": "tag-1"},
+ "tag-2": {**base, "title": "tag-2"},
+ "tag-3": {**base, "title": "tag-3"},
+ "tag-group": {
+ "title": "tag-group",
+ "description": "Contains the following tags: tag-4, tag-5",
+ "icon": "fas fa-tags"
+ }
}, result)
- def test_trimmed_tag_content(self):
- """Test a tag with a long body that requires trimming."""
- tag = models.Tag.objects.create(name="long-tag", body="E" * 300)
- result = utils.get_category_pages(settings.CONTENT_PAGES_PATH / "tags")
- self.assertDictEqual({"long-tag": {
- "title": "long-tag",
- "description": markdown.markdown(tag.body[:100] + "..."),
- "icon": "fas fa-tag",
- }}, result)
+ def test_get_category_group(self):
+ """Test the function for a group root page."""
+ body = "normal body"
+ base = {"description": markdown.markdown(body), "icon": "fas fa-tag"}
+
+ included = [
+ models.Tag.objects.create(name="tag-1", body=body, group="group"),
+ models.Tag.objects.create(name="tag-2", body=body, group="group"),
+ ]
+ models.Tag.objects.create(name="not-included", body=body)
+
+ result = utils.get_tag_category(included, collapse_groups=False)
+ self.assertDictEqual({
+ "tag-1": {**base, "title": "tag-1"},
+ "tag-2": {**base, "title": "tag-2"},
+ }, result)
+
+ def test_tag_url(self):
+ """Test that tag URLs are generated correctly."""
+ cases = [
+ ({"name": "tag"}, f"{models.Tag.URL_BASE}/tag.md"),
+ ({"name": "grouped", "group": "abc"}, f"{models.Tag.URL_BASE}/abc/grouped.md"),
+ ]
+
+ for options, url in cases:
+ tag = models.Tag(**options)
+ with self.subTest(tag=tag):
+ self.assertEqual(url, tag.url)
diff --git a/pydis_site/apps/content/tests/test_views.py b/pydis_site/apps/content/tests/test_views.py
index c4d3474e..c5c25be4 100644
--- a/pydis_site/apps/content/tests/test_views.py
+++ b/pydis_site/apps/content/tests/test_views.py
@@ -194,6 +194,23 @@ class TagViewTests(django.test.TestCase):
"""Set test helpers, then set up fake filesystem."""
super().setUp()
+ def test_routing(self):
+ """Test that the correct template is returned for each route."""
+ Tag.objects.create(name="example")
+ Tag.objects.create(name="grouped-tag", group="group-name")
+
+ cases = [
+ ("/pages/tags/example/", "content/tag.html"),
+ ("/pages/tags/group-name/", "content/listing.html"),
+ ("/pages/tags/group-name/grouped-tag/", "content/tag.html"),
+ ]
+
+ for url, template in cases:
+ with self.subTest(url=url):
+ response = self.client.get(url)
+ self.assertEqual(200, response.status_code)
+ self.assertTemplateUsed(response, template)
+
def test_valid_tag_returns_200(self):
"""Test that a page is returned for a valid tag."""
Tag.objects.create(name="example", body="This is the tag body.")
@@ -207,8 +224,8 @@ class TagViewTests(django.test.TestCase):
response = self.client.get("/pages/tags/non-existent/")
self.assertEqual(404, response.status_code)
- def test_context(self):
- """Check that the context contains all the necessary data."""
+ def test_context_tag(self):
+ """Test that the context contains the required data for a tag."""
body = textwrap.dedent("""
---
unused: frontmatter
@@ -222,12 +239,55 @@ class TagViewTests(django.test.TestCase):
"page_title": "example",
"page": markdown.markdown("Tag content here."),
"tag": tag,
+ "breadcrumb_items": [
+ {"name": "Pages", "path": "."},
+ {"name": "Tags", "path": "tags"},
+ ]
}
for key in expected:
self.assertEqual(
expected[key], response.context.get(key), f"context.{key} did not match"
)
+ def test_context_grouped_tag(self):
+ """
+ Test the context for a tag in a group.
+
+ The only difference between this and a regular tag are the breadcrumbs,
+ so only those are checked.
+ """
+ Tag.objects.create(name="example", body="Body text", group="group-name")
+ response = self.client.get("/pages/tags/group-name/example/")
+ self.assertListEqual([
+ {"name": "Pages", "path": "."},
+ {"name": "Tags", "path": "tags"},
+ {"name": "group-name", "path": "tags/group-name"},
+ ], response.context.get("breadcrumb_items"))
+
+ def test_group_page(self):
+ """Test rendering of a group's root page."""
+ Tag.objects.create(name="tag-1", body="Body 1", group="group-name")
+ Tag.objects.create(name="tag-2", body="Body 2", group="group-name")
+ Tag.objects.create(name="not-included")
+
+ response = self.client.get("/pages/tags/group-name/")
+ content = response.content.decode("utf-8")
+
+ self.assertInHTML("group-name
", content)
+ self.assertInHTML(
+ f"",
+ content
+ )
+ self.assertIn(">tag-1", content)
+ self.assertIn(">tag-2", content)
+ self.assertNotIn(
+ ">not-included",
+ content,
+ "Tags not in this group shouldn't be rendered."
+ )
+
+ self.assertInHTML("Body 1
", content)
+
def test_markdown(self):
"""Test that markdown content is rendered properly."""
body = textwrap.dedent("""
@@ -287,7 +347,7 @@ class TagViewTests(django.test.TestCase):
body = filler_before + "`!tags return`" + filler_after
Tag.objects.create(name="example", body=body)
- other_url = reverse("content:tag", kwargs={"name": "return"})
+ other_url = reverse("content:tag", kwargs={"location": "return"})
response = self.client.get("/pages/tags/example/")
self.assertEqual(
markdown.markdown(filler_before + f"[`!tags return`]({other_url})" + filler_after),
@@ -304,7 +364,7 @@ class TagViewTests(django.test.TestCase):
content = response.content.decode("utf-8")
self.assertTemplateUsed(response, "content/listing.html")
- self.assertInHTML('Tags
', content)
+ self.assertInHTML('Tags
', content)
for tag_number in range(1, 4):
self.assertIn(f"tag-{tag_number}", content)
diff --git a/pydis_site/apps/content/utils.py b/pydis_site/apps/content/utils.py
index da6a024d..11100ba5 100644
--- a/pydis_site/apps/content/utils.py
+++ b/pydis_site/apps/content/utils.py
@@ -48,7 +48,7 @@ def get_tags_static() -> list[Tag]:
This will return a cached value, so it should only be used for static builds.
"""
tags = fetch_tags()
- for tag in tags[3:5]:
+ for tag in tags[3:5]: # pragma: no cover
tag.group = "very-cool-group"
return tags
@@ -190,6 +190,7 @@ def get_tag_category(
# Flatten group description into a single string
for group in groups.values():
+ # If the following string is updated, make sure to update it in the frontend JS as well
group["description"] = "Contains the following tags: " + ", ".join(group["description"])
data.append(group)
--
cgit v1.2.3
From 25db8f564c0f5c473b165ccab14413ca4471ac7d Mon Sep 17 00:00:00 2001
From: Hassan Abouelela
Date: Sun, 14 Aug 2022 07:20:34 +0200
Subject: Explicitly Specify Infraction Time In Tests
The infraction tests checked that the route returned infractions in the
correct order, which is based on insertion time. This can be fragile
however, since the insertion time can be very close (or identical)
during the tests. That became especially more likely with PR #741
(commit 149e67b4) which improved database access speed.
This is fixed by explicitly specifying the insertion time, and spacing
them out properly.
Signed-off-by: Hassan Abouelela
---
pydis_site/apps/api/tests/test_infractions.py | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/pydis_site/apps/api/tests/test_infractions.py b/pydis_site/apps/api/tests/test_infractions.py
index f1107734..89ee4e23 100644
--- a/pydis_site/apps/api/tests/test_infractions.py
+++ b/pydis_site/apps/api/tests/test_infractions.py
@@ -56,15 +56,17 @@ class InfractionTests(AuthenticatedAPITestCase):
type='ban',
reason='He terk my jerb!',
hidden=True,
+ inserted_at=dt(2020, 10, 10, 0, 0, 0, tzinfo=timezone.utc),
expires_at=dt(5018, 11, 20, 15, 52, tzinfo=timezone.utc),
- active=True
+ active=True,
)
cls.ban_inactive = Infraction.objects.create(
user_id=cls.user.id,
actor_id=cls.user.id,
type='ban',
reason='James is an ass, and we won\'t be working with him again.',
- active=False
+ active=False,
+ inserted_at=dt(2020, 10, 10, 0, 1, 0, tzinfo=timezone.utc),
)
cls.mute_permanent = Infraction.objects.create(
user_id=cls.user.id,
@@ -72,7 +74,8 @@ class InfractionTests(AuthenticatedAPITestCase):
type='mute',
reason='He has a filthy mouth and I am his soap.',
active=True,
- expires_at=None
+ inserted_at=dt(2020, 10, 10, 0, 2, 0, tzinfo=timezone.utc),
+ expires_at=None,
)
cls.superstar_expires_soon = Infraction.objects.create(
user_id=cls.user.id,
@@ -80,7 +83,8 @@ class InfractionTests(AuthenticatedAPITestCase):
type='superstar',
reason='This one doesn\'t matter anymore.',
active=True,
- expires_at=dt.now(timezone.utc) + datetime.timedelta(hours=5)
+ inserted_at=dt(2020, 10, 10, 0, 3, 0, tzinfo=timezone.utc),
+ expires_at=dt.now(timezone.utc) + datetime.timedelta(hours=5),
)
cls.voiceban_expires_later = Infraction.objects.create(
user_id=cls.user.id,
@@ -88,7 +92,8 @@ class InfractionTests(AuthenticatedAPITestCase):
type='voice_ban',
reason='Jet engine mic',
active=True,
- expires_at=dt.now(timezone.utc) + datetime.timedelta(days=5)
+ inserted_at=dt(2020, 10, 10, 0, 4, 0, tzinfo=timezone.utc),
+ expires_at=dt.now(timezone.utc) + datetime.timedelta(days=5),
)
def test_list_all(self):
--
cgit v1.2.3
From c5e03fbb8f7a4ebc2f75ce9f8099ba9ef1366f1e Mon Sep 17 00:00:00 2001
From: Ibrahim
Date: Tue, 16 Aug 2022 20:13:21 +0530
Subject: striked passed date
---
pydis_site/templates/events/pages/code-jams/9/_index.html | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pydis_site/templates/events/pages/code-jams/9/_index.html b/pydis_site/templates/events/pages/code-jams/9/_index.html
index 7c2617d7..ca7c4f90 100644
--- a/pydis_site/templates/events/pages/code-jams/9/_index.html
+++ b/pydis_site/templates/events/pages/code-jams/9/_index.html
@@ -27,8 +27,8 @@
Wednesday, July 6 - Voting for the theme opens
Wednesday, July 13 - The Qualifier closes
Thursday, July 21 - Code Jam Begins
- Sunday, July 31 - Coding portion of the jam ends
- Sunday, August 4 - Code Jam submissions are closed
+ Sunday, July 31 - Coding portion of the jam ends
+ Sunday, August 4 - Code Jam submissions are closed
--
cgit v1.2.3
From 5dfe019745b53ceb8ce37f0db937d6e2a302f6d7 Mon Sep 17 00:00:00 2001
From: Hassan Abouelela
Date: Tue, 16 Aug 2022 18:58:29 +0400
Subject: Move GitHub strptime Format To Settings
Signed-off-by: Hassan Abouelela
---
pydis_site/apps/api/github_utils.py | 4 +---
pydis_site/settings.py | 2 ++
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/pydis_site/apps/api/github_utils.py b/pydis_site/apps/api/github_utils.py
index 5d7bcdc3..e9d7347b 100644
--- a/pydis_site/apps/api/github_utils.py
+++ b/pydis_site/apps/api/github_utils.py
@@ -11,8 +11,6 @@ from pydis_site import settings
MAX_RUN_TIME = datetime.timedelta(minutes=10)
"""The maximum time allowed before an action is declared timed out."""
-ISO_FORMAT_STRING = "%Y-%m-%dT%H:%M:%SZ"
-"""The datetime string format GitHub uses."""
class ArtifactProcessingError(Exception):
@@ -147,7 +145,7 @@ def authorize(owner: str, repo: str) -> httpx.Client:
def check_run_status(run: WorkflowRun) -> str:
"""Check if the provided run has been completed, otherwise raise an exception."""
- created_at = datetime.datetime.strptime(run.created_at, ISO_FORMAT_STRING)
+ created_at = datetime.datetime.strptime(run.created_at, settings.GITHUB_TIMESTAMP_FORMAT)
run_time = datetime.datetime.utcnow() - created_at
if run.status != "completed":
diff --git a/pydis_site/settings.py b/pydis_site/settings.py
index 315ea737..9fbd0273 100644
--- a/pydis_site/settings.py
+++ b/pydis_site/settings.py
@@ -38,6 +38,8 @@ GITHUB_API = "https://api.github.com"
GITHUB_TOKEN = env("GITHUB_TOKEN")
GITHUB_APP_ID = env("GITHUB_APP_ID")
GITHUB_APP_KEY = env("GITHUB_APP_KEY")
+GITHUB_TIMESTAMP_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
+"""The datetime string format GitHub uses."""
if GITHUB_APP_KEY and (key_file := Path(GITHUB_APP_KEY)).is_file():
# Allow the OAuth key to be loaded from a file
--
cgit v1.2.3
From f2374900c4c83097c105b56de02ea82d66bd9466 Mon Sep 17 00:00:00 2001
From: Hassan Abouelela
Date: Tue, 16 Aug 2022 21:19:53 +0400
Subject: Unify Tag Migrations & Add Commit Model
Signed-off-by: Hassan Abouelela
---
.../apps/content/migrations/0001_add_tags.py | 34 ++++++++++++++++++++
pydis_site/apps/content/migrations/0001_initial.py | 23 --------------
.../migrations/0002_remove_tag_url_tag_group.py | 22 -------------
pydis_site/apps/content/models/__init__.py | 4 +--
pydis_site/apps/content/models/tag.py | 36 ++++++++++++++++++++++
5 files changed, 72 insertions(+), 47 deletions(-)
create mode 100644 pydis_site/apps/content/migrations/0001_add_tags.py
delete mode 100644 pydis_site/apps/content/migrations/0001_initial.py
delete mode 100644 pydis_site/apps/content/migrations/0002_remove_tag_url_tag_group.py
diff --git a/pydis_site/apps/content/migrations/0001_add_tags.py b/pydis_site/apps/content/migrations/0001_add_tags.py
new file mode 100644
index 00000000..2e9d8c45
--- /dev/null
+++ b/pydis_site/apps/content/migrations/0001_add_tags.py
@@ -0,0 +1,34 @@
+# Generated by Django 4.0.6 on 2022-08-16 16:17
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Commit',
+ fields=[
+ ('sha', models.CharField(help_text='The SHA hash of this commit.', max_length=40, primary_key=True, serialize=False)),
+ ('message', models.TextField(help_text='The commit message.')),
+ ('date', models.DateTimeField(help_text='The date and time the commit was created.')),
+ ('author', models.TextField(help_text='The person(s) who created the commit.')),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Tag',
+ fields=[
+ ('last_updated', models.DateTimeField(auto_now=True, help_text='The date and time this data was last fetched.')),
+ ('name', models.CharField(help_text="The tag's name.", max_length=50, primary_key=True, serialize=False)),
+ ('group', models.CharField(help_text='The group the tag belongs to.', max_length=50, null=True)),
+ ('body', models.TextField(help_text='The content of the tag.')),
+ ('last_commit', models.OneToOneField(help_text='The commit this file was last touched in.', null=True, on_delete=django.db.models.deletion.CASCADE, to='content.commit')),
+ ],
+ ),
+ ]
diff --git a/pydis_site/apps/content/migrations/0001_initial.py b/pydis_site/apps/content/migrations/0001_initial.py
deleted file mode 100644
index 15e3fc95..00000000
--- a/pydis_site/apps/content/migrations/0001_initial.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# Generated by Django 4.0.6 on 2022-08-13 00:53
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- initial = True
-
- dependencies = [
- ]
-
- operations = [
- migrations.CreateModel(
- name='Tag',
- fields=[
- ('last_updated', models.DateTimeField(auto_now=True, help_text='The date and time this data was last fetched.')),
- ('name', models.CharField(help_text="The tag's name.", max_length=50, primary_key=True, serialize=False)),
- ('body', models.TextField(help_text='The content of the tag.')),
- ('url', models.URLField(help_text='The URL to this tag on GitHub.')),
- ],
- ),
- ]
diff --git a/pydis_site/apps/content/migrations/0002_remove_tag_url_tag_group.py b/pydis_site/apps/content/migrations/0002_remove_tag_url_tag_group.py
deleted file mode 100644
index e59077f0..00000000
--- a/pydis_site/apps/content/migrations/0002_remove_tag_url_tag_group.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# Generated by Django 4.0.6 on 2022-08-13 23:48
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('content', '0001_initial'),
- ]
-
- operations = [
- migrations.RemoveField(
- model_name='tag',
- name='url',
- ),
- migrations.AddField(
- model_name='tag',
- name='group',
- field=models.CharField(help_text='The group the tag belongs to.', max_length=50, null=True),
- ),
- ]
diff --git a/pydis_site/apps/content/models/__init__.py b/pydis_site/apps/content/models/__init__.py
index 2718ce94..60007e27 100644
--- a/pydis_site/apps/content/models/__init__.py
+++ b/pydis_site/apps/content/models/__init__.py
@@ -1,3 +1,3 @@
-from .tag import Tag
+from .tag import Commit, Tag
-__all__ = ["Tag"]
+__all__ = ["Commit", "Tag"]
diff --git a/pydis_site/apps/content/models/tag.py b/pydis_site/apps/content/models/tag.py
index 01264ff1..1c89fe1e 100644
--- a/pydis_site/apps/content/models/tag.py
+++ b/pydis_site/apps/content/models/tag.py
@@ -1,6 +1,36 @@
+import json
+
from django.db import models
+class Commit(models.Model):
+ """A git commit."""
+
+ URL_BASE = "https://github.com/python-discord/bot/commit/"
+
+ sha = models.CharField(
+ help_text="The SHA hash of this commit.",
+ primary_key=True,
+ max_length=40,
+ )
+ message = models.TextField(help_text="The commit message.")
+ date = models.DateTimeField(help_text="The date and time the commit was created.")
+ author = models.TextField(help_text="The person(s) who created the commit.")
+
+ @property
+ def url(self) -> str:
+ """The URL to the commit on GitHub."""
+ return self.URL_BASE + self.sha
+
+ @property
+ def format_users(self) -> str:
+ """Return a nice representation of the user(s)' name and email."""
+ authors = []
+ for author in json.loads(self.author):
+ authors.append(f"{author['name']} <{author['email']}>")
+ return ", ".join(authors)
+
+
class Tag(models.Model):
"""A tag from the python-discord server."""
@@ -10,6 +40,12 @@ class Tag(models.Model):
help_text="The date and time this data was last fetched.",
auto_now=True,
)
+ last_commit = models.OneToOneField(
+ Commit,
+ help_text="The commit this file was last touched in.",
+ null=True,
+ on_delete=models.CASCADE,
+ )
name = models.CharField(
help_text="The tag's name.",
primary_key=True,
--
cgit v1.2.3
From 04babac2f281487adcddbf1e92d9d028896e086e Mon Sep 17 00:00:00 2001
From: Hassan Abouelela
Date: Tue, 16 Aug 2022 21:21:59 +0400
Subject: Add Tag Metadata
Uses the commit API to obtain tag metadata such as when it was last
edited, and by whom.
Signed-off-by: Hassan Abouelela
---
.../apps/content/migrations/0001_add_tags.py | 5 +-
pydis_site/apps/content/models/tag.py | 14 ++-
pydis_site/apps/content/utils.py | 124 ++++++++++++++++++---
pydis_site/static/css/content/tag.css | 6 +-
pydis_site/templates/content/tag.html | 22 +++-
5 files changed, 146 insertions(+), 25 deletions(-)
diff --git a/pydis_site/apps/content/migrations/0001_add_tags.py b/pydis_site/apps/content/migrations/0001_add_tags.py
index 2e9d8c45..73525243 100644
--- a/pydis_site/apps/content/migrations/0001_add_tags.py
+++ b/pydis_site/apps/content/migrations/0001_add_tags.py
@@ -1,4 +1,4 @@
-# Generated by Django 4.0.6 on 2022-08-16 16:17
+# Generated by Django 4.0.6 on 2022-08-16 17:38
import django.db.models.deletion
from django.db import migrations, models
@@ -25,10 +25,11 @@ class Migration(migrations.Migration):
name='Tag',
fields=[
('last_updated', models.DateTimeField(auto_now=True, help_text='The date and time this data was last fetched.')),
+ ('sha', models.CharField(help_text="The tag's hash, as calculated by GitHub.", max_length=40)),
('name', models.CharField(help_text="The tag's name.", max_length=50, primary_key=True, serialize=False)),
('group', models.CharField(help_text='The group the tag belongs to.', max_length=50, null=True)),
('body', models.TextField(help_text='The content of the tag.')),
- ('last_commit', models.OneToOneField(help_text='The commit this file was last touched in.', null=True, on_delete=django.db.models.deletion.CASCADE, to='content.commit')),
+ ('last_commit', models.ForeignKey(help_text='The commit this file was last touched in.', null=True, on_delete=django.db.models.deletion.CASCADE, to='content.commit')),
],
),
]
diff --git a/pydis_site/apps/content/models/tag.py b/pydis_site/apps/content/models/tag.py
index 1c89fe1e..3c729768 100644
--- a/pydis_site/apps/content/models/tag.py
+++ b/pydis_site/apps/content/models/tag.py
@@ -1,3 +1,4 @@
+import collections.abc
import json
from django.db import models
@@ -22,13 +23,10 @@ class Commit(models.Model):
"""The URL to the commit on GitHub."""
return self.URL_BASE + self.sha
- @property
- def format_users(self) -> str:
+ def format_users(self) -> collections.abc.Iterable[str]:
"""Return a nice representation of the user(s)' name and email."""
- authors = []
for author in json.loads(self.author):
- authors.append(f"{author['name']} <{author['email']}>")
- return ", ".join(authors)
+ yield f"{author['name']} <{author['email']}>"
class Tag(models.Model):
@@ -40,7 +38,11 @@ class Tag(models.Model):
help_text="The date and time this data was last fetched.",
auto_now=True,
)
- last_commit = models.OneToOneField(
+ sha = models.CharField(
+ help_text="The tag's hash, as calculated by GitHub.",
+ max_length=40,
+ )
+ last_commit = models.ForeignKey(
Commit,
help_text="The commit this file was last touched in.",
null=True,
diff --git a/pydis_site/apps/content/utils.py b/pydis_site/apps/content/utils.py
index 11100ba5..7b078de6 100644
--- a/pydis_site/apps/content/utils.py
+++ b/pydis_site/apps/content/utils.py
@@ -1,5 +1,6 @@
import datetime
import functools
+import json
import tarfile
import tempfile
import typing
@@ -15,11 +16,26 @@ from django.utils import timezone
from markdown.extensions.toc import TocExtension
from pydis_site import settings
-from .models import Tag
+from .models import Commit, Tag
TAG_CACHE_TTL = datetime.timedelta(hours=1)
+def github_client(**kwargs) -> httpx.Client:
+ """Get a client to access the GitHub API with important settings pre-configured."""
+ client = httpx.Client(
+ base_url=settings.GITHUB_API,
+ follow_redirects=True,
+ timeout=settings.TIMEOUT_PERIOD,
+ **kwargs
+ )
+ if settings.GITHUB_TOKEN: # pragma: no cover
+ if not client.headers.get("Authorization"):
+ client.headers = {"Authorization": f"token {settings.GITHUB_TOKEN}"}
+
+ return client
+
+
def get_category(path: Path) -> dict[str, str]:
"""Load category information by name from _info.yml."""
if not path.is_dir():
@@ -60,19 +76,31 @@ def fetch_tags() -> list[Tag]:
The entire repository is downloaded and extracted locally because
getting file content would require one request per file, and can get rate-limited.
"""
- if settings.GITHUB_TOKEN: # pragma: no cover
- headers = {"Authorization": f"token {settings.GITHUB_TOKEN}"}
- else:
- headers = {}
+ client = github_client()
+
+ # Grab metadata
+ metadata = client.get("/repos/python-discord/bot/contents/bot/resources")
+ metadata.raise_for_status()
+
+ hashes = {}
+ for entry in metadata.json():
+ if entry["type"] == "dir":
+ # Tag group
+ files = client.get(entry["url"])
+ files.raise_for_status()
+ files = files.json()
+ else:
+ files = [entry]
- tar_file = httpx.get(
- f"{settings.GITHUB_API}/repos/python-discord/bot/tarball",
- follow_redirects=True,
- timeout=settings.TIMEOUT_PERIOD,
- headers=headers,
- )
+ for file in files:
+ hashes[file["name"]] = file["sha"]
+
+ # Download the files
+ tar_file = client.get("/repos/python-discord/bot/tarball")
tar_file.raise_for_status()
+ client.close()
+
tags = []
with tempfile.TemporaryDirectory() as folder:
with tarfile.open(fileobj=BytesIO(tar_file.content)) as repo:
@@ -83,20 +111,83 @@ def fetch_tags() -> list[Tag]:
repo.extractall(folder, included)
for tag_file in Path(folder).rglob("*.md"):
+ name = tag_file.name
group = None
if tag_file.parent.name != "tags":
# Tags in sub-folders are considered part of a group
group = tag_file.parent.name
tags.append(Tag(
- name=tag_file.name.removesuffix(".md"),
+ name=name.removesuffix(".md"),
+ sha=hashes[name],
group=group,
body=tag_file.read_text(encoding="utf-8"),
+ last_commit=None,
))
return tags
+def set_tag_commit(tag: Tag) -> Tag:
+ """Fetch commit information from the API, and save it for the tag."""
+ path = "/bot/resources/tags"
+ if tag.group:
+ path += f"/{tag.group}"
+ path += f"/{tag.name}.md"
+
+ # Fetch and set the commit
+ with github_client() as client:
+ data = client.get("/repos/python-discord/bot/commits", params={"path": path})
+ data.raise_for_status()
+ data = data.json()[0]
+
+ commit = data["commit"]
+ author, committer = commit["author"], commit["committer"]
+
+ date = datetime.datetime.strptime(committer["date"], settings.GITHUB_TIMESTAMP_FORMAT)
+ date = date.replace(tzinfo=datetime.timezone.utc)
+
+ if author["email"] == committer["email"]:
+ commit_author = [author]
+ else:
+ commit_author = [author, committer]
+
+ commit_obj, _ = Commit.objects.get_or_create(
+ sha=data["sha"],
+ message=commit["message"],
+ date=date,
+ author=json.dumps(commit_author),
+ )
+ tag.last_commit = commit_obj
+ tag.save()
+
+ return tag
+
+
+def record_tags(tags: list[Tag]) -> None:
+ """Sync the database with an updated set of tags."""
+ # Remove entries which no longer exist
+ Tag.objects.exclude(name__in=[tag.name for tag in tags]).delete()
+
+ # Insert/update the tags
+ for tag in tags:
+ try:
+ old_tag = Tag.objects.get(name=tag.name)
+ except Tag.DoesNotExist:
+ # The tag is not in the database yet,
+ # pretend it's previous state is the current state
+ old_tag = tag
+
+ if old_tag.sha == tag.sha and old_tag.last_commit is not None:
+ # We still have an up-to-date commit entry
+ tag.last_commit = old_tag.last_commit
+
+ tag.save()
+
+ # Drop old, unused commits
+ Commit.objects.filter(tag__isnull=True).delete()
+
+
def get_tags() -> list[Tag]:
"""Return a list of all tags visible to the application, from the cache or API."""
if settings.STATIC_BUILD: # pragma: no cover
@@ -113,9 +204,7 @@ def get_tags() -> list[Tag]:
tags = get_tags_static()
else:
tags = fetch_tags()
- Tag.objects.exclude(name__in=[tag.name for tag in tags]).delete()
- for tag in tags:
- tag.save()
+ record_tags(tags)
return tags
else:
@@ -127,6 +216,9 @@ def get_tag(path: str) -> typing.Union[Tag, list[Tag]]:
"""
Return a tag based on the search location.
+ If certain tag data is out of sync (for instance a commit date is missing),
+ an extra request will be made to sync the information.
+
The tag name and group must match. If only one argument is provided in the path,
it's assumed to either be a group name, or a no-group tag name.
@@ -142,6 +234,8 @@ def get_tag(path: str) -> typing.Union[Tag, list[Tag]]:
matches = []
for tag in get_tags():
if tag.name == name and tag.group == group:
+ if tag.last_commit is None:
+ set_tag_commit(tag)
return tag
elif tag.group == name and group is None:
matches.append(tag)
diff --git a/pydis_site/static/css/content/tag.css b/pydis_site/static/css/content/tag.css
index 32a605a8..79795f9e 100644
--- a/pydis_site/static/css/content/tag.css
+++ b/pydis_site/static/css/content/tag.css
@@ -5,5 +5,9 @@
}
.content a *:hover {
- color: black;
+ color: dimgray;
+}
+
+span.update-time {
+ text-decoration: black underline dotted;
}
diff --git a/pydis_site/templates/content/tag.html b/pydis_site/templates/content/tag.html
index 9bd65744..513009da 100644
--- a/pydis_site/templates/content/tag.html
+++ b/pydis_site/templates/content/tag.html
@@ -9,10 +9,30 @@
{% endblock %}
{% block title_element %}
-
+
+
+
{% endblock %}
--
cgit v1.2.3
From 7c240c68e24c0f3bf041522ce21de271cb92c6f3 Mon Sep 17 00:00:00 2001
From: Hassan Abouelela
Date: Tue, 16 Aug 2022 22:08:39 +0400
Subject: Better Split Up Tag Commit Messages
Signed-off-by: Hassan Abouelela
---
pydis_site/apps/content/models/tag.py | 5 +++++
pydis_site/templates/content/tag.html | 4 +++-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/pydis_site/apps/content/models/tag.py b/pydis_site/apps/content/models/tag.py
index 3c729768..c504ce21 100644
--- a/pydis_site/apps/content/models/tag.py
+++ b/pydis_site/apps/content/models/tag.py
@@ -23,6 +23,11 @@ class Commit(models.Model):
"""The URL to the commit on GitHub."""
return self.URL_BASE + self.sha
+ def lines(self) -> collections.abc.Iterable[str]:
+ """Return each line in the commit message."""
+ for line in self.message.split("\n"):
+ yield line
+
def format_users(self) -> collections.abc.Iterable[str]:
"""Return a nice representation of the user(s)' name and email."""
for author in json.loads(self.author):
diff --git a/pydis_site/templates/content/tag.html b/pydis_site/templates/content/tag.html
index 513009da..655dd786 100644
--- a/pydis_site/templates/content/tag.html
+++ b/pydis_site/templates/content/tag.html
@@ -31,7 +31,9 @@
{{ user }}
{% endfor %}
- {{ tag.last_commit.message }}
+ {% for line in tag.last_commit.lines %}
+ {{ line }}
+ {% endfor %}
--
cgit v1.2.3
From 89b0853245fdf5ba7f1f386d7ea7ab1548b538da Mon Sep 17 00:00:00 2001
From: Hassan Abouelela
Date: Tue, 16 Aug 2022 22:09:14 +0400
Subject: Fix Tag Metadata For Static Builds
Signed-off-by: Hassan Abouelela
---
pydis_site/apps/content/utils.py | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/pydis_site/apps/content/utils.py b/pydis_site/apps/content/utils.py
index 7b078de6..e4a24a73 100644
--- a/pydis_site/apps/content/utils.py
+++ b/pydis_site/apps/content/utils.py
@@ -128,8 +128,19 @@ def fetch_tags() -> list[Tag]:
return tags
-def set_tag_commit(tag: Tag) -> Tag:
+def set_tag_commit(tag: Tag) -> None:
"""Fetch commit information from the API, and save it for the tag."""
+ if settings.STATIC_BUILD:
+ # Static builds request every page during build, which can ratelimit it.
+ # Instead, we return some fake data.
+ tag.last_commit = Commit(
+ sha="68da80efc00d9932a209d5cccd8d344cec0f09ea",
+ message="Initial Commit\n\nTHIS IS FAKE DEMO DATA",
+ date=datetime.datetime(2018, 2, 3, 12, 20, 26, tzinfo=datetime.timezone.utc),
+ author=json.dumps([{"name": "Joseph", "email": "joseph@josephbanks.me"}]),
+ )
+ return
+
path = "/bot/resources/tags"
if tag.group:
path += f"/{tag.group}"
@@ -161,8 +172,6 @@ def set_tag_commit(tag: Tag) -> Tag:
tag.last_commit = commit_obj
tag.save()
- return tag
-
def record_tags(tags: list[Tag]) -> None:
"""Sync the database with an updated set of tags."""
--
cgit v1.2.3
From 92a42694b6ad1a29e5a21e0b3e57639528837113 Mon Sep 17 00:00:00 2001
From: Hassan Abouelela
Date: Tue, 16 Aug 2022 23:45:25 +0400
Subject: Fix Tests For Tag Metadata
Signed-off-by: Hassan Abouelela
---
pydis_site/apps/api/tests/test_github_utils.py | 7 +-
pydis_site/apps/content/tests/test_utils.py | 132 +++++++++++++++++++++++--
pydis_site/apps/content/tests/test_views.py | 36 ++++---
pydis_site/apps/content/utils.py | 2 +-
4 files changed, 148 insertions(+), 29 deletions(-)
diff --git a/pydis_site/apps/api/tests/test_github_utils.py b/pydis_site/apps/api/tests/test_github_utils.py
index f642f689..6e25bc80 100644
--- a/pydis_site/apps/api/tests/test_github_utils.py
+++ b/pydis_site/apps/api/tests/test_github_utils.py
@@ -11,6 +11,7 @@ import rest_framework.response
import rest_framework.test
from django.urls import reverse
+from pydis_site import settings
from .. import github_utils
@@ -49,7 +50,7 @@ class CheckRunTests(unittest.TestCase):
"head_sha": "sha",
"status": "completed",
"conclusion": "success",
- "created_at": datetime.datetime.utcnow().strftime(github_utils.ISO_FORMAT_STRING),
+ "created_at": datetime.datetime.utcnow().strftime(settings.GITHUB_TIMESTAMP_FORMAT),
"artifacts_url": "url",
}
@@ -74,7 +75,7 @@ class CheckRunTests(unittest.TestCase):
# to guarantee the right conclusion
kwargs["created_at"] = (
datetime.datetime.utcnow() - github_utils.MAX_RUN_TIME - datetime.timedelta(minutes=10)
- ).strftime(github_utils.ISO_FORMAT_STRING)
+ ).strftime(settings.GITHUB_TIMESTAMP_FORMAT)
with self.assertRaises(github_utils.RunTimeoutError):
github_utils.check_run_status(github_utils.WorkflowRun(**kwargs))
@@ -178,7 +179,7 @@ class ArtifactFetcherTests(unittest.TestCase):
run = github_utils.WorkflowRun(
name="action_name",
head_sha="action_sha",
- created_at=datetime.datetime.now().strftime(github_utils.ISO_FORMAT_STRING),
+ created_at=datetime.datetime.now().strftime(settings.GITHUB_TIMESTAMP_FORMAT),
status="completed",
conclusion="success",
artifacts_url="artifacts_url"
diff --git a/pydis_site/apps/content/tests/test_utils.py b/pydis_site/apps/content/tests/test_utils.py
index 556f633c..2ef033e4 100644
--- a/pydis_site/apps/content/tests/test_utils.py
+++ b/pydis_site/apps/content/tests/test_utils.py
@@ -1,3 +1,5 @@
+import datetime
+import json
import tarfile
import tempfile
import textwrap
@@ -15,6 +17,18 @@ from pydis_site.apps.content.tests.helpers import (
BASE_PATH, MockPagesTestCase, PARSED_CATEGORY_INFO, PARSED_HTML, PARSED_METADATA
)
+_time = datetime.datetime(2022, 10, 10, 10, 10, 10, tzinfo=datetime.timezone.utc)
+_time_str = _time.strftime(settings.GITHUB_TIMESTAMP_FORMAT)
+TEST_COMMIT_KWARGS = {
+ "sha": "123",
+ "message": "Hello world\n\nThis is a commit message",
+ "date": _time,
+ "author": json.dumps([
+ {"name": "Author 1", "email": "mail1@example.com", "date": _time_str},
+ {"name": "Author 2", "email": "mail2@example.com", "date": _time_str},
+ ]),
+}
+
class GetCategoryTests(MockPagesTestCase):
"""Tests for the get_category function."""
@@ -109,6 +123,10 @@ class GetPageTests(MockPagesTestCase):
class TagUtilsTests(TestCase):
"""Tests for the tag-related utilities."""
+ def setUp(self) -> None:
+ super().setUp()
+ self.commit = models.Commit.objects.create(**TEST_COMMIT_KWARGS)
+
@mock.patch.object(utils, "fetch_tags")
def test_static_fetch(self, fetch_mock: mock.Mock):
"""Test that the static fetch function is only called at most once during static builds."""
@@ -121,9 +139,27 @@ class TagUtilsTests(TestCase):
self.assertEqual(tags, result)
self.assertEqual(tags, second_result)
- @mock.patch("httpx.get")
+ @mock.patch("httpx.Client.get")
def test_mocked_fetch(self, get_mock: mock.Mock):
"""Test that proper data is returned from fetch, but with a mocked API response."""
+ fake_request = httpx.Request("GET", "https://google.com")
+
+ # Metadata requests
+ returns = [httpx.Response(
+ request=fake_request,
+ status_code=200,
+ json=[
+ {"type": "file", "name": "first_tag.md", "sha": "123"},
+ {"type": "file", "name": "second_tag.md", "sha": "456"},
+ {"type": "dir", "name": "some_group", "sha": "789", "url": "/some_group"},
+ ]
+ ), httpx.Response(
+ request=fake_request,
+ status_code=200,
+ json=[{"type": "file", "name": "grouped_tag.md", "sha": "789123"}]
+ )]
+
+ # Main content request
bodies = (
"This is the first tag!",
textwrap.dedent("""
@@ -156,33 +192,36 @@ class TagUtilsTests(TestCase):
body = (tar_folder / "temp.tar").read_bytes()
- get_mock.return_value = httpx.Response(
+ returns.append(httpx.Response(
status_code=200,
content=body,
- request=httpx.Request("GET", "https://google.com"),
- )
+ request=fake_request,
+ ))
+ get_mock.side_effect = returns
result = utils.fetch_tags()
def sort(_tag: models.Tag) -> str:
return _tag.name
self.assertEqual(sorted([
- models.Tag(name="first_tag", body=bodies[0]),
- models.Tag(name="second_tag", body=bodies[1]),
- models.Tag(name="grouped_tag", body=bodies[2], group=group_folder.name),
+ models.Tag(name="first_tag", body=bodies[0], sha="123"),
+ models.Tag(name="second_tag", body=bodies[1], sha="245"),
+ models.Tag(name="grouped_tag", body=bodies[2], group=group_folder.name, sha="789123"),
], key=sort), sorted(result, key=sort))
def test_get_real_tag(self):
"""Test that a single tag is returned if it exists."""
- tag = models.Tag.objects.create(name="real-tag")
+ tag = models.Tag.objects.create(name="real-tag", last_commit=self.commit)
result = utils.get_tag("real-tag")
self.assertEqual(tag, result)
def test_get_grouped_tag(self):
"""Test fetching a tag from a group."""
- tag = models.Tag.objects.create(name="real-tag", group="real-group")
+ tag = models.Tag.objects.create(
+ name="real-tag", group="real-group", last_commit=self.commit
+ )
result = utils.get_tag("real-group/real-tag")
self.assertEqual(tag, result)
@@ -269,3 +308,78 @@ class TagUtilsTests(TestCase):
tag = models.Tag(**options)
with self.subTest(tag=tag):
self.assertEqual(url, tag.url)
+
+ @mock.patch("httpx.Client.get")
+ def test_get_tag_commit(self, get_mock: mock.Mock):
+ """Test the get commit function with a normal tag."""
+ tag = models.Tag.objects.create(name="example")
+
+ authors = json.loads(self.commit.author)
+
+ get_mock.return_value = httpx.Response(
+ request=httpx.Request("GET", "https://google.com"),
+ status_code=200,
+ json=[{
+ "sha": self.commit.sha,
+ "commit": {
+ "message": self.commit.message,
+ "author": authors[0],
+ "committer": authors[1],
+ }
+ }]
+ )
+
+ result = utils.get_tag(tag.name)
+ self.assertEqual(tag, result)
+
+ get_mock.assert_called_once()
+ call_params = get_mock.call_args[1]["params"]
+
+ self.assertEqual({"path": "/bot/resources/tags/example.md"}, call_params)
+ self.assertEqual(self.commit, models.Tag.objects.get(name=tag.name).last_commit)
+
+ @mock.patch("httpx.Client.get")
+ def test_get_group_tag_commit(self, get_mock: mock.Mock):
+ """Test the get commit function with a group tag."""
+ tag = models.Tag.objects.create(name="example", group="group-name")
+
+ authors = json.loads(self.commit.author)
+ authors.pop()
+ self.commit.author = json.dumps(authors)
+ self.commit.save()
+
+ get_mock.return_value = httpx.Response(
+ request=httpx.Request("GET", "https://google.com"),
+ status_code=200,
+ json=[{
+ "sha": self.commit.sha,
+ "commit": {
+ "message": self.commit.message,
+ "author": authors[0],
+ "committer": authors[0],
+ }
+ }]
+ )
+
+ utils.set_tag_commit(tag)
+
+ get_mock.assert_called_once()
+ call_params = get_mock.call_args[1]["params"]
+
+ self.assertEqual({"path": "/bot/resources/tags/group-name/example.md"}, call_params)
+ self.assertEqual(self.commit, models.Tag.objects.get(name=tag.name).last_commit)
+
+ @mock.patch.object(utils, "set_tag_commit")
+ def test_exiting_commit(self, set_commit_mock: mock.Mock):
+ """Test that a commit is saved when the data has not changed."""
+ tag = models.Tag.objects.create(name="tag-name", body="old body", last_commit=self.commit)
+
+ # This is only applied to the object, not to the database
+ tag.last_commit = None
+
+ utils.record_tags([tag])
+ self.assertEqual(self.commit, tag.last_commit)
+
+ result = utils.get_tag("tag-name")
+ self.assertEqual(tag, result)
+ set_commit_mock.assert_not_called()
diff --git a/pydis_site/apps/content/tests/test_views.py b/pydis_site/apps/content/tests/test_views.py
index c5c25be4..658ac2cc 100644
--- a/pydis_site/apps/content/tests/test_views.py
+++ b/pydis_site/apps/content/tests/test_views.py
@@ -8,10 +8,11 @@ from django.http import Http404
from django.test import RequestFactory, SimpleTestCase, override_settings
from django.urls import reverse
-from pydis_site.apps.content.models import Tag
+from pydis_site.apps.content.models import Commit, Tag
from pydis_site.apps.content.tests.helpers import (
BASE_PATH, MockPagesTestCase, PARSED_CATEGORY_INFO, PARSED_HTML, PARSED_METADATA
)
+from pydis_site.apps.content.tests.test_utils import TEST_COMMIT_KWARGS
from pydis_site.apps.content.views import PageOrCategoryView
@@ -193,11 +194,12 @@ class TagViewTests(django.test.TestCase):
def setUp(self):
"""Set test helpers, then set up fake filesystem."""
super().setUp()
+ self.commit = Commit.objects.create(**TEST_COMMIT_KWARGS)
def test_routing(self):
"""Test that the correct template is returned for each route."""
- Tag.objects.create(name="example")
- Tag.objects.create(name="grouped-tag", group="group-name")
+ Tag.objects.create(name="example", last_commit=self.commit)
+ Tag.objects.create(name="grouped-tag", group="group-name", last_commit=self.commit)
cases = [
("/pages/tags/example/", "content/tag.html"),
@@ -213,7 +215,7 @@ class TagViewTests(django.test.TestCase):
def test_valid_tag_returns_200(self):
"""Test that a page is returned for a valid tag."""
- Tag.objects.create(name="example", body="This is the tag body.")
+ Tag.objects.create(name="example", body="This is the tag body.", last_commit=self.commit)
response = self.client.get("/pages/tags/example/")
self.assertEqual(200, response.status_code)
self.assertIn("This is the tag body", response.content.decode("utf-8"))
@@ -233,7 +235,7 @@ class TagViewTests(django.test.TestCase):
Tag content here.
""")
- tag = Tag.objects.create(name="example", body=body)
+ tag = Tag.objects.create(name="example", body=body, last_commit=self.commit)
response = self.client.get("/pages/tags/example/")
expected = {
"page_title": "example",
@@ -256,7 +258,9 @@ class TagViewTests(django.test.TestCase):
The only difference between this and a regular tag are the breadcrumbs,
so only those are checked.
"""
- Tag.objects.create(name="example", body="Body text", group="group-name")
+ Tag.objects.create(
+ name="example", body="Body text", group="group-name", last_commit=self.commit
+ )
response = self.client.get("/pages/tags/group-name/example/")
self.assertListEqual([
{"name": "Pages", "path": "."},
@@ -266,9 +270,9 @@ class TagViewTests(django.test.TestCase):
def test_group_page(self):
"""Test rendering of a group's root page."""
- Tag.objects.create(name="tag-1", body="Body 1", group="group-name")
- Tag.objects.create(name="tag-2", body="Body 2", group="group-name")
- Tag.objects.create(name="not-included")
+ Tag.objects.create(name="tag-1", body="Body 1", group="group-name", last_commit=self.commit)
+ Tag.objects.create(name="tag-2", body="Body 2", group="group-name", last_commit=self.commit)
+ Tag.objects.create(name="not-included", last_commit=self.commit)
response = self.client.get("/pages/tags/group-name/")
content = response.content.decode("utf-8")
@@ -298,7 +302,7 @@ class TagViewTests(django.test.TestCase):
**This text is in bold**
""")
- Tag.objects.create(name="example", body=body)
+ Tag.objects.create(name="example", body=body, last_commit=self.commit)
response = self.client.get("/pages/tags/example/")
content = response.content.decode("utf-8")
@@ -317,7 +321,7 @@ class TagViewTests(django.test.TestCase):
Tag body.
""")
- Tag.objects.create(name="example", body=body)
+ Tag.objects.create(name="example", body=body, last_commit=self.commit)
response = self.client.get("/pages/tags/example/")
content = response.content.decode("utf-8")
@@ -333,7 +337,7 @@ class TagViewTests(django.test.TestCase):
---
""")
- Tag.objects.create(name="example", body=body)
+ Tag.objects.create(name="example", body=body, last_commit=self.commit)
response = self.client.get("/pages/tags/example/")
self.assertEqual(
"Embed title",
@@ -345,7 +349,7 @@ class TagViewTests(django.test.TestCase):
"""Test hyperlinking of tags works as intended."""
filler_before, filler_after = "empty filler text\n\n", "more\nfiller"
body = filler_before + "`!tags return`" + filler_after
- Tag.objects.create(name="example", body=body)
+ Tag.objects.create(name="example", body=body, last_commit=self.commit)
other_url = reverse("content:tag", kwargs={"location": "return"})
response = self.client.get("/pages/tags/example/")
@@ -356,9 +360,9 @@ class TagViewTests(django.test.TestCase):
def test_tag_root_page(self):
"""Test the root tag page which lists all tags."""
- Tag.objects.create(name="tag-1")
- Tag.objects.create(name="tag-2")
- Tag.objects.create(name="tag-3")
+ Tag.objects.create(name="tag-1", last_commit=self.commit)
+ Tag.objects.create(name="tag-2", last_commit=self.commit)
+ Tag.objects.create(name="tag-3", last_commit=self.commit)
response = self.client.get("/pages/tags/")
content = response.content.decode("utf-8")
diff --git a/pydis_site/apps/content/utils.py b/pydis_site/apps/content/utils.py
index e4a24a73..63f1c41c 100644
--- a/pydis_site/apps/content/utils.py
+++ b/pydis_site/apps/content/utils.py
@@ -130,7 +130,7 @@ def fetch_tags() -> list[Tag]:
def set_tag_commit(tag: Tag) -> None:
"""Fetch commit information from the API, and save it for the tag."""
- if settings.STATIC_BUILD:
+ if settings.STATIC_BUILD: # pragma: no cover
# Static builds request every page during build, which can ratelimit it.
# Instead, we return some fake data.
tag.last_commit = Commit(
--
cgit v1.2.3
From c0823236d20e801550fccdbb021d8aabb56d59c0 Mon Sep 17 00:00:00 2001
From: Amrou Bellalouna
Date: Thu, 18 Aug 2022 16:58:08 +0100
Subject: add collection of keywords per rule
In reference to issue #2108, this commit aims to add an initial set of keywords per rule.
These keywords will be later in the "rule" bot command in order to make rule identification easier
---
pydis_site/apps/api/views.py | 27 ++++++++++++++++++---------
1 file changed, 18 insertions(+), 9 deletions(-)
diff --git a/pydis_site/apps/api/views.py b/pydis_site/apps/api/views.py
index ad2d948e..f96d6a8d 100644
--- a/pydis_site/apps/api/views.py
+++ b/pydis_site/apps/api/views.py
@@ -124,35 +124,44 @@ class RulesView(APIView):
return Response([
(
- f"Follow the {pydis_coc}."
+ f"Follow the {pydis_coc}.",
+ {"coc", "conduct", "code"}
),
(
- f"Follow the {discord_community_guidelines} and {discord_tos}."
+ f"Follow the {discord_community_guidelines} and {discord_tos}.",
+ {"guidelines", "discord_tos"}
),
(
- "Respect staff members and listen to their instructions."
+ "Respect staff members and listen to their instructions.",
+ {"staff", "instructions"}
),
(
"Use English to the best of your ability. "
- "Be polite if someone speaks English imperfectly."
+ "Be polite if someone speaks English imperfectly.",
+ {"english", "language"}
),
(
"Do not provide or request help on projects that may break laws, "
- "breach terms of services, or are malicious or inappropriate."
+ "breach terms of services, or are malicious or inappropriate.",
+ {"infraction", "tos", "breach", "malicious", "inappropriate"}
),
(
- "Do not post unapproved advertising."
+ "Do not post unapproved advertising.",
+ {"ads", "advertising"}
),
(
"Keep discussions relevant to the channel topic. "
- "Each channel's description tells you the topic."
+ "Each channel's description tells you the topic.",
+ {"off-topic", "topic", "relevance"}
),
(
"Do not help with ongoing exams. When helping with homework, "
- "help people learn how to do the assignment without doing it for them."
+ "help people learn how to do the assignment without doing it for them.",
+ {"exams", "assignment", "assignments", "homework"}
),
(
- "Do not offer or ask for paid work of any kind."
+ "Do not offer or ask for paid work of any kind.",
+ {"work", "money"}
),
])
--
cgit v1.2.3
From c0384c626121684ad4e354aeb817fdbd2741fc4f Mon Sep 17 00:00:00 2001
From: Hassan Abouelela
Date: Tue, 23 Aug 2022 01:09:01 +0400
Subject: Improve Tag Commit Naming
Signed-off-by: Hassan Abouelela
---
pydis_site/apps/content/models/tag.py | 6 +++---
pydis_site/apps/content/urls.py | 2 +-
pydis_site/templates/content/tag.html | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/pydis_site/apps/content/models/tag.py b/pydis_site/apps/content/models/tag.py
index c504ce21..73d6cb79 100644
--- a/pydis_site/apps/content/models/tag.py
+++ b/pydis_site/apps/content/models/tag.py
@@ -5,7 +5,7 @@ from django.db import models
class Commit(models.Model):
- """A git commit."""
+ """A git commit from the Python Discord Bot project."""
URL_BASE = "https://github.com/python-discord/bot/commit/"
@@ -28,8 +28,8 @@ class Commit(models.Model):
for line in self.message.split("\n"):
yield line
- def format_users(self) -> collections.abc.Iterable[str]:
- """Return a nice representation of the user(s)' name and email."""
+ def format_authors(self) -> collections.abc.Iterable[str]:
+ """Return a nice representation of the author(s)' name and email."""
for author in json.loads(self.author):
yield f"{author['name']} <{author['email']}>"
diff --git a/pydis_site/apps/content/urls.py b/pydis_site/apps/content/urls.py
index 03c0015a..163d05bc 100644
--- a/pydis_site/apps/content/urls.py
+++ b/pydis_site/apps/content/urls.py
@@ -63,5 +63,5 @@ urlpatterns = [
views.PageOrCategoryView.as_view(),
name='page_category',
distill_func=get_all_pages
- )
+ ),
]
diff --git a/pydis_site/templates/content/tag.html b/pydis_site/templates/content/tag.html
index 655dd786..fa9e44f5 100644
--- a/pydis_site/templates/content/tag.html
+++ b/pydis_site/templates/content/tag.html
@@ -27,7 +27,7 @@