Add section markers
This commit is contained in:
parent
b97118cffd
commit
007b8f7ec6
7 changed files with 44 additions and 4 deletions
|
|
@ -1,12 +1,17 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from accounts import views
|
from accounts import views
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from django.urls.resolvers import URLPattern
|
||||||
|
|
||||||
app_name = "accounts"
|
app_name = "accounts"
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns: list[URLPattern] = [
|
||||||
path("login/", views.CustomLoginView.as_view(), name="login"),
|
path("login/", views.CustomLoginView.as_view(), name="login"),
|
||||||
path("logout/", views.CustomLogoutView.as_view(), name="logout"),
|
path("logout/", views.CustomLogoutView.as_view(), name="logout"),
|
||||||
path("signup/", views.SignUpView.as_view(), name="signup"),
|
path("signup/", views.SignUpView.as_view(), name="signup"),
|
||||||
|
|
|
||||||
|
|
@ -30,13 +30,13 @@ class CustomLoginView(LoginView):
|
||||||
Returns:
|
Returns:
|
||||||
str: URL to redirect to after successful login.
|
str: URL to redirect to after successful login.
|
||||||
"""
|
"""
|
||||||
return reverse_lazy("twitch:dashboard")
|
return reverse_lazy("twitch:dashboard") # pyright: ignore[reportReturnType]
|
||||||
|
|
||||||
|
|
||||||
class CustomLogoutView(LogoutView):
|
class CustomLogoutView(LogoutView):
|
||||||
"""Custom logout view."""
|
"""Custom logout view."""
|
||||||
|
|
||||||
next_page = reverse_lazy("twitch:dashboard")
|
next_page = reverse_lazy("twitch:dashboard") # pyright: ignore[reportAssignmentType]
|
||||||
http_method_names = ["get", "post", "options"]
|
http_method_names = ["get", "post", "options"]
|
||||||
|
|
||||||
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ from django.contrib import admin
|
||||||
from twitch.models import DropBenefit, DropBenefitEdge, DropCampaign, Game, Organization, TimeBasedDrop
|
from twitch.models import DropBenefit, DropBenefitEdge, DropCampaign, Game, Organization, TimeBasedDrop
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: Game
|
||||||
@admin.register(Game)
|
@admin.register(Game)
|
||||||
class GameAdmin(admin.ModelAdmin):
|
class GameAdmin(admin.ModelAdmin):
|
||||||
"""Admin configuration for Game model."""
|
"""Admin configuration for Game model."""
|
||||||
|
|
@ -14,6 +15,7 @@ class GameAdmin(admin.ModelAdmin):
|
||||||
readonly_fields = ("added_at", "updated_at")
|
readonly_fields = ("added_at", "updated_at")
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: Organization
|
||||||
@admin.register(Organization)
|
@admin.register(Organization)
|
||||||
class OrganizationAdmin(admin.ModelAdmin):
|
class OrganizationAdmin(admin.ModelAdmin):
|
||||||
"""Admin configuration for Organization model."""
|
"""Admin configuration for Organization model."""
|
||||||
|
|
@ -30,6 +32,7 @@ class TimeBasedDropInline(admin.TabularInline):
|
||||||
extra = 0
|
extra = 0
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: DropCampaign
|
||||||
@admin.register(DropCampaign)
|
@admin.register(DropCampaign)
|
||||||
class DropCampaignAdmin(admin.ModelAdmin):
|
class DropCampaignAdmin(admin.ModelAdmin):
|
||||||
"""Admin configuration for DropCampaign model."""
|
"""Admin configuration for DropCampaign model."""
|
||||||
|
|
@ -48,6 +51,7 @@ class DropBenefitEdgeInline(admin.TabularInline):
|
||||||
extra = 0
|
extra = 0
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: TimeBasedDrop
|
||||||
@admin.register(TimeBasedDrop)
|
@admin.register(TimeBasedDrop)
|
||||||
class TimeBasedDropAdmin(admin.ModelAdmin):
|
class TimeBasedDropAdmin(admin.ModelAdmin):
|
||||||
"""Admin configuration for TimeBasedDrop model."""
|
"""Admin configuration for TimeBasedDrop model."""
|
||||||
|
|
@ -68,6 +72,7 @@ class TimeBasedDropAdmin(admin.ModelAdmin):
|
||||||
inlines = [DropBenefitEdgeInline]
|
inlines = [DropBenefitEdgeInline]
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: DropBenefit
|
||||||
@admin.register(DropBenefit)
|
@admin.register(DropBenefit)
|
||||||
class DropBenefitAdmin(admin.ModelAdmin):
|
class DropBenefitAdmin(admin.ModelAdmin):
|
||||||
"""Admin configuration for DropBenefit model."""
|
"""Admin configuration for DropBenefit model."""
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ if TYPE_CHECKING:
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: /rss/organizations/
|
||||||
class OrganizationFeed(Feed):
|
class OrganizationFeed(Feed):
|
||||||
"""RSS feed for latest organizations."""
|
"""RSS feed for latest organizations."""
|
||||||
|
|
||||||
|
|
@ -36,6 +37,7 @@ class OrganizationFeed(Feed):
|
||||||
return reverse("twitch:organization_detail", args=[item.pk])
|
return reverse("twitch:organization_detail", args=[item.pk])
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: /rss/games/
|
||||||
class GameFeed(Feed):
|
class GameFeed(Feed):
|
||||||
"""RSS feed for latest games."""
|
"""RSS feed for latest games."""
|
||||||
|
|
||||||
|
|
@ -60,6 +62,7 @@ class GameFeed(Feed):
|
||||||
return reverse("twitch:game_detail", args=[item.pk])
|
return reverse("twitch:game_detail", args=[item.pk])
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: /rss/campaigns/
|
||||||
class DropCampaignFeed(Feed):
|
class DropCampaignFeed(Feed):
|
||||||
"""RSS feed for latest drop campaigns."""
|
"""RSS feed for latest drop campaigns."""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ if TYPE_CHECKING:
|
||||||
logger: logging.Logger = logging.getLogger("ttvdrops")
|
logger: logging.Logger = logging.getLogger("ttvdrops")
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: Organization
|
||||||
class Organization(auto_prefetch.Model):
|
class Organization(auto_prefetch.Model):
|
||||||
"""Represents an organization on Twitch that can own drop campaigns."""
|
"""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
|
return self.name or self.id
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: Game
|
||||||
class Game(auto_prefetch.Model):
|
class Game(auto_prefetch.Model):
|
||||||
"""Represents a game on Twitch."""
|
"""Represents a game on Twitch."""
|
||||||
|
|
||||||
|
|
@ -204,6 +206,7 @@ class Game(auto_prefetch.Model):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: Channel
|
||||||
class Channel(auto_prefetch.Model):
|
class Channel(auto_prefetch.Model):
|
||||||
"""Represents a Twitch channel that can participate in drop campaigns."""
|
"""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
|
return self.display_name or self.name or self.id
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: DropCampaign
|
||||||
class DropCampaign(auto_prefetch.Model):
|
class DropCampaign(auto_prefetch.Model):
|
||||||
"""Represents a Twitch drop campaign."""
|
"""Represents a Twitch drop campaign."""
|
||||||
|
|
||||||
|
|
@ -409,6 +413,7 @@ class DropCampaign(auto_prefetch.Model):
|
||||||
return self.image_url or ""
|
return self.image_url or ""
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: DropBenefit
|
||||||
class DropBenefit(auto_prefetch.Model):
|
class DropBenefit(auto_prefetch.Model):
|
||||||
"""Represents a benefit that can be earned from a drop."""
|
"""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 ""
|
return self.image_asset_url or ""
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: TimeBasedDrop
|
||||||
class TimeBasedDrop(auto_prefetch.Model):
|
class TimeBasedDrop(auto_prefetch.Model):
|
||||||
"""Represents a time-based drop in a drop campaign."""
|
"""Represents a time-based drop in a drop campaign."""
|
||||||
|
|
||||||
|
|
@ -593,6 +599,7 @@ class TimeBasedDrop(auto_prefetch.Model):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: DropBenefitEdge
|
||||||
class DropBenefitEdge(auto_prefetch.Model):
|
class DropBenefitEdge(auto_prefetch.Model):
|
||||||
"""Represents the relationship between a TimeBasedDrop and a DropBenefit."""
|
"""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}"
|
return f"{self.drop.name} - {self.benefit.name}"
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: NotificationSubscription
|
||||||
class NotificationSubscription(auto_prefetch.Model):
|
class NotificationSubscription(auto_prefetch.Model):
|
||||||
"""Users can subscribe to games to get notified."""
|
"""Users can subscribe to games to get notified."""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from twitch import views
|
from twitch import views
|
||||||
|
|
@ -9,9 +11,12 @@ from twitch.feeds import (
|
||||||
OrganizationFeed,
|
OrganizationFeed,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from django.urls.resolvers import URLPattern
|
||||||
|
|
||||||
app_name = "twitch"
|
app_name = "twitch"
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns: list[URLPattern] = [
|
||||||
path("", views.dashboard, name="dashboard"),
|
path("", views.dashboard, name="dashboard"),
|
||||||
path("search/", views.search_view, name="search"),
|
path("search/", views.search_view, name="search"),
|
||||||
path("debug/", views.debug_view, name="debug"),
|
path("debug/", views.debug_view, name="debug"),
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ MIN_QUERY_LENGTH_FOR_FTS = 3
|
||||||
MIN_SEARCH_RANK = 0.05
|
MIN_SEARCH_RANK = 0.05
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: /search/
|
||||||
def search_view(request: HttpRequest) -> HttpResponse:
|
def search_view(request: HttpRequest) -> HttpResponse:
|
||||||
"""Search view for all models.
|
"""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})
|
return render(request, "twitch/search_results.html", {"query": query, "results": results})
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: /organizations/
|
||||||
class OrgListView(ListView):
|
class OrgListView(ListView):
|
||||||
"""List view for organization."""
|
"""List view for organization."""
|
||||||
|
|
||||||
|
|
@ -103,6 +105,7 @@ class OrgListView(ListView):
|
||||||
context_object_name = "orgs"
|
context_object_name = "orgs"
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: /organizations/<pk>/
|
||||||
class OrgDetailView(DetailView):
|
class OrgDetailView(DetailView):
|
||||||
"""Detail view for organization."""
|
"""Detail view for organization."""
|
||||||
|
|
||||||
|
|
@ -157,6 +160,7 @@ class OrgDetailView(DetailView):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: /campaigns/
|
||||||
class DropCampaignListView(ListView):
|
class DropCampaignListView(ListView):
|
||||||
"""List view for drop campaigns."""
|
"""List view for drop campaigns."""
|
||||||
|
|
||||||
|
|
@ -213,6 +217,7 @@ def format_and_color_json(code: str) -> str:
|
||||||
return highlight(formatted_code, JsonLexer(), HtmlFormatter())
|
return highlight(formatted_code, JsonLexer(), HtmlFormatter())
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: /campaigns/<pk>/
|
||||||
class DropCampaignDetailView(DetailView):
|
class DropCampaignDetailView(DetailView):
|
||||||
"""Detail view for a drop campaign."""
|
"""Detail view for a drop campaign."""
|
||||||
|
|
||||||
|
|
@ -342,6 +347,7 @@ class DropCampaignDetailView(DetailView):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: /games/
|
||||||
class GamesGridView(ListView):
|
class GamesGridView(ListView):
|
||||||
"""List view for games grouped by organization."""
|
"""List view for games grouped by organization."""
|
||||||
|
|
||||||
|
|
@ -412,6 +418,7 @@ class GamesGridView(ListView):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: /games/<pk>/
|
||||||
class GameDetailView(DetailView):
|
class GameDetailView(DetailView):
|
||||||
"""Detail view for a game."""
|
"""Detail view for a game."""
|
||||||
|
|
||||||
|
|
@ -574,6 +581,7 @@ def dashboard(request: HttpRequest) -> HttpResponse:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: /debug/
|
||||||
@login_required
|
@login_required
|
||||||
def debug_view(request: HttpRequest) -> HttpResponse:
|
def debug_view(request: HttpRequest) -> HttpResponse:
|
||||||
"""Debug view showing potentially broken or inconsistent data.
|
"""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)
|
return render(request, "twitch/debug.html", context)
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: /games/<pk>/subscribe/
|
||||||
@login_required
|
@login_required
|
||||||
def subscribe_game_notifications(request: HttpRequest, game_id: str) -> HttpResponseRedirect:
|
def subscribe_game_notifications(request: HttpRequest, game_id: str) -> HttpResponseRedirect:
|
||||||
"""Update Game notification for a user.
|
"""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)
|
return redirect("twitch:game_detail", pk=game.id)
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: /organizations/<pk>/subscribe/
|
||||||
@login_required
|
@login_required
|
||||||
def subscribe_org_notifications(request: HttpRequest, org_id: str) -> HttpResponseRedirect:
|
def subscribe_org_notifications(request: HttpRequest, org_id: str) -> HttpResponseRedirect:
|
||||||
"""Update Organization notification for a user.
|
"""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)
|
return redirect("twitch:organization_detail", pk=organization.id)
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: /games/list/
|
||||||
class GamesListView(GamesGridView):
|
class GamesListView(GamesGridView):
|
||||||
"""List view for games in simple list format."""
|
"""List view for games in simple list format."""
|
||||||
|
|
||||||
template_name = "twitch/games_list.html"
|
template_name = "twitch/games_list.html"
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: /docs/rss/
|
||||||
def docs_rss_view(request: HttpRequest) -> HttpResponse:
|
def docs_rss_view(request: HttpRequest) -> HttpResponse:
|
||||||
"""View for /docs/rss that lists all available RSS feeds.
|
"""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})
|
return render(request, "twitch/docs_rss.html", {"feeds": feeds})
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: /channels/
|
||||||
class ChannelListView(ListView):
|
class ChannelListView(ListView):
|
||||||
"""List view for channels."""
|
"""List view for channels."""
|
||||||
|
|
||||||
|
|
@ -793,6 +806,7 @@ class ChannelListView(ListView):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
# MARK: /channels/<pk>/
|
||||||
class ChannelDetailView(DetailView):
|
class ChannelDetailView(DetailView):
|
||||||
"""Detail view for a channel."""
|
"""Detail view for a channel."""
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue