nixify and fixify

This commit is contained in:
Felix Albrigtsen 2023-08-27 01:51:57 +02:00
parent 29c6f5c4ef
commit 6f125fdb1f
9 changed files with 209 additions and 12 deletions

6
README.md Normal file
View File

@ -0,0 +1,6 @@
# PVV Calendar -> Matrix bot
This bot scrapes https://pvv.ntnu.no/hendelser/, fetches todays events and sends announcement messages in matrix.
Packaged as a nix flake, see ./module.nix for options.

26
flake.lock Normal file
View File

@ -0,0 +1,26 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1692986144,
"narHash": "sha256-M4VFpy7Av9j+33HF5nIGm0k2+DXXW4qSSKdidIKg5jY=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "74e5bdc5478ebbe7ba5849f0d765f92757bb9dbf",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-23.05",
"type": "indirect"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

57
flake.nix Normal file
View File

@ -0,0 +1,57 @@
{
inputs = {
nixpkgs.url = "nixpkgs/nixos-23.05";
};
outputs = { self, nixpkgs }: let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
in {
packages.${system} = {
default = self.packages.${system}.pvv-calendar-bot;
pvv-calendar-bot = pkgs.python3Packages.buildPythonPackage {
name = "pvv-calendar-bot";
src = ./.;
format = "pyproject";
nativeBuildInputs = [
pkgs.python3Packages.setuptools
];
propagatedBuildInputs = with pkgs.python3Packages; [
beautifulsoup4
markdown2
matrix-nio
requests
];
};
};
nixosModules.default = ./module.nix;
overlays.${system}.default = prevPackages: finalPackages: {
inherit (self.packages.${system}) pvv-calendar-bot;
};
nixosConfigurations."test" = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
self.nixosModules.default
{ nixpkgs.overlays = [ self.overlays."x86_64-linux".default ]; }
{
boot.isContainer = true;
services.pvv-calendar-bot = {
enable = true;
settings.matrix = {
channel = "testchannel";
user = "testuser";
homeserver = "pvv.ntnu.no";
};
settings.secretsFile = pkgs.writeText "calendarSecrets" "snakeoil";
};
}
];
};
};
}

75
module.nix Normal file
View File

@ -0,0 +1,75 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.pvv-calendar-bot;
inherit (lib) mkDefault mkEnableOption mkPackageOption mkIf mkOption types mdDoc;
in {
options.services.pvv-calendar-bot = {
enable = mkEnableOption (lib.mdDoc "Enable pvv-calendar-bot to post to matrix");
package = mkPackageOption pkgs "pvv-calendar-bot" {};
settings = {
onCalendar = mkOption {
type = types.str;
default = "9 0 * * *";
description = mdDoc "OnCalendar string for the systemd service(e.g. crontab format)";
};
matrix = {
user = mkOption {
type = types.str;
description = mdDoc "Matrix username to authenticate with";
example = "@bot_calendar:pvv.ntnu.no";
};
channel = mkOption {
type = types.str;
description = mdDoc "Room ID of the channel to post announcements in";
example = "!abcdef:matrix.org";
};
homeserver = mkOption {
type = types.str;
description = mdDoc "Matrix homeserver URL to connect to";
example = "https://matrix.org";
};
};
secretsFile = mkOption {
type = types.path;
description = mdDoc "Path to secrets file that defines MATRIX_ACCESS_TOKEN";
};
};
};
config = mkIf cfg.enable {
systemd.timers."pvv-calendar-bot" = {
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = cfg.settings.onCalendar;
Unit = "pvv-calendar-bot";
};
};
systemd.services."pvv-calendar-bot" = {
preStart = let
envFile = pkgs.writeText "pvv-calendar-bot-env" ''
MATRIX_URL=${cfg.settings.matrix.homeserver}
MATRIX_USER=${cfg.settings.matrix.user}
ANNOUNCEMENT_CHANNEL=${cfg.settings.matrix.channel}
MATRIX_TOKEN=@MATRIX_ACCESS_TOKEN@
'';
in ''
${pkgs.replace-secret}/bin/replace-secret '@MATRIX_ACCESS_TOKEN@' ${cfg.settings.secretsFile} /run/pvv-calendar-bot/env
'';
serviceConfig = {
ExecStart = "${cfg.package}/bin/pvv-calendar-bot";
RuntimeDirectory = "pvv-calendar-bot";
DynamicUser = true;
EnvironmentFile = [ "-/run/pvv-calendar-bot/env" ];
};
};
};
}

28
pyproject.toml Normal file
View File

@ -0,0 +1,28 @@
[build-system]
requires = ["setuptools", "setuptools-scm"]
build-backend = "setuptools.build_meta"
[project]
name = "pvv-calendar-bot"
authors = [
{name = "Felix Albrigtsen", email = "felix@albrigtsen.it"},
{name = "Fredrik Robertsen", email = "fredrikrobertsen7@gmail.com"}
]
version = "1.0.0"
description = "PVV Calendar -> Matrix bot"
requires-python = ">=3.10"
keywords = []
license = {text = "MIT"}
dependencies = [
"beautifulsoup4",
"markdown2",
"matrix-nio",
"requests"
]
[tool.setuptools.packages.find]
where = ["src"]
include = ["*"]
[project.scripts]
pvv-calendar-bot = "pvv_calendar_bot:main"

View File

@ -0,0 +1 @@
from pvv_calendar_bot.main import main

View File

@ -1,4 +1,7 @@
from event import Event #! /usr/bin/env python
from .event import Event
from .scraping import get_soup, process_soup, get_events_today
import os import os
from nio import AsyncClient from nio import AsyncClient
@ -7,8 +10,6 @@ from markdown2 import Markdown
import asyncio import asyncio
import datetime import datetime
from scraping import get_soup, process_soup, get_events_today
MATRIX_URL=os.environ["MATRIX_URL"] MATRIX_URL=os.environ["MATRIX_URL"]
MATRIX_USER=os.environ["MATRIX_USER"] MATRIX_USER=os.environ["MATRIX_USER"]
MATRIX_TOKEN=os.environ["MATRIX_TOKEN"] MATRIX_TOKEN=os.environ["MATRIX_TOKEN"]
@ -44,18 +45,21 @@ async def sendMatrixAnnouncement(event: Event, channel: str = ANNOUNCEMENT_CHANN
} }
) )
async def sendCalendarEvents() -> None:
async def main() -> None:
global client global client
client = AsyncClient(MATRIX_URL, MATRIX_USER) client = AsyncClient(MATRIX_URL, MATRIX_USER)
client.access_token = MATRIX_TOKEN client.access_token = MATRIX_TOKEN
s = get_soup() scrapeData = get_soup()
es = get_events_today(process_soup(s)) eventsToday = get_events_today(process_soup(scrapeData))
for e in es: for event in eventsToday:
await sendMatrixAnnouncement(e, ANNOUNCEMENT_CHANNEL, False) await sendMatrixAnnouncement(event, ANNOUNCEMENT_CHANNEL, False)
await client.close() await client.close()
asyncio.run(main()) def main():
asyncio.run(sendCalendarEvents())
if __name__ == "__main__":
main()

View File

@ -1,11 +1,11 @@
from .event import Event
from typing import List from typing import List
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
import requests import requests
from operator import add from operator import add
from functools import reduce from functools import reduce
import datetime import datetime
from event import Event
def get_soup() -> BeautifulSoup: def get_soup() -> BeautifulSoup:
r = requests.get("http://www.pvv.ntnu.no/hendelser/") r = requests.get("http://www.pvv.ntnu.no/hendelser/")