Compare commits
3 Commits
4e4fe62f11
...
developmen
| Author | SHA1 | Date | |
|---|---|---|---|
| 72e6388c0c | |||
| cb3da371d1 | |||
| 8f9357f1b8 |
@@ -149,7 +149,6 @@ CONSTANCE_CONFIG = {
|
|||||||
"TF_DEFAULT_SEASON_MONTH": (config("TF_DEFAULT_SEASON_MONTH", default=8, cast=int), "Default season start month", int),
|
"TF_DEFAULT_SEASON_MONTH": (config("TF_DEFAULT_SEASON_MONTH", default=8, cast=int), "Default season start month", int),
|
||||||
"TF_DEFAULT_SEASON_DAY": (config("TF_DEFAULT_SEASON_DAY", default=1, cast=int), "Default season start day", int),
|
"TF_DEFAULT_SEASON_DAY": (config("TF_DEFAULT_SEASON_DAY", default=1, cast=int), "Default season start day", int),
|
||||||
"TF_DEFAULT_SEASON_DURATION": (config("TF_DEFAULT_SEASON_DURATION", default="1y", cast=str), "Default season duration", str),
|
"TF_DEFAULT_SEASON_DURATION": (config("TF_DEFAULT_SEASON_DURATION", default="1y", cast=str), "Default season duration", str),
|
||||||
"TF_ENABLE_TEAMS": (config("TF_ENABLE_TEAMS", default=True, cast=bool), "Enable teams", bool),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PHONENUMBER_DEFAULT_FORMAT = "INTERNATIONAL"
|
PHONENUMBER_DEFAULT_FORMAT = "INTERNATIONAL"
|
||||||
@@ -158,3 +157,4 @@ PHONENUMBER_DEFAULT_REGION = config("CM_CLUB_COUNTRY_CODE", default="BE", cast=s
|
|||||||
TAILWIND_APP_NAME = "theme"
|
TAILWIND_APP_NAME = "theme"
|
||||||
|
|
||||||
WAFFLE_CREATE_MISSING_FLAGS = True
|
WAFFLE_CREATE_MISSING_FLAGS = True
|
||||||
|
WAFFLE_CREATE_MISSING_SWITCHES = True
|
||||||
|
|||||||
12
backend/forms.py
Normal file
12
backend/forms.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
from django import forms
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigurationForm(forms.Form):
|
||||||
|
"""Form instance that holds configuration values for the application."""
|
||||||
|
|
||||||
|
club_name = forms.CharField(label=_("Club name"), max_length=250)
|
||||||
|
club_location = forms.CharField(label=_("Club location"), max_length=250, help_text=_("Changing this setting will set a new home game location and will update already existing games"))
|
||||||
|
club_logo = forms.ImageField(label=_("Club logo"), required=False)
|
||||||
|
enable_teams = forms.BooleanField(label=_("Enable teams"), required=False)
|
||||||
|
enable_activities = forms.BooleanField(label=_("Enable activities"), required=False)
|
||||||
@@ -124,7 +124,7 @@ class MemberLoadView(PermissionRequiredMixin, HTMXViewMixin, SuccessMessageMixin
|
|||||||
partial_name = "members/member_load.html#content"
|
partial_name = "members/member_load.html#content"
|
||||||
menu_highlight = "members"
|
menu_highlight = "members"
|
||||||
template_name = "members/member_load.html"
|
template_name = "members/member_load.html"
|
||||||
waffle_flag = "mass_upload"
|
waffle_flag = "TF_MASS_UPLOAD"
|
||||||
|
|
||||||
def handle_no_permission(self) -> HttpResponseRedirect:
|
def handle_no_permission(self) -> HttpResponseRedirect:
|
||||||
messages.error(self.request, self.get_permission_denied_message())
|
messages.error(self.request, self.get_permission_denied_message())
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
|
|
||||||
from .views import index
|
from .views import configuration, index
|
||||||
|
|
||||||
app_name = "backend"
|
app_name = "backend"
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", index, name="index"),
|
path("", index, name="index"),
|
||||||
path("members/", include("backend.members.urls")),
|
path("members/", include("backend.members.urls")),
|
||||||
|
path("configuration", configuration, name="configuration")
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,6 +1,59 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from constance import config
|
||||||
|
from django.conf import settings
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.decorators import login_required, user_passes_test
|
||||||
|
from django.core.cache import cache
|
||||||
|
from django.core.files.storage import default_storage
|
||||||
|
from django.http import HttpRequest, HttpResponse
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from waffle.models import Switch
|
||||||
|
|
||||||
|
from backend.forms import ConfigurationForm
|
||||||
|
|
||||||
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
def index(request):
|
def index(request):
|
||||||
return render(request, "backend/index.html")
|
return render(request, "backend/index.html")
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
@user_passes_test(lambda u: u.is_superuser)
|
||||||
|
def configuration(request: HttpRequest) -> HttpResponse:
|
||||||
|
switches = {
|
||||||
|
"enable_teams": Switch.objects.get_or_create(name="TF_TEAMS", defaults={"active": False})[0],
|
||||||
|
"enable_activities": Switch.objects.get_or_create(name="TF_ACTIVITIES", defaults={"active": False})[0],
|
||||||
|
}
|
||||||
|
|
||||||
|
initial_data = {
|
||||||
|
"club_name": config.TF_CLUB_NAME,
|
||||||
|
"club_location": config.TF_CLUB_HOME,
|
||||||
|
"club_logo": config.TF_CLUB_LOGO,
|
||||||
|
"enable_teams": switches["enable_teams"].active,
|
||||||
|
"enable_activities": switches["enable_activities"].active,
|
||||||
|
}
|
||||||
|
|
||||||
|
form = ConfigurationForm(initial=initial_data)
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
form = ConfigurationForm(request.POST, request.FILES)
|
||||||
|
if form.is_valid():
|
||||||
|
config.TF_CLUB_NAME = form.cleaned_data["club_name"]
|
||||||
|
config.TF_CLUB_HOME = form.cleaned_data["club_location"]
|
||||||
|
|
||||||
|
if form.cleaned_data["club_logo"] is not None:
|
||||||
|
default_storage.save(str(Path(settings.STATIC_ROOT) / form.cleaned_data["club_logo"].name), form.cleaned_data["club_logo"])
|
||||||
|
config.TF_CLUB_LOGO = form.cleaned_data["club_logo"].name
|
||||||
|
|
||||||
|
for switch_key in switches.keys():
|
||||||
|
if switches[switch_key].active != form.cleaned_data[switch_key]:
|
||||||
|
switches[switch_key].active = form.cleaned_data[switch_key]
|
||||||
|
|
||||||
|
Switch.objects.bulk_update(switches.values(), ["active"])
|
||||||
|
cache.clear()
|
||||||
|
|
||||||
|
messages.success(request=request, message=_("Settings have been saved successfully"))
|
||||||
|
|
||||||
|
return render(request, "backend/configuration.html", {"form": form})
|
||||||
|
|||||||
@@ -4,17 +4,18 @@
|
|||||||
|
|
||||||
{% block sidebar %}
|
{% block sidebar %}
|
||||||
{% url "backend:members:list" as members_list %}
|
{% url "backend:members:list" as members_list %}
|
||||||
|
{% url "backend:configuration" as configuration %}
|
||||||
|
|
||||||
{% has_perm "members.member_manager" request.user as is_member_manager %}
|
{% has_perm "members.member_manager" request.user as is_member_manager %}
|
||||||
|
|
||||||
{% if is_member_manager %}
|
{% if is_member_manager %}
|
||||||
<li class="menu-title">Members</li>
|
<li class="menu-title">Members</li>
|
||||||
<li><a href="{{ members_list }}" class="menu-item {% if members_list in request.path %}menu-active{% endif %}" data-menu="members" hx-get="{% url "backend:members:list" %}" hx-target="#content"><i class="fa-solid fa-users"></i> Members</a></li>
|
<li><a href="{{ members_list }}" class="menu-item {% if members_list in request.path %}menu-active{% endif %}" data-menu="members" hx-get="{% url "backend:members:list" %}" hx-target="#content"><i class="fa-solid fa-users"></i> Members</a>
|
||||||
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<li class="menu-title mt-4">Navigation</li>
|
{% if request.user.is_superuser %}
|
||||||
<li><a href="#"><i class="fa-solid fa-house"></i> Dashboard</a></li>
|
<li class="menu-title mt-4">Configuration</li>
|
||||||
<li><a href="#"><i class="fa-solid fa-calendar"></i> Calendar</a></li>
|
<li><a href="{% url "backend:configuration" %}" class="menu-item {% if configuration in request.path %}menu-active{% endif %}" data-menu="configuration"><i class="fa-solid fa-screwdriver-wrench"></i> Settings</a></li>
|
||||||
<li><a href="#"><i class="fa-solid fa-users"></i> Members</a></li>
|
{% endif %}
|
||||||
<li><a href="#"><i class="fa-solid fa-gear"></i> Settings</a></li>
|
|
||||||
{% endblock sidebar %}
|
{% endblock sidebar %}
|
||||||
76
templates/backend/configuration.html
Normal file
76
templates/backend/configuration.html
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
{% extends "backend/base.html" %}
|
||||||
|
|
||||||
|
{% load i18n %}
|
||||||
|
{% load form_field %}
|
||||||
|
{% load avatar %}
|
||||||
|
{% load waffle_tags %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% partialdef content inline %}
|
||||||
|
<h1 class="page-title">{% translate "Configuration" %}</h1>
|
||||||
|
|
||||||
|
{% blocktranslate %}
|
||||||
|
<article class="prose text-justify max-w-none">
|
||||||
|
<p>Use the below options to configure your TeamForge instance. Options marked as required will need to be set in order for TeamForge to function properly.</p>
|
||||||
|
<p>You can also use this form to enable or disable certain pieces of functionality for your users.</p>
|
||||||
|
</article>
|
||||||
|
{% endblocktranslate %}
|
||||||
|
|
||||||
|
{% if form.errors %}
|
||||||
|
<div class="flex flex-row items-center gap-2 p-2 m-4 rounded-lg bg-error">
|
||||||
|
<i class="mr-2 text-3xl fa-solid fa-exclamation-triangle text-error-content"></i>
|
||||||
|
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div class="mb-1 font-semibold text-error-content">{% translate "Error" %}</div>
|
||||||
|
<div class="text-sm text-error-content">{% translate "Please correct the errors below before saving again." %}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
|
||||||
|
<h2 class="page-subtitle">{% translate "General configuration" %}</h2>
|
||||||
|
<div class="grid grid-cols-1 gap-4 mt-2 lg:grid-cols-2 xl:grid-cols-3">
|
||||||
|
{% form_field form.club_name %}
|
||||||
|
{% form_field form.club_location %}
|
||||||
|
{% form_field form.club_logo %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 class="page-subtitle">{% translate "Module configuration" %}</h2>
|
||||||
|
<div class="grid grid-cols-1 gap-1 mt-2 gap-x-4 lg:grid-cols-3 xl:grid-cols-5">
|
||||||
|
<div class="flex flex-row gap-2">
|
||||||
|
<span class="font-semibold">{% translate "Teams" %}</span>
|
||||||
|
{% form_field form.enable_teams show_label=False show_as_toggle=True %}
|
||||||
|
|
||||||
|
{% switch "TF_TEAMS" %}
|
||||||
|
<div class="badge badge-success"><i class="fa-solid fa-check"></i>{% translate "Enabled" %}</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="badge badge-error"><i class="fa-solid fa-times"></i>{% translate "Disabled" %}</div>
|
||||||
|
{% endswitch %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div></div>
|
||||||
|
|
||||||
|
<div class="flex flex-row gap-2">
|
||||||
|
<span class="font-semibold">{% translate "Activities" %}</span>
|
||||||
|
{% form_field form.enable_activities show_label=False show_as_toggle=True %}
|
||||||
|
|
||||||
|
{% switch "TF_ACTIVITIES" %}
|
||||||
|
<div class="badge badge-success"><i class="fa-solid fa-check"></i>{% translate "Enabled" %}</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="badge badge-error"><i class="fa-solid fa-times"></i>{% translate "Disabled" %}</div>
|
||||||
|
{% endswitch %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="w-full mt-8 btn btn-neutral" type="submit">
|
||||||
|
<i class="fa-solid fa-floppy-disk"></i>{% translate "Save" %}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
new Choices(document.querySelector("#id_family_members"));
|
||||||
|
</script>
|
||||||
|
{% endpartialdef content %}
|
||||||
|
{% endblock content %}
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="add">
|
<div class="add">
|
||||||
{% flag "mass_upload" %}
|
{% flag "TF_MASS_UPLOAD" %}
|
||||||
<a class="btn btn-accent btn-sm grow hidden lg:flex" href="{% url "backend:members:load" %}" hx-get="{% url "backend:members:load" %}" hx-target="#content">
|
<a class="btn btn-accent btn-sm grow hidden lg:flex" href="{% url "backend:members:load" %}" hx-get="{% url "backend:members:load" %}" hx-target="#content">
|
||||||
<i class="fa-solid fa-file-upload"></i>{% translate "Load members from file" %}
|
<i class="fa-solid fa-file-upload"></i>{% translate "Load members from file" %}
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load form_field %}
|
{% load form_field %}
|
||||||
{% load avatar %}
|
{% load avatar %}
|
||||||
|
{% load waffle_tags %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% partialdef content inline %}
|
{% partialdef content inline %}
|
||||||
@@ -45,17 +46,17 @@
|
|||||||
|
|
||||||
{% if member.emergency_phone_number %}
|
{% if member.emergency_phone_number %}
|
||||||
<a href="{{ member.emergency_phone_number.as_rfc3966 }}" class="btn btn-error btn-outline btn-sm grow">
|
<a href="{{ member.emergency_phone_number.as_rfc3966 }}" class="btn btn-error btn-outline btn-sm grow">
|
||||||
<i class="fa-solid fa-file-medical"></i>
|
<i class="fa-solid fa-star-of-life"></i>
|
||||||
{{ member.emergency_phone_number }}
|
{{ member.emergency_phone_number }}
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if config.TF_ENABLE_TEAMS %}
|
{% switch "TF_TEAMS" %}
|
||||||
<a href="?member__user__first_name={{ member.user.first_name }}&member__user__last_name={{ member.user.last_name }}" class="btn btn-sm w-full mt-2 btn-outline btn-neutral lg:hidden">
|
<a href="?member__user__first_name={{ member.user.first_name }}&member__user__last_name={{ member.user.last_name }}" class="btn btn-sm w-full mt-2 btn-outline btn-neutral lg:hidden">
|
||||||
<i class="fa-solid fa-ticket"></i>{% translate "View team memberships" %}
|
<i class="fa-solid fa-ticket"></i>{% translate "View team memberships" %}
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endswitch %}
|
||||||
|
|
||||||
<div class="hidden flex-row items-center mt-8 gap-x-3 hidden lg:flex">
|
<div class="hidden flex-row items-center mt-8 gap-x-3 hidden lg:flex">
|
||||||
{% avatar first_name=member.user.first_name last_name=member.user.last_name %}
|
{% avatar first_name=member.user.first_name last_name=member.user.last_name %}
|
||||||
@@ -72,14 +73,14 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if member.emergency_phone_number %}
|
{% if member.emergency_phone_number %}
|
||||||
<a href="{{ member.emergency_phone_number.as_rfc3966 }}" class="btn btn-outline btn-error"><i class="fa-solid fa-file-medical"></i>{{ member.emergency_phone_number }}</a>
|
<a href="{{ member.emergency_phone_number.as_rfc3966 }}" class="btn btn-outline btn-error"><i class="fa-solid fa-star-of-life"></i>{{ member.emergency_phone_number }}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if config.TF_ENABLE_TEAMS %}
|
{% switch "TF_TEAMS" %}
|
||||||
<a href="?member__user__first_name={{ member.user.first_name }}&member__user__last_name={{ member.user.last_name }}" class="btn btn-outline btn-neutral">
|
<a href="?member__user__first_name={{ member.user.first_name }}&member__user__last_name={{ member.user.last_name }}" class="btn btn-outline btn-neutral">
|
||||||
<i class="fa-solid fa-ticket"></i>{% translate "Team Memberships" %}
|
<i class="fa-solid fa-ticket"></i>{% translate "Team Memberships" %}
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endswitch %}
|
||||||
|
|
||||||
<a href="{% url "backend:members:delete" member.pk %}" class="btn btn-error btn-outline" hx-get="{% url "backend:members:delete" member.pk %}" hx-target="#content">
|
<a href="{% url "backend:members:delete" member.pk %}" class="btn btn-error btn-outline" hx-get="{% url "backend:members:delete" member.pk %}" hx-target="#content">
|
||||||
<i class="fa-solid fa-trash"></i>{% translate "Delete" %}
|
<i class="fa-solid fa-trash"></i>{% translate "Delete" %}
|
||||||
|
|||||||
Reference in New Issue
Block a user