1 Commits

Author SHA1 Message Date
9b1a81fd91 Update dependency gunicorn to v25 2026-02-19 17:00:56 +00:00
25 changed files with 601 additions and 1255 deletions

View File

@@ -1,10 +0,0 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
max_line_length = 120
trim_trailing_whitespace = true

View File

@@ -1,10 +1,8 @@
FROM python:3.14-alpine
ENV PYTHONUNBUFFERED=1
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /usr/local/bin/
WORKDIR /app
COPY pyproject.toml .
ENV VIRTUAL_ENV=/opt/venv
RUN uv venv $VIRTUAL_ENV && uv pip install -r pyproject.toml
ENV PATH="/opt/venv/bin:$PATH"
WORKDIR /code/
COPY requirements.txt .
RUN pip install --upgrade pip && \
pip install --no-cache-dir --requirement requirements.txt
COPY . .
ENTRYPOINT ["./entrypoint.sh"]

View File

@@ -1,29 +1,30 @@
services:
db:
image: postgres:18-alpine
init: true
environment:
POSTGRES_DB: "gaehsnitzdb"
POSTGRES_USER: "gaehsnitzuser"
POSTGRES_PASSWORD: "SCKL97ukwICPpjJ9rXyhdljZ86T29A"
expose:
- "5432"
volumes:
- ./volumes/db/postgresql:/var/lib/postgresql:rw
web:
build:
context: .
init: true
environment:
DB_HOST: "db"
DB_PORT: "5432"
DB_NAME: "gaehsnitzdb"
DB_USER: "gaehsnitzuser"
DB_PASSWORD: "SCKL97ukwICPpjJ9rXyhdljZ86T29A"
depends_on:
- db
ports:
- "80:8000"
volumes:
- .:/app
db:
image: postgres:18-alpine
init: true
environment:
POSTGRES_DB: "gaehsnitzdb"
POSTGRES_USER: "gaehsnitzuser"
POSTGRES_PASSWORD: "SCKL97ukwICPpjJ9rXyhdljZ86T29A"
expose:
- "5432"
volumes:
- ./volumes/db/data:/var/lib/postgresql/data:rw
web:
build:
context: .
init: true
environment:
DB_HOST: "db"
DB_PORT: "5432"
DB_NAME: "gaehsnitzdb"
DB_USER: "gaehsnitzuser"
DB_PASSWORD: "SCKL97ukwICPpjJ9rXyhdljZ86T29A"
depends_on:
- db
ports:
- "80:8000"
volumes:
- .:/code:rw

View File

@@ -20,18 +20,17 @@ class CustomUserAdmin(UserAdmin):
ordering = ("username",)
list_filter = []
fieldsets = (
(
None,
{
"fields": (
"username",
"password",
)
},
),
("BALANCE", {"fields": ("consumed_drinks_price",)}),
(None, {"fields": (
"username",
"password",
)}),
("BALANCE", {"fields": (
"consumed_drinks_price",
)}),
)
readonly_fields = (
"consumed_drinks_price",
)
readonly_fields = ("consumed_drinks_price",)
inlines = (ConsumptionInline,)
def consumed_drinks_price(self, user: User):
@@ -62,88 +61,52 @@ class PaymentAdmin(admin.ModelAdmin):
class DrinkAdmin(admin.ModelAdmin):
list_display = ("name", "purchase_price_per_crate", "crates_purchased", "purchase_price_total")
fieldsets = (
(None, {"fields": ("name",)}),
(
"crates",
{
"fields": (
"crates_ordered",
"crates_purchased",
"crates_returned",
)
},
),
(
"bottles",
{
"fields": (
"bottles_per_crate",
"bottles_total",
"bottles_returned",
)
},
),
(
"amount",
{
"fields": (
"bottle_size",
"amount_per_crate",
"amount_total",
)
},
),
(
"purchase",
{
"fields": (
"purchase_price_per_crate",
"purchase_price_per_bottle",
"purchase_price_total",
)
},
),
(
"deposit",
{
"fields": (
"deposit_per_crate",
"deposit_total",
"deposit_refund",
"deposit_kept",
)
},
),
(
"sales",
{
"fields": (
"sale_price_per_bottle",
"bottles_sold",
"sales_purchase_value",
"sale_price_total",
"bottles_given_away",
"giveaway_purchase_value",
"balance",
)
},
),
(None, {"fields": (
"name",
)}),
("crates", {"fields": (
"crates_ordered",
"crates_purchased",
"crates_returned",
)}),
("bottles", {"fields": (
"bottles_per_crate",
"bottles_total",
"bottles_returned",
)}),
("amount", {"fields": (
"bottle_size",
"amount_per_crate",
"amount_total",
)}),
("purchase", {"fields": (
"purchase_price_per_crate",
"purchase_price_per_bottle",
"purchase_price_total",
)}),
("deposit", {"fields": (
"deposit_per_crate",
"deposit_total",
"deposit_refund",
"deposit_kept",
)}),
("sales", {"fields": (
"sale_price_per_bottle",
"bottles_sold",
"sales_purchase_value",
"sale_price_total",
"bottles_given_away",
"giveaway_purchase_value",
"balance",
)}),
)
readonly_fields = (
"bottles_total",
"bottles_returned",
"amount_per_crate",
"amount_total",
"purchase_price_per_bottle",
"purchase_price_total",
"deposit_total",
"deposit_refund",
"deposit_kept",
"bottles_sold",
"sales_purchase_value",
"sale_price_total",
"bottles_given_away",
"giveaway_purchase_value",
"bottles_total", "bottles_returned",
"amount_per_crate", "amount_total",
"purchase_price_per_bottle", "purchase_price_total",
"deposit_total", "deposit_refund", "deposit_kept",
"bottles_sold", "sales_purchase_value", "sale_price_total",
"bottles_given_away", "giveaway_purchase_value",
"balance",
)

View File

@@ -46,14 +46,16 @@ def payback(user, day, month, amount, note):
def consumption(day: int, for_free: bool, drink_dict: Dict[User, List[Tuple[int, Drink]]]):
for user, drink_list in drink_dict.items():
for amount, drink in drink_list:
Consumption.objects.create(user=user, drink=drink, amount=amount, day=day, for_free=for_free)
Consumption.objects.create(
user=user, drink=drink, amount=amount, day=day, for_free=for_free)
class Command(BaseCommand):
@transaction.atomic()
def handle(self, *args, **options):
if any(model.objects.exists() for model in [Donation, Payment, Drink, Consumption]):
raise CommandError("clear all donation, payment, drink and consumption objects before running this command")
raise CommandError(
"clear all donation, payment, drink and consumption objects before running this command")
# --------------- PEOPLE ---------------
@@ -222,106 +224,82 @@ class Command(BaseCommand):
# --------------- THURSDAY ---------------
consumption(
day=1,
for_free=False,
drink_dict={
robert: [(2, mate), (2, radler), (1, wasser)],
thure: [(4, sterni), (1, krosti), (2, radler)],
tobi: [(7, sterni), (2, krosti)],
herald: [(1, radler), (2, wasser), (4, wein)],
annemarie: [(1, sterni), (1, wasser), (2, wein)],
cathi_clemens: [(1, sterni), (2, radler)],
flo: [(6, sterni), (1, wasser)],
josi: [(4, sterni)],
aimee: [(5, sterni)],
lutz: [(1, sterni), (1, wasser)],
lasse: [(2, sterni), (1, wasser)],
domi: [(1, sterni), (1, radler)],
},
)
consumption(
day=1,
for_free=True,
drink_dict={
seth_family: [(1, krosti), (1, radler)],
},
)
consumption(day=1, for_free=False, drink_dict={
robert: [(2, mate), (2, radler), (1, wasser)],
thure: [(4, sterni), (1, krosti), (2, radler)],
tobi: [(7, sterni), (2, krosti)],
herald: [(1, radler), (2, wasser), (4, wein)],
annemarie: [(1, sterni), (1, wasser), (2, wein)],
cathi_clemens: [(1, sterni), (2, radler)],
flo: [(6, sterni), (1, wasser)],
josi: [(4, sterni)],
aimee: [(5, sterni)],
lutz: [(1, sterni), (1, wasser)],
lasse: [(2, sterni), (1, wasser)],
domi: [(1, sterni), (1, radler)],
})
consumption(day=1, for_free=True, drink_dict={
seth_family: [(1, krosti), (1, radler)],
})
# --------------- FRIDAY ---------------
consumption(
day=2,
for_free=False,
drink_dict={
robert: [(2, mate), (1, radler)],
thure: [(8, sterni), (2, krosti), (1, wasser)],
tobi: [(2, mate), (5, sterni), (5, krosti), (3, radler), (1, cola)],
herald: [(1, mate), (1, sterni), (2, radler), (1, cola), (4, wasser), (7, wein)],
annemarie: [(2, mate), (9, sterni), (1, krosti), (2, radler), (3, wasser)],
cathi_clemens: [(3, sterni), (3, radler)],
flo: [(1, mate), (6, sterni), (3, wasser)],
josi: [(8, sterni), (1, krosti), (2, radler)],
andrew: [(4, sterni)],
peter: [(7, sterni), (1, krosti), (2, wasser)],
fiddi_melli: [(6, sterni), (3, radler), (1, wasser)],
suse: [(1, krosti), (1, radler)],
lilly_simon: [(1, mate), (7, sterni), (3, wasser)],
},
)
consumption(day=2, for_free=False, drink_dict={
robert: [(2, mate), (1, radler)],
thure: [(8, sterni), (2, krosti), (1, wasser)],
tobi: [(2, mate), (5, sterni), (5, krosti), (3, radler), (1, cola)],
herald: [(1, mate), (1, sterni), (2, radler), (1, cola), (4, wasser), (7, wein)],
annemarie: [(2, mate), (9, sterni), (1, krosti), (2, radler), (3, wasser)],
cathi_clemens: [(3, sterni), (3, radler)],
flo: [(1, mate), (6, sterni), (3, wasser)],
josi: [(8, sterni), (1, krosti), (2, radler)],
andrew: [(4, sterni)],
peter: [(7, sterni), (1, krosti), (2, wasser)],
fiddi_melli: [(6, sterni), (3, radler), (1, wasser)],
suse: [(1, krosti), (1, radler)],
lilly_simon: [(1, mate), (7, sterni), (3, wasser)]
})
consumption(
day=2,
for_free=True,
drink_dict={
seth_family: [(1, mate), (6, sterni), (3, wasser)],
aimee: [(1, mate), (9, sterni), (3, wasser)],
lutz: [(1, mate), (9, sterni), (3, wasser)],
lasse: [(7, sterni), (1, wasser)],
domi: [(1, mate), (4, sterni), (1, wasser)],
hans_welle: [(3, mate), (7, sterni), (7, krosti), (1, cola), (2, wasser)],
},
)
consumption(day=2, for_free=True, drink_dict={
seth_family: [(1, mate), (6, sterni), (3, wasser)],
aimee: [(1, mate), (9, sterni), (3, wasser)],
lutz: [(1, mate), (9, sterni), (3, wasser)],
lasse: [(7, sterni), (1, wasser)],
domi: [(1, mate), (4, sterni), (1, wasser)],
hans_welle: [(3, mate), (7, sterni), (7, krosti), (1, cola), (2, wasser)],
})
# --------------- SATURDAY ---------------
consumption(
day=3,
for_free=False,
drink_dict={
robert: [(4, mate), (1, cola), (4, wasser)],
tobi: [(9, sterni), (1, krosti), (2, radler), (1, cola)],
herald: [(2, mate), (2, radler), (3, wasser), (5, wein)],
annemarie: [(2, mate), (6, sterni), (3, radler), (1, cola), (1, wasser)],
cathi_clemens: [(4, sterni), (8, radler), (1, wasser)],
flo: [(2, mate), (8, sterni), (1, radler), (3, wasser)],
josi: [(9, sterni), (2, radler), (2, wasser)],
aimee: [(10, sterni), (2, radler)],
lutz: [(1, krosti), (1, wasser)],
lasse: [(1, mate), (8, sterni)],
domi: [(6, sterni), (2, radler), (1, wasser)],
peter: [(3, sterni), (3, krosti), (2, radler)],
fiddi_melli: [(1, mate), (1, wasser)],
suse: [(1, mate), (1, sterni), (2, krosti), (4, radler)],
lilly_simon: [(1, mate), (2, radler), (7, wasser)],
kevin: [(1, mate), (1, radler)],
rebecca: [(1, radler)],
resi_simon: [(8, sterni), (1, radler), (1, wasser)],
},
)
consumption(day=3, for_free=False, drink_dict={
robert: [(4, mate), (1, cola), (4, wasser)],
tobi: [(9, sterni), (1, krosti), (2, radler), (1, cola)],
herald: [(2, mate), (2, radler), (3, wasser), (5, wein)],
annemarie: [(2, mate), (6, sterni), (3, radler), (1, cola), (1, wasser)],
cathi_clemens: [(4, sterni), (8, radler), (1, wasser)],
flo: [(2, mate), (8, sterni), (1, radler), (3, wasser)],
josi: [(9, sterni), (2, radler), (2, wasser)],
aimee: [(10, sterni), (2, radler)],
lutz: [(1, krosti), (1, wasser)],
lasse: [(1, mate), (8, sterni)],
domi: [(6, sterni), (2, radler), (1, wasser)],
peter: [(3, sterni), (3, krosti), (2, radler)],
fiddi_melli: [(1, mate), (1, wasser)],
suse: [(1, mate), (1, sterni), (2, krosti), (4, radler)],
lilly_simon: [(1, mate), (2, radler), (7, wasser)],
kevin: [(1, mate), (1, radler)],
rebecca: [(1, radler)],
resi_simon: [(8, sterni), (1, radler), (1, wasser)],
})
consumption(
day=3,
for_free=True,
drink_dict={
thure: [(1, mate), (4, sterni), (5, radler), (3, wasser)],
seth_family: [(1, mate), (2, sterni), (12, krosti), (1, wasser)],
andrew: [(3, sterni), (2, krosti), (3, radler), (1, wasser)],
robin: [(1, mate), (4, krosti), (2, radler)],
melokomplott: [(5, mate), (13, sterni), (1, krosti), (1, radler)],
residudes: [(2, mate), (1, sterni), (15, krosti), (7, radler), (1, wasser)],
},
)
consumption(day=3, for_free=True, drink_dict={
thure: [(1, mate), (4, sterni), (5, radler), (3, wasser)],
seth_family: [(1, mate), (2, sterni), (12, krosti), (1, wasser)],
andrew: [(3, sterni), (2, krosti), (3, radler), (1, wasser)],
robin: [(1, mate), (4, krosti), (2, radler)],
melokomplott: [(5, mate), (13, sterni), (1, krosti), (1, radler)],
residudes: [(2, mate), (1, sterni), (15, krosti), (7, radler), (1, wasser)],
})
# --------------- ADMIN STUFF ---------------

View File

@@ -35,14 +35,16 @@ def payment(purpose, day, month, amount):
def consumption(day: int, for_free: bool, drink_dict: Dict[User, List[Tuple[int, Drink]]]):
for user, drink_list in drink_dict.items():
for amount, drink in drink_list:
Consumption.objects.create(user=user, drink=drink, amount=amount, day=day, for_free=for_free)
Consumption.objects.create(
user=user, drink=drink, amount=amount, day=day, for_free=for_free)
class Command(BaseCommand):
@transaction.atomic()
def handle(self, *args, **options):
if any(model.objects.exists() for model in [Donation, Payment, Drink, Consumption]):
raise CommandError("clear all donation, payment, drink and consumption objects before running this command")
raise CommandError(
"clear all donation, payment, drink and consumption objects before running this command")
# --------------- PEOPLE ---------------
@@ -230,106 +232,86 @@ class Command(BaseCommand):
# --------------- THURSDAY ---------------
consumption(
day=1,
for_free=False,
drink_dict={
enni: [(2, wasser), (9, sterni)],
robert: [(2, wasser), (2, freiberger), (1, spezi), (2, mate)],
josi: [(5, sterni), (1, radler)],
tobi: [(5, sterni), (1, freiberger), (2, mate)],
annemarie: [(1, wasser), (4, sterni), (1, radler)],
sandra: [(1, wasser), (3, sterni), (1, spezi), (1, mate)],
flo: [(2, wasser), (5, sterni), (1, mate), (1, helles)],
},
)
consumption(day=1, for_free=False, drink_dict={
enni: [(2, wasser), (9, sterni)],
robert: [(2, wasser), (2, freiberger), (1, spezi), (2, mate)],
josi: [(5, sterni), (1, radler)],
tobi: [(5, sterni), (1, freiberger), (2, mate)],
annemarie: [(1, wasser), (4, sterni), (1, radler)],
sandra: [(1, wasser), (3, sterni), (1, spezi), (1, mate)],
flo: [(2, wasser), (5, sterni), (1, mate), (1, helles)],
})
# --------------- FRIDAY ---------------
consumption(
day=2,
for_free=False,
drink_dict={
tobi: [(2, wasser), (9, sterni), (2, freiberger)],
annemarie: [(1, wasser), (5, sterni), (2, mate), (2, radler), (2, buddi), (3, sekt)],
sandra: [(1, freiberger), (1, buddi), (1, spezi), (2, mate), (1, radler), (2, sekt)],
robert: [(2, wasser), (1, freiberger), (1, buddi), (1, spezi)],
josi: [(2, wasser), (6, sterni), (1, freiberger), (2, radler)],
enni: [(2, wasser), (10, sterni), (1, spezi)],
steven: [(1, sterni), (1, krosti), (1, radler), (5, helles)],
marten: [(9, krosti)],
thure: [(4, sterni)],
jona: [(2, freiberger), (10, krosti)],
benni: [(5, krosti), (1, helles)],
katha: [(1, krosti), (1, mate)],
diana: [(5, sterni), (1, radler)],
katz: [(3, krosti), (1, buddi)],
alexius: [(8, sterni)],
pauline: [(5, sterni), (1, radler)],
herald: [(1, wasser), (2, sterni), (1, freiberger)],
arthur: [(6, sterni), (1, radler)],
matze: [(1, sterni), (1, freiberger)],
dennis: [(1, sterni), (2, krosti)],
marvin: [(3, sterni), (1, krosti), (1, mate)],
simon: [(1, sterni)],
},
)
consumption(day=2, for_free=False, drink_dict={
tobi: [(2, wasser), (9, sterni), (2, freiberger)],
annemarie: [(1, wasser), (5, sterni), (2, mate), (2, radler), (2, buddi), (3, sekt)],
sandra: [(1, freiberger), (1, buddi), (1, spezi), (2, mate), (1, radler), (2, sekt)],
robert: [(2, wasser), (1, freiberger), (1, buddi), (1, spezi)],
josi: [(2, wasser), (6, sterni), (1, freiberger), (2, radler)],
enni: [(2, wasser), (10, sterni), (1, spezi)],
steven: [(1, sterni), (1, krosti), (1, radler), (5, helles)],
marten: [(9, krosti)],
thure: [(4, sterni)],
jona: [(2, freiberger), (10, krosti)],
benni: [(5, krosti), (1, helles)],
katha: [(1, krosti), (1, mate)],
diana: [(5, sterni), (1, radler)],
katz: [(3, krosti), (1, buddi)],
alexius: [(8, sterni)],
pauline: [(5, sterni), (1, radler)],
herald: [(1, wasser), (2, sterni), (1, freiberger)],
arthur: [(6, sterni), (1, radler)],
matze: [(1, sterni), (1, freiberger)],
dennis: [(1, sterni), (2, krosti)],
marvin: [(3, sterni), (1, krosti), (1, mate)],
simon: [(1, sterni)],
})
consumption(
day=2,
for_free=True,
drink_dict={
flo: [(2, wasser), (3, sterni), (1, freiberger), (3, helles)],
casi: [(6, sterni)],
sepp: [(6, sterni)],
ohli: [(4, sterni)],
marius: [(1, radler)],
anonym: [(10, sterni), (10, krosti), (2, radler), (4, helles), (1, sekt)],
},
)
consumption(day=2, for_free=True, drink_dict={
flo: [(2, wasser), (3, sterni), (1, freiberger), (3, helles)],
casi: [(6, sterni)],
sepp: [(6, sterni)],
ohli: [(4, sterni)],
marius: [(1, radler)],
anonym: [(10, sterni), (10, krosti), (2, radler), (4, helles), (1, sekt)]
})
# --------------- SATURDAY ---------------
consumption(
day=3,
for_free=False,
drink_dict={
herald: [(1, sterni), (2, freiberger), (2, radler), (1, buddi), (5, spezi), (2, wasser)],
thure: [(6, sterni), (1, krosti), (1, radler), (2, spezi)],
sandra: [(6, sterni), (1, freiberger), (2, radler), (1, mate), (1, cola), (1, sekt)],
marvin: [(1, sterni), (1, mate)],
simon: [(10, sterni), (1, radler), (1, mate)],
jona: [(6, sterni), (4, krosti)],
robert: [(1, sterni), (1, freiberger), (1, buddi), (2, mate), (2, spezi), (3, wasser)],
steven: [(5, helles), (1, sterni), (2, radler), (1, mate)],
flo: [(4, helles), (1, freiberger), (1, buddi), (2, mate)],
matze: [(4, sterni), (2, radler), (3, buddi), (7, spezi)],
alexius: [(2, helles), (3, sterni), (1, radler), (1, cola)],
josi: [(5, sterni), (1, radler), (2, mate), (2, wasser), (1, sekt)],
benni: [(1, helles), (2, krosti), (2, radler), (1, wasser)],
ohli: [(1, helles), (3, sterni), (2, krosti), (1, radler), (1, buddi), (1, mate)],
arthur: [(3, sterni), (1, krosti), (1, radler), (1, mate), (3, spezi), (2, sekt)],
pauline: [(2, sterni), (2, radler), (1, mate), (1, cola)],
enni: [(9, sterni), (1, spezi), (2, wasser), (1, sekt)],
annemarie: [(5, sterni), (4, radler), (2, buddi), (1, mate), (1, wasser), (2, sekt)],
tobi: [(3, sterni), (1, radler), (1, mate), (1, wasser)],
marten: [(4, helles), (1, krosti)],
lukas: [(4, sterni), (1, spezi)],
lilly: [(5, sterni), (1, mate)],
andrea: [(1, buddi)],
lena: [(1, sterni)],
anonym: [(2, helles), (3, sterni), (5, krosti), (2, radler), (1, cola), (2, sekt)],
},
)
consumption(day=3, for_free=False, drink_dict={
herald: [(1, sterni), (2, freiberger), (2, radler), (1, buddi), (5, spezi), (2, wasser)],
thure: [(6, sterni), (1, krosti), (1, radler), (2, spezi)],
sandra: [(6, sterni), (1, freiberger), (2, radler), (1, mate), (1, cola), (1, sekt)],
marvin: [(1, sterni), (1, mate)],
simon: [(10, sterni), (1, radler), (1, mate)],
jona: [(6, sterni), (4, krosti)],
robert: [(1, sterni), (1, freiberger), (1, buddi), (2, mate), (2, spezi), (3, wasser)],
steven: [(5, helles), (1, sterni), (2, radler), (1, mate)],
flo: [(4, helles), (1, freiberger), (1, buddi), (2, mate)],
matze: [(4, sterni), (2, radler), (3, buddi), (7, spezi)],
alexius: [(2, helles), (3, sterni), (1, radler), (1, cola)],
josi: [(5, sterni), (1, radler), (2, mate), (2, wasser), (1, sekt)],
benni: [(1, helles), (2, krosti), (2, radler), (1, wasser)],
ohli: [(1, helles), (3, sterni), (2, krosti), (1, radler), (1, buddi), (1, mate)],
arthur: [(3, sterni), (1, krosti), (1, radler), (1, mate), (3, spezi), (2, sekt)],
pauline: [(2, sterni), (2, radler), (1, mate), (1, cola)],
enni: [(9, sterni), (1, spezi), (2, wasser), (1, sekt)],
annemarie: [(5, sterni), (4, radler), (2, buddi), (1, mate), (1, wasser), (2, sekt)],
tobi: [(3, sterni), (1, radler), (1, mate), (1, wasser)],
marten: [(4, helles), (1, krosti)],
lukas: [(4, sterni), (1, spezi)],
lilly: [(5, sterni), (1, mate)],
andrea: [(1, buddi)],
lena: [(1, sterni)],
anonym: [(2, helles), (3, sterni), (5, krosti), (2, radler), (1, cola), (2, sekt)]
})
consumption(
day=3,
for_free=True,
drink_dict={
rockbert: [(8, krosti), (1, radler), (1, mate)],
anonym: [(8, sterni), (2, krosti), (2, mate), (1, cola)],
},
)
consumption(day=3, for_free=True, drink_dict={
rockbert: [(8, krosti), (1, radler), (1, mate)],
anonym: [(8, sterni), (2, krosti), (2, mate), (1, cola)]
})
# --------------- ADMIN STUFF ---------------

View File

@@ -20,4 +20,4 @@ class Command(BaseCommand):
name = id_to_name[drink_dict["drink_id"]]
amount = drink_dict["amount"]
drink_list.append(f"{amount}x {name}")
print(f"{user.username.capitalize()}: {euro(to_pay)} ({', '.join(drink_list)})")
print(f"{user.username.capitalize()}: {euro(to_pay)} ({", ".join(drink_list)})")

View File

@@ -10,189 +10,94 @@ import gaehsnitz.models
class Migration(migrations.Migration):
initial = True
dependencies = [
("auth", "0012_alter_user_first_name_max_length"),
('auth', '0012_alter_user_first_name_max_length'),
]
operations = [
migrations.CreateModel(
name="User",
name='User',
fields=[
("id", models.SmallAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("password", models.CharField(max_length=128, verbose_name="password")),
("last_login", models.DateTimeField(blank=True, null=True, verbose_name="last login")),
(
"is_superuser",
models.BooleanField(
default=False,
help_text="Designates that this user has all permissions without explicitly assigning them.",
verbose_name="superuser status",
),
),
(
"username",
models.CharField(
error_messages={"unique": "A user with that username already exists."},
help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
max_length=150,
unique=True,
validators=[django.contrib.auth.validators.UnicodeUsernameValidator()],
verbose_name="username",
),
),
("first_name", models.CharField(blank=True, max_length=150, verbose_name="first name")),
("last_name", models.CharField(blank=True, max_length=150, verbose_name="last name")),
("email", models.EmailField(blank=True, max_length=254, verbose_name="email address")),
(
"is_staff",
models.BooleanField(
default=False,
help_text="Designates whether the user can log into this admin site.",
verbose_name="staff status",
),
),
(
"is_active",
models.BooleanField(
default=True,
help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
verbose_name="active",
),
),
("date_joined", models.DateTimeField(default=django.utils.timezone.now, verbose_name="date joined")),
(
"groups",
models.ManyToManyField(
blank=True,
help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.",
related_name="user_set",
related_query_name="user",
to="auth.group",
verbose_name="groups",
),
),
(
"user_permissions",
models.ManyToManyField(
blank=True,
help_text="Specific permissions for this user.",
related_name="user_set",
related_query_name="user",
to="auth.permission",
verbose_name="user permissions",
),
),
('id', models.SmallAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
],
options={
"verbose_name": "user",
"verbose_name_plural": "users",
"abstract": False,
'verbose_name': 'user',
'verbose_name_plural': 'users',
'abstract': False,
},
managers=[
("objects", django.contrib.auth.models.UserManager()),
('objects', django.contrib.auth.models.UserManager()),
],
),
migrations.CreateModel(
name="Drink",
name='Drink',
fields=[
("id", models.SmallAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("name", models.CharField(max_length=32, unique=True)),
(
"crates_ordered",
models.PositiveSmallIntegerField(
help_text="just informational to see how good we planned, not the actual consumed/paid drinks"
),
),
("crates_purchased", models.PositiveSmallIntegerField()),
("crates_returned", models.PositiveSmallIntegerField()),
("purchase_price_per_crate", gaehsnitz.models.PriceField(decimal_places=2, max_digits=6)),
("deposit_per_crate", gaehsnitz.models.PriceField(decimal_places=2, max_digits=6)),
("bottles_per_crate", models.PositiveSmallIntegerField()),
("bottle_size", models.FloatField()),
("sale_price_per_bottle", gaehsnitz.models.PriceField(decimal_places=2, max_digits=6)),
('id', models.SmallAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=32, unique=True)),
('crates_ordered', models.PositiveSmallIntegerField(help_text='just informational to see how good we planned, not the actual consumed/paid drinks')),
('crates_purchased', models.PositiveSmallIntegerField()),
('crates_returned', models.PositiveSmallIntegerField()),
('purchase_price_per_crate', gaehsnitz.models.PriceField(decimal_places=2, max_digits=6)),
('deposit_per_crate', gaehsnitz.models.PriceField(decimal_places=2, max_digits=6)),
('bottles_per_crate', models.PositiveSmallIntegerField()),
('bottle_size', models.FloatField()),
('sale_price_per_bottle', gaehsnitz.models.PriceField(decimal_places=2, max_digits=6)),
],
),
migrations.CreateModel(
name="Payment",
name='Payment',
fields=[
("id", models.SmallAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("purpose", models.CharField(max_length=64)),
("date", models.DateField()),
("amount", gaehsnitz.models.PriceField(decimal_places=2, max_digits=6)),
(
"from_user",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
related_name="payments",
related_query_name="payment",
to=settings.AUTH_USER_MODEL,
),
),
('id', models.SmallAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('purpose', models.CharField(max_length=64)),
('date', models.DateField()),
('amount', gaehsnitz.models.PriceField(decimal_places=2, max_digits=6)),
('from_user', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='payments', related_query_name='payment', to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name="Payback",
name='Payback',
fields=[
("id", models.SmallAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("date", models.DateField()),
("amount", gaehsnitz.models.PriceField(decimal_places=2, max_digits=6)),
("note", models.CharField(blank=True, default="", max_length=64)),
(
"to_user",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
related_name="paybacks",
related_query_name="payback",
to=settings.AUTH_USER_MODEL,
),
),
('id', models.SmallAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('date', models.DateField()),
('amount', gaehsnitz.models.PriceField(decimal_places=2, max_digits=6)),
('note', models.CharField(blank=True, default='', max_length=64)),
('to_user', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='paybacks', related_query_name='payback', to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name="Donation",
name='Donation',
fields=[
("id", models.SmallAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("date", models.DateField()),
("amount", gaehsnitz.models.PriceField(decimal_places=2, max_digits=6)),
("note", models.CharField(blank=True, default="", max_length=64)),
(
"from_user",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
related_name="donations",
related_query_name="donation",
to=settings.AUTH_USER_MODEL,
),
),
('id', models.SmallAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('date', models.DateField()),
('amount', gaehsnitz.models.PriceField(decimal_places=2, max_digits=6)),
('note', models.CharField(blank=True, default='', max_length=64)),
('from_user', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='donations', related_query_name='donation', to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name="Consumption",
name='Consumption',
fields=[
("id", models.SmallAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("amount", models.PositiveSmallIntegerField()),
("day", models.PositiveSmallIntegerField(choices=[(1, "Do"), (2, "Fr"), (3, "Sa")])),
("for_free", models.BooleanField(default=False)),
(
"drink",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="consumption_list",
related_query_name="consumption",
to="gaehsnitz.drink",
),
),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="consumption_list",
related_query_name="consumption",
to=settings.AUTH_USER_MODEL,
),
),
('id', models.SmallAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('amount', models.PositiveSmallIntegerField()),
('day', models.PositiveSmallIntegerField(choices=[(1, 'Do'), (2, 'Fr'), (3, 'Sa')])),
('for_free', models.BooleanField(default=False)),
('drink', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='consumption_list', related_query_name='consumption', to='gaehsnitz.drink')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='consumption_list', related_query_name='consumption', to=settings.AUTH_USER_MODEL)),
],
),
]

View File

@@ -4,25 +4,26 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("gaehsnitz", "0001_initial"),
('gaehsnitz', '0001_initial'),
]
operations = [
migrations.RemoveField(
model_name="donation",
name="from_user",
model_name='donation',
name='from_user',
),
migrations.RemoveField(
model_name="payment",
name="from_user",
model_name='payment',
name='from_user',
),
migrations.AlterField(
model_name="consumption",
name="day",
field=models.PositiveSmallIntegerField(choices=[(1, "Do"), (2, "Fr"), (3, "Sa"), (4, "So")]),
model_name='consumption',
name='day',
field=models.PositiveSmallIntegerField(choices=[(1, 'Do'), (2, 'Fr'), (3, 'Sa'), (4, 'So')]),
),
migrations.DeleteModel(
name="Payback",
name='Payback',
),
]

View File

@@ -4,12 +4,14 @@ from django.db.models import Sum, F
class PriceField(models.DecimalField):
def __init__(self, verbose_name=None, name=None, **kwargs):
kwargs.update({"max_digits": 6, "decimal_places": 2})
super().__init__(verbose_name, name, **kwargs)
class User(AbstractUser):
@property
def paid_drinks(self):
return self.consumption_list.filter(for_free=False)
@@ -20,9 +22,9 @@ class User(AbstractUser):
@property
def consumed_drinks_price(self):
query = self.paid_drinks.annotate(cost=F("amount") * F("drink__sale_price_per_bottle")).aggregate(
sum=Sum("cost")
)
query = self.paid_drinks \
.annotate(cost=F("amount") * F("drink__sale_price_per_bottle")) \
.aggregate(sum=Sum("cost"))
return query["sum"] or 0
@@ -43,6 +45,7 @@ class Payment(models.Model):
amount = PriceField()
class Drink(models.Model):
name = models.CharField(max_length=32, unique=True)
crates_ordered = models.PositiveSmallIntegerField(
@@ -124,11 +127,11 @@ class Drink(models.Model):
class Consumption(models.Model):
user = models.ForeignKey(
to=User, on_delete=models.CASCADE, related_name="consumption_list", related_query_name="consumption"
)
to=User, on_delete=models.CASCADE,
related_name="consumption_list", related_query_name="consumption")
drink = models.ForeignKey(
to=Drink, on_delete=models.CASCADE, related_name="consumption_list", related_query_name="consumption"
)
to=Drink, on_delete=models.CASCADE,
related_name="consumption_list", related_query_name="consumption")
amount = models.PositiveSmallIntegerField()
day = models.PositiveSmallIntegerField(choices=[(1, "Do"), (2, "Fr"), (3, "Sa"), (4, "So")])
for_free = models.BooleanField(default=False)

View File

@@ -53,21 +53,21 @@ body {
#title {
margin-top: 24px;
text-align: center;
color: #FFCC77;
color: #CCEE66;
font-weight: bold;
}
h1 {
margin-bottom: 10px;
font-size: 1.6rem;
color: #EE9933;
text-shadow: 0 0 16px #CC6611;
color: #99EE33;
text-shadow: 0 0 16px #669933;
}
#navi {
padding: 8px 0;
text-align: center;
color: #885522;
color: #446622;
}
#navi a {
@@ -77,7 +77,7 @@ h1 {
a {
text-decoration: none;
color: #EE9933;
color: #99EE33;
transition: color 100ms;
}
@@ -103,7 +103,7 @@ h2 {
margin-bottom: 14px;
font-size: 1.3rem;
font-weight: normal;
color: #EE9933;
color: #99EE33;
}
h3 {
@@ -111,7 +111,7 @@ h3 {
margin-bottom: 8px;
font-size: 1.15rem;
font-weight: normal;
color: #FFCC77;
color: #CCEE66;
}
p, ul {
@@ -131,15 +131,15 @@ table {
}
thead {
color: #FFCC77;
color: #CCEE66;
}
.odd-row {
background-color: rgba(80, 40, 10, 0.4);
background-color: rgba(40, 60, 20, 0.4);
}
.even-row {
background-color: rgba(80, 40, 10, 0.1);
background-color: rgba(40, 60, 20, 0.1);
}
td {
@@ -150,7 +150,7 @@ td {
hr {
margin-top: 24px;
margin-bottom: 24px;
border: 3px solid #885522;
border: 3px solid #446622;
border-radius: 3px;
}
@@ -191,7 +191,7 @@ hr {
margin-top: 12px;
margin-bottom: 12px;
border: 2px solid;
border-image: linear-gradient(to right, rgb(238, 153, 51) 0%, rgba(238, 102, 34, 0) 100%) 1;
border-image: linear-gradient(to right, rgb(153, 238, 51) 0%, rgba(238, 153, 51, 0) 100%) 1;
overflow: hidden;
}
@@ -200,7 +200,7 @@ hr {
max-width: 160px;
max-height: 90px;
z-index: -1;
box-shadow: 0 0 30px #885522;
box-shadow: 0 0 30px #446622;
}
.bandbox p {
@@ -249,18 +249,3 @@ hr {
.marked {
color: #CC66EE;
}
#footer {
margin-top: 32px;
padding-bottom: 32px;
border-bottom: 1px solid transparent;
}
/* archive pages: neutral blue-grey color scheme (content only, nav/title stay amber) */
.archive #content h2 { color: #D8DEF0; }
.archive #content h3 { color: #B8C0D8; }
.archive #content a { color: #B8C0D8; }
.archive #content thead { color: #B8C0D8; }
.archive #content .odd-row { background-color: rgba(180, 200, 255, 0.07); }
.archive #content .even-row { background-color: rgba(180, 200, 255, 0.02); }
.archive #content hr { border-color: #505870; }

View File

@@ -1,255 +0,0 @@
{% extends "gaehsnitz/base.html" %}
{% block body_class %}archive{% endblock %}
{% block content %}
<h2>Archiv 2022</h2>
<p>25. - 28. August 2022</p>
<hr>
<h2>News</h2>
<h3>11.09. - Aftermath</h3>
<p>
Tja Leute, wie das immer so ist: lang geplant, kurz gefeiert... aber es war wieder absolut Klasse! Die bunte
Band-Mischung hat richtig gefetzt, die Versorgung hat der hohen Trichterfrequenz bei weitem standgehalten, aber
vor allem war mal wieder ein ganzer Haufen lieber Leute am Start,
<span class="accent">Danke dafür! ❤</span>
</p>
<h3>15.08. - TL;DR</h3>
<p>
In anderthalb Wochen ist es so weit, deshalb hier kurz das Wichtigste zusammengefasst:
</p>
<ul>
<li>Checkt die Anreise und bildet Fahrgemeinschaften.</li>
<li>Bringt gern Leute mit, aber fragt uns bitte vorher. Außerdem nicht im Internet posten - die Veranstaltung ist privat.</li>
<li>Bitte helft uns mit eurer Eintrittsspende und noch besser vorab mit einem Suff-Kredit. ❤</li>
<li>Suff aller Art gibt's genug und zu fairen Preisen.</li>
<li>Das Essen könnte knapp werden. Bitte bringt eine Kleinigkeit mit (Aufstriche, Salate, Käse etc.).</li>
<li>Draußen gibt es kein Trinkwasser - bringt Wasserkanister mit.</li>
</ul>
<h3>17.07. - .. es wird!</h3>
<p>
Wir haben uns dieses Wochenende noch einmal ins Zeug gelegt: einen Drehstrom-Anschluss verkabelt, die Bar neu
lackiert, den Drum-Riser gebaut, die Laube aufgeräumt und mal wieder überall gemäht.
</p>
<h3>27.05. - Himmelfahrtsaktion</h3>
<p>Am Wochenende nach Himmelfahrt haben wir schonmal gaaanz viel geschafft:</p>
<ul>
<li>Rasen gemäht und einige Büsche verschnitten</li>
<li>die Bar stabilisiert</li>
<li>die Bühnenfläche vermessen, mit Platten begrenzt und geebnet</li>
<li>die Hauptfläche weiter begradigt</li>
<li>sämtliches Holz am Grundstücksrand gestapelt</li>
</ul>
<hr>
<h2>Programm</h2>
<ul>
<li>Donnerstag 25.: Aufbau</li>
<li>Freitag 26.: Quast, Direct Juice</li>
<li>Samstag 27.: Melo-Komplott, The Residudes, RATs</li>
<li>Sonntag 28.: Abbau</li>
</ul>
<hr>
<h2>Von A bis Z</h2>
<p>
Wie letztes Jahr schon werden wir womöglich demnächst mal auswerten, wie die Dinge im Detail so gelaufen sind.
Dann wird hier alles kommentiert, damit wir uns das bis nächstes Jahr merken können. ;)
</p>
<h3 id="address">Adresse &amp; Anfahrt</h3>
<p>
Die Sause findet im Garten auf dem Grundstück von Tobis Eltern statt.
</p>
<p>
Adresse: Gähsnitzer Ring 9, 04618 Nobitz<br>
Koordinaten: 50.9070, 12.5465
</p>
<p>
Bekanntlich kann man ja im August noch für 9,-€ die Welt bereisen, daher empfiehlt sich die gemeinsame Anreise
<span class="accent">mit dem Zug</span>. Die S5X fährt stündlich um :40 von Leipzig Hbf und kommt um :25 in
Gößnitz an. Von dort sind es noch etwa 11km.
</p>
<h3 id="event">Art der Veranstaltung</h3>
<p>
Das ganze ist immer noch eine private Gartenparty, keine angemeldete Veranstaltung! Das bringt folgende Regeln
mit sich:
</p>
<ul>
<li>Bitte macht <span class="accent">keine öffentliche Werbung</span>, vor allem nicht im Internet.</li>
<li>Ihr könnt Freund*innen mitbringen, aber bitte fragt uns vorher mal kurz.</li>
<li>Achtet auf das Wohl der Anwohner*innen.</li>
<li>Live-Mucke sollte bis 22:00 durch sein. Danach können wir immer noch Konservenmucke hören, aber am besten nur auf 70% Lautstärke. ;)</li>
</ul>
<h3 id="food">Essen</h3>
<p>
Hauptmahlzeiten: Am Donnerstag werden wir wohl den Grill anhauen. Am Freitag und Samstag wird es jeweils eine
vegane Hauptmahlzeit aus dem großen Feuertopf geben.
</p>
<p>
Rundherum bitten wir euch, euch <span class="accent">selbst etwas zu essen mitzubringen</span> - Aufstriche,
Salate, Käse etc. in verschließbaren Behältern. Wir besorgen Brot/Brötchen und einen Grundvorrat.
</p>
<h3 id="drinks">Getränke &amp; Bar</h3>
<p>
Ein lokaler Getränkehändler bringt uns 'nen LKW voll Suff vorbei - es gibt Bier, Radler, Wasser, Mate und Cola.
Alles wird in Flaschen verkauft, seid deshalb bitte besonders vorsichtig, dass nichts zu Bruch geht!
</p>
<h3>Mucke &amp; Playlists</h3>
<p>
DJ Hymr wird einen Haufen Mucke bereithalten. Darüber hinaus gibt es Klinkenparty, allerdings streng limitiert
von den Geschmäckern der Veranstalter. :P
</p>
<h3>Parken &amp; Zelten</h3>
<p>
Der Großteil des Gartens (hinter der Bühne) dient als Zeltplatz. Es gibt einige Parkplätze rund um das
Grundstück und die Garage.
</p>
<h3 id="sanitary">Sanitär</h3>
<p>
<span class="accent">Es gibt kein Wasser auf dem Gelände!</span> Wenn ihr die Möglichkeit habt, bringt bitte
größtmögliche <span class="accent">Wasserkanister</span> (auch leer) mit. Es wird Dixi-Toiletten mit
Desinfektionsmittel und einem mobilen Waschbecken geben.
</p>
<h3>Wetter</h3>
<p>
Wir haben viele Pavillons, um auch bei Regen noch einigermaßen gute Laune zu wahren. Haltet Abstand mit Feuer
zur Vegetation und werft keine Kippen in die Gegend!
</p>
<hr>
<h2>Bühne &amp; Technik</h2>
<h3>Backline</h3>
<ul>
<li>Bassbox: Markbass 4x10", 4 Ohm, Speakon</li>
<li>Gitarrenbox: JetCity 2x12", 8 Ohm, Klinke</li>
<li>Drums: Pearl, Bassdrum, 3 Toms, Stative für Snare, HiHat, Crash, Ride</li>
<li>(Bass-Amp: Markbass Little Mark Tube 800 darf mitgenutzt werden)</li>
<li>(Gitarrenkombo: Blackstar HT-5 darf mitbenutzt werden)</li>
</ul>
<h3>Mikrofonierung</h3>
<ul>
<li>3 Gesangsmikros: SM58, PG58 und noch 'n billiges</li>
<li>3 Amp/Instrumenten-Mikros (Bass sowieso lieber via DI)</li>
<li>Drum-Mikros: t.bone Beta BD 500 und ein Set für alles andere</li>
<li>1 DI-Box</li>
<li>6 große Mikro-Stative, 3 kleine Mikro-Stative</li>
</ul>
<h3>Monitoring</h3>
<ul>
<li>1 Aktivbox neben den Drums</li>
<li>2 Front-Monitore (RATs)</li>
</ul>
<h3>PA</h3>
<ul>
<li>Mischpult &amp; Stagebox: Behringer X-Air 18</li>
<li>Beschallung: 2 aktive Subwoofer, 2 passive Hochtöner + Amp, Stative</li>
</ul>
<hr>
<h2>Finanzen</h2>
<p>
Da eine offene Kommunikation irgendwie zu dem ganzen unkommerziellen DIY-Gedöhns dazugehört, findet ihr hier
ganz transparent eine Übersicht, von wo nach wo eigentlich wie viel Kohle geflossen ist.
Nur keine Klarnamen. ;)
</p>
<h3>Zusammenfassung</h3>
<table>
<tr class="odd-row">
<td>Summe aller Spenden/Zahlungen</td>
<td>1.130 €</td>
</tr>
<tr class="even-row">
<td>Summe aller Ausgaben</td>
<td>1.250 €</td>
</tr>
<tr class="odd-row">
<td>Stand</td>
<td class="accent">-120 €</td>
</tr>
</table>
<h3>Ausgaben</h3>
<table>
<thead>
<tr class="odd-row">
<td>Zweck</td>
<td>Betrag</td>
<td>Datum</td>
</tr>
</thead>
<tr class="even-row">
<td>Baumarkt/Elektrik</td>
<td>70 €</td>
<td>16.07.</td>
</tr>
<tr class="odd-row">
<td>Baumarkt/Elektrik</td>
<td>27 €</td>
<td>18.07.</td>
</tr>
<tr class="even-row">
<td>Dixis</td>
<td>328 €</td>
<td>08.08.</td>
</tr>
<tr class="odd-row">
<td>Getränke/Anzahlung</td>
<td>400 €</td>
<td>22.08.</td>
</tr>
<tr class="even-row">
<td>Supermarkt/Essen</td>
<td>193 €</td>
<td>25.08.</td>
</tr>
<tr class="odd-row">
<td>Getränke/Abrechnung</td>
<td>122 €</td>
<td>01.09.</td>
</tr>
<tr class="even-row">
<td>Bands</td>
<td>110 €</td>
<td>-</td>
</tr>
</table>
<p>
Details zu den Spenden und Rückzahlungen an die Leute, die die Ausgaben geleistet haben,
lassen wir hier erstmal weg. Wer's ganz genau wissen will, kann ja fragen.
</p>
<p>
Nicht aufgelistet sind kurzfristige Dinge für die Vorbereitungsaktionen, also z.B. Suff und Sprit, den wir für
die Arbeitseinsätze gekauft und auch direkt vernichtet haben. Danke an dieser Stelle nochmal allen für die
jeweiligen Einkäufe und die unbezahlbare Arbeitskraft!
</p>
{% endblock %}

View File

@@ -1,273 +0,0 @@
{% extends "gaehsnitz/base.html" %}
{% load static %}
{% load money %}
{% block body_class %}archive{% endblock %}
{% block content %}
<h2>Archiv 2024</h2>
<p>06. - 09. Juni 2024</p>
<hr>
<h2>News</h2>
<h3>06.05. - Hochoffizielle Einladung</h3>
<p>
Der Plan für Gähsnitz dieses Jahr steht und zur Motivation gibt's diesmal auch 'n digitales Plakat. 🍾
</p>
<a href="{% static 'gaehsnitz/plakat-2024.jpg' %}">
<img id="flyer" src="{% static 'gaehsnitz/plakat-2024-small.jpg' %}" alt="Plakat">
</a>
<p>
Fühlt euch alle eingeladen, am 6., 7., spätestens aber am 8. Juni bei uns im Garten vorbeizuschneien. Es gibt
bunt gemischte Live-Musik, Getränke für'n schmalen Taler, echte Landluft und was sonst noch alles auf dem Bild
zu finden ist.
</p>
<p>
Mehr Details gibt's nochmal 1-2 Wochen vorher - bis dahin einfach den Termin freihalten, Urlaub nehmen oder
kündigen, und am besten auch schonmal üben, wie man ganz schnell Pavillons aufbaut und Wurfzelte wieder in ihre
Verpackung kriegt.
</p>
<p>
Bringt gern noch mehr liebe Leute mit, aber bitte nich bei MySpace posten oder Plakate aufhängen - ist immer
noch 'ne Privatveranstaltung. ;)
</p>
<h3>04.04. - Der Winterschlaf ist vorbei</h3>
<p>
Der Termin für unsere diesjährige Gartensause steht ja schon seit letztem Jahr fest:
<span class="accent">06. - 09. Juni</span>. Sogar die Dixis sind schon vorbestellt! Den größten Fokus (und die
meiste Live-Mucke) wollen wir dieses Mal auf Samstag (08.06.) legen, aber mehr dazu später.
</p>
<p>
Über Ostern waren haben wir uns mal das Gelände angeschaut und uns gefreut, dass sich in anderthalb Jahren gar
nicht mal so viel verändert hat - sogar das Drum-Podest ist noch nutzbar. Trotzdem gibt's natürlich alle Hände
voll zu tun, um den Garten wieder festivaltauglich zu machen und zu konservieren.
</p>
<p>
Wir wollen über <span class="accent">Himmelfahrt</span> (09. - 12.05.) nochmal hinfahren und könnten dafür auch
so viele helfende Hände wie möglich gebrauchen. Wer also Bock auf Handarbeit, kühle Getränke und Feuermachen in
der Pampa hat, bitte melden! :)
</p>
<p>
Nun zur To-do-Liste: zum einen gibt's viel zu <span class="accent">gärtnern</span>:
</p>
<ul>
<li>Rasen mähen</li>
<li>"Palisade" befestigen, damit sie nicht zu breit wird</li>
<li>Efeu vom Boden entfernen / Fläche neben dem Schuppen wieder nutzbar machen</li>
<li>Bäume, Büsche und Hecken auf dem Gelände verschneiden (auch überm Dach der Laube)</li>
<li>Bäume und Büsche an den Grundstücksgrenzen verschneiden (vor allem oben an der Ecke)</li>
<li>Todholz einsammeln und die Palisade erweitern / Feuerholz separat sammeln</li>
<li>Müll/Schrott sammeln</li>
<li>neuen Rasen sähen</li>
</ul>
<p>
Zum anderen gibt es Folgendes zu <span class="accent">bauen</span>:
</p>
<ul>
<li>
Bar: neue OSB-Platte drauf schrauben, nochmal lackieren<br>
Maße: 310 lang, 63 breit
</li>
<li>
Erde auf der Bühne aufschütten und neu ebnen, womöglich noch ein paar Steinplatten dazulegen
</li>
<li>
Treppe zur Laube bzw. zur "Hochebene" bauen (Erde kann für Bühne genutzt werden)
</li>
<li>
Drum-Podest erneuern: marode Stellen mit Ziegelsteinen befestigen, OSB-Platten drauf schrauben,
lackieren<br>
Maße: 240 breit, 160 lang
</li>
<li>
lose Paletten streichen
</li>
<li>
<del>Plumpsklo: Wände putzen, neuen Boden bauen, neue Sitzbank bauen, Brille besorgen</del>
<br>
Maße Sitzbank: 70 breit, 50 tief
</li>
</ul>
<p>
Hier ist der <span class="accent">Einkaufszettel</span> dafür:
</p>
<ul>
<li>Rasensamen, z.B. 5 kg für 200 m² - 30 €</li>
<li>Bar: OSB-Platte, z.B. 250x125 cm längs halbiert, 18 mm stark, 37 €</li>
<li>Drum-Podest: OSB-Verlegeplatten, z.b. 4x 205x67 cm, 25 mm stark, 80 €</li>
<li>Holzfarbe: z.B. Wetterschutzfarbe schwedenrot 2,5 l (reicht für Bar und Podest), 38 €</li>
<li>Holzlasur: z.B. 10 l Kanister, 10 €</li>
<li>
<del>Plumpsklo</del>
</li>
</ul>
<p>&rarr; ca. 200 €</p>
<p>
Und weil's so schön ist, hier noch ein paar Impressionen, Stand 30.03.:
</p>
<div class="image-list">
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/feld-eingang-auszen.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/feld-eingang-innen.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/bar-fern.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/bar-nah.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/buehne-bar-palisade.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/buehne.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/laube-von-unten.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/laube-von-vorn.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/laube-von-oben.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/laube-dach.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/haus-zeltplatz.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/strasze-eingang.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/haus-buesche.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/haus-feuerholz.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/unten-gewaechshaus.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/unten-wiese.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/unten-rand.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/schuppen.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/rand-efeu.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/rand-pissecke.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/rand-waeldchen.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/rand-zaun.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/rand-portal.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/grosze-tanne.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/strasze-kirschen.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/strasze-hecke.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/strasze-oben.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/feld-spaghetti.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/feld-rand.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/plumpsklo.jpg' %}" alt=""></div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/plumpsklo-boden.jpg' %}" alt=""></div>
</div>
<hr>
<h2>Programm</h2>
<ul>
<li>Donnerstag 06.: ganz viel Aufbau</li>
<li>Freitag 07.: Warm-Up</li>
<li>Samstag 08.: ganz viel Live-Mucke</li>
<li>Sonntag 09.: ganz viel Abbau</li>
</ul>
<hr>
<h2>Bühne &amp; Technik</h2>
<p>zur Info für Künstler*innen und als Packliste für uns ;)</p>
<h3>Backline</h3>
<ul>
<li>
Drums:<br>
(Josi) Bassdrum, 2 Toms, Floor-Tom, Hocker, Stative für Snare, HiHat, Crash und Ride<br>
(Josi) Snare (nur für Open Stage)<br>
(Flo) Iron Cobra 600 Double Bass Pedal (darf für alles mitbenutzt werden)<br>
(Tobi) HiHat, Crash, Ride (nur für Open Stage)
</li>
<li>Bassbox: Markbass 4x10", 4 Ohm, Speakon</li>
<li>(Bass-Topteil: Markbass Little Mark Tube 800 darf mitbenutzt werden)</li>
<li>Gitarrenbox: Palmer 2x12", 8 Ohm, Klinke</li>
<li>(Gitarrenkombo: Blackstar HT-5 darf mitbenutzt werden)</li>
</ul>
<h3>Mikrofonierung</h3>
<ul>
<li>Kick: t.bone Beta 500</li>
<li>Snare: SM57</li>
<li>Toms: 3x Audix f2</li>
<li>Overheads: 2x Rode M5</li>
<li>Amps: 3x Superlux Grenzfläche</li>
<li>DI: 1x Behringer DI-Box (Mono)</li>
<li>Gesang: 1x Beta 58, 1x SM58 (Sepp), 1x Superlux</li>
<li>Stative: mal Inventur machen ...</li>
</ul>
<h3>Monitoring</h3>
<ul>
<li>3 Boxen angefragt mit der PA, noch in Klärung ...</li>
</ul>
<h3>PA</h3>
<ul>
<li>Mischpult &amp; Stagebox: Behringer X-Air 18</li>
<li>Beschallung: HK-Audio Pro, 2 18"-Subs, 2 Tops, aktiv</li>
</ul>
<h3>Beleuchtung</h3>
<ul>
<li>2x Bars mit jeweils 4 LED-Spots</li>
<li>Superfly</li>
<li>DMX-Steuerung über Laptop möglich</li>
</ul>
<h3>Kabel</h3>
<ul>
<li>24x XLR (16 Channels, 3 Monitore, 4 PA, 1 Reserve)</li>
<li>2x XLR-Male ↔ Klinke</li>
<li>13x Kaltgeräte-Stecker (Mixer, Markbass, Blackstar, 3 Monitore, 4 PA, 1 Lampe, 1 Reserve)</li>
<li>2x Kaltgeräte-Verlängerung (zwischen Lampen)</li>
<li>4x DMX (3 Lampen, 1 Reserve)</li>
<li>...</li>
</ul>
<hr>
<h2>Finanzen</h2>
<p>
Da eine offene Kommunikation irgendwie zu dem ganzen unkommerziellen DIY-Gedöhns dazugehört, findet ihr hier
ganz transparent eine Übersicht, von wo nach wo eigentlich wie viel Kohle geflossen ist.
Nur keine Klarnamen. ;)
</p>
<h3>Zusammenfassung</h3>
<table>
<tr class="odd-row">
<td>Summe aller Spenden/Zahlungen</td>
<td>{{ total_donations|euro }}</td>
</tr>
<tr class="even-row-row">
<td>Summe aller Ausgaben</td>
<td>{{ total_payments|euro }}</td>
</tr>
<tr class="odd-row">
<td>Stand</td>
<td class="accent">{{ total_balance|euro }}</td>
</tr>
</table>
<h3>Ausgaben</h3>
<table>
<thead>
<tr class="odd-row">
<td>Zweck</td>
<td>Betrag</td>
<td>Datum</td>
</tr>
</thead>
{% for payment in payments %}
<tr class="{% cycle 'even-row' 'odd-row' %}">
<td>{{ payment.purpose }}</td>
<td>{{ payment.amount|euro }}</td>
<td>{% if payment.date %}{{ payment.date|date:"d.m." }}{% else %}-{% endif %}</td>
</tr>
{% endfor %}
</table>
<p>
Details zu den Spenden und Rückzahlungen an die Leute, die die Ausgaben geleistet haben,
lassen wir hier erstmal weg. Wer's ganz genau wissen will, kann ja fragen.
</p>
<p>
Nicht aufgelistet sind kurzfristige Dinge für die Vorbereitungsaktionen, also z.B. Suff und Sprit, den wir für
die Arbeitseinsätze gekauft und auch direkt vernichtet haben. Danke an dieser Stelle nochmal allen für die
jeweiligen Einkäufe und die unbezahlbare Arbeitskraft!
</p>
{% endblock %}

View File

@@ -0,0 +1,9 @@
{% extends "gaehsnitz/base.html" %}
{% load static %}
{% block content %}
<h2>&#128736; Alles noch in Planung</h2>
<p>Bald gibt's mehr Infos.</p>
{% endblock %}

View File

@@ -8,15 +8,21 @@
<title>Gähsnitz Open Air</title>
<link rel="stylesheet" type="text/css" href="{% static 'gaehsnitz/style.css' %}">
</head>
<body class="{% block body_class %}{% endblock %}">
<body>
<div id="title">
<h1>Gähsnitz Open Air 2026</h1>
~ Do 11. - So 14. Juni ~
<h1>Gähsnitz Open Air 2024</h1>
~ Do 06. - So 09. Juni ~
</div>
<div id="navi">
<a href="{% url 'gaehsnitz:news' %}">Festival</a>
<a href="{% url 'gaehsnitz:news' %}">News</a>
|
<a href="{% url 'gaehsnitz:atoz' %}">A-Z</a>
|
<a href="{% url 'gaehsnitz:program' %}">Programm</a>
|
<a href="{% url 'gaehsnitz:finance' %}">Finanzen</a>
|
<a href="{% url 'gaehsnitz:for-bands' %}">für Bands</a>
</div>
@@ -25,11 +31,5 @@
{% block content %}{% endblock %}
</div>
<div id="footer">
<a href="{% url 'gaehsnitz:archive-2022' %}">Archiv 2022</a>
|
<a href="{% url 'gaehsnitz:archive-2024' %}">Archiv 2024</a>
</div>
</body>
</html>

View File

@@ -0,0 +1,62 @@
{% extends "gaehsnitz/base.html" %}
{% load money %}
{% block content %}
<h2>&#128736; Abwarten</h2>
<p>Auch hier wird noch geplant ...</p>
<h2>Details</h2>
<p>
Da eine offene Kommunikation irgendwie zu dem ganzen unkommerziellen DIY-Gedöhns dazugehört, findet ihr hier
ganz transparent eine Übersicht, von wo nach wo eigentlich wie viel Kohle geflossen ist.
Nur keine Klarnamen. ;)
</p>
<h3>Zusammenfassung</h3>
<table>
<tr class="odd-row">
<td>Summe aller Spenden/Zahlungen</td>
<td>{{ total_donations|euro }}</td>
</tr>
<tr class="even-row-row">
<td>Summe aller Ausgaben</td>
<td>{{ total_payments|euro }}</td>
</tr>
<tr class="odd-row">
<td>Stand</td>
<td class="accent">{{ total_balance|euro }}</td>
</tr>
</table>
<h3>Ausgaben</h3>
<table>
<thead>
<tr class="odd-row">
<td>Zweck</td>
<td>Betrag</td>
<td>Datum</td>
</tr>
</thead>
{% for payment in payments %}
<tr class="{% cycle 'even-row' 'odd-row' %}">
<td>{{ payment.purpose }}</td>
<td>{{ payment.amount|euro }}</td>
<td>{% if payment.date %}{{ payment.date|date:"d.m." }}{% else %}-{% endif %}</td>
</tr>
{% endfor %}
</table>
<p>
Details zu den Spenden und Rückzahlungen an die Leute, die die Ausgaben geleistet haben,
lassen wir hier erstmal weg. Wer's ganz genau wissen will, kann ja fragen.
</p>
<p>
Nicht aufgelistet sind kurzfristige Dinge für die Vorbereitungsaktionen, also z.B. Suff und Sprit, den wir für
die Arbeitseinsätze gekauft und auch direkt vernichtet haben. Danke an dieser Stelle nochmal allen für die
jeweiligen Einkäufe und die unbezahlbare Arbeitskraft!
</p>
{% endblock %}

View File

@@ -1,144 +1,168 @@
{% extends "gaehsnitz/base.html" %}
{% load money %}
{% load static %}
{% block content %}
<h2>Über uns</h2>
<h2>06.05. - Hochoffizielle Einladung</h2>
<p>
Angefangen hat das alles als Geburtstagsparty - irgendwann hat sich daraus eine kleine Gruppe geformt,
die sich ab und zu zusammensetzt und dieses winzige Festival plant. Kein Kommerz, kein großes Ding,
einfach ein paar Tage Musik, gute Leute und frische Luft im Garten.
Der Plan für Gähsnitz dieses Jahr steht und zur Motivation gibt's diesmal auch 'n digitales Plakat. 🍾
</p>
<a href="{% static 'gaehsnitz/plakat-2024.jpg' %}">
<img id="flyer" src="{% static 'gaehsnitz/plakat-2024-small.jpg' %}" alt="Plakat">
</a>
<p>
Fühlt euch alle eingeladen, am 6., 7., spätestens aber am 8. Juni bei uns im Garten vorbeizuschneien. Es gibt
bunt gemischte Live-Musik, Getränke für'n schmalen Taler, echte Landluft und was sonst noch alles auf dem Bild
zu finden ist.
</p>
<p>
Mehr Details gibt's nochmal 1-2 Wochen vorher - bis dahin einfach den Termin freihalten, Urlaub nehmen oder
kündigen, und am besten auch schonmal üben, wie man ganz schnell Pavillons aufbaut und Wurfzelte wieder in ihre
Verpackung kriegt.
</p>
<p>
Bringt gern noch mehr liebe Leute mit, aber bitte nich bei MySpace posten oder Plakate aufhängen - ist immer
noch 'ne Privatveranstaltung. ;)
</p>
<hr>
<h2>Programm</h2>
<ul>
<li>Donnerstag 11.: Aufbau</li>
<li>Freitag 12.: Melokomplott, M&#xF8;rtel</li>
<li>Samstag 13.: Quast, Knast, Kotpiloten</li>
<li>Sonntag 14.: Abbau</li>
</ul>
<hr>
<h2>Von A bis Z</h2>
<p class="marked">kopiert von 2022 - muss noch angepasst werden</p>
<h3 id="address">Adresse &amp; Anfahrt</h3>
<h2>04.04. - Der Winterschlaf ist vorbei</h2>
<p>
Die Sause findet im Garten auf dem Grundstück von Tobis Eltern statt.
Der Termin für unsere diesjährige Gartensause steht ja schon seit letztem Jahr fest:
<span class="accent">06. - 09. Juni</span>. Sogar die Dixis sind schon vorbestellt! Den größten Fokus (und die
meiste Live-Mucke) wollen wir dieses Mal auf Samstag (08.06.) legen, aber mehr dazu später.
</p>
<p>
Adresse: Gähsnitzer Ring 9, 04618 Nobitz<br>
Koordinaten: 50.9070, 12.5465
Über Ostern waren haben wir uns mal das Gelände angeschaut und uns gefreut, dass sich in anderthalb Jahren gar
nicht mal so viel verändert hat - sogar das Drum-Podest ist noch nutzbar. Trotzdem gibt's natürlich alle Hände
voll zu tun, um den Garten wieder festivaltauglich zu machen und zu konservieren.
</p>
<p>
Bekanntlich kann man ja im August noch für 9,-€ die Welt bereisen, daher empfiehlt sich die gemeinsame Anreise
<span class="accent">mit dem Zug</span>. Die S5X fährt stündlich um :40 von Leipzig Hbf und kommt um :25 in
Gößnitz an. Von dort sind es noch etwa 11km.
Wir wollen über <span class="accent">Himmelfahrt</span> (09. - 12.05.) nochmal hinfahren und könnten dafür auch
so viele helfende Hände wie möglich gebrauchen. Wer also Bock auf Handarbeit, kühle Getränke und Feuermachen in
der Pampa hat, bitte melden! :)
</p>
<h3 id="event">Art der Veranstaltung</h3>
<p>
Das ganze ist immer noch eine private Gartenparty, keine angemeldete Veranstaltung! Das bringt folgende Regeln
mit sich:
Nun zur To-do-Liste: zum einen gibt's viel zu <span class="accent">gärtnern</span>:
</p>
<ul>
<li>Bitte macht <span class="accent">keine öffentliche Werbung</span>, vor allem nicht im Internet.</li>
<li>Ihr könnt Freund*innen mitbringen, aber bitte fragt uns vorher mal kurz.</li>
<li>Achtet auf das Wohl der Anwohner*innen.</li>
<li>Live-Mucke sollte bis 22:00 durch sein. Danach können wir immer noch Konservenmucke hören, aber am besten nur auf 70% Lautstärke. ;)</li>
<li>Rasen mähen</li>
<li>"Palisade" befestigen, damit sie nicht zu breit wird</li>
<li>Efeu vom Boden entfernen / Fläche neben dem Schuppen wieder nutzbar machen</li>
<li>Bäume, Büsche und Hecken auf dem Gelände verschneiden (auch überm Dach der Laube)</li>
<li>Bäume und Büsche an den Grundstücksgrenzen verschneiden (vor allem oben an der Ecke)</li>
<li>Todholz einsammeln und die Palisade erweitern / Feuerholz separat sammeln</li>
<li>Müll/Schrott sammeln</li>
<li>neuen Rasen sähen</li>
</ul>
<h3 id="food">Essen</h3>
<p>
Hauptmahlzeiten: Am Donnerstag werden wir wohl den Grill anhauen. Am Freitag und Samstag wird es jeweils eine
vegane Hauptmahlzeit aus dem großen Feuertopf geben.
Zum anderen gibt es Folgendes zu <span class="accent">bauen</span>:
</p>
<ul>
<li>
Bar: neue OSB-Platte drauf schrauben, nochmal lackieren<br>
Maße: 310 lang, 63 breit
</li>
<li>
Erde auf der Bühne aufschütten und neu ebnen, womöglich noch ein paar Steinplatten dazulegen
</li>
<li>
Treppe zur Laube bzw. zur "Hochebene" bauen (Erde kann für Bühne genutzt werden)
</li>
<li>
Drum-Podest erneuern: marode Stellen mit Ziegelsteinen befestigen, OSB-Platten drauf schrauben,
lackieren<br>
Maße: 240 breit, 160 lang
</li>
<li>
lose Paletten streichen
</li>
<li>
<del>Plumpsklo: Wände putzen, neuen Boden bauen, neue Sitzbank bauen, Brille besorgen</del>
<br>
Maße Sitzbank: 70 breit, 50 tief
</li>
</ul>
<p>
Rundherum bitten wir euch, euch <span class="accent">selbst etwas zu essen mitzubringen</span> - Aufstriche,
Salate, Käse etc. in verschließbaren Behältern. Wir besorgen Brot/Brötchen und einen Grundvorrat.
Hier ist der <span class="accent">Einkaufszettel</span> dafür:
</p>
<h3 id="drinks">Getränke &amp; Bar</h3>
<ul>
<li>Rasensamen, z.B. 5 kg für 200 m² - 30 €</li>
<li>Bar: OSB-Platte, z.B. 250x125 cm längs halbiert, 18 mm stark, 37 €</li>
<li>Drum-Podest: OSB-Verlegeplatten, z.b. 4x 205x67 cm, 25 mm stark, 80 €</li>
<li>Holzfarbe: z.B. Wetterschutzfarbe schwedenrot 2,5 l (reicht für Bar und Podest), 38 €</li>
<li>Holzlasur: z.B. 10 l Kanister, 10 €</li>
<li>
<del>Plumpsklo</del>
</li>
</ul>
<p>&rarr; ca. 200 €</p>
<p>
Ein lokaler Getränkehändler bringt uns 'nen LKW voll Suff vorbei - es gibt Bier, Radler, Wasser, Mate und Cola.
Alles wird in Flaschen verkauft, seid deshalb bitte besonders vorsichtig, dass nichts zu Bruch geht!
Und weil's so schön ist, hier noch ein paar Impressionen, Stand 30.03.:
</p>
<h3>Parken &amp; Zelten</h3>
<p>
Der Großteil des Gartens (hinter der Bühne) dient als Zeltplatz. Es gibt einige Parkplätze rund um das
Grundstück und die Garage.
</p>
<h3 id="sanitary">Sanitär</h3>
<p>
<span class="accent">Es gibt kein Wasser auf dem Gelände!</span> Wenn ihr die Möglichkeit habt, bringt bitte
größtmögliche <span class="accent">Wasserkanister</span> (auch leer) mit. Es wird Dixi-Toiletten mit
Desinfektionsmittel und einem mobilen Waschbecken geben.
</p>
<h3>Wetter</h3>
<p>
Wir haben viele Pavillons, um auch bei Regen noch einigermaßen gute Laune zu wahren. Haltet Abstand mit Feuer
zur Vegetation und werft keine Kippen in die Gegend!
</p>
<hr>
<h2>Finanzen</h2>
<p>
Da eine offene Kommunikation irgendwie zu dem ganzen unkommerziellen DIY-Gedöhns dazugehört, findet ihr hier
ganz transparent eine Übersicht, von wo nach wo eigentlich wie viel Kohle geflossen ist.
Nur keine Klarnamen. ;)
</p>
<h3>Zusammenfassung</h3>
<table>
<tr class="odd-row">
<td>Summe aller Spenden/Zahlungen</td>
<td>{{ total_donations|euro }}</td>
</tr>
<tr class="even-row">
<td>Summe aller Ausgaben</td>
<td>{{ total_payments|euro }}</td>
</tr>
<tr class="odd-row">
<td>Stand</td>
<td class="accent">{{ total_balance|euro }}</td>
</tr>
</table>
<h3>Ausgaben</h3>
<table>
<thead>
<tr class="odd-row">
<td>Zweck</td>
<td>Betrag</td>
<td>Datum</td>
</tr>
</thead>
{% for payment in payments %}
<tr class="{% cycle 'even-row' 'odd-row' %}">
<td>{{ payment.purpose }}</td>
<td>{{ payment.amount|euro }}</td>
<td>{% if payment.date %}{{ payment.date|date:"d.m." }}{% else %}-{% endif %}</td>
</tr>
{% endfor %}
</table>
<p>
Details zu den Spenden und Rückzahlungen an die Leute, die die Ausgaben geleistet haben,
lassen wir hier erstmal weg. Wer's ganz genau wissen will, kann ja fragen.
</p>
<p>
Nicht aufgelistet sind kurzfristige Dinge für die Vorbereitungsaktionen, also z.B. Suff und Sprit, den wir für
die Arbeitseinsätze gekauft und auch direkt vernichtet haben. Danke an dieser Stelle nochmal allen für die
jeweiligen Einkäufe und die unbezahlbare Arbeitskraft!
</p>
<div class="image-list">
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/feld-eingang-auszen.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/feld-eingang-innen.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/bar-fern.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/bar-nah.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/buehne-bar-palisade.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/buehne.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/laube-von-unten.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/laube-von-vorn.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/laube-von-oben.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/laube-dach.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/haus-zeltplatz.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/strasze-eingang.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/haus-buesche.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/haus-feuerholz.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/unten-gewaechshaus.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/unten-wiese.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/unten-rand.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/schuppen.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/rand-efeu.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/rand-pissecke.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/rand-waeldchen.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/rand-zaun.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/rand-portal.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/grosze-tanne.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/strasze-kirschen.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/strasze-hecke.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/strasze-oben.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/feld-spaghetti.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/feld-rand.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/plumpsklo.jpg' %}" alt="">
</div>
<div class="image-wrapper"><img src="{% static 'gaehsnitz/photos-2024-03-30/plumpsklo-boden.jpg' %}" alt="">
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,18 @@
{% extends "gaehsnitz/base.html" %}
{% load static %}
{% block content %}
<h2>&#128736; Donnerstag 06.</h2>
<p>ganz viel Aufbau</p>
<h2>&#128736; Freitag 07.</h2>
<p>Warm-Up</p>
<h2>&#128736; Samstag 08.</h2>
<p>ganz viel Live-Mucke</p>
<h2>&#128736; Sonntag 09.</h2>
<p>ganz viel Abbau</p>
{% endblock %}

View File

@@ -1,10 +1,11 @@
from django.urls import path
from gaehsnitz.views import NewsView, ForBandsView, Archive2022View, Archive2024View
from gaehsnitz.views import NewsView, AToZView, ProgramView, FinanceView, ForBandsView
urlpatterns = [
path("", NewsView.as_view(), name="news"),
path("atoz", AToZView.as_view(), name="atoz"),
path("program", ProgramView.as_view(), name="program"),
path("finance", FinanceView.as_view(), name="finance"),
path("for-bands", ForBandsView.as_view(), name="for-bands"),
path("archive/2022", Archive2022View.as_view(), name="archive-2022"),
path("archive/2024", Archive2024View.as_view(), name="archive-2024"),
]

View File

@@ -14,17 +14,27 @@ class GaehsnitzTemplateView(TemplateView):
context = super().get_context_data(**kwargs)
delta_til_start = festival_start_date - date.today()
days_til_start = max(delta_til_start.days, 0)
context.update(
{
"days_til_festival_start": days_til_start,
}
)
context.update({
"days_til_festival_start": days_til_start,
})
return context
class NewsView(GaehsnitzTemplateView):
template_name = "gaehsnitz/news.html"
class AToZView(GaehsnitzTemplateView):
template_name = "gaehsnitz/atoz.html"
class ProgramView(GaehsnitzTemplateView):
template_name = "gaehsnitz/program.html"
class FinanceView(GaehsnitzTemplateView):
template_name = "gaehsnitz/finance.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
@@ -45,54 +55,14 @@ class NewsView(GaehsnitzTemplateView):
displayed_payments.append(Payment(purpose="Bands", amount=band_sum))
context.update(
{
"total_donations": total_donations,
"total_payments": total_payments,
"total_balance": total_balance,
"payments": displayed_payments,
}
)
context.update({
"total_donations": total_donations,
"total_payments": total_payments,
"total_balance": total_balance,
"payments": displayed_payments,
})
return context
class ForBandsView(GaehsnitzTemplateView):
template_name = "gaehsnitz/for-bands.html"
class Archive2022View(GaehsnitzTemplateView):
template_name = "gaehsnitz/archive-2022.html"
class Archive2024View(GaehsnitzTemplateView):
template_name = "gaehsnitz/archive-2024.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
donations = Donation.objects.filter(date__year=2024)
payments = Payment.objects.filter(date__year=2024)
total_donations = donations.aggregate(sum=Sum("amount"))["sum"] or 0
total_payments = payments.aggregate(sum=Sum("amount"))["sum"] or 0
total_balance = total_donations - total_payments
band_sum, displayed_payments = 0, []
for pay in payments.order_by("date"):
if pay.purpose.startswith("Band"):
band_sum += pay.amount
else:
displayed_payments.append(pay)
displayed_payments.append(Payment(purpose="Bands", amount=band_sum))
context.update(
{
"total_donations": total_donations,
"total_payments": total_payments,
"total_balance": total_balance,
"payments": displayed_payments,
}
)
return context

View File

@@ -2,6 +2,6 @@ import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gaehsnitzproject.settings")
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'gaehsnitzproject.settings')
application = get_wsgi_application()

View File

@@ -1,12 +1,11 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gaehsnitzproject.settings")
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'gaehsnitzproject.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
@@ -18,5 +17,5 @@ def main():
execute_from_command_line(sys.argv)
if __name__ == "__main__":
if __name__ == '__main__':
main()

View File

@@ -1,21 +0,0 @@
[project]
name = "gaehsnitz"
version = "0.1.0"
requires-python = ">=3.14"
dependencies = [
"django==6.0.3",
"gunicorn==25.3.0",
"psycopg[binary]==3.3.3",
]
[dependency-groups]
dev = [
"ruff==0.15.12",
]
[tool.ruff]
target-version = "py314"
line-length = 120
[tool.ruff.lint]
select = ["E", "F", "W", "I"]

View File

@@ -1,4 +1,7 @@
{
$schema: "https://docs.renovatebot.com/renovate-schema.json",
extends: ["config:recommended", ":configMigration"],
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended",
":configMigration"
]
}

3
requirements.txt Normal file
View File

@@ -0,0 +1,3 @@
django==6.0.2
gunicorn==25.1.0
psycopg[binary]==3.3.3