sandwitches 1.1.0__py3-none-any.whl → 1.2.0__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.
@@ -1,12 +1,12 @@
1
1
  {% extends "base_pico.html" %}
2
- {% load static %}
3
- {% block title %}Sign Up{% endblock %}
2
+ {% load static i18n %}
3
+ {% block title %}{% trans "Sign Up" %}{% endblock %}
4
4
 
5
5
  {% block content %}
6
6
  <div class="container" style="max-width:720px; margin:2rem auto;">
7
7
  <article class="card">
8
8
  <div class="card-body">
9
- <h2>Sign up</h2>
9
+ <h2>{% trans "Sign up" %}</h2>
10
10
 
11
11
  <form method="post" novalidate>
12
12
  {% csrf_token %}
@@ -20,27 +20,27 @@
20
20
  </div>
21
21
  {% endif %}
22
22
 
23
- <label for="{{ form.username.id_for_label }}">Username</label>
23
+ <label for="{{ form.username.id_for_label }}">{% trans "Username" %}</label>
24
24
  {{ form.username }}
25
25
 
26
- <label for="{{ form.email.id_for_label }}">Email (optional)</label>
26
+ <label for="{{ form.email.id_for_label }}">{% trans "Email (optional)" %}</label>
27
27
  {{ form.email }}
28
28
 
29
- <label for="{{ form.first_name.id_for_label }}">First name</label>
29
+ <label for="{{ form.first_name.id_for_label }}">{% trans "First name" %}</label>
30
30
  {{ form.first_name }}
31
31
 
32
- <label for="{{ form.last_name.id_for_label }}">Last name</label>
32
+ <label for="{{ form.last_name.id_for_label }}">{% trans "Last name" %}</label>
33
33
  {{ form.last_name }}
34
34
 
35
- <label for="{{ form.password1.id_for_label }}">Password</label>
35
+ <label for="{{ form.password1.id_for_label }}">{% trans "Password" %}</label>
36
36
  {{ form.password1 }}
37
37
 
38
- <label for="{{ form.password2.id_for_label }}">Confirm password</label>
38
+ <label for="{{ form.password2.id_for_label }}">{% trans "Confirm password" %}</label>
39
39
  {{ form.password2 }}
40
40
 
41
41
  <p style="margin-top:1rem;">
42
- <button type="submit">Sign Up</button>
43
- <a class="contrast" href="{% url 'index' %}">Cancel</a>
42
+ <button type="submit">{% trans "Sign Up" %}</button>
43
+ <a class="contrast" href="{% url 'index' %}">{% trans "Cancel" %}</a>
44
44
  </p>
45
45
  </form>
46
46
  </div>
sandwitches/urls.py CHANGED
@@ -16,27 +16,31 @@ Including another URLconf
16
16
  """
17
17
 
18
18
  from django.contrib import admin
19
- from django.urls import path
19
+ from django.urls import path, include
20
20
  from . import views
21
21
  from .api import api
22
+ from django.conf.urls.i18n import i18n_patterns
22
23
 
23
24
 
24
- from django.conf import settings
25
- from django.conf.urls.static import static
26
- from debug_toolbar.toolbar import debug_toolbar_urls
27
25
  import os
28
26
  import sys
29
27
 
30
28
 
31
29
  urlpatterns = [
32
- path("", views.index, name="index"),
30
+ path("i18n/", include("django.conf.urls.i18n")),
31
+ path("signup/", views.signup, name="signup"),
33
32
  path("admin/", admin.site.urls),
33
+ path("api/", api.urls),
34
+ path("media/<path:file_path>", views.media, name="media"),
35
+ path("", views.index, name="index"),
36
+ ]
37
+
38
+ urlpatterns += i18n_patterns(
34
39
  path("recipes/<slug:slug>/", views.recipe_detail, name="recipe_detail"),
35
40
  path("setup/", views.setup, name="setup"),
36
- path("api/", api.urls),
37
- path("signup/", views.signup, name="signup"),
38
41
  path("recipes/<int:pk>/rate/", views.recipe_rate, name="recipe_rate"),
39
- ]
42
+ prefix_default_language=True,
43
+ )
40
44
 
41
45
  if "test" not in sys.argv or "PYTEST_VERSION" in os.environ:
42
46
  from debug_toolbar.toolbar import debug_toolbar_urls
@@ -44,7 +48,3 @@ if "test" not in sys.argv or "PYTEST_VERSION" in os.environ:
44
48
  urlpatterns = [
45
49
  *urlpatterns,
46
50
  ] + debug_toolbar_urls()
47
-
48
-
49
- if settings.DEBUG:
50
- urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
sandwitches/views.py CHANGED
@@ -4,9 +4,14 @@ from django.contrib import messages
4
4
  from django.contrib.auth import login
5
5
  from django.contrib.auth import get_user_model
6
6
  from django.contrib.auth.decorators import login_required
7
-
7
+ from django.utils.translation import gettext as _
8
8
  from .models import Recipe, Rating
9
9
  from .forms import RecipeForm, AdminSetupForm, UserSignupForm, RatingForm
10
+ from django.http import HttpResponseBadRequest
11
+ from django.conf import settings
12
+ from django.http import FileResponse, Http404
13
+ from pathlib import Path
14
+ import mimetypes
10
15
 
11
16
  User = get_user_model()
12
17
 
@@ -31,8 +36,8 @@ def recipe_detail(request, slug):
31
36
  rating_form = None
32
37
  if request.user.is_authenticated:
33
38
  try:
34
- user_rating = Rating.objects.get(recipe=recipe, user=request.user)
35
- except Rating.DoesNotExist:
39
+ user_rating = Rating.objects.get(recipe=recipe, user=request.user) # ty:ignore[unresolved-attribute]
40
+ except Rating.DoesNotExist: # ty:ignore[unresolved-attribute]
36
41
  user_rating = None
37
42
  # show form prefilled when possible
38
43
  initial = {"score": str(user_rating.score)} if user_rating else None
@@ -62,19 +67,19 @@ def recipe_rate(request, pk):
62
67
  form = RatingForm(request.POST)
63
68
  if form.is_valid():
64
69
  score = int(form.cleaned_data["score"])
65
- Rating.objects.update_or_create(
70
+ Rating.objects.update_or_create( # ty:ignore[unresolved-attribute]
66
71
  recipe=recipe, user=request.user, defaults={"score": score}
67
72
  )
68
- messages.success(request, "Your rating has been saved.")
73
+ messages.success(request, _("Your rating has been saved."))
69
74
  else:
70
- messages.error(request, "Could not save rating.")
75
+ messages.error(request, _("Could not save rating."))
71
76
  return redirect("recipe_detail", slug=recipe.slug)
72
77
 
73
78
 
74
79
  def index(request):
75
80
  if not User.objects.filter(is_superuser=True).exists():
76
81
  return redirect("setup")
77
- recipes = Recipe.objects.order_by("-created_at")
82
+ recipes = Recipe.objects.order_by("-created_at") # ty:ignore[unresolved-attribute]
78
83
  return render(request, "index.html", {"recipes": recipes})
79
84
 
80
85
 
@@ -91,10 +96,9 @@ def setup(request):
91
96
  form = AdminSetupForm(request.POST)
92
97
  if form.is_valid():
93
98
  user = form.save()
94
- # log in the newly created admin
95
99
  user.backend = "django.contrib.auth.backends.ModelBackend"
96
100
  login(request, user)
97
- messages.success(request, "Admin account created and signed in.")
101
+ messages.success(request, _("Admin account created and signed in."))
98
102
  return redirect(reverse("admin:index"))
99
103
  else:
100
104
  form = AdminSetupForm()
@@ -113,9 +117,32 @@ def signup(request):
113
117
  # log in the newly created user
114
118
  user.backend = "django.contrib.auth.backends.ModelBackend"
115
119
  login(request, user)
116
- messages.success(request, "Account created and signed in.")
120
+ messages.success(request, _("Account created and signed in."))
117
121
  return redirect("index")
118
122
  else:
119
123
  form = UserSignupForm()
120
124
 
121
125
  return render(request, "signup.html", {"form": form})
126
+
127
+
128
+ def media(request, file_path=None):
129
+ media_root = getattr(settings, "MEDIA_ROOT", None)
130
+ if not media_root:
131
+ return HttpResponseBadRequest("Invalid Media Root Configuration")
132
+ if not file_path:
133
+ return HttpResponseBadRequest("Invalid File Path")
134
+
135
+ base_path = Path(media_root).resolve()
136
+ full_path = base_path.joinpath(file_path).resolve()
137
+ if base_path not in full_path.parents:
138
+ return HttpResponseBadRequest("Access Denied")
139
+
140
+ if not full_path.exists() or not full_path.is_file():
141
+ raise Http404("File not found")
142
+
143
+ content_type, _ = mimetypes.guess_type(full_path)
144
+ if not content_type or not content_type.startswith("image/"):
145
+ return HttpResponseBadRequest("Access Denied: Only image files are allowed.")
146
+
147
+ response = FileResponse(open(full_path, "rb"), as_attachment=True)
148
+ return response
@@ -1,18 +1,21 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: sandwitches
3
- Version: 1.1.0
3
+ Version: 1.2.0
4
4
  Summary: Add your description here
5
5
  Author: Martyn van Dijke
6
6
  Author-email: Martyn van Dijke <martijnvdijke600@gmail.com>
7
7
  Requires-Dist: django-debug-toolbar>=6.1.0
8
8
  Requires-Dist: django-filter>=25.2
9
+ Requires-Dist: django-imagekit>=6.0.0
9
10
  Requires-Dist: django-ninja>=1.5.1
10
11
  Requires-Dist: django-simple-history>=3.10.1
12
+ Requires-Dist: django-tasks>=0.10.0
11
13
  Requires-Dist: django>=6.0.0
12
14
  Requires-Dist: gunicorn>=23.0.0
13
15
  Requires-Dist: markdown>=3.10
14
16
  Requires-Dist: pillow>=12.0.0
15
- Requires-Dist: uwsgi>=2.0.31
17
+ Requires-Dist: uvicorn>=0.40.0
18
+ Requires-Dist: whitenoise[brotli]>=6.11.0
16
19
  Requires-Python: >=3.12
17
20
  Description-Content-Type: text/markdown
18
21
 
@@ -0,0 +1,33 @@
1
+ sandwitches/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ sandwitches/admin.py,sha256=IIVQOr_CIXsdFXDPQoZ_c83DuqbHVnw4Ht9tAtmvLM0,870
3
+ sandwitches/api.py,sha256=r4HrlEv9IQMuvlr-WravamzTbUWcn85zS1e-iReHEuU,1968
4
+ sandwitches/asgi.py,sha256=cygnXdXSSVspM7ZXuj47Ef6oz7HSTw4D7BPzgE2PU5w,399
5
+ sandwitches/forms.py,sha256=NeGUi3xPzQpgw2cVWpo2ZKpYUXsCuJ3SzgGUkvxdV2A,2610
6
+ sandwitches/locale/nl/LC_MESSAGES/django.mo,sha256=GgZ4aNmU-v0FStt7mafi_UCR4hC0PC06W0mIUPPWtUE,2906
7
+ sandwitches/locale/nl/LC_MESSAGES/django.po,sha256=uk2W5ai6tyhKlA-rcucv5NpZfBrHNBev6Rp5wKWirqc,2843
8
+ sandwitches/migrations/0001_initial.py,sha256=01IfkFbUyYMpTHV5GaBxJEKjzRIdUdPR5sY3AUTODww,2546
9
+ sandwitches/migrations/0002_historicalrecipe.py,sha256=yU2KYssfjYhPXRYN6C8IMRFr-4QUGJozz-O167XuabM,2499
10
+ sandwitches/migrations/0003_rating.py,sha256=iKk9M9lcBS5LwsJkMYsmYfHKqKs2QRTILgINbnilASM,1857
11
+ sandwitches/migrations/0004_add_uploaded_by.py,sha256=gZawakGU-H0Abnn2Bw_Mswy9ngipzUC-BHRXRByKVZo,720
12
+ sandwitches/migrations/0005_historicalrecipe_uploaded_by.py,sha256=xmYDXgBxjrQkbEtorQlDzW0K1Z70UNxRrUk75WjYdEI,766
13
+ sandwitches/migrations/0006_profile.py,sha256=gzmxZWXmjldimYRdovuNouc2Y2idihg8UvEaU0ad_Ds,1558
14
+ sandwitches/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ sandwitches/models.py,sha256=7Upm6abkEZjmk5rIzViW7M_4a3ai03-9tLWLkCty2hs,6390
16
+ sandwitches/settings.py,sha256=5Qg0Wd-X1Kj1Fm7Teh0SRO8jOmVSUkpnUXfZRe1TjwI,5604
17
+ sandwitches/storage.py,sha256=HIiOEDa_LhpsbhCUBNO-SlCZDUJOoANUbyDIbspEcoE,2325
18
+ sandwitches/tasks.py,sha256=aGLpTE42mCZbh2Pyt7fXIjbELm9lD727ir_2bto-wWw,3241
19
+ sandwitches/templates/base.html,sha256=C9tUPfMKRvvdMqdDpE8ww21DH25bNktcVIwdrDEhajw,570
20
+ sandwitches/templates/base_pico.html,sha256=yeWlWlrCfI9yVLStSyODvcNtSmxXvWm4SZORZN-31R4,8273
21
+ sandwitches/templates/detail.html,sha256=p7FikXyse1bYxRCFCYH3GSwgNXHS7D9O6j4fUmmDkWQ,4592
22
+ sandwitches/templates/form.html,sha256=S4yUq9p2v7vWifhA5xj_Z4ObpMoaqUq2w08TDw3vk0o,449
23
+ sandwitches/templates/index.html,sha256=tgZFplcedG1r4s8pBc_qvJDXECPqrESPOSw56FnnCkw,2606
24
+ sandwitches/templates/setup.html,sha256=btid1XtR0MO_qSWriWX7LeWUtNFA7rDB4zt5Md9UNhU,1787
25
+ sandwitches/templates/signup.html,sha256=3qOdDMUHMshe2FoaQzR07lIm3Wbrzorb_h9Fp8Og-Eg,1585
26
+ sandwitches/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
+ sandwitches/templatetags/markdown_extras.py,sha256=0ibmRzxE3r85x4k7kK71R-9UT0CgeegYF7MHzj3juTI,344
28
+ sandwitches/urls.py,sha256=maKaIDfb_kNmMwrpS495TymuFnJJ6fbLoi5QRLjrFds,1582
29
+ sandwitches/views.py,sha256=Av9dfTAygGkFkHO47NK6RDjprMTVRpDa4c63X_h9ur8,5192
30
+ sandwitches/wsgi.py,sha256=Eyncpnahq_4s3Lr9ruB-R3Lu9j9zBXqgPbUj7qhIbwU,399
31
+ sandwitches-1.2.0.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
32
+ sandwitches-1.2.0.dist-info/METADATA,sha256=psetHwoaKHYa-_anYOLXOaBdi1UumZwg5lR8uStEg_I,731
33
+ sandwitches-1.2.0.dist-info/RECORD,,
@@ -1,28 +0,0 @@
1
- sandwitches/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- sandwitches/admin.py,sha256=8QyK9xOUvGGPz30-7p2phyc-Ks9VKD_K1kCAagisPwA,120
3
- sandwitches/api.py,sha256=HaTOgqGZK4sPUoGx1IFJoUQntcB1EX91pnyM7-TREjg,1565
4
- sandwitches/asgi.py,sha256=cygnXdXSSVspM7ZXuj47Ef6oz7HSTw4D7BPzgE2PU5w,399
5
- sandwitches/forms.py,sha256=NeGUi3xPzQpgw2cVWpo2ZKpYUXsCuJ3SzgGUkvxdV2A,2610
6
- sandwitches/migrations/0001_initial.py,sha256=01IfkFbUyYMpTHV5GaBxJEKjzRIdUdPR5sY3AUTODww,2546
7
- sandwitches/migrations/0002_historicalrecipe.py,sha256=yU2KYssfjYhPXRYN6C8IMRFr-4QUGJozz-O167XuabM,2499
8
- sandwitches/migrations/0003_rating.py,sha256=iKk9M9lcBS5LwsJkMYsmYfHKqKs2QRTILgINbnilASM,1857
9
- sandwitches/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- sandwitches/models.py,sha256=7dJ5vHZ1bQWG2ebAJKEwaPHMukgdPth7i6quswRldmw,3974
11
- sandwitches/settings.py,sha256=ApYwzWeJGX5Af4zJ6wWKq0-u8Lro8RVfO7xS7PRbpmw,3829
12
- sandwitches/storage.py,sha256=XrzMw8mcUowEoV5hYjP-ZI27C3vfk010UkukA5SrGDk,917
13
- sandwitches/tasks.py,sha256=rsCpfCwcIoSthpN0IZ_dt2jPsMSUe8otBmE2UbFeKg0,468
14
- sandwitches/templates/base.html,sha256=gUOxxwD7G8VeBranSYp40PCWsJ-ywf8e7Qyv8VoqRP4,494
15
- sandwitches/templates/base_pico.html,sha256=ntvh9wrfVqkqI58LregrPuVr9czsYB75n7HazbbkFhM,7477
16
- sandwitches/templates/detail.html,sha256=1GuCwmIV-k9ROhR9bddv19rjqgC5CbLs3AzounmnAEE,3723
17
- sandwitches/templates/form.html,sha256=XgrQfb_ZEJfnAou7z3gxcj7wqZ4fwFANplvYdzXg80A,373
18
- sandwitches/templates/index.html,sha256=fnsU5N5dPaa3BXOoIUvgD-9a3EPz0Fs25M0p_eQnf5w,2307
19
- sandwitches/templates/setup.html,sha256=Y45l96Tl6ln9Mb5gCC4JnT1bf-zuQOpYYL1JL3k-1T0,1677
20
- sandwitches/templates/signup.html,sha256=UR5Doueq58hSUQgqDrhH5y5Ivdxp_8cfZ0TPaTW_IrI,1439
21
- sandwitches/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
- sandwitches/templatetags/markdown_extras.py,sha256=0ibmRzxE3r85x4k7kK71R-9UT0CgeegYF7MHzj3juTI,344
23
- sandwitches/urls.py,sha256=dBZ4o5lQqAapIVEIZ1OkNTWmU16tUoG3LygusDREaHY,1573
24
- sandwitches/views.py,sha256=W8HvLFkdmS-nDj3sDY8IZWXv4V7CU5riQy75HSkbEqM,4001
25
- sandwitches/wsgi.py,sha256=Eyncpnahq_4s3Lr9ruB-R3Lu9j9zBXqgPbUj7qhIbwU,399
26
- sandwitches-1.1.0.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
27
- sandwitches-1.1.0.dist-info/METADATA,sha256=f4X5Ovu99_ADGnBoWqgWGP5xZKmU6Y5WWFzWQqtrRvA,613
28
- sandwitches-1.1.0.dist-info/RECORD,,