From dd4e5c63e3693ea1d5fe7ba6c9da28b035f51237 Mon Sep 17 00:00:00 2001 From: Joakim Repomaa Date: Wed, 12 Feb 2025 20:58:10 +0200 Subject: [PATCH] add donetick --- hosts/freun.dev/secrets.nix | 1 + hosts/freun.dev/services.nix | 12 ++ modules/services/default.nix | 1 + modules/services/donetick.nix | 212 ++++++++++++++++++++++++++++++++++ secrets/donetick.age | 10 ++ 5 files changed, 236 insertions(+) create mode 100644 modules/services/donetick.nix create mode 100644 secrets/donetick.age diff --git a/hosts/freun.dev/secrets.nix b/hosts/freun.dev/secrets.nix index 985e32f..0c7f4ab 100644 --- a/hosts/freun.dev/secrets.nix +++ b/hosts/freun.dev/secrets.nix @@ -9,6 +9,7 @@ "readeck" "storage-box-credentials" "vaultwarden" + "donetick" ] ) // { smtp-password = { diff --git a/hosts/freun.dev/services.nix b/hosts/freun.dev/services.nix index 5e77a7a..4c5abdf 100644 --- a/hosts/freun.dev/services.nix +++ b/hosts/freun.dev/services.nix @@ -118,5 +118,17 @@ in from_noreply = smtp.from; }; }; + + donetick = { + enable = true; + subdomain = "do"; + settings = { + email = { + host = smtp.host; + port = smtp.port; + email = smtp.username; + }; + }; + }; }; } diff --git a/modules/services/default.nix b/modules/services/default.nix index 175bd3a..7329b3a 100644 --- a/modules/services/default.nix +++ b/modules/services/default.nix @@ -15,5 +15,6 @@ ./hastebin.nix ./workout-sync.nix ./readeck.nix + ./donetick.nix ]; } diff --git a/modules/services/donetick.nix b/modules/services/donetick.nix new file mode 100644 index 0000000..548957c --- /dev/null +++ b/modules/services/donetick.nix @@ -0,0 +1,212 @@ +{ lib, pkgs, config, ... }: +let + types = { + jwtSettings = { + session_time = lib.mkOption { + type = lib.types.str; + default = "168h"; + }; + max_refresh = lib.mkOption { + type = lib.types.str; + default = "168h"; + }; + }; + serverSettings = { + port = lib.mkOption { + type = lib.types.int; + default = 2021; + }; + read_timeout = lib.mkOption { + type = lib.types.str; + default = "10s"; + }; + write_timeout = lib.mkOption { + type = lib.types.str; + default = "10s"; + }; + rate_period = lib.mkOption { + type = lib.types.str; + default = "60s"; + }; + rate_limit = lib.mkOption { + type = lib.types.int; + default = 300; + }; + cors_allow_origins = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ + "http://localhost:5173" + "http://localhost:7926" + "https://localhost" + "capacitor://localhost" + ]; + }; + serve_frontend = lib.mkOption { + type = lib.types.bool; + default = true; + }; + }; + schedulerSettings = { + due_job = lib.mkOption { + type = lib.types.str; + default = "30m"; + }; + overdue_job = lib.mkOption { + type = lib.types.str; + default = "3h"; + }; + pre_due_job = lib.mkOption { + type = lib.types.str; + default = "3h"; + }; + }; + emailSettings = { + host = lib.mkOption { + type = lib.types.str; + default = ""; + }; + port = lib.mkOption { + type = lib.types.int; + default = 587; + }; + email = lib.mkOption { + type = lib.types.str; + default = ""; + }; + key = lib.mkOption { + type = lib.types.str; + default = ""; + }; + }; + oauth2Settings = { + client_id = lib.mkOption { + type = lib.types.str; + default = ""; + }; + client_secret = lib.mkOption { + type = lib.types.str; + default = ""; + }; + auth_url = lib.mkOption { + type = lib.types.str; + default = ""; + }; + token_url = lib.mkOption { + type = lib.types.str; + default = ""; + }; + user_info_url = lib.mkOption { + type = lib.types.str; + default = ""; + }; + redirect_url = lib.mkOption { + type = lib.types.str; + default = ""; + }; + name = lib.mkOption { + type = lib.types.str; + default = ""; + }; + }; + settings = lib.types.submodule { + options = { + is_user_creation_disabled = lib.mkEnableOption "Disable user creation"; + telegram.token = lib.mkOption { + type = lib.types.str; + default = ""; + }; + pushover.token = lib.mkOption { + type = lib.types.str; + default = ""; + }; + jwt = types.jwtSettings; + server = types.serverSettings; + scheduler_jobs = types.schedulerSettings; + email = types.emailSettings; + oauth2 = types.oauth2Settings; + }; + }; + }; + version = "0.0.33"; + + package = pkgs.stdenv.mkDerivation { + name = "donetick"; + src = pkgs.fetchurl { + url = "https://github.com/donetick/donetick/releases/download/v${version}/donetick_Linux_arm64.tar.gz"; + hash = "sha256-o5PcONv+fxBMToOCwBcr2fnSpsHn5bdfujyUTuMKTbI="; + }; + nativeBuildInputs = [ + pkgs.autoPatchelfHook + ]; + sourceRoot = "."; + installPhase = '' + runHook preInstall + install -Dm755 donetick $out/bin/donetick + runHook postInstall + ''; + meta = with pkgs.lib; { + description = "A self-hosted task and chore manager"; + license = licenses.mit; + mainProgram = "donetick"; + }; + }; + cfg = config.services.donetick; + fqdn = "${cfg.subdomain}.${config.networking.domain}"; + + immutableSettings = { + name = "selfhosted"; + is_done_tick_dot_com = false; + email.appHost = "https://${fqdn}"; + database = { + type = "sqlite"; + migration = true; + }; + }; + settings = (pkgs.formats.yaml { }).generate "selfhosted.yaml" (cfg.settings // immutableSettings); + secrets = config.age.secrets; +in +{ + options.services.donetick = { + enable = lib.mkEnableOption "Enable donetick"; + subdomain = lib.mkOption { + type = lib.types.str; + }; + settings = lib.mkOption { + type = types.settings; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.services.donetick = { + enable = true; + environment = { + DT_ENV = "selfhosted"; + }; + serviceConfig = { + DynamicUser = true; + ExecStart = "${package}/bin/donetick"; + BindReadOnlyPaths = [ + "${settings}:/var/lib/donetick/config/selfhosted.yaml" + /run/systemd/resolve/stub-resolv.conf + /etc/ssl + /etc/static/ssl + /etc/resolv.conf + /etc/static/resolv.conf + /etc/nsswitch.conf + /etc/static/nsswitch.conf + /etc/hosts + ]; + WorkingDirectory = "/var/lib/donetick"; + StateDirectory = "donetick"; + EnvironmentFile = secrets.donetick.path; + }; + wantedBy = [ "multi-user.target" ]; + confinement.enable = true; + }; + + modules.services.webserver = { + enable = lib.mkDefault true; + vHosts.${fqdn}.locations."/" .proxyPort = cfg.settings.server.port; + }; + }; +} diff --git a/secrets/donetick.age b/secrets/donetick.age new file mode 100644 index 0000000..1ea88bf --- /dev/null +++ b/secrets/donetick.age @@ -0,0 +1,10 @@ +age-encryption.org/v1 +-> ssh-ed25519 osOCZA Uhj0wv4ftLWngI5kLmUYm/MIKgV8DMX+P9ODdBgnmR8 +F3nokDZUpTMtD+GSy/lHZQDRWbpQA3euOfnPTvnAnyE +-> ssh-ed25519 DFiohQ Ydx/DFxmGrc1AzR8F7kpWFz3bDjpiAY2biCYCwRwt0w +/OFFEw3Hb720ST36K7woG26skB2Sq9cOWrPaTN/aIpw +-> ssh-ed25519 PT7ffg R1+hn9bq5P5zpOSAsKWmnPEpmRLdWBmx36+2o6bmBDQ +bu9yOfiVGc7qHGr12bVtUJTCZ8DfAAxs9FdCgDBRwr4 +--- 9q8U0DARF8YjVla+Gywx2xlaZk2LHgcK7nOENR4Eup0 + +£¯M¾µM®ÔÖ »8ûìwi˜çÕ§ XA>äç›ýÏr,2¹N´a5{}K.Ïσ5¨š‰›ÀÉeÖòØätS¤‚¯ˆb Åd