Use django-dbsettings package for site settings

This commit is contained in:
Christopher C. Wells 2023-04-15 13:59:44 -07:00
parent 2007f998cf
commit 694bb3f811
14 changed files with 72 additions and 151 deletions

View File

@ -25,6 +25,7 @@ uritemplate = "*"
whitenoise = "*" whitenoise = "*"
django-taggit = "*" django-taggit = "*"
django-qr-code = "*" django-qr-code = "*"
django-dbsettings = "*"
[dev-packages] [dev-packages]
coveralls = "*" coveralls = "*"

View File

@ -6,22 +6,7 @@ from django.contrib.auth.forms import PasswordChangeForm, UserCreationForm
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from core.widgets import TimeInput from .models import Settings
from .models import Settings, SiteSettings
class SiteSettingsForm(forms.ModelForm):
class Meta:
model = SiteSettings
fields = [
"nap_start_min",
"nap_start_max",
]
widgets = {
"nap_start_min": TimeInput(),
"nap_start_max": TimeInput(),
}
class BabyBuddyUserForm(forms.ModelForm): class BabyBuddyUserForm(forms.ModelForm):

View File

@ -1,44 +0,0 @@
# Generated by Django 4.0.7 on 2022-08-14 23:28
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("babybuddy", "0027_remove_standard_group"),
]
operations = [
migrations.CreateModel(
name="SiteSettings",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"nap_start_min",
models.TimeField(
blank=True,
help_text="The minimum default time that a sleep entry is consider a nap.If set the nap property will be preselected if the starttime is within the bounds.",
null=True,
verbose_name="Default minimum nap start time",
),
),
(
"nap_start_max",
models.TimeField(
blank=True,
help_text="The maximum default time that a sleep entry is consider a nap.If set the nap property will be preselected if the starttime is within the bounds.",
null=True,
verbose_name="Default maximum nap start time",
),
),
],
),
]

View File

@ -94,32 +94,6 @@ class Settings(models.Model):
return None return None
class SiteSettings(models.Model):
nap_start_min = models.TimeField(
verbose_name=_("Default minimum nap start time"),
help_text=_(
"The minimum default time that a sleep entry is consider a nap."
"If set the nap property will be preselected if the start"
"time is within the bounds."
),
blank=True,
null=True,
)
nap_start_max = models.TimeField(
verbose_name=_("Default maximum nap start time"),
help_text=_(
"The maximum default time that a sleep entry is consider a nap."
"If set the nap property will be preselected if the start"
"time is within the bounds."
),
blank=True,
null=True,
)
def __str__(self):
return _("Site Settings")
@receiver(post_save, sender=get_user_model()) @receiver(post_save, sender=get_user_model())
def create_user_settings(sender, instance, created, **kwargs): def create_user_settings(sender, instance, created, **kwargs):
if created: if created:

View File

@ -37,6 +37,7 @@ INSTALLED_APPS = [
"storages", "storages",
"import_export", "import_export",
"qr_code", "qr_code",
"dbsettings",
"django.contrib.admin", "django.contrib.admin",
"django.contrib.auth", "django.contrib.auth",
"django.contrib.contenttypes", "django.contrib.contenttypes",
@ -353,7 +354,5 @@ DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
BABY_BUDDY = { BABY_BUDDY = {
"ALLOW_UPLOADS": bool(strtobool(os.environ.get("ALLOW_UPLOADS") or "True")), "ALLOW_UPLOADS": bool(strtobool(os.environ.get("ALLOW_UPLOADS") or "True")),
"NAP_START_MAX": os.environ.get("NAP_START_MAX") or "18:00",
"NAP_START_MIN": os.environ.get("NAP_START_MIN") or "06:00",
"READ_ONLY_GROUP_NAME": "read_only", "READ_ONLY_GROUP_NAME": "read_only",
} }

View File

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
from datetime import time
from django.utils.translation import gettext_lazy as _
import dbsettings
from .widgets import TimeInput
class NapSettings(dbsettings.Group):
nap_start_min = dbsettings.TimeValue(
default=time(6),
description=_("Default minimum nap start time"),
help_text=_(
"The minimum default time that a sleep entry is consider a nap. If set the "
"nap property will be preselected if the start time is within the bounds."
),
widget=TimeInput,
)
nap_start_max = dbsettings.TimeValue(
default=time(18),
description=_("Default maximum nap start time"),
help_text=_(
"The maximum default time that a sleep entry is consider a nap. If set the "
"nap property will be preselected if the start time is within the bounds."
),
widget=TimeInput,
)

View File

@ -336,7 +336,7 @@
<h6 class="dropdown-header">{% trans "Site" %}</h6> <h6 class="dropdown-header">{% trans "Site" %}</h6>
<a href="{% url 'api:api-root' %}" class="dropdown-item">{% trans "API Browser" %}</a> <a href="{% url 'api:api-root' %}" class="dropdown-item">{% trans "API Browser" %}</a>
{% if request.user.is_staff %} {% if request.user.is_staff %}
<a href="{% url 'babybuddy:site-settings-update' %}" <a href="{% url 'babybuddy:site_settings' %}"
class="dropdown-item">{% trans "Settings" %}</a> class="dropdown-item">{% trans "Settings" %}</a>
<a href="{% url 'babybuddy:user-list' %}" <a href="{% url 'babybuddy:user-list' %}"
class="dropdown-item">{% trans "Users" %}</a> class="dropdown-item">{% trans "Users" %}</a>

View File

@ -35,7 +35,6 @@ app_patterns = [
name="password_reset_complete", name="password_reset_complete",
), ),
path("", views.RootRouter.as_view(), name="root-router"), path("", views.RootRouter.as_view(), name="root-router"),
path("settings/", views.SiteSettingsUpdate.as_view(), name="site-settings-update"),
path("welcome/", views.Welcome.as_view(), name="welcome"), path("welcome/", views.Welcome.as_view(), name="welcome"),
path("users/", views.UserList.as_view(), name="user-list"), path("users/", views.UserList.as_view(), name="user-list"),
path("users/add/", views.UserAdd.as_view(), name="user-add"), path("users/add/", views.UserAdd.as_view(), name="user-add"),
@ -45,6 +44,7 @@ app_patterns = [
path("user/password/", views.UserPassword.as_view(), name="user-password"), path("user/password/", views.UserPassword.as_view(), name="user-password"),
path("user/settings/", views.UserSettings.as_view(), name="user-settings"), path("user/settings/", views.UserSettings.as_view(), name="user-settings"),
path("user/add-device/", views.UserAddDevice.as_view(), name="user-add-device"), path("user/add-device/", views.UserAddDevice.as_view(), name="user-add-device"),
path("settings/", include("dbsettings.urls")),
] ]
urlpatterns = [ urlpatterns = [

View File

@ -37,7 +37,6 @@ from django_filters.views import FilterView
from babybuddy import forms from babybuddy import forms
from babybuddy.mixins import LoginRequiredMixin, PermissionRequiredMixin, StaffOnlyMixin from babybuddy.mixins import LoginRequiredMixin, PermissionRequiredMixin, StaffOnlyMixin
from babybuddy.models import SiteSettings
def csrf_failure(request, reason=""): def csrf_failure(request, reason=""):
@ -96,17 +95,6 @@ class LogoutView(LogoutViewBase):
pass pass
class SiteSettingsUpdate(StaffOnlyMixin, SuccessMessageMixin, UpdateView):
model = SiteSettings
template_name = "babybuddy/site_settings_form.html"
form_class = forms.SiteSettingsForm
success_url = reverse_lazy("babybuddy:site-settings-update")
success_message = gettext_lazy("Site settings updated.")
def get_object(self, queryset=None):
return SiteSettings.objects.get_or_create(pk=1)[0]
class UserList(StaffOnlyMixin, BabyBuddyFilterView): class UserList(StaffOnlyMixin, BabyBuddyFilterView):
model = get_user_model() model = get_user_model()
template_name = "babybuddy/user_list.html" template_name = "babybuddy/user_list.html"

29
babybuddy/widgets.py Normal file
View File

@ -0,0 +1,29 @@
import datetime
from django.forms import widgets
class DateTimeBaseInput(widgets.DateTimeBaseInput):
def format_value(self, value):
if isinstance(value, datetime.datetime):
value = value.isoformat()
return value
class DateTimeInput(DateTimeBaseInput):
input_type = "datetime-local"
def build_attrs(self, base_attrs, extra_attrs=None):
attrs = super().build_attrs(base_attrs, extra_attrs)
# Default to seconds granularity. Required for client validation in Safari.
if "step" not in attrs:
attrs["step"] = 1
return attrs
class DateInput(DateTimeBaseInput):
input_type = "date"
class TimeInput(DateTimeBaseInput):
input_type = "time"

View File

@ -7,8 +7,9 @@ from django.utils.translation import gettext as _
from taggit.forms import TagField from taggit.forms import TagField
from babybuddy.widgets import DateInput, DateTimeInput
from core import models from core import models
from core.widgets import TagsEditor, ChildRadioSelect, DateInput, DateTimeInput from core.widgets import TagsEditor, ChildRadioSelect
def set_initial_values(kwargs, form_type): def set_initial_values(kwargs, form_type):

View File

@ -2,7 +2,6 @@
import re import re
from datetime import timedelta from datetime import timedelta
from django.conf import settings
from django.core.cache import cache from django.core.cache import cache
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator from django.core.validators import RegexValidator
@ -13,6 +12,7 @@ from django.utils.translation import gettext_lazy as _
from taggit.managers import TaggableManager as TaggitTaggableManager from taggit.managers import TaggableManager as TaggitTaggableManager
from taggit.models import GenericTaggedItemBase, TagBase from taggit.models import GenericTaggedItemBase, TagBase
from babybuddy.site_settings import NapSettings
from core.utils import random_color from core.utils import random_color
@ -477,6 +477,7 @@ class Sleep(models.Model):
objects = models.Manager() objects = models.Manager()
naps = NapsManager() naps = NapsManager()
settings = NapSettings(_("Nap settings"))
class Meta: class Meta:
default_permissions = ("view", "add", "change", "delete") default_permissions = ("view", "add", "change", "delete")
@ -489,14 +490,12 @@ class Sleep(models.Model):
@property @property
def nap(self): def nap(self):
nap_start_min = timezone.datetime.strptime(
settings.BABY_BUDDY["NAP_START_MIN"], "%H:%M"
).time()
nap_start_max = timezone.datetime.strptime(
settings.BABY_BUDDY["NAP_START_MAX"], "%H:%M"
).time()
local_start_time = timezone.localtime(self.start).time() local_start_time = timezone.localtime(self.start).time()
return nap_start_min <= local_start_time <= nap_start_max return (
Sleep.settings.nap_start_min
<= local_start_time
<= Sleep.settings.nap_start_max
)
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if self.start and self.end: if self.start and self.end:

View File

@ -104,29 +104,3 @@ class ChildRadioSelect(RadioSelect):
if value != "": if value != "":
option["picture"] = value.instance.picture option["picture"] = value.instance.picture
return option return option
class DateTimeBaseInput(widgets.DateTimeBaseInput):
def format_value(self, value):
if isinstance(value, datetime.datetime):
value = value.isoformat()
return value
class DateTimeInput(DateTimeBaseInput):
input_type = "datetime-local"
def build_attrs(self, base_attrs, extra_attrs=None):
attrs = super().build_attrs(base_attrs, extra_attrs)
# Default to seconds granularity. Required for client validation in Safari.
if "step" not in attrs:
attrs["step"] = 1
return attrs
class DateInput(DateTimeBaseInput):
input_type = "date"
class TimeInput(DateTimeBaseInput):
input_type = "time"

View File

@ -9,20 +9,6 @@ for exceptions. This setting should be *False* in production deployments.
See also [Django's documentation on the DEBUG setting](https://docs.djangoproject.com/en/4.0/ref/settings/#debug). See also [Django's documentation on the DEBUG setting](https://docs.djangoproject.com/en/4.0/ref/settings/#debug).
## `NAP_START_MAX`
*Default:* `18:00`
The maximum nap *start* time (in the instance's time zone). Expects the 24-hour
format %H:%M.
## `NAP_START_MIN`
*Default:* `06:00`
The minimum nap *start* time (in the instance's time zone). Expects the 24-hour
format %H:%M.
## `SUB_PATH` ## `SUB_PATH`
*Default:* `None` *Default:* `None`