Move profile and settings into the new unified dashboard, showing user info in one place

This commit is contained in:
badblocks 2025-03-31 22:20:59 -07:00
parent 2d826734a0
commit 7edefe23c3
37 changed files with 726 additions and 500 deletions

View file

@ -1,4 +1,4 @@
# Generated by Django 5.1.2 on 2025-03-29 21:23
# Generated by Django 5.1.2 on 2025-03-31 22:48
import accounts.models
import django.contrib.auth.models
@ -33,6 +33,7 @@ class Migration(migrations.Migration):
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
('show_friend_code_on_link_previews', models.BooleanField(default=False, help_text='This will primarily affect share link previews on X, Discord, etc.', verbose_name='Show Friend Code on Link Previews')),
('reputation_score', models.PositiveIntegerField(default=0)),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
],

View file

@ -17,6 +17,7 @@ class CustomUser(AbstractUser):
verbose_name="Show Friend Code on Link Previews",
help_text="This will primarily affect share link previews on X, Discord, etc."
)
reputation_score = models.PositiveIntegerField(default=0)
def __str__(self):
return self.email

View file

@ -5,8 +5,7 @@ from .views import (
DeleteFriendCodeView,
ChangeDefaultFriendCodeView,
EditFriendCodeView,
SettingsView,
ProfileView,
DashboardView,
)
urlpatterns = [
@ -16,6 +15,5 @@ urlpatterns = [
path("friend-codes/edit/<int:pk>/", EditFriendCodeView.as_view(), name="edit_friend_code"),
path("friend-codes/delete/<int:pk>/", DeleteFriendCodeView.as_view(), name="delete_friend_code"),
path("friend-codes/default/<int:pk>/", ChangeDefaultFriendCodeView.as_view(), name="change_default_friend_code"),
path("settings/", SettingsView.as_view(), name="settings"),
path("profile/", ProfileView.as_view(), name="profile"),
path("dashboard/", DashboardView.as_view(), name="dashboard"),
]

View file

@ -7,6 +7,8 @@ from accounts.models import FriendCode, CustomUser
from accounts.forms import FriendCodeForm, UserSettingsForm
from django.db.models import Case, When, Value, BooleanField
from trades.models import TradeOffer, TradeAcceptance
from django.core.exceptions import PermissionDenied
from trades.mixins import FriendCodeRequiredMixin
class ListFriendCodesView(LoginRequiredMixin, ListView):
"""
@ -127,30 +129,6 @@ class ChangeDefaultFriendCodeView(LoginRequiredMixin, View):
messages.success(request, "Default friend code updated successfully.")
return redirect("list_friend_codes")
# Updated SettingsView to update the new user setting.
class SettingsView(LoginRequiredMixin, UpdateView):
"""
Display account navigation links and allow the user to update their friend code
visibility setting.
"""
model = CustomUser
form_class = UserSettingsForm
template_name = "account/settings.html"
success_url = reverse_lazy("settings")
def get_object(self):
return self.request.user
def form_valid(self, form):
messages.success(self.request, "Settings updated successfully.")
return super().form_valid(form)
class ProfileView(LoginRequiredMixin, TemplateView):
"""
Display the user's profile.
"""
template_name = "account/profile.html"
class EditFriendCodeView(LoginRequiredMixin, UpdateView):
"""
Edit the in-game name for a friend code.
@ -170,4 +148,147 @@ class EditFriendCodeView(LoginRequiredMixin, UpdateView):
def form_valid(self, form):
messages.success(self.request, "Friend code updated successfully.")
return super().form_valid(form)
return super().form_valid(form)
class DashboardView(LoginRequiredMixin, FriendCodeRequiredMixin, TemplateView):
template_name = "account/dashboard.html"
def post(self, request, *args, **kwargs):
if 'update_settings' in request.POST:
from accounts.forms import UserSettingsForm
form = UserSettingsForm(request.POST, instance=request.user)
if form.is_valid():
form.save()
messages.success(request, "Settings updated successfully.")
else:
messages.error(request, "Please correct the errors below.")
return self.get(request, *args, **kwargs)
def get_selected_friend_code(self):
friend_codes = self.request.user.friend_codes.all()
friend_code_param = self.request.GET.get("friend_code")
if friend_code_param:
try:
selected_friend_code = friend_codes.get(pk=friend_code_param)
except friend_codes.model.DoesNotExist:
selected_friend_code = self.request.user.default_friend_code or friend_codes.first()
else:
selected_friend_code = self.request.user.default_friend_code or friend_codes.first()
if not selected_friend_code:
raise PermissionDenied("You do not have an active friend code associated with your account.")
return selected_friend_code
def get_dashboard_offers_paginated(self, page_param):
from django.core.paginator import Paginator
selected_friend_code = self.get_selected_friend_code()
queryset = TradeOffer.objects.filter(initiated_by=selected_friend_code, is_closed=False)
return Paginator(queryset, 10).get_page(page_param)
def get_involved_acceptances(self, selected_friend_code):
from django.db.models import Q
terminal_states = [
TradeAcceptance.AcceptanceState.THANKED_BY_INITIATOR,
TradeAcceptance.AcceptanceState.THANKED_BY_ACCEPTOR,
TradeAcceptance.AcceptanceState.THANKED_BY_BOTH,
TradeAcceptance.AcceptanceState.REJECTED_BY_INITIATOR,
TradeAcceptance.AcceptanceState.REJECTED_BY_ACCEPTOR,
]
involved = TradeAcceptance.objects.filter(
Q(trade_offer__initiated_by=selected_friend_code) | Q(accepted_by=selected_friend_code)
).order_by("-updated_at")
return involved.exclude(state__in=terminal_states)
def get_trade_acceptances_waiting_paginated(self, page_param):
selected_friend_code = self.get_selected_friend_code()
involved = self.get_involved_acceptances(selected_friend_code)
from django.db.models import Q
waiting = involved.filter(
Q(trade_offer__initiated_by=selected_friend_code, state__in=[
TradeAcceptance.AcceptanceState.ACCEPTED,
TradeAcceptance.AcceptanceState.RECEIVED,
]) |
Q(accepted_by=selected_friend_code, state__in=[TradeAcceptance.AcceptanceState.SENT])
)
from django.core.paginator import Paginator
return Paginator(waiting, 10).get_page(page_param)
def get_other_party_trade_acceptances_paginated(self, page_param):
selected_friend_code = self.get_selected_friend_code()
involved = self.get_involved_acceptances(selected_friend_code)
from django.db.models import Q
waiting = involved.filter(
Q(trade_offer__initiated_by=selected_friend_code, state__in=[
TradeAcceptance.AcceptanceState.ACCEPTED,
TradeAcceptance.AcceptanceState.RECEIVED,
]) |
Q(accepted_by=selected_friend_code, state__in=[TradeAcceptance.AcceptanceState.SENT])
)
others = involved.exclude(pk__in=waiting.values("pk"))
from django.core.paginator import Paginator
return Paginator(others, 10).get_page(page_param)
def get_closed_offers_paginated(self, page_param):
from django.core.paginator import Paginator
selected_friend_code = self.get_selected_friend_code()
queryset = TradeOffer.objects.filter(initiated_by=selected_friend_code, is_closed=True)
return Paginator(queryset, 10).get_page(page_param)
def get_closed_acceptances_paginated(self, page_param):
from django.db.models import Q
from django.core.paginator import Paginator
selected_friend_code = self.get_selected_friend_code()
terminal_success_states = [
TradeAcceptance.AcceptanceState.THANKED_BY_INITIATOR,
TradeAcceptance.AcceptanceState.THANKED_BY_ACCEPTOR,
TradeAcceptance.AcceptanceState.THANKED_BY_BOTH,
]
acceptance_qs = TradeAcceptance.objects.filter(
Q(trade_offer__initiated_by=selected_friend_code) | Q(accepted_by=selected_friend_code),
state__in=terminal_success_states
).order_by("-updated_at")
return Paginator(acceptance_qs, 10).get_page(page_param)
def get_rejected_by_me_paginated(self, page_param):
from django.db.models import Q
from django.core.paginator import Paginator
selected_friend_code = self.get_selected_friend_code()
rejection = TradeAcceptance.objects.filter(
Q(trade_offer__initiated_by=selected_friend_code, state=TradeAcceptance.AcceptanceState.REJECTED_BY_INITIATOR) |
Q(accepted_by=selected_friend_code, state=TradeAcceptance.AcceptanceState.REJECTED_BY_ACCEPTOR)
).order_by("-updated_at")
return Paginator(rejection, 10).get_page(page_param)
def get_rejected_by_them_paginated(self, page_param):
from django.db.models import Q
from django.core.paginator import Paginator
selected_friend_code = self.get_selected_friend_code()
rejection = TradeAcceptance.objects.filter(
Q(trade_offer__initiated_by=selected_friend_code, state=TradeAcceptance.AcceptanceState.REJECTED_BY_ACCEPTOR) |
Q(accepted_by=selected_friend_code, state=TradeAcceptance.AcceptanceState.REJECTED_BY_INITIATOR)
).order_by("-updated_at")
return Paginator(rejection, 10).get_page(page_param)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
request = self.request
selected_friend_code = self.get_selected_friend_code()
context["selected_friend_code"] = selected_friend_code
context["friend_codes"] = request.user.friend_codes.all()
offers_page = request.GET.get("offers_page", 1)
waiting_page = request.GET.get("waiting_page", 1)
other_page = request.GET.get("other_page", 1)
closed_offers_page = request.GET.get("closed_offers_page", 1)
closed_acceptances_page = request.GET.get("closed_acceptances_page", 1)
rejected_by_me_page = request.GET.get("rejected_by_me_page", 1)
rejected_by_them_page = request.GET.get("rejected_by_them_page", 1)
context["dashboard_offers_paginated"] = self.get_dashboard_offers_paginated(offers_page)
context["trade_acceptances_waiting_paginated"] = self.get_trade_acceptances_waiting_paginated(waiting_page)
context["other_party_trade_acceptances_paginated"] = self.get_other_party_trade_acceptances_paginated(other_page)
context["closed_offers_paginated"] = self.get_closed_offers_paginated(closed_offers_page)
context["closed_acceptances_paginated"] = self.get_closed_acceptances_paginated(closed_acceptances_page)
context["rejected_by_me_paginated"] = self.get_rejected_by_me_paginated(rejected_by_me_page)
context["rejected_by_them_paginated"] = self.get_rejected_by_them_paginated(rejected_by_them_page)
from accounts.forms import UserSettingsForm
context["settings_form"] = UserSettingsForm(instance=request.user)
context["active_tab"] = request.GET.get("tab", "dash")
return context