diff --git a/configuration/default.mjs b/configuration/default.mjs index e69de29..358b482 100644 --- a/configuration/default.mjs +++ b/configuration/default.mjs @@ -0,0 +1,17 @@ +import path from "node:path"; + +export default { + hostname: "localhost", + dataDirectory: path.join(process.cwd(), "data"), + email: { + options: { streamTransport: true, buffer: true }, + defaults: { + from: { + name: "Courselore", + address: "feedback@courselore.org", + }, + }, + }, + administratorEmail: "feedback@courselore.org", + environment: "other", +}; diff --git a/configuration/development.mjs b/configuration/development.mjs new file mode 100644 index 0000000..6de9081 --- /dev/null +++ b/configuration/development.mjs @@ -0,0 +1,9 @@ +import url from "node:url"; + +export default { + hostname: process.env.TUNNEL ?? process.env.HOSTNAME ?? "localhost", + dataDirectory: url.fileURLToPath(new URL("../data/", import.meta.url)), + administratorEmail: "kill-the-newsletter@leafac.com", + environment: "development", + tunnel: typeof process.env.TUNNEL === "string", +}; diff --git a/configuration/example.mjs b/configuration/example.mjs new file mode 100644 index 0000000..0a5e39e --- /dev/null +++ b/configuration/example.mjs @@ -0,0 +1,47 @@ +// COURSELORE CONFIGURATION + +import url from "node:url"; + +export default { + // The main hostname through which people may access Courselore. + hostname: "YOUR-DOMAIN.EDU", + + // The path to the folder in which Courselore stores data: + // the database and the files uploaded by users (for example, user avatars and attachments in messages). + // With the line below this is a folder called ‘data/’ relative to this configuration file. + // In most cases this is appropriate, but you may want to change it to an absolute path, for example, ‘/home/courselore/data/’. + dataDirectory: url.fileURLToPath(new URL("./data/", import.meta.url)), + + // Configuration for the email server that delivers email on Courselore’s behalf. + // Use the format of arguments accepted by Nodemailer’s ‘.createTransport()’. See https://nodemailer.com/smtp/. + email: { + options: { + host: "SMTP.YOUR-DOMAIN.EDU", + auth: { + user: "SMTP USERNAME", + pass: "SMTP PASSWORD", + }, + }, + defaults: { + from: { + name: "Courselore", + address: "FROM@YOUR-DOMAIN.EDU", + }, + }, + }, + + // This email address serves two purposes: + // 1. If something goes wrong in Courselore, we direct users to report the issue to this email. + // 2. We provide this email to the certificate authority providing a TLS certificate (necessary for httpS to work). + // In case something goes wrong with the certificate, they’ll contact you at this address. + administratorEmail: "ADMINISTRATOR@YOUR-DOMAIN.EDU", + + // [OPTIONAL] Other hostnames you’d like to redirect to this Courselore installation. + // alternativeHostnames: ["WWW.YOUR-DOMAIN.EDU", "..."], + + // [OPTIONAL, BUT RECOMMENDED] See https://hstspreload.org/. + // hstsPreload: true, + + // [OPTIONAL] Extra Caddy configuration to add to Courselore’s Caddy configuration. See https://caddyserver.com. + // caddy: ``, +}; diff --git a/configuration/kill-the-newsletter.com.mjs b/configuration/kill-the-newsletter.com.mjs new file mode 100644 index 0000000..4bf0af2 --- /dev/null +++ b/configuration/kill-the-newsletter.com.mjs @@ -0,0 +1,50 @@ +import url from "node:url"; +import fs from "node:fs/promises"; + +const secrets = JSON.parse( + await fs.readFile(new URL("./secrets.json", import.meta.url), "utf8") +); + +export default { + hostname: "courselore.org", + dataDirectory: url.fileURLToPath(new URL("./data/", import.meta.url)), + email: { + options: { + host: "email-smtp.us-east-1.amazonaws.com", + auth: { + user: secrets.smtp.username, + pass: secrets.smtp.password, + }, + }, + defaults: { + from: { + name: "Courselore", + address: "administrator@courselore.org", + }, + }, + }, + administratorEmail: "administrator@courselore.org", + alternativeHostnames: [ + "www.courselore.org", + "courselore.com", + "www.courselore.com", + ], + hstsPreload: true, + caddy: ` + http://meta.courselore.org, http://meta.courselore.com { + import common + redir https://{host}{uri} 308 + handle_errors { + import common + } + } + + https://meta.courselore.org, https://meta.courselore.com { + import common + redir https://courselore.org/courses/8537410611/invitations/3667859788?{query} 307 + handle_errors { + import common + } + } + `, +}; diff --git a/configuration/kill-the-newsletter.service b/configuration/kill-the-newsletter.service new file mode 100644 index 0000000..a31aed8 --- /dev/null +++ b/configuration/kill-the-newsletter.service @@ -0,0 +1,11 @@ +[Unit] +Description=Kill the Newsletter! +After=network.target + +[Service] +ExecStart=/root/kill-the-newsletter/kill-the-newsletter /root/kill-the-newsletter/configuration.mjs +User=root +Restart=always + +[Install] +WantedBy=multi-user.target diff --git a/server/index.mts b/server/index.mts index 88fdeac..ebeb77a 100644 --- a/server/index.mts +++ b/server/index.mts @@ -275,6 +275,9 @@ await commander.program }, web: express(), email: "TODO", + log: (...messageParts: any[]) => { + console.log(messageParts.join(" ")); + }, }; application.configuration.environment ??= "production";