diff options
| author | 2022-10-16 15:28:44 -0500 | |
|---|---|---|
| committer | 2022-10-16 15:28:44 -0500 | |
| commit | de3b6a48f773a9738fa76d14192f27ca7ee10a80 (patch) | |
| tree | 5fd1b9733e170b2d6de940e16983bd9c17960144 /pydis_site | |
| parent | Merge branch 'main' into main (diff) | |
| parent | Merge pull request #780 from python-discord/repo-token-remove (diff) | |
Merge branch 'main' into main
Diffstat (limited to 'pydis_site')
19 files changed, 70 insertions, 68 deletions
diff --git a/pydis_site/apps/api/__init__.py b/pydis_site/apps/api/__init__.py index afa5b4d5..e69de29b 100644 --- a/pydis_site/apps/api/__init__.py +++ b/pydis_site/apps/api/__init__.py @@ -1 +0,0 @@ -default_app_config = 'pydis_site.apps.api.apps.ApiConfig' diff --git a/pydis_site/apps/api/github_utils.py b/pydis_site/apps/api/github_utils.py index 5d7bcdc3..986c64e1 100644 --- a/pydis_site/apps/api/github_utils.py +++ b/pydis_site/apps/api/github_utils.py @@ -108,7 +108,7 @@ def authorize(owner: str, repo: str) -> httpx.Client:      client = httpx.Client(          base_url=settings.GITHUB_API,          headers={"Authorization": f"bearer {generate_token()}"}, -        timeout=settings.TIMEOUT_PERIOD, +        timeout=10,      )      try: diff --git a/pydis_site/apps/api/migrations/0013_specialsnake_image.py b/pydis_site/apps/api/migrations/0013_specialsnake_image.py index a0d0d318..8ba3432f 100644 --- a/pydis_site/apps/api/migrations/0013_specialsnake_image.py +++ b/pydis_site/apps/api/migrations/0013_specialsnake_image.py @@ -2,7 +2,6 @@  import datetime  from django.db import migrations, models -from django.utils.timezone import utc  class Migration(migrations.Migration): @@ -15,7 +14,7 @@ class Migration(migrations.Migration):          migrations.AddField(              model_name='specialsnake',              name='image', -            field=models.URLField(default=datetime.datetime(2018, 10, 23, 11, 51, 23, 703868, tzinfo=utc)), +            field=models.URLField(default=datetime.datetime(2018, 10, 23, 11, 51, 23, 703868, tzinfo=datetime.timezone.utc)),              preserve_default=False,          ),      ] diff --git a/pydis_site/apps/api/models/bot/message.py b/pydis_site/apps/api/models/bot/message.py index bfa54721..89ae27e4 100644 --- a/pydis_site/apps/api/models/bot/message.py +++ b/pydis_site/apps/api/models/bot/message.py @@ -1,9 +1,8 @@ -from datetime import datetime +import datetime  from django.contrib.postgres import fields as pgfields  from django.core.validators import MinValueValidator  from django.db import models -from django.utils import timezone  from pydis_site.apps.api.models.bot.user import User  from pydis_site.apps.api.models.mixins import ModelReprMixin @@ -60,11 +59,11 @@ class Message(ModelReprMixin, models.Model):      )      @property -    def timestamp(self) -> datetime: +    def timestamp(self) -> datetime.datetime:          """Attribute that represents the message timestamp as derived from the snowflake id.""" -        tz_naive_datetime = datetime.utcfromtimestamp(((self.id >> 22) + 1420070400000) / 1000) -        tz_aware_datetime = timezone.make_aware(tz_naive_datetime, timezone=timezone.utc) -        return tz_aware_datetime +        return datetime.datetime.utcfromtimestamp( +            ((self.id >> 22) + 1420070400000) / 1000 +        ).replace(tzinfo=datetime.timezone.utc)      class Meta:          """Metadata provided for Django's ORM.""" diff --git a/pydis_site/apps/api/tests/test_filterlists.py b/pydis_site/apps/api/tests/test_filterlists.py index 5a5bca60..9959617e 100644 --- a/pydis_site/apps/api/tests/test_filterlists.py +++ b/pydis_site/apps/api/tests/test_filterlists.py @@ -64,8 +64,8 @@ class FetchTests(AuthenticatedAPITestCase):          self.assertEqual(response.status_code, 200)          for api_type, model_type in zip(response.json(), FilterList.FilterListType.choices): -            self.assertEquals(api_type[0], model_type[0]) -            self.assertEquals(api_type[1], model_type[1]) +            self.assertEqual(api_type[0], model_type[0]) +            self.assertEqual(api_type[1], model_type[1])  class CreationTests(AuthenticatedAPITestCase): diff --git a/pydis_site/apps/api/tests/test_github_utils.py b/pydis_site/apps/api/tests/test_github_utils.py index f642f689..2eaf48d9 100644 --- a/pydis_site/apps/api/tests/test_github_utils.py +++ b/pydis_site/apps/api/tests/test_github_utils.py @@ -28,7 +28,7 @@ class GeneralUtilityTests(unittest.TestCase):              """              self.assertEqual("RS256", algorithm, "The GitHub App JWT must be signed using RS256.")              return original_encode( -                payload, "secret-encoding-key", algorithm="HS256", *args, **kwargs +                payload, "secret-encoding-key", *args, algorithm="HS256", **kwargs              )          original_encode = jwt.encode diff --git a/pydis_site/apps/api/viewsets/bot/aoc_completionist_block.py b/pydis_site/apps/api/viewsets/bot/aoc_completionist_block.py index 3a4cec60..97efb63c 100644 --- a/pydis_site/apps/api/viewsets/bot/aoc_completionist_block.py +++ b/pydis_site/apps/api/viewsets/bot/aoc_completionist_block.py @@ -70,4 +70,4 @@ class AocCompletionistBlockViewSet(      serializer_class = AocCompletionistBlockSerializer      queryset = AocCompletionistBlock.objects.all()      filter_backends = (DjangoFilterBackend,) -    filter_fields = ("user__id", "is_blocked") +    filterset_fields = ("user__id", "is_blocked") diff --git a/pydis_site/apps/api/viewsets/bot/aoc_link.py b/pydis_site/apps/api/viewsets/bot/aoc_link.py index c7a96629..3cdc342d 100644 --- a/pydis_site/apps/api/viewsets/bot/aoc_link.py +++ b/pydis_site/apps/api/viewsets/bot/aoc_link.py @@ -68,4 +68,4 @@ class AocAccountLinkViewSet(      serializer_class = AocAccountLinkSerializer      queryset = AocAccountLink.objects.all()      filter_backends = (DjangoFilterBackend,) -    filter_fields = ("user__id", "aoc_username") +    filterset_fields = ("user__id", "aoc_username") diff --git a/pydis_site/apps/api/viewsets/bot/infraction.py b/pydis_site/apps/api/viewsets/bot/infraction.py index 7f31292f..93d29391 100644 --- a/pydis_site/apps/api/viewsets/bot/infraction.py +++ b/pydis_site/apps/api/viewsets/bot/infraction.py @@ -1,9 +1,8 @@ -from datetime import datetime +import datetime  from django.db import IntegrityError  from django.db.models import QuerySet  from django.http.request import HttpRequest -from django.utils import timezone  from django_filters.rest_framework import DjangoFilterBackend  from rest_framework.decorators import action  from rest_framework.exceptions import ValidationError @@ -154,7 +153,7 @@ class InfractionViewSet(      queryset = Infraction.objects.all()      pagination_class = LimitOffsetPaginationExtended      filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter) -    filter_fields = ('user__id', 'actor__id', 'active', 'hidden', 'type') +    filterset_fields = ('user__id', 'actor__id', 'active', 'hidden', 'type')      search_fields = ('$reason',)      frozen_fields = ('id', 'inserted_at', 'type', 'user', 'actor', 'hidden') @@ -185,23 +184,21 @@ class InfractionViewSet(          filter_expires_after = self.request.query_params.get('expires_after')          if filter_expires_after:              try: -                expires_after_parsed = datetime.fromisoformat(filter_expires_after) +                expires_after_parsed = datetime.datetime.fromisoformat(filter_expires_after)              except ValueError:                  raise ValidationError({'expires_after': ['failed to convert to datetime']}) -            additional_filters['expires_at__gte'] = timezone.make_aware( -                expires_after_parsed, -                timezone=timezone.utc, +            additional_filters['expires_at__gte'] = expires_after_parsed.replace( +                tzinfo=datetime.timezone.utc              )          filter_expires_before = self.request.query_params.get('expires_before')          if filter_expires_before:              try: -                expires_before_parsed = datetime.fromisoformat(filter_expires_before) +                expires_before_parsed = datetime.datetime.fromisoformat(filter_expires_before)              except ValueError:                  raise ValidationError({'expires_before': ['failed to convert to datetime']}) -            additional_filters['expires_at__lte'] = timezone.make_aware( -                expires_before_parsed, -                timezone=timezone.utc, +            additional_filters['expires_at__lte'] = expires_before_parsed.replace( +                tzinfo=datetime.timezone.utc              )          if 'expires_at__lte' in additional_filters and 'expires_at__gte' in additional_filters: diff --git a/pydis_site/apps/api/viewsets/bot/nomination.py b/pydis_site/apps/api/viewsets/bot/nomination.py index 144daab0..6af42bcb 100644 --- a/pydis_site/apps/api/viewsets/bot/nomination.py +++ b/pydis_site/apps/api/viewsets/bot/nomination.py @@ -172,7 +172,7 @@ class NominationViewSet(CreateModelMixin, RetrieveModelMixin, ListModelMixin, Ge      serializer_class = NominationSerializer      queryset = Nomination.objects.all()      filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter) -    filter_fields = ('user__id', 'active') +    filterset_fields = ('user__id', 'active')      frozen_fields = ('id', 'inserted_at', 'user', 'ended_at')      frozen_on_create = ('ended_at', 'end_reason', 'active', 'inserted_at', 'reviewed') diff --git a/pydis_site/apps/api/viewsets/bot/reminder.py b/pydis_site/apps/api/viewsets/bot/reminder.py index 78d7cb3b..5f997052 100644 --- a/pydis_site/apps/api/viewsets/bot/reminder.py +++ b/pydis_site/apps/api/viewsets/bot/reminder.py @@ -125,4 +125,4 @@ class ReminderViewSet(      serializer_class = ReminderSerializer      queryset = Reminder.objects.prefetch_related('author')      filter_backends = (DjangoFilterBackend, SearchFilter) -    filter_fields = ('active', 'author__id') +    filterset_fields = ('active', 'author__id') diff --git a/pydis_site/apps/api/viewsets/bot/user.py b/pydis_site/apps/api/viewsets/bot/user.py index 3318b2b9..ba1bcd9d 100644 --- a/pydis_site/apps/api/viewsets/bot/user.py +++ b/pydis_site/apps/api/viewsets/bot/user.py @@ -237,7 +237,7 @@ class UserViewSet(ModelViewSet):      queryset = User.objects.all().order_by("id")      pagination_class = UserListPagination      filter_backends = (DjangoFilterBackend,) -    filter_fields = ('name', 'discriminator') +    filterset_fields = ('name', 'discriminator')      def get_serializer(self, *args, **kwargs) -> ModelSerializer:          """Set Serializer many attribute to True if request body contains a list.""" diff --git a/pydis_site/apps/content/resources/guides/pydis-guides/contributing/bot.md b/pydis_site/apps/content/resources/guides/pydis-guides/contributing/bot.md index ad446cc8..02316bca 100644 --- a/pydis_site/apps/content/resources/guides/pydis-guides/contributing/bot.md +++ b/pydis_site/apps/content/resources/guides/pydis-guides/contributing/bot.md @@ -88,6 +88,7 @@ urls:      # Snekbox      snekbox_eval_api: "http://localhost:8060/eval" +    snekbox_311_eval_api: "http://localhost:8065/eval"  ##### <<  Replace the following � characters with the channel IDs in your test server  >> #####  #  This assumes the template was used: https://discord.new/zmHtscpYN9E3 @@ -481,10 +482,14 @@ You are now almost ready to run the Python bot. The simplest way to do so is wit  In your `config.yml` file:  * Set `urls.site` to `"web:8000"`. -* If you wish to work with snekbox set `urls.snekbox_eval_api` to `"http://snekbox:8060/eval"`. +* If you wish to work with snekbox set the following: +    * `urls.snekbox_eval_api` to `"http://snekbox:8060/eval"` +    * `urls.snekbox_311_eval_api` to `"http://snekbox-311:8060/eval"`.  Assuming you have Docker installed **and running**, enter the cloned repo in the command line and type `docker-compose up`. +If working with snekbox you can run `docker-compose --profile 3.10 up` to also start up a 3.10 snekbox container, in addition to the default 3.11 container! +  After pulling the images and building the containers, your bot will start. Enter your server and type `!help` (or whatever prefix you chose instead of `!`).  Your bot is now running, but this method makes debugging with an IDE a fairly involved process. For additional running methods, continue reading the following sections. @@ -494,12 +499,13 @@ The advantage of this method is that you can run the bot's code in your preferre  * Append the following line to your `.env` file: `BOT_API_KEY=badbot13m0n8f570f942013fc818f234916ca531`.  * In your `config.yml` file, set `urls.site` to `"localhost:8000"`. If you wish to keep using `web:8000`, then [COMPOSE_PROJECT_NAME](../docker/#compose-project-names) has to be set. -* To work with snekbox, set `urls.snekbox_eval_api` to `"http://localhost:8060/eval"` +* To work with snekbox, set `urls.snekbox_eval_api` to `"http://localhost:8060/eval"` and `urls.snekbox_311_eval_api` to `"http://localhost:8065/eval"`  You will need to start the services separately, but if you got the previous section with Docker working, that's pretty simple:  * `docker-compose up web` to start the site container. This is required.  * `docker-compose up snekbox` to start the snekbox container. You only need this if you're planning on working on the snekbox cog. +* `docker-compose up snekbox-311` to start the snekbox 3.11 container. You only need this if you're planning on working on the snekbox cog.  * `docker-compose up redis` to start the Redis container. You only need this if you're not using fakeredis. For more info refer to [Working with Redis](#optional-working-with-redis).  You can start several services together: `docker-compose up web snekbox redis`. @@ -507,7 +513,7 @@ You can start several services together: `docker-compose up web snekbox redis`.  ##### Setting Up a Development Environment  The bot's code is Python code like any other. To run it locally, you will need the right version of Python with the necessary packages installed: -1. Make sure you have [Python 3.9](https://www.python.org/downloads/) installed. It helps if it is your system's default Python version. +1. Make sure you have [Python 3.10](https://www.python.org/downloads/) installed. It helps if it is your system's default Python version.  2. [Install Poetry](https://github.com/python-poetry/poetry#installation).  3. [Install the dependencies](../installing-project-dependencies). diff --git a/pydis_site/apps/content/resources/guides/pydis-guides/contributing/site.md b/pydis_site/apps/content/resources/guides/pydis-guides/contributing/site.md index 520e41ad..9786698b 100644 --- a/pydis_site/apps/content/resources/guides/pydis-guides/contributing/site.md +++ b/pydis_site/apps/content/resources/guides/pydis-guides/contributing/site.md @@ -9,7 +9,7 @@ You should have already forked the [`site`](https://github.com/python-discord/si  ### Requirements -- [Python 3.9](https://www.python.org/downloads/) +- [Python 3.10](https://www.python.org/downloads/)  - [Poetry](https://python-poetry.org/docs/#installation)      - `pip install poetry`  - [Git](https://git-scm.com/downloads) diff --git a/pydis_site/apps/content/resources/guides/pydis-guides/contributing/style-guide.md b/pydis_site/apps/content/resources/guides/pydis-guides/contributing/style-guide.md index 4dba45c8..b26c467c 100644 --- a/pydis_site/apps/content/resources/guides/pydis-guides/contributing/style-guide.md +++ b/pydis_site/apps/content/resources/guides/pydis-guides/contributing/style-guide.md @@ -202,6 +202,3 @@ def foo(input_1: int, input_2: dict[str, int]) -> bool:  This tells us that `foo` accepts an `int` and a `dict`, with `str` keys and `int` values, and returns a `bool`.  In previous examples, we have purposely omitted annotations to keep focus on the specific points they represent. - -> **Note:** if the project is running Python 3.8 or below you have to use `typing.Dict` instead of `dict`, but our three main projects are all >=3.9. -> See [PEP 585](https://www.python.org/dev/peps/pep-0585/) for more information. diff --git a/pydis_site/apps/content/tests/test_views.py b/pydis_site/apps/content/tests/test_views.py index eadad7e3..a09d22d8 100644 --- a/pydis_site/apps/content/tests/test_views.py +++ b/pydis_site/apps/content/tests/test_views.py @@ -172,7 +172,7 @@ class PageOrCategoryViewTests(MockPagesTestCase, SimpleTestCase, TestCase):          for item in context["breadcrumb_items"]:              item["path"] = Path(item["path"]) -        self.assertEquals( +        self.assertEqual(              context["breadcrumb_items"],              [                  {"name": PARSED_CATEGORY_INFO["title"], "path": Path(".")}, diff --git a/pydis_site/apps/home/tests/test_repodata_helpers.py b/pydis_site/apps/home/tests/test_repodata_helpers.py index 4007eded..a963f733 100644 --- a/pydis_site/apps/home/tests/test_repodata_helpers.py +++ b/pydis_site/apps/home/tests/test_repodata_helpers.py @@ -42,7 +42,7 @@ class TestRepositoryMetadataHelpers(TestCase):          metadata = self.home_view._get_repo_data()          self.assertIsInstance(metadata[0], RepositoryMetadata) -        self.assertEquals(len(metadata), len(self.home_view.repos)) +        self.assertEqual(len(metadata), len(self.home_view.repos))      def test_returns_cached_metadata(self):          """Test if the _get_repo_data helper returns cached data when available.""" @@ -82,7 +82,7 @@ class TestRepositoryMetadataHelpers(TestCase):          repo = self.home_view.repos[0]          self.assertIsInstance(api_data, dict) -        self.assertEquals(len(api_data), len(self.home_view.repos)) +        self.assertEqual(len(api_data), len(self.home_view.repos))          self.assertIn(repo, api_data.keys())          self.assertIn("stargazers_count", api_data[repo]) @@ -126,7 +126,7 @@ class TestRepositoryMetadataHelpers(TestCase):          with self.assertLogs():              metadata = self.home_view._get_repo_data() -        self.assertEquals(len(metadata), 0) +        self.assertEqual(len(metadata), 0)      def test_cleans_up_stale_metadata(self):          """Tests that we clean up stale metadata when we start the HomeView.""" diff --git a/pydis_site/apps/redirect/urls.py b/pydis_site/apps/redirect/urls.py index f7ddf45b..f86fe665 100644 --- a/pydis_site/apps/redirect/urls.py +++ b/pydis_site/apps/redirect/urls.py @@ -3,6 +3,7 @@ import re  import yaml  from django import conf +from django.http import HttpResponse  from django.urls import URLPattern, path  from django_distill import distill_path @@ -53,7 +54,7 @@ def map_redirect(name: str, data: Redirect) -> list[URLPattern]:          class RedirectFunc:              def __init__(self, new_url: str, _name: str): -                self.result = REDIRECT_TEMPLATE.format(url=new_url) +                self.result = HttpResponse(REDIRECT_TEMPLATE.format(url=new_url))                  self.__qualname__ = _name              def __call__(self, *args, **kwargs): @@ -95,7 +96,7 @@ def map_redirect(name: str, data: Redirect) -> list[URLPattern]:          return [distill_path(              data.original_path, -            lambda *args: REDIRECT_TEMPLATE.format(url=new_redirect), +            lambda *args: HttpResponse(REDIRECT_TEMPLATE.format(url=new_redirect)),              name=name,          )] diff --git a/pydis_site/settings.py b/pydis_site/settings.py index bbf1d3aa..cb05956b 100644 --- a/pydis_site/settings.py +++ b/pydis_site/settings.py @@ -43,12 +43,13 @@ if GITHUB_APP_KEY and (key_file := Path(GITHUB_APP_KEY)).is_file():      # Allow the OAuth key to be loaded from a file      GITHUB_APP_KEY = key_file.read_text(encoding="utf-8") -sentry_sdk.init( -    dsn=env('SITE_DSN'), -    integrations=[DjangoIntegration()], -    send_default_pii=True, -    release=f"site@{GIT_SHA}" -) +if not env("STATIC_BUILD"): +    sentry_sdk.init( +        dsn=env('SITE_DSN'), +        integrations=[DjangoIntegration()], +        send_default_pii=True, +        release=f"site@{GIT_SHA}" +    )  # Build paths inside the project like this: os.path.join(BASE_DIR, ...)  BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -128,25 +129,29 @@ INSTALLED_APPS = [  if not env("BUILDING_DOCKER"):      INSTALLED_APPS.append("django_prometheus") -NON_STATIC_MIDDLEWARE = [ -    'django_prometheus.middleware.PrometheusBeforeMiddleware', -] if not env("STATIC_BUILD") else [] - -# Ensure that Prometheus middlewares are first and last here. -MIDDLEWARE = [ -    *NON_STATIC_MIDDLEWARE, - -    'django.middleware.security.SecurityMiddleware', -    'whitenoise.middleware.WhiteNoiseMiddleware', -    'django.contrib.sessions.middleware.SessionMiddleware', -    'django.middleware.common.CommonMiddleware', -    'django.middleware.csrf.CsrfViewMiddleware', -    'django.contrib.auth.middleware.AuthenticationMiddleware', -    'django.contrib.messages.middleware.MessageMiddleware', -    'django.middleware.clickjacking.XFrameOptionsMiddleware', - -    'django_prometheus.middleware.PrometheusAfterMiddleware' -] +if env("STATIC_BUILD"): +    # The only middleware required during static builds +    MIDDLEWARE = [ +        'django.contrib.sessions.middleware.SessionMiddleware', +        'django.contrib.auth.middleware.AuthenticationMiddleware', +        'django.contrib.messages.middleware.MessageMiddleware', +    ] +else: +    # Ensure that Prometheus middlewares are first and last here. +    MIDDLEWARE = [ +        'django_prometheus.middleware.PrometheusBeforeMiddleware', + +        'django.middleware.security.SecurityMiddleware', +        'whitenoise.middleware.WhiteNoiseMiddleware', +        'django.contrib.sessions.middleware.SessionMiddleware', +        'django.middleware.common.CommonMiddleware', +        'django.middleware.csrf.CsrfViewMiddleware', +        'django.contrib.auth.middleware.AuthenticationMiddleware', +        'django.contrib.messages.middleware.MessageMiddleware', +        'django.middleware.clickjacking.XFrameOptionsMiddleware', + +        'django_prometheus.middleware.PrometheusAfterMiddleware' +    ]  ROOT_URLCONF = 'pydis_site.urls' @@ -200,7 +205,6 @@ AUTH_PASSWORD_VALIDATORS = [  LANGUAGE_CODE = 'en-us'  TIME_ZONE = 'UTC'  USE_I18N = True -USE_L10N = True  USE_TZ = True  # Static files (CSS, JavaScript, Images)  |