sandwitches 2.2.0__py3-none-any.whl → 2.3.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.
Files changed (32) hide show
  1. sandwitches/admin.py +23 -2
  2. sandwitches/api.py +22 -1
  3. sandwitches/forms.py +49 -0
  4. sandwitches/management/__init__.py +0 -0
  5. sandwitches/management/commands/__init__.py +0 -0
  6. sandwitches/management/commands/reset_daily_orders.py +14 -0
  7. sandwitches/migrations/0007_historicalrecipe_price_recipe_price_order.py +86 -0
  8. sandwitches/migrations/0008_historicalrecipe_daily_orders_count_and_more.py +36 -0
  9. sandwitches/migrations/0009_historicalrecipe_is_approved_recipe_is_approved.py +22 -0
  10. sandwitches/models.py +63 -1
  11. sandwitches/settings.py +1 -0
  12. sandwitches/tasks.py +74 -0
  13. sandwitches/templates/admin/admin_base.html +4 -0
  14. sandwitches/templates/admin/dashboard.html +125 -61
  15. sandwitches/templates/admin/order_list.html +30 -0
  16. sandwitches/templates/admin/partials/dashboard_charts.html +90 -0
  17. sandwitches/templates/admin/partials/order_rows.html +28 -0
  18. sandwitches/templates/admin/rating_list.html +2 -0
  19. sandwitches/templates/admin/recipe_form.html +26 -0
  20. sandwitches/templates/admin/recipe_list.html +65 -15
  21. sandwitches/templates/base.html +12 -0
  22. sandwitches/templates/components/navbar.html +10 -5
  23. sandwitches/templates/components/recipe_header.html +17 -0
  24. sandwitches/templates/components/side_menu.html +4 -0
  25. sandwitches/templates/partials/recipe_list.html +7 -0
  26. sandwitches/templates/profile.html +95 -0
  27. sandwitches/templates/recipe_form.html +15 -1
  28. sandwitches/urls.py +9 -0
  29. sandwitches/views.py +178 -21
  30. {sandwitches-2.2.0.dist-info → sandwitches-2.3.1.dist-info}/METADATA +1 -1
  31. {sandwitches-2.2.0.dist-info → sandwitches-2.3.1.dist-info}/RECORD +32 -22
  32. {sandwitches-2.2.0.dist-info → sandwitches-2.3.1.dist-info}/WHEEL +0 -0
@@ -0,0 +1,95 @@
1
+ {% extends "base_beer.html" %}
2
+ {% load static i18n %}
3
+ {% block title %}{% trans "Your Profile" %}{% endblock %}
4
+
5
+ {% block content %}
6
+ <div class="large-space"></div>
7
+
8
+ <div class="grid">
9
+ <div class="s12 m10 l8 xl6 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 "Edit your profile" %}</h4>
13
+ </div>
14
+
15
+ <form method="post" enctype="multipart/form-data" novalidate>
16
+ {% csrf_token %}
17
+
18
+ {% if form.non_field_errors %}
19
+ <div class="padding error surface round mb">
20
+ {% for err in form.non_field_errors %}
21
+ <div class="row align-center">
22
+ <i class="error-text">warning</i>
23
+ <span class="error-text">{{ err }}</span>
24
+ </div>
25
+ {% endfor %}
26
+ </div>
27
+ {% endif %}
28
+
29
+ <div class="grid">
30
+ <div class="s12 m6">
31
+ <div class="field label border round {% if form.first_name.errors %}error{% endif %}">
32
+ <input type="text" name="{{ form.first_name.name }}" id="{{ form.first_name.id_for_label }}" value="{{ form.first_name.value|default:'' }}">
33
+ <label>{% trans "First name" %}</label>
34
+ {% if form.first_name.errors %}
35
+ <span class="helper error-text">{{ form.first_name.errors.0 }}</span>
36
+ {% endif %}
37
+ </div>
38
+ </div>
39
+ <div class="s12 m6">
40
+ <div class="field label border round {% if form.last_name.errors %}error{% endif %}">
41
+ <input type="text" name="{{ form.last_name.name }}" id="{{ form.last_name.id_for_label }}" value="{{ form.last_name.value|default:'' }}">
42
+ <label>{% trans "Last name" %}</label>
43
+ {% if form.last_name.errors %}
44
+ <span class="helper error-text">{{ form.last_name.errors.0 }}</span>
45
+ {% endif %}
46
+ </div>
47
+ </div>
48
+ </div>
49
+
50
+ <div class="field label border round {% if form.email.errors %}error{% endif %}">
51
+ <input type="email" name="{{ form.email.name }}" id="{{ form.email.id_for_label }}" value="{{ form.email.value|default:'' }}">
52
+ <label>{% trans "Email" %}</label>
53
+ {% if form.email.errors %}
54
+ <span class="helper error-text">{{ form.email.errors.0 }}</span>
55
+ {% endif %}
56
+ </div>
57
+
58
+ <div class="field label border round textarea {% if form.bio.errors %}error{% endif %}">
59
+ <textarea name="{{ form.bio.name }}" id="{{ form.bio.id_for_label }}" rows="3">{{ form.bio.value|default:'' }}</textarea>
60
+ <label>{% trans "Bio" %}</label>
61
+ {% if form.bio.errors %}
62
+ <span class="helper error-text">{{ form.bio.errors.0 }}</span>
63
+ {% endif %}
64
+ </div>
65
+
66
+ <div class="field middle-align {% if form.avatar.errors %}error{% endif %}">
67
+ <nav>
68
+ <div class="max">
69
+ <label class="button border transparent round">
70
+ <input type="file" name="{{ form.avatar.name }}" id="{{ form.avatar.id_for_label }}" accept="image/*">
71
+ <i>upload</i>
72
+ <span>{% trans "Upload Profile Picture" %}</span>
73
+ </label>
74
+ </div>
75
+ {% if user.avatar %}
76
+ <img src="{{ user.avatar.url }}" class="circle small">
77
+ {% endif %}
78
+ </nav>
79
+ {% if form.avatar.errors %}
80
+ <span class="helper error-text">{{ form.avatar.errors.0 }}</span>
81
+ {% endif %}
82
+ </div>
83
+
84
+ <div class="large-space"></div>
85
+
86
+ <nav class="right-align">
87
+ <a class="button transparent border round" href="{% url 'index' %}">{% trans "Cancel" %}</a>
88
+ <button type="submit" class="button primary round">{% trans "Save changes" %}</button>
89
+ </nav>
90
+
91
+ </form>
92
+ </article>
93
+ </div>
94
+ </div>
95
+ {% endblock %}
@@ -68,9 +68,23 @@
68
68
  </div>
69
69
  </div>
70
70
 
71
+ <div class="s12 m6">
72
+ <div class="field label border round">
73
+ {{ form.price }}
74
+ <label>{% trans "Price" %}</label>
75
+ </div>
76
+ </div>
77
+
78
+ <div class="s12 m6">
79
+ <div class="field label border round">
80
+ {{ form.servings }}
81
+ <label>{% trans "Servings" %}</label>
82
+ </div>
83
+ </div>
84
+
71
85
  <div class="s12">
72
86
  <div class="field label border round">
73
- {{ form.tags }}
87
+ {{ form.tags_string }}
74
88
  <label>{% trans "Tags (comma separated)" %}</label>
75
89
  </div>
76
90
  </div>
sandwitches/urls.py CHANGED
@@ -33,6 +33,8 @@ urlpatterns = [
33
33
  path("signup/", views.signup, name="signup"),
34
34
  path("login/", views.CustomLoginView.as_view(), name="login"),
35
35
  path("logout/", LogoutView.as_view(next_page="index"), name="logout"),
36
+ path("profile/", views.user_profile, name="user_profile"),
37
+ path("submit-recipe/", views.submit_recipe, name="submit_recipe"),
36
38
  path("admin/", admin.site.urls),
37
39
  path("api/", api.urls),
38
40
  path("media/<path:file_path>", views.media, name="media"),
@@ -48,6 +50,7 @@ urlpatterns += i18n_patterns(
48
50
  path("recipes/<slug:slug>/", views.recipe_detail, name="recipe_detail"),
49
51
  path("setup/", views.setup, name="setup"),
50
52
  path("recipes/<int:pk>/rate/", views.recipe_rate, name="recipe_rate"),
53
+ path("recipes/<int:pk>/order/", views.order_recipe, name="order_recipe"),
51
54
  path("recipes/<int:pk>/favorite/", views.toggle_favorite, name="toggle_favorite"),
52
55
  path("dashboard/", views.admin_dashboard, name="admin_dashboard"),
53
56
  path("dashboard/recipes/", views.admin_recipe_list, name="admin_recipe_list"),
@@ -62,6 +65,11 @@ urlpatterns += i18n_patterns(
62
65
  views.admin_recipe_delete,
63
66
  name="admin_recipe_delete",
64
67
  ),
68
+ path(
69
+ "dashboard/recipes/<int:pk>/approve/",
70
+ views.admin_recipe_approve,
71
+ name="admin_recipe_approve",
72
+ ),
65
73
  path(
66
74
  "dashboard/recipes/<int:pk>/rotate/",
67
75
  views.admin_recipe_rotate,
@@ -98,6 +106,7 @@ urlpatterns += i18n_patterns(
98
106
  views.admin_rating_delete,
99
107
  name="admin_rating_delete",
100
108
  ),
109
+ path("dashboard/orders/", views.admin_order_list, name="admin_order_list"),
101
110
  prefix_default_language=True,
102
111
  )
103
112
 
sandwitches/views.py CHANGED
@@ -1,3 +1,5 @@
1
+ import logging
2
+ from django.core.exceptions import ValidationError
1
3
  from django.shortcuts import render, get_object_or_404, redirect
2
4
  from django.urls import reverse
3
5
  from django.contrib import messages
@@ -6,7 +8,7 @@ from django.contrib.auth import get_user_model
6
8
  from django.contrib.auth.decorators import login_required
7
9
  from django.contrib.admin.views.decorators import staff_member_required
8
10
  from django.utils.translation import gettext as _
9
- from .models import Recipe, Rating, Tag
11
+ from .models import Recipe, Rating, Tag, Order
10
12
  from .forms import (
11
13
  RecipeForm,
12
14
  AdminSetupForm,
@@ -14,10 +16,12 @@ from .forms import (
14
16
  RatingForm,
15
17
  UserEditForm,
16
18
  TagForm,
19
+ UserProfileForm,
20
+ UserRecipeSubmissionForm,
17
21
  )
18
- from django.http import HttpResponseBadRequest
22
+ from django.http import HttpResponseBadRequest, Http404
19
23
  from django.conf import settings
20
- from django.http import FileResponse, Http404
24
+ from django.http import FileResponse
21
25
  from pathlib import Path
22
26
  import mimetypes
23
27
  from PIL import Image
@@ -31,6 +35,30 @@ from sandwitches import __version__ as sandwitches_version
31
35
  User = get_user_model()
32
36
 
33
37
 
38
+ @login_required
39
+ def submit_recipe(request):
40
+ if request.method == "POST":
41
+ form = UserRecipeSubmissionForm(request.POST, request.FILES)
42
+ if form.is_valid():
43
+ recipe = form.save(commit=False)
44
+ recipe.uploaded_by = request.user
45
+ recipe.is_approved = False # Explicitly set to False just in case
46
+ recipe.save()
47
+ form.save_m2m()
48
+ messages.success(
49
+ request,
50
+ _("Your recipe has been submitted and is awaiting admin approval."),
51
+ )
52
+ return redirect("user_profile")
53
+ else:
54
+ form = UserRecipeSubmissionForm()
55
+ return render(
56
+ request,
57
+ "recipe_form.html",
58
+ {"form": form, "title": _("Submit Recipe"), "version": sandwitches_version},
59
+ )
60
+
61
+
34
62
  class CustomLoginView(LoginView):
35
63
  template_name = "login.html"
36
64
  redirect_authenticated_user = True
@@ -87,6 +115,15 @@ def admin_dashboard(request):
87
115
  .order_by("date")
88
116
  )
89
117
 
118
+ # Orders over time
119
+ order_data = (
120
+ Order.objects.filter(created_at__date__range=(start_date, end_date)) # ty:ignore[unresolved-attribute]
121
+ .annotate(date=TruncDate("created_at"))
122
+ .values("date")
123
+ .annotate(count=Count("id"))
124
+ .order_by("date")
125
+ )
126
+
90
127
  # Prepare labels and data for JS
91
128
  recipe_labels = [d["date"].strftime("%d/%m/%Y") for d in recipe_data]
92
129
  recipe_counts = [d["count"] for d in recipe_data]
@@ -94,36 +131,71 @@ def admin_dashboard(request):
94
131
  rating_labels = [d["date"].strftime("%d/%m/%Y") for d in rating_data]
95
132
  rating_avgs = [float(d["avg"]) for d in rating_data]
96
133
 
134
+ order_labels = [d["date"].strftime("%d/%m/%Y") for d in order_data]
135
+ order_counts = [d["count"] for d in order_data]
136
+
137
+ pending_recipes = Recipe.objects.filter(is_approved=False).order_by("-created_at") # ty:ignore[unresolved-attribute]
138
+
139
+ context = {
140
+ "recipe_count": recipe_count,
141
+ "user_count": user_count,
142
+ "tag_count": tag_count,
143
+ "recent_recipes": recent_recipes,
144
+ "pending_recipes": pending_recipes,
145
+ "recipe_labels": recipe_labels,
146
+ "recipe_counts": recipe_counts,
147
+ "rating_labels": rating_labels,
148
+ "rating_avgs": rating_avgs,
149
+ "order_labels": order_labels,
150
+ "order_counts": order_counts,
151
+ "start_date": start_date.strftime("%Y-%m-%d"),
152
+ "end_date": end_date.strftime("%Y-%m-%d"),
153
+ "version": sandwitches_version,
154
+ }
155
+
156
+ if request.headers.get("HX-Request"):
157
+ return render(request, "admin/partials/dashboard_charts.html", context)
158
+
97
159
  return render(
98
160
  request,
99
161
  "admin/dashboard.html",
100
- {
101
- "recipe_count": recipe_count,
102
- "user_count": user_count,
103
- "tag_count": tag_count,
104
- "recent_recipes": recent_recipes,
105
- "recipe_labels": recipe_labels,
106
- "recipe_counts": recipe_counts,
107
- "rating_labels": rating_labels,
108
- "rating_avgs": rating_avgs,
109
- "start_date": start_date.strftime("%Y-%m-%d"),
110
- "end_date": end_date.strftime("%Y-%m-%d"),
111
- "version": sandwitches_version,
112
- },
162
+ context,
113
163
  )
114
164
 
115
165
 
116
166
  @staff_member_required
117
167
  def admin_recipe_list(request):
168
+ sort_param = request.GET.get("sort", "-created_at")
169
+ allowed_sorts = {
170
+ "title": "title",
171
+ "-title": "-title",
172
+ "created_at": "created_at",
173
+ "-created_at": "-created_at",
174
+ "uploader": "uploaded_by__username",
175
+ "-uploader": "-uploaded_by__username",
176
+ "price": "price",
177
+ "-price": "-price",
178
+ "orders": "daily_orders_count",
179
+ "-orders": "-daily_orders_count",
180
+ "rating": "avg_rating",
181
+ "-rating": "-avg_rating",
182
+ }
183
+
184
+ order_by = allowed_sorts.get(sort_param, "-created_at")
185
+
118
186
  recipes = (
119
187
  Recipe.objects.annotate(avg_rating=Avg("ratings__score")) # ty:ignore[unresolved-attribute]
120
188
  .prefetch_related("tags")
121
- .all()
189
+ .order_by(order_by)
122
190
  )
123
191
  return render(
124
192
  request,
125
193
  "admin/recipe_list.html",
126
- {"recipes": recipes, "version": sandwitches_version},
194
+ {
195
+ "recipes": recipes,
196
+ "version": sandwitches_version,
197
+ "current_sort": sort_param,
198
+ },
127
199
  )
128
200
 
129
201
 
@@ -170,6 +242,17 @@ def admin_recipe_edit(request, pk):
170
242
  )
171
243
 
172
244
 
245
+ @staff_member_required
246
+ def admin_recipe_approve(request, pk):
247
+ recipe = get_object_or_404(Recipe, pk=pk)
248
+ recipe.is_approved = True
249
+ recipe.save()
250
+ messages.success(
251
+ request, _("Recipe '%(title)s' approved.") % {"title": recipe.title}
252
+ )
253
+ return redirect("admin_recipe_list")
254
+
255
+
173
256
  @staff_member_required
174
257
  def admin_recipe_delete(request, pk):
175
258
  recipe = get_object_or_404(Recipe, pk=pk)
@@ -365,8 +448,38 @@ def admin_rating_delete(request, pk):
365
448
  )
366
449
 
367
450
 
451
+ @staff_member_required
452
+ def admin_order_list(request):
453
+ orders = (
454
+ Order.objects.select_related("user", "recipe") # ty:ignore[unresolved-attribute]
455
+ .all()
456
+ .order_by("-created_at")
457
+ )
458
+
459
+ if request.headers.get("HX-Request"):
460
+ return render(
461
+ request,
462
+ "admin/partials/order_rows.html",
463
+ {"orders": orders, "version": sandwitches_version},
464
+ )
465
+
466
+ return render(
467
+ request,
468
+ "admin/order_list.html",
469
+ {"orders": orders, "version": sandwitches_version},
470
+ )
471
+
472
+
368
473
  def recipe_detail(request, slug):
369
474
  recipe = get_object_or_404(Recipe, slug=slug)
475
+
476
+ if not recipe.is_approved:
477
+ if not (
478
+ request.user.is_authenticated
479
+ and (request.user.is_staff or recipe.uploaded_by == request.user)
480
+ ):
481
+ raise Http404("Recipe not found or pending approval.")
482
+
370
483
  avg = recipe.average_rating()
371
484
  count = recipe.rating_count()
372
485
  user_rating = None
@@ -400,6 +513,28 @@ def recipe_detail(request, slug):
400
513
  )
401
514
 
402
515
 
516
+ @login_required
517
+ def order_recipe(request, pk):
518
+ """
519
+ Create an order for the given recipe by the logged-in user.
520
+ """
521
+ recipe = get_object_or_404(Recipe, pk=pk)
522
+ if request.method != "POST":
523
+ return redirect("recipe_detail", slug=recipe.slug)
524
+
525
+ try:
526
+ order = Order.objects.create(user=request.user, recipe=recipe) # ty:ignore[unresolved-attribute]
527
+ logging.debug(f"Created {order}")
528
+ messages.success(
529
+ request,
530
+ _("Your order for %(title)s has been submitted!") % {"title": recipe.title},
531
+ )
532
+ except (ValidationError, ValueError) as e:
533
+ messages.error(request, str(e))
534
+
535
+ return redirect("recipe_detail", slug=recipe.slug)
536
+
537
+
403
538
  @login_required
404
539
  def recipe_rate(request, pk):
405
540
  """
@@ -509,9 +644,16 @@ def favorites(request):
509
644
  def index(request):
510
645
  if not User.objects.filter(is_superuser=True).exists():
511
646
  return redirect("setup")
512
- recipes = (
513
- Recipe.objects.all().prefetch_related("favorited_by") # ty:ignore[unresolved-attribute]
514
- ) # Start with all, order later
647
+
648
+ recipes = Recipe.objects.all().prefetch_related("favorited_by") # ty:ignore[unresolved-attribute]
649
+
650
+ if not (request.user.is_authenticated and request.user.is_staff):
651
+ if request.user.is_authenticated:
652
+ # Show approved recipes OR recipes uploaded by the current user
653
+ recipes = recipes.filter(Q(is_approved=True) | Q(uploaded_by=request.user))
654
+ else:
655
+ # Show only approved recipes for anonymous users
656
+ recipes = recipes.filter(is_approved=True)
515
657
 
516
658
  # Filtering
517
659
  q = request.GET.get("q")
@@ -645,3 +787,18 @@ def media(request, file_path=None):
645
787
 
646
788
  response = FileResponse(open(full_path, "rb"), as_attachment=True)
647
789
  return response
790
+
791
+
792
+ @login_required
793
+ def user_profile(request):
794
+ if request.method == "POST":
795
+ form = UserProfileForm(request.POST, request.FILES, instance=request.user)
796
+ if form.is_valid():
797
+ form.save()
798
+ messages.success(request, _("Profile updated successfully."))
799
+ return redirect("user_profile")
800
+ else:
801
+ form = UserProfileForm(instance=request.user)
802
+ return render(
803
+ request, "profile.html", {"form": form, "version": sandwitches_version}
804
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: sandwitches
3
- Version: 2.2.0
3
+ Version: 2.3.1
4
4
  Summary: Add your description here
5
5
  Author: Martyn van Dijke
6
6
  Author-email: Martyn van Dijke <martijnvdijke600@gmail.com>
@@ -1,35 +1,44 @@
1
1
  sandwitches/__init__.py,sha256=YTDsQDSdJmxV2Z0dTbBqZhuJRuXcNLSKL0SX73Lu2u8,195
2
- sandwitches/admin.py,sha256=c_FBgg_moMwlNVJKRknHF9_KI97oYGgk_MhwLDJGDFQ,1910
3
- sandwitches/api.py,sha256=4Upjd78dHVZDOIFkZjPst0mLfVdiToB3RVVrBpttTYg,5714
2
+ sandwitches/admin.py,sha256=-02WqE8U3rxrVCoNB7sfvtyE4v_e3pt7mFwXfUlindo,2421
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=QMSCpiy42AjretzEkj8FghfmBj-gkalSOXZVwiTtkOQ,5916
6
+ sandwitches/forms.py,sha256=YvkSTa9h_ag_b58ToOHCQIHBa3VeHMC9RKB9F7qI-gk,7152
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
+ sandwitches/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ sandwitches/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ sandwitches/management/commands/reset_daily_orders.py,sha256=PrGPFfJ7r3J1SYYgyU5YDaFVvc7uvMGzkkePL07GDyo,480
9
12
  sandwitches/migrations/0001_initial.py,sha256=hXnCAhoA91C6YCinXyUdIfQ7QL29NPBHFfTqLgulMsY,12507
10
13
  sandwitches/migrations/0002_historicalrecipe_servings_recipe_servings.py,sha256=8E09y99FdVNzaQMn8R1d5zEcCN9jZICVCTW8MsGRBqs,743
11
14
  sandwitches/migrations/0003_setting.py,sha256=DmugIrz0Wtftx7B0MrX6ms34j60kSOwcPz1sLRP4wE0,1200
12
15
  sandwitches/migrations/0004_alter_setting_ai_api_key_and_more.py,sha256=516vcSxWzsZiJaskH1JC-1FgB0t4ijNC2L3PcfdRPNg,1109
13
16
  sandwitches/migrations/0005_rating_comment.py,sha256=MRlTZkyATH1aJdkaesPlPkXkYt-mzqBik-MCcNrbLRI,398
14
17
  sandwitches/migrations/0006_historicalrecipe_is_highlighted_and_more.py,sha256=BBCx4uxPK9udqsJ6qkoYpZ_3tH4uujquj9j0Gm7Ff6w,566
18
+ sandwitches/migrations/0007_historicalrecipe_price_recipe_price_order.py,sha256=o-hsVK39ArT_KkSkMnZfhCTQu66v81P6LbZPqRxjonU,2793
19
+ sandwitches/migrations/0008_historicalrecipe_daily_orders_count_and_more.py,sha256=PyjettGABOcH6ryCXApOpEPNKBIs23AFIK302uQxpiY,1105
20
+ sandwitches/migrations/0009_historicalrecipe_is_approved_recipe_is_approved.py,sha256=XP76J2_HiMOFeIU17Yu8AYXtswE-dcsNZq3lJGFgGtg,588
15
21
  sandwitches/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
- sandwitches/models.py,sha256=dgPc32_VTcKPvhBXjy9jRquI5BgLDNeLnLxnhZN37J8,7252
17
- sandwitches/settings.py,sha256=hNLDqbRPGdtNVNX31zxcDWKxWa95AcswKbj4XW4Z2lE,5821
22
+ sandwitches/models.py,sha256=p67bGRaacH-ccJmcS9Mfco4nCdidvOwHhWeiFakKYnA,9979
23
+ sandwitches/settings.py,sha256=5_eQAJCAV093hnhr3XOxHekT4IF-PEJcRiTecq71_SQ,5841
18
24
  sandwitches/storage.py,sha256=ibBG6tVtArqzgEKsRimZPwsqW7i9j4WiPLLHrOJchow,3578
19
- sandwitches/tasks.py,sha256=rRQpWZp-vDbMgVmnZAz8GaPzK7F3uzAr6lho7Zq-mdM,3656
20
- sandwitches/templates/admin/admin_base.html,sha256=yPFo1K1LrRuPKfOuOGLEgQm29vWqzvkSoDNlpmxYPaY,4261
25
+ sandwitches/tasks.py,sha256=YiliAT2rj0fh7hrwKq5_qWtv9AGhd5iulj_iBwZBBKg,6024
26
+ sandwitches/templates/admin/admin_base.html,sha256=5ZtJbZMstLjjyCc73smhIUJOhU7vscwqLuung1Gf15g,4489
21
27
  sandwitches/templates/admin/confirm_delete.html,sha256=HfsZI_gV8JQTKz215TYgPWBrgrFhGv1UB3N-0Hln-14,804
22
- sandwitches/templates/admin/dashboard.html,sha256=uHisWI3x-KehPDlwBFF5bIT5-tPsCVU5duA_ZPF-GHc,6168
23
- sandwitches/templates/admin/rating_list.html,sha256=ZTxu4emeYInlYyw7b19c8cYlj90fo1wtA-1BEJKZGt0,1256
24
- sandwitches/templates/admin/recipe_form.html,sha256=ssLnS63UobRFwPbDHMrnwniJEta3QHkWOJb8IPzYd_k,7560
25
- sandwitches/templates/admin/recipe_list.html,sha256=HDOmhK-XEPwTv1CCBqTXK79pLoH5y2xKPFjjue0HFeQ,2454
28
+ sandwitches/templates/admin/dashboard.html,sha256=lZhywLTC-PHtezIZdqGNnIC-G13a6mqjGohUnqCgoao,5758
29
+ sandwitches/templates/admin/order_list.html,sha256=eHFUn2speXaaj5_SFUG0Z0HfWVUR9-VCDRBeb8ufFb0,819
30
+ sandwitches/templates/admin/partials/dashboard_charts.html,sha256=NYrt-LDZO4__2KDWhAYL5K_f-2Zgj0iiuaZQiRZlBWg,3639
31
+ sandwitches/templates/admin/partials/order_rows.html,sha256=Ye35liahKbQ3rqa6fIGSTwb7seoXoqyqSw0wyNq2C_o,893
32
+ sandwitches/templates/admin/rating_list.html,sha256=8CHAsBfKfs4izhb-IyOiDjJXqAZxFcStoRSGh4pRlgM,1365
33
+ sandwitches/templates/admin/recipe_form.html,sha256=23wHT4hs128xnv2nkS6AtcKzY3sblia_dGVNnaeIp5Y,8734
34
+ sandwitches/templates/admin/recipe_list.html,sha256=5fGnRIQ7JfvM3yfG-sngEIEgiPnPDkjK1Tn3nO8EDh4,5359
26
35
  sandwitches/templates/admin/tag_form.html,sha256=JRWgAl4fz_Oy-Kuo1K6Mex_CXdsHMABzzyPazthr1Kg,989
27
36
  sandwitches/templates/admin/tag_list.html,sha256=ttxwXgfdxkEs4Cmrz5RHaGmaqLd7JDmWhjv80XIQqyw,1246
28
37
  sandwitches/templates/admin/task_detail.html,sha256=dO5zHOG-yTY1ly3VPA3o3jjie0wmxw0gdddtSKpN-W8,3825
29
38
  sandwitches/templates/admin/task_list.html,sha256=3YF7YQ3nbXnWjApKeA07Z7HkhdMuH4s6sLoN7gwg0eE,1535
30
39
  sandwitches/templates/admin/user_form.html,sha256=7_6GShLROFeJJexL1XLFUXdW9_lYF87eT6cigB5bQo4,1314
31
40
  sandwitches/templates/admin/user_list.html,sha256=6O1YctULY-tqJnagybJof9ERA_NL1LX_a8cAu6_aWVQ,2193
32
- sandwitches/templates/base.html,sha256=07zDXWzRC-aptZW6oq3xcxvDA1Lh87F7kTpBeYFUwsg,3211
41
+ sandwitches/templates/base.html,sha256=mwCESNirfvvdyMg2e1Siy_LA8fLH29m0aS_Jv0Qom4U,3597
33
42
  sandwitches/templates/base_beer.html,sha256=4QgU4_gu_RRMtimmRAhATDJ3mj_WANxtilQJYNgAL60,2077
34
43
  sandwitches/templates/components/carousel_scripts.html,sha256=9vEL5JJv8zUUjEtsnHW-BwwXUNWqQ6w_vf6UdxgEv_I,1934
35
44
  sandwitches/templates/components/favorites_search_form.html,sha256=tpD8SpS47TUDJBwxhMuvjhTN9pjWoRGFW50TBv48Ld4,5202
@@ -38,28 +47,29 @@ sandwitches/templates/components/ingredients_scripts.html,sha256=2zKTC65GYF589uW
38
47
  sandwitches/templates/components/ingredients_section.html,sha256=XsaVXTs9MIwjfJeLjlzah3GWWj8oFU-_HJd9i9l1HAo,665
39
48
  sandwitches/templates/components/instructions_section.html,sha256=RFlA4uPiI6vf1e2QgiD5KzGoy7Vg7y7nFY7TFabCYLA,277
40
49
  sandwitches/templates/components/language_dialog.html,sha256=iz-6QhFe4f_dsVhGDhVx6KKKLgQz4grX8tbIqSQjDsg,1184
41
- sandwitches/templates/components/navbar.html,sha256=CtWqAmPke7nm-UqSvGGl6TPaNwT2Zqkw9UySOCA8hfo,1049
50
+ sandwitches/templates/components/navbar.html,sha256=X2qOPHhVrSl4TkTk4YY-60YjpwCG7IEe4L6a9ywMih4,1164
42
51
  sandwitches/templates/components/rating_section.html,sha256=8O5IsFfQwnElMQZLnDpJiuCvvQMLa3jCS67u_RhMi7o,2717
43
- sandwitches/templates/components/recipe_header.html,sha256=-LCp6KqkQO7a7yqR0jKUQ95-RczYU-_MFO058lE04_w,1473
52
+ sandwitches/templates/components/recipe_header.html,sha256=jH9bnT6tis3OuePBq-xzP87IIx2ipDTuw2LO0BQwLXg,1996
44
53
  sandwitches/templates/components/search_form.html,sha256=B8579Jo44gLrlmvkkc2-Vuv_QD93Ljt6F2J1WgTDV60,6617
45
54
  sandwitches/templates/components/search_scripts.html,sha256=HvsO5e50DoTZeoFiYeNP5S8S5h7Zfr9VULOWKKR1i_M,3423
46
- sandwitches/templates/components/side_menu.html,sha256=JyrhmyWLKKZj1yqriHqQc6Fv25TpmIgXNhoEdxrePVQ,1529
55
+ sandwitches/templates/components/side_menu.html,sha256=QMkgPgWIUXBFyXe1ZEP_CYm1wnaq1h6q645tbDQjNdw,1804
47
56
  sandwitches/templates/components/user_menu.html,sha256=c20cBpyLheGvHdQ5nn-c4fjNlhfnAt3FAsw1V46rTwQ,369
48
57
  sandwitches/templates/detail.html,sha256=g-O_RsW9Ix9ivWC0nZ4FwHY2NhgYZ3bEGLpqGY0JSxg,5642
49
58
  sandwitches/templates/favorites.html,sha256=0cPpW07N6Isrb8XpvA5Eh97L2-12QFZ43EzeJvbOlXo,917
50
59
  sandwitches/templates/index.html,sha256=7anU7k8s80JYk59Rwsm8EdlNYd7B5clCvV7pKq2IUy0,2518
51
60
  sandwitches/templates/login.html,sha256=LiQskhkOkfx0EE4ssA1ToqQ3oEll08OPYLDIkLjHfU8,2177
52
- sandwitches/templates/partials/recipe_list.html,sha256=AVzz_fIE4cBVU-E2E0VpE1tFmUV8jy7QpOninZEUMi8,3952
53
- sandwitches/templates/recipe_form.html,sha256=TzdlzeSqUoJTDTuCdFbeF5jCBZUTZEtlTIC_IQM3WL8,4754
61
+ sandwitches/templates/partials/recipe_list.html,sha256=oF5zlgAyX_uG63BwulyhFywrn8QLnWXatXVtZPVcPmE,4186
62
+ sandwitches/templates/profile.html,sha256=PQTL6_xn0pGUxqEOYuz5j0pmqAyG0Wr3KvyFBO8_k1s,4156
63
+ sandwitches/templates/recipe_form.html,sha256=eaQN6331f4hxqrN_FhDXmT1i86Mknf072xpFXoFvoAo,5261
54
64
  sandwitches/templates/setup.html,sha256=iNveFgePATsCSO4XMbGPa8TnWHyvj8S_5WwcW6i7pbo,4661
55
65
  sandwitches/templates/signup.html,sha256=pNBSlRGZI_B5ccF3dWpUgWBcjODkdLlq7HhyJLYIHCI,6176
56
66
  sandwitches/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
67
  sandwitches/templatetags/custom_filters.py,sha256=0KDFlFz4b5LwlcURBAmzyYWKKea-LwydZytJGVkkuKA,243
58
68
  sandwitches/templatetags/markdown_extras.py,sha256=0ibmRzxE3r85x4k7kK71R-9UT0CgeegYF7MHzj3juTI,344
59
- sandwitches/urls.py,sha256=fT4JYLMrTS1IDgb3Ruivj69lXcW86Th44Lt4Kr6Tchs,3922
69
+ sandwitches/urls.py,sha256=bbFsx0G2_pl7LuhO6wHtnt-X890IsRQFOEsN2mqfdzo,4351
60
70
  sandwitches/utils.py,sha256=SJP-TkeRZ0OIfaMigYrOSbxRqYXswoqoWhwll3nFuAM,7245
61
- sandwitches/views.py,sha256=sQU4qU3p-zszHnTF67gqyhsPLw47CVd5mFM6OZqGrCI,20533
71
+ sandwitches/views.py,sha256=3gAUZuIIWevu2xW8ewxBWM5O-1hTarn8ZT9DJBTeDyw,25565
62
72
  sandwitches/wsgi.py,sha256=Eyncpnahq_4s3Lr9ruB-R3Lu9j9zBXqgPbUj7qhIbwU,399
63
- sandwitches-2.2.0.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
64
- sandwitches-2.2.0.dist-info/METADATA,sha256=6tQwqwzy-aFz3fzZdlN4Aw2L8xOTV8sx_TRcUpAs730,3111
65
- sandwitches-2.2.0.dist-info/RECORD,,
73
+ sandwitches-2.3.1.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
74
+ sandwitches-2.3.1.dist-info/METADATA,sha256=0FOR_loqc7pHOjzBvUU5HOWTToY-FQJ0EnU0Vc4HqxM,3111
75
+ sandwitches-2.3.1.dist-info/RECORD,,