From 79cd2b993c89b168b94a63b81be3100c7eb5a3d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Jul 2026 09:08:51 +0000 Subject: [PATCH 1/2] chore(deps-dev): bump ruff from 0.15.21 to 0.16.0 Bumps [ruff](https://github.com/astral-sh/ruff) from 0.15.21 to 0.16.0. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ruff/compare/0.15.21...0.16.0) --- updated-dependencies: - dependency-name: ruff dependency-version: 0.16.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- apps/backend/pyproject.toml | 2 +- uv.lock | 44 ++++++++++++++++++------------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/apps/backend/pyproject.toml b/apps/backend/pyproject.toml index 5e7c090..8ba62e7 100644 --- a/apps/backend/pyproject.toml +++ b/apps/backend/pyproject.toml @@ -20,7 +20,7 @@ dependencies = [ ] [dependency-groups] -dev = ["ruff==0.15.21"] +dev = ["ruff==0.16.0"] [tool.uv] add-bounds = "exact" diff --git a/uv.lock b/uv.lock index 04c6cc4..5c58f8c 100644 --- a/uv.lock +++ b/uv.lock @@ -60,7 +60,7 @@ requires-dist = [ ] [package.metadata.requires-dev] -dev = [{ name = "ruff", specifier = "==0.15.21" }] +dev = [{ name = "ruff", specifier = "==0.16.0" }] [[package]] name = "aliencommons-contributor-docs" @@ -961,27 +961,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.21" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0f/36/6f65aa9989acdec45d417192d8f4e7921931d8a6cf87ac74bce3eed98a8e/ruff-0.15.21.tar.gz", hash = "sha256:d0cfc841c572283c36548f82664a54ce6565567f1b0d5b4cf2caac693d8b7500", size = 4769401, upload-time = "2026-07-09T20:01:34.005Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/c6/ede15cac6839f3dbce52565c8f5164a8210e669c7bc4decb03e5bdf47d0d/ruff-0.15.21-py3-none-linux_armv6l.whl", hash = "sha256:63ea0e965e5d73c90e95b2434beeafc70820536717f561b32ab6e777cb9bdf5d", size = 10854342, upload-time = "2026-07-09T20:00:53.998Z" }, - { url = "https://files.pythonhosted.org/packages/28/9d/d825b07ee7ea9e2d61df92a860033c94e06e7300d50a1c2653aac27d24fe/ruff-0.15.21-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:0f212c5d7d54c01bbfe6dcab02b724a39300f3e34ed7acbe995ccb320a2c58bd", size = 11139539, upload-time = "2026-07-09T20:00:57.809Z" }, - { url = "https://files.pythonhosted.org/packages/f5/de/3b107712e642f063c7a9e0887c427b22cb44097de5aab36c05f2e280670c/ruff-0.15.21-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e6312e41bc96791299614995ea3a977c5857c3b5662b1ecef6755b02b87cb646", size = 10595437, upload-time = "2026-07-09T20:01:00.006Z" }, - { url = "https://files.pythonhosted.org/packages/9a/6f/b4523cc90ba239ede441447a19d0c968846a3012e5a0b0c5b62831a3d5e3/ruff-0.15.21-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01d65b4831c6b2a4ba8ee6faa84049d44d982b7a706e622c4094c509e51673be", size = 10990053, upload-time = "2026-07-09T20:01:02.187Z" }, - { url = "https://files.pythonhosted.org/packages/92/cc/c6a9872a5375f0628875481cf2f66b13d7d865bf3ca2e57f91c7e762d976/ruff-0.15.21-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2c5a913a589120ce67933d5d05fd6ddbcc2481c6a054980ee767f7414c72b4fd", size = 10666096, upload-time = "2026-07-09T20:01:04.299Z" }, - { url = "https://files.pythonhosted.org/packages/ab/97/c621f7a17e097f1790fa3af6374138823b330b2d03fc38337945daca212c/ruff-0.15.21-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef04b681d02ad4dc9620f00f83ac5c22f652d0e9a9cfe431d219b16ad5ccc41", size = 11537011, upload-time = "2026-07-09T20:01:06.771Z" }, - { url = "https://files.pythonhosted.org/packages/ea/51/d928727e476e25ccc57c6f449ffd80241a651a973ad949d39cfb2a771d28/ruff-0.15.21-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16d090c0740916594157e75b80d666eab8e78083b39b3b0e1d698f4670a17b86", size = 12347101, upload-time = "2026-07-09T20:01:08.859Z" }, - { url = "https://files.pythonhosted.org/packages/1e/88/8cd62026802b16018ad06931d87997cf795ba2a6239ab659606c87d96bf0/ruff-0.15.21-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a10e74757dd65004d779b73e2f3c5210156d9980b41224d50d2ebcf1db51e67", size = 11572001, upload-time = "2026-07-09T20:01:11.092Z" }, - { url = "https://files.pythonhosted.org/packages/b2/97/f63084cf55444fc110e8cb985ebfcc592af47f597d44453d778cb81bc156/ruff-0.15.21-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bab0905d2f29e0d9fbc3c373ed23db0095edaa3f71f1f4f519ec15134d9e85c8", size = 11549239, upload-time = "2026-07-09T20:01:13.27Z" }, - { url = "https://files.pythonhosted.org/packages/9d/77/f107da4a2874b7715914b03f09ba9c54424de3ff8a1cc5d015d3ee2ce0ac/ruff-0.15.21-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:00eca240af5789fec6fe7df74c088cc1f9644ed83027113468efba7c92b94075", size = 11535340, upload-time = "2026-07-09T20:01:15.206Z" }, - { url = "https://files.pythonhosted.org/packages/d5/e9/601deb322d3303a7bf212b0100ead6f2ee3f6a044d89c30f2f92bf83c731/ruff-0.15.21-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:262ab31557a75141325e32d3357f3597645a7f084e732b6b054dde428ecd9341", size = 10964048, upload-time = "2026-07-09T20:01:17.723Z" }, - { url = "https://files.pythonhosted.org/packages/ea/2e/0f2176d1e99c15192caea19c8c3a0a955246b4cb4de795042eeb616345cd/ruff-0.15.21-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:659c4e7a4212f83306045ec7c5e5a356d16d9a6ef4ae0c7a4d872914fc655d9d", size = 10667055, upload-time = "2026-07-09T20:01:19.73Z" }, - { url = "https://files.pythonhosted.org/packages/48/60/abd74a02e0c4214f12a68becfd30af7165cfdcb0e661ecdc60bbb949c09a/ruff-0.15.21-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9e866eab611a5f959d36df2d10e446973a3610bc42b0c15b31dc27977d59c233", size = 11242043, upload-time = "2026-07-09T20:01:21.947Z" }, - { url = "https://files.pythonhosted.org/packages/b2/c6/583075d8ccabb4b229345edcaf1545eb3d8d6be90f686a479d7e94088bbf/ruff-0.15.21-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e89bc93c0d3803ba870b55c29671bad9dc6d94bb1eb181b056b52eb05b52854f", size = 11648064, upload-time = "2026-07-09T20:01:24.023Z" }, - { url = "https://files.pythonhosted.org/packages/3a/3c/37d0ecb729a7cc2d393ea7dce316fc585680f35d93b8d62139d7d0a3700c/ruff-0.15.21-py3-none-win32.whl", hash = "sha256:01f8d5be84823c172b389e123174f781f9daf86d6c58719d603f941932195cdd", size = 10896555, upload-time = "2026-07-09T20:01:26.941Z" }, - { url = "https://files.pythonhosted.org/packages/c0/b8/e43466b2a6067ce91e669068f6e28d6c719a920f014b070d5c8731725de3/ruff-0.15.21-py3-none-win_amd64.whl", hash = "sha256:d4b8d9a2f0f12b816b50447f6eccb9f4bb01a6b82c86b50fb3b5354b458dc6d3", size = 12038772, upload-time = "2026-07-09T20:01:29.497Z" }, - { url = "https://files.pythonhosted.org/packages/dd/75/e90ab9aeece218a9fc5a5bc3ec97d0ee6bb3c4ff95869463c1de58e29a1c/ruff-0.15.21-py3-none-win_arm64.whl", hash = "sha256:6e83115d4b9377c1cbc13abf0e051f069fab0ef815ea0504a8a008cee24dd0a8", size = 11375265, upload-time = "2026-07-09T20:01:31.772Z" }, +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4d/94/1e5e4967626faf12fa56999cd6222dff6992ceb086ad7945756baf70c7a7/ruff-0.16.0.tar.gz", hash = "sha256:e460aafd5495ec89efaa6ced2e4a9a581116451e1c88b9d37ef497e0f8e93982", size = 4790557, upload-time = "2026-07-23T19:11:30.981Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/81/1c8818fee7ce1a04cd7d1b3172e0a8f8e4f1dc4feb7fc390e16daa8af323/ruff-0.16.0-py3-none-linux_armv6l.whl", hash = "sha256:e5115729eb08c585e5121978ba5d5b60caeae394ce21b9fb5e6cd33a1c6c9b1e", size = 10754633, upload-time = "2026-07-23T19:10:46.415Z" }, + { url = "https://files.pythonhosted.org/packages/23/df/beaf59c09d68db84304d555f188b276a77132a5d5b0b67a5c762aa143628/ruff-0.16.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:3c954b1d580bfa035b41654f7858cc7e71d5fc3ac5b723dd62bd9133830ed522", size = 10969164, upload-time = "2026-07-23T19:10:50.271Z" }, + { url = "https://files.pythonhosted.org/packages/42/ce/741cd197496a1abbf51352710fd15ed995d2a2be87189c1da26a450d6e83/ruff-0.16.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e01c21d10eb1b29f47b7454e1f4056db9a3f0260c646aa88457c610291db9f81", size = 10488846, upload-time = "2026-07-23T19:10:52.639Z" }, + { url = "https://files.pythonhosted.org/packages/52/2a/a2db8e88cade358f5cdcb05674a917751074109315d014eb6352d9a893f7/ruff-0.16.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e364e5ed22ed8dc05082fd78e35308618260907ac2d3c1d637b2e682415b6c9", size = 10889729, upload-time = "2026-07-23T19:10:54.89Z" }, + { url = "https://files.pythonhosted.org/packages/42/65/62a771694ebd63029dc953e27dbad40e1588bd4860ff9fe881018fddaa49/ruff-0.16.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d327b8fc113a1d4421a04f3839d3752057c8dd1ee320223a6f3f52d04ada462a", size = 10568275, upload-time = "2026-07-23T19:10:56.993Z" }, + { url = "https://files.pythonhosted.org/packages/3f/e2/ced249fe8af5f086c5c58cc21cc3356d50f32f7401c5df87050c999620a7/ruff-0.16.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9b50c55e263103586b3dcf5f73d479eb8cb5fdb6098fec59a62891dab653717", size = 11385112, upload-time = "2026-07-23T19:10:59.615Z" }, + { url = "https://files.pythonhosted.org/packages/87/0b/05154977a8fd69eeb6c103271f55403bfd8711f5c0f8ed07489d95a504e7/ruff-0.16.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ff4a79ce3ec0172f3241943835de1c4cb4e2dcd07f0f8c2d02603dbbbee4b17", size = 12207008, upload-time = "2026-07-23T19:11:02.154Z" }, + { url = "https://files.pythonhosted.org/packages/fb/29/98225831a3a1eab0e02f4acc6ca6559a98611dcc68b6965ff4b7234627c1/ruff-0.16.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e95c448fca1fb2a18372a9440926c5a6ee789639bb975c72e7ae6d0b04218ab4", size = 11650842, upload-time = "2026-07-23T19:11:04.557Z" }, + { url = "https://files.pythonhosted.org/packages/91/66/6bd3cf90500653d55dc0ffc8507aa8300bd49d0214b2e8cb4d3fef2943ba/ruff-0.16.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f11a8d11010301d0a398a2fdef67691feca7294da6aef55e2150e8fa2cd520b", size = 11400718, upload-time = "2026-07-23T19:11:09.233Z" }, + { url = "https://files.pythonhosted.org/packages/8e/a2/a54eb4eae05d66364050a5d3b8a9c5ef88196531b3cbe7109d873f87f819/ruff-0.16.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:48044c678e9cb8698246c99b14aaccfa6601dea7379eb48a6f8f73f7a6d86cd0", size = 11426177, upload-time = "2026-07-23T19:11:11.994Z" }, + { url = "https://files.pythonhosted.org/packages/1a/be/16e3eea4b2a478a496919f5e36f17c4559e54620bd3bbac5d6affa068006/ruff-0.16.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:7aa0959bad8eb8bef50340154fc9b58678dae31fa4293afa38b44b6e552c0213", size = 10856126, upload-time = "2026-07-23T19:11:14.221Z" }, + { url = "https://files.pythonhosted.org/packages/a2/84/252eb8b868a16eec7257c14f504f77537e734b2d69c762e639e588e304a3/ruff-0.16.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:28ea2b7df8ebf7f9da6b7d47b230ab48f387c0a29be3b474c4d0740e197bb9af", size = 10571208, upload-time = "2026-07-23T19:11:16.378Z" }, + { url = "https://files.pythonhosted.org/packages/21/09/817a482f542f7570cbb4554b26e896610c7114f539b1d9e2d2145bf6bef6/ruff-0.16.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:33a3dfac8c35f81498dea9181bccc2f4c4bc8f1521a1dd9406e77643e0f0fb09", size = 11063329, upload-time = "2026-07-23T19:11:19.173Z" }, + { url = "https://files.pythonhosted.org/packages/2e/23/9403c180ca1cb9b1f7335f5c3e5305c09d49ea5b345196682a36028bde4a/ruff-0.16.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a5237a0bda500d30d81b8e07a6973a5cbc772864cbf746ae2f4e8a2e01c9f4ed", size = 11489751, upload-time = "2026-07-23T19:11:21.74Z" }, + { url = "https://files.pythonhosted.org/packages/b2/1d/1b2ef7bcde851c78d7f17f1cca13fd6dc695fc4b3d6197941e72cae5b132/ruff-0.16.0-py3-none-win32.whl", hash = "sha256:7fab76fa065c873f41ff744347c6e77bcc3dfec4bcc754dc26b63d23c0f7f5fb", size = 10785885, upload-time = "2026-07-23T19:11:23.947Z" }, + { url = "https://files.pythonhosted.org/packages/b2/a3/d5e4ef7a56be3f928ffb90b94c25ba7d3cb9c7fe0736aeaaedf361770712/ruff-0.16.0-py3-none-win_amd64.whl", hash = "sha256:429c117f022bf481fabd9d551e7a3952b24c65e6ef44337ea09d90bebef14472", size = 11923141, upload-time = "2026-07-23T19:11:26.409Z" }, + { url = "https://files.pythonhosted.org/packages/cb/9a/8415f2657cbe200f41a4531ccededf135505a92d4a012229121f885b26f9/ruff-0.16.0-py3-none-win_arm64.whl", hash = "sha256:14296fedcd2705c77ab8235439278bbb38f285cf7da5528b00b3e330c3d4872d", size = 11273407, upload-time = "2026-07-23T19:11:28.705Z" }, ] [[package]] From 9947a1941c352fc777dbc03fd1a0a0275a9ca3c6 Mon Sep 17 00:00:00 2001 From: 4rcadia <97033226+Arcadi4@users.noreply.github.com> Date: Sat, 1 Aug 2026 00:53:02 -0400 Subject: [PATCH 2/2] style: make backend Ruff 0.16 clean --- apps/backend/articles/admin.py | 8 +-- apps/backend/articles/filters.py | 1 + apps/backend/articles/models/__init__.py | 13 +++-- apps/backend/articles/models/articles.py | 12 +++-- apps/backend/articles/permissions.py | 1 + apps/backend/articles/serializers/__init__.py | 12 ++--- apps/backend/articles/serializers/articles.py | 14 +++-- apps/backend/articles/services/articles.py | 15 +++--- apps/backend/articles/services/markdown.py | 1 - apps/backend/articles/tasks.py | 13 +++-- apps/backend/articles/tests/test_models.py | 23 ++++---- apps/backend/articles/tests/test_services.py | 14 ++--- apps/backend/articles/tests/test_views.py | 24 ++++----- apps/backend/articles/urls.py | 7 ++- apps/backend/articles/views/__init__.py | 6 +-- apps/backend/articles/views/articles.py | 18 +++++-- apps/backend/articles/views/collections.py | 2 +- apps/backend/backend/settings/base.py | 4 +- apps/backend/backend/settings/test.py | 1 - apps/backend/backend/urls.py | 9 ++-- apps/backend/bookmarks/tests/test_models.py | 17 +++--- apps/backend/bookmarks/tests/test_views.py | 7 ++- apps/backend/bookmarks/urls.py | 1 - apps/backend/bookmarks/views.py | 2 +- apps/backend/comments/mentions.py | 5 +- apps/backend/comments/serializers.py | 2 +- apps/backend/comments/services.py | 4 +- apps/backend/comments/tests/test_models.py | 4 +- apps/backend/comments/tests/test_views.py | 5 +- apps/backend/comments/urls.py | 1 - apps/backend/comments/views.py | 4 +- apps/backend/core/fields.py | 8 +-- apps/backend/core/middleware.py | 4 +- apps/backend/core/model_mixins.py | 4 +- apps/backend/core/tests/factories.py | 5 +- .../core/tests/test_exception_handler.py | 4 +- apps/backend/core/tests/test_markdown.py | 1 + apps/backend/core/tests/test_responses.py | 2 +- apps/backend/core/tests/test_view_mixins.py | 6 +-- apps/backend/core/tests/testcases.py | 2 +- apps/backend/core/utils/alienmark.py | 1 - apps/backend/core/utils/markdown.py | 6 +-- apps/backend/core/validators.py | 4 +- apps/backend/logs/logging/context.py | 7 ++- apps/backend/logs/middleware.py | 2 +- apps/backend/manage.py | 1 + apps/backend/notifications/services.py | 2 +- .../notifications/tests/test_services.py | 8 +-- apps/backend/notifications/urls.py | 1 - apps/backend/notifications/views.py | 3 +- apps/backend/posts/serializers.py | 4 +- apps/backend/posts/services.py | 4 +- apps/backend/posts/tests/test_permissions.py | 1 - apps/backend/posts/tests/test_views.py | 3 +- apps/backend/posts/urls.py | 1 - apps/backend/posts/views.py | 3 +- apps/backend/reactions/models.py | 2 +- apps/backend/reactions/services.py | 2 +- apps/backend/reactions/tests/test_models.py | 21 ++++---- apps/backend/reactions/tests/test_views.py | 7 ++- apps/backend/reactions/urls.py | 1 - apps/backend/reactions/views.py | 7 +-- apps/backend/reports/serializers.py | 1 - apps/backend/reports/services.py | 1 - apps/backend/reports/tests/test_models.py | 4 +- apps/backend/reports/tests/test_views.py | 5 +- apps/backend/reports/urls.py | 1 - apps/backend/reports/views.py | 2 +- apps/backend/ruff.toml | 52 +++++++++++++++++++ .../tasks/management/commands/init_tasks.py | 2 +- .../tasks/management/commands/runscheduler.py | 8 +-- apps/backend/tasks/schedulers.py | 5 +- apps/backend/tasks/tests/test_schedulers.py | 3 +- apps/backend/tasks/tests/test_utils.py | 3 +- apps/backend/tasks/utils.py | 4 +- apps/backend/users/admin.py | 3 +- apps/backend/users/backends.py | 2 +- apps/backend/users/middleware.py | 7 +-- apps/backend/users/models/__init__.py | 4 +- apps/backend/users/models/emails.py | 2 +- apps/backend/users/models/sessions.py | 4 +- apps/backend/users/models/users.py | 15 +++--- apps/backend/users/serializers/__init__.py | 5 +- apps/backend/users/serializers/emails.py | 1 - apps/backend/users/serializers/users.py | 12 ++--- apps/backend/users/services/sessions.py | 6 +-- apps/backend/users/services/users.py | 16 +++--- apps/backend/users/tasks.py | 2 +- apps/backend/users/tests/test_models.py | 10 ++-- apps/backend/users/tests/test_services.py | 2 +- apps/backend/users/tests/test_views.py | 1 - apps/backend/users/urls.py | 1 - apps/backend/users/views/emails.py | 2 +- apps/backend/users/views/sessions.py | 3 +- apps/backend/users/views/subscriptions.py | 7 ++- apps/backend/users/views/users.py | 6 +-- 96 files changed, 311 insertions(+), 268 deletions(-) diff --git a/apps/backend/articles/admin.py b/apps/backend/articles/admin.py index ff4eece..2d699c7 100644 --- a/apps/backend/articles/admin.py +++ b/apps/backend/articles/admin.py @@ -1,14 +1,14 @@ from django.contrib import admin, messages from .models import ( - Collection, - CollectionItem, Article, - ArticleSource, + ArticleEvent, ArticlePublication, ArticlePublicationVersion, ArticleSnapshot, - ArticleEvent, + ArticleSource, + Collection, + CollectionItem, ) diff --git a/apps/backend/articles/filters.py b/apps/backend/articles/filters.py index 450d912..9cf9ea2 100644 --- a/apps/backend/articles/filters.py +++ b/apps/backend/articles/filters.py @@ -1,4 +1,5 @@ from django_filters import rest_framework as filters + from .models import Article diff --git a/apps/backend/articles/models/__init__.py b/apps/backend/articles/models/__init__.py index 95602b3..318852f 100644 --- a/apps/backend/articles/models/__init__.py +++ b/apps/backend/articles/models/__init__.py @@ -1,13 +1,20 @@ -from .articles import Article, ArticleSource, ArticlePublication, ArticlePublicationVersion, ArticleSnapshot, ArticleEvent +from .articles import ( + Article, + ArticleEvent, + ArticlePublication, + ArticlePublicationVersion, + ArticleSnapshot, + ArticleSource, +) from .collections import Collection, CollectionItem __all__ = [ "Article", - "ArticleSource", + "ArticleEvent", "ArticlePublication", "ArticlePublicationVersion", "ArticleSnapshot", - "ArticleEvent", + "ArticleSource", "Collection", "CollectionItem", ] diff --git a/apps/backend/articles/models/articles.py b/apps/backend/articles/models/articles.py index 6e8df53..6cdfa4b 100644 --- a/apps/backend/articles/models/articles.py +++ b/apps/backend/articles/models/articles.py @@ -1,10 +1,14 @@ -from django.db import models -from django.contrib.auth import get_user_model from django.conf import settings +from django.contrib.auth import get_user_model +from django.db import models from django.utils.translation import gettext_lazy as _ -from core.model_mixins import TimeStampedMixin, UUIDPrimaryKeyMixin, SoftDeleteMixin, CreatedAtMixin - +from core.model_mixins import ( + CreatedAtMixin, + SoftDeleteMixin, + TimeStampedMixin, + UUIDPrimaryKeyMixin, +) User = get_user_model() diff --git a/apps/backend/articles/permissions.py b/apps/backend/articles/permissions.py index e3272b8..c3cbfb6 100644 --- a/apps/backend/articles/permissions.py +++ b/apps/backend/articles/permissions.py @@ -1,6 +1,7 @@ from rest_framework import permissions from core.utils.permissions import is_moderator + from .models import ArticleEvent, Collection, CollectionItem diff --git a/apps/backend/articles/serializers/__init__.py b/apps/backend/articles/serializers/__init__.py index 67dd7f8..045ef49 100644 --- a/apps/backend/articles/serializers/__init__.py +++ b/apps/backend/articles/serializers/__init__.py @@ -1,12 +1,12 @@ from .articles import ( ArticleActionResponseSerializer, ArticleEventSerializer, - ArticleSnapshotSerializer, - ImageUploadSerializer, ArticlePublicationSerializer, ArticlePublicationVersionSerializer, ArticleReadSerializer, + ArticleSnapshotSerializer, ArticleWriteSerializer, + ImageUploadSerializer, ) from .collections import ( CollectionItemReadSerializer, @@ -18,14 +18,14 @@ __all__ = [ "ArticleActionResponseSerializer", "ArticleEventSerializer", + "ArticlePublicationSerializer", + "ArticlePublicationVersionSerializer", + "ArticleReadSerializer", "ArticleSnapshotSerializer", + "ArticleWriteSerializer", "CollectionItemReadSerializer", "CollectionItemWriteSerializer", "CollectionReadSerializer", "CollectionWriteSerializer", "ImageUploadSerializer", - "ArticlePublicationSerializer", - "ArticlePublicationVersionSerializer", - "ArticleReadSerializer", - "ArticleWriteSerializer", ] diff --git a/apps/backend/articles/serializers/articles.py b/apps/backend/articles/serializers/articles.py index f06edfe..6ce82d6 100644 --- a/apps/backend/articles/serializers/articles.py +++ b/apps/backend/articles/serializers/articles.py @@ -1,30 +1,28 @@ -from pathlib import Path import io import uuid +from pathlib import Path from django.contrib.auth import get_user_model from django.core.files.base import ContentFile from django.core.files.storage import default_storage from django.db import models from django.utils import timezone +from drf_std_response import ServiceError from PIL import Image from rest_framework import serializers -from core.validators import ( - FileTypeValidator, FileSizeValidator -) -from drf_std_response import ServiceError +from core.validators import FileSizeValidator, FileTypeValidator + from ..models import ( Article, - ArticleSource, + ArticleEvent, ArticlePublication, ArticlePublicationVersion, ArticleSnapshot, - ArticleEvent, + ArticleSource, ) from ..services.markdown import extract_title_from_markdown - User = get_user_model() diff --git a/apps/backend/articles/services/articles.py b/apps/backend/articles/services/articles.py index d2b7fa3..a65392d 100644 --- a/apps/backend/articles/services/articles.py +++ b/apps/backend/articles/services/articles.py @@ -1,23 +1,24 @@ +import hashlib +import json +from datetime import timedelta + from django.db import transaction from django.db.models import Max from django.utils import timezone - -from datetime import timedelta -import json -import hashlib +from drf_std_response import ServiceError from articles.models import ( Article, - ArticleSource, + ArticleEvent, ArticlePublication, ArticlePublicationVersion, ArticleSnapshot, - ArticleEvent, + ArticleSource, ) -from drf_std_response import ServiceError from core.utils.alienmark import render_md_to_html from logs.logging import get_logger from notifications.services import notify_subscribed_author_posted + from .markdown import extract_title_from_markdown, validate_article_markdown logger = get_logger(__name__) diff --git a/apps/backend/articles/services/markdown.py b/apps/backend/articles/services/markdown.py index 887f577..147088e 100644 --- a/apps/backend/articles/services/markdown.py +++ b/apps/backend/articles/services/markdown.py @@ -1,6 +1,5 @@ from core.utils.markdown import extract_title_from_markdown, validate_article_markdown - __all__ = [ "extract_title_from_markdown", "validate_article_markdown", diff --git a/apps/backend/articles/tasks.py b/apps/backend/articles/tasks.py index a2ceb1e..a828e4b 100644 --- a/apps/backend/articles/tasks.py +++ b/apps/backend/articles/tasks.py @@ -1,13 +1,12 @@ -from django.conf import settings -from django.utils import timezone -from django.tasks import task - -from pathlib import Path import re +from pathlib import Path from urllib.parse import urlparse -from articles.models import ArticleSource +from django.conf import settings +from django.tasks import task +from django.utils import timezone +from articles.models import ArticleSource MARKDOWN_IMAGE_RE = re.compile(r"!\[[^\]]*]\(\s*(<[^>]+>|[^)\s]+)") @@ -33,7 +32,7 @@ def normalize_src(src): src = src[1:-1] # absolute url -> take path part - if src.startswith("http://") or src.startswith("https://"): + if src.startswith(("http://", "https://")): src = urlparse(src).path # "/media/xxx" # only handle MEDIA_URL files diff --git a/apps/backend/articles/tests/test_models.py b/apps/backend/articles/tests/test_models.py index 91df1f4..c839697 100644 --- a/apps/backend/articles/tests/test_models.py +++ b/apps/backend/articles/tests/test_models.py @@ -1,21 +1,21 @@ from django.db import IntegrityError, transaction from articles.models import ( + Article, ArticleEvent, + ArticlePublication, + ArticlePublicationVersion, ArticleSnapshot, Collection, CollectionItem, - ArticlePublication, - ArticlePublicationVersion, - Article, ) from articles.services.articles import ArticleWorkflow from core.models import ContentTarget from core.tests.factories import ( + create_article, + create_article_publication, create_collection, create_collection_item, - create_article_publication, - create_article, create_user, ) from core.tests.testcases import BaseTestCase @@ -134,13 +134,12 @@ def test_collection_item_rejects_duplicate_article_in_collection(self): published = create_article_publication(article) create_collection_item(collection, published) - with self.assertRaises(IntegrityError): - with transaction.atomic(): - CollectionItem.objects.create( - collection=collection, - article_publication=published, - position=2, - ) + with self.assertRaises(IntegrityError), transaction.atomic(): + CollectionItem.objects.create( + collection=collection, + article_publication=published, + position=2, + ) def test_collection_delete_removes_collection_items(self): collection = create_collection(author=self.author) diff --git a/apps/backend/articles/tests/test_services.py b/apps/backend/articles/tests/test_services.py index 356791f..95f5ae2 100644 --- a/apps/backend/articles/tests/test_services.py +++ b/apps/backend/articles/tests/test_services.py @@ -1,14 +1,15 @@ -from django.utils import timezone - from datetime import timedelta from unittest.mock import patch +from django.utils import timezone +from drf_std_response import ServiceError + from articles.models import ( + Article, ArticleEvent, - ArticleSnapshot, ArticlePublication, ArticlePublicationVersion, - Article, + ArticleSnapshot, ) from articles.services.articles import ( approve, @@ -19,12 +20,11 @@ unpublish, withdraw, ) -from drf_std_response import ServiceError from core.tests.factories import ( + create_article, + create_article_publication, create_article_snapshot, create_moderator, - create_article_publication, - create_article, create_user, ) from core.tests.testcases import BaseTestCase diff --git a/apps/backend/articles/tests/test_views.py b/apps/backend/articles/tests/test_views.py index 0cf9f2d..dabde9c 100644 --- a/apps/backend/articles/tests/test_views.py +++ b/apps/backend/articles/tests/test_views.py @@ -1,26 +1,26 @@ -from django.urls import reverse +from unittest.mock import patch +from django.urls import reverse from rest_framework import status -from unittest.mock import patch +from articles.models import ( + Article, + ArticleEvent, + ArticlePublication, + ArticleSnapshot, + Collection, + CollectionItem, +) from core.tests.factories import ( + create_article, + create_article_publication, create_article_snapshot, create_collection, create_collection_item, create_moderator, - create_article_publication, - create_article, create_user, ) from core.tests.testcases import BaseAPITestCase -from articles.models import ( - ArticleEvent, - ArticleSnapshot, - Collection, - CollectionItem, - ArticlePublication, - Article, -) class ArticleViewTests(BaseAPITestCase): diff --git a/apps/backend/articles/urls.py b/apps/backend/articles/urls.py index 6067199..1c90961 100644 --- a/apps/backend/articles/urls.py +++ b/apps/backend/articles/urls.py @@ -1,15 +1,14 @@ from rest_framework import routers from .views import ( - ArticleViewSet, + ArticleEventReadViewset, ArticlePublicationViewSet, ArticleSnapshotViewSet, - ArticleEventReadViewset, - CollectionViewSet, + ArticleViewSet, CollectionItemViewSet, + CollectionViewSet, ) - router = routers.SimpleRouter() router.register(r'articles', ArticleViewSet, basename='article') diff --git a/apps/backend/articles/views/__init__.py b/apps/backend/articles/views/__init__.py index 73d9ce3..6ca6009 100644 --- a/apps/backend/articles/views/__init__.py +++ b/apps/backend/articles/views/__init__.py @@ -1,16 +1,16 @@ from .articles import ( ArticleEventReadViewset, - ArticleSnapshotViewSet, ArticlePublicationViewSet, + ArticleSnapshotViewSet, ArticleViewSet, ) from .collections import CollectionItemViewSet, CollectionViewSet __all__ = [ "ArticleEventReadViewset", + "ArticlePublicationViewSet", "ArticleSnapshotViewSet", + "ArticleViewSet", "CollectionItemViewSet", "CollectionViewSet", - "ArticlePublicationViewSet", - "ArticleViewSet", ] diff --git a/apps/backend/articles/views/articles.py b/apps/backend/articles/views/articles.py index 2f58237..4f4ab4b 100644 --- a/apps/backend/articles/views/articles.py +++ b/apps/backend/articles/views/articles.py @@ -1,14 +1,15 @@ from django.db.models import OuterRef, Subquery from django_filters import rest_framework as filters +from drf_std_response import EnvelopeMixin from rest_framework import status from rest_framework.decorators import action from rest_framework.permissions import IsAuthenticated from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet from core.utils.permissions import is_moderator -from drf_std_response import EnvelopeMixin + from ..filters import ArticleFilter -from ..models import Article, ArticleEvent, ArticleSnapshot, ArticlePublication +from ..models import Article, ArticleEvent, ArticlePublication, ArticleSnapshot from ..permissions import ( ArticleEventPermission, AuthorOnly, @@ -17,14 +18,21 @@ from ..serializers import ( ArticleActionResponseSerializer, ArticleEventSerializer, - ArticleSnapshotSerializer, - ImageUploadSerializer, ArticlePublicationSerializer, ArticleReadSerializer, + ArticleSnapshotSerializer, ArticleWriteSerializer, + ImageUploadSerializer, ) from ..services.articles import ( - approve, create_article, reject, save_draft, soft_delete, submit, unpublish, withdraw + approve, + create_article, + reject, + save_draft, + soft_delete, + submit, + unpublish, + withdraw, ) diff --git a/apps/backend/articles/views/collections.py b/apps/backend/articles/views/collections.py index 961b143..8a07e2e 100644 --- a/apps/backend/articles/views/collections.py +++ b/apps/backend/articles/views/collections.py @@ -1,9 +1,9 @@ from django.db.models import Count, Max +from drf_std_response import EnvelopeMixin from rest_framework import status from rest_framework.exceptions import PermissionDenied from rest_framework.viewsets import ModelViewSet -from drf_std_response import EnvelopeMixin from ..models import Collection, CollectionItem from ..permissions import CollectionItemPermission, CollectionPermission from ..serializers import ( diff --git a/apps/backend/backend/settings/base.py b/apps/backend/backend/settings/base.py index 16e1f41..83674b9 100644 --- a/apps/backend/backend/settings/base.py +++ b/apps/backend/backend/settings/base.py @@ -1,7 +1,7 @@ # from django.utils.translation import gettext_lazy as _ -from django.contrib import messages - from pathlib import Path + +from django.contrib import messages from environs import Env BASE_DIR = Path(__file__).resolve().parents[2] diff --git a/apps/backend/backend/settings/test.py b/apps/backend/backend/settings/test.py index 6d4a83f..e5b9181 100644 --- a/apps/backend/backend/settings/test.py +++ b/apps/backend/backend/settings/test.py @@ -6,7 +6,6 @@ from django.utils.translation import gettext_lazy as _ - BASE_DIR = Path(__file__).resolve().parent.parent.parent SECRET_KEY = "test-secret-key" diff --git a/apps/backend/backend/urls.py b/apps/backend/backend/urls.py index e032a26..c2fd684 100644 --- a/apps/backend/backend/urls.py +++ b/apps/backend/backend/urls.py @@ -1,10 +1,7 @@ -from django.contrib import admin -from django.conf.urls.static import static -from django.urls import path, include - - from django.conf import settings - +from django.conf.urls.static import static +from django.contrib import admin +from django.urls import include, path urlpatterns = [ path("admin/", admin.site.urls), diff --git a/apps/backend/bookmarks/tests/test_models.py b/apps/backend/bookmarks/tests/test_models.py index 2343e4f..cb9f7e3 100644 --- a/apps/backend/bookmarks/tests/test_models.py +++ b/apps/backend/bookmarks/tests/test_models.py @@ -1,11 +1,12 @@ -from django.db import IntegrityError, transaction from django.conf import settings +from django.db import IntegrityError, transaction + from bookmarks.models import Bookmark, BookmarkFolder from core.tests.factories import ( + create_article, + create_article_publication, create_bookmark, create_bookmark_folder, - create_article_publication, - create_article, create_user, ) from core.tests.testcases import BaseTestCase @@ -41,18 +42,16 @@ def test_bookmark_string_representation_references_user_and_article(self): def test_bookmark_folder_rejects_duplicate_name_per_user(self): create_bookmark_folder(user=self.user, name="Research") - with self.assertRaises(IntegrityError): - with transaction.atomic(): - create_bookmark_folder(user=self.user, name="Research") + with self.assertRaises(IntegrityError), transaction.atomic(): + create_bookmark_folder(user=self.user, name="Research") def test_bookmark_rejects_duplicate_article_publication_per_user(self): article = create_article() published = create_article_publication(article) create_bookmark(self.user, published) - with self.assertRaises(IntegrityError): - with transaction.atomic(): - create_bookmark(self.user, published) + with self.assertRaises(IntegrityError), transaction.atomic(): + create_bookmark(self.user, published) def test_bookmark_folder_delete_removes_bookmarks(self): article = create_article() diff --git a/apps/backend/bookmarks/tests/test_views.py b/apps/backend/bookmarks/tests/test_views.py index 2f8b091..a9e2d78 100644 --- a/apps/backend/bookmarks/tests/test_views.py +++ b/apps/backend/bookmarks/tests/test_views.py @@ -1,14 +1,13 @@ -from django.urls import reverse from django.conf import settings - +from django.urls import reverse from rest_framework import status from bookmarks.models import Bookmark, BookmarkFolder from core.tests.factories import ( + create_article, + create_article_publication, create_bookmark, create_bookmark_folder, - create_article_publication, - create_article, create_user, ) from core.tests.testcases import BaseAPITestCase diff --git a/apps/backend/bookmarks/urls.py b/apps/backend/bookmarks/urls.py index cae9fa5..f3593a4 100644 --- a/apps/backend/bookmarks/urls.py +++ b/apps/backend/bookmarks/urls.py @@ -2,7 +2,6 @@ from .views import BookmarkFolderViewSet, BookmarkViewSet - router = DefaultRouter() router.register(r"bookmark_folders", BookmarkFolderViewSet, basename="bookmark_folder") router.register(r"bookmarks", BookmarkViewSet, basename="bookmark") diff --git a/apps/backend/bookmarks/views.py b/apps/backend/bookmarks/views.py index daa403c..1f21088 100644 --- a/apps/backend/bookmarks/views.py +++ b/apps/backend/bookmarks/views.py @@ -1,8 +1,8 @@ from django.db.models import Count +from drf_std_response import EnvelopeMixin from rest_framework import status from rest_framework.viewsets import ModelViewSet -from drf_std_response import EnvelopeMixin from .models import Bookmark, BookmarkFolder from .permissions import BookmarkOwnerOnly from .serializers import ( diff --git a/apps/backend/comments/mentions.py b/apps/backend/comments/mentions.py index f4657c5..d42afb8 100644 --- a/apps/backend/comments/mentions.py +++ b/apps/backend/comments/mentions.py @@ -1,10 +1,13 @@ from core.utils.markdown import ( render_markdown_mentions as render_body, +) +from core.utils.markdown import ( serialize_markdown_mentions as serialize_mentions, +) +from core.utils.markdown import ( validate_markdown_mentions as validate_mentions, ) - __all__ = [ "render_body", "serialize_mentions", diff --git a/apps/backend/comments/serializers.py b/apps/backend/comments/serializers.py index 8621496..f7412af 100644 --- a/apps/backend/comments/serializers.py +++ b/apps/backend/comments/serializers.py @@ -1,7 +1,7 @@ +from drf_std_response import ServiceError from rest_framework import serializers from articles.models import ArticlePublication -from drf_std_response import ServiceError from core.models import ContentTarget from core.utils.markdown import ( render_markdown_mentions, diff --git a/apps/backend/comments/services.py b/apps/backend/comments/services.py index 6e36b27..9e7ac8c 100644 --- a/apps/backend/comments/services.py +++ b/apps/backend/comments/services.py @@ -1,12 +1,12 @@ from django.db import transaction +from drf_std_response import ServiceError from articles.models import ArticlePublication -from drf_std_response import ServiceError from core.models import ContentTarget from core.services.content_targets import ( + get_or_create_article_publication_target, get_or_create_comment_target, get_or_create_community_post_target, - get_or_create_article_publication_target, ) from notifications.services import notify_comment_reply, notify_mentions from posts.models import CommunityPost diff --git a/apps/backend/comments/tests/test_models.py b/apps/backend/comments/tests/test_models.py index 3c8c481..e08945b 100644 --- a/apps/backend/comments/tests/test_models.py +++ b/apps/backend/comments/tests/test_models.py @@ -3,9 +3,9 @@ from core.models import ContentTarget from core.services.content_targets import get_or_create_article_publication_target from core.tests.factories import ( - create_comment, - create_article_publication, create_article, + create_article_publication, + create_comment, create_user, ) from core.tests.testcases import BaseTestCase diff --git a/apps/backend/comments/tests/test_views.py b/apps/backend/comments/tests/test_views.py index 729bba4..bd9db47 100644 --- a/apps/backend/comments/tests/test_views.py +++ b/apps/backend/comments/tests/test_views.py @@ -1,13 +1,12 @@ from django.urls import reverse - from rest_framework import status from comments.models import Comment from core.tests.factories import ( + create_article, + create_article_publication, create_comment, create_community_post, - create_article_publication, - create_article, create_user, ) from core.tests.testcases import BaseAPITestCase diff --git a/apps/backend/comments/urls.py b/apps/backend/comments/urls.py index b039538..f3900bc 100644 --- a/apps/backend/comments/urls.py +++ b/apps/backend/comments/urls.py @@ -2,7 +2,6 @@ from .views import CommentViewSet - router = routers.SimpleRouter() router.register(r"comments", CommentViewSet, basename="comment") diff --git a/apps/backend/comments/views.py b/apps/backend/comments/views.py index 4001c37..5177d88 100644 --- a/apps/backend/comments/views.py +++ b/apps/backend/comments/views.py @@ -1,15 +1,15 @@ from django.db.models import Count, Q +from drf_std_response import EnvelopeMixin from rest_framework import status from rest_framework.viewsets import ModelViewSet -from drf_std_response import EnvelopeMixin from .models import Comment from .permissions import CommentPermission from .serializers import CommentReadSerializer, CommentWriteSerializer from .services import ( create_comment, - get_community_post_target, get_article_publication_target, + get_community_post_target, soft_delete_comment, update_comment, ) diff --git a/apps/backend/core/fields.py b/apps/backend/core/fields.py index 751ba78..7a90f2e 100644 --- a/apps/backend/core/fields.py +++ b/apps/backend/core/fields.py @@ -1,9 +1,9 @@ -from rest_framework import serializers -from django.utils.dateparse import parse_datetime -from django.utils.timezone import make_aware, is_naive - from datetime import datetime +from django.utils.dateparse import parse_datetime +from django.utils.timezone import is_naive, make_aware +from rest_framework import serializers + class FlexibleDateTimeField(serializers.DateTimeField): """ diff --git a/apps/backend/core/middleware.py b/apps/backend/core/middleware.py index 14d805a..6f2c7f1 100644 --- a/apps/backend/core/middleware.py +++ b/apps/backend/core/middleware.py @@ -1,7 +1,7 @@ -from django.utils import timezone - import uuid +from django.utils import timezone + class RequestMetaMiddleware: """ diff --git a/apps/backend/core/model_mixins.py b/apps/backend/core/model_mixins.py index 8a00598..cf895c9 100644 --- a/apps/backend/core/model_mixins.py +++ b/apps/backend/core/model_mixins.py @@ -1,8 +1,8 @@ +import uuid + from django.db import models from django.utils.translation import gettext_lazy as _ -import uuid - class CreatedAtMixin(models.Model): """ diff --git a/apps/backend/core/tests/factories.py b/apps/backend/core/tests/factories.py index be7cbf6..a798f3a 100644 --- a/apps/backend/core/tests/factories.py +++ b/apps/backend/core/tests/factories.py @@ -17,16 +17,15 @@ from comments.models import Comment from core.models import ContentTarget from core.services.content_targets import ( - get_or_create_comment_target, get_or_create_article_publication_target, + get_or_create_comment_target, ) +from posts.services import create_community_post as create_community_post_service from reactions.models import Reaction from reports.models import ContentReport, UserReport -from posts.services import create_community_post as create_community_post_service from .helpers import unique_suffix - User = get_user_model() diff --git a/apps/backend/core/tests/test_exception_handler.py b/apps/backend/core/tests/test_exception_handler.py index 2ef20ed..c81b621 100644 --- a/apps/backend/core/tests/test_exception_handler.py +++ b/apps/backend/core/tests/test_exception_handler.py @@ -2,12 +2,12 @@ from django.core.exceptions import PermissionDenied from django.http import Http404 +from drf_std_response import ServiceError +from drf_std_response.exception_handlers import exception_handler from rest_framework import status from rest_framework.exceptions import NotAuthenticated, ValidationError from core.tests.testcases import BaseTestCase -from drf_std_response import ServiceError -from drf_std_response.exception_handlers import exception_handler class CustomExceptionHandlerTests(BaseTestCase): diff --git a/apps/backend/core/tests/test_markdown.py b/apps/backend/core/tests/test_markdown.py index cc6ac03..f06bef9 100644 --- a/apps/backend/core/tests/test_markdown.py +++ b/apps/backend/core/tests/test_markdown.py @@ -1,4 +1,5 @@ from drf_std_response import ServiceError + from core.tests.factories import create_user from core.tests.testcases import BaseTestCase from core.utils.markdown import ( diff --git a/apps/backend/core/tests/test_responses.py b/apps/backend/core/tests/test_responses.py index 0c5221e..773a7c8 100644 --- a/apps/backend/core/tests/test_responses.py +++ b/apps/backend/core/tests/test_responses.py @@ -1,9 +1,9 @@ from types import SimpleNamespace +from drf_std_response import format_response from rest_framework import status from core.tests.testcases import BaseTestCase -from drf_std_response import format_response class FormatResponseTests(BaseTestCase): diff --git a/apps/backend/core/tests/test_view_mixins.py b/apps/backend/core/tests/test_view_mixins.py index 3051812..759d9c5 100644 --- a/apps/backend/core/tests/test_view_mixins.py +++ b/apps/backend/core/tests/test_view_mixins.py @@ -1,7 +1,7 @@ from django.contrib.auth import get_user_model -from django.urls import path from django.test import override_settings - +from django.urls import path +from drf_std_response import EnvelopeMixin from rest_framework import serializers, status from rest_framework.mixins import ListModelMixin from rest_framework.test import APIRequestFactory @@ -11,8 +11,6 @@ from core.pagination import StandardPagination from core.tests.factories import create_article from core.tests.testcases import BaseTestCase -from drf_std_response import EnvelopeMixin - User = get_user_model() diff --git a/apps/backend/core/tests/testcases.py b/apps/backend/core/tests/testcases.py index 313d579..9fee716 100644 --- a/apps/backend/core/tests/testcases.py +++ b/apps/backend/core/tests/testcases.py @@ -1,5 +1,5 @@ -from django.test import TestCase from django.core.cache import cache +from django.test import TestCase from rest_framework.test import APITestCase from .mixins import ( diff --git a/apps/backend/core/utils/alienmark.py b/apps/backend/core/utils/alienmark.py index 9a409ed..bcc076b 100644 --- a/apps/backend/core/utils/alienmark.py +++ b/apps/backend/core/utils/alienmark.py @@ -1,6 +1,5 @@ import requests from django.conf import settings - from drf_std_response import ServiceError diff --git a/apps/backend/core/utils/markdown.py b/apps/backend/core/utils/markdown.py index bd53071..6ddf73a 100644 --- a/apps/backend/core/utils/markdown.py +++ b/apps/backend/core/utils/markdown.py @@ -3,10 +3,8 @@ from django.conf import settings from django.contrib.auth import get_user_model - from drf_std_response import ServiceError - H1_RE = re.compile(r"^#(?!#)\s+(.+?)\s*$") CLOSING_HASHES_RE = re.compile(r"\s+#+\s*$") MENTION_TOKEN_PATTERN = re.compile(r"\{\{mention:(\d+)}}") @@ -112,10 +110,10 @@ def validate_markdown_mentions(*, body, mentions): ) User = get_user_model() - existing_user_ids = set( + existing_user_ids = { str(user_id) for user_id in User.objects.filter(id__in=mentions).values_list("id", flat=True) - ) + } missing_user_ids = [str(user_id) for user_id in mentions if str(user_id) not in existing_user_ids] if missing_user_ids: raise ServiceError( diff --git a/apps/backend/core/validators.py b/apps/backend/core/validators.py index 42204e6..1d29ae1 100644 --- a/apps/backend/core/validators.py +++ b/apps/backend/core/validators.py @@ -1,5 +1,5 @@ from django.contrib.auth.password_validation import validate_password - +from django.core.exceptions import ValidationError as DjangoValidationError from rest_framework import serializers from core.utils.file_types import FILE_TYPE_MAP @@ -12,7 +12,7 @@ def __init__(self, min_length=8): def __call__(self, value): try: validate_password(value) - except Exception: + except DjangoValidationError: message = "Your password does not meet the requirement(s)" raise serializers.ValidationError(message) diff --git a/apps/backend/logs/logging/context.py b/apps/backend/logs/logging/context.py index 2116778..a67346d 100644 --- a/apps/backend/logs/logging/context.py +++ b/apps/backend/logs/logging/context.py @@ -1,7 +1,6 @@ from contextvars import ContextVar - -_log_context = ContextVar('log_context', default={}) +_log_context = ContextVar('log_context', default=None) def get_log_context() -> dict: @@ -13,7 +12,7 @@ def get_log_context() -> dict: - clear_log_context() - unbind_log_context() """ - context_copy = dict(_log_context.get()) + context_copy = dict(_log_context.get() or {}) return context_copy @@ -30,7 +29,7 @@ def add_log_context(**values) -> None: Merge the provided values into the current logging context. Accepts only keyword arguments. """ - current_context = dict(_log_context.get()) + current_context = dict(_log_context.get() or {}) current_context.update(values) _log_context.set(current_context) diff --git a/apps/backend/logs/middleware.py b/apps/backend/logs/middleware.py index 3b97a56..845ff25 100644 --- a/apps/backend/logs/middleware.py +++ b/apps/backend/logs/middleware.py @@ -1,7 +1,7 @@ from django.utils import timezone -from logs.logging.context import add_log_context, clear_log_context from logs.logging import get_logger +from logs.logging.context import add_log_context, clear_log_context logger = get_logger(__name__) diff --git a/apps/backend/manage.py b/apps/backend/manage.py index 58cd5b4..402db11 100755 --- a/apps/backend/manage.py +++ b/apps/backend/manage.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python3 import os import sys diff --git a/apps/backend/notifications/services.py b/apps/backend/notifications/services.py index 5f0c61b..86e3fa5 100644 --- a/apps/backend/notifications/services.py +++ b/apps/backend/notifications/services.py @@ -130,7 +130,7 @@ def fan_out_pending_events(*, batch_size=100): try: fan_out_event(event_id=event_id) delivered += 1 - except Exception: + except (NotificationEvent.DoesNotExist, ValueError, TypeError): failed += 1 return {"scanned": len(event_ids), "delivered": delivered, "failed": failed} diff --git a/apps/backend/notifications/tests/test_services.py b/apps/backend/notifications/tests/test_services.py index c598767..79e05f3 100644 --- a/apps/backend/notifications/tests/test_services.py +++ b/apps/backend/notifications/tests/test_services.py @@ -1,11 +1,13 @@ from comments.services import create_comment from core.tests.factories import ( - create_comment as create_comment_record, - create_community_post, - create_article_publication, create_article, + create_article_publication, + create_community_post, create_user, ) +from core.tests.factories import ( + create_comment as create_comment_record, +) from core.tests.testcases import BaseTestCase from notifications.models import NotificationEvent from notifications.services import ( diff --git a/apps/backend/notifications/urls.py b/apps/backend/notifications/urls.py index 0771c2a..8a3af46 100644 --- a/apps/backend/notifications/urls.py +++ b/apps/backend/notifications/urls.py @@ -2,7 +2,6 @@ from .views import NotificationDeliveryViewSet - router = routers.SimpleRouter() router.register(r"notifications", NotificationDeliveryViewSet, basename="notification") diff --git a/apps/backend/notifications/views.py b/apps/backend/notifications/views.py index 1621f63..a0ffe43 100644 --- a/apps/backend/notifications/views.py +++ b/apps/backend/notifications/views.py @@ -1,10 +1,9 @@ +from drf_std_response import EnvelopeMixin, ServiceError from rest_framework import status from rest_framework.decorators import action from rest_framework.permissions import IsAuthenticated from rest_framework.viewsets import ReadOnlyModelViewSet -from drf_std_response import EnvelopeMixin, ServiceError - from .models import NotificationDelivery, NotificationEvent from .serializers import NotificationDeliverySerializer from .services import mark_all_deliveries_read, mark_delivery_read diff --git a/apps/backend/posts/serializers.py b/apps/backend/posts/serializers.py index 6513c33..a5b4ada 100644 --- a/apps/backend/posts/serializers.py +++ b/apps/backend/posts/serializers.py @@ -1,7 +1,7 @@ -from rest_framework import serializers from django.db import models - from drf_std_response import ServiceError +from rest_framework import serializers + from core.utils.markdown import ( render_markdown_mentions, serialize_markdown_mentions, diff --git a/apps/backend/posts/services.py b/apps/backend/posts/services.py index 474423a..72a2c4e 100644 --- a/apps/backend/posts/services.py +++ b/apps/backend/posts/services.py @@ -4,7 +4,7 @@ from .models import CommunityPost -def create_community_post(*, author, body: str, mentions: list = None): +def create_community_post(*, author, body: str, mentions: list | None = None): post = CommunityPost.objects.create(author=author, body=body, mentions=mentions or []) target = get_or_create_community_post_target(post) notify_mentions( @@ -21,7 +21,7 @@ def create_community_post(*, author, body: str, mentions: list = None): return post -def update_community_post(*, post: CommunityPost, body: str, mentions: list = None): +def update_community_post(*, post: CommunityPost, body: str, mentions: list | None = None): previous_mentions = set(post.mentions) post.body = body if mentions is not None: diff --git a/apps/backend/posts/tests/test_permissions.py b/apps/backend/posts/tests/test_permissions.py index bfb8931..66ada44 100644 --- a/apps/backend/posts/tests/test_permissions.py +++ b/apps/backend/posts/tests/test_permissions.py @@ -1,5 +1,4 @@ from django.contrib.auth.models import AnonymousUser - from rest_framework.test import APIRequestFactory from core.tests.factories import create_user diff --git a/apps/backend/posts/tests/test_views.py b/apps/backend/posts/tests/test_views.py index 2878b16..08c420e 100644 --- a/apps/backend/posts/tests/test_views.py +++ b/apps/backend/posts/tests/test_views.py @@ -1,10 +1,9 @@ from django.urls import reverse - from rest_framework import status +from comments.models import Comment from core.tests.factories import create_community_post, create_user from core.tests.testcases import BaseAPITestCase -from comments.models import Comment from posts.models import CommunityPost from reactions.models import Reaction diff --git a/apps/backend/posts/urls.py b/apps/backend/posts/urls.py index d2fd8f9..ebf182c 100644 --- a/apps/backend/posts/urls.py +++ b/apps/backend/posts/urls.py @@ -2,7 +2,6 @@ from .views import CommunityPostViewSet - router = routers.SimpleRouter() router.register(r"community_posts", CommunityPostViewSet, basename="community_post") diff --git a/apps/backend/posts/views.py b/apps/backend/posts/views.py index 6cf8117..5d7057b 100644 --- a/apps/backend/posts/views.py +++ b/apps/backend/posts/views.py @@ -1,8 +1,7 @@ +from drf_std_response import EnvelopeMixin from rest_framework import status from rest_framework.viewsets import ModelViewSet -from drf_std_response import EnvelopeMixin - from .models import CommunityPost from .permissions import CommunityPostPermission from .serializers import CommunityPostReadSerializer, CommunityPostWriteSerializer diff --git a/apps/backend/reactions/models.py b/apps/backend/reactions/models.py index e9f0aee..f1f54bf 100644 --- a/apps/backend/reactions/models.py +++ b/apps/backend/reactions/models.py @@ -2,8 +2,8 @@ from django.db import models from django.utils.translation import gettext_lazy as _ -from core.models import ContentTarget from core.model_mixins import CreatedAtMixin, UUIDPrimaryKeyMixin +from core.models import ContentTarget class Reaction(UUIDPrimaryKeyMixin, diff --git a/apps/backend/reactions/services.py b/apps/backend/reactions/services.py index 243de42..7d67e44 100644 --- a/apps/backend/reactions/services.py +++ b/apps/backend/reactions/services.py @@ -3,8 +3,8 @@ from articles.models import ArticlePublication from core.models import ContentTarget from core.services.content_targets import ( - get_or_create_community_post_target, get_or_create_article_publication_target, + get_or_create_community_post_target, ) from posts.models import CommunityPost diff --git a/apps/backend/reactions/tests/test_models.py b/apps/backend/reactions/tests/test_models.py index 5cb4f5b..42135b8 100644 --- a/apps/backend/reactions/tests/test_models.py +++ b/apps/backend/reactions/tests/test_models.py @@ -1,15 +1,15 @@ from django.db import IntegrityError, transaction -from articles.models import ArticlePublication, Article +from articles.models import Article, ArticlePublication +from core.models import ContentTarget from core.tests.factories import ( - create_content_target, + create_article, create_article_publication, + create_content_target, create_reaction, - create_article, create_user, ) from core.tests.testcases import BaseTestCase -from core.models import ContentTarget from reactions.models import Reaction @@ -38,13 +38,12 @@ def test_user_can_only_have_one_reaction_per_target(self): target = create_content_target(self.published) create_reaction(self.user, self.published, target=target) - with self.assertRaises(IntegrityError): - with transaction.atomic(): - Reaction.objects.create( - user=self.user, - target=target, - reaction_type=Reaction.ReactionType.DISLIKE, - ) + with self.assertRaises(IntegrityError), transaction.atomic(): + Reaction.objects.create( + user=self.user, + target=target, + reaction_type=Reaction.ReactionType.DISLIKE, + ) def test_article_publication_delete_cascades_content_target_and_reactions(self): target = create_content_target(self.published) diff --git a/apps/backend/reactions/tests/test_views.py b/apps/backend/reactions/tests/test_views.py index 1fc60ee..6c46760 100644 --- a/apps/backend/reactions/tests/test_views.py +++ b/apps/backend/reactions/tests/test_views.py @@ -1,16 +1,15 @@ from django.urls import reverse - from rest_framework import status +from core.models import ContentTarget from core.tests.factories import ( - create_community_post, + create_article, create_article_publication, + create_community_post, create_reaction, - create_article, create_user, ) from core.tests.testcases import BaseAPITestCase -from core.models import ContentTarget from reactions.models import Reaction diff --git a/apps/backend/reactions/urls.py b/apps/backend/reactions/urls.py index 31379be..135c8ff 100644 --- a/apps/backend/reactions/urls.py +++ b/apps/backend/reactions/urls.py @@ -2,7 +2,6 @@ from .views import ReactionViewSet - router = routers.SimpleRouter() router.register(r"reactions", ReactionViewSet, basename="reaction") diff --git a/apps/backend/reactions/views.py b/apps/backend/reactions/views.py index 1c5babb..cb9041a 100644 --- a/apps/backend/reactions/views.py +++ b/apps/backend/reactions/views.py @@ -1,3 +1,4 @@ +from drf_std_response import EnvelopeMixin from rest_framework import status from rest_framework.decorators import action from rest_framework.generics import get_object_or_404 @@ -5,15 +6,15 @@ from rest_framework.viewsets import ModelViewSet from articles.models import ArticlePublication -from drf_std_response import EnvelopeMixin from posts.models import CommunityPost + from .models import Reaction from .serializers import ReactionReadSerializer, ReactionWriteSerializer from .services import ( - clear_community_post_reaction, clear_article_publication_reaction, - set_community_post_reaction, + clear_community_post_reaction, set_article_publication_reaction, + set_community_post_reaction, update_reaction_type, ) diff --git a/apps/backend/reports/serializers.py b/apps/backend/reports/serializers.py index 74be540..24fcd63 100644 --- a/apps/backend/reports/serializers.py +++ b/apps/backend/reports/serializers.py @@ -5,7 +5,6 @@ from .models import BaseReport, ContentReport, UserReport - User = get_user_model() diff --git a/apps/backend/reports/services.py b/apps/backend/reports/services.py index c722f26..58ed089 100644 --- a/apps/backend/reports/services.py +++ b/apps/backend/reports/services.py @@ -5,7 +5,6 @@ from .models import BaseReport, ContentReport, UserReport - TERMINAL_REPORT_STATUSES = { BaseReport.ReportStatus.RESOLVED, BaseReport.ReportStatus.REJECTED, diff --git a/apps/backend/reports/tests/test_models.py b/apps/backend/reports/tests/test_models.py index fb00d62..d5c2d48 100644 --- a/apps/backend/reports/tests/test_models.py +++ b/apps/backend/reports/tests/test_models.py @@ -1,9 +1,9 @@ from core.services.content_targets import get_or_create_article_publication_target from core.tests.factories import ( + create_article, + create_article_publication, create_community_post, create_content_report, - create_article_publication, - create_article, create_user, create_user_report, ) diff --git a/apps/backend/reports/tests/test_views.py b/apps/backend/reports/tests/test_views.py index 27a8937..8e2a230 100644 --- a/apps/backend/reports/tests/test_views.py +++ b/apps/backend/reports/tests/test_views.py @@ -1,13 +1,12 @@ from django.urls import reverse - from rest_framework import status from core.services.content_targets import get_or_create_article_publication_target from core.tests.factories import ( + create_article, + create_article_publication, create_content_report, create_moderator, - create_article_publication, - create_article, create_user, create_user_report, ) diff --git a/apps/backend/reports/urls.py b/apps/backend/reports/urls.py index 8370981..6d56057 100644 --- a/apps/backend/reports/urls.py +++ b/apps/backend/reports/urls.py @@ -2,7 +2,6 @@ from .views import ContentReportViewSet, UserReportViewSet - router = routers.SimpleRouter() router.register(r"content_reports", ContentReportViewSet, basename="content_report") router.register(r"user_reports", UserReportViewSet, basename="user_report") diff --git a/apps/backend/reports/views.py b/apps/backend/reports/views.py index 9084551..505c965 100644 --- a/apps/backend/reports/views.py +++ b/apps/backend/reports/views.py @@ -1,8 +1,8 @@ +from drf_std_response import EnvelopeMixin from rest_framework import status from rest_framework.viewsets import ModelViewSet from core.utils.permissions import is_moderator -from drf_std_response import EnvelopeMixin from .models import ContentReport, UserReport from .permissions import ReportPermission diff --git a/apps/backend/ruff.toml b/apps/backend/ruff.toml index 4beccd1..f305e1f 100644 --- a/apps/backend/ruff.toml +++ b/apps/backend/ruff.toml @@ -1,4 +1,56 @@ +# Django/DRF declarative class metadata is intentionally class-level framework +# configuration, not mutable runtime state. Keep RUF012 enabled elsewhere. [lint.per-file-ignores] +"articles/admin.py" = ["RUF012"] +"articles/filters.py" = ["RUF012"] +"articles/migrations/0001_initial.py" = ["I001", "RUF012"] +"articles/models/articles.py" = ["RUF012"] +"articles/models/collections.py" = ["RUF012"] +"articles/serializers/articles.py" = ["RUF012"] +"articles/serializers/collections.py" = ["RUF012"] +"articles/views/articles.py" = ["RUF012"] +"articles/views/collections.py" = ["RUF012"] +"bookmarks/admin.py" = ["RUF012"] +"bookmarks/migrations/0001_initial.py" = ["I001", "RUF012"] +"bookmarks/models.py" = ["RUF012"] +"bookmarks/serializers.py" = ["RUF012"] +"bookmarks/views.py" = ["RUF012"] +"comments/migrations/0001_initial.py" = ["I001", "RUF012"] +"comments/migrations/0002_initial.py" = ["I001", "RUF012"] +"comments/models.py" = ["RUF012"] +"comments/views.py" = ["RUF012"] +"core/migrations/0001_initial.py" = ["I001", "RUF012"] +"core/models.py" = ["RUF012"] +# Test-only DRF view declarations use mutable class metadata by design. +"core/tests/test_view_mixins.py" = ["RUF012"] +"notifications/migrations/0001_initial.py" = ["I001", "RUF012"] +"notifications/models.py" = ["RUF012"] +"notifications/views.py" = ["RUF012"] +"posts/migrations/0001_initial.py" = ["I001", "RUF012"] +"posts/migrations/0002_communitypost_mentions.py" = ["I001", "RUF012"] +"posts/models.py" = ["RUF012"] +"posts/views.py" = ["RUF012"] +"reactions/migrations/0001_initial.py" = ["I001", "RUF012"] +"reactions/models.py" = ["RUF012"] +"reactions/views.py" = ["RUF012"] +"reports/migrations/0001_initial.py" = ["I001", "RUF012"] +"reports/models.py" = ["RUF012"] +"reports/views.py" = ["RUF012"] +"tasks/admin.py" = ["RUF012"] +"tasks/migrations/0001_initial.py" = ["I001", "RUF012"] +"tasks/models.py" = ["RUF012"] +"users/admin.py" = ["RUF012"] +"users/migrations/0001_initial.py" = ["I001", "RUF012"] +"users/migrations/0002_usersubscription.py" = ["I001", "RUF012"] +"users/models/emails.py" = ["RUF012"] +"users/models/sessions.py" = ["RUF012"] +"users/models/subscriptions.py" = ["RUF012"] +"users/models/users.py" = ["RUF012"] +"users/serializers/subscriptions.py" = ["RUF012"] +"users/views/subscriptions.py" = ["RUF012"] +"users/views/users.py" = ["RUF012"] +# Preserve Django model bootstrap import order in this package initializer. +"users/models/__init__.py" = ["I001"] "backend/settings/dev.py" = ["F403", "F405"] "backend/settings/pro.py" = ["F403", "F405"] "backend/settings/stg.py" = ["F403", "F405"] diff --git a/apps/backend/tasks/management/commands/init_tasks.py b/apps/backend/tasks/management/commands/init_tasks.py index 94fbd27..5baff5d 100644 --- a/apps/backend/tasks/management/commands/init_tasks.py +++ b/apps/backend/tasks/management/commands/init_tasks.py @@ -1,9 +1,9 @@ from django.core.management.base import BaseCommand, CommandError +from logs.logging import get_logger from tasks.models import IntervalSchedule, PeriodicTask from tasks.periodic_tasks_registry import periodic_tasks from tasks.utils import compute_next_enqueue_at -from logs.logging import get_logger logger = get_logger(__name__) diff --git a/apps/backend/tasks/management/commands/runscheduler.py b/apps/backend/tasks/management/commands/runscheduler.py index eeacf02..6069fbe 100644 --- a/apps/backend/tasks/management/commands/runscheduler.py +++ b/apps/backend/tasks/management/commands/runscheduler.py @@ -1,10 +1,10 @@ -from django.core.management.base import BaseCommand - import time -from tasks.schedulers import enqueue_due_tasks -from tasks.models import PeriodicTask +from django.core.management.base import BaseCommand + from logs.logging.logger import get_logger +from tasks.models import PeriodicTask +from tasks.schedulers import enqueue_due_tasks logger = get_logger(__name__) diff --git a/apps/backend/tasks/schedulers.py b/apps/backend/tasks/schedulers.py index a16a79e..e843afe 100644 --- a/apps/backend/tasks/schedulers.py +++ b/apps/backend/tasks/schedulers.py @@ -1,13 +1,14 @@ +from dataclasses import dataclass + from django.core.cache import cache from django.core.exceptions import ImproperlyConfigured from django.db import transaction from django.utils import timezone from django.utils.module_loading import import_string -from dataclasses import dataclass - from core.utils.cache import get_key from logs.logging import get_logger + from .models import PeriodicTask from .utils import compute_next_enqueue_at diff --git a/apps/backend/tasks/tests/test_schedulers.py b/apps/backend/tasks/tests/test_schedulers.py index 540c483..e030fc9 100644 --- a/apps/backend/tasks/tests/test_schedulers.py +++ b/apps/backend/tasks/tests/test_schedulers.py @@ -1,9 +1,8 @@ +from datetime import timedelta from unittest.mock import Mock, patch from django.utils import timezone -from datetime import timedelta - from core.tests.testcases import BaseTestCase from tasks.models import IntervalSchedule, PeriodicTask from tasks.schedulers import SchedulerRunResult, dispatch_task, enqueue_due_tasks diff --git a/apps/backend/tasks/tests/test_utils.py b/apps/backend/tasks/tests/test_utils.py index 34cc277..7d559a7 100644 --- a/apps/backend/tasks/tests/test_utils.py +++ b/apps/backend/tasks/tests/test_utils.py @@ -1,9 +1,8 @@ +from datetime import timedelta from unittest.mock import patch from django.utils import timezone -from datetime import timedelta - from core.tests.testcases import BaseTestCase from tasks.utils import compute_next_enqueue_at diff --git a/apps/backend/tasks/utils.py b/apps/backend/tasks/utils.py index 8e1ac25..de4c8d2 100644 --- a/apps/backend/tasks/utils.py +++ b/apps/backend/tasks/utils.py @@ -1,7 +1,7 @@ -from django.utils import timezone - from datetime import datetime, timedelta +from django.utils import timezone + def compute_next_enqueue_at(interval_seconds: float) -> datetime: if interval_seconds <= 0: diff --git a/apps/backend/users/admin.py b/apps/backend/users/admin.py index e33d1f7..78261f3 100644 --- a/apps/backend/users/admin.py +++ b/apps/backend/users/admin.py @@ -1,12 +1,11 @@ -from django.contrib import admin from django.conf import settings +from django.contrib import admin from django.contrib.auth import get_user_model from django.contrib.auth.admin import UserAdmin from bookmarks.models import BookmarkFolder from users.models import UserSubscription - User = get_user_model() diff --git a/apps/backend/users/backends.py b/apps/backend/users/backends.py index 839b61c..1871dd6 100644 --- a/apps/backend/users/backends.py +++ b/apps/backend/users/backends.py @@ -1,5 +1,5 @@ -from django.contrib.auth.backends import BaseBackend from django.contrib.auth import get_user_model +from django.contrib.auth.backends import BaseBackend from .models import EmailAddress from .utils import normalize_email diff --git a/apps/backend/users/middleware.py b/apps/backend/users/middleware.py index 15a4e30..9d29f37 100644 --- a/apps/backend/users/middleware.py +++ b/apps/backend/users/middleware.py @@ -1,15 +1,16 @@ +from datetime import datetime, timedelta + from django.conf import settings from django.utils import timezone -from datetime import datetime, timedelta - from logs.logging import get_logger + from .services.sessions import update_last_accessed_at logger = get_logger(__name__) -class SessionTrackingMiddleware(): +class SessionTrackingMiddleware: def __init__(self, get_response): self.get_response = get_response diff --git a/apps/backend/users/models/__init__.py b/apps/backend/users/models/__init__.py index 0897553..f531555 100644 --- a/apps/backend/users/models/__init__.py +++ b/apps/backend/users/models/__init__.py @@ -4,10 +4,10 @@ from .subscriptions import UserSubscription as UserSubscription __all__ = [ - "User", "AvatarStorage", - "ProfileManager", "EmailAddress", + "ProfileManager", + "User", "UserSession", "UserSubscription", ] diff --git a/apps/backend/users/models/emails.py b/apps/backend/users/models/emails.py index 2f3f88f..ba3ae25 100644 --- a/apps/backend/users/models/emails.py +++ b/apps/backend/users/models/emails.py @@ -1,5 +1,5 @@ -from django.db import models from django.contrib.auth import get_user_model +from django.db import models from django.utils.translation import gettext_lazy as _ from core.model_mixins import CreatedAtMixin, UUIDPrimaryKeyMixin diff --git a/apps/backend/users/models/sessions.py b/apps/backend/users/models/sessions.py index c57abf2..b64f497 100644 --- a/apps/backend/users/models/sessions.py +++ b/apps/backend/users/models/sessions.py @@ -1,8 +1,8 @@ -from django.db import models from django.contrib.auth import get_user_model +from django.db import models from django.utils.translation import gettext_lazy as _ -from core.model_mixins import UUIDPrimaryKeyMixin, CreatedAtMixin +from core.model_mixins import CreatedAtMixin, UUIDPrimaryKeyMixin User = get_user_model() diff --git a/apps/backend/users/models/users.py b/apps/backend/users/models/users.py index 68c5ef9..d9760fe 100644 --- a/apps/backend/users/models/users.py +++ b/apps/backend/users/models/users.py @@ -1,15 +1,14 @@ -from django.db import models -from django.contrib.auth.models import AbstractUser -from django.contrib.auth.models import BaseUserManager -from django.core.files.storage import FileSystemStorage -from django.utils.encoding import filepath_to_uri -from django.conf import settings -from django.utils.translation import gettext_lazy as _ - import uuid from pathlib import Path from urllib.parse import urljoin +from django.conf import settings +from django.contrib.auth.models import AbstractUser, BaseUserManager +from django.core.files.storage import FileSystemStorage +from django.db import models +from django.utils.encoding import filepath_to_uri +from django.utils.translation import gettext_lazy as _ + from core.model_mixins import UUIDPrimaryKeyMixin diff --git a/apps/backend/users/serializers/__init__.py b/apps/backend/users/serializers/__init__.py index 6756214..818eb12 100644 --- a/apps/backend/users/serializers/__init__.py +++ b/apps/backend/users/serializers/__init__.py @@ -1,6 +1,9 @@ from .emails import EmailVerifyRequestSerializer, EmailVerifyResponseSerializer from .sessions import UserLoginSerializer -from .subscriptions import UserSubscriptionReadSerializer, UserSubscriptionWriteSerializer +from .subscriptions import ( + UserSubscriptionReadSerializer, + UserSubscriptionWriteSerializer, +) from .users import ( UserListSerializer, UserRegisterRequestSerializer, diff --git a/apps/backend/users/serializers/emails.py b/apps/backend/users/serializers/emails.py index f5b991e..e84e14b 100644 --- a/apps/backend/users/serializers/emails.py +++ b/apps/backend/users/serializers/emails.py @@ -1,5 +1,4 @@ from django.core.validators import RegexValidator - from rest_framework import serializers from ..utils import normalize_email diff --git a/apps/backend/users/serializers/users.py b/apps/backend/users/serializers/users.py index 4d304df..cc2a9c1 100644 --- a/apps/backend/users/serializers/users.py +++ b/apps/backend/users/serializers/users.py @@ -1,20 +1,20 @@ +import io + from django.contrib.auth import get_user_model from django.core.files.base import ContentFile - +from PIL import Image from rest_framework import serializers from rest_framework.validators import UniqueValidator -import io -from PIL import Image from core.validators import ( FileSizeValidator, FileTypeValidator, PasswordValidator, ) + from ..models import EmailAddress from ..utils import normalize_email - User = get_user_model() @@ -162,11 +162,11 @@ class Meta: def update(self, instance, validated_data): username = validated_data.get('username', None) if username is not None: - setattr(instance, 'username', username) + instance.username = username signature = validated_data.get('signature', None) if signature is not None: - setattr(instance, 'signature', signature) + instance.signature = signature avatar = validated_data.get('avatar', None) if avatar is not None: diff --git a/apps/backend/users/services/sessions.py b/apps/backend/users/services/sessions.py index 8ecf4b1..503b55a 100644 --- a/apps/backend/users/services/sessions.py +++ b/apps/backend/users/services/sessions.py @@ -1,10 +1,10 @@ -from django.utils import timezone +import user_agents from django.contrib.auth import get_user_model +from django.utils import timezone -import user_agents +from logs.logging import get_logger from ..models import UserSession -from logs.logging import get_logger logger = get_logger(__name__) User = get_user_model() diff --git a/apps/backend/users/services/users.py b/apps/backend/users/services/users.py index 1c6af1c..10dac13 100644 --- a/apps/backend/users/services/users.py +++ b/apps/backend/users/services/users.py @@ -1,17 +1,17 @@ -from django.contrib.auth import get_user_model -from django.conf import settings -from django.db import transaction - -import secrets -import random import hashlib +import random +import secrets +from django.conf import settings +from django.contrib.auth import get_user_model +from django.db import transaction from drf_std_response import ServiceError -from core.utils.cache import add_cache, set_cache, get_cache, delete_cache, incr_cache + from bookmarks.models import BookmarkFolder +from core.utils.cache import add_cache, delete_cache, get_cache, incr_cache, set_cache +from logs.logging import get_logger from users.models import EmailAddress from users.tasks import send_verification_email_task -from logs.logging import get_logger logger = get_logger(__name__) User = get_user_model() diff --git a/apps/backend/users/tasks.py b/apps/backend/users/tasks.py index 1257402..2eadc00 100644 --- a/apps/backend/users/tasks.py +++ b/apps/backend/users/tasks.py @@ -1,7 +1,7 @@ from django.conf import settings from django.core.mail import send_mail -from django.tasks import task from django.core.management import call_command +from django.tasks import task from logs.logging import get_logger diff --git a/apps/backend/users/tests/test_models.py b/apps/backend/users/tests/test_models.py index 43dbed1..3ff2626 100644 --- a/apps/backend/users/tests/test_models.py +++ b/apps/backend/users/tests/test_models.py @@ -89,13 +89,11 @@ def test_user_subscription_rejects_duplicates(self): author = create_user(username="author") UserSubscription.objects.create(subscriber=subscriber, subscribed_to=author) - with self.assertRaises(IntegrityError): - with transaction.atomic(): - UserSubscription.objects.create(subscriber=subscriber, subscribed_to=author) + with self.assertRaises(IntegrityError), transaction.atomic(): + UserSubscription.objects.create(subscriber=subscriber, subscribed_to=author) def test_user_subscription_rejects_self_subscription(self): user = create_user(username="reader") - with self.assertRaises(IntegrityError): - with transaction.atomic(): - UserSubscription.objects.create(subscriber=user, subscribed_to=user) + with self.assertRaises(IntegrityError), transaction.atomic(): + UserSubscription.objects.create(subscriber=user, subscribed_to=user) diff --git a/apps/backend/users/tests/test_services.py b/apps/backend/users/tests/test_services.py index b05ac4b..814ff63 100644 --- a/apps/backend/users/tests/test_services.py +++ b/apps/backend/users/tests/test_services.py @@ -1,9 +1,9 @@ from unittest.mock import patch from django.conf import settings +from drf_std_response import ServiceError from bookmarks.models import BookmarkFolder -from drf_std_response import ServiceError from core.tests.factories import create_user from core.tests.testcases import BaseTestCase from core.utils.cache import get_cache, set_cache diff --git a/apps/backend/users/tests/test_views.py b/apps/backend/users/tests/test_views.py index 1f4826b..41541e6 100644 --- a/apps/backend/users/tests/test_views.py +++ b/apps/backend/users/tests/test_views.py @@ -2,7 +2,6 @@ from django.conf import settings from django.urls import reverse - from rest_framework import status from bookmarks.models import BookmarkFolder diff --git a/apps/backend/users/urls.py b/apps/backend/users/urls.py index bbc0775..e6c64fc 100644 --- a/apps/backend/users/urls.py +++ b/apps/backend/users/urls.py @@ -2,7 +2,6 @@ from .views import EmailViewSet, SessionViewSet, UserSubscriptionViewSet, UserViewSet - router = DefaultRouter() router.register(r'profiles', UserViewSet, basename='profile') router.register(r'sessions', SessionViewSet, basename='session') diff --git a/apps/backend/users/views/emails.py b/apps/backend/users/views/emails.py index d7fb102..3f95599 100644 --- a/apps/backend/users/views/emails.py +++ b/apps/backend/users/views/emails.py @@ -1,8 +1,8 @@ +from drf_std_response import EnvelopeMixin from rest_framework import status, viewsets from rest_framework.decorators import action from rest_framework.permissions import IsAuthenticated -from drf_std_response import EnvelopeMixin from ..serializers import EmailVerifyRequestSerializer, EmailVerifyResponseSerializer from ..services.users import verify_email diff --git a/apps/backend/users/views/sessions.py b/apps/backend/users/views/sessions.py index 5412529..e10e549 100644 --- a/apps/backend/users/views/sessions.py +++ b/apps/backend/users/views/sessions.py @@ -1,13 +1,12 @@ from django.conf import settings from django.contrib.auth import authenticate, login, logout from django.utils import timezone - +from drf_std_response import EnvelopeMixin from rest_framework import status, viewsets from rest_framework.decorators import action from rest_framework.exceptions import AuthenticationFailed from rest_framework.permissions import AllowAny, IsAuthenticated -from drf_std_response import EnvelopeMixin from ..serializers import UserLoginSerializer from ..services.sessions import create_user_session, delete_user_session diff --git a/apps/backend/users/views/subscriptions.py b/apps/backend/users/views/subscriptions.py index 35a0f0c..8b4403c 100644 --- a/apps/backend/users/views/subscriptions.py +++ b/apps/backend/users/views/subscriptions.py @@ -1,10 +1,13 @@ +from drf_std_response import EnvelopeMixin from rest_framework import status from rest_framework.permissions import IsAuthenticated from rest_framework.viewsets import ModelViewSet -from drf_std_response import EnvelopeMixin from ..models import UserSubscription -from ..serializers import UserSubscriptionReadSerializer, UserSubscriptionWriteSerializer +from ..serializers import ( + UserSubscriptionReadSerializer, + UserSubscriptionWriteSerializer, +) class UserSubscriptionViewSet(EnvelopeMixin, ModelViewSet): diff --git a/apps/backend/users/views/users.py b/apps/backend/users/views/users.py index 7a4f268..23d6a81 100644 --- a/apps/backend/users/views/users.py +++ b/apps/backend/users/views/users.py @@ -1,12 +1,11 @@ from django.contrib.auth import get_user_model - +from drf_std_response import EnvelopeMixin from rest_framework import status, viewsets from rest_framework.decorators import action +from rest_framework.mixins import ListModelMixin, RetrieveModelMixin from rest_framework.parsers import FormParser, JSONParser, MultiPartParser from rest_framework.permissions import AllowAny, IsAuthenticated -from rest_framework.mixins import ListModelMixin, RetrieveModelMixin -from drf_std_response import EnvelopeMixin from ..serializers import ( UserListSerializer, UserRegisterRequestSerializer, @@ -16,7 +15,6 @@ ) from ..services.users import register - User = get_user_model()