Release 13 (devel -> main) #35

Merged
ChaoticByte merged 7 commits from devel into main 2022-11-05 09:54:19 +00:00
10 changed files with 278 additions and 68 deletions
Showing only changes of commit 86ea7c0000 - Show all commits

View file

@ -49,6 +49,10 @@ class CustomUserAdmin(UserAdmin):
{"fields": ("balance", "allow_order_with_negative_balance")}, {"fields": ("balance", "allow_order_with_negative_balance")},
)) ))
fieldsets_.insert(2, ( fieldsets_.insert(2, (
"Supply",
{"fields": ("allowed_to_supply",)},
))
fieldsets_.insert(3, (
"Profile Picture", "Profile Picture",
{"fields": ("profile_picture_filename",)}, {"fields": ("profile_picture_filename",)},
)) ))

View file

@ -21,6 +21,7 @@ class User(AbstractUser):
balance = models.DecimalField(max_digits=8, decimal_places=2, default=0.00) balance = models.DecimalField(max_digits=8, decimal_places=2, default=0.00)
allow_order_with_negative_balance = models.BooleanField(default=False) allow_order_with_negative_balance = models.BooleanField(default=False)
profile_picture_filename = models.CharField(default="default.svg", max_length=25) profile_picture_filename = models.CharField(default="default.svg", max_length=25)
allowed_to_supply = models.BooleanField(default=False)
def delete(self, *args, **kwargs): def delete(self, *args, **kwargs):
self.balance = 0 self.balance = 0

View file

@ -0,0 +1,61 @@
{% extends "baseLayout.html" %}
{% load i18n %}
{% load l10n %}
{% block title %}
{% translate "Drinks - Supply" %}
{% endblock %}
{% block headAdditional %}
<link rel="stylesheet" href="/static/css/supply.css">
<link rel="stylesheet" href="/static/css/customNumberInput.css">
{% endblock %}
{% block heading %}
{% translate "Supply" %}
{% endblock %}
{% block content %}
{% if user.is_superuser or user.allowed_to_supply %}
<form id="supplyForm">
{% csrf_token %}
<div class="row">
<div class="column">{% translate "Description" %}:</div>
<input type="text" name="supplyDescription" id="supplyDescription" autofocus>
</div>
<div class="row">
<div class="column">{% translate "Price" %} ({{ currency_suffix }}):</div>
<div class="column">
<input type="number" name="supplyPrice" id="supplyPrice" max="9999.99" min="1.00" step="0.01">
</div>
</div>
<div id="statusInfo"></div>
<div class="horizontalButtonList">
<a href="/" class="button">{% translate "cancel" %}</a>
<input type="submit" id="supplySubmitBtn" class="button" value='{% translate "submit" %}'>
</div>
</form>
<script src="/static/js/supply.js"></script>
<script src="/static/js/customNumberInput.js"></script>
{% else %}
<div class="centeringFlex">
<p>{% translate "You are not allowed to view this site." %}</p>
<a href="/">{% translate "back" %}</a>
</div>
{% endif %}
<script src="/static/js/autoreload.js"></script>
{% endblock %}

View file

@ -32,6 +32,9 @@
{% if user.is_superuser or user.is_staff %} {% if user.is_superuser or user.is_staff %}
<a class="button dropDownChoice" href="/admin/">Admin Panel</a> <a class="button dropDownChoice" href="/admin/">Admin Panel</a>
{% endif %} {% endif %}
{% if user.is_superuser or user.allowed_to_supply %}
<a class="button dropDownChoice" href="/supply/">{% translate "Supply" %}</a>
{% endif %}
<a class="button dropDownChoice" href="/accounts/password_change/">{% translate "Change Password" %}</a> <a class="button dropDownChoice" href="/accounts/password_change/">{% translate "Change Password" %}</a>
</div> </div>
</div> </div>

View file

@ -10,6 +10,7 @@ urlpatterns = [
path('history/', views.history), path('history/', views.history),
path('deposit/', views.deposit), path('deposit/', views.deposit),
path('statistics/', views.statistics), path('statistics/', views.statistics),
path('supply/', views.supply),
path('accounts/login/', views.login_page, name="login"), path('accounts/login/', views.login_page, name="login"),
path('accounts/logout/', auth_views.LogoutView.as_view(), name='logout'), path('accounts/logout/', auth_views.LogoutView.as_view(), name='logout'),
path('accounts/password_change/', auth_views.PasswordChangeView.as_view(), name='password_change'), path('accounts/password_change/', auth_views.PasswordChangeView.as_view(), name='password_change'),
@ -18,5 +19,6 @@ urlpatterns = [
# API # # API #
path('api/order-drink', views.api_order_drink), path('api/order-drink', views.api_order_drink),
path('api/deposit', views.api_deposit), path('api/deposit', views.api_deposit),
path('api/supply', views.api_supply)
#path('api/get-statistics', views.api_get_statistics) #path('api/get-statistics', views.api_get_statistics)
] ]

View file

@ -103,6 +103,10 @@ def statistics(request):
} }
return render(request, "statistics.html", context) return render(request, "statistics.html", context)
@login_required
def supply(request):
return render(request, "supply.html")
@login_required @login_required
def redirect_home(request): def redirect_home(request):
return HttpResponseRedirect("/") return HttpResponseRedirect("/")
@ -132,7 +136,7 @@ def api_order_drink(request):
else: else:
return HttpResponse("notAvailable", status=400) return HttpResponse("notAvailable", status=400)
else: raise Exception("Balance below zero.") else: raise Exception("Unexpected input or missing privileges.")
except Exception as e: except Exception as e:
print(f"An exception occured while processing an order: User: {user.username} - Exception: {e}", file=sys.stderr) print(f"An exception occured while processing an order: User: {user.username} - Exception: {e}", file=sys.stderr)
@ -163,5 +167,33 @@ def api_deposit(request):
else: raise Exception("Deposit amount too big or small.") else: raise Exception("Deposit amount too big or small.")
except Exception as e: except Exception as e:
print(f"An exception occured while processing an transaction: User: {user.username} - Exception: {e}", file=sys.stderr) print(f"An exception occured while processing a transaction: User: {user.username} - Exception: {e}", file=sys.stderr)
return HttpResponse(b"", status=500)
@login_required
def api_supply(request):
# check request -> supply
user = request.user
try:
price = decimal.Decimal(request.POST["supplyPrice"])
description = str(request.POST["supplyDescription"])
if 0.00 < price < 9999.99 and (user.allowed_to_supply or user.is_superuser):
# create transaction
RegisterTransaction.objects.create(
transaction_sum=-price,
comment=f"Supply: {description}",
is_user_deposit=False,
user=user
)
#
return HttpResponse("success", status=200)
else: raise Exception("Unexpected input or missing privileges.")
except Exception as e:
print(f"An exception occured while processing a supply transaction: User: {user.username} - Exception: {e}", file=sys.stderr)
return HttpResponse(b"", status=500) return HttpResponse(b"", status=500)

View file

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-06-13 19:01+0200\n" "POT-Creation-Date: 2022-10-15 19:20+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Julian MĂĽller (W13R)\n" "Last-Translator: Julian MĂĽller (W13R)\n"
"Language: DE\n" "Language: DE\n"
@ -17,221 +17,266 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: app/templates/admin/base_site.html:7 #: application/app/templates/admin/base_site.html:7
msgid "Django site admin" msgid "Django site admin"
msgstr "Django Administrator" msgstr "Django Administrator"
#: app/templates/admin/base_site.html:15 #: application/app/templates/admin/base_site.html:15
msgid "Django administration" msgid "Django administration"
msgstr "Django Administration" msgstr "Django Administration"
#: app/templates/baseLayout.html:41 #: application/app/templates/baseLayout.html:41
msgid "An error occured. Please log out and log in again." msgid "An error occured. Please log out and log in again."
msgstr "Ein Fehler ist aufgetreten. Bitte ab- und wieder anmelden." msgstr "Ein Fehler ist aufgetreten. Bitte ab- und wieder anmelden."
#: app/templates/deposit.html:6 #: application/app/templates/deposit.html:6
msgid "Drinks - Deposit" msgid "Drinks - Deposit"
msgstr "Getränke - Einzahlen" msgstr "Getränke - Einzahlen"
#: app/templates/deposit.html:14 app/templates/userPanel.html:19 #: application/app/templates/deposit.html:14
#: application/app/templates/userPanel.html:23
msgid "Deposit" msgid "Deposit"
msgstr "Einzahlen" msgstr "Einzahlen"
#: app/templates/deposit.html:23 #: application/app/templates/deposit.html:23
msgid "Amount" msgid "Amount"
msgstr "Summe" msgstr "Summe"
#: app/templates/deposit.html:31 app/templates/order.html:72 #: application/app/templates/deposit.html:31
#: app/templates/registration/login.html:56 #: application/app/templates/order.html:72
#: application/app/templates/registration/login.html:57
#: application/app/templates/supply.html:41
msgid "cancel" msgid "cancel"
msgstr "Abbrechen" msgstr "Abbrechen"
#: app/templates/deposit.html:32 #: application/app/templates/deposit.html:32
msgid "confirm" msgid "confirm"
msgstr "Bestätigen" msgstr "Bestätigen"
#: app/templates/history.html:6 #: application/app/templates/history.html:6
msgid "Drinks - History" msgid "Drinks - History"
msgstr "Getränke - Verlauf" msgstr "Getränke - Verlauf"
#: app/templates/history.html:14 app/templates/userPanel.html:25 #: application/app/templates/history.html:14
#: application/app/templates/userPanel.html:30
msgid "History" msgid "History"
msgstr "Verlauf" msgstr "Verlauf"
#: app/templates/history.html:22 #: application/app/templates/history.html:22
msgid "last 30 actions" msgid "last 30 actions"
msgstr "letzte 30 Vorgänge" msgstr "letzte 30 Vorgänge"
#: app/templates/history.html:33 app/templates/statistics.html:41 #: application/app/templates/history.html:33
#: app/templates/statistics.html:61 app/templates/statistics.html:81 #: application/app/templates/statistics.html:41
#: app/templates/statistics.html:101 app/templates/statistics.html:121 #: application/app/templates/statistics.html:61
#: app/templates/statistics.html:141 #: application/app/templates/statistics.html:81
#: application/app/templates/statistics.html:101
#: application/app/templates/statistics.html:121
#: application/app/templates/statistics.html:141
msgid "No history." msgid "No history."
msgstr "Kein Verlauf verfĂĽgbar." msgstr "Kein Verlauf verfĂĽgbar."
#: app/templates/index.html:6 #: application/app/templates/index.html:6
msgid "Drinks - Home" msgid "Drinks - Home"
msgstr "Getränke - Home" msgstr "Getränke - Home"
#: app/templates/index.html:14 #: application/app/templates/index.html:14
msgid "Available Drinks" msgid "Available Drinks"
msgstr "Verfügbare Getränke" msgstr "Verfügbare Getränke"
#: app/templates/index.html:27 app/templates/index.html:34 #: application/app/templates/index.html:27
#: application/app/templates/index.html:34
msgid "available" msgid "available"
msgstr "verfĂĽgbar" msgstr "verfĂĽgbar"
#: app/templates/index.html:43 #: application/app/templates/index.html:43
msgid "No drinks available." msgid "No drinks available."
msgstr "Es sind gerade keine Getränke verfügbar." msgstr "Es sind gerade keine Getränke verfügbar."
#: app/templates/order.html:7 #: application/app/templates/order.html:7
msgid "Drinks - Order" msgid "Drinks - Order"
msgstr "Getränke - Bestellen" msgstr "Getränke - Bestellen"
#: app/templates/order.html:16 #: application/app/templates/order.html:16
#: packages/django/forms/formsets.py:405 packages/django/forms/formsets.py:412
msgid "Order" msgid "Order"
msgstr "Bestellung" msgstr "Bestellung"
#: app/templates/order.html:29 #: application/app/templates/order.html:29
msgid "Drink" msgid "Drink"
msgstr "Getränk" msgstr "Getränk"
#: app/templates/order.html:34 #: application/app/templates/order.html:34
msgid "Price per Item" msgid "Price per Item"
msgstr "Preis pro Getränk" msgstr "Preis pro Getränk"
#: app/templates/order.html:40 #: application/app/templates/order.html:40
msgid "Available" msgid "Available"
msgstr "VerfĂĽgbar" msgstr "VerfĂĽgbar"
#: app/templates/order.html:46 #: application/app/templates/order.html:46
msgid "Count" msgid "Count"
msgstr "Anzahl" msgstr "Anzahl"
#: app/templates/order.html:63 #: application/app/templates/order.html:63
msgid "Sum" msgid "Sum"
msgstr "Summe" msgstr "Summe"
#: app/templates/order.html:73 #: application/app/templates/order.html:73
msgid "order" msgid "order"
msgstr "Bestellen" msgstr "Bestellen"
#: app/templates/order.html:85 #: application/app/templates/order.html:85
msgid "Your balance is too low to order a drink." msgid "Your balance is too low to order a drink."
msgstr "Dein Saldo ist zu niedrig um Getränke zu bestellen." msgstr "Dein Saldo ist zu niedrig um Getränke zu bestellen."
#: app/templates/order.html:86 app/templates/order.html:95 #: application/app/templates/order.html:86
#: application/app/templates/order.html:95
#: application/app/templates/supply.html:54
msgid "back" msgid "back"
msgstr "zurĂĽck" msgstr "zurĂĽck"
#: app/templates/order.html:94 #: application/app/templates/order.html:94
msgid "This drink is not available." msgid "This drink is not available."
msgstr "Dieses Getränk ist gerade nicht verfügbar." msgstr "Dieses Getränk ist gerade nicht verfügbar."
#: app/templates/registration/logged_out.html:7 #: application/app/templates/registration/logged_out.html:7
msgid "Drinks - Logged Out" msgid "Drinks - Logged Out"
msgstr "Getränke - Abgemeldet" msgstr "Getränke - Abgemeldet"
#: app/templates/registration/logged_out.html:17 #: application/app/templates/registration/logged_out.html:17
msgid "Logged out! You will be redirected shortly." msgid "Logged out! You will be redirected shortly."
msgstr "Du wurdest abgemeldet und wirst in KĂĽrze weitergeleitet." msgstr "Du wurdest abgemeldet und wirst in KĂĽrze weitergeleitet."
#: app/templates/registration/logged_out.html:19 #: application/app/templates/registration/logged_out.html:19
msgid "Click here if automatic redirection does not work." msgid "Click here if automatic redirection does not work."
msgstr "" msgstr ""
"Bitte klicke hier, wenn die automatische Weiterleitung nicht funktioniert." "Bitte klicke hier, wenn die automatische Weiterleitung nicht funktioniert."
#: app/templates/registration/login.html:7 #: application/app/templates/registration/login.html:8
msgid "Drinks - Login" msgid "Drinks - Login"
msgstr "Getränke - Anmeldung" msgstr "Getränke - Anmeldung"
#: app/templates/registration/login.html:26 #: application/app/templates/registration/login.html:27
msgid "Log in" msgid "Log in"
msgstr "Anmelden" msgstr "Anmelden"
#: app/templates/registration/login.html:28 #: application/app/templates/registration/login.html:29
msgid "Password/PIN" msgid "Password/PIN"
msgstr "Passwort/PIN" msgstr "Passwort/PIN"
#: app/templates/registration/login.html:57 #: application/app/templates/registration/login.html:58
msgid "login" msgid "login"
msgstr "Anmelden" msgstr "Anmelden"
#: app/templates/registration/login.html:65 #: application/app/templates/registration/login.html:66
msgid "Choose your account" msgid "Choose your account"
msgstr "Wähle deinen Account" msgstr "Wähle deinen Account"
#: app/templates/statistics.html:6 #: application/app/templates/statistics.html:6
msgid "Drinks - Statistics" msgid "Drinks - Statistics"
msgstr "Getränke - Statistiken" msgstr "Getränke - Statistiken"
#: app/templates/statistics.html:15 app/templates/userPanel.html:26 #: application/app/templates/statistics.html:15
#: application/app/templates/userPanel.html:31
msgid "Statistics" msgid "Statistics"
msgstr "Statistiken" msgstr "Statistiken"
#: app/templates/statistics.html:26 #: application/app/templates/statistics.html:26
msgid "Your orders per drink" msgid "Your orders per drink"
msgstr "Deine Bestellungen pro Getränk" msgstr "Deine Bestellungen pro Getränk"
#: app/templates/statistics.html:30 app/templates/statistics.html:50 #: application/app/templates/statistics.html:30
#: application/app/templates/statistics.html:50
msgid "drink" msgid "drink"
msgstr "Getränk" msgstr "Getränk"
#: app/templates/statistics.html:31 app/templates/statistics.html:51 #: application/app/templates/statistics.html:31
#: app/templates/statistics.html:71 app/templates/statistics.html:91 #: application/app/templates/statistics.html:51
#: app/templates/statistics.html:111 app/templates/statistics.html:131 #: application/app/templates/statistics.html:71
#: application/app/templates/statistics.html:91
#: application/app/templates/statistics.html:111
#: application/app/templates/statistics.html:131
msgid "count" msgid "count"
msgstr "Anzahl" msgstr "Anzahl"
#: app/templates/statistics.html:46 #: application/app/templates/statistics.html:46
msgid "All orders per drink" msgid "All orders per drink"
msgstr "Alle Bestellungen pro Getränk" msgstr "Alle Bestellungen pro Getränk"
#: app/templates/statistics.html:66 #: application/app/templates/statistics.html:66
msgid "Your orders per month (last 12 months)" msgid "Your orders per month (last 12 months)"
msgstr "Deine Bestellungen pro Monat (letzte 12 Monate)" msgstr "Deine Bestellungen pro Monat (letzte 12 Monate)"
#: app/templates/statistics.html:70 app/templates/statistics.html:90 #: application/app/templates/statistics.html:70
#: application/app/templates/statistics.html:90
msgid "month" msgid "month"
msgstr "Monat" msgstr "Monat"
#: app/templates/statistics.html:86 #: application/app/templates/statistics.html:86
msgid "All orders per month (last 12 months)" msgid "All orders per month (last 12 months)"
msgstr "Alle Bestellungen pro Monat (letzte 12 Monate)" msgstr "Alle Bestellungen pro Monat (letzte 12 Monate)"
#: app/templates/statistics.html:106 #: application/app/templates/statistics.html:106
msgid "Your orders per weekday" msgid "Your orders per weekday"
msgstr "Deine Bestellungen pro Wochentag" msgstr "Deine Bestellungen pro Wochentag"
#: app/templates/statistics.html:110 app/templates/statistics.html:130 #: application/app/templates/statistics.html:110
#: application/app/templates/statistics.html:130
msgid "day" msgid "day"
msgstr "Tag" msgstr "Tag"
#: app/templates/statistics.html:126 #: application/app/templates/statistics.html:126
msgid "All orders per weekday" msgid "All orders per weekday"
msgstr "Alle Bestellungen pro Wochentag" msgstr "Alle Bestellungen pro Wochentag"
#: app/templates/userPanel.html:6 app/templates/userPanel.html:8 #: application/app/templates/supply.html:7
msgid "Drinks - Supply"
msgstr "Getränke - Beschaffung"
#: application/app/templates/supply.html:16
#: application/app/templates/userPanel.html:36
msgid "Supply"
msgstr "Beschaffung"
#: application/app/templates/supply.html:27
msgid "Description"
msgstr "Beschreibung"
#: application/app/templates/supply.html:32
msgid "Price"
msgstr "Preis"
#: application/app/templates/supply.html:42
msgid "submit"
msgstr "Senden"
#: application/app/templates/supply.html:53
msgid "You are not allowed to view this site."
msgstr "Dir fehlt die Berechtigung, diese Seite anzuzeigen."
#: application/app/templates/userPanel.html:9
#: application/app/templates/userPanel.html:11
msgid "User" msgid "User"
msgstr "Benutzer" msgstr "Benutzer"
#: app/templates/userPanel.html:12 app/templates/userPanel.html:14 #: application/app/templates/userPanel.html:15
#: application/app/templates/userPanel.html:17
msgid "Balance" msgid "Balance"
msgstr "Saldo" msgstr "Saldo"
#: app/templates/userPanel.html:22 #: application/app/templates/userPanel.html:24
msgid "Account"
msgstr "Account"
#: app/templates/userPanel.html:30
msgid "Change Password"
msgstr "Passwort ändern"
#: app/templates/userPanel.html:31
msgid "Logout" msgid "Logout"
msgstr "Abmelden" msgstr "Abmelden"
#: app/views.py:47 #: application/app/templates/userPanel.html:27
msgid "Account"
msgstr "Account"
#: application/app/templates/userPanel.html:38
msgid "Change Password"
msgstr "Passwort ändern"
#: application/app/views.py:47
msgid "Invalid username or password." msgid "Invalid username or password."
msgstr "Benutzername oder Passwort ungĂĽltig." msgstr "Benutzername oder Passwort ungĂĽltig."

6
static/css/supply.css Normal file
View file

@ -0,0 +1,6 @@
form {
width: 24rem;
}
#supplyPrice {
width: 10rem;
}

56
static/js/supply.js Normal file
View file

@ -0,0 +1,56 @@
document.addEventListener("DOMContentLoaded", () => {
// elements
let supply_description = document.getElementById("supplyDescription");
let supply_price = document.getElementById("supplyPrice");
let supply_form = document.getElementById("supplyForm");
let status_info = document.getElementById("statusInfo");
let supply_submit_button = document.getElementById("supplySubmitBtn");
// custom submit method
supply_form.addEventListener("submit", (event) => {
supply_submit_button.disabled = true;
event.preventDefault(); // Don't do the default submit action!
if (isNaN(parseFloat(supply_price.value)) || supply_description.value == "") {
status_info.innerText = "Please enter a description and price."
supply_submit_button.disabled = false;
}
let xhr = new XMLHttpRequest();
let formData = new FormData(supply_form);
xhr.addEventListener("load", (event) => {
status_ = event.target.status;
response_ = event.target.responseText;
if (status_ == 200 && response_ == "success") {
status_info.innerText = "Success.";
window.location.replace("/");
}
else {
status_info.classList.add("errorText");
status_info.innerText = "An error occured.";
window.setTimeout(() => { window.location.reload() }, 5000);
}
})
xhr.addEventListener("error", (event) => {
status_info.classList.add("errorText");
status_info.innerText = "An error occured.";
window.setTimeout(() => { window.location.reload() }, 5000);
})
xhr.open("POST", "/api/supply");
xhr.send(formData);
});
})