"""Views for the main app.""" import json from functools import reduce from django.shortcuts import render, redirect from django.http import JsonResponse from django.db.models import Q, Case, When, Value, IntegerField, Min from django.db.utils import IntegrityError from django.views import View from django.views.decorators.http import require_GET, require_POST from django.http import HttpRequest, HttpResponseNotFound from django.core import serializers from django.forms.models import model_to_dict from .models import Venue, Waters # from .models import Team, Member, Section, SectionManager, ReusableAutoField, SectionValidator def index(request): venues = Venue.objects.all() context = {"venues": venues, "venue_types": Venue.VENUE_TYPES} return render(request, 'index.html', context) def results(request): return render(request, 'results.html') def scoreboard(request): return render(request, 'scoreboard.html') def teams(request): return render(request, 'teams.html') def venues(request): venues = Venue.objects.all() context = {"venues": venues, "venue_types": Venue.VENUE_TYPES} return render(request, 'venues.html', context) def venue_details(request, venue_id): try: venue = Venue.objects.get(id=venue_id) except Venue.DoesNotExist: return HttpResponseNotFound("

404 - Venue not found

") context = {"venue": venue} return render(request, 'venue_details.html', context) def create_venue(request): if request.method != "POST": return JsonResponse({"error", "Method not allowed"}, status=403) test = request.POST attributes = { name: request.POST.get(name) for name in [field.name for field in Venue._meta.get_fields()] } venue_id = request.POST.get("id") if venue_id: venue = Venue.objects.get(id=venue_id) for k, v in attributes.items(): setattr(venue, k, v) venue.save() return JsonResponse({"success": "successful update"}, status=200) del attributes["id"] Venue.objects.create(**attributes) return JsonResponse({"success": "successful creation"}, status=200) def get_venue_details(request, venue_id: int): try: venue = Venue.objects.get(pk=venue_id) except Venue.DoesNotExist: return JsonResponse({"error": "Venue not found"}, status=404) json_venue = model_to_dict(venue) return JsonResponse({"data": json_venue}) def get_venue_waters(request, venue_id: int): try: venue = Venue.objects.get(pk=venue_id) except Venue.DoesNotExist: return JsonResponse({"error": "Venue not found"}, status=404) waters = Waters.objects.filter(venue=venue) waters_data = [ { "name": water.name, "description": water.description, "pegs_min": water.pegs_min, "pegs_max": water.pegs_max, "water_type": water.water_type, "fish_type": water.fish_type } for water in waters ] return JsonResponse({"waters", waters_data}) # def bulk_create_pegs(request): # """Bulk create pegs""" # number_of_pegs = request.POST.get("pegAmount") # for i in range(int(number_of_pegs)): # Peg.objects.create() # # return to previous page # return redirect(request.META.get('HTTP_REFERER')) def name_sort_key(section): if len(section.name) == 1: return (0, section.name) else: return (1, section.name[:-1], section.name[-1]) class ManageAnglersView(View): """View for the Manage Anglers page.""" template_name = "anglers.html" def get(self, request: HttpRequest, *args, **kwargs) -> HttpRequest: """Handle GET requests to the Manage Anglers page. Args: request (HttpRequest): The HttpRequest object, contains GET data. Returns: HttpRequest: A render of the Manage Anglers page. """ anglers = Member.objects.order_by("first_name", "last_name") context = {"anglers": anglers} return render(request, self.template_name, context) def post(self, request: HttpRequest, *args, **kwargs) -> JsonResponse: """Handle POST requests to the Manage Anglers page. Args: request (HttpRequest): The HttpRequest object, contains POST data. Returns: JsonResponse: Contains the result of the action. """ tasks = request.POST.getlist("tasks[]") data = {} for task in tasks: data.update(self.handle_task(request, task)) return JsonResponse(data) def handle_task(self, request, task: str) -> dict[str, str]: """Handle a task. Args: request (HttpRequest): HttpRequest object, contains POST data. task (str): The task to handle. Raises: ValueError: The task is invalid. Returns: dict[str, str]: The result of the task. """ # Format is {key = ACTION-TASK_NAME: value = HANDLER_FUNCTION} task_handlers = { "update-team": self.update_team, "update-section": self.update_section, "update-angler": self.update_angler, "get-teams": self.get_teams, "get-sections": self.get_sections, "get-anglers": self.get_anglers, "delete-team": self.delete_team, "delete-section": self.delete_section, "delete-angler": self.delete_angler, "get-nextTeamNumber": self.get_next_team_number, "get-nextPegNumber": self.get_next_peg_number, } handler = task_handlers.get(task) if not handler: raise ValueError(f"Invalid task: {task}") return handler(request) def update_team(self, request) -> dict[str]: """Update a team, returns a dictionary of the new team's data.""" result = {"form_errors": {}, "team": None} team_id = request.POST.get("id") team_number = request.POST.get("number") if not (team_id and team_number): raise ValueError("Team ID or Team Number is missing or empty") if team_id == "-1": team = Team(number=team_number) else: team = Team.objects.get(id=team_id) team.number = team_number try: team.save() result["team"] = {"id": team.id, "number": team.number} except IntegrityError: result["form_errors"]["#teamNumber"] = "A Team with this number already exists" return result def update_section(self, request) -> dict[str]: """Update a section, returns a dictionary of the new section's data.""" result = {"form_errors": {}, "section": None} section_id = request.POST.get("id") section_character = request.POST.get("character") if not (section_id and section_character): raise ValueError("Section ID or Section Character is missing or empty") if section_id == "-1": section = Section(character=section_character) else: section = Section.objects.get(id=section_id) section.character = section_character try: section.save() result["section"] = {"id": section.id, "character": section.character} except IntegrityError: result["form_errors"]["#editSectionNameError"] = "A Section with this character already exists" return result def update_angler(self, request) -> dict[str]: """Update an Angler, returns a dictionary of the new angler's data.""" result = {"form_errors": {}, "angler": None} angler_id = request.POST.get("angler_id") forename = request.POST.get("forename") surname = request.POST.get("surname") peg_number = request.POST.get("peg_number") team_id = request.POST.get("team_id") section_id = request.POST.get("section_id") if not angler_id: raise ValueError("Invalid angler ID") team = Team.objects.get(id=team_id) section = Section.objects.get(id=section_id) if angler_id == "-1": angler = Member( first_name=forename, last_name=surname, peg_number=peg_number, team=team, section=section ) else: angler = Member.objects.get(id=angler_id) angler.first_name = forename angler.last_name = surname angler.peg_number = peg_number angler.team = team angler.section = section try: angler.save() except IntegrityError: result["form_errors"]["#anglerPeg"] = "An Angler with this peg number already exists" result["angler"] = { "id": angler.id, "forename": forename, "surname": surname, "peg_number": peg_number, "team_id": team_id, "section_id": section_id, "team_number": angler.team.number, "section_character": angler.section.character } return result def get_teams(self, request) -> dict[str]: """Returns a dictionary of all teams.""" search = request.POST.get("search") teams = Team.objects.order_by("number").all() # Search works by exluding teams that do not contain members with the search term in their names. if search: search_terms = search.split() members = Member.objects.filter(reduce(lambda x, y: x & y, [ Q(first_name__icontains=term) | Q(last_name__icontains=term) for term in search_terms ])) teams = teams.filter(members__in=members).distinct() return {"teams": [{"id": team.id, "number": team.number} for team in teams]} def get_sections(self, request) -> dict[str]: """Returns a dictionary of all sections.""" search = request.POST.get("search") sections = Section.objects.order_by("character").all() if search: search_terms = search.split() members = Member.objects.filter(reduce(lambda x, y: x & y, [ Q(first_name__icontains=term) | Q(last_name__icontains=term) for term in search_terms ])) sections = sections.filter(members__in=members).distinct() return {"sections": [{"id": section.id, "character": section.character} for section in sections]} def get_anglers(self, request) -> dict[str]: """Returns a dictionary of all anglers.""" search = request.POST.get("search") anglers = Member.objects.order_by("first_name").all() order_by = "peg_number" if request.POST.get("sortAnglers") == "pegs" else "first_name" if search: search_terms = search.split() anglers = anglers.filter(reduce(lambda x, y: x & y, [ Q(first_name__icontains=term) | Q(last_name__icontains=term) for term in search_terms ])).distinct() return { "anglers": [ { "id": angler.id, "first_name": angler.first_name, "last_name": angler.last_name, "peg_number": angler.peg_number, "team_id": angler.team.id, "section_id": angler.section.id, "team_number": angler.team.number, "section_character": angler.section.character } for angler in anglers.order_by(order_by).all() ] } def delete_team(self, request) -> dict: """Deletes a team.""" team_id = request.POST.get("team_id") if not team_id: raise ValueError("Invalid team ID") teams = Team.objects.get(id=team_id) teams.delete() return {} def delete_section(self, request) -> dict: """Deletes a section.""" section_id = request.POST.get("section_id") if not section_id: raise ValueError("Invalid section ID") sections = Section.objects.get(id=section_id) sections.delete() return {} def delete_angler(self, request) -> dict: """Delete an angler.""" angler_id = request.POST.get("angler_id") if not angler_id: raise ValueError("Invalid angler ID") angler = Member.objects.get(id=angler_id) angler.delete() return {} def get_next_team_number(self, request) -> dict[str, int]: """Returns the next available team number.""" next_team_number = 1 while Team.objects.filter(number=next_team_number).exists(): next_team_number += 1 return {"nextTeamNumber": next_team_number} def get_next_peg_number(self, request) -> dict[str, int]: """Returns the next available peg number.""" next_peg_number = 1 while Member.objects.filter(peg_number=next_peg_number).exists(): next_peg_number += 1 return {"nextPegNumber": next_peg_number} def get_angler_page_data(request, **kwargs): """Returns a JsonResponse containing a dictionary with a k/v pair for a list of teams. Args: request: the web request object. Returns: JsonResponse: dictionary of teams like so {'teams': [{}, {}, {}]}. """ if not request.POST: return search = request.POST.get("search") sort_groups = request.POST.get("sortGroups") or "team" sort_members = request.POST.get("sortMembers") or "peg_number" teams = Team.objects.order_by("number").all() sections = Section.objects.order_by("character").all() if search: search_terms = search.split() members = Member.objects.filter( reduce( lambda x, y: x & y, ## changed to AND from OR to fix bug with whitespace searches [ Q(first_name__icontains=term) | Q(last_name__icontains=term) for term in search_terms ] ) ) teams = teams.filter(members__in=members).distinct() sections = sections.filter(members__in=members).distinct() response_data = { "teams": [ {"id": team.id, "number": team.number} for team in teams ], "sections": [ {"id": sec.id, "character": sec.character} for sec in sections ], "anglers": [ { "id": member.id, "first": member.first_name, "last": member.last_name, "peg": member.peg_number, "team_id": member.team.id if member.team else None, "section_id": member.section.id if member.section else None } for member in Member.objects.order_by(sort_members).all() ] } response_data["sortGroups"] = sort_groups response_data["sortMembers"] = sort_members for key, value in kwargs.items(): response_data[key] = value return JsonResponse(response_data) def update_member(request): """Update a member. Returns a JsonResponse with the updated teams.""" if not request.POST: return # Get the updated values member_id = request.POST.get("memberId") first = request.POST.get("first") last = request.POST.get("last") team_number = request.POST.get("teamNumber") peg_number = request.POST.get("pegNumber") # Get the member and team member = Member.objects.get(id=member_id) team = Team.objects.get(name=team_number) # Update the member member.first_name = first member.last_name = last member.team = team member.peg_number = peg_number member.save() return get_angler_page_data(request) def update_section(request): """Update a section, returns JsonResponse with updated teams data.""" if not request.POST: return section_id = request.POST.get("sectionId") section_name = request.POST.get("sectionName") validator = SectionValidator() if not validator.is_valid(section_name): json_response = get_angler_page_data(request, form_errors={ "editSectionName": "This is an invalid section" }) return json_response if section_id == "-1": section = Section(character=section_name) else: section = Section.objects.get(id=section_id) section.character = section_name try: section.save() except IntegrityError: json_response = get_angler_page_data(request, form_errors={ "editSectionName": "A Section with this character already exists" }) return json_response return get_angler_page_data(request) # returns jsonresponse with new details def update_team(request): """Update a team, returns a JsonResponse with updated teams data.""" if not request.POST: return team_id = request.POST.get("id") team_number = request.POST.get("number") try: if team_id == "-1": team = Team.objects.create(number=team_number) else: team = Team.objects.get(id=team_id) team.number = team_number team.save() except IntegrityError as error: json_response = get_angler_page_data(request, form_errors={ "editTeamNumber": "A Team with this number already exists" }) return json_response return get_angler_page_data(request) def get_next_peg() -> int: pass def get_next_section() -> str: section_name = SectionManager.get_max_section() return SectionManager.find_next_section(section_name) def get_next_team() -> int: field = ReusableAutoField field.model = Team return field().get_default() def get_next_identifier(request): """Get the next available identifer (peg, section character, etc.) for an object.""" if not request.POST: return item = request.POST.get("item") match item: case "member_peg": result = get_next_peg() case "section_name": result = get_next_section() case "team_number": result = get_next_team() case _: raise ValueError(f"Bad identifier item: {item}") return JsonResponse({"identifier": result})