Source code for events.views.congress_builder

""" This file contains all of the code relating to an convener building
    a congress or editing a congress. """
from datetime import date
from decimal import Decimal

import pytz
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db.models import ProtectedError
from django.forms.widgets import HiddenInput
from django.http import HttpResponse
from django.shortcuts import render, get_object_or_404, redirect
from django.urls import reverse
from django.utils import timezone
from django.utils.html import strip_tags

from cobalt.settings import (
    TIME_ZONE,
)
from events.views.core import sort_events_by_start_date
from logs.views import log_event
from organisations.models import Organisation
from rbac.core import (
    rbac_user_allowed_for_model,
    rbac_user_has_role,
)
from rbac.views import rbac_forbidden
from events.forms import (
    CongressForm,
    NewCongressForm,
    EventForm,
    SessionForm,
    CongressDownloadForm,
)
from events.models import (
    Congress,
    Category,
    CongressMaster,
    Event,
    Session,
    CongressDownload,
    EventEntry,
    EVENT_PLAYER_FORMAT_SIZE,
)
from utils.models import Slug
from utils.utils import cobalt_round

TZ = pytz.timezone(TIME_ZONE)


def _increment_date_by_a_year(old_date):
    """Add a year to a date if it is not None"""
    if not old_date:
        return None

    # Add a year, handle 29th Feb (move to 1 March)
    try:
        return old_date.replace(year=old_date.year + 1)
    except ValueError:
        return old_date + (date(old_date.year + 1, 1, 1) - date(old_date.year, 1, 1))


[docs] def update_event_start_and_end_times(event: Event): """When a session date changes, recalculate the start and end dates for the event""" # Sessions in start order - could be possible for overlapping sessions, but we don't handle that sessions = Session.objects.filter(event=event).order_by( "session_date", "session_start" ) if sessions: event.denormalised_start_date = sessions.first().session_date event.denormalised_start_time = sessions.first().session_start event.denormalised_end_date = sessions.last().session_date event.denormalised_end_time = sessions.last().session_end else: event.denormalised_start_date = None event.denormalised_start_time = None event.denormalised_end_date = None event.denormalised_end_time = None event.save()
[docs] def copy_congress_from_another(congress_id: int): """Copy a congress from another congress. Also copy events.""" congress = get_object_or_404(Congress, pk=congress_id) original_congress = get_object_or_404(Congress, pk=congress_id) congress.pk = None congress.status = "Draft" # Most things can be left, but dates need some changes congress.start_date = _increment_date_by_a_year(congress.start_date) congress.end_date = _increment_date_by_a_year(congress.end_date) congress.date_string = None congress.entry_open_date = _increment_date_by_a_year(congress.entry_open_date) congress.entry_close_date = _increment_date_by_a_year(congress.entry_close_date) # increment year if congress.year: congress.year += 1 congress.created_date = timezone.now() congress.last_updated = timezone.now() # COB-746 # congress.entry_close_date = _increment_date_by_a_year(congress.entry_close_date) congress.save() # Also copy events and sessions events = Event.objects.filter(congress=original_congress) for event in events: sessions = Session.objects.filter(event=event) event.pk = None event.congress = congress event.save() for session in sessions: session.pk = None session.event = event session.save() # Update denormalised dates update_event_start_and_end_times(event) return congress
[docs] @login_required() def delete_congress(request, congress_id): """delete a congress Args: request(HTTPRequest): standard user request congress_id(int): congress to delete Returns: page(HTTPResponse): redirects to events """ congress = get_object_or_404(Congress, pk=congress_id) # check access role = f"events.org.{congress.congress_master.org.id}.edit" if not rbac_user_has_role(request.user, role): return rbac_forbidden(request, role) if request.method == "POST": # Check for entries if EventEntry.objects.filter(event__congress=congress).exists(): messages.error( request, "Deletion not allowed. Congress has entries.", extra_tags="cobalt-message-error", ) return redirect( "events:create_congress_wizard", congress_id=congress.id, step=7 ) # Delete Session.objects.filter(event__congress=congress).delete() Event.objects.filter(congress=congress).delete() congress.delete() messages.success( request, "Congress deleted", extra_tags="cobalt-message-success" ) return redirect("events:congress_listing") return render( request, "events/congress_builder/delete_congress.html", {"congress": congress} )
[docs] @login_required() def create_congress_wizard(request, step=1, congress_id=None): """create a new congress using a wizard format. There are a number of steps. Step 1 creates a congress either from scratch or by copying another one. All other steps edit data on the congress. The last steps allows the congress to be published. """ # handle stepper on screen step_list = {i: "btn-default" for i in range(1, 8)} step_list[step] = "btn-primary" # Step 1 - Create if step == 1: return create_congress_wizard_1(request, step_list) # all subsequent steps need the congress congress = get_object_or_404(Congress, pk=congress_id) # check access role = f"events.org.{congress.congress_master.org.id}.edit" if not rbac_user_has_role(request.user, role): return rbac_forbidden(request, role) if step == 2: return create_congress_wizard_2(request, step_list, congress) if step == 3: return create_congress_wizard_3(request, step_list, congress) if step == 4: return create_congress_wizard_4(request, step_list, congress) if step == 5: return create_congress_wizard_5(request, step_list, congress) if step == 6: return create_congress_wizard_6(request, step_list, congress) if step == 7: return create_congress_wizard_7(request, step_list, congress)
[docs] def create_congress_wizard_1(request, step_list): """congress wizard step 1 - create""" if request.method == "POST": form = NewCongressForm(request.POST) if form.is_valid(): if "scratch" in request.POST: congress_master_id = form.cleaned_data["congress_master"] congress_master = get_object_or_404( CongressMaster, pk=congress_master_id ) # check access role = "events.org.%s.edit" % congress_master.org.id if not rbac_user_has_role(request.user, role): return rbac_forbidden(request, role) congress = Congress() congress.congress_master = congress_master congress.save() messages.success( request, "Congress Created", extra_tags="cobalt-message-success" ) return redirect( "events:create_congress_wizard", step=2, congress_id=congress.id ) if "copy" in request.POST: congress_id = form.cleaned_data["congress"] congress = get_object_or_404(Congress, pk=congress_id) # check access role = "events.org.%s.edit" % congress.congress_master.org.id if not rbac_user_has_role(request.user, role): return rbac_forbidden(request, role) congress = copy_congress_from_another(congress_id) messages.success( request, "Congress Copied", extra_tags="cobalt-message-success" ) return redirect( "events:create_congress_wizard", step=2, congress_id=congress.id ) else: print(form.errors) else: # valid orgs everything, valid_orgs = rbac_user_allowed_for_model( user=request.user, app="events", model="org", action="edit" ) if everything: valid_orgs = Organisation.objects.all().values_list("pk") form = NewCongressForm(valid_orgs=valid_orgs) return render( request, "events/congress_builder/congress_wizard_1.html", {"form": form, "step_list": step_list}, )
[docs] def create_congress_wizard_2(request, step_list, congress): """wizard step 2 - general""" # Get the path to this event for the slug (which may or may not exist). Slugs are used so conveners can # send links to myabf/huntershill rather than myabf/events/6567 redirect_path = f"events/congress/view/{congress.id}" if request.method == "POST": form = CongressForm( request.POST, congress_masters=CongressMaster.objects.filter( org=congress.congress_master.org ), ) if form.is_valid(): # Extra validation if already published if congress.status == "Published": errors, _ = _create_congress_wizard_errors(congress) return _create_congress_wizard_2_handle_form(form, congress) else: print(form.errors) else: # datepicker is very fussy about format initial = {} if congress.start_date: initial["start_date"] = congress.start_date.strftime("%d/%m/%Y") if congress.end_date: initial["end_date"] = congress.end_date.strftime("%d/%m/%Y") form = CongressForm( instance=congress, initial=initial, congress_masters=CongressMaster.objects.filter( org=congress.congress_master.org ), ) form.fields["year"].required = True form.fields["name"].required = True form.fields["start_date"].required = True form.fields["end_date"].required = True form.fields["date_string"].required = True form.fields["general_info"].required = True form.fields["links"].required = True form.fields["people"].required = True form.fields["contact_email"].required = True form.fields["congress_master"].required = True # we can have multiple matches, but it is unlikely slug = Slug.objects.filter(redirect_path=redirect_path).first() # slug_text starts as the registered slug or blank but gets changed by the HTMX calls slug_text = slug.slug if slug else "" return render( request, "events/congress_builder/congress_wizard_2.html", { "form": form, "step_list": step_list, "congress": congress, "slug": slug, "slug_text": slug_text, }, )
# TODO Rename this here and in `create_congress_wizard_2` def _create_congress_wizard_2_handle_form(form, congress): congress.year = form.cleaned_data["year"] congress.congress_type = form.cleaned_data["congress_type"] congress.name = form.cleaned_data["name"] congress.date_string = form.cleaned_data["date_string"] congress.start_date = form.cleaned_data["start_date"] congress.end_date = form.cleaned_data["end_date"] congress.general_info = form.cleaned_data["general_info"] congress.links = form.cleaned_data["links"] congress.people = form.cleaned_data["people"] congress.additional_info = form.cleaned_data["additional_info"] congress.contact_email = form.cleaned_data["contact_email"] congress.congress_venue_type = form.cleaned_data["congress_venue_type"] congress.online_platform = form.cleaned_data["online_platform"] congress.congress_master = form.cleaned_data["congress_master"] congress.save() return redirect("events:create_congress_wizard", step=3, congress_id=congress.id)
[docs] def create_congress_wizard_3(request, step_list, congress): """wizard step 3 - venue""" if request.method == "POST": form = CongressForm(request.POST) if form.is_valid(): congress.venue_name = form.cleaned_data["venue_name"] congress.venue_location = form.cleaned_data["venue_location"] congress.venue_transport = form.cleaned_data["venue_transport"] congress.venue_catering = form.cleaned_data["venue_catering"] congress.venue_additional_info = form.cleaned_data["venue_additional_info"] congress.save() return redirect( "events:create_congress_wizard", step=4, congress_id=congress.id ) else: print(form.errors) else: form = CongressForm(instance=congress) form.fields["venue_name"].required = True # form.fields["venue_location"].required = True form.fields["venue_transport"].required = True form.fields["venue_catering"].required = True return render( request, "events/congress_builder/congress_wizard_3.html", {"form": form, "step_list": step_list, "congress": congress}, )
[docs] def create_congress_wizard_4(request, step_list, congress): """wizard step 3 - sponsor""" if request.method == "POST": form = CongressForm(request.POST) if form.is_valid(): congress.sponsors = form.cleaned_data["sponsors"] congress.save() return redirect( "events:create_congress_wizard", step=5, congress_id=congress.id ) else: print(form.errors) else: form = CongressForm(instance=congress) return render( request, "events/congress_builder/congress_wizard_4.html", {"form": form, "step_list": step_list, "congress": congress}, )
[docs] def create_congress_wizard_5(request, step_list, congress): """wizard step 5 - options""" if request.method == "POST": form = CongressForm(request.POST) if form.is_valid(): # congress.payment_method_system_dollars = form.cleaned_data[ # "payment_method_system_dollars" # ] congress.payment_method_bank_transfer = form.cleaned_data[ "payment_method_bank_transfer" ] congress.payment_method_cash = form.cleaned_data["payment_method_cash"] congress.payment_method_cheques = form.cleaned_data[ "payment_method_cheques" ] congress.payment_method_off_system_pp = form.cleaned_data[ "payment_method_off_system_pp" ] congress.entry_open_date = form.cleaned_data["entry_open_date"] congress.entry_close_date = form.cleaned_data["entry_close_date"] congress.automatic_refund_cutoff = form.cleaned_data[ "automatic_refund_cutoff" ] congress.allow_partnership_desk = form.cleaned_data[ "allow_partnership_desk" ] congress.allow_early_payment_discount = form.cleaned_data[ "allow_early_payment_discount" ] congress.early_payment_discount_date = form.cleaned_data[ "early_payment_discount_date" ] congress.allow_youth_payment_discount = form.cleaned_data[ "allow_youth_payment_discount" ] congress.youth_payment_discount_age = form.cleaned_data[ "youth_payment_discount_age" ] congress.youth_payment_discount_date = form.cleaned_data[ "youth_payment_discount_date" ] congress.senior_age = form.cleaned_data["senior_age"] congress.senior_date = form.cleaned_data["senior_date"] congress.members_only = form.cleaned_data["members_only"] congress.allow_member_entry_fee = form.cleaned_data[ "allow_member_entry_fee" ] congress.bank_transfer_details = form.cleaned_data["bank_transfer_details"] congress.cheque_details = form.cleaned_data["cheque_details"] congress.save() if congress.members_only or congress.allow_member_entry_fee: _congress_builder_populate_member_entry_fee(congress) return redirect( "events:create_congress_wizard", step=6, congress_id=congress.id ) else: print(form.errors) for er in form.errors: messages.error( request, form.errors[er], extra_tags="cobalt-message-error", ) return render( request, "events/congress_builder/congress_wizard_5.html", {"form": form, "step_list": step_list, "congress": congress}, ) else: # sort out dates initial = {} if congress.entry_open_date: initial["entry_open_date"] = congress.entry_open_date.strftime("%d/%m/%Y") if congress.automatic_refund_cutoff: initial[ "automatic_refund_cutoff" ] = congress.automatic_refund_cutoff.strftime("%d/%m/%Y") if congress.entry_close_date: initial["entry_close_date"] = congress.entry_close_date.strftime("%d/%m/%Y") if congress.early_payment_discount_date: initial[ "early_payment_discount_date" ] = congress.early_payment_discount_date.strftime("%d/%m/%Y") if congress.youth_payment_discount_date: initial[ "youth_payment_discount_date" ] = congress.youth_payment_discount_date.strftime("%d/%m/%Y") if congress.senior_date: initial["senior_date"] = congress.senior_date.strftime("%d/%m/%Y") form = CongressForm(instance=congress, initial=initial) form.fields["payment_method_system_dollars"].required = True form.fields["payment_method_bank_transfer"].required = True form.fields["payment_method_cash"].required = True form.fields["payment_method_cheques"].required = True form.fields["payment_method_off_system_pp"].required = True form.fields["entry_open_date"].required = True form.fields["entry_close_date"].required = True form.fields["automatic_refund_cutoff"].required = True form.fields["allow_partnership_desk"].required = True form.fields["allow_early_payment_discount"].required = True form.fields["bank_transfer_details"].required = True form.fields["senior_date"].required = True form.fields["senior_age"].required = True form.fields["cheque_details"].required = True return render( request, "events/congress_builder/congress_wizard_5.html", {"form": form, "step_list": step_list, "congress": congress}, )
def _congress_builder_populate_member_entry_fee(congress): """Either the members only or the separate member and non-member entry fee option has been enabled. Default the member entry fee for any existing events (if zero) to be the same as the general entry fee""" # update any existing events events = Event.objects.filter(congress=congress) for event in events: if event.member_entry_fee == Decimal(0.00) and event.entry_fee != Decimal(0.00): event.member_entry_fee = event.entry_fee event.save()
[docs] def create_congress_wizard_6(request, step_list, congress): """wizard step 6 - events""" events = Event.objects.filter(congress=congress) if request.method == "POST": return redirect( "events:create_congress_wizard", step=7, congress_id=congress.id ) # add start date and sort by start date events_list_sorted = sort_events_by_start_date(events) return render( request, "events/congress_builder/congress_wizard_6.html", {"step_list": step_list, "congress": congress, "events": events_list_sorted}, )
[docs] def create_congress_wizard_7(request, step_list, congress): """wizard step 7 - publish""" errors, warnings = _create_congress_wizard_errors(congress) if request.method == "POST": if "Publish" in request.POST: if errors: for error in errors: messages.error( request, f"Error. Cannot publish Congress. {strip_tags(error)}", extra_tags="cobalt-message-error", ) else: congress.status = "Published" congress.save() messages.success( request, "Congress published", extra_tags="cobalt-message-success", ) return redirect("events:view_congress", congress_id=congress.id) if "Unpublish" in request.POST: congress.status = "Draft" congress.save() messages.success( request, "Congress returned to Draft status", extra_tags="cobalt-message-success", ) return render( request, "events/congress_builder/congress_wizard_7.html", { "step_list": step_list, "congress": congress, "errors": errors, "warnings": warnings, }, )
def _create_congress_wizard_errors(congress): """check congress for errors""" url = "%s/%s/" % (reverse("events:create_congress_wizard"), congress.id) errors = [] warnings = [] if not congress.name: errors.append("<a href='%s%s'>%s</a>" % (url, 2, "Congress name is missing")) if not congress.additional_info: warnings.append( "<a href='%s%s'>%s</a>" % (url, 2, "Congress Additional Info is missing") ) if not congress.start_date: errors.append("<a href='%s%s'>%s</a>" % (url, 2, "Start date is missing")) if not congress.end_date: errors.append("<a href='%s%s'>%s</a>" % (url, 2, "End date is missing")) if not congress.date_string: warnings.append("<a href='%s%s'>%s</a>" % (url, 2, "Date string is missing")) if not congress.year: warnings.append("<a href='%s%s'>%s</a>" % (url, 2, "Year is missing")) if not congress.general_info: errors.append("<a href='%s%s'>%s</a>" % (url, 2, "General is missing")) if not congress.people: errors.append("<a href='%s%s'>%s</a>" % (url, 2, "People is missing")) if not congress.venue_name: warnings.append("<a href='%s%s'>%s</a>" % (url, 3, "Venue name is missing")) if not congress.venue_location: warnings.append("<a href='%s%s'>%s</a>" % (url, 3, "Venue location is missing")) if not congress.venue_transport: warnings.append( "<a href='%s%s'>%s</a>" % (url, 3, "Venue transport is missing") ) if not congress.venue_catering: warnings.append("<a href='%s%s'>%s</a>" % (url, 3, "Venue catering is missing")) if not congress.venue_additional_info: warnings.append( "<a href='%s%s'>%s</a>" % (url, 3, "Venue Additional info is missing") ) if not congress.entry_open_date: warnings.append( "<a href='%s%s'>%s</a>" % ( url, 5, "Entry open date is missing. Entries will be accepted any time before closing date.", ) ) if not congress.entry_close_date: warnings.append( "<a href='%s%s'>%s</a>" % ( url, 5, "Entry close date is missing. Entries will be accepted even after the congress has started.", ) ) events = Event.objects.filter(congress=congress) if events.count() == 0: errors.append( "<a href='%s%s'>%s</a>" % (url, 6, "This congress has no events defined") ) for event in events: sessions = Session.objects.filter(event=event).count() if sessions == 0: errors.append( "<a href='%s%s'>%s</a>" % (url, 6, f"{event.event_name} has no sessions defined") ) return errors, warnings
[docs] @login_required def create_event(request, congress_id): """create an event within a congress""" congress = get_object_or_404(Congress, pk=congress_id) # check access role = "events.org.%s.edit" % congress.congress_master.org.id if not rbac_user_has_role(request.user, role): return rbac_forbidden(request, role) form = EventForm( request.POST or None, initial={ "entry_early_payment_discount": 0.0, "entry_fee": 0.0, "member_entry_fee": 0.0, }, ) if request.method == "POST": if form.is_valid(): event = form.save(commit=False) event.congress = congress event.save() messages.success( request, "Event added", extra_tags="cobalt-message-success" ) return redirect( "events:edit_event", event_id=event.id, congress_id=congress_id ) else: print(form.errors) # create a dummy event so template doesn't generate errors - we share the template with the edit function # which has an event dummy_event = {"id": "dummy"} return render( request, "events/congress_builder/edit_event.html", {"form": form, "congress": congress, "page_type": "add", "event": dummy_event}, )
[docs] @login_required def edit_event(request, congress_id, event_id): """edit an event within a congress""" congress = get_object_or_404(Congress, pk=congress_id) # check access role = "events.org.%s.edit" % congress.congress_master.org.id if not rbac_user_has_role(request.user, role): return rbac_forbidden(request, role) event = get_object_or_404(Event, pk=event_id) sessions = Session.objects.filter(event=event).order_by( "session_date", "session_start" ) if request.method == "POST": form = EventForm(request.POST, instance=event) if form.is_valid(): form.save() messages.success( request, "Event updated", extra_tags="cobalt-message-success" ) else: # datepicker is very fussy about format initial = {} if event.entry_open_date: initial["entry_open_date"] = event.entry_open_date.strftime("%d/%m/%Y") if event.entry_close_date: initial["entry_close_date"] = event.entry_close_date.strftime("%d/%m/%Y") if event.entry_close_time: initial["entry_close_time"] = event.entry_close_time.strftime("%H:%M") # convert saved entry fee values from per entry to per player players_per_entry = EVENT_PLAYER_FORMAT_SIZE[event.player_format] if event.player_format == "Teams": players_per_entry = 4 initial["member_entry_fee"] = cobalt_round( event.member_entry_fee / players_per_entry ) initial["entry_fee"] = cobalt_round(event.entry_fee / players_per_entry) initial["entry_early_payment_discount"] = cobalt_round( event.entry_early_payment_discount / players_per_entry ) form = EventForm(instance=event, initial=initial) # the member_entry_fee field needs to be on the view even when disabled (ie hidden) # otherwise the value becomes corrupted when the event is saved (seems to pick up # the database value and saves that multiplied by the number of players) if not (congress.allow_member_entry_fee or congress.members_only): form.fields["member_entry_fee"].widget = HiddenInput() categories = Category.objects.filter(event=event) return render( request, "events/congress_builder/edit_event.html", { "form": form, "congress": congress, "event": event, "sessions": sessions, "categories": categories, "page_type": "edit", }, )
[docs] @login_required def create_session(request, event_id): """create session within an event""" event = get_object_or_404(Event, pk=event_id) # check access role = f"events.org.{event.congress.congress_master.org.id}.edit" if not rbac_user_has_role(request.user, role): return rbac_forbidden(request, role) if request.method == "POST": form = SessionForm(request.POST) if form.is_valid(): session = Session() session.event = event session.session_date = form.cleaned_data["session_date"] session.session_start = form.cleaned_data["session_start"] session.session_end = form.cleaned_data["session_end"] session.save() update_event_start_and_end_times(event) log_event( user=request.user, severity="INFO", source="Events", sub_source="events_admin", message=f"Added session '{session.href}' to {event.href}", ) messages.success( request, "Session Added", extra_tags="cobalt-message-success" ) return redirect( "events:edit_event", event_id=event_id, congress_id=event.congress.id ) else: print(form.errors) else: form = SessionForm() return render( request, "events/congress_builder/create_session.html", {"form": form, "event": event}, )
[docs] @login_required def edit_session(request, event_id, session_id): """edit session within an event""" event = get_object_or_404(Event, pk=event_id) session = get_object_or_404(Session, pk=session_id) # check access role = f"events.org.{event.congress.congress_master.org.id}.edit" if not rbac_user_has_role(request.user, role): return rbac_forbidden(request, role) if request.method == "POST": form = SessionForm(request.POST, instance=session) if form.is_valid(): session.session_date = form.cleaned_data["session_date"] session.session_start = form.cleaned_data["session_start"] session.session_end = form.cleaned_data["session_end"] session.save() update_event_start_and_end_times(event) messages.success( request, "Session Updated", extra_tags="cobalt-message-success" ) return redirect( "events:edit_event", event_id=event_id, congress_id=event.congress.id ) else: print(form.errors) else: # datepicker is very fussy about format initial = {} if session.session_date: initial["session_date"] = session.session_date.strftime("%d/%m/%Y") if session.session_start: initial["session_start"] = session.session_start.strftime("%I:%M %p") if session.session_end: initial["session_end"] = session.session_end.strftime("%I:%M %p") form = SessionForm(instance=event, initial=initial) return render( request, "events/congress_builder/edit_session.html", {"form": form, "event": event, "session": session}, )
[docs] @login_required def view_draft_congresses(request): """Show any draft congresses that the user can edit""" draft_congresses = Congress.objects.filter(status="Draft") draft_congress_list = [] for draft_congress in draft_congresses: role = "events.org.%s.edit" % draft_congress.congress_master.org.id if rbac_user_has_role(request.user, role): draft_congress_list.append(draft_congress) return render( request, "events/congress_builder/view_draft_congresses.html", {"congress_list": draft_congress_list}, )
[docs] @login_required() def manage_congress_download(request, congress_id): """Manage download files""" congress = get_object_or_404(Congress, pk=congress_id) # check access role = "events.org.%s.edit" % congress.congress_master.org.id if not rbac_user_has_role(request.user, role): return rbac_forbidden(request, role) if request.method == "POST": form = CongressDownloadForm(request.POST, request.FILES) if form.is_valid(): form.save() messages.success( request, "Document uploaded", extra_tags="cobalt-message-success" ) log_event( user=request.user, severity="INFO", source="Events", sub_source="events_admin", message=f"Uploaded a download document to {congress.href}", ) form = CongressDownloadForm() # Get bulletins downloads = CongressDownload.objects.filter(congress=congress).order_by("-pk") return render( request, "events/congress_builder/congress_wizard_downloads.html", {"form": form, "congress": congress, "downloads": downloads}, )
[docs] @login_required() def slug_handler_htmx(request): """Generates the slug row in congress wizard 2""" congress_id = request.POST.get("congress_id") slug_text = request.POST.get("slug_text") congress = Congress.objects.filter(pk=congress_id).first() slug = Slug.objects.filter(slug=slug_text).first() redirect_path = f"events/congress/view/{congress_id}" if "create" in request.POST: slug = Slug( slug=slug_text, redirect_path=redirect_path, owner=congress.congress_master.org, ) slug.save() slug_msg = "Short name created" show_save = False else: if slug: slug_msg = "Short name already used. Please select another name." show_save = False elif slug_text: slug_msg = "Name is available" show_save = True else: slug_msg = "" show_save = False return render( request, "events/congress_builder/congress_wizard_2_slug_htmx.html", { "congress": congress, "slug": slug, "slug_text": slug_text, "slug_msg": slug_msg, "show_save": show_save, }, )