Use official pretix module

This commit is contained in:
Jakob Lechner 2024-05-22 22:22:22 +02:00
parent cec9622771
commit eebbc3d2a3
15 changed files with 130 additions and 3678 deletions

View file

@ -1,43 +1,82 @@
args@{ config, lib, pkgs, custom-utils, ... }:
let
cfg = config.services.pretix;
ports = import ../ports.nix args;
domain = "tickets.weinturm-open-air.de";
extraDomains = [
"tickets.weinturm.jalr.de"
"tickets.wasted-openair.de"
"oel.wasted-openair.de"
"tickets.buendnis-gegen-rechts-nea.de"
];
gunicornWorkers = 4;
secretsFile = ../secrets.yaml;
in
{
services.pretix = {
enable = true;
instanceName = "Digitaler Dienst GmbH";
domain = "tickets.weinturm-open-air.de";
extraDomains = [
"tickets.weinturm.jalr.de"
"tickets.wasted-openair.de"
"oel.wasted-openair.de"
"tickets.buendnis-gegen-rechts-nea.de"
];
enableTls = true;
enableRegistration = false;
passwordReset = true;
locale = "de";
timezone = "Europe/Berlin";
secretsFile = ../secrets.yaml;
banktool = {
enable = true;
days = 14;
sops.secrets = {
pretix-cfg = {
sopsFile = secretsFile;
};
mail = {
enable = true;
from = "no-reply@tickets.weinturm-open-air.de";
admins = [
"mail@jalr.de"
"pretix@digitaler-dienst.gmbh"
];
pretix-banktool-cfg = {
sopsFile = secretsFile;
};
gunicornWorkers = 4;
};
services.nginx = {
services.pretix = {
enable = true;
settings = {
instance_name = "Digitaler Dienst GmbH";
pretix = {
url = "https://${domain}";
registration = false;
password_reset = true;
};
locale = {
default = "de";
timezone = "Europe/Berlin";
};
mail = {
from = "no-reply@tickets.weinturm-open-air.de";
};
};
nginx = {
enable = true;
inherit domain;
};
gunicorn = {
extraArgs = [
"--workers=${toString gunicornWorkers}"
];
};
};
services.pretix-banktool = {
enable = true;
days = 14;
secretsFile = config.sops.secrets.pretix-banktool-cfg.path;
};
services.nginx = lib.mkIf cfg.nginx.enable {
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
virtualHosts = {
${cfg.nginx.domain} = {
extraConfig = ''
add_header Strict-Transport-Security \"max-age=31536000; includeSubDomains; preload\" always;
more_set_headers Referrer-Policy same-origin;
more_set_headers X-Content-Type-Options nosniff;
'';
};
} // lib.listToAttrs (map
(d: {
name = d;
value = config.services.nginx.virtualHosts.${cfg.nginx.domain};
})
extraDomains
);
};
jalr.mailserver = {

View file

@ -17,11 +17,7 @@ in
myintercom-doorbell = callPackage ./myintercom-doorbell {
inherit poetry2nix;
};
pretix = callPackage ./pretix/pretix.nix {
inherit poetry2nix;
};
pretix-banktool = callPackage ./pretix/pretix-banktool.nix { };
pretix-static = callPackage ./pretix/pretix-static.nix { };
pretix-banktool = callPackage ./pretix-banktool { };
tabbed-box-maker = callPackage ./tabbed-box-maker { };
vesc-firmware = callPackage ./vesc-tool/firmware.nix { };
vesc-tool = callPackage ./vesc-tool/tool.nix { };

View file

@ -4,6 +4,6 @@
imports = [
./asterisk-sounds-de/module.nix
./myintercom-doorbell/module.nix
./pretix/module.nix
./pretix-banktool/module.nix
];
}

View file

@ -11,7 +11,7 @@ python3Packages.buildPythonApplication rec {
};
patches = [
./pretix-banktool-requirements.patch
./requirements.patch
];
buildInputs = with python3Packages; [

View file

@ -0,0 +1,60 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.pretix;
mkTimer = { description, unit, onCalendar }: {
inherit description;
requires = [ "pretix-migrate.service" ];
after = [ "network.target" ];
wantedBy = [ "timers.target" ];
timerConfig = {
Persistent = true;
OnCalendar = onCalendar;
Unit = unit;
};
};
in
{
options.services.pretix-banktool = with lib; with lib.types; {
enable = mkEnableOption "Enable tool to query bank account and sync transaction data to pretix server.";
days = mkOption {
type = types.int;
description = "The timeframe of transaction to fetch from the bank in days.";
};
secretsFile = mkOption {
type = types.path;
description = ''
Path of file containing secrets for pretix banktool.
'';
};
};
config = {
systemd.services.pretix-banktool = lib.mkIf cfg.enable {
description = "Tool to query bank account and sync transaction data to pretix server.";
serviceConfig = {
Type = "oneshot";
DynamicUser = true;
CapabilityBoundingSet = null;
PrivateUsers = true;
ProtectHome = true;
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
RestrictNamespaces = true;
SystemCallFilter = "@system-service";
LoadCredential = "config:${cfg.secretsFile}";
};
script = "${pkgs.pretix-banktool}/bin/pretix-banktool upload \"$CREDENTIALS_DIRECTORY/config\" --days=${toString cfg.days}";
};
systemd.timers.pretix-banktool = lib.mkIf cfg.enable {
description = "Run tool to query bank account and sync transaction data to pretix server.";
after = [ "network.target" ];
wantedBy = [ "timers.target" ];
timerConfig = {
Persistent = true;
OnCalendar = "*-*-* *:00:00";
Unit = "pretix-banktool.service";
};
};
};
}

View file

@ -1 +0,0 @@
use nix

View file

@ -1,318 +0,0 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.pretix;
name = "pretix";
user = "pretix";
group = "pretix";
bind = {
host = "127.0.0.1";
port = 8000;
};
postgresql = {
database = "pretix";
user = "pretix";
password = "pretix";
};
redisPort = 6379;
urlScheme = if cfg.enableTls then "https" else "http";
url = "${urlScheme}://${cfg.domain}";
toBool = x: if x then "on" else "off";
hstsHeader = if cfg.enableTls then "add_header Strict-Transport-Security \"max-age=31536000; includeSubDomains; preload\" always;" else "";
pythonPackages = pkgs.pretix.passthru.pythonModule.passthru.pkgs;
python = pkgs.pretix.passthru.python;
runCommandArgs = {
# Sets PYTHONPATH in derivation
buildInputs = [
pkgs.pretix
pythonPackages.gunicorn
pythonPackages.celery
];
};
staticRoot = pkgs.pretix-static;
environmentFile = pkgs.runCommand "pretix-environ" runCommandArgs (''
cat > $out <<EOF
DATA_DIR = /var/pretix
DJANGO_SETTINGS_MODULE=pretix_wrapper.settings
PRETIX_CELERY_BACKEND=redis://127.0.0.1:${toString redisPort}/2
PRETIX_CELERY_BROKER=redis://127.0.0.1:${toString redisPort}/1
PRETIX_DATABASE_BACKEND=postgresql
PRETIX_DATABASE_HOST=localhost
PRETIX_DATABASE_NAME=${postgresql.database}
PRETIX_DATABASE_PASSWORD=${postgresql.password}
PRETIX_DATABASE_USER=${postgresql.user}
PRETIX_LOCALE_DEFAULT=${cfg.locale}
PRETIX_LOCALE_TIMEZONE=${cfg.timezone}
PRETIX_PRETIX_INSTANCE_NAME=${cfg.instanceName}
PRETIX_PRETIX_PASSWORD_RESET=${toBool cfg.passwordReset}
PRETIX_PRETIX_REGISTRATION=${toBool cfg.enableRegistration}
PRETIX_PRETIX_URL=${url}
PRETIX_REDIS_LOCATION=redis://127.0.0.1:${toString redisPort}/0
PRETIX_REDIS_SESSIONS=true
PRETIX_STATIC_ROOT=${staticRoot}
'' + (
if cfg.mail.enable then
''
PRETIX_MAIL_FROM=${toString cfg.mail.from}
PRETIX_MAIL_HOST="${cfg.mail.host}"
PRETIX_MAIL_PORT=${toString cfg.mail.port}
'' else ""
) +
''
PYTHONPATH=$PYTHONPATH
EOF
'');
mkTimer = { description, unit, onCalendar }: {
inherit description;
requires = [ "pretix-migrate.service" ];
after = [ "network.target" ];
wantedBy = [ "timers.target" ];
timerConfig = {
Persistent = true;
OnCalendar = onCalendar;
Unit = unit;
};
};
in
{
options.services.pretix = with lib; with lib.types; {
enable = mkEnableOption "Enable pretix ticket shop application";
instanceName = mkOption {
type = types.str;
description = "The name of this installation.";
};
domain = mkOption {
type = types.str;
description = "The installations main domain";
example = "pretix.example.net";
};
extraDomains = mkOption {
type = listOf str;
description = "A list of extra domains";
default = [ ];
};
enableTls = mkEnableOption "Whether to use TLS or not";
enableRegistration = mkEnableOption "Enables or disables the registration of new admin users.";
passwordReset = mkEnableOption "Enables or disables password reset.";
locale = mkOption {
type = types.str;
description = "The systems default locale.";
};
timezone = mkOption {
type = types.str;
description = "The systems default timezone as a pytz name.";
};
secretsFile = mkOption {
type = types.path;
description = "Path to the sops secrets file which stores pretix.cfg settings.";
};
gunicornWorkers = mkOption {
type = types.int;
description = "Number of gunicorn workers. Recommended is roughly two times the number of CPU cores available.";
default = 2;
};
mail = {
enable = mkEnableOption "Enables or disables emailing.";
from = mkOption {
type = types.str;
description = "The email address to set as From header in outgoing emails by the system.";
};
host = mkOption {
type = types.str;
description = "The SMTP Host to connect to.";
default = "localhost";
};
port = mkOption {
type = types.port;
description = "The SMTP Port to connect to.";
default = 25;
};
admins = mkOption {
type = listOf str;
description = ''
Comma-separated list of email addresses that should receive a report about every error code 500 thrown by pretix.
'';
default = [ ];
};
};
banktool = {
enable = mkEnableOption "Enable tool to query bank account and sync transaction data to pretix server.";
days = mkOption {
type = types.int;
description = "The timeframe of transaction to fetch from the bank in days.";
};
};
};
config = lib.mkIf cfg.enable {
sops.secrets.pretix-cfg = {
sopsFile = cfg.secretsFile;
};
sops.secrets.pretix-banktool-cfg = {
sopsFile = cfg.secretsFile;
};
users.users."${user}" = {
createHome = true;
description = "Pretix user";
home = "/var/pretix";
isNormalUser = false;
isSystemUser = true;
group = group;
};
users.groups."${group}" = { };
services.nginx = {
enable = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
virtualHosts = lib.listToAttrs (map
(d: {
name = d;
value = {
enableACME = cfg.enableTls;
forceSSL = cfg.enableTls;
kTLS = cfg.enableTls;
locations."/" = {
proxyPass = "http://${bind.host}:${toString bind.port}";
};
extraConfig = ''
${hstsHeader}
'';
};
})
([ cfg.domain ] ++ cfg.extraDomains)
);
};
services.postgresql = {
enable = true;
enableTCPIP = true;
authentication = pkgs.lib.mkOverride 10 ''
local all all trust
host all all ::1/128 trust
'';
initialScript = pkgs.writeText "backend-initScript" ''
CREATE ROLE ${postgresql.user} WITH LOGIN PASSWORD '${postgresql.password}' CREATEDB;
CREATE DATABASE ${postgresql.database};
GRANT ALL PRIVILEGES ON DATABASE ${postgresql.database} TO ${postgresql.user};
ALTER DATABASE ${postgresql.database} OWNER TO ${postgresql.user};
'';
};
services.redis.servers.pretix = {
enable = true;
port = redisPort;
databases = 3;
};
networking.firewall.allowedTCPPorts = [ 80 443 ];
systemd.services.pretix-migrate = {
description = "Pretix DB Migrations";
serviceConfig = {
Type = "oneshot";
EnvironmentFile = environmentFile;
User = user;
LoadCredential = "config:${config.sops.secrets.pretix-cfg.path}";
};
script = ''
export PRETIX_CONFIG_FILE="$CREDENTIALS_DIRECTORY/config"
${pkgs.pretix}/bin/pretix migrate
'';
};
systemd.services.pretix-web = {
description = "Pretix Web Service";
serviceConfig = {
Type = "simple";
Restart = "on-failure";
EnvironmentFile = environmentFile;
User = user;
LoadCredential = "config:${config.sops.secrets.pretix-cfg.path}";
ExecStart = pkgs.writeScript "webserver" ''
#!${pkgs.runtimeShell}
set -euo pipefail
export PRETIX_CONFIG_FILE="$CREDENTIALS_DIRECTORY/config"
exec ${pythonPackages.gunicorn}/bin/gunicorn pretix.wsgi --name ${name} \
--workers ${toString cfg.gunicornWorkers} \
--log-level=info \
--bind=${bind.host}:${toString bind.port}
'';
};
wantedBy = [ "multi-user.target" ];
requires = [ "pretix-migrate.service" ];
after = [ "network.target" ];
};
systemd.services.pretix-worker = {
description = "Pretix Celery (Worker) Service";
serviceConfig = {
Type = "simple";
Restart = "on-failure";
EnvironmentFile = environmentFile;
User = user;
LoadCredential = "config:${config.sops.secrets.pretix-cfg.path}";
ExecStart = pkgs.writeScript "worker" ''
#!${pkgs.runtimeShell}
set -euo pipefail
export PRETIX_CONFIG_FILE="$CREDENTIALS_DIRECTORY/config"
exec ${pythonPackages.celery}/bin/celery -A pretix.celery_app worker -l info
'';
};
wantedBy = [ "multi-user.target" ];
requires = [ "pretix-migrate.service" ];
after = [ "network.target" ];
};
systemd.services.pretix-runperiodic = {
description = "Pretix periodic tasks";
serviceConfig = {
Type = "oneshot";
EnvironmentFile = environmentFile;
User = user;
LoadCredential = "config:${config.sops.secrets.pretix-cfg.path}";
};
script = ''
export PRETIX_CONFIG_FILE="$CREDENTIALS_DIRECTORY/config"
${pkgs.pretix}/bin/pretix runperiodic
'';
};
# Once every 5 minutes
systemd.timers.pretix-runperiodic = mkTimer {
description = "Run pretix tasks";
unit = "pretix-runperiodic.service";
onCalendar = "*:0/5";
};
systemd.services.pretix-banktool = lib.mkIf cfg.banktool.enable {
description = "Tool to query bank account and sync transaction data to pretix server.";
serviceConfig = {
Type = "oneshot";
DynamicUser = true;
CapabilityBoundingSet = null;
PrivateUsers = true;
ProtectHome = true;
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
RestrictNamespaces = true;
SystemCallFilter = "@system-service";
LoadCredential = "config:${config.sops.secrets.pretix-banktool-cfg.path}";
};
script = "${pkgs.pretix-banktool}/bin/pretix-banktool upload \"$CREDENTIALS_DIRECTORY/config\" --days=${toString cfg.banktool.days}";
};
systemd.timers.pretix-banktool = lib.mkIf cfg.banktool.enable {
description = "Run tool to query bank account and sync transaction data to pretix server.";
after = [ "network.target" ];
wantedBy = [ "timers.target" ];
timerConfig = {
Persistent = true;
OnCalendar = "*-*-* *:00:00";
Unit = "pretix-banktool.service";
};
};
};
}

3176
pkgs/pretix/poetry.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,48 +0,0 @@
{ stdenvNoCC
, pretix
, buildNpmPackage
, makeWrapper
}:
let
nodeEnv = buildNpmPackage rec {
name = "pretix-nodejs";
src = "${pretix.passthru.pythonModule.pkgs.pretix}/lib/${pretix.python.libPrefix}/site-packages/pretix/static/npm_dir";
npmDepsHash = "sha256-2fHlEEmYzpF3SyvF7+FbwCt+zQVGF0/kslDFnJ+DQGE=";
dontNpmBuild = true;
installPhase = ''
mkdir -p $out
cp -r node_modules $out/
mkdir -p $out/bin
ln -s $out/node_modules/rollup/dist/bin/rollup $out/bin/rollup
'';
postFixup = ''
wrapProgram $out/bin/rollup --prefix NODE_PATH : $out
'';
nativeBuildInputs = [
makeWrapper
];
};
in
stdenvNoCC.mkDerivation {
name = "pretix-static";
src = ./.;
buildPhase = ''
mkdir $out
export PRETIX_STATIC_ROOT=$out
export DJANGO_SETTINGS_MODULE=pretix_wrapper.settings
${pretix}/bin/pretix collectstatic --noinput
mkdir -p $PRETIX_STATIC_ROOT/node_prefix
ln -s ${nodeEnv}/node_modules $PRETIX_STATIC_ROOT/node_prefix/node_modules
echo ${nodeEnv}/bin/rollup
${pretix}/bin/pretix compress
'';
installPhase = ''
runHook preInstall
runHook postInstall
'';
nativeBuildInputs = [
nodeEnv
];
}

View file

@ -1,60 +0,0 @@
{ lib
, poetry2nix
, pkgs
, gettext
, tlds-alpha-by-domain ? ./tlds-alpha-by-domain.txt
}:
let
tlds = pkgs.fetchurl {
url = "https://data.iana.org/TLD/tlds-alpha-by-domain.txt";
sha256 = "0153py77ll759jacq41dp2z2ksr08pdcfic0rwjd6pr84dk89y9v";
};
pkgsRequiringSetuptools = [
"dj-static"
"django-jquery-js"
"paypal-checkout-serversdk"
"python-u2flib-server"
"slimit"
"static3"
];
in
poetry2nix.mkPoetryApplication rec {
projectDir = ./.;
#python = pkgs.python310;
preferWheels = true;
overrides = poetry2nix.defaultPoetryOverrides.extend
(
self: super: lib.attrsets.genAttrs pkgsRequiringSetuptools
(
pythonPackage:
super."${pythonPackage}".overridePythonAttrs (
old: {
buildInputs = (old.buildInputs or [ ]) ++ [ super.setuptools ];
}
)
) // {
tlds = super.tlds.overridePythonAttrs (
old: {
buildInputs = (old.buildInputs or [ ]) ++ [ super.setuptools ];
}
);
pretix = super.pretix.overridePythonAttrs (
old: {
buildInputs = (old.buildInputs or [ ]) ++ [
gettext
];
preFixup = ''
python -m pretix compilemessages
python -m pretix compilejsi18n
'';
}
);
reportlab = super.reportlab.overridePythonAttrs (
old: {
postPatch = "";
}
);
}
);
}

View file

@ -1,9 +0,0 @@
import sys
import os
module_name = "pretix"
def main():
os.environ["PYTHONPATH"] = ":".join(sys.path)
os.execv(sys.executable, [sys.executable, "-m", module_name, *sys.argv[1:]])

View file

@ -1,4 +0,0 @@
import os
from pretix.settings import *
STATIC_ROOT = os.getenv("PRETIX_STATIC_ROOT")

View file

@ -1,19 +0,0 @@
[tool.poetry]
name = "pretix_wrapper"
version = "1.0.0"
description = ""
authors = ["Jakob Lechner <mail@jalr.de>"]
license = "MIT"
[tool.poetry.dependencies]
python = "^3.10"
pretix = "^2024.3.0"
[tool.poetry.dev-dependencies]
[tool.poetry.scripts]
pretix = "pretix_wrapper.__main__:main"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

View file

@ -1,8 +0,0 @@
with import <nixpkgs> { };
mkShell {
buildInputs = [
poetry
];
}