diff --git a/accounts/urls.py b/accounts/urls.py index bb2001b..4b6b9f6 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -1,12 +1,17 @@ from __future__ import annotations +from typing import TYPE_CHECKING + from django.urls import path from accounts import views +if TYPE_CHECKING: + from django.urls.resolvers import URLPattern + app_name = "accounts" -urlpatterns = [ +urlpatterns: list[URLPattern] = [ path("login/", views.CustomLoginView.as_view(), name="login"), path("logout/", views.CustomLogoutView.as_view(), name="logout"), path("signup/", views.SignUpView.as_view(), name="signup"), diff --git a/accounts/views.py b/accounts/views.py index 618dbc7..94ab94d 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -30,13 +30,13 @@ class CustomLoginView(LoginView): Returns: str: URL to redirect to after successful login. """ - return reverse_lazy("twitch:dashboard") + return reverse_lazy("twitch:dashboard") # pyright: ignore[reportReturnType] class CustomLogoutView(LogoutView): """Custom logout view.""" - next_page = reverse_lazy("twitch:dashboard") + next_page = reverse_lazy("twitch:dashboard") # pyright: ignore[reportAssignmentType] http_method_names = ["get", "post", "options"] def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse: diff --git a/twitch/admin.py b/twitch/admin.py index 2cdca24..7e3c719 100644 --- a/twitch/admin.py +++ b/twitch/admin.py @@ -5,6 +5,7 @@ from django.contrib import admin from twitch.models import DropBenefit, DropBenefitEdge, DropCampaign, Game, Organization, TimeBasedDrop +# MARK: Game @admin.register(Game) class GameAdmin(admin.ModelAdmin): """Admin configuration for Game model.""" @@ -14,6 +15,7 @@ class GameAdmin(admin.ModelAdmin): readonly_fields = ("added_at", "updated_at") +# MARK: Organization @admin.register(Organization) class OrganizationAdmin(admin.ModelAdmin): """Admin configuration for Organization model.""" @@ -30,6 +32,7 @@ class TimeBasedDropInline(admin.TabularInline): extra = 0 +# MARK: DropCampaign @admin.register(DropCampaign) class DropCampaignAdmin(admin.ModelAdmin): """Admin configuration for DropCampaign model.""" @@ -48,6 +51,7 @@ class DropBenefitEdgeInline(admin.TabularInline): extra = 0 +# MARK: TimeBasedDrop @admin.register(TimeBasedDrop) class TimeBasedDropAdmin(admin.ModelAdmin): """Admin configuration for TimeBasedDrop model.""" @@ -68,6 +72,7 @@ class TimeBasedDropAdmin(admin.ModelAdmin): inlines = [DropBenefitEdgeInline] +# MARK: DropBenefit @admin.register(DropBenefit) class DropBenefitAdmin(admin.ModelAdmin): """Admin configuration for DropBenefit model.""" diff --git a/twitch/feeds.py b/twitch/feeds.py index 9f4f183..c11f36a 100644 --- a/twitch/feeds.py +++ b/twitch/feeds.py @@ -12,6 +12,7 @@ if TYPE_CHECKING: import datetime +# MARK: /rss/organizations/ class OrganizationFeed(Feed): """RSS feed for latest organizations.""" @@ -36,6 +37,7 @@ class OrganizationFeed(Feed): return reverse("twitch:organization_detail", args=[item.pk]) +# MARK: /rss/games/ class GameFeed(Feed): """RSS feed for latest games.""" @@ -60,6 +62,7 @@ class GameFeed(Feed): return reverse("twitch:game_detail", args=[item.pk]) +# MARK: /rss/campaigns/ class DropCampaignFeed(Feed): """RSS feed for latest drop campaigns.""" diff --git a/twitch/models.py b/twitch/models.py index caeee43..1ea9329 100644 --- a/twitch/models.py +++ b/twitch/models.py @@ -19,6 +19,7 @@ if TYPE_CHECKING: logger: logging.Logger = logging.getLogger("ttvdrops") +# MARK: Organization class Organization(auto_prefetch.Model): """Represents an organization on Twitch that can own drop campaigns.""" @@ -63,6 +64,7 @@ class Organization(auto_prefetch.Model): return self.name or self.id +# MARK: Game class Game(auto_prefetch.Model): """Represents a game on Twitch.""" @@ -204,6 +206,7 @@ class Game(auto_prefetch.Model): return "" +# MARK: Channel class Channel(auto_prefetch.Model): """Represents a Twitch channel that can participate in drop campaigns.""" @@ -248,6 +251,7 @@ class Channel(auto_prefetch.Model): return self.display_name or self.name or self.id +# MARK: DropCampaign class DropCampaign(auto_prefetch.Model): """Represents a Twitch drop campaign.""" @@ -409,6 +413,7 @@ class DropCampaign(auto_prefetch.Model): return self.image_url or "" +# MARK: DropBenefit class DropBenefit(auto_prefetch.Model): """Represents a benefit that can be earned from a drop.""" @@ -501,6 +506,7 @@ class DropBenefit(auto_prefetch.Model): return self.image_asset_url or "" +# MARK: TimeBasedDrop class TimeBasedDrop(auto_prefetch.Model): """Represents a time-based drop in a drop campaign.""" @@ -593,6 +599,7 @@ class TimeBasedDrop(auto_prefetch.Model): return self.name +# MARK: DropBenefitEdge class DropBenefitEdge(auto_prefetch.Model): """Represents the relationship between a TimeBasedDrop and a DropBenefit.""" @@ -634,6 +641,7 @@ class DropBenefitEdge(auto_prefetch.Model): return f"{self.drop.name} - {self.benefit.name}" +# MARK: NotificationSubscription class NotificationSubscription(auto_prefetch.Model): """Users can subscribe to games to get notified.""" diff --git a/twitch/urls.py b/twitch/urls.py index 3c65f56..ff88a9d 100644 --- a/twitch/urls.py +++ b/twitch/urls.py @@ -1,5 +1,7 @@ from __future__ import annotations +from typing import TYPE_CHECKING + from django.urls import path from twitch import views @@ -9,9 +11,12 @@ from twitch.feeds import ( OrganizationFeed, ) +if TYPE_CHECKING: + from django.urls.resolvers import URLPattern + app_name = "twitch" -urlpatterns = [ +urlpatterns: list[URLPattern] = [ path("", views.dashboard, name="dashboard"), path("search/", views.search_view, name="search"), path("debug/", views.debug_view, name="debug"), diff --git a/twitch/views.py b/twitch/views.py index abadb83..12b831b 100644 --- a/twitch/views.py +++ b/twitch/views.py @@ -35,6 +35,7 @@ MIN_QUERY_LENGTH_FOR_FTS = 3 MIN_SEARCH_RANK = 0.05 +# MARK: /search/ def search_view(request: HttpRequest) -> HttpResponse: """Search view for all models. @@ -95,6 +96,7 @@ def search_view(request: HttpRequest) -> HttpResponse: return render(request, "twitch/search_results.html", {"query": query, "results": results}) +# MARK: /organizations/ class OrgListView(ListView): """List view for organization.""" @@ -103,6 +105,7 @@ class OrgListView(ListView): context_object_name = "orgs" +# MARK: /organizations// class OrgDetailView(DetailView): """Detail view for organization.""" @@ -157,6 +160,7 @@ class OrgDetailView(DetailView): return context +# MARK: /campaigns/ class DropCampaignListView(ListView): """List view for drop campaigns.""" @@ -213,6 +217,7 @@ def format_and_color_json(code: str) -> str: return highlight(formatted_code, JsonLexer(), HtmlFormatter()) +# MARK: /campaigns// class DropCampaignDetailView(DetailView): """Detail view for a drop campaign.""" @@ -342,6 +347,7 @@ class DropCampaignDetailView(DetailView): return context +# MARK: /games/ class GamesGridView(ListView): """List view for games grouped by organization.""" @@ -412,6 +418,7 @@ class GamesGridView(ListView): return context +# MARK: /games// class GameDetailView(DetailView): """Detail view for a game.""" @@ -574,6 +581,7 @@ def dashboard(request: HttpRequest) -> HttpResponse: ) +# MARK: /debug/ @login_required def debug_view(request: HttpRequest) -> HttpResponse: """Debug view showing potentially broken or inconsistent data. @@ -635,6 +643,7 @@ def debug_view(request: HttpRequest) -> HttpResponse: return render(request, "twitch/debug.html", context) +# MARK: /games//subscribe/ @login_required def subscribe_game_notifications(request: HttpRequest, game_id: str) -> HttpResponseRedirect: """Update Game notification for a user. @@ -678,6 +687,7 @@ def subscribe_game_notifications(request: HttpRequest, game_id: str) -> HttpResp return redirect("twitch:game_detail", pk=game.id) +# MARK: /organizations//subscribe/ @login_required def subscribe_org_notifications(request: HttpRequest, org_id: str) -> HttpResponseRedirect: """Update Organization notification for a user. @@ -722,12 +732,14 @@ def subscribe_org_notifications(request: HttpRequest, org_id: str) -> HttpRespon return redirect("twitch:organization_detail", pk=organization.id) +# MARK: /games/list/ class GamesListView(GamesGridView): """List view for games in simple list format.""" template_name = "twitch/games_list.html" +# MARK: /docs/rss/ def docs_rss_view(request: HttpRequest) -> HttpResponse: """View for /docs/rss that lists all available RSS feeds. @@ -757,6 +769,7 @@ def docs_rss_view(request: HttpRequest) -> HttpResponse: return render(request, "twitch/docs_rss.html", {"feeds": feeds}) +# MARK: /channels/ class ChannelListView(ListView): """List view for channels.""" @@ -793,6 +806,7 @@ class ChannelListView(ListView): return context +# MARK: /channels// class ChannelDetailView(DetailView): """Detail view for a channel."""