add resources flow and secure config
Document resources, extend list actions, and wire Nix settings/token handling to support new resource saves and UI tweaks.
This commit is contained in:
parent
47a712b4ae
commit
6f3c5a6894
4 changed files with 916 additions and 85 deletions
6
AGENTS.md
Normal file
6
AGENTS.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# Repository Guidelines
|
||||
|
||||
## NixOS Module Notes
|
||||
|
||||
- `services.readlater-bot.settings` is rendered to TOML without the token; the token must come from `services.readlater-bot.tokenFile` and is combined at runtime in `/run/readlater-bot/config.toml` to keep secrets out of the Nix store.
|
||||
- If you override `services.readlater-bot.user`/`group`, ensure the group exists; otherwise systemd fails at step GROUP. Defaults only auto-create the `readlater-bot` user/group when you keep the defaults.
|
||||
11
SPEC.md
11
SPEC.md
|
|
@ -17,6 +17,16 @@ Read Later behavior
|
|||
- New items are prepended (inserted immediately after any preamble).
|
||||
- Deduping: exact full-block match (entire entry text). If identical block exists, skip add and inform user.
|
||||
- Add acknowledgment: send Saved. and auto-delete after 5s.
|
||||
- After single-item or multi-item saves, delete the user's original message.
|
||||
|
||||
Resources behavior
|
||||
- /add <text> prompts for Reading list vs Resource.
|
||||
- Add Resource is available in the selected item view; it does not change the current view.
|
||||
- Resource adds prompt for a target .md file in resources_path (or a new filename).
|
||||
- New resource entry is prepended to the chosen file as: `- (Auto-Resource): <message contents>`.
|
||||
- Preserve additional lines after the first.
|
||||
- Deduping: exact full-block match (entire entry text). If identical block exists, skip add and inform user.
|
||||
- Resource acknowledgment: send Added to resources. and auto-delete after 5s.
|
||||
|
||||
Finished Reading behavior
|
||||
- Mark Finished moves an entry: remove from Read Later, prepend to Finished (no separators).
|
||||
|
|
@ -63,6 +73,7 @@ Config
|
|||
- user_id (Telegram user ID)
|
||||
- read_later_path (absolute path)
|
||||
- finished_path (absolute path)
|
||||
- resources_path (absolute path to resources directory)
|
||||
- data_dir (absolute path)
|
||||
- retry_interval_seconds (default 30, configurable)
|
||||
|
||||
|
|
|
|||
75
flake.nix
75
flake.nix
|
|
@ -38,6 +38,16 @@
|
|||
}:
|
||||
let
|
||||
cfg = config.services.readlater-bot;
|
||||
tomlFormat = pkgs.formats.toml { };
|
||||
defaultSettings = {
|
||||
data_dir = "/var/lib/readlater-bot";
|
||||
retry_interval_seconds = 30;
|
||||
};
|
||||
mergedSettings = defaultSettings // cfg.settings;
|
||||
settingsFile = tomlFormat.generate "readlater-bot.toml" mergedSettings;
|
||||
runtimeConfig = "/run/readlater-bot/config.toml";
|
||||
useRuntimeConfig = cfg.configFile == null;
|
||||
configPath = if useRuntimeConfig then runtimeConfig else cfg.configFile;
|
||||
in
|
||||
{
|
||||
options.services.readlater-bot = {
|
||||
|
|
@ -47,22 +57,81 @@
|
|||
default = self.packages.${pkgs.system}.default;
|
||||
description = "Package providing the bot binary.";
|
||||
};
|
||||
settings = lib.mkOption {
|
||||
type = tomlFormat.type;
|
||||
default = { };
|
||||
description = "TOML settings without the token.";
|
||||
};
|
||||
tokenFile = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
description = "Path to a file containing the Telegram bot token.";
|
||||
};
|
||||
configFile = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
description = "Path to TOML config file.";
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
description = "Path to a TOML config file (bypasses settings/tokenFile).";
|
||||
};
|
||||
user = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "readlater-bot";
|
||||
description = "User account for the bot service.";
|
||||
};
|
||||
group = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "readlater-bot";
|
||||
description = "Group for the bot service.";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.configFile != null || cfg.tokenFile != null;
|
||||
message = "services.readlater-bot: set tokenFile with settings, or provide configFile.";
|
||||
}
|
||||
{
|
||||
assertion = !(cfg.settings ? token);
|
||||
message = "services.readlater-bot: do not set settings.token; use tokenFile.";
|
||||
}
|
||||
{
|
||||
assertion = cfg.configFile == null || (cfg.settings == { } && cfg.tokenFile == null);
|
||||
message = "services.readlater-bot: when configFile is set, do not set settings or tokenFile.";
|
||||
}
|
||||
];
|
||||
|
||||
users.users = lib.mkIf (cfg.user == "readlater-bot") {
|
||||
readlater-bot = {
|
||||
isSystemUser = true;
|
||||
group = cfg.group;
|
||||
};
|
||||
};
|
||||
users.groups = lib.mkIf (cfg.group == "readlater-bot") {
|
||||
readlater-bot = { };
|
||||
};
|
||||
|
||||
systemd.services.readlater-bot = {
|
||||
description = "Read Later Telegram bot";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
preStart = lib.optionalString useRuntimeConfig ''
|
||||
umask 0077
|
||||
{
|
||||
printf 'token = "%s"\n' "$(cat ${cfg.tokenFile})"
|
||||
cat ${settingsFile}
|
||||
} > ${runtimeConfig}
|
||||
'';
|
||||
serviceConfig = {
|
||||
ExecStart = "${cfg.package}/bin/readlater-bot --config ${cfg.configFile}";
|
||||
ExecStart = "${cfg.package}/bin/readlater-bot --config ${configPath}";
|
||||
Restart = "on-failure";
|
||||
RestartSec = 5;
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
RuntimeDirectory = "readlater-bot";
|
||||
RuntimeDirectoryMode = "0700";
|
||||
StateDirectory = "readlater-bot";
|
||||
StateDirectoryMode = "0700";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
909
src/main.rs
909
src/main.rs
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue