nixos/timekpr: init at 0.5.8 (#419487)

authored by Matt Sturgeon and committed by GitHub 04698ee1 6f1c0bf5

+251
+13
nixos/doc/manual/configuration/user-mgmt.chapter.md
··· 152 152 Userborn implements immutable users by re-mounting the password files 153 153 read-only. This means that unlike when using the Perl script, trying to add a 154 154 new user (e.g. via `useradd`) will fail right away. 155 + 156 + ## Restrict usage time {#sec-restrict-usage-time} 157 + 158 + [Timekpr-nExT](https://mjasnik.gitlab.io/timekpr-next/) is a screen time managing application that helps optimizing time spent at computer for your subordinates, children or even for yourself. 159 + 160 + You can enable it via: 161 + 162 + ```nix 163 + { services.timekpr.enable = true; } 164 + ``` 165 + 166 + This will install the `timekpr` package and start the `timekpr` service. 167 + You can then use the `timekpra` application to configure time limits for users.
+3
nixos/doc/manual/redirects.json
··· 338 338 "sec-userborn": [ 339 339 "index.html#sec-userborn" 340 340 ], 341 + "sec-restrict-usage-time": [ 342 + "index.html#sec-restrict-usage-time" 343 + ], 341 344 "ch-file-systems": [ 342 345 "index.html#ch-file-systems" 343 346 ],
+2
nixos/doc/manual/release-notes/rl-2511.section.md
··· 100 100 101 101 - [mautrix-discord](https://github.com/mautrix/discord), a Matrix-Discord puppeting/relay bridge. Available as [services.mautrix-discord](#opt-services.mautrix-discord.enable). 102 102 103 + - [Timekpr-nExT](https://mjasnik.gitlab.io/timekpr-next/), a time managing application that helps optimizing time spent at computer for your subordinates, children or even for yourself. Available as [](#opt-services.timekpr.enable). 104 + 103 105 - [SuiteNumérique Meet](https://github.com/suitenumerique/meet) is an open source alternative to Google Meet and Zoom powered by LiveKit: HD video calls, screen sharing, and chat features. Built with Django and React. Available as [services.lasuite-meet](#opt-services.lasuite-meet.enable). 104 106 105 107 - [lemurs](https://github.com/coastalwhite/lemurs), a customizable TUI display/login manager. Available at [services.displayManager.lemurs](#opt-services.displayManager.lemurs.enable).
+1
nixos/modules/module-list.nix
··· 1477 1477 ./services/security/sslmate-agent.nix 1478 1478 ./services/security/step-ca.nix 1479 1479 ./services/security/tang.nix 1480 + ./services/security/timekpr.nix 1480 1481 ./services/security/tor.nix 1481 1482 ./services/security/torify.nix 1482 1483 ./services/security/torsocks.nix
+65
nixos/modules/services/security/timekpr.nix
··· 1 + { 2 + pkgs, 3 + lib, 4 + config, 5 + ... 6 + }: 7 + let 8 + cfg = config.services.timekpr; 9 + targetBaseDir = "/var/lib/timekpr"; 10 + daemonUser = "root"; 11 + daemonGroup = "root"; 12 + in 13 + { 14 + options = { 15 + services.timekpr = { 16 + package = lib.mkPackageOption pkgs "timekpr" { }; 17 + enable = lib.mkEnableOption "Timekpr-nExT, a screen time managing application that helps optimizing time spent at computer for your subordinates, children or even for yourself"; 18 + adminUsers = lib.mkOption { 19 + type = lib.types.listOf lib.types.str; 20 + default = [ ]; 21 + example = [ 22 + "alice" 23 + "bob" 24 + ]; 25 + description = '' 26 + All listed users will become part of the `timekpr` group so they can manage timekpr settings without requiring sudo. 27 + ''; 28 + }; 29 + }; 30 + }; 31 + 32 + config = lib.mkIf cfg.enable { 33 + users.groups.timekpr = { 34 + gid = 2000; 35 + members = cfg.adminUsers; 36 + }; 37 + 38 + environment.systemPackages = [ 39 + # Add timekpr to system packages so that polkit can find it 40 + cfg.package 41 + ]; 42 + services.dbus.enable = true; 43 + services.dbus.packages = [ 44 + cfg.package 45 + ]; 46 + environment.etc."timekpr" = { 47 + source = "${cfg.package}/etc/timekpr"; 48 + }; 49 + systemd.packages = [ 50 + cfg.package 51 + ]; 52 + systemd.services.timekpr = { 53 + enable = true; 54 + wantedBy = [ "multi-user.target" ]; 55 + }; 56 + security.polkit.enable = true; 57 + systemd.tmpfiles.rules = [ 58 + "d ${targetBaseDir} 0755 ${daemonUser} ${daemonGroup} -" 59 + "d ${targetBaseDir}/config 0755 ${daemonUser} ${daemonGroup} -" 60 + "d ${targetBaseDir}/work 0755 ${daemonUser} ${daemonGroup} -" 61 + ]; 62 + }; 63 + 64 + meta.maintainers = [ lib.maintainers.atry ]; 65 + }
+17
nixos/tests/timekpr.nix
··· 1 + { pkgs, lib, ... }: 2 + { 3 + name = "timekpr"; 4 + meta.maintainers = [ lib.maintainers.atry ]; 5 + 6 + nodes.machine = 7 + { pkgs, lib, ... }: 8 + { 9 + services.timekpr.enable = true; 10 + }; 11 + 12 + testScript = '' 13 + start_all() 14 + machine.wait_for_file("/etc/timekpr/timekpr.conf") 15 + machine.wait_for_unit("timekpr.service") 16 + ''; 17 + }
+150
pkgs/by-name/ti/timekpr/package.nix
··· 1 + { 2 + fetchgit, 3 + gitUpdater, 4 + glib, 5 + gobject-introspection, 6 + gtk3, 7 + lib, 8 + python3Packages, 9 + sound-theme-freedesktop, 10 + stdenv, 11 + wrapGAppsHook4, 12 + }: 13 + python3Packages.buildPythonApplication rec { 14 + pname = "timekpr"; 15 + version = "0.5.8"; 16 + 17 + src = fetchgit { 18 + url = "https://git.launchpad.net/timekpr-next"; 19 + tag = "v${version}"; 20 + hash = "sha256-Y0jAKl553HjoP59wJnKBKq4Ogko1cs8uazW2dy7AlBo="; 21 + }; 22 + 23 + buildInputs = [ 24 + glib 25 + gtk3 26 + ]; 27 + 28 + nativeBuildInputs = [ 29 + gobject-introspection 30 + wrapGAppsHook4 31 + ]; 32 + 33 + pyproject = true; 34 + 35 + build-system = with python3Packages; [ 36 + setuptools 37 + ]; 38 + 39 + dependencies = with python3Packages; [ 40 + dbus-python 41 + pygobject3 42 + psutil 43 + ]; 44 + 45 + # Generate setup.py because the upstream repository does not include it 46 + SETUP_PY = '' 47 + from setuptools import setup, find_namespace_packages 48 + 49 + package_dir={"timekpr": "."} 50 + setup( 51 + name="timekpr-next", 52 + version="${version}", 53 + package_dir=package_dir, 54 + packages=[ 55 + f"{package_prefix}.{package_suffix}" 56 + for package_prefix, where in package_dir.items() 57 + for package_suffix in find_namespace_packages(where=where) 58 + ], 59 + install_requires=[ 60 + ${lib.concatMapStringsSep ", " (dependency: "'${dependency.pname}'") dependencies} 61 + ], 62 + ) 63 + ''; 64 + 65 + postPatch = '' 66 + shopt -s globstar extglob nullglob 67 + 68 + substituteInPlace bin/* **/*.py resource/server/systemd/timekpr.service \ 69 + --replace-quiet /usr/lib/python3/dist-packages "$out"/${lib.escapeShellArg python3Packages.python.sitePackages} 70 + 71 + substituteInPlace **/*.desktop **/*.policy **/*.service \ 72 + --replace-fail /usr/bin/timekpr "$out"/bin/timekpr 73 + 74 + substituteInPlace common/constants/constants.py \ 75 + --replace-fail /usr/share/sounds/freedesktop ${lib.escapeShellArg sound-theme-freedesktop}/share/sounds/freedesktop \ 76 + --replace-fail /usr/share/timekpr "$out"/share/timekpr \ 77 + --replace-fail /usr/share/locale "$out"/share/locale 78 + 79 + substituteInPlace resource/server/timekpr.conf \ 80 + --replace-fail /usr/share/timekpr "$out"/share/timekpr \ 81 + 82 + # The original file name `timekpra` is renamed to `..timekpra-wrapped-wrapped` because `makeCWrapper` was used multiple times. 83 + substituteInPlace client/admin/adminprocessor.py \ 84 + --replace-fail '"/timekpra" in ' '"/..timekpra-wrapped-wrapped" in ' 85 + 86 + printf %s "$SETUP_PY" > setup.py 87 + ''; 88 + 89 + # We need to manually inject $PYTHONPATH here, because `buildPythonApplication` does not recognize timekpr's executables as Python scripts, and therefore it does not automatically inject $PYTHONPATH into them. 90 + postFixup = '' 91 + for executable in $out/bin/* 92 + do 93 + wrapProgram "$executable" --prefix PYTHONPATH : "$PYTHONPATH" 94 + done 95 + ''; 96 + 97 + preInstall = '' 98 + while IFS= read -r line 99 + do 100 + # Trim leading/trailing whitespace 101 + line=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') 102 + 103 + # Skip empty lines and comments 104 + if [[ -z "$line" || "$line" =~ ^# ]]; then 105 + continue 106 + fi 107 + 108 + # Separate source and destination 109 + # This assumes the destination is the last field and source path doesn't contain problematic spaces 110 + # More robust parsing might be needed if source paths have spaces. 111 + source_path=$(echo "$line" | awk '{ $NF=""; print $0 }' | sed 's/[[:space:]]*$//') 112 + dest_path=$(echo "$line" | awk '{ print $NF }') 113 + 114 + # Check destination path prefix and map to $out/* 115 + case "$dest_path" in 116 + usr/share/*) 117 + # Remove "usr/" prefix and prepend "$out/" 118 + install -D --mode=444 "$source_path" --target-directory="$out/''${dest_path#usr/}" 119 + ;; 120 + usr/bin/*) 121 + # Remove "usr/" prefix and prepend "$out/" 122 + install -D --mode=555 "$source_path" --target-directory="$out/''${dest_path#usr/}" 123 + ;; 124 + etc/*|lib/*|var/*) 125 + # Prepend "$out/" 126 + install -D --mode=444 "$source_path" --target-directory="$out/$dest_path" 127 + ;; 128 + usr/lib/python3/dist-packages/*) 129 + # Skip this line if the destination is a Python module 130 + # because it will be handled by the Python build process 131 + continue 132 + ;; 133 + *) 134 + echo "Error: Unknown destination prefix: '$dest_path'" >&2 135 + exit 1 136 + ;; 137 + esac 138 + done < debian/install 139 + ''; 140 + 141 + passthru.updateScript = gitUpdater { rev-prefix = "v"; }; 142 + 143 + meta = { 144 + description = "Manages and restricts user screen time by enforcing time limits"; 145 + homepage = "https://mjasnik.gitlab.io/timekpr-next/"; 146 + license = lib.licenses.gpl3; 147 + maintainers = [ lib.maintainers.atry ]; 148 + platforms = lib.platforms.linux; 149 + }; 150 + }