mirror of https://github.com/snachodog/mybuddy.git
Use django-dbsettings package for site settings
This commit is contained in:
parent
2007f998cf
commit
694bb3f811
1
Pipfile
1
Pipfile
|
@ -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 = "*"
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -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:
|
||||||
|
|
|
@ -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",
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
)
|
|
@ -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>
|
||||||
|
|
|
@ -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 = [
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
|
@ -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):
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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"
|
|
||||||
|
|
|
@ -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`
|
||||||
|
|
Loading…
Reference in New Issue