mirror of
https://github.com/NixOS/nixpkgs.git
synced 2024-11-26 00:43:20 +00:00
nixos/invoiceplane: init module and package at 1.5.11 (#146909)
This commit is contained in:
parent
98ae5a9298
commit
80475b46f5
@ -108,6 +108,14 @@
|
|||||||
<link xlink:href="options.html#opt-services.powerdns-admin.enable">services.powerdns-admin</link>.
|
<link xlink:href="options.html#opt-services.powerdns-admin.enable">services.powerdns-admin</link>.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<link xlink:href="https://invoiceplane.com">InvoicePlane</link>,
|
||||||
|
web application for managing and creating invoices. Available
|
||||||
|
at
|
||||||
|
<link xlink:href="options.html#opt-services.invoiceplane.enable">services.invoiceplane</link>.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
<link xlink:href="https://maddy.email">maddy</link>, a
|
<link xlink:href="https://maddy.email">maddy</link>, a
|
||||||
|
@ -35,6 +35,8 @@ In addition to numerous new and upgraded packages, this release has the followin
|
|||||||
|
|
||||||
- [PowerDNS-Admin](https://github.com/ngoduykhanh/PowerDNS-Admin), a web interface for the PowerDNS server. Available at [services.powerdns-admin](options.html#opt-services.powerdns-admin.enable).
|
- [PowerDNS-Admin](https://github.com/ngoduykhanh/PowerDNS-Admin), a web interface for the PowerDNS server. Available at [services.powerdns-admin](options.html#opt-services.powerdns-admin.enable).
|
||||||
|
|
||||||
|
- [InvoicePlane](https://invoiceplane.com), web application for managing and creating invoices. Available at [services.invoiceplane](options.html#opt-services.invoiceplane.enable).
|
||||||
|
|
||||||
- [maddy](https://maddy.email), a composable all-in-one mail server. Available as [services.maddy](options.html#opt-services.maddy.enable).
|
- [maddy](https://maddy.email), a composable all-in-one mail server. Available as [services.maddy](options.html#opt-services.maddy.enable).
|
||||||
|
|
||||||
- [mtr-exporter](https://github.com/mgumz/mtr-exporter), a Prometheus exporter for mtr metrics. Available as [services.mtr-exporter](options.html#opt-services.mtr-exporter.enable).
|
- [mtr-exporter](https://github.com/mgumz/mtr-exporter), a Prometheus exporter for mtr metrics. Available as [services.mtr-exporter](options.html#opt-services.mtr-exporter.enable).
|
||||||
|
@ -1022,6 +1022,7 @@
|
|||||||
./services/web-apps/keycloak.nix
|
./services/web-apps/keycloak.nix
|
||||||
./services/web-apps/lemmy.nix
|
./services/web-apps/lemmy.nix
|
||||||
./services/web-apps/invidious.nix
|
./services/web-apps/invidious.nix
|
||||||
|
./services/web-apps/invoiceplane.nix
|
||||||
./services/web-apps/limesurvey.nix
|
./services/web-apps/limesurvey.nix
|
||||||
./services/web-apps/mastodon.nix
|
./services/web-apps/mastodon.nix
|
||||||
./services/web-apps/mattermost.nix
|
./services/web-apps/mattermost.nix
|
||||||
|
305
nixos/modules/services/web-apps/invoiceplane.nix
Normal file
305
nixos/modules/services/web-apps/invoiceplane.nix
Normal file
@ -0,0 +1,305 @@
|
|||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.services.invoiceplane;
|
||||||
|
eachSite = cfg.sites;
|
||||||
|
user = "invoiceplane";
|
||||||
|
webserver = config.services.${cfg.webserver};
|
||||||
|
|
||||||
|
invoiceplane-config = hostName: cfg: pkgs.writeText "ipconfig.php" ''
|
||||||
|
IP_URL=http://${hostName}
|
||||||
|
ENABLE_DEBUG=false
|
||||||
|
DISABLE_SETUP=false
|
||||||
|
REMOVE_INDEXPHP=false
|
||||||
|
DB_HOSTNAME=${cfg.database.host}
|
||||||
|
DB_USERNAME=${cfg.database.user}
|
||||||
|
# NOTE: file_get_contents adds newline at the end of returned string
|
||||||
|
DB_PASSWORD=${if cfg.database.passwordFile == null then "" else "trim(file_get_contents('${cfg.database.passwordFile}'), \"\\r\\n\")"}
|
||||||
|
DB_DATABASE=${cfg.database.name}
|
||||||
|
DB_PORT=${toString cfg.database.port}
|
||||||
|
SESS_EXPIRATION=864000
|
||||||
|
ENABLE_INVOICE_DELETION=false
|
||||||
|
DISABLE_READ_ONLY=false
|
||||||
|
ENCRYPTION_KEY=
|
||||||
|
ENCRYPTION_CIPHER=AES-256
|
||||||
|
SETUP_COMPLETED=false
|
||||||
|
'';
|
||||||
|
|
||||||
|
extraConfig = hostName: cfg: pkgs.writeText "extraConfig.php" ''
|
||||||
|
${toString cfg.extraConfig}
|
||||||
|
'';
|
||||||
|
|
||||||
|
pkg = hostName: cfg: pkgs.stdenv.mkDerivation rec {
|
||||||
|
pname = "invoiceplane-${hostName}";
|
||||||
|
version = src.version;
|
||||||
|
src = pkgs.invoiceplane;
|
||||||
|
|
||||||
|
patchPhase = ''
|
||||||
|
# Patch index.php file to load additional config file
|
||||||
|
substituteInPlace index.php \
|
||||||
|
--replace "require('vendor/autoload.php');" "require('vendor/autoload.php'); \$dotenv = new \Dotenv\Dotenv(__DIR__, 'extraConfig.php'); \$dotenv->load();";
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p $out
|
||||||
|
cp -r * $out/
|
||||||
|
|
||||||
|
# symlink uploads and log directories
|
||||||
|
rm -r $out/uploads $out/application/logs $out/vendor/mpdf/mpdf/tmp
|
||||||
|
ln -sf ${cfg.stateDir}/uploads $out/
|
||||||
|
ln -sf ${cfg.stateDir}/logs $out/application/
|
||||||
|
ln -sf ${cfg.stateDir}/tmp $out/vendor/mpdf/mpdf/
|
||||||
|
|
||||||
|
# symlink the InvoicePlane config
|
||||||
|
ln -s ${cfg.stateDir}/ipconfig.php $out/ipconfig.php
|
||||||
|
|
||||||
|
# symlink the extraConfig file
|
||||||
|
ln -s ${extraConfig hostName cfg} $out/extraConfig.php
|
||||||
|
|
||||||
|
# symlink additional templates
|
||||||
|
${concatMapStringsSep "\n" (template: "cp -r ${template}/. $out/application/views/invoice_templates/pdf/") cfg.invoiceTemplates}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
siteOpts = { lib, name, ... }:
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
|
||||||
|
enable = mkEnableOption "InvoicePlane web application";
|
||||||
|
|
||||||
|
stateDir = mkOption {
|
||||||
|
type = types.path;
|
||||||
|
default = "/var/lib/invoiceplane/${name}";
|
||||||
|
description = ''
|
||||||
|
This directory is used for uploads of attachements and cache.
|
||||||
|
The directory passed here is automatically created and permissions
|
||||||
|
adjusted as required.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
database = {
|
||||||
|
host = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "localhost";
|
||||||
|
description = "Database host address.";
|
||||||
|
};
|
||||||
|
|
||||||
|
port = mkOption {
|
||||||
|
type = types.port;
|
||||||
|
default = 3306;
|
||||||
|
description = "Database host port.";
|
||||||
|
};
|
||||||
|
|
||||||
|
name = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "invoiceplane";
|
||||||
|
description = "Database name.";
|
||||||
|
};
|
||||||
|
|
||||||
|
user = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "invoiceplane";
|
||||||
|
description = "Database user.";
|
||||||
|
};
|
||||||
|
|
||||||
|
passwordFile = mkOption {
|
||||||
|
type = types.nullOr types.path;
|
||||||
|
default = null;
|
||||||
|
example = "/run/keys/invoiceplane-dbpassword";
|
||||||
|
description = ''
|
||||||
|
A file containing the password corresponding to
|
||||||
|
<option>database.user</option>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
createLocally = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Create the database and database user locally.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
invoiceTemplates = mkOption {
|
||||||
|
type = types.listOf types.path;
|
||||||
|
default = [];
|
||||||
|
description = ''
|
||||||
|
List of path(s) to respective template(s) which are copied from the 'invoice_templates/pdf' directory.
|
||||||
|
<note><para>These templates need to be packaged before use, see example.</para></note>
|
||||||
|
'';
|
||||||
|
example = literalExpression ''
|
||||||
|
let
|
||||||
|
# Let's package an example template
|
||||||
|
template-vtdirektmarketing = pkgs.stdenv.mkDerivation {
|
||||||
|
name = "vtdirektmarketing";
|
||||||
|
# Download the template from a public repository
|
||||||
|
src = pkgs.fetchgit {
|
||||||
|
url = "https://git.project-insanity.org/onny/invoiceplane-vtdirektmarketing.git";
|
||||||
|
sha256 = "1hh0q7wzsh8v8x03i82p6qrgbxr4v5fb05xylyrpp975l8axyg2z";
|
||||||
|
};
|
||||||
|
sourceRoot = ".";
|
||||||
|
# Installing simply means copying template php file to the output directory
|
||||||
|
installPhase = ""
|
||||||
|
mkdir -p $out
|
||||||
|
cp invoiceplane-vtdirektmarketing/vtdirektmarketing.php $out/
|
||||||
|
"";
|
||||||
|
};
|
||||||
|
# And then pass this package to the template list like this:
|
||||||
|
in [ template-vtdirektmarketing ]
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
poolConfig = mkOption {
|
||||||
|
type = with types; attrsOf (oneOf [ str int bool ]);
|
||||||
|
default = {
|
||||||
|
"pm" = "dynamic";
|
||||||
|
"pm.max_children" = 32;
|
||||||
|
"pm.start_servers" = 2;
|
||||||
|
"pm.min_spare_servers" = 2;
|
||||||
|
"pm.max_spare_servers" = 4;
|
||||||
|
"pm.max_requests" = 500;
|
||||||
|
};
|
||||||
|
description = ''
|
||||||
|
Options for the InvoicePlane PHP pool. See the documentation on <literal>php-fpm.conf</literal>
|
||||||
|
for details on configuration directives.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
extraConfig = mkOption {
|
||||||
|
type = types.nullOr types.lines;
|
||||||
|
default = null;
|
||||||
|
example = ''
|
||||||
|
SETUP_COMPLETED=true
|
||||||
|
DISABLE_SETUP=true
|
||||||
|
IP_URL=https://invoice.example.com
|
||||||
|
'';
|
||||||
|
description = ''
|
||||||
|
InvoicePlane configuration. Refer to
|
||||||
|
<link xlink:href="https://github.com/InvoicePlane/InvoicePlane/blob/master/ipconfig.php.example"/>
|
||||||
|
for details on supported values.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# interface
|
||||||
|
options = {
|
||||||
|
services.invoiceplane = mkOption {
|
||||||
|
type = types.submodule {
|
||||||
|
|
||||||
|
options.sites = mkOption {
|
||||||
|
type = types.attrsOf (types.submodule siteOpts);
|
||||||
|
default = {};
|
||||||
|
description = "Specification of one or more WordPress sites to serve";
|
||||||
|
};
|
||||||
|
|
||||||
|
options.webserver = mkOption {
|
||||||
|
type = types.enum [ "caddy" ];
|
||||||
|
default = "caddy";
|
||||||
|
description = ''
|
||||||
|
Which webserver to use for virtual host management. Currently only
|
||||||
|
caddy is supported.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
default = {};
|
||||||
|
description = "InvoicePlane configuration.";
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
# implementation
|
||||||
|
config = mkIf (eachSite != {}) (mkMerge [{
|
||||||
|
|
||||||
|
assertions = flatten (mapAttrsToList (hostName: cfg:
|
||||||
|
[{ assertion = cfg.database.createLocally -> cfg.database.user == user;
|
||||||
|
message = ''services.invoiceplane.sites."${hostName}".database.user must be ${user} if the database is to be automatically provisioned'';
|
||||||
|
}
|
||||||
|
{ assertion = cfg.database.createLocally -> cfg.database.passwordFile == null;
|
||||||
|
message = ''services.invoiceplane.sites."${hostName}".database.passwordFile cannot be specified if services.invoiceplane.sites."${hostName}".database.createLocally is set to true.'';
|
||||||
|
}]
|
||||||
|
) eachSite);
|
||||||
|
|
||||||
|
services.mysql = mkIf (any (v: v.database.createLocally) (attrValues eachSite)) {
|
||||||
|
enable = true;
|
||||||
|
package = mkDefault pkgs.mariadb;
|
||||||
|
ensureDatabases = mapAttrsToList (hostName: cfg: cfg.database.name) eachSite;
|
||||||
|
ensureUsers = mapAttrsToList (hostName: cfg:
|
||||||
|
{ name = cfg.database.user;
|
||||||
|
ensurePermissions = { "${cfg.database.name}.*" = "ALL PRIVILEGES"; };
|
||||||
|
}
|
||||||
|
) eachSite;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.phpfpm = {
|
||||||
|
phpPackage = pkgs.php74;
|
||||||
|
pools = mapAttrs' (hostName: cfg: (
|
||||||
|
nameValuePair "invoiceplane-${hostName}" {
|
||||||
|
inherit user;
|
||||||
|
group = webserver.group;
|
||||||
|
settings = {
|
||||||
|
"listen.owner" = webserver.user;
|
||||||
|
"listen.group" = webserver.group;
|
||||||
|
} // cfg.poolConfig;
|
||||||
|
}
|
||||||
|
)) eachSite;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
systemd.tmpfiles.rules = flatten (mapAttrsToList (hostName: cfg: [
|
||||||
|
"d ${cfg.stateDir} 0750 ${user} ${webserver.group} - -"
|
||||||
|
"f ${cfg.stateDir}/ipconfig.php 0750 ${user} ${webserver.group} - -"
|
||||||
|
"d ${cfg.stateDir}/logs 0750 ${user} ${webserver.group} - -"
|
||||||
|
"d ${cfg.stateDir}/uploads 0750 ${user} ${webserver.group} - -"
|
||||||
|
"d ${cfg.stateDir}/uploads/archive 0750 ${user} ${webserver.group} - -"
|
||||||
|
"d ${cfg.stateDir}/uploads/customer_files 0750 ${user} ${webserver.group} - -"
|
||||||
|
"d ${cfg.stateDir}/uploads/temp 0750 ${user} ${webserver.group} - -"
|
||||||
|
"d ${cfg.stateDir}/uploads/temp/mpdf 0750 ${user} ${webserver.group} - -"
|
||||||
|
"d ${cfg.stateDir}/tmp 0750 ${user} ${webserver.group} - -"
|
||||||
|
]) eachSite);
|
||||||
|
|
||||||
|
systemd.services.invoiceplane-config = {
|
||||||
|
serviceConfig.Type = "oneshot";
|
||||||
|
script = concatStrings (mapAttrsToList (hostName: cfg:
|
||||||
|
''
|
||||||
|
mkdir -p ${cfg.stateDir}/logs \
|
||||||
|
${cfg.stateDir}/uploads
|
||||||
|
if ! grep -q IP_URL "${cfg.stateDir}/ipconfig.php"; then
|
||||||
|
cp "${invoiceplane-config hostName cfg}" "${cfg.stateDir}/ipconfig.php"
|
||||||
|
fi
|
||||||
|
'') eachSite);
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
users.users.${user} = {
|
||||||
|
group = webserver.group;
|
||||||
|
isSystemUser = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
(mkIf (cfg.webserver == "caddy") {
|
||||||
|
services.caddy = {
|
||||||
|
enable = true;
|
||||||
|
virtualHosts = mapAttrs' (hostName: cfg: (
|
||||||
|
nameValuePair "http://${hostName}" {
|
||||||
|
extraConfig = ''
|
||||||
|
root * ${pkg hostName cfg}
|
||||||
|
file_server
|
||||||
|
|
||||||
|
php_fastcgi unix/${config.services.phpfpm.pools."invoiceplane-${hostName}".socket}
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
)) eachSite;
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
@ -215,6 +215,7 @@ in
|
|||||||
initrd-secrets = handleTest ./initrd-secrets.nix {};
|
initrd-secrets = handleTest ./initrd-secrets.nix {};
|
||||||
inspircd = handleTest ./inspircd.nix {};
|
inspircd = handleTest ./inspircd.nix {};
|
||||||
installer = handleTest ./installer.nix {};
|
installer = handleTest ./installer.nix {};
|
||||||
|
invoiceplane = handleTest ./invoiceplane.nix {};
|
||||||
iodine = handleTest ./iodine.nix {};
|
iodine = handleTest ./iodine.nix {};
|
||||||
ipfs = handleTest ./ipfs.nix {};
|
ipfs = handleTest ./ipfs.nix {};
|
||||||
ipv6 = handleTest ./ipv6.nix {};
|
ipv6 = handleTest ./ipv6.nix {};
|
||||||
|
82
nixos/tests/invoiceplane.nix
Normal file
82
nixos/tests/invoiceplane.nix
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import ./make-test-python.nix ({ pkgs, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
name = "invoiceplane";
|
||||||
|
meta = with pkgs.lib.maintainers; {
|
||||||
|
maintainers = [
|
||||||
|
onny
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
nodes = {
|
||||||
|
invoiceplane_caddy = { ... }: {
|
||||||
|
services.invoiceplane.webserver = "caddy";
|
||||||
|
services.invoiceplane.sites = {
|
||||||
|
"site1.local" = {
|
||||||
|
#database.name = "invoiceplane1";
|
||||||
|
database.createLocally = true;
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
"site2.local" = {
|
||||||
|
#database.name = "invoiceplane2";
|
||||||
|
database.createLocally = true;
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = [ 80 ];
|
||||||
|
networking.hosts."127.0.0.1" = [ "site1.local" "site2.local" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = ''
|
||||||
|
start_all()
|
||||||
|
|
||||||
|
invoiceplane_caddy.wait_for_unit("caddy")
|
||||||
|
invoiceplane_caddy.wait_for_open_port(80)
|
||||||
|
invoiceplane_caddy.wait_for_open_port(3306)
|
||||||
|
|
||||||
|
site_names = ["site1.local", "site2.local"]
|
||||||
|
|
||||||
|
for site_name in site_names:
|
||||||
|
machine.wait_for_unit(f"phpfpm-invoiceplane-{site_name}")
|
||||||
|
|
||||||
|
with subtest("Website returns welcome screen"):
|
||||||
|
assert "Please install InvoicePlane" in machine.succeed(f"curl -L {site_name}")
|
||||||
|
|
||||||
|
with subtest("Finish InvoicePlane setup"):
|
||||||
|
machine.succeed(
|
||||||
|
f"curl -sSfL --cookie-jar cjar {site_name}/index.php/setup/language"
|
||||||
|
)
|
||||||
|
csrf_token = machine.succeed(
|
||||||
|
"grep ip_csrf_cookie cjar | cut -f 7 | tr -d '\n'"
|
||||||
|
)
|
||||||
|
machine.succeed(
|
||||||
|
f"curl -sSfL --cookie cjar --cookie-jar cjar -d '_ip_csrf={csrf_token}&ip_lang=english&btn_continue=Continue' {site_name}/index.php/setup/language"
|
||||||
|
)
|
||||||
|
csrf_token = machine.succeed(
|
||||||
|
"grep ip_csrf_cookie cjar | cut -f 7 | tr -d '\n'"
|
||||||
|
)
|
||||||
|
machine.succeed(
|
||||||
|
f"curl -sSfL --cookie cjar --cookie-jar cjar -d '_ip_csrf={csrf_token}&btn_continue=Continue' {site_name}/index.php/setup/prerequisites"
|
||||||
|
)
|
||||||
|
csrf_token = machine.succeed(
|
||||||
|
"grep ip_csrf_cookie cjar | cut -f 7 | tr -d '\n'"
|
||||||
|
)
|
||||||
|
machine.succeed(
|
||||||
|
f"curl -sSfL --cookie cjar --cookie-jar cjar -d '_ip_csrf={csrf_token}&btn_continue=Continue' {site_name}/index.php/setup/configure_database"
|
||||||
|
)
|
||||||
|
csrf_token = machine.succeed(
|
||||||
|
"grep ip_csrf_cookie cjar | cut -f 7 | tr -d '\n'"
|
||||||
|
)
|
||||||
|
machine.succeed(
|
||||||
|
f"curl -sSfl --cookie cjar --cookie-jar cjar -d '_ip_csrf={csrf_token}&btn_continue=Continue' {site_name}/index.php/setup/install_tables"
|
||||||
|
)
|
||||||
|
csrf_token = machine.succeed(
|
||||||
|
"grep ip_csrf_cookie cjar | cut -f 7 | tr -d '\n'"
|
||||||
|
)
|
||||||
|
machine.succeed(
|
||||||
|
f"curl -sSfl --cookie cjar --cookie-jar cjar -d '_ip_csrf={csrf_token}&btn_continue=Continue' {site_name}/index.php/setup/upgrade_tables"
|
||||||
|
)
|
||||||
|
'';
|
||||||
|
})
|
32
pkgs/servers/web-apps/invoiceplane/default.nix
Normal file
32
pkgs/servers/web-apps/invoiceplane/default.nix
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{ lib, stdenv, fetchurl, writeText, unzip, nixosTests }:
|
||||||
|
|
||||||
|
stdenv.mkDerivation rec {
|
||||||
|
pname = "invoiceplane";
|
||||||
|
version = "1.5.11";
|
||||||
|
|
||||||
|
src = fetchurl {
|
||||||
|
url = "https://github.com/InvoicePlane/InvoicePlane/releases/download/v${version}/v${version}.zip";
|
||||||
|
sha256 = "137g0xps4kb3j7f5gz84ql18iggbya6d9dnrfp05g2qcbbp8kqad";
|
||||||
|
};
|
||||||
|
|
||||||
|
nativeBuildInputs = [ unzip ];
|
||||||
|
|
||||||
|
sourceRoot = ".";
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p $out/
|
||||||
|
cp -r . $out/
|
||||||
|
'';
|
||||||
|
|
||||||
|
passthru.tests = {
|
||||||
|
inherit (nixosTests) invoiceplane;
|
||||||
|
};
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Self-hosted open source application for managing your invoices, clients and payments";
|
||||||
|
license = licenses.mit;
|
||||||
|
homepage = "https://www.invoiceplane.com";
|
||||||
|
platforms = platforms.all;
|
||||||
|
maintainers = with maintainers; [ onny ];
|
||||||
|
};
|
||||||
|
}
|
@ -3240,6 +3240,8 @@ with pkgs;
|
|||||||
|
|
||||||
interlock = callPackage ../servers/interlock {};
|
interlock = callPackage ../servers/interlock {};
|
||||||
|
|
||||||
|
invoiceplane = callPackage ../servers/web-apps/invoiceplane { };
|
||||||
|
|
||||||
iotools = callPackage ../tools/misc/iotools { };
|
iotools = callPackage ../tools/misc/iotools { };
|
||||||
|
|
||||||
jellyfin = callPackage ../servers/jellyfin { };
|
jellyfin = callPackage ../servers/jellyfin { };
|
||||||
|
Loading…
Reference in New Issue
Block a user