sandwitches 2.4.1__py3-none-any.whl → 2.5.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sandwitches/forms.py +13 -8
- sandwitches/migrations/0016_user_theme.py +21 -0
- sandwitches/migrations/0017_setting_gotify_token_setting_gotify_url.py +31 -0
- sandwitches/models.py +39 -1
- sandwitches/tasks.py +31 -1
- sandwitches/templates/admin/admin_base.html +0 -3
- sandwitches/templates/base.html +1 -1
- sandwitches/templates/base_beer.html +0 -1
- sandwitches/templates/components/navbar.html +0 -6
- sandwitches/templates/components/side_menu.html +4 -0
- sandwitches/templates/components/user_menu.html +1 -0
- sandwitches/templates/profile.html +1 -0
- sandwitches/templates/settings.html +53 -0
- sandwitches/templates/signup.html +0 -12
- sandwitches/urls.py +1 -0
- sandwitches/views.py +28 -0
- {sandwitches-2.4.1.dist-info → sandwitches-2.5.1.dist-info}/METADATA +1 -1
- {sandwitches-2.4.1.dist-info → sandwitches-2.5.1.dist-info}/RECORD +19 -17
- sandwitches/templates/components/language_dialog.html +0 -26
- {sandwitches-2.4.1.dist-info → sandwitches-2.5.1.dist-info}/WHEEL +0 -0
sandwitches/forms.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from django import forms
|
|
2
|
-
from django.conf import settings
|
|
3
2
|
from django.contrib.auth import get_user_model
|
|
4
3
|
from django.contrib.auth.forms import UserCreationForm
|
|
5
4
|
from django.utils.translation import gettext_lazy as _
|
|
@@ -47,11 +46,6 @@ class AdminSetupForm(forms.ModelForm, BaseUserFormMixin):
|
|
|
47
46
|
|
|
48
47
|
|
|
49
48
|
class UserSignupForm(UserCreationForm, BaseUserFormMixin):
|
|
50
|
-
language = forms.ChoiceField(
|
|
51
|
-
choices=settings.LANGUAGES,
|
|
52
|
-
label=_("Preferred language"),
|
|
53
|
-
initial=settings.LANGUAGE_CODE,
|
|
54
|
-
)
|
|
55
49
|
avatar = forms.ImageField(label=_("Profile Image"), required=False)
|
|
56
50
|
bio = forms.CharField(
|
|
57
51
|
widget=forms.Textarea(attrs={"rows": 3}), label=_("Bio"), required=False
|
|
@@ -64,7 +58,6 @@ class UserSignupForm(UserCreationForm, BaseUserFormMixin):
|
|
|
64
58
|
"first_name",
|
|
65
59
|
"last_name",
|
|
66
60
|
"email",
|
|
67
|
-
"language",
|
|
68
61
|
"avatar",
|
|
69
62
|
"bio",
|
|
70
63
|
)
|
|
@@ -77,7 +70,6 @@ class UserSignupForm(UserCreationForm, BaseUserFormMixin):
|
|
|
77
70
|
user.is_superuser = False
|
|
78
71
|
user.is_staff = False
|
|
79
72
|
# Explicitly save the extra fields if they aren't automatically handled by ModelForm save (they should be if in Meta.fields)
|
|
80
|
-
user.language = self.cleaned_data["language"]
|
|
81
73
|
user.avatar = self.cleaned_data["avatar"]
|
|
82
74
|
user.bio = self.cleaned_data["bio"]
|
|
83
75
|
if commit:
|
|
@@ -114,6 +106,16 @@ class UserProfileForm(forms.ModelForm):
|
|
|
114
106
|
return user
|
|
115
107
|
|
|
116
108
|
|
|
109
|
+
class UserSettingsForm(forms.ModelForm):
|
|
110
|
+
class Meta:
|
|
111
|
+
model = User
|
|
112
|
+
fields = ("language", "theme")
|
|
113
|
+
labels = {
|
|
114
|
+
"language": _("Preferred Language"),
|
|
115
|
+
"theme": _("Preferred Theme"),
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
117
119
|
class UserEditForm(forms.ModelForm):
|
|
118
120
|
image_data = forms.CharField(widget=forms.HiddenInput(), required=False)
|
|
119
121
|
|
|
@@ -299,7 +301,10 @@ class SettingForm(forms.ModelForm):
|
|
|
299
301
|
"ai_connection_point",
|
|
300
302
|
"ai_model",
|
|
301
303
|
"ai_api_key",
|
|
304
|
+
"gotify_url",
|
|
305
|
+
"gotify_token",
|
|
302
306
|
]
|
|
303
307
|
widgets = {
|
|
304
308
|
"ai_api_key": forms.PasswordInput(render_value=True),
|
|
309
|
+
"gotify_token": forms.PasswordInput(render_value=True),
|
|
305
310
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Generated by Django 6.0.1 on 2026-01-28 09:08
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
dependencies = [
|
|
8
|
+
("sandwitches", "0015_order_completed_alter_order_status_and_more"),
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
operations = [
|
|
12
|
+
migrations.AddField(
|
|
13
|
+
model_name="user",
|
|
14
|
+
name="theme",
|
|
15
|
+
field=models.CharField(
|
|
16
|
+
choices=[("light", "Light"), ("dark", "Dark")],
|
|
17
|
+
default="light",
|
|
18
|
+
max_length=10,
|
|
19
|
+
),
|
|
20
|
+
),
|
|
21
|
+
]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Generated by Django 6.0.1 on 2026-01-28 12:45
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
dependencies = [
|
|
8
|
+
("sandwitches", "0016_user_theme"),
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
operations = [
|
|
12
|
+
migrations.AddField(
|
|
13
|
+
model_name="setting",
|
|
14
|
+
name="gotify_token",
|
|
15
|
+
field=models.CharField(
|
|
16
|
+
blank=True,
|
|
17
|
+
help_text="The application token for Gotify",
|
|
18
|
+
max_length=255,
|
|
19
|
+
null=True,
|
|
20
|
+
),
|
|
21
|
+
),
|
|
22
|
+
migrations.AddField(
|
|
23
|
+
model_name="setting",
|
|
24
|
+
name="gotify_url",
|
|
25
|
+
field=models.URLField(
|
|
26
|
+
blank=True,
|
|
27
|
+
help_text="The URL of your Gotify server (e.g., https://gotify.example.com)",
|
|
28
|
+
null=True,
|
|
29
|
+
),
|
|
30
|
+
),
|
|
31
|
+
]
|
sandwitches/models.py
CHANGED
|
@@ -4,7 +4,7 @@ from .storage import HashedFilenameStorage
|
|
|
4
4
|
from simple_history.models import HistoricalRecords
|
|
5
5
|
from django.contrib.auth.models import AbstractUser
|
|
6
6
|
from django.db.models import Avg
|
|
7
|
-
from .tasks import email_users, notify_order_submitted
|
|
7
|
+
from .tasks import email_users, notify_order_submitted, send_gotify_notification
|
|
8
8
|
from django.conf import settings
|
|
9
9
|
from django.core.validators import MinValueValidator, MaxValueValidator
|
|
10
10
|
import logging
|
|
@@ -27,6 +27,18 @@ class Setting(SingletonModel):
|
|
|
27
27
|
ai_model = models.CharField(max_length=255, blank=True, null=True)
|
|
28
28
|
ai_api_key = models.CharField(max_length=255, blank=True, null=True)
|
|
29
29
|
|
|
30
|
+
gotify_url = models.URLField(
|
|
31
|
+
blank=True,
|
|
32
|
+
null=True,
|
|
33
|
+
help_text="The URL of your Gotify server (e.g., https://gotify.example.com)",
|
|
34
|
+
)
|
|
35
|
+
gotify_token = models.CharField(
|
|
36
|
+
max_length=255,
|
|
37
|
+
blank=True,
|
|
38
|
+
null=True,
|
|
39
|
+
help_text="The application token for Gotify",
|
|
40
|
+
)
|
|
41
|
+
|
|
30
42
|
def __str__(self):
|
|
31
43
|
return "Site Settings"
|
|
32
44
|
|
|
@@ -50,6 +62,11 @@ class User(AbstractUser):
|
|
|
50
62
|
choices=settings.LANGUAGES,
|
|
51
63
|
default=settings.LANGUAGE_CODE,
|
|
52
64
|
)
|
|
65
|
+
theme = models.CharField(
|
|
66
|
+
max_length=10,
|
|
67
|
+
choices=[("light", "Light"), ("dark", "Dark")],
|
|
68
|
+
default="light",
|
|
69
|
+
)
|
|
53
70
|
favorites = models.ManyToManyField(
|
|
54
71
|
"Recipe", related_name="favorited_by", blank=True
|
|
55
72
|
)
|
|
@@ -61,6 +78,16 @@ class User(AbstractUser):
|
|
|
61
78
|
def __str__(self):
|
|
62
79
|
return self.username
|
|
63
80
|
|
|
81
|
+
def save(self, *args, **kwargs):
|
|
82
|
+
is_new = self.pk is None
|
|
83
|
+
super().save(*args, **kwargs)
|
|
84
|
+
if is_new:
|
|
85
|
+
send_gotify_notification.enqueue(
|
|
86
|
+
title="New User Created",
|
|
87
|
+
message=f"User {self.username} has joined Sandwitches!",
|
|
88
|
+
priority=4,
|
|
89
|
+
)
|
|
90
|
+
|
|
64
91
|
|
|
65
92
|
class Tag(models.Model):
|
|
66
93
|
name = models.CharField(max_length=50, unique=True)
|
|
@@ -173,6 +200,12 @@ class Recipe(models.Model):
|
|
|
173
200
|
logging.warning(
|
|
174
201
|
"Email sending is disabled; not sending email notification, make sure SEND_EMAIL is set to True in settings."
|
|
175
202
|
)
|
|
203
|
+
|
|
204
|
+
send_gotify_notification.enqueue(
|
|
205
|
+
title="New Recipe Uploaded",
|
|
206
|
+
message=f"A new recipe '{self.title}' has been uploaded by {self.uploaded_by or 'Unknown'}.",
|
|
207
|
+
priority=5,
|
|
208
|
+
)
|
|
176
209
|
else:
|
|
177
210
|
logging.debug(
|
|
178
211
|
"Existing recipe saved (update); skipping email notification."
|
|
@@ -282,6 +315,11 @@ class Order(models.Model):
|
|
|
282
315
|
|
|
283
316
|
if is_new:
|
|
284
317
|
notify_order_submitted.enqueue(order_id=self.pk)
|
|
318
|
+
send_gotify_notification.enqueue(
|
|
319
|
+
title="New Order Received",
|
|
320
|
+
message=f"Order #{self.pk} for '{self.recipe.title}' by {self.user.username}. Total: {self.total_price}€",
|
|
321
|
+
priority=6,
|
|
322
|
+
)
|
|
285
323
|
|
|
286
324
|
def __str__(self):
|
|
287
325
|
return f"Order #{self.pk} - {self.user} - {self.recipe}"
|
sandwitches/tasks.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
# from gunicorn.http.wsgi import log
|
|
2
1
|
import logging
|
|
2
|
+
import requests
|
|
3
3
|
|
|
4
4
|
# from django.core.mail import send_mail
|
|
5
5
|
from django_tasks import task
|
|
@@ -109,6 +109,36 @@ def notify_order_submitted(order_id):
|
|
|
109
109
|
logging.info(f"Order confirmation email sent to {user.email} for order {order.id}")
|
|
110
110
|
|
|
111
111
|
|
|
112
|
+
@task(priority=1, queue_name="emails")
|
|
113
|
+
def send_gotify_notification(title, message, priority=5):
|
|
114
|
+
from .models import Setting
|
|
115
|
+
|
|
116
|
+
config = Setting.get_solo()
|
|
117
|
+
url = config.gotify_url
|
|
118
|
+
token = config.gotify_token
|
|
119
|
+
|
|
120
|
+
if not url or not token:
|
|
121
|
+
logging.debug("Gotify URL or Token not configured. Skipping notification.")
|
|
122
|
+
return False
|
|
123
|
+
|
|
124
|
+
try:
|
|
125
|
+
response = requests.post(
|
|
126
|
+
f"{url.rstrip('/')}/message?token={token}",
|
|
127
|
+
json={
|
|
128
|
+
"title": title,
|
|
129
|
+
"message": message,
|
|
130
|
+
"priority": priority,
|
|
131
|
+
},
|
|
132
|
+
timeout=10,
|
|
133
|
+
)
|
|
134
|
+
response.raise_for_status()
|
|
135
|
+
logging.info(f"Gotify notification sent: {title}")
|
|
136
|
+
return True
|
|
137
|
+
except Exception as e:
|
|
138
|
+
logging.error(f"Failed to send Gotify notification: {e}")
|
|
139
|
+
return False
|
|
140
|
+
|
|
141
|
+
|
|
112
142
|
def send_emails(recipe_id, emails):
|
|
113
143
|
from .models import Recipe
|
|
114
144
|
|
|
@@ -30,9 +30,6 @@
|
|
|
30
30
|
<h6 class="max">{% block admin_title %}{% trans "Sandwitches Admin" %}{% endblock %}</h6>
|
|
31
31
|
</a>
|
|
32
32
|
<div class="max"></div>
|
|
33
|
-
<button class="circle transparent" onclick="toggleMode()">
|
|
34
|
-
<i>dark_mode</i>
|
|
35
|
-
</button>
|
|
36
33
|
|
|
37
34
|
{% if user.avatar %}
|
|
38
35
|
<img src="{{ user.avatar.url }}" class="circle" data-ui="#user-menu">
|
sandwitches/templates/base.html
CHANGED
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
</style>
|
|
48
48
|
{% block extra_head %}{% endblock %}
|
|
49
49
|
</head>
|
|
50
|
-
<body class="{% block body_class %}{% endblock %}">
|
|
50
|
+
<body class="{% block body_class %}{% endblock %} {% if user.is_authenticated %}{{ user.theme }}{% endif %}">
|
|
51
51
|
<div id="loading-sandwich" class="loading-sandwich-container">
|
|
52
52
|
<svg class="loading-sandwich-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
53
53
|
<path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z" />
|
|
@@ -7,12 +7,6 @@
|
|
|
7
7
|
<img src="{% static 'icons/icon.svg' %}" class="circle small">
|
|
8
8
|
</a>
|
|
9
9
|
<div class="max"></div>
|
|
10
|
-
<button class="circle transparent" onclick="ui('mode', ui('mode') == 'dark' ? 'light' : 'dark')">
|
|
11
|
-
<i>dark_mode</i>
|
|
12
|
-
</button>
|
|
13
|
-
<button class="circle transparent" data-ui="#language-menu">
|
|
14
|
-
<i>language</i>
|
|
15
|
-
</button>
|
|
16
10
|
|
|
17
11
|
{% if user.is_authenticated %}
|
|
18
12
|
<a href="{% url 'view_cart' %}" class="button circle transparent">
|
|
@@ -19,6 +19,10 @@
|
|
|
19
19
|
<i class="extra padding">group</i>
|
|
20
20
|
<span class="large-text">{% trans "Community" %}</span>
|
|
21
21
|
</a>
|
|
22
|
+
<a href="{% url 'user_settings' %}" class="padding {% if request.resolver_match.url_name == 'user_settings' %}active{% endif %}">
|
|
23
|
+
<i class="extra padding">settings</i>
|
|
24
|
+
<span class="large-text">{% trans "Settings" %}</span>
|
|
25
|
+
</a>
|
|
22
26
|
{% endif %}
|
|
23
27
|
<a href="/api/docs" class="padding">
|
|
24
28
|
<i class="extra padding">api</i>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{% load i18n %}
|
|
2
2
|
{% if user.is_authenticated %}
|
|
3
3
|
<menu id="user-menu" class="no-wrap left">
|
|
4
|
+
<a href="{% url 'user_settings' %}" class="row"><i>settings</i>{% trans "Settings" %}</a>
|
|
4
5
|
{% if user.is_staff %}
|
|
5
6
|
<a href="{% url 'admin_dashboard' %}" class="row"><i>admin_panel_settings</i>{% trans "Admin" %}</a>
|
|
6
7
|
<div class="divider"></div>
|
|
@@ -84,6 +84,7 @@
|
|
|
84
84
|
<div class="large-space"></div>
|
|
85
85
|
|
|
86
86
|
<nav class="right-align">
|
|
87
|
+
<a class="button transparent border round" href="{% url 'user_settings' %}"><i>settings</i> {% trans "Settings" %}</a>
|
|
87
88
|
<a class="button transparent border round" href="{% url 'index' %}">{% trans "Cancel" %}</a>
|
|
88
89
|
<button type="submit" class="button primary round">{% trans "Save changes" %}</button>
|
|
89
90
|
</nav>
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{% extends "base_beer.html" %}
|
|
2
|
+
{% load static i18n %}
|
|
3
|
+
{% block title %}{% trans "Settings" %}{% endblock %}
|
|
4
|
+
|
|
5
|
+
{% block content %}
|
|
6
|
+
<div class="large-space"></div>
|
|
7
|
+
|
|
8
|
+
<div class="grid">
|
|
9
|
+
<div class="s12 m8 l6 xl4 middle-align center-align" style="margin: 0 auto;">
|
|
10
|
+
<article class="round elevate">
|
|
11
|
+
<div class="padding">
|
|
12
|
+
<h4 class="center-align primary-text">{% trans "User Settings" %}</h4>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<form method="post" novalidate>
|
|
16
|
+
{% csrf_token %}
|
|
17
|
+
|
|
18
|
+
<div class="field label border round {% if form.language.errors %}error{% endif %}">
|
|
19
|
+
<select name="{{ form.language.name }}" id="{{ form.language.id_for_label }}">
|
|
20
|
+
{% for value, label in form.language.field.choices %}
|
|
21
|
+
<option value="{{ value }}" {% if form.language.value == value %}selected{% endif %}>{{ label }}</option>
|
|
22
|
+
{% endfor %}
|
|
23
|
+
</select>
|
|
24
|
+
<label>{% trans "Preferred Language" %}</label>
|
|
25
|
+
{% if form.language.errors %}
|
|
26
|
+
<span class="helper error-text">{{ form.language.errors.0 }}</span>
|
|
27
|
+
{% endif %}
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<div class="field label border round {% if form.theme.errors %}error{% endif %}">
|
|
31
|
+
<select name="{{ form.theme.name }}" id="{{ form.theme.id_for_label }}">
|
|
32
|
+
{% for value, label in form.theme.field.choices %}
|
|
33
|
+
<option value="{{ value }}" {% if form.theme.value == value %}selected{% endif %}>{{ label }}</option>
|
|
34
|
+
{% endfor %}
|
|
35
|
+
</select>
|
|
36
|
+
<label>{% trans "Preferred Theme" %}</label>
|
|
37
|
+
{% if form.theme.errors %}
|
|
38
|
+
<span class="helper error-text">{{ form.theme.errors.0 }}</span>
|
|
39
|
+
{% endif %}
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<div class="large-space"></div>
|
|
43
|
+
|
|
44
|
+
<nav class="right-align">
|
|
45
|
+
<a class="button transparent border round" href="{% url 'index' %}">{% trans "Cancel" %}</a>
|
|
46
|
+
<button type="submit" class="button primary round">{% trans "Save changes" %}</button>
|
|
47
|
+
</nav>
|
|
48
|
+
|
|
49
|
+
</form>
|
|
50
|
+
</article>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
{% endblock %}
|
|
@@ -64,18 +64,6 @@
|
|
|
64
64
|
{% endif %}
|
|
65
65
|
</div>
|
|
66
66
|
|
|
67
|
-
<div class="field label border round {% if form.language.errors %}error{% endif %}">
|
|
68
|
-
<select name="{{ form.language.name }}" id="{{ form.language.id_for_label }}">
|
|
69
|
-
{% for value, label in form.language.field.choices %}
|
|
70
|
-
<option value="{{ value }}" {% if form.language.value == value %}selected{% endif %}>{{ label }}</option>
|
|
71
|
-
{% endfor %}
|
|
72
|
-
</select>
|
|
73
|
-
<label>{% trans "Preferred Language" %}</label>
|
|
74
|
-
{% if form.language.errors %}
|
|
75
|
-
<span class="helper error-text">{{ form.language.errors.0 }}</span>
|
|
76
|
-
{% endif %}
|
|
77
|
-
</div>
|
|
78
|
-
|
|
79
67
|
<div class="field label border round textarea {% if form.bio.errors %}error{% endif %}">
|
|
80
68
|
<textarea name="{{ form.bio.name }}" id="{{ form.bio.id_for_label }}" rows="3">{{ form.bio.value|default:'' }}</textarea>
|
|
81
69
|
<label>{% trans "Bio" %}</label>
|
sandwitches/urls.py
CHANGED
|
@@ -34,6 +34,7 @@ urlpatterns = [
|
|
|
34
34
|
path("login/", views.CustomLoginView.as_view(), name="login"),
|
|
35
35
|
path("logout/", LogoutView.as_view(next_page="index"), name="logout"),
|
|
36
36
|
path("profile/", views.user_profile, name="user_profile"),
|
|
37
|
+
path("settings/", views.user_settings, name="user_settings"),
|
|
37
38
|
path("orders/<int:pk>/", views.user_order_detail, name="user_order_detail"),
|
|
38
39
|
path("community/", views.community, name="community"),
|
|
39
40
|
path("admin/", admin.site.urls),
|
sandwitches/views.py
CHANGED
|
@@ -8,6 +8,7 @@ from django.contrib.auth import get_user_model
|
|
|
8
8
|
from django.contrib.auth.decorators import login_required
|
|
9
9
|
from django.contrib.admin.views.decorators import staff_member_required
|
|
10
10
|
from django.utils.translation import gettext as _
|
|
11
|
+
from django.utils import translation
|
|
11
12
|
from .models import Recipe, Rating, Tag, Order, CartItem
|
|
12
13
|
from .forms import (
|
|
13
14
|
RecipeForm,
|
|
@@ -18,6 +19,7 @@ from .forms import (
|
|
|
18
19
|
TagForm,
|
|
19
20
|
UserProfileForm,
|
|
20
21
|
UserRecipeSubmissionForm,
|
|
22
|
+
UserSettingsForm,
|
|
21
23
|
)
|
|
22
24
|
from django.http import HttpResponseBadRequest, Http404
|
|
23
25
|
from django.conf import settings
|
|
@@ -898,6 +900,32 @@ def user_profile(request):
|
|
|
898
900
|
)
|
|
899
901
|
|
|
900
902
|
|
|
903
|
+
@login_required
|
|
904
|
+
def user_settings(request):
|
|
905
|
+
if request.method == "POST":
|
|
906
|
+
form = UserSettingsForm(request.POST, instance=request.user)
|
|
907
|
+
if form.is_valid():
|
|
908
|
+
user = form.save()
|
|
909
|
+
# Update language in session and cookie
|
|
910
|
+
translation.activate(user.language)
|
|
911
|
+
request.session[translation.LANGUAGE_SESSION_KEY] = user.language # ty:ignore[unresolved-attribute]
|
|
912
|
+
messages.success(request, _("Settings updated successfully."))
|
|
913
|
+
response = redirect("user_settings")
|
|
914
|
+
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, user.language)
|
|
915
|
+
return response
|
|
916
|
+
else:
|
|
917
|
+
form = UserSettingsForm(instance=request.user)
|
|
918
|
+
|
|
919
|
+
return render(
|
|
920
|
+
request,
|
|
921
|
+
"settings.html",
|
|
922
|
+
{
|
|
923
|
+
"form": form,
|
|
924
|
+
"version": sandwitches_version,
|
|
925
|
+
},
|
|
926
|
+
)
|
|
927
|
+
|
|
928
|
+
|
|
901
929
|
@login_required
|
|
902
930
|
def user_order_detail(request, pk):
|
|
903
931
|
order = get_object_or_404(Order, pk=pk, user=request.user)
|
|
@@ -3,7 +3,7 @@ sandwitches/admin.py,sha256=-4QA5InEvLHyb6VFAGKapWbJO9mXdiV4GeQcGsM4xlI,2510
|
|
|
3
3
|
sandwitches/api.py,sha256=ruD5QeOPY-l9PvkJQiaOYoI0sRARDpqpFrFDgBxo9cQ,6389
|
|
4
4
|
sandwitches/asgi.py,sha256=cygnXdXSSVspM7ZXuj47Ef6oz7HSTw4D7BPzgE2PU5w,399
|
|
5
5
|
sandwitches/feeds.py,sha256=iz1d11dV0utA0ZNsB7VIAp0h8Zr5mFNSKJWHbw_j6YM,683
|
|
6
|
-
sandwitches/forms.py,sha256=
|
|
6
|
+
sandwitches/forms.py,sha256=yTiPRw5tknik8D5_8p5FM8cxuTtU5P18v3-tsgHi5kM,9637
|
|
7
7
|
sandwitches/locale/nl/LC_MESSAGES/django.mo,sha256=EzQWzIhz_Na3w9AS7F-YjB-Xv63t4sMRSAkEQ1-g32M,5965
|
|
8
8
|
sandwitches/locale/nl/LC_MESSAGES/django.po,sha256=znxspEoMwkmktusZtbVrt1KG1LDUwIEi4ZEIE3XGeoI,25904
|
|
9
9
|
sandwitches/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -24,12 +24,14 @@ sandwitches/migrations/0012_rename_is_community_made_historicalrecipe_is_approve
|
|
|
24
24
|
sandwitches/migrations/0013_cartitem.py,sha256=KYMinpnZiLHwjo7p7EdJHQExuEGC9jtpcZcbm1r7JFo,1787
|
|
25
25
|
sandwitches/migrations/0014_ensure_groups_exist.py,sha256=5FSA742bEQtwHZl5CWZQYIdmS8FBxMgWS079dOaOltY,564
|
|
26
26
|
sandwitches/migrations/0015_order_completed_alter_order_status_and_more.py,sha256=PTXQZUE8RqTAK8l0vkZhiGKv2T0PDiWEue7f6qz3AQ0,1670
|
|
27
|
+
sandwitches/migrations/0016_user_theme.py,sha256=2tJnT6Bjd6fuwLAr2J47IXTfmmde1BpPGM_1HB37sSg,537
|
|
28
|
+
sandwitches/migrations/0017_setting_gotify_token_setting_gotify_url.py,sha256=ABebUfj92uZcRg9XnAz-W_am74l9qjrg_vwDKaMjjBc,839
|
|
27
29
|
sandwitches/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
|
-
sandwitches/models.py,sha256=
|
|
30
|
+
sandwitches/models.py,sha256=L8qMFoJ7WpIito2nTgsAB8s-UPUQMwDux63aKbP71aE,12468
|
|
29
31
|
sandwitches/settings.py,sha256=5_eQAJCAV093hnhr3XOxHekT4IF-PEJcRiTecq71_SQ,5841
|
|
30
32
|
sandwitches/storage.py,sha256=ibBG6tVtArqzgEKsRimZPwsqW7i9j4WiPLLHrOJchow,3578
|
|
31
|
-
sandwitches/tasks.py,sha256=
|
|
32
|
-
sandwitches/templates/admin/admin_base.html,sha256=
|
|
33
|
+
sandwitches/tasks.py,sha256=cGPgEqxGOCwliIq0oxNZBGjnCtvrTdJN-XyIp1ciJ3k,6865
|
|
34
|
+
sandwitches/templates/admin/admin_base.html,sha256=kpVZkoeDQMqhpxqdKbQ4-t0qqJ3cbFM9LojWY5s8qKk,4403
|
|
33
35
|
sandwitches/templates/admin/confirm_delete.html,sha256=HfsZI_gV8JQTKz215TYgPWBrgrFhGv1UB3N-0Hln-14,804
|
|
34
36
|
sandwitches/templates/admin/dashboard.html,sha256=Ial8zH2odIPpstSkQmzGrasl0QxvgGhFPAGy7V5xRzY,5916
|
|
35
37
|
sandwitches/templates/admin/order_list.html,sha256=eHFUn2speXaaj5_SFUG0Z0HfWVUR9-VCDRBeb8ufFb0,819
|
|
@@ -45,8 +47,8 @@ sandwitches/templates/admin/task_detail.html,sha256=dO5zHOG-yTY1ly3VPA3o3jjie0wm
|
|
|
45
47
|
sandwitches/templates/admin/task_list.html,sha256=3YF7YQ3nbXnWjApKeA07Z7HkhdMuH4s6sLoN7gwg0eE,1535
|
|
46
48
|
sandwitches/templates/admin/user_form.html,sha256=7_6GShLROFeJJexL1XLFUXdW9_lYF87eT6cigB5bQo4,1314
|
|
47
49
|
sandwitches/templates/admin/user_list.html,sha256=6O1YctULY-tqJnagybJof9ERA_NL1LX_a8cAu6_aWVQ,2193
|
|
48
|
-
sandwitches/templates/base.html,sha256=
|
|
49
|
-
sandwitches/templates/base_beer.html,sha256=
|
|
50
|
+
sandwitches/templates/base.html,sha256=4IkEdeEksQ9o4Ad72osMgMVnzz14aJa8WKg9HE3F0MU,3655
|
|
51
|
+
sandwitches/templates/base_beer.html,sha256=7dWwGOUEdBz19X3Rilbam1xSNkQqXqvC6cYrDdQvYIE,2025
|
|
50
52
|
sandwitches/templates/cart.html,sha256=YqmrzOLLPAXSqeXeUTrt9AwTTWOitOLTaD_k3mYYVpM,4537
|
|
51
53
|
sandwitches/templates/community.html,sha256=-YhpPtLbrVK9mc2Go1XBInLK-7OXrtb7kKukjl7rGbg,9607
|
|
52
54
|
sandwitches/templates/components/carousel_scripts.html,sha256=9vEL5JJv8zUUjEtsnHW-BwwXUNWqQ6w_vf6UdxgEv_I,1934
|
|
@@ -55,30 +57,30 @@ sandwitches/templates/components/footer.html,sha256=Qk-myRtXS6-1b3fMowVGnSuFb_Uk
|
|
|
55
57
|
sandwitches/templates/components/ingredients_scripts.html,sha256=2zKTC65GYF589uW1sCpDq0jOkS3BnsuOwUpJbbigrn4,1794
|
|
56
58
|
sandwitches/templates/components/ingredients_section.html,sha256=XsaVXTs9MIwjfJeLjlzah3GWWj8oFU-_HJd9i9l1HAo,665
|
|
57
59
|
sandwitches/templates/components/instructions_section.html,sha256=RFlA4uPiI6vf1e2QgiD5KzGoy7Vg7y7nFY7TFabCYLA,277
|
|
58
|
-
sandwitches/templates/components/
|
|
59
|
-
sandwitches/templates/components/navbar.html,sha256=t-ZWvd9Z3UQRR2RswcsRXRNbygiesOD0Bh1jhmm2vEY,1396
|
|
60
|
+
sandwitches/templates/components/navbar.html,sha256=UO0F4J_yDTOGo-C7thNNZu_9IJ0t1pDyu5mwm9L-Ql8,1166
|
|
60
61
|
sandwitches/templates/components/rating_section.html,sha256=8O5IsFfQwnElMQZLnDpJiuCvvQMLa3jCS67u_RhMi7o,2717
|
|
61
62
|
sandwitches/templates/components/recipe_header.html,sha256=U6CxuR275QD9TIqo3VQftqvV6tqmH1rJdDcQotnXxYM,2001
|
|
62
63
|
sandwitches/templates/components/search_form.html,sha256=B8579Jo44gLrlmvkkc2-Vuv_QD93Ljt6F2J1WgTDV60,6617
|
|
63
64
|
sandwitches/templates/components/search_scripts.html,sha256=HvsO5e50DoTZeoFiYeNP5S8S5h7Zfr9VULOWKKR1i_M,3423
|
|
64
|
-
sandwitches/templates/components/side_menu.html,sha256=
|
|
65
|
-
sandwitches/templates/components/user_menu.html,sha256=
|
|
65
|
+
sandwitches/templates/components/side_menu.html,sha256=FMy-gwjBh4JjMD8XcQ1nHBzf6_YoxY97flrafIN30RY,2055
|
|
66
|
+
sandwitches/templates/components/user_menu.html,sha256=KV_0gtvWbo3nvKZQ0peSZDtB3GgVuOyeBdar-wmwsDg,461
|
|
66
67
|
sandwitches/templates/detail.html,sha256=g-O_RsW9Ix9ivWC0nZ4FwHY2NhgYZ3bEGLpqGY0JSxg,5642
|
|
67
68
|
sandwitches/templates/favorites.html,sha256=0cPpW07N6Isrb8XpvA5Eh97L2-12QFZ43EzeJvbOlXo,917
|
|
68
69
|
sandwitches/templates/index.html,sha256=7anU7k8s80JYk59Rwsm8EdlNYd7B5clCvV7pKq2IUy0,2518
|
|
69
70
|
sandwitches/templates/login.html,sha256=LiQskhkOkfx0EE4ssA1ToqQ3oEll08OPYLDIkLjHfU8,2177
|
|
70
71
|
sandwitches/templates/order_detail.html,sha256=D6MjUVibQuED2VRNHSjKVnLHcLgFtLvcVmuwlzfoJzo,2498
|
|
71
72
|
sandwitches/templates/partials/recipe_list.html,sha256=LUHKFKG90D72K9X2X3d1osvj2jX1QU_MbPe0lNwRSII,4555
|
|
72
|
-
sandwitches/templates/profile.html,sha256=
|
|
73
|
+
sandwitches/templates/profile.html,sha256=9Sj0UjbUNmWHEG9Nnc95LK5P3Gl86FqsnikDsubJERY,8670
|
|
74
|
+
sandwitches/templates/settings.html,sha256=Q3dwXdwiNgPxevfArjiHhIu-wCsQaii2Uymf_CqbWWg,2121
|
|
73
75
|
sandwitches/templates/setup.html,sha256=iNveFgePATsCSO4XMbGPa8TnWHyvj8S_5WwcW6i7pbo,4661
|
|
74
|
-
sandwitches/templates/signup.html,sha256=
|
|
76
|
+
sandwitches/templates/signup.html,sha256=wVRyj6Sy1z5TRvJDT9ufEOp8-tKbW44Fzer4SYq9AGw,5518
|
|
75
77
|
sandwitches/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
76
78
|
sandwitches/templatetags/custom_filters.py,sha256=0KDFlFz4b5LwlcURBAmzyYWKKea-LwydZytJGVkkuKA,243
|
|
77
79
|
sandwitches/templatetags/markdown_extras.py,sha256=0ibmRzxE3r85x4k7kK71R-9UT0CgeegYF7MHzj3juTI,344
|
|
78
|
-
sandwitches/urls.py,sha256=
|
|
80
|
+
sandwitches/urls.py,sha256=0p7MpYranWc4qNPyInxNzg8J3vNhap_gdt2n892exJM,5006
|
|
79
81
|
sandwitches/utils.py,sha256=SJP-TkeRZ0OIfaMigYrOSbxRqYXswoqoWhwll3nFuAM,7245
|
|
80
|
-
sandwitches/views.py,sha256=
|
|
82
|
+
sandwitches/views.py,sha256=Bv05_8qEbuD_f3EkiR-2PAIx0XbJCNvoR3ZeOz6Yfqg,33078
|
|
81
83
|
sandwitches/wsgi.py,sha256=Eyncpnahq_4s3Lr9ruB-R3Lu9j9zBXqgPbUj7qhIbwU,399
|
|
82
|
-
sandwitches-2.
|
|
83
|
-
sandwitches-2.
|
|
84
|
-
sandwitches-2.
|
|
84
|
+
sandwitches-2.5.1.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
|
|
85
|
+
sandwitches-2.5.1.dist-info/METADATA,sha256=MejRoFtbhF27QtmgWJdRgvkBdMjZ4wIq4NNTMbEq6ns,3111
|
|
86
|
+
sandwitches-2.5.1.dist-info/RECORD,,
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
{% load i18n %}
|
|
2
|
-
<dialog id="language-menu">
|
|
3
|
-
<form method="post" action="{% url 'set_language' %}">
|
|
4
|
-
{% csrf_token %}
|
|
5
|
-
<h5 class="center-align">{% trans "Select Language" %}</h5>
|
|
6
|
-
<div class="grid center-align">
|
|
7
|
-
{% get_current_language as LANGUAGE_CODE %}
|
|
8
|
-
{% get_available_languages as LANGUAGES %}
|
|
9
|
-
{% for code, name in LANGUAGES %}
|
|
10
|
-
<div class="s6">
|
|
11
|
-
<button type="submit" name="language" value="{{ code }}" class="circle large {% if code == LANGUAGE_CODE %}primary{% else %}surface{% endif %}">
|
|
12
|
-
<span style="font-size: 2rem;">
|
|
13
|
-
{% if code == 'en' %}🇬🇧{% elif code == 'nl' %}🇳🇱{% else %}🌐{% endif %}
|
|
14
|
-
</span>
|
|
15
|
-
</button>
|
|
16
|
-
<div class="small-text">{{ name }}</div>
|
|
17
|
-
</div>
|
|
18
|
-
{% endfor %}
|
|
19
|
-
</div>
|
|
20
|
-
<input type="hidden" name="next" value="{{ request.get_full_path }}" />
|
|
21
|
-
</form>
|
|
22
|
-
<div class="space"></div>
|
|
23
|
-
<nav class="center-align">
|
|
24
|
-
<button class="transparent link" data-ui="#language-menu">{% trans "Close" %}</button>
|
|
25
|
-
</nav>
|
|
26
|
-
</dialog>
|
|
File without changes
|