nixos-config/config/host-config/nutboy3/forum_selby_ca.nix

195 lines
6.5 KiB
Nix

{ config, lib, pkgs, ... }:
with lib;
let
site = "forum.test.selby.ca";
hostname = config.instance.hostname;
host-secrets = config.fudo.secrets.host-secrets.${hostname};
discourse-user = config.systemd.services.discourse.serviceConfig.User;
database-name = "forum_selby_ca";
database-user = "forum_selby_ca";
state-directory = "/state/selby/forum";
password-injector-sql = csv-file: pkgs.stdenv.mkDerivation {
name = "${site}-password-injector-sql";
phases = [ "installPhase" ];
buildInputs = [ pkgs.ruby ];
installPhase = ''
${password-convert-script csv-file}
'';
};
password-convert-script = csv-file: pkgs.writeScript "vanilla-forum-password-convert.rb" ''
#!${pkgs.ruby}/bin/ruby
require 'csv'
data = CSV::readlines("${csv-file}")
File::open(ENV["out"], "w") { |sql|
data.each { |row|
sql.puts("UPDATE users SET import_pass='#{row[2]}' FROM user_emails WHERE users.id = user_emails.user_id AND user_emails.email = '#{row[1]}';")
}
}
'';
in {
config = {
services.discourse = {
enable = true;
hostname = site;
enableACME = true;
plugins = with config.services.discourse.package.plugins; [
discourse-migratepassword
];
admin = {
username = "admin";
fullName = "Admin";
email = "admin@selby.ca";
passwordFile = host-secrets.selby-discourse-admin.target-file;
};
database = {
name = database-name;
host = "localhost";
username = database-user;
passwordFile =
host-secrets.selby-discourse-database-passwd.target-file;
};
};
fudo = {
secrets.host-secrets.${hostname} = let
selby-discourse-db-password =
pkgs.lib.passwd.stablerandom-passwd-file
"selby-discourse-database-password"
"selby-discourse-database-password-${config.instance.build-seed}";
files = config.fudo.secrets.files;
in {
selby-discourse-database-passwd = {
source-file = selby-discourse-db-password;
target-file = "/run/selby/forum/database.passwd";
user = discourse-user;
};
postgresql-selby-discourse-password = {
source-file = selby-discourse-db-password;
target-file = "/run/postgres/selby-discourse.passwd";
user = config.services.postgresql.superUser;
};
selby-discourse-admin = {
source-file = pkgs.lib.passwd.stablerandom-passwd-file
"selby-discourse-admin"
"selby-discourse-admin-${config.instance.build-seed}";
target-file = "/run/selby/forum/admin.passwd";
user = discourse-user;
};
selby-forum-data = {
source-file = files.blobs."selby-forum-2021-12-14.clean";
target-file = "/run/selby/forum/forum-data.txt";
user = discourse-user;
};
selby-forum-passwords-sql = {
source-file = "${password-injector-sql files.blobs."forum_selby_ca-passwd.csv"}";
target-file = "/run/postgres/selby/forum-passwords.sql";
user = config.services.postgresql.superUser;
};
};
postgresql = {
databases.${database-name}.users = [ "niten" ];
users.${database-user} = {
password-file = host-secrets.postgresql-selby-discourse-password.target-file;
databases.${database-name} = {
access = "CONNECT,CREATE";
entity-access = {
"ALL TABLES IN SCHEMA public" = "SELECT,INSERT,UPDATE,DELETE";
"ALL SEQUENCES IN SCHEMA public" = "SELECT,UPDATE";
};
};
};
};
};
security.acme.certs.${site}.email = "admin@selby.ca";
systemd = {
tmpfiles.rules = [
"d ${state-directory} 750 ${discourse-user} - - -"
"L /var/lib/discourse - - - - ${state-directory}"
];
services = {
discourse = {
bindsTo = [ "postgresql.service" ];
after = [
config.fudo.postgresql.systemd-target
"postgresql.service"
];
};
discourse-prepare = {
description = "Do discourse's superuser-requiring database work for it.";
wantedBy = [ "discourse.service" ];
before = [ "discourse.service" ];
requires = [ config.fudo.postgresql.systemd-target ];
after = [ config.fudo.postgresql.systemd-target ];
path = with pkgs; [ postgresql ];
serviceConfig = {
User = config.services.postgresql.superUser;
ExecStart = pkgs.writeShellScript "discourse-prepare.sh" ''
psql -d ${database-name} -c "CREATE EXTENSION IF NOT EXISTS hstore;"
psql -d ${database-name} -c "CREATE EXTENSION IF NOT EXISTS pg_trgm;"
'';
};
};
discourse-import-vanilla = let
env-without-path =
filterAttrs (attr: _: attr != "PATH")
config.systemd.services.discourse.environment;
selby-forum-data = host-secrets.selby-forum-data.target-file;
in {
description = "One-off job to import Vanilla forum.";
path = config.systemd.services.discourse.path;
environment = env-without-path;
serviceConfig = {
User = config.systemd.services.discourse.serviceConfig.User;
Group = config.systemd.services.discourse.serviceConfig.Group;
Type = "oneshot";
WorkingDirectory = config.systemd.services.discourse.serviceConfig.WorkingDirectory;
ExecStart = pkgs.writeShellScript "import-vanilla-forum.sh" ''
ruby script/import_scripts/vanilla.rb ${selby-forum-data}
'';
};
};
discourse-add-password-hash = let
alter-user-script = pkgs.writeText "create-password-column.sql" ''
ALTER TABLE users ADD COLUMN IF NOT EXISTS import_pass VARCHAR (64);
'';
in {
description = "One-off job to add user password hashes from Vanilla forum.";
path = with pkgs; [ postgresql ];
wantedBy = [ "discourse.service" ];
serviceConfig = {
User = config.services.postgresql.superUser;
Type = "oneshot";
ExecStart = pkgs.writeShellScript "import-vanilla-passwords.sh" ''
psql -d ${database-name} -f ${alter-user-script}
psql -d ${database-name} -f ${host-secrets.selby-forum-passwords-sql.target-file}
'';
};
};
};
};
};
}