Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #68973 from symphorien/ihatemoney
ihatemoney: init at 4.1 plus module and test
- Loading branch information
Showing
7 changed files
with
300 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
{ config, pkgs, lib, ... }: | ||
with lib; | ||
let | ||
cfg = config.services.ihatemoney; | ||
user = "ihatemoney"; | ||
group = "ihatemoney"; | ||
db = "ihatemoney"; | ||
python3 = config.services.uwsgi.package.python3; | ||
pkg = python3.pkgs.ihatemoney; | ||
toBool = x: if x then "True" else "False"; | ||
configFile = pkgs.writeText "ihatemoney.cfg" '' | ||
from secrets import token_hex | ||
# load a persistent secret key | ||
SECRET_KEY_FILE = "/var/lib/ihatemoney/secret_key" | ||
SECRET_KEY = "" | ||
try: | ||
with open(SECRET_KEY_FILE) as f: | ||
SECRET_KEY = f.read() | ||
except FileNotFoundError: | ||
pass | ||
if not SECRET_KEY: | ||
print("ihatemoney: generating a new secret key") | ||
SECRET_KEY = token_hex(50) | ||
with open(SECRET_KEY_FILE, "w") as f: | ||
f.write(SECRET_KEY) | ||
del token_hex | ||
del SECRET_KEY_FILE | ||
# "normal" configuration | ||
DEBUG = False | ||
SQLALCHEMY_DATABASE_URI = '${ | ||
if cfg.backend == "sqlite" | ||
then "sqlite:////var/lib/ihatemoney/ihatemoney.sqlite" | ||
else "postgresql:///${db}"}' | ||
SQLALCHEMY_TRACK_MODIFICATIONS = False | ||
MAIL_DEFAULT_SENDER = ("${cfg.defaultSender.name}", "${cfg.defaultSender.email}") | ||
ACTIVATE_DEMO_PROJECT = ${toBool cfg.enableDemoProject} | ||
ADMIN_PASSWORD = "${toString cfg.adminHashedPassword /*toString null == ""*/}" | ||
ALLOW_PUBLIC_PROJECT_CREATION = ${toBool cfg.enablePublicProjectCreation} | ||
ACTIVATE_ADMIN_DASHBOARD = ${toBool cfg.enableAdminDashboard} | ||
${cfg.extraConfig} | ||
''; | ||
in | ||
{ | ||
options.services.ihatemoney = { | ||
enable = mkEnableOption "ihatemoney webapp. Note that this will set uwsgi to emperor mode running as root"; | ||
backend = mkOption { | ||
type = types.enum [ "sqlite" "postgresql" ]; | ||
default = "sqlite"; | ||
description = '' | ||
The database engine to use for ihatemoney. | ||
If <literal>postgresql</literal> is selected, then a database called | ||
<literal>${db}</literal> will be created. If you disable this option, | ||
it will however not be removed. | ||
''; | ||
}; | ||
adminHashedPassword = mkOption { | ||
type = types.nullOr types.str; | ||
default = null; | ||
description = "The hashed password of the administrator. To obtain it, run <literal>ihatemoney generate_password_hash</literal>"; | ||
}; | ||
uwsgiConfig = mkOption { | ||
type = types.attrs; | ||
example = { | ||
http = ":8000"; | ||
}; | ||
description = "Additionnal configuration of the UWSGI vassal running ihatemoney. It should notably specify on which interfaces and ports the vassal should listen."; | ||
}; | ||
defaultSender = { | ||
name = mkOption { | ||
type = types.str; | ||
default = "Budget manager"; | ||
description = "The display name of the sender of ihatemoney emails"; | ||
}; | ||
email = mkOption { | ||
type = types.str; | ||
default = "ihatemoney@${config.networking.hostName}"; | ||
description = "The email of the sender of ihatemoney emails"; | ||
}; | ||
}; | ||
enableDemoProject = mkEnableOption "access to the demo project in ihatemoney"; | ||
enablePublicProjectCreation = mkEnableOption "permission to create projects in ihatemoney by anyone"; | ||
enableAdminDashboard = mkEnableOption "ihatemoney admin dashboard"; | ||
extraConfig = mkOption { | ||
type = types.str; | ||
default = ""; | ||
description = "Extra configuration appended to ihatemoney's configuration file. It is a python file, so pay attention to indentation."; | ||
}; | ||
}; | ||
config = mkIf cfg.enable { | ||
services.postgresql = mkIf (cfg.backend == "postgresql") { | ||
enable = true; | ||
ensureDatabases = [ db ]; | ||
ensureUsers = [ { | ||
name = user; | ||
ensurePermissions = { | ||
"DATABASE ${db}" = "ALL PRIVILEGES"; | ||
}; | ||
} ]; | ||
}; | ||
systemd.services.postgresql = mkIf (cfg.backend == "postgresql") { | ||
wantedBy = [ "uwsgi.service" ]; | ||
before = [ "uwsgi.service" ]; | ||
}; | ||
systemd.tmpfiles.rules = [ | ||
"d /var/lib/ihatemoney 770 ${user} ${group}" | ||
]; | ||
users = { | ||
users.${user} = { | ||
isSystemUser = true; | ||
inherit group; | ||
}; | ||
groups.${group} = {}; | ||
}; | ||
services.uwsgi = { | ||
enable = true; | ||
plugins = [ "python3" ]; | ||
# the vassal needs to be able to setuid | ||
user = "root"; | ||
group = "root"; | ||
instance = { | ||
type = "emperor"; | ||
vassals.ihatemoney = { | ||
type = "normal"; | ||
strict = true; | ||
uid = user; | ||
gid = group; | ||
# apparently flask uses threads: https://github.com/spiral-project/ihatemoney/commit/c7815e48781b6d3a457eaff1808d179402558f8c | ||
enable-threads = true; | ||
module = "wsgi:application"; | ||
chdir = "${pkg}/${pkg.pythonModule.sitePackages}/ihatemoney"; | ||
env = [ "IHATEMONEY_SETTINGS_FILE_PATH=${configFile}" ]; | ||
pythonPackages = self: [ self.ihatemoney ]; | ||
} // cfg.uwsgiConfig; | ||
}; | ||
}; | ||
}; | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
{ system ? builtins.currentSystem | ||
, config ? {} | ||
, pkgs ? import ../.. { inherit system config; } | ||
}: | ||
|
||
let | ||
inherit (import ../lib/testing.nix { inherit system pkgs; }) makeTest; | ||
in | ||
map ( | ||
backend: makeTest { | ||
name = "ihatemoney-${backend}"; | ||
machine = { lib, ... }: { | ||
services.ihatemoney = { | ||
enable = true; | ||
enablePublicProjectCreation = true; | ||
inherit backend; | ||
uwsgiConfig = { | ||
http = ":8000"; | ||
}; | ||
}; | ||
boot.cleanTmpDir = true; | ||
# ihatemoney needs a local smtp server otherwise project creation just crashes | ||
services.opensmtpd = { | ||
enable = true; | ||
serverConfiguration = '' | ||
listen on lo | ||
action foo relay | ||
match from any for any action foo | ||
''; | ||
}; | ||
}; | ||
testScript = '' | ||
$machine->waitForOpenPort(8000); | ||
$machine->waitForUnit("uwsgi.service"); | ||
my $return = $machine->succeed("curl -X POST http://localhost:8000/api/projects -d 'name=yay&id=yay&password=yay&contact_email=yay\@example.com'"); | ||
die "wrong project id $return" unless "\"yay\"\n" eq $return; | ||
my $timestamp = $machine->succeed("stat --printf %Y /var/lib/ihatemoney/secret_key"); | ||
my $owner = $machine->succeed("stat --printf %U:%G /var/lib/ihatemoney/secret_key"); | ||
die "wrong ownership for the secret key: $owner, is uwsgi running as the right user ?" unless $owner eq "ihatemoney:ihatemoney"; | ||
$machine->shutdown(); | ||
$machine->start(); | ||
$machine->waitForOpenPort(8000); | ||
$machine->waitForUnit("uwsgi.service"); | ||
# check that the database is really persistent | ||
print $machine->succeed("curl --basic -u yay:yay http://localhost:8000/api/projects/yay"); | ||
# check that the secret key is really persistent | ||
my $timestamp2 = $machine->succeed("stat --printf %Y /var/lib/ihatemoney/secret_key"); | ||
die unless $timestamp eq $timestamp2; | ||
$machine->succeed("curl http://localhost:8000 | grep ihatemoney"); | ||
''; | ||
} | ||
) [ "sqlite" "postgresql" ] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
{ buildPythonPackage, lib, fetchFromGitHub, nixosTests | ||
, alembic | ||
, aniso8601 | ||
, Babel | ||
, blinker | ||
, click | ||
, dnspython | ||
, email_validator | ||
, flask | ||
, flask-babel | ||
, flask-cors | ||
, flask_mail | ||
, flask_migrate | ||
, flask-restful | ||
, flask_script | ||
, flask_sqlalchemy | ||
, flask_wtf | ||
, idna | ||
, itsdangerous | ||
, jinja2 | ||
, Mako | ||
, markupsafe | ||
, python-dateutil | ||
, pytz | ||
, six | ||
, sqlalchemy | ||
, werkzeug | ||
, wtforms | ||
, psycopg2 # optional, for postgresql support | ||
, flask_testing | ||
}: | ||
|
||
buildPythonPackage rec { | ||
pname = "ihatemoney"; | ||
version = "4.1"; | ||
|
||
src = fetchFromGitHub { | ||
owner = "spiral-project"; | ||
repo = pname; | ||
rev = version; | ||
sha256 = "1ai7v2i2rvswzv21nwyq51fvp8lr2x2cl3n34p11br06kc1pcmin"; | ||
}; | ||
|
||
propagatedBuildInputs = [ | ||
alembic | ||
aniso8601 | ||
Babel | ||
blinker | ||
click | ||
dnspython | ||
email_validator | ||
flask | ||
flask-babel | ||
flask-cors | ||
flask_mail | ||
flask_migrate | ||
flask-restful | ||
flask_script | ||
flask_sqlalchemy | ||
flask_wtf | ||
idna | ||
itsdangerous | ||
jinja2 | ||
Mako | ||
markupsafe | ||
python-dateutil | ||
pytz | ||
six | ||
sqlalchemy | ||
werkzeug | ||
wtforms | ||
psycopg2 | ||
]; | ||
|
||
checkInputs = [ | ||
flask_testing | ||
]; | ||
|
||
passthru.tests = { | ||
inherit (nixosTests) ihatemoney; | ||
}; | ||
meta = with lib; { | ||
homepage = "https://ihatemoney.org"; | ||
description = "A simple shared budget manager web application"; | ||
platforms = platforms.linux; | ||
license = licenses.beerware; | ||
maintainers = [ maintainers.symphorien ]; | ||
}; | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters