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 = "*"
django-taggit = "*"
django-qr-code = "*"
django-dbsettings = "*"
[dev-packages]
coveralls = "*"

View File

@ -6,22 +6,7 @@ from django.contrib.auth.forms import PasswordChangeForm, UserCreationForm
from django.contrib.auth.models import Group
from django.utils.translation import gettext_lazy as _
from core.widgets import TimeInput
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(),
}
from .models import Settings
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
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())
def create_user_settings(sender, instance, created, **kwargs):
if created:

View File

@ -37,6 +37,7 @@ INSTALLED_APPS = [
"storages",
"import_export",
"qr_code",
"dbsettings",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
@ -353,7 +354,5 @@ DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
BABY_BUDDY = {
"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",
}

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>
<a href="{% url 'api:api-root' %}" class="dropdown-item">{% trans "API Browser" %}</a>
{% if request.user.is_staff %}
<a href="{% url 'babybuddy:site-settings-update' %}"
<a href="{% url 'babybuddy:site_settings' %}"
class="dropdown-item">{% trans "Settings" %}</a>
<a href="{% url 'babybuddy:user-list' %}"
class="dropdown-item">{% trans "Users" %}</a>

View File

@ -35,7 +35,6 @@ app_patterns = [
name="password_reset_complete",
),
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("users/", views.UserList.as_view(), name="user-list"),
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/settings/", views.UserSettings.as_view(), name="user-settings"),
path("user/add-device/", views.UserAddDevice.as_view(), name="user-add-device"),
path("settings/", include("dbsettings.urls")),
]
urlpatterns = [

View File

@ -37,7 +37,6 @@ from django_filters.views import FilterView
from babybuddy import forms
from babybuddy.mixins import LoginRequiredMixin, PermissionRequiredMixin, StaffOnlyMixin
from babybuddy.models import SiteSettings
def csrf_failure(request, reason=""):
@ -96,17 +95,6 @@ class LogoutView(LogoutViewBase):
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):
model = get_user_model()
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 babybuddy.widgets import DateInput, DateTimeInput
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):

View File

@ -2,7 +2,6 @@
import re
from datetime import timedelta
from django.conf import settings
from django.core.cache import cache
from django.core.exceptions import ValidationError
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.models import GenericTaggedItemBase, TagBase
from babybuddy.site_settings import NapSettings
from core.utils import random_color
@ -477,6 +477,7 @@ class Sleep(models.Model):
objects = models.Manager()
naps = NapsManager()
settings = NapSettings(_("Nap settings"))
class Meta:
default_permissions = ("view", "add", "change", "delete")
@ -489,14 +490,12 @@ class Sleep(models.Model):
@property
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()
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):
if self.start and self.end:

View File

@ -104,29 +104,3 @@ class ChildRadioSelect(RadioSelect):
if value != "":
option["picture"] = value.instance.picture
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).
## `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`
*Default:* `None`