From 36b43f94cb1f8c622914048696efec8ccdeb608f Mon Sep 17 00:00:00 2001 From: Cam Caswell Date: Sat, 19 Mar 2022 23:42:45 -0400 Subject: Add guide for pull requests and reviews This covers the GitHub UI for opening a pull request, getting it reviewed, and draft PRs. --- .../static/images/content/contributing/pull_request.png | Bin 0 -> 10190 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 pydis_site/static/images/content/contributing/pull_request.png (limited to 'pydis_site/static') diff --git a/pydis_site/static/images/content/contributing/pull_request.png b/pydis_site/static/images/content/contributing/pull_request.png new file mode 100644 index 00000000..87b7ffbe Binary files /dev/null and b/pydis_site/static/images/content/contributing/pull_request.png differ -- cgit v1.2.3 From fc982b4bfad66ae9e5adfdb2ec42e142920dff49 Mon Sep 17 00:00:00 2001 From: minalike Date: Tue, 26 Apr 2022 23:45:37 -0400 Subject: Force line break at arbritrary points for really long words --- pydis_site/static/css/staff/logs.css | 3 +++ 1 file changed, 3 insertions(+) (limited to 'pydis_site/static') diff --git a/pydis_site/static/css/staff/logs.css b/pydis_site/static/css/staff/logs.css index acf4f1f7..56a12380 100644 --- a/pydis_site/static/css/staff/logs.css +++ b/pydis_site/static/css/staff/logs.css @@ -25,7 +25,10 @@ main.site-content { .discord-message:first-child { border-top: 1px; +} +.discord-message-content { + overflow-wrap: break-word; } .discord-message-header { -- cgit v1.2.3 From fa1dd4058e8606f165df5ff7902d9215eeec4679 Mon Sep 17 00:00:00 2001 From: Krypton Date: Thu, 28 Apr 2022 19:00:06 +0200 Subject: Using static images --- .../python-guides/discord-messages-with-colors.md | 8 ++++---- .../content/discord_colored_messages/ansi-colors.png | Bin 0 -> 33579 bytes .../images/content/discord_colored_messages/result.png | Bin 0 -> 13740 bytes 3 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 pydis_site/static/images/content/discord_colored_messages/ansi-colors.png create mode 100644 pydis_site/static/images/content/discord_colored_messages/result.png (limited to 'pydis_site/static') diff --git a/pydis_site/apps/content/resources/guides/python-guides/discord-messages-with-colors.md b/pydis_site/apps/content/resources/guides/python-guides/discord-messages-with-colors.md index c8e50d71..6845ce76 100644 --- a/pydis_site/apps/content/resources/guides/python-guides/discord-messages-with-colors.md +++ b/pydis_site/apps/content/resources/guides/python-guides/discord-messages-with-colors.md @@ -48,17 +48,17 @@ I simply use `\u001b[0;40m` (background color) and `\u001b[1;32m` (text color) a Alternatively you can also directly combine them into a single prefix like the following: `\u001b[1;40;32m` and you can also use multiple values. Something like `\u001b[1;40;4;32m` would underline the text, make it bold, make it green and have a dark blue background. Raw message:
-\`\`\`ansi
+\`\`\`ansi \u001b[0;40m\u001b[1;32mThat's some cool formatted text right?
-or
+or \u001b[1;40;32mThat's some cool formatted text right?
\`\`\` Result: -![Background and text color](https://media.discordapp.net/attachments/739937507768270939/930460020603224084/Background-Text-Color.png) +![Background and text color result](/static/images/content/discord_colored_messages/result.png) The way the colors look like on Discord is shown in the image below: -![ANSI Colors](https://media.discordapp.net/attachments/739937507768270939/930825555803263016/ANSI-Colors.png) +![ANSI Colors](/static/images/content/discord_colored_messages/ansi-colors.png) Note: If the change as not been brought to you yet, or other users, then you can use other code blocks in the meantime to get colored text. See this gist: diff --git a/pydis_site/static/images/content/discord_colored_messages/ansi-colors.png b/pydis_site/static/images/content/discord_colored_messages/ansi-colors.png new file mode 100644 index 00000000..32af146f Binary files /dev/null and b/pydis_site/static/images/content/discord_colored_messages/ansi-colors.png differ diff --git a/pydis_site/static/images/content/discord_colored_messages/result.png b/pydis_site/static/images/content/discord_colored_messages/result.png new file mode 100644 index 00000000..a666804e Binary files /dev/null and b/pydis_site/static/images/content/discord_colored_messages/result.png differ -- cgit v1.2.3 From e3067dc451a3a5da02a90d61791c1c7c5731cab0 Mon Sep 17 00:00:00 2001 From: Krypton Date: Thu, 28 Apr 2022 19:17:00 +0200 Subject: Removed `
`'s and used code block for raw message --- .../python-guides/discord-messages-with-colors.md | 15 +++++++++------ .../discord_colored_messages/ansi-colors.png | Bin 33579 -> 43004 bytes 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'pydis_site/static') diff --git a/pydis_site/apps/content/resources/guides/python-guides/discord-messages-with-colors.md b/pydis_site/apps/content/resources/guides/python-guides/discord-messages-with-colors.md index 6845ce76..9a69973e 100644 --- a/pydis_site/apps/content/resources/guides/python-guides/discord-messages-with-colors.md +++ b/pydis_site/apps/content/resources/guides/python-guides/discord-messages-with-colors.md @@ -44,15 +44,18 @@ Here is the list of values you can use to replace `{color}`: * 47: White Let's take an example, I want a bold green colored text with the very dark blue background. -I simply use `\u001b[0;40m` (background color) and `\u001b[1;32m` (text color) as prefix. Note that the order is **important**, first you give the background color and then the text color.
+I simply use `\u001b[0;40m` (background color) and `\u001b[1;32m` (text color) as prefix. Note that the order is **important**, first you give the background color and then the text color. + Alternatively you can also directly combine them into a single prefix like the following: `\u001b[1;40;32m` and you can also use multiple values. Something like `\u001b[1;40;4;32m` would underline the text, make it bold, make it green and have a dark blue background. -Raw message:
-\`\`\`ansi -\u001b[0;40m\u001b[1;32mThat's some cool formatted text right?
+Raw message: +````nohighlight +```ansi +\u001b[0;40m\u001b[1;32mThat's some cool formatted text right? or -\u001b[1;40;32mThat's some cool formatted text right?
-\`\`\` +\u001b[1;40;32mThat's some cool formatted text right? +``` +```` Result: diff --git a/pydis_site/static/images/content/discord_colored_messages/ansi-colors.png b/pydis_site/static/images/content/discord_colored_messages/ansi-colors.png index 32af146f..d7176393 100644 Binary files a/pydis_site/static/images/content/discord_colored_messages/ansi-colors.png and b/pydis_site/static/images/content/discord_colored_messages/ansi-colors.png differ -- cgit v1.2.3 From 754070ef247ea6d0e28d7a9f14fc41a2080201f6 Mon Sep 17 00:00:00 2001 From: mbaruh Date: Sat, 18 Jun 2022 20:41:30 +0300 Subject: Initial CJ9 info --- pydis_site/static/images/events/Replit.png | Bin 0 -> 12114 bytes .../events/summer_code_jam_2022/site_banner.png | Bin 0 -> 301066 bytes pydis_site/templates/events/index.html | 3 + .../templates/events/pages/code-jams/9/_index.html | 40 ++++++++++++ .../templates/events/pages/code-jams/9/rules.html | 69 +++++++++++++++++++++ .../templates/events/pages/code-jams/_index.html | 8 +++ .../templates/events/sidebar/code-jams/9.html | 20 ++++++ .../events/sidebar/code-jams/ongoing-code-jam.html | 6 +- .../templates/events/sidebar/events-list.html | 10 +-- .../templates/events/sidebar/ongoing-event.html | 6 +- 10 files changed, 151 insertions(+), 11 deletions(-) create mode 100644 pydis_site/static/images/events/Replit.png create mode 100644 pydis_site/static/images/events/summer_code_jam_2022/site_banner.png create mode 100644 pydis_site/templates/events/pages/code-jams/9/_index.html create mode 100644 pydis_site/templates/events/pages/code-jams/9/rules.html create mode 100644 pydis_site/templates/events/sidebar/code-jams/9.html (limited to 'pydis_site/static') diff --git a/pydis_site/static/images/events/Replit.png b/pydis_site/static/images/events/Replit.png new file mode 100644 index 00000000..a8202641 Binary files /dev/null and b/pydis_site/static/images/events/Replit.png differ diff --git a/pydis_site/static/images/events/summer_code_jam_2022/site_banner.png b/pydis_site/static/images/events/summer_code_jam_2022/site_banner.png new file mode 100644 index 00000000..30b3dfbc Binary files /dev/null and b/pydis_site/static/images/events/summer_code_jam_2022/site_banner.png differ diff --git a/pydis_site/templates/events/index.html b/pydis_site/templates/events/index.html index 158ec56b..ccbbabf0 100644 --- a/pydis_site/templates/events/index.html +++ b/pydis_site/templates/events/index.html @@ -9,6 +9,9 @@ {% block event_content %}

Code Jams

+
+ The 2022 Summer Code Jam qualifier will open June 29th. Check out the details here. +

Each year, we organize at least one code jam, one during the summer and sometimes one during the winter. During these events, members of our community will work together in teams to 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/9/_index.html b/pydis_site/templates/events/pages/code-jams/9/_index.html new file mode 100644 index 00000000..c8d5fbf7 --- /dev/null +++ b/pydis_site/templates/events/pages/code-jams/9/_index.html @@ -0,0 +1,40 @@ +{% extends "events/base_sidebar.html" %} + +{% block title %}Summer Code Jam 2022{% endblock %} + +{% block breadcrumb %} +
  • Events
  • +
  • Code Jams
  • +
  • Summer Code Jam 2022
  • +{% endblock %} + +{% block event_content %} +

    Once a year we host a code jam for members of our server to participate in. The code jam is an event where we place you + in a team with 5 other random server members. You then have 11 days to code some sort of application or program in Python. + Your program must use the specified technology/framework and incorporate the theme chosen by the server. +

    +

    + After the 11 days are complete, your team has 4 days to finish documentation and create a video presentation showcasing + and walking through the program that your team has created. More details and specifics of this will be released within the next 2 weeks. +

    + +

    Important Dates

    +
      +
    • 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
    • +
    • Thursday, July 21 - Code Jam Begins
    • +
    • Sunday, July 31 - Coding portion of the jam ends
    • +
    • Sunday, August 4 - Code Jam submissions are closed
    • +
    +

    How to Join

    +

    The Qualifier isn't released yet, but to receive the most up-to-date information and to get notified + when the Qualifier is released you can join the server: discord.gg/python.

    +{% endblock %} + +{% block sidebar %} + + {% include "events/sidebar/code-jams/9.html" %} + +{% endblock %} diff --git a/pydis_site/templates/events/pages/code-jams/9/rules.html b/pydis_site/templates/events/pages/code-jams/9/rules.html new file mode 100644 index 00000000..72c0372e --- /dev/null +++ b/pydis_site/templates/events/pages/code-jams/9/rules.html @@ -0,0 +1,69 @@ +{% extends "events/base_sidebar.html" %} + +{% block title %}Summer Code Jam 2022{% endblock %} + +{% block breadcrumb %} +
  • Events
  • +
  • Code Jams
  • +
  • Summer Code Jam 2022
  • +
  • Rules
  • +{% endblock %} + +{% block event_content %} +
      +
    1. Your solution must use one of the approved frameworks (a list will be released soon). It is not permitted to circumvent this rule by e.g. using the approved framework as a wrapper for another framework.

    2. +
    3. 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.

    4. +
    5. +

      + You must document precisely how to install and run your project. + This should be as easy as possible, which means you should consider using dependency managers like pipenv or poetry. + We would also encourage you to use docker and docker-compose to containerize your project, but this isn't a requirement. +

      +
    6. +
    7. + You must get contributions from every member of your team, if you have an issue with someone on your team please contact a member of the administration team. + These contributions do not necessarily have to be code, for example it's absolutely fine for someone to contribute management, documentation, graphics or audio. + + Team members that do not contribute will be removed from the Code Jam, and will not receive their share of any prizes the team may win. + They may also be barred from entering future events. + +
    8. +
    9. You must use GitHub as source control.

    10. +
    11. +

      + All code and assets must be compatible with the MIT license. + This is because we will be merging your submission into our summer-code-jam-2022 repo at the end of the jam, + and this repo is licensed with the MIT license. + Projects that include assets that are incompatible with this license may be disqualified. +

      +
    12. +
    13. All code must be written and committed within the time constrictions of the jam. Late commits may be reverted, so make sure you leave enough time to bug test your program.

    14. +
    15. +

      + Use English as the main language for your project, including names, comments, documentation, and commit messages. + Any text displayed in your application should also be in English, + although you are allowed to provide the user with options for internationalisation and translation. +

      +
    16. +
    17. +

      + Your team, once the coding portion of the code jam is complete, must create a video presentation that showcases and explains your final product. + This must be in a video format and must be uploaded somewhere for the judges to view (i.e. unlisted Youtube video, Vimeo, etc.) + The video can be as simple as a screen recording with annotated text. + Teams who do not submit a final video presentation may be disqualified. +

      +
    18. +
    + +
    + Please note that our regular + community rules and code of conduct + also apply during the event and that we reserve the right to make changes to these rules at any time. +
    +{% endblock %} + +{% block sidebar %} + + {% include "events/sidebar/code-jams/9.html" %} + +{% endblock %} diff --git a/pydis_site/templates/events/pages/code-jams/_index.html b/pydis_site/templates/events/pages/code-jams/_index.html index 207d4b9a..04e01a24 100644 --- a/pydis_site/templates/events/pages/code-jams/_index.html +++ b/pydis_site/templates/events/pages/code-jams/_index.html @@ -8,6 +8,14 @@ {% block title %}Code Jams{% endblock %} {% block event_content %} +

    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. diff --git a/pydis_site/templates/events/sidebar/code-jams/9.html b/pydis_site/templates/events/sidebar/code-jams/9.html new file mode 100644 index 00000000..69bc7dfd --- /dev/null +++ b/pydis_site/templates/events/sidebar/code-jams/9.html @@ -0,0 +1,20 @@ +{% load static %} +

    +

    Important Links

    + Rules + The Code Style Guide + +
    +
    + Summer Code Jam 2022 + + + Digital Ocean + + + JetBrains + + + Replit + +
    diff --git a/pydis_site/templates/events/sidebar/code-jams/ongoing-code-jam.html b/pydis_site/templates/events/sidebar/code-jams/ongoing-code-jam.html index f4fa3a37..37569e57 100644 --- a/pydis_site/templates/events/sidebar/code-jams/ongoing-code-jam.html +++ b/pydis_site/templates/events/sidebar/code-jams/ongoing-code-jam.html @@ -1,8 +1,8 @@ {% load static %}
    - - - Summer Code Jam 2021 + + + Summer Code Jam 2022
    diff --git a/pydis_site/templates/events/sidebar/events-list.html b/pydis_site/templates/events/sidebar/events-list.html index 5dfe5dc2..b8745231 100644 --- a/pydis_site/templates/events/sidebar/events-list.html +++ b/pydis_site/templates/events/sidebar/events-list.html @@ -1,10 +1,10 @@ diff --git a/pydis_site/templates/events/sidebar/ongoing-event.html b/pydis_site/templates/events/sidebar/ongoing-event.html index 37dfdf77..e375fa38 100644 --- a/pydis_site/templates/events/sidebar/ongoing-event.html +++ b/pydis_site/templates/events/sidebar/ongoing-event.html @@ -1,8 +1,8 @@ {% load static %}
    - - - Summer Code Jam 2021 + + + Summer Code Jam 2022
    -- cgit v1.2.3 From d73d32513435a3978f9529bd17f523ec6e1c14f7 Mon Sep 17 00:00:00 2001 From: kosayoda Date: Sat, 18 Jun 2022 19:50:49 -0400 Subject: Remove weird top padding for first panel item. --- pydis_site/static/css/events/base.css | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'pydis_site/static') diff --git a/pydis_site/static/css/events/base.css b/pydis_site/static/css/events/base.css index 266bca1d..9e244ed9 100644 --- a/pydis_site/static/css/events/base.css +++ b/pydis_site/static/css/events/base.css @@ -10,3 +10,11 @@ pre { */ background-color: #282c34; } + +.panel .panel-heading { + /* + * Remove whitespace between the panel heading and the first item in a panel, + * since it makes the first panel item taller than the others. + */ + margin-bottom: 0 !important +} -- cgit v1.2.3 From 9d3a1adeda965971ed86b2e177e7ed608a60f2ab Mon Sep 17 00:00:00 2001 From: kosayoda Date: Sat, 18 Jun 2022 21:27:41 -0400 Subject: Add frontpage banner assets for Summer CJ 2022. --- .../front_page_banners/live_now.png | Bin 0 -> 406158 bytes .../front_page_banners/qualifier_release.png | Bin 0 -> 470631 bytes .../front_page_banners/sign_up.png | Bin 0 -> 432495 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 pydis_site/static/images/events/summer_code_jam_2022/front_page_banners/live_now.png create mode 100644 pydis_site/static/images/events/summer_code_jam_2022/front_page_banners/qualifier_release.png create mode 100644 pydis_site/static/images/events/summer_code_jam_2022/front_page_banners/sign_up.png (limited to 'pydis_site/static') diff --git a/pydis_site/static/images/events/summer_code_jam_2022/front_page_banners/live_now.png b/pydis_site/static/images/events/summer_code_jam_2022/front_page_banners/live_now.png new file mode 100644 index 00000000..eb30bf7e Binary files /dev/null and b/pydis_site/static/images/events/summer_code_jam_2022/front_page_banners/live_now.png differ diff --git a/pydis_site/static/images/events/summer_code_jam_2022/front_page_banners/qualifier_release.png b/pydis_site/static/images/events/summer_code_jam_2022/front_page_banners/qualifier_release.png new file mode 100644 index 00000000..1e45024b Binary files /dev/null and b/pydis_site/static/images/events/summer_code_jam_2022/front_page_banners/qualifier_release.png differ diff --git a/pydis_site/static/images/events/summer_code_jam_2022/front_page_banners/sign_up.png b/pydis_site/static/images/events/summer_code_jam_2022/front_page_banners/sign_up.png new file mode 100644 index 00000000..f807418e Binary files /dev/null and b/pydis_site/static/images/events/summer_code_jam_2022/front_page_banners/sign_up.png differ -- cgit v1.2.3 From deb7e6521d1434775ca9a912a44e71adef7b6e1e Mon Sep 17 00:00:00 2001 From: kosayoda Date: Sat, 18 Jun 2022 21:29:01 -0400 Subject: Show shadow on hover for CJ frontpage banner. --- pydis_site/static/css/home/index.css | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'pydis_site/static') diff --git a/pydis_site/static/css/home/index.css b/pydis_site/static/css/home/index.css index 7ec8af74..a5732003 100644 --- a/pydis_site/static/css/home/index.css +++ b/pydis_site/static/css/home/index.css @@ -49,13 +49,17 @@ h1 { margin: auto auto; } -#wave-hero-right img{ +#wave-hero-right img { border-radius: 10px; box-shadow: 0 1px 6px rgba(0,0,0,0.16), 0 1px 6px rgba(0,0,0,0.23); margin-top: 1em; text-align: right; } +#wave-hero-right img:hover { + box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22); +} + #wave-hero .wave { background: url(../../images/waves/wave_dark.svg) repeat-x; position: absolute; -- cgit v1.2.3 From 1364a1a6e27d59fa28eb3c6ebecc4e4d2f98c668 Mon Sep 17 00:00:00 2001 From: kosayoda Date: Sun, 19 Jun 2022 13:53:06 -0400 Subject: Add hover transition to match welcome video. --- pydis_site/static/css/home/index.css | 1 + 1 file changed, 1 insertion(+) (limited to 'pydis_site/static') diff --git a/pydis_site/static/css/home/index.css b/pydis_site/static/css/home/index.css index a5732003..e1d70370 100644 --- a/pydis_site/static/css/home/index.css +++ b/pydis_site/static/css/home/index.css @@ -54,6 +54,7 @@ h1 { box-shadow: 0 1px 6px rgba(0,0,0,0.16), 0 1px 6px rgba(0,0,0,0.23); margin-top: 1em; text-align: right; + transition: all 0.3s cubic-bezier(.25,.8,.25,1); } #wave-hero-right img:hover { -- cgit v1.2.3 From 3a30fed05d736836dd243ddeb55146cdaea3e564 Mon Sep 17 00:00:00 2001 From: LemonPi314 <49930425+LemonPi314@users.noreply.github.com> Date: Thu, 23 Jun 2022 16:04:49 -0700 Subject: Update Discord logo in navbar to use new Discord branding --- pydis_site/static/images/navbar/discord.svg | 327 +++++++++++++++++----------- 1 file changed, 203 insertions(+), 124 deletions(-) (limited to 'pydis_site/static') diff --git a/pydis_site/static/images/navbar/discord.svg b/pydis_site/static/images/navbar/discord.svg index 406e3836..2cf3d6cc 100644 --- a/pydis_site/static/images/navbar/discord.svg +++ b/pydis_site/static/images/navbar/discord.svg @@ -1,165 +1,244 @@ - - - - - - - - - - image/svg+xml - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - + y="75.881691" /> -- cgit v1.2.3 From 382f5cc427dedc95056e04db38980a6a9fd15f73 Mon Sep 17 00:00:00 2001 From: kosayoda Date: Sun, 26 Jun 2022 23:05:13 -0400 Subject: Improve icon size and alignment. --- pydis_site/static/css/home/index.css | 3 +-- pydis_site/templates/home/index.html | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'pydis_site/static') diff --git a/pydis_site/static/css/home/index.css b/pydis_site/static/css/home/index.css index e1d70370..e117a35b 100644 --- a/pydis_site/static/css/home/index.css +++ b/pydis_site/static/css/home/index.css @@ -126,8 +126,7 @@ h1 { margin: 0 4% 0 4%; background-color: #3EB2EF; color: white; - font-size: 15px; - line-height: 33px; + line-height: 31px; border:none; box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); transition: all 0.3s cubic-bezier(.25,.8,.25,1); diff --git a/pydis_site/templates/home/index.html b/pydis_site/templates/home/index.html index 33c84a97..fcbb87e4 100644 --- a/pydis_site/templates/home/index.html +++ b/pydis_site/templates/home/index.html @@ -99,9 +99,9 @@
    - + - +
    -- cgit v1.2.3 From 42124deb7ea5f17bc6faf959baba8e951b567655 Mon Sep 17 00:00:00 2001 From: Hassan Abouelela Date: Sat, 13 Aug 2022 06:10:38 +0200 Subject: Add Tag Page Template Add a template for the tag page itself, and add a route to use it. Signed-off-by: Hassan Abouelela --- pydis_site/apps/content/urls.py | 21 ++++++++++-- pydis_site/apps/content/views/__init__.py | 3 +- pydis_site/apps/content/views/tags.py | 56 +++++++++++++++++++++++++++++++ pydis_site/static/css/content/tag.css | 7 ++++ pydis_site/templates/content/base.html | 2 +- pydis_site/templates/content/tag.html | 21 ++++++++++++ 6 files changed, 105 insertions(+), 5 deletions(-) create mode 100644 pydis_site/apps/content/views/tags.py create mode 100644 pydis_site/static/css/content/tag.css create mode 100644 pydis_site/templates/content/tag.html (limited to 'pydis_site/static') diff --git a/pydis_site/apps/content/urls.py b/pydis_site/apps/content/urls.py index f8496095..b4ffc07d 100644 --- a/pydis_site/apps/content/urls.py +++ b/pydis_site/apps/content/urls.py @@ -3,7 +3,7 @@ from pathlib import Path from django_distill import distill_path -from . import views +from . import utils, views app_name = "content" @@ -29,18 +29,33 @@ def __get_all_files(root: Path, folder: typing.Optional[Path] = None) -> list[st return results -def get_all_pages() -> typing.Iterator[dict[str, str]]: +DISTILL_RETURN = typing.Iterator[dict[str, str]] + + +def get_all_pages() -> DISTILL_RETURN: """Yield a dict of all page categories.""" for location in __get_all_files(Path("pydis_site", "apps", "content", "resources")): yield {"location": location} +def get_all_tags() -> DISTILL_RETURN: + """Return all tag names in the repository in static builds.""" + for tag in utils.get_tags_static(): + yield {"name": tag.name} + + urlpatterns = [ distill_path("", views.PageOrCategoryView.as_view(), name='pages'), + distill_path( + "tags//", + views.TagView.as_view(), + name="tag", + distill_func=get_all_tags + ), distill_path( "/", views.PageOrCategoryView.as_view(), name='page_category', distill_func=get_all_pages - ), + ) ] diff --git a/pydis_site/apps/content/views/__init__.py b/pydis_site/apps/content/views/__init__.py index 70ea1c7a..a969b1dc 100644 --- a/pydis_site/apps/content/views/__init__.py +++ b/pydis_site/apps/content/views/__init__.py @@ -1,3 +1,4 @@ from .page_category import PageOrCategoryView +from .tags import TagView -__all__ = ["PageOrCategoryView"] +__all__ = ["PageOrCategoryView", "TagView"] diff --git a/pydis_site/apps/content/views/tags.py b/pydis_site/apps/content/views/tags.py new file mode 100644 index 00000000..12e311dc --- /dev/null +++ b/pydis_site/apps/content/views/tags.py @@ -0,0 +1,56 @@ +import re + +import frontmatter +import markdown +from django.conf import settings +from django.http import Http404 +from django.urls import reverse +from django.views.generic import TemplateView + +from pydis_site.apps.content import utils +from pydis_site.apps.content.models.tag import Tag + +COMMAND_REGEX = re.compile(r"`*!tags? (?P[\w\d-]+)`*") + + +class TagView(TemplateView): + """Handles tag pages.""" + + template_name = "content/tag.html" + + def get_context_data(self, **kwargs) -> dict: + """Get the relevant context for this tag page.""" + try: + tag = utils.get_tag(kwargs.get("name")) + except Tag.DoesNotExist: + raise Http404 + + context = super().get_context_data(**kwargs) + context["page_title"] = tag.name + body = frontmatter.parse(tag.body) + content = body[1] + + # Check for tags which can be hyperlinked + start = 0 + while match := COMMAND_REGEX.search(content, start): + link = reverse("content:tag", kwargs={"name": match.group("name")}) + content = content[:match.start()] + f"[{match.group()}]({link})" + content[match.end():] + start = match.end() + + # Add support for some embed elements + if embed := body[0].get("embed"): + context["page_title"] = embed["title"] + if image := embed.get("image"): + content = f"![{embed['title']}]({image['url']})\n\n" + content + + context.update({ + "page": markdown.markdown(content, extensions=["pymdownx.superfences"]), + "tag": tag, + }) + + context["breadcrumb_items"] = [{ + "name": utils.get_category(settings.CONTENT_PAGES_PATH / location)["title"], + "path": str(location) + } for location in [".", "tags"]] + + return context diff --git a/pydis_site/static/css/content/tag.css b/pydis_site/static/css/content/tag.css new file mode 100644 index 00000000..a144ce24 --- /dev/null +++ b/pydis_site/static/css/content/tag.css @@ -0,0 +1,7 @@ +h1.title a { + color: black; +} + +h1.title a:hover { + color: #7289DA; +} diff --git a/pydis_site/templates/content/base.html b/pydis_site/templates/content/base.html index 4a19a275..dbd303a1 100644 --- a/pydis_site/templates/content/base.html +++ b/pydis_site/templates/content/base.html @@ -35,7 +35,7 @@
    -

    {{ page_title }}

    +

    {% block title_element %}{{ page_title }}{% endblock %}

    {% block page_content %}{% endblock %}
    diff --git a/pydis_site/templates/content/tag.html b/pydis_site/templates/content/tag.html new file mode 100644 index 00000000..264f63d0 --- /dev/null +++ b/pydis_site/templates/content/tag.html @@ -0,0 +1,21 @@ +{% extends "content/page.html" %} +{% load static %} + +{% block head %} + {{ block.super }} + + {{ tag.name }} +{% endblock %} + +{% block title_element %} +
    +
    {{ block.super }}
    +
    + +
    +
    +{% endblock %} + +{% block page_content %} + {{ block.super }} +{% endblock %} -- cgit v1.2.3 From db24ace579d70d50970f9503997148e063d63392 Mon Sep 17 00:00:00 2001 From: Hassan Abouelela Date: Sat, 13 Aug 2022 21:52:02 +0200 Subject: Set Link Color For Sub-elements Signed-off-by: Hassan Abouelela --- pydis_site/static/css/content/tag.css | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'pydis_site/static') diff --git a/pydis_site/static/css/content/tag.css b/pydis_site/static/css/content/tag.css index a144ce24..a3db046c 100644 --- a/pydis_site/static/css/content/tag.css +++ b/pydis_site/static/css/content/tag.css @@ -5,3 +5,9 @@ h1.title a { h1.title a:hover { color: #7289DA; } + +.content a * { + /* This is the original color, but propagated down the chain */ + /* which allows for elements inside links, such as codeblocks */ + color: #7289DA; +} -- cgit v1.2.3 From f2ad3eed8ef8872713666f69ec783f59006d3d81 Mon Sep 17 00:00:00 2001 From: Hassan Abouelela Date: Sat, 13 Aug 2022 22:53:50 +0200 Subject: Improve Tag Cropping Move the tag cropping logic to the frontend, which makes it easier to crop without crossing boundaries such as link or code block boundaries. Signed-off-by: Hassan Abouelela --- pydis_site/apps/content/utils.py | 6 +----- pydis_site/static/js/content/listing.js | 36 +++++++++++++++++++++++++++++++ pydis_site/templates/content/listing.html | 4 +++- 3 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 pydis_site/static/js/content/listing.js (limited to 'pydis_site/static') diff --git a/pydis_site/apps/content/utils.py b/pydis_site/apps/content/utils.py index 76437593..cc08f81f 100644 --- a/pydis_site/apps/content/utils.py +++ b/pydis_site/apps/content/utils.py @@ -131,14 +131,10 @@ def get_category_pages(path: Path) -> dict[str, dict]: tags = {} for tag in get_tags(): content = frontmatter.parse(tag.body)[1] - if len(content) > 100: - # Trim the preview to a maximum of 100 visible characters - # This causes some markdown to break, but we ignore that - content = content[:100] + "..." tags[tag.name] = { "title": tag.name, - "description": markdown.markdown(content), + "description": markdown.markdown(content, extensions=["pymdownx.superfences"]), "icon": "fas fa-tag" } diff --git a/pydis_site/static/js/content/listing.js b/pydis_site/static/js/content/listing.js new file mode 100644 index 00000000..3502cb2a --- /dev/null +++ b/pydis_site/static/js/content/listing.js @@ -0,0 +1,36 @@ +/** + * Trim a tag listing to only show a few lines of content. + */ +function trimTag() { + const containers = document.getElementsByClassName("tag-container"); + for (const container of containers) { + // Remove every element after the first two paragraphs + while (container.children.length > 2) { + container.removeChild(container.lastChild); + } + + // Trim down the elements if they are too long + const containerLength = container.textContent.length; + if (containerLength > 300) { + if (containerLength - container.firstChild.textContent.length > 300) { + // The first element alone takes up more than 300 characters + container.removeChild(container.lastChild); + } + + let last = container.lastChild.lastChild; + while (container.textContent.length > 300 && container.lastChild.childNodes.length > 0) { + last = container.lastChild.lastChild; + last.remove(); + } + + if (container.textContent.length > 300 && (last instanceof HTMLElement && last.tagName !== "CODE")) { + // Add back the final element (up to a period if possible) + const stop = last.textContent.indexOf("."); + last.textContent = last.textContent.slice(0, stop > 0 ? stop + 1: null); + container.lastChild.appendChild(last); + } + } + } +} + +trimTag(); diff --git a/pydis_site/templates/content/listing.html b/pydis_site/templates/content/listing.html index eeb6b5e2..098f4237 100644 --- a/pydis_site/templates/content/listing.html +++ b/pydis_site/templates/content/listing.html @@ -1,5 +1,6 @@ {# Base navigation screen for resources #} {% extends 'content/base.html' %} +{% load static %} {% block page_content %} {# Nested Categories #} @@ -26,10 +27,11 @@ {{ data.title }} {% if "tags" in location %} -

    {{ data.description | safe }}

    +
    {{ data.description | safe }}
    {% else %}

    {{ data.description }}

    {% endif %}
    {% endfor %} + {% endblock %} -- cgit v1.2.3 From 45cdb27a82297ede18d7bd908213dde54fef06a9 Mon Sep 17 00:00:00 2001 From: Hassan Abouelela Date: Sun, 14 Aug 2022 05:34:27 +0200 Subject: Add Tag Group Support Adds support for tag groups in content. This involves some modification to the routing, and templating. Signed-off-by: Hassan Abouelela --- pydis_site/apps/content/urls.py | 12 ++- pydis_site/apps/content/utils.py | 101 ++++++++++++++++++++----- pydis_site/apps/content/views/page_category.py | 5 +- pydis_site/apps/content/views/tags.py | 79 +++++++++++++++---- pydis_site/static/css/content/color.css | 7 ++ pydis_site/static/css/content/tag.css | 8 -- pydis_site/static/js/content/listing.js | 5 ++ pydis_site/templates/content/listing.html | 17 ++++- pydis_site/templates/content/tag.html | 5 +- 9 files changed, 187 insertions(+), 52 deletions(-) create mode 100644 pydis_site/static/css/content/color.css (limited to 'pydis_site/static') diff --git a/pydis_site/apps/content/urls.py b/pydis_site/apps/content/urls.py index b4ffc07d..03c0015a 100644 --- a/pydis_site/apps/content/urls.py +++ b/pydis_site/apps/content/urls.py @@ -39,15 +39,21 @@ def get_all_pages() -> DISTILL_RETURN: def get_all_tags() -> DISTILL_RETURN: - """Return all tag names in the repository in static builds.""" + """Return all tag names and groups in static builds.""" + groups = {None} for tag in utils.get_tags_static(): - yield {"name": tag.name} + groups.add(tag.group) + yield {"location": (f"{tag.group}/" if tag.group else "") + tag.name} + + groups.remove(None) + for group in groups: + yield {"location": group} urlpatterns = [ distill_path("", views.PageOrCategoryView.as_view(), name='pages'), distill_path( - "tags//", + "tags//", views.TagView.as_view(), name="tag", distill_func=get_all_tags diff --git a/pydis_site/apps/content/utils.py b/pydis_site/apps/content/utils.py index cc08f81f..da6a024d 100644 --- a/pydis_site/apps/content/utils.py +++ b/pydis_site/apps/content/utils.py @@ -2,6 +2,7 @@ import datetime import functools import tarfile import tempfile +import typing from io import BytesIO from pathlib import Path @@ -16,7 +17,6 @@ from markdown.extensions.toc import TocExtension from pydis_site import settings from .models import Tag -TAG_URL_BASE = "https://github.com/python-discord/bot/tree/main/bot/resources/tags" TAG_CACHE_TTL = datetime.timedelta(hours=1) @@ -44,9 +44,13 @@ def get_tags_static() -> list[Tag]: """ Fetch tag information in static builds. + This also includes some fake tags to preview the tag groups feature. This will return a cached value, so it should only be used for static builds. """ - return fetch_tags() + tags = fetch_tags() + for tag in tags[3:5]: + tag.group = "very-cool-group" + return tags def fetch_tags() -> list[Tag]: @@ -79,10 +83,15 @@ def fetch_tags() -> list[Tag]: repo.extractall(folder, included) for tag_file in Path(folder).rglob("*.md"): + 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"), + group=group, body=tag_file.read_text(encoding="utf-8"), - url=f"{TAG_URL_BASE}/{tag_file.name}" )) return tags @@ -114,31 +123,85 @@ def get_tags() -> list[Tag]: return Tag.objects.all() -def get_tag(name: str) -> Tag: - """Return a tag by name.""" - tags = get_tags() - for tag in tags: - if tag.name == name: +def get_tag(path: str) -> typing.Union[Tag, list[Tag]]: + """ + Return a tag based on the search location. + + 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. + + If it's a group name, a list of tags which belong to it is returned. + """ + path = path.split("/") + if len(path) == 2: + group, name = path[0], path[1] + else: + name = path[0] + group = None + + matches = [] + for tag in get_tags(): + if tag.name == name and tag.group == group: return tag + elif tag.group == name and group is None: + matches.append(tag) + + if matches: + return matches raise Tag.DoesNotExist() -def get_category_pages(path: Path) -> dict[str, dict]: - """Get all page names and their metadata at a category path.""" - # Special handling for tags - if path == Path(__file__).parent / "resources/tags": - tags = {} - for tag in get_tags(): - content = frontmatter.parse(tag.body)[1] +def get_tag_category( + tags: typing.Optional[list[Tag]] = None, *, collapse_groups: bool +) -> dict[str, dict]: + """ + Generate context data for `tags`, or all tags if None. + + If `tags` is None, `get_tag` is used to populate the data. + If `collapse_groups` is True, tags with parent groups are not included in the list, + and instead the parent itself is included as a single entry with it's sub-tags + in the description. + """ + if not tags: + tags = get_tags() + + data = [] + groups = {} - tags[tag.name] = { + # Create all the metadata for the tags + for tag in tags: + if tag.group is None or not collapse_groups: + content = frontmatter.parse(tag.body)[1] + data.append({ "title": tag.name, "description": markdown.markdown(content, extensions=["pymdownx.superfences"]), - "icon": "fas fa-tag" - } + "icon": "fas fa-tag", + }) + else: + if tag.group not in groups: + groups[tag.group] = { + "title": tag.group, + "description": [tag.name], + "icon": "fas fa-tags", + } + else: + groups[tag.group]["description"].append(tag.name) - return {name: tags[name] for name in sorted(tags)} + # Flatten group description into a single string + for group in groups.values(): + group["description"] = "Contains the following tags: " + ", ".join(group["description"]) + data.append(group) + + # Sort the tags, and return them in the proper format + return {tag["title"]: tag for tag in sorted(data, key=lambda tag: tag["title"].lower())} + + +def get_category_pages(path: Path) -> dict[str, dict]: + """Get all page names and their metadata at a category path.""" + # Special handling for tags + if path == Path(__file__).parent / "resources/tags": + return get_tag_category(collapse_groups=True) pages = {} diff --git a/pydis_site/apps/content/views/page_category.py b/pydis_site/apps/content/views/page_category.py index 01ce8402..062c2bc1 100644 --- a/pydis_site/apps/content/views/page_category.py +++ b/pydis_site/apps/content/views/page_category.py @@ -5,7 +5,7 @@ from django.conf import settings from django.http import Http404, HttpRequest, HttpResponse from django.views.generic import TemplateView -from pydis_site.apps.content import utils +from pydis_site.apps.content import models, utils class PageOrCategoryView(TemplateView): @@ -91,4 +91,7 @@ class PageOrCategoryView(TemplateView): "page_title": category["title"], "page_description": category["description"], "icon": category.get("icon"), + "app_name": "content:page_category", + "is_tag_listing": "/resources/tags" in path.as_posix(), + "tag_url": models.Tag.URL_BASE, } diff --git a/pydis_site/apps/content/views/tags.py b/pydis_site/apps/content/views/tags.py index 5295537d..a8df65db 100644 --- a/pydis_site/apps/content/views/tags.py +++ b/pydis_site/apps/content/views/tags.py @@ -1,4 +1,5 @@ import re +import typing import frontmatter import markdown @@ -16,23 +17,65 @@ COMMAND_REGEX = re.compile(r"`*!tags? (?P[\w\d-]+)`*") class TagView(TemplateView): """Handles tag pages.""" - template_name = "content/tag.html" + tag: typing.Union[Tag, list[Tag]] + is_group: bool + + def setup(self, *args, **kwargs) -> None: + """Look for a tag, and configure the view.""" + super().setup(*args, **kwargs) - def get_context_data(self, **kwargs) -> dict: - """Get the relevant context for this tag page.""" try: - tag = utils.get_tag(kwargs.get("name")) + self.tag = utils.get_tag(kwargs.get("location")) + self.is_group = isinstance(self.tag, list) except Tag.DoesNotExist: raise Http404 + def get_template_names(self) -> list[str]: + """Either return the tag page template, or the listing.""" + if self.is_group: + template_name = "content/listing.html" + else: + template_name = "content/tag.html" + + return [template_name] + + def get_context_data(self, **kwargs) -> dict: + """Get the relevant context for this tag page or group.""" context = super().get_context_data(**kwargs) - context["page_title"] = tag.name + context["breadcrumb_items"] = [{ + "name": utils.get_category(settings.CONTENT_PAGES_PATH / location)["title"], + "path": location, + } for location in (".", "tags")] + + if self.is_group: + self._set_group_context(context, self.tag) + else: + self._set_tag_context(context, self.tag) + + return context + + @staticmethod + def _set_tag_context(context: dict[str, any], tag: Tag) -> None: + """Update the context with the information for a tag page.""" + context.update({ + "page_title": tag.name, + "tag": tag, + }) + + if tag.group: + # Add group names to the breadcrumbs + context["breadcrumb_items"].append({ + "name": tag.group, + "path": f"tags/{tag.group}", + }) + + # Clean up tag body body = frontmatter.parse(tag.body) content = body[1] # Check for tags which can be hyperlinked def sub(match: re.Match) -> str: - link = reverse("content:tag", kwargs={"name": match.group("name")}) + link = reverse("content:tag", kwargs={"location": match.group("name")}) return f"[{match.group()}]({link})" content = COMMAND_REGEX.sub(sub, content) @@ -42,14 +85,20 @@ class TagView(TemplateView): if image := embed.get("image"): content = f"![{embed['title']}]({image['url']})\n\n" + content + # Insert the content + context["page"] = markdown.markdown(content, extensions=["pymdownx.superfences"]) + + @staticmethod + def _set_group_context(context: dict[str, any], tags: list[Tag]) -> None: + """Update the context with the information for a group of tags.""" + group = tags[0].group context.update({ - "page": markdown.markdown(content, extensions=["pymdownx.superfences"]), - "tag": tag, + "categories": {}, + "pages": utils.get_tag_category(tags, collapse_groups=False), + "page_title": group, + "icon": "fab fa-tags", + "is_tag_listing": True, + "app_name": "content:tag", + "path": f"{group}/", + "tag_url": f"{tags[0].URL_BASE}/{group}" }) - - context["breadcrumb_items"] = [{ - "name": utils.get_category(settings.CONTENT_PAGES_PATH / location)["title"], - "path": str(location) - } for location in [".", "tags"]] - - return context diff --git a/pydis_site/static/css/content/color.css b/pydis_site/static/css/content/color.css new file mode 100644 index 00000000..f4801c28 --- /dev/null +++ b/pydis_site/static/css/content/color.css @@ -0,0 +1,7 @@ +.content .fa-github { + color: black; +} + +.content .fa-github:hover { + color: #7289DA; +} diff --git a/pydis_site/static/css/content/tag.css b/pydis_site/static/css/content/tag.css index a3db046c..ec45bfc7 100644 --- a/pydis_site/static/css/content/tag.css +++ b/pydis_site/static/css/content/tag.css @@ -1,11 +1,3 @@ -h1.title a { - color: black; -} - -h1.title a:hover { - color: #7289DA; -} - .content a * { /* This is the original color, but propagated down the chain */ /* which allows for elements inside links, such as codeblocks */ diff --git a/pydis_site/static/js/content/listing.js b/pydis_site/static/js/content/listing.js index 3502cb2a..4b722632 100644 --- a/pydis_site/static/js/content/listing.js +++ b/pydis_site/static/js/content/listing.js @@ -4,6 +4,11 @@ function trimTag() { const containers = document.getElementsByClassName("tag-container"); for (const container of containers) { + if (container.textContent.startsWith("Contains the following tags:")) { + // Tag group, no need to trim + continue; + } + // Remove every element after the first two paragraphs while (container.children.length > 2) { container.removeChild(container.lastChild); diff --git a/pydis_site/templates/content/listing.html b/pydis_site/templates/content/listing.html index 098f4237..934b95f6 100644 --- a/pydis_site/templates/content/listing.html +++ b/pydis_site/templates/content/listing.html @@ -2,6 +2,19 @@ {% extends 'content/base.html' %} {% load static %} +{# Show a GitHub button on tag pages #} +{% block title_element %} +{% if is_tag_listing %} + +
    +
    {{ block.super }}
    +
    + +
    +
    +{% endif %} +{% endblock %} + {% block page_content %} {# Nested Categories #} {% for category, data in categories.items %} @@ -23,10 +36,10 @@ - + {{ data.title }} - {% if "tags" in location %} + {% if is_tag_listing %}
    {{ data.description | safe }}
    {% else %}

    {{ data.description }}

    diff --git a/pydis_site/templates/content/tag.html b/pydis_site/templates/content/tag.html index 264f63d0..9bd65744 100644 --- a/pydis_site/templates/content/tag.html +++ b/pydis_site/templates/content/tag.html @@ -3,6 +3,7 @@ {% block head %} {{ block.super }} + {{ tag.name }} {% endblock %} @@ -15,7 +16,3 @@ {% 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(+) (limited to 'pydis_site/static') 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 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(-) (limited to 'pydis_site/static') 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 %} -
    +
    {{ block.super }}
    + + {% endblock %} -- cgit v1.2.3 From 0d59f046eac4a73f82885c84269ac02edf3d2bfe Mon Sep 17 00:00:00 2001 From: Xithrius Date: Sat, 12 Nov 2022 20:25:45 -0800 Subject: Migrated from #discord-bot pin --- .../guides/python-guides/fix-ssl-certificate.md | 23 +++++++++++++++++++++ .../images/content/fix-ssl-certificate/pem.png | Bin 0 -> 45703 bytes 2 files changed, 23 insertions(+) create mode 100644 pydis_site/apps/content/resources/guides/python-guides/fix-ssl-certificate.md create mode 100644 pydis_site/static/images/content/fix-ssl-certificate/pem.png (limited to 'pydis_site/static') diff --git a/pydis_site/apps/content/resources/guides/python-guides/fix-ssl-certificate.md b/pydis_site/apps/content/resources/guides/python-guides/fix-ssl-certificate.md new file mode 100644 index 00000000..ea141838 --- /dev/null +++ b/pydis_site/apps/content/resources/guides/python-guides/fix-ssl-certificate.md @@ -0,0 +1,23 @@ +--- +title: Fixing an SSL Certificate Verification Error. +description: A guide on fixing verification of an SSL certificate. +--- + +We're fixing the error Python specifies as [ssl.SSLCertVerificationError](https://docs.python.org/3/library/ssl.html#ssl.SSLCertVerificationError). + +# How to fix SSL Certificate issue on Windows + +Firstly, try updating your OS, wouldn't hurt to try. + +Now, if you're still having an issue, you would need to download the certificate for the SSL. + +The SSL Certificate, Sectigo (cert vendor) provides a download link of [certificate](https://crt.sh/?id=2835394). You should find it in the bottom left corner, where it's saying Download Certificate: *PEM*. + +A picture where to find the certificate in the website is: +![location of certificate](/static/images/content/fix-ssl-certificate/pem.png) + +You have to setup the certificate yourself. To do that you can just click on it, or if that doesn't work, refer to [this link](https://portal.threatpulse.com/docs/sol/Solutions/ManagePolicy/SSL/ssl_chrome_cert_ta.htm) + +# How to fix SSL Certificate issue on Mac + +Navigate to your `Applications/Python 3.x/` folder and double-click the `Install Certificates.command` to fix this. diff --git a/pydis_site/static/images/content/fix-ssl-certificate/pem.png b/pydis_site/static/images/content/fix-ssl-certificate/pem.png new file mode 100644 index 00000000..d63d018d Binary files /dev/null and b/pydis_site/static/images/content/fix-ssl-certificate/pem.png differ -- cgit v1.2.3 From 1a3fe0e61149c9371b734817130c4693568a9757 Mon Sep 17 00:00:00 2001 From: Xithrius Date: Sat, 12 Nov 2022 20:43:43 -0800 Subject: Made static PEM image better --- .../images/content/fix-ssl-certificate/pem.png | Bin 45703 -> 13988 bytes 1 file changed, 0 insertions(+), 0 deletions(-) (limited to 'pydis_site/static') diff --git a/pydis_site/static/images/content/fix-ssl-certificate/pem.png b/pydis_site/static/images/content/fix-ssl-certificate/pem.png index d63d018d..cb902bb3 100644 Binary files a/pydis_site/static/images/content/fix-ssl-certificate/pem.png and b/pydis_site/static/images/content/fix-ssl-certificate/pem.png differ -- cgit v1.2.3 From f4b3a0d006a07dd6f32c6105021f39c56ddfeadd Mon Sep 17 00:00:00 2001 From: Xithrius Date: Sat, 12 Nov 2022 20:55:26 -0800 Subject: Made stuff and things even better --- .../guides/python-guides/fix-ssl-certificate.md | 4 ++-- .../images/content/fix-ssl-certificate/pem.png | Bin 13988 -> 11619 bytes 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'pydis_site/static') diff --git a/pydis_site/apps/content/resources/guides/python-guides/fix-ssl-certificate.md b/pydis_site/apps/content/resources/guides/python-guides/fix-ssl-certificate.md index ea141838..096e3a90 100644 --- a/pydis_site/apps/content/resources/guides/python-guides/fix-ssl-certificate.md +++ b/pydis_site/apps/content/resources/guides/python-guides/fix-ssl-certificate.md @@ -1,5 +1,5 @@ --- -title: Fixing an SSL Certificate Verification Error. +title: Fixing an SSL Certificate Verification Error description: A guide on fixing verification of an SSL certificate. --- @@ -11,7 +11,7 @@ Firstly, try updating your OS, wouldn't hurt to try. Now, if you're still having an issue, you would need to download the certificate for the SSL. -The SSL Certificate, Sectigo (cert vendor) provides a download link of [certificate](https://crt.sh/?id=2835394). You should find it in the bottom left corner, where it's saying Download Certificate: *PEM*. +The SSL Certificate, Sectigo (cert vendor) provides a download link of an [SSL certificate](https://crt.sh/?id=2835394). You should find it in the bottom left corner, shown below: A picture where to find the certificate in the website is: ![location of certificate](/static/images/content/fix-ssl-certificate/pem.png) diff --git a/pydis_site/static/images/content/fix-ssl-certificate/pem.png b/pydis_site/static/images/content/fix-ssl-certificate/pem.png index cb902bb3..face520f 100644 Binary files a/pydis_site/static/images/content/fix-ssl-certificate/pem.png and b/pydis_site/static/images/content/fix-ssl-certificate/pem.png differ -- cgit v1.2.3