Merge pull request #116074 from talyz/discourse
discourse: Add package and NixOS module
This commit is contained in:
commit
5a1bd5ff66
@ -118,6 +118,16 @@
|
||||
<xref linkend="opt-services.samba-wsdd.enable" /> Web Services Dynamic Discovery host daemon
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xlink:href="https://www.discourse.org/">Discourse</link>, a
|
||||
modern and open source discussion platform.
|
||||
</para>
|
||||
<para>
|
||||
See the <link linkend="module-services-discourse">Discourse
|
||||
section of the NixOS manual</link> for more information.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
</section>
|
||||
|
@ -897,6 +897,7 @@
|
||||
./services/web-apps/calibre-web.nix
|
||||
./services/web-apps/convos.nix
|
||||
./services/web-apps/cryptpad.nix
|
||||
./services/web-apps/discourse.nix
|
||||
./services/web-apps/documize.nix
|
||||
./services/web-apps/dokuwiki.nix
|
||||
./services/web-apps/engelsystem.nix
|
||||
|
1035
nixos/modules/services/web-apps/discourse.nix
Normal file
1035
nixos/modules/services/web-apps/discourse.nix
Normal file
File diff suppressed because it is too large
Load Diff
323
nixos/modules/services/web-apps/discourse.xml
Normal file
323
nixos/modules/services/web-apps/discourse.xml
Normal file
@ -0,0 +1,323 @@
|
||||
<chapter xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
version="5.0"
|
||||
xml:id="module-services-discourse">
|
||||
<title>Discourse</title>
|
||||
<para>
|
||||
<link xlink:href="https://www.discourse.org/">Discourse</link> is a
|
||||
modern and open source discussion platform.
|
||||
</para>
|
||||
|
||||
<section xml:id="module-services-discourse-basic-usage">
|
||||
<title>Basic usage</title>
|
||||
<para>
|
||||
A minimal configuration using Let's Encrypt for TLS certificates looks like this:
|
||||
<programlisting>
|
||||
services.discourse = {
|
||||
<link linkend="opt-services.discourse.enable">enable</link> = true;
|
||||
<link linkend="opt-services.discourse.hostname">hostname</link> = "discourse.example.com";
|
||||
admin = {
|
||||
<link linkend="opt-services.discourse.admin.email">email</link> = "admin@example.com";
|
||||
<link linkend="opt-services.discourse.admin.username">username</link> = "admin";
|
||||
<link linkend="opt-services.discourse.admin.fullName">fullName</link> = "Administrator";
|
||||
<link linkend="opt-services.discourse.admin.passwordFile">passwordFile</link> = "/path/to/password_file";
|
||||
};
|
||||
<link linkend="opt-services.discourse.secretKeyBaseFile">secretKeyBaseFile</link> = "/path/to/secret_key_base_file";
|
||||
};
|
||||
<link linkend="opt-security.acme.email">security.acme.email</link> = "me@example.com";
|
||||
<link linkend="opt-security.acme.acceptTerms">security.acme.acceptTerms</link> = true;
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Provided a proper DNS setup, you'll be able to connect to the
|
||||
instance at <literal>discourse.example.com</literal> and log in
|
||||
using the credentials provided in
|
||||
<literal>services.discourse.admin</literal>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="module-services-discourse-tls">
|
||||
<title>Using a regular TLS certificate</title>
|
||||
<para>
|
||||
To set up TLS using a regular certificate and key on file, use
|
||||
the <xref linkend="opt-services.discourse.sslCertificate" />
|
||||
and <xref linkend="opt-services.discourse.sslCertificateKey" />
|
||||
options:
|
||||
|
||||
<programlisting>
|
||||
services.discourse = {
|
||||
<link linkend="opt-services.discourse.enable">enable</link> = true;
|
||||
<link linkend="opt-services.discourse.hostname">hostname</link> = "discourse.example.com";
|
||||
<link linkend="opt-services.discourse.sslCertificate">sslCertificate</link> = "/path/to/ssl_certificate";
|
||||
<link linkend="opt-services.discourse.sslCertificateKey">sslCertificateKey</link> = "/path/to/ssl_certificate_key";
|
||||
admin = {
|
||||
<link linkend="opt-services.discourse.admin.email">email</link> = "admin@example.com";
|
||||
<link linkend="opt-services.discourse.admin.username">username</link> = "admin";
|
||||
<link linkend="opt-services.discourse.admin.fullName">fullName</link> = "Administrator";
|
||||
<link linkend="opt-services.discourse.admin.passwordFile">passwordFile</link> = "/path/to/password_file";
|
||||
};
|
||||
<link linkend="opt-services.discourse.secretKeyBaseFile">secretKeyBaseFile</link> = "/path/to/secret_key_base_file";
|
||||
};
|
||||
</programlisting>
|
||||
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="module-services-discourse-database">
|
||||
<title>Database access</title>
|
||||
<para>
|
||||
<productname>Discourse</productname> uses
|
||||
<productname>PostgreSQL</productname> to store most of its
|
||||
data. A database will automatically be enabled and a database
|
||||
and role created unless <xref
|
||||
linkend="opt-services.discourse.database.host" /> is changed from
|
||||
its default of <literal>null</literal> or <xref
|
||||
linkend="opt-services.discourse.database.createLocally" /> is set
|
||||
to <literal>false</literal>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
External database access can also be configured by setting
|
||||
<xref linkend="opt-services.discourse.database.host" />, <xref
|
||||
linkend="opt-services.discourse.database.username" /> and <xref
|
||||
linkend="opt-services.discourse.database.passwordFile" /> as
|
||||
appropriate. Note that you need to manually create a database
|
||||
called <literal>discourse</literal> (or the name you chose in
|
||||
<xref linkend="opt-services.discourse.database.name" />) and
|
||||
allow the configured database user full access to it.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="module-services-discourse-mail">
|
||||
<title>Email</title>
|
||||
<para>
|
||||
In addition to the basic setup, you'll want to configure an SMTP
|
||||
server <productname>Discourse</productname> can use to send user
|
||||
registration and password reset emails, among others. You can
|
||||
also optionally let <productname>Discourse</productname> receive
|
||||
email, which enables people to reply to threads and conversations
|
||||
via email.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A basic setup which assumes you want to use your configured <link
|
||||
linkend="opt-services.discourse.hostname">hostname</link> as
|
||||
email domain can be done like this:
|
||||
|
||||
<programlisting>
|
||||
services.discourse = {
|
||||
<link linkend="opt-services.discourse.enable">enable</link> = true;
|
||||
<link linkend="opt-services.discourse.hostname">hostname</link> = "discourse.example.com";
|
||||
<link linkend="opt-services.discourse.sslCertificate">sslCertificate</link> = "/path/to/ssl_certificate";
|
||||
<link linkend="opt-services.discourse.sslCertificateKey">sslCertificateKey</link> = "/path/to/ssl_certificate_key";
|
||||
admin = {
|
||||
<link linkend="opt-services.discourse.admin.email">email</link> = "admin@example.com";
|
||||
<link linkend="opt-services.discourse.admin.username">username</link> = "admin";
|
||||
<link linkend="opt-services.discourse.admin.fullName">fullName</link> = "Administrator";
|
||||
<link linkend="opt-services.discourse.admin.passwordFile">passwordFile</link> = "/path/to/password_file";
|
||||
};
|
||||
mail.outgoing = {
|
||||
<link linkend="opt-services.discourse.mail.outgoing.serverAddress">serverAddress</link> = "smtp.emailprovider.com";
|
||||
<link linkend="opt-services.discourse.mail.outgoing.port">port</link> = 587;
|
||||
<link linkend="opt-services.discourse.mail.outgoing.username">username</link> = "user@emailprovider.com";
|
||||
<link linkend="opt-services.discourse.mail.outgoing.passwordFile">passwordFile</link> = "/path/to/smtp_password_file";
|
||||
};
|
||||
<link linkend="opt-services.discourse.mail.incoming.enable">mail.incoming.enable</link> = true;
|
||||
<link linkend="opt-services.discourse.secretKeyBaseFile">secretKeyBaseFile</link> = "/path/to/secret_key_base_file";
|
||||
};
|
||||
</programlisting>
|
||||
|
||||
This assumes you have set up an MX record for the address you've
|
||||
set in <link linkend="opt-services.discourse.hostname">hostname</link> and
|
||||
requires proper SPF, DKIM and DMARC configuration to be done for
|
||||
the domain you're sending from, in order for email to be reliably delivered.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If you want to use a different domain for your outgoing email
|
||||
(for example <literal>example.com</literal> instead of
|
||||
<literal>discourse.example.com</literal>) you should set
|
||||
<xref linkend="opt-services.discourse.mail.notificationEmailAddress" /> and
|
||||
<xref linkend="opt-services.discourse.mail.contactEmailAddress" /> manually.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
Setup of TLS for incoming email is currently only configured
|
||||
automatically when a regular TLS certificate is used, i.e. when
|
||||
<xref linkend="opt-services.discourse.sslCertificate" /> and
|
||||
<xref linkend="opt-services.discourse.sslCertificateKey" /> are
|
||||
set.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
</section>
|
||||
|
||||
<section xml:id="module-services-discourse-settings">
|
||||
<title>Additional settings</title>
|
||||
<para>
|
||||
Additional site settings and backend settings, for which no
|
||||
explicit <productname>NixOS</productname> options are provided,
|
||||
can be set in <xref linkend="opt-services.discourse.siteSettings" /> and
|
||||
<xref linkend="opt-services.discourse.backendSettings" /> respectively.
|
||||
</para>
|
||||
|
||||
<section xml:id="module-services-discourse-site-settings">
|
||||
<title>Site settings</title>
|
||||
<para>
|
||||
<quote>Site settings</quote> are the settings that can be
|
||||
changed through the <productname>Discourse</productname>
|
||||
UI. Their <emphasis>default</emphasis> values can be set using
|
||||
<xref linkend="opt-services.discourse.siteSettings" />.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Settings are expressed as a Nix attribute set which matches the
|
||||
structure of the configuration in
|
||||
<link xlink:href="https://github.com/discourse/discourse/blob/master/config/site_settings.yml">config/site_settings.yml</link>.
|
||||
To find a setting's path, you only need to care about the first
|
||||
two levels; i.e. its category (e.g. <literal>login</literal>)
|
||||
and name (e.g. <literal>invite_only</literal>).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Settings containing secret data should be set to an attribute
|
||||
set containing the attribute <literal>_secret</literal> - a
|
||||
string pointing to a file containing the value the option
|
||||
should be set to. See the example.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="module-services-discourse-backend-settings">
|
||||
<title>Backend settings</title>
|
||||
<para>
|
||||
Settings are expressed as a Nix attribute set which matches the
|
||||
structure of the configuration in
|
||||
<link xlink:href="https://github.com/discourse/discourse/blob/stable/config/discourse_defaults.conf">config/discourse.conf</link>.
|
||||
Empty parameters can be defined by setting them to
|
||||
<literal>null</literal>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="module-services-discourse-settings-example">
|
||||
<title>Example</title>
|
||||
<para>
|
||||
The following example sets the title and description of the
|
||||
<productname>Discourse</productname> instance and enables
|
||||
<productname>GitHub</productname> login in the site settings,
|
||||
and changes a few request limits in the backend settings:
|
||||
<programlisting>
|
||||
services.discourse = {
|
||||
<link linkend="opt-services.discourse.enable">enable</link> = true;
|
||||
<link linkend="opt-services.discourse.hostname">hostname</link> = "discourse.example.com";
|
||||
<link linkend="opt-services.discourse.sslCertificate">sslCertificate</link> = "/path/to/ssl_certificate";
|
||||
<link linkend="opt-services.discourse.sslCertificateKey">sslCertificateKey</link> = "/path/to/ssl_certificate_key";
|
||||
admin = {
|
||||
<link linkend="opt-services.discourse.admin.email">email</link> = "admin@example.com";
|
||||
<link linkend="opt-services.discourse.admin.username">username</link> = "admin";
|
||||
<link linkend="opt-services.discourse.admin.fullName">fullName</link> = "Administrator";
|
||||
<link linkend="opt-services.discourse.admin.passwordFile">passwordFile</link> = "/path/to/password_file";
|
||||
};
|
||||
mail.outgoing = {
|
||||
<link linkend="opt-services.discourse.mail.outgoing.serverAddress">serverAddress</link> = "smtp.emailprovider.com";
|
||||
<link linkend="opt-services.discourse.mail.outgoing.port">port</link> = 587;
|
||||
<link linkend="opt-services.discourse.mail.outgoing.username">username</link> = "user@emailprovider.com";
|
||||
<link linkend="opt-services.discourse.mail.outgoing.passwordFile">passwordFile</link> = "/path/to/smtp_password_file";
|
||||
};
|
||||
<link linkend="opt-services.discourse.mail.incoming.enable">mail.incoming.enable</link> = true;
|
||||
<link linkend="opt-services.discourse.siteSettings">siteSettings</link> = {
|
||||
required = {
|
||||
title = "My Cats";
|
||||
site_description = "Discuss My Cats (and be nice plz)";
|
||||
};
|
||||
login = {
|
||||
enable_github_logins = true;
|
||||
github_client_id = "a2f6dfe838cb3206ce20";
|
||||
github_client_secret._secret = /run/keys/discourse_github_client_secret;
|
||||
};
|
||||
};
|
||||
<link linkend="opt-services.discourse.backendSettings">backendSettings</link> = {
|
||||
max_reqs_per_ip_per_minute = 300;
|
||||
max_reqs_per_ip_per_10_seconds = 60;
|
||||
max_asset_reqs_per_ip_per_10_seconds = 250;
|
||||
max_reqs_per_ip_mode = "warn+block";
|
||||
};
|
||||
<link linkend="opt-services.discourse.secretKeyBaseFile">secretKeyBaseFile</link> = "/path/to/secret_key_base_file";
|
||||
};
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
In the resulting site settings file, the
|
||||
<literal>login.github_client_secret</literal> key will be set
|
||||
to the contents of the
|
||||
<filename>/run/keys/discourse_github_client_secret</filename>
|
||||
file.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
<section xml:id="module-services-discourse-plugins">
|
||||
<title>Plugins</title>
|
||||
<para>
|
||||
You can install <productname>Discourse</productname> plugins
|
||||
using the <xref linkend="opt-services.discourse.plugins" />
|
||||
option. As long as a plugin supports the standard install
|
||||
method, packaging it should only require fetching its source
|
||||
with an appropriate fetcher.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Some plugins provide <link
|
||||
linkend="module-services-discourse-site-settings">site
|
||||
settings</link>. Their defaults can be configured using <xref
|
||||
linkend="opt-services.discourse.siteSettings" />, just like
|
||||
regular site settings. To find the names of these settings, look
|
||||
in the <literal>config/settings.yml</literal> file of the plugin
|
||||
repo.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For example, to add the <link
|
||||
xlink:href="https://github.com/discourse/discourse-spoiler-alert">discourse-spoiler-alert</link>
|
||||
plugin and disable it by default:
|
||||
|
||||
<programlisting>
|
||||
services.discourse = {
|
||||
<link linkend="opt-services.discourse.enable">enable</link> = true;
|
||||
<link linkend="opt-services.discourse.hostname">hostname</link> = "discourse.example.com";
|
||||
<link linkend="opt-services.discourse.sslCertificate">sslCertificate</link> = "/path/to/ssl_certificate";
|
||||
<link linkend="opt-services.discourse.sslCertificateKey">sslCertificateKey</link> = "/path/to/ssl_certificate_key";
|
||||
admin = {
|
||||
<link linkend="opt-services.discourse.admin.email">email</link> = "admin@example.com";
|
||||
<link linkend="opt-services.discourse.admin.username">username</link> = "admin";
|
||||
<link linkend="opt-services.discourse.admin.fullName">fullName</link> = "Administrator";
|
||||
<link linkend="opt-services.discourse.admin.passwordFile">passwordFile</link> = "/path/to/password_file";
|
||||
};
|
||||
mail.outgoing = {
|
||||
<link linkend="opt-services.discourse.mail.outgoing.serverAddress">serverAddress</link> = "smtp.emailprovider.com";
|
||||
<link linkend="opt-services.discourse.mail.outgoing.port">port</link> = 587;
|
||||
<link linkend="opt-services.discourse.mail.outgoing.username">username</link> = "user@emailprovider.com";
|
||||
<link linkend="opt-services.discourse.mail.outgoing.passwordFile">passwordFile</link> = "/path/to/smtp_password_file";
|
||||
};
|
||||
<link linkend="opt-services.discourse.mail.incoming.enable">mail.incoming.enable</link> = true;
|
||||
<link linkend="opt-services.discourse.mail.incoming.enable">plugins</link> = [
|
||||
(pkgs.fetchFromGitHub {
|
||||
owner = "discourse";
|
||||
repo = "discourse-spoiler-alert";
|
||||
rev = "e200cfa571d252cab63f3d30d619b370986e4cee";
|
||||
sha256 = "0ya69ix5g77wz4c9x9gmng6l25ghb5xxlx3icr6jam16q14dzc33";
|
||||
})
|
||||
];
|
||||
<link linkend="opt-services.discourse.siteSettings">siteSettings</link> = {
|
||||
plugins = {
|
||||
spoiler_enabled = false;
|
||||
};
|
||||
};
|
||||
<link linkend="opt-services.discourse.secretKeyBaseFile">secretKeyBaseFile</link> = "/path/to/secret_key_base_file";
|
||||
};
|
||||
</programlisting>
|
||||
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
@ -397,6 +397,9 @@ in
|
||||
default = pkgs.nginxStable;
|
||||
defaultText = "pkgs.nginxStable";
|
||||
type = types.package;
|
||||
apply = p: p.override {
|
||||
modules = p.modules ++ cfg.additionalModules;
|
||||
};
|
||||
description = "
|
||||
Nginx package to use. This defaults to the stable version. Note
|
||||
that the nginx team recommends to use the mainline version which
|
||||
@ -404,6 +407,17 @@ in
|
||||
";
|
||||
};
|
||||
|
||||
additionalModules = mkOption {
|
||||
default = [];
|
||||
type = types.listOf (types.attrsOf types.anything);
|
||||
example = literalExample "[ pkgs.nginxModules.brotli ]";
|
||||
description = ''
|
||||
Additional <link xlink:href="https://www.nginx.com/resources/wiki/modules/">third-party nginx modules</link>
|
||||
to install. Packaged modules are available in
|
||||
<literal>pkgs.nginxModules</literal>.
|
||||
'';
|
||||
};
|
||||
|
||||
logError = mkOption {
|
||||
default = "stderr";
|
||||
type = types.str;
|
||||
|
@ -88,6 +88,7 @@ in
|
||||
croc = handleTest ./croc.nix {};
|
||||
deluge = handleTest ./deluge.nix {};
|
||||
dhparams = handleTest ./dhparams.nix {};
|
||||
discourse = handleTest ./discourse.nix {};
|
||||
dnscrypt-proxy2 = handleTestOn ["x86_64-linux"] ./dnscrypt-proxy2.nix {};
|
||||
dnscrypt-wrapper = handleTestOn ["x86_64-linux"] ./dnscrypt-wrapper {};
|
||||
doas = handleTest ./doas.nix {};
|
||||
|
197
nixos/tests/discourse.nix
Normal file
197
nixos/tests/discourse.nix
Normal file
@ -0,0 +1,197 @@
|
||||
# This tests Discourse by:
|
||||
# 1. logging in as the admin user
|
||||
# 2. sending a private message to the admin user through the API
|
||||
# 3. replying to that message via email.
|
||||
|
||||
import ./make-test-python.nix (
|
||||
{ pkgs, lib, ... }:
|
||||
let
|
||||
certs = import ./common/acme/server/snakeoil-certs.nix;
|
||||
clientDomain = "client.fake.domain";
|
||||
discourseDomain = certs.domain;
|
||||
adminPassword = "eYAX85qmMJ5GZIHLaXGDAoszD7HSZp5d";
|
||||
secretKeyBase = "381f4ac6d8f5e49d804dae72aa9c046431d2f34c656a705c41cd52fed9b4f6f76f51549f0b55db3b8b0dded7a00d6a381ebe9a4367d2d44f5e743af6628b4d42";
|
||||
admin = {
|
||||
email = "alice@${clientDomain}";
|
||||
username = "alice";
|
||||
fullName = "Alice Admin";
|
||||
passwordFile = "${pkgs.writeText "admin-pass" adminPassword}";
|
||||
};
|
||||
in
|
||||
{
|
||||
name = "discourse";
|
||||
meta = with pkgs.lib.maintainers; {
|
||||
maintainers = [ talyz ];
|
||||
};
|
||||
|
||||
nodes.discourse =
|
||||
{ nodes, ... }:
|
||||
{
|
||||
virtualisation.memorySize = 2048;
|
||||
|
||||
imports = [ common/user-account.nix ];
|
||||
|
||||
security.pki.certificateFiles = [
|
||||
certs.ca.cert
|
||||
];
|
||||
|
||||
networking.extraHosts = ''
|
||||
127.0.0.1 ${discourseDomain}
|
||||
${nodes.client.config.networking.primaryIPAddress} ${clientDomain}
|
||||
'';
|
||||
|
||||
services.postfix = {
|
||||
enableSubmission = true;
|
||||
enableSubmissions = true;
|
||||
submissionsOptions = {
|
||||
smtpd_sasl_auth_enable = "yes";
|
||||
smtpd_client_restrictions = "permit";
|
||||
};
|
||||
};
|
||||
|
||||
environment.systemPackages = [ pkgs.jq ];
|
||||
|
||||
services.discourse = {
|
||||
enable = true;
|
||||
inherit admin;
|
||||
hostname = discourseDomain;
|
||||
sslCertificate = "${certs.${discourseDomain}.cert}";
|
||||
sslCertificateKey = "${certs.${discourseDomain}.key}";
|
||||
secretKeyBaseFile = "${pkgs.writeText "secret-key-base" secretKeyBase}";
|
||||
enableACME = false;
|
||||
mail.outgoing.serverAddress = clientDomain;
|
||||
mail.incoming.enable = true;
|
||||
siteSettings = {
|
||||
posting = {
|
||||
min_post_length = 5;
|
||||
min_first_post_length = 5;
|
||||
min_personal_message_post_length = 5;
|
||||
};
|
||||
};
|
||||
unicornTimeout = 900;
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 25 465 ];
|
||||
};
|
||||
|
||||
nodes.client =
|
||||
{ nodes, ... }:
|
||||
{
|
||||
imports = [ common/user-account.nix ];
|
||||
|
||||
security.pki.certificateFiles = [
|
||||
certs.ca.cert
|
||||
];
|
||||
|
||||
networking.extraHosts = ''
|
||||
127.0.0.1 ${clientDomain}
|
||||
${nodes.discourse.config.networking.primaryIPAddress} ${discourseDomain}
|
||||
'';
|
||||
|
||||
services.dovecot2 = {
|
||||
enable = true;
|
||||
protocols = [ "imap" ];
|
||||
modules = [ pkgs.dovecot_pigeonhole ];
|
||||
};
|
||||
|
||||
services.postfix = {
|
||||
enable = true;
|
||||
origin = clientDomain;
|
||||
relayDomains = [ clientDomain ];
|
||||
config = {
|
||||
compatibility_level = "2";
|
||||
smtpd_banner = "ESMTP server";
|
||||
myhostname = clientDomain;
|
||||
mydestination = clientDomain;
|
||||
};
|
||||
};
|
||||
|
||||
environment.systemPackages =
|
||||
let
|
||||
replyToEmail = pkgs.writeScriptBin "reply-to-email" ''
|
||||
#!${pkgs.python3.interpreter}
|
||||
import imaplib
|
||||
import smtplib
|
||||
import ssl
|
||||
import email.header
|
||||
from email import message_from_bytes
|
||||
from email.message import EmailMessage
|
||||
|
||||
with imaplib.IMAP4('localhost') as imap:
|
||||
imap.login('alice', 'foobar')
|
||||
imap.select()
|
||||
status, data = imap.search(None, 'ALL')
|
||||
assert status == 'OK'
|
||||
|
||||
nums = data[0].split()
|
||||
assert len(nums) == 1
|
||||
|
||||
status, msg_data = imap.fetch(nums[0], '(RFC822)')
|
||||
assert status == 'OK'
|
||||
|
||||
msg = email.message_from_bytes(msg_data[0][1])
|
||||
subject = str(email.header.make_header(email.header.decode_header(msg['Subject'])))
|
||||
reply_to = email.header.decode_header(msg['Reply-To'])[0][0]
|
||||
message_id = email.header.decode_header(msg['Message-ID'])[0][0]
|
||||
date = email.header.decode_header(msg['Date'])[0][0]
|
||||
|
||||
ctx = ssl.create_default_context()
|
||||
with smtplib.SMTP_SSL(host='${discourseDomain}', context=ctx) as smtp:
|
||||
reply = EmailMessage()
|
||||
reply['Subject'] = 'Re: ' + subject
|
||||
reply['To'] = reply_to
|
||||
reply['From'] = 'alice@${clientDomain}'
|
||||
reply['In-Reply-To'] = message_id
|
||||
reply['References'] = message_id
|
||||
reply['Date'] = date
|
||||
reply.set_content("Test reply.")
|
||||
|
||||
smtp.send_message(reply)
|
||||
smtp.quit()
|
||||
'';
|
||||
in
|
||||
[ replyToEmail ];
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 25 ];
|
||||
};
|
||||
|
||||
|
||||
testScript = { nodes }:
|
||||
let
|
||||
request = builtins.toJSON {
|
||||
title = "Private message";
|
||||
raw = "This is a test message.";
|
||||
target_usernames = admin.username;
|
||||
archetype = "private_message";
|
||||
};
|
||||
in ''
|
||||
discourse.start()
|
||||
client.start()
|
||||
|
||||
discourse.wait_for_unit("discourse.service")
|
||||
discourse.wait_for_file("/run/discourse/sockets/unicorn.sock")
|
||||
discourse.wait_until_succeeds("curl -sS -f https://${discourseDomain}")
|
||||
discourse.succeed(
|
||||
"curl -sS -f https://${discourseDomain}/session/csrf -c cookie -b cookie -H 'Accept: application/json' | jq -r '\"X-CSRF-Token: \" + .csrf' > csrf_token",
|
||||
"curl -sS -f https://${discourseDomain}/session -c cookie -b cookie -H @csrf_token -H 'Accept: application/json' -d 'login=${nodes.discourse.config.services.discourse.admin.username}' -d \"password=${adminPassword}\" | jq -e '.user.username == \"${nodes.discourse.config.services.discourse.admin.username}\"'",
|
||||
"curl -sS -f https://${discourseDomain}/login -v -H 'Accept: application/json' -c cookie -b cookie 2>&1 | grep ${nodes.discourse.config.services.discourse.admin.username}",
|
||||
)
|
||||
|
||||
client.wait_for_unit("postfix.service")
|
||||
client.wait_for_unit("dovecot2.service")
|
||||
|
||||
discourse.succeed(
|
||||
"sudo -u discourse discourse-rake api_key:create_master[master] >api_key",
|
||||
'curl -sS -f https://${discourseDomain}/posts -X POST -H "Content-Type: application/json" -H "Api-Key: $(<api_key)" -H "Api-Username: system" -d \'${request}\' ',
|
||||
)
|
||||
|
||||
client.wait_until_succeeds("reply-to-email")
|
||||
|
||||
discourse.wait_until_succeeds(
|
||||
'curl -sS -f https://${discourseDomain}/topics/private-messages/system -H "Accept: application/json" -H "Api-Key: $(<api_key)" -H "Api-Username: system" | jq -e \'if .topic_list.topics[0].id != null then .topic_list.topics[0].id else null end\' >topic_id'
|
||||
)
|
||||
discourse.succeed(
|
||||
'curl -sS -f https://${discourseDomain}/t/$(<topic_id) -H "Accept: application/json" -H "Api-Key: $(<api_key)" -H "Api-Username: system" | jq -e \'if .post_stream.posts[1].cooked == "<p>Test reply.</p>" then true else null end\' '
|
||||
)
|
||||
'';
|
||||
})
|
@ -11,23 +11,23 @@ let
|
||||
deps = {
|
||||
"base/trace_event/common" = fetchgit {
|
||||
url = "${git_url}/chromium/src/base/trace_event/common.git";
|
||||
rev = "936ba8a963284a6b3737cf2f0474a7131073abee";
|
||||
sha256 = "14nr22fqdpxma1kzjflj6a865vr3hfnnm2gs4vcixyq4kmfzfcy2";
|
||||
rev = "dab187b372fc17e51f5b9fad8201813d0aed5129";
|
||||
sha256 = "0dmpj9hj4xv3xb0fl1kb9hm4bhpbs2s5csx3z8cgjd5vwvhdzig4";
|
||||
};
|
||||
build = fetchgit {
|
||||
url = "${git_url}/chromium/src/build.git";
|
||||
rev = "325e95d6dae64f35b160b3dc7d73218cee5ec079";
|
||||
sha256 = "0dddyxa76p2xpjhmxif05v63i5ar6h5v684fdl667sg84f5bhhxf";
|
||||
rev = "26e9d485d01d6e0eb9dadd21df767a63494c8fea";
|
||||
sha256 = "1jjvsgj0cs97d26i3ba531ic1f9gqan8x7z4aya8yl8jx02l342q";
|
||||
};
|
||||
"third_party/googletest/src" = fetchgit {
|
||||
url = "${git_url}/external/github.com/google/googletest.git";
|
||||
rev = "5ec7f0c4a113e2f18ac2c6cc7df51ad6afc24081";
|
||||
sha256 = "0gmr10042c0xybxnn6g7ndj1na1mmd3l9w7449qlcv4s8gmfs7k6";
|
||||
rev = "e3f0319d89f4cbf32993de595d984183b1a9fc57";
|
||||
sha256 = "18xz71l2xjrqsc0q317whgw4xi1i5db24zcj7v04f5g6r1hyf1a5";
|
||||
};
|
||||
"third_party/icu" = fetchgit {
|
||||
url = "${git_url}/chromium/deps/icu.git";
|
||||
rev = "960f195aa87acaec46e6104ec93a596da7ae0843";
|
||||
sha256 = "073kh6gpcairgjxf3hlhpqljc13gwl2aj8fz91fv220xibwqs834";
|
||||
rev = "f2223961702f00a8833874b0560d615a2cc42738";
|
||||
sha256 = "0z5p53kbrjfkjn0i12dpk55cp8976j2zk7a4wk88423s2c5w87zl";
|
||||
};
|
||||
"third_party/jinja2" = fetchgit {
|
||||
url = "${git_url}/chromium/src/third_party/jinja2.git";
|
||||
@ -39,29 +39,31 @@ let
|
||||
rev = "8f45f5cfa0009d2a70589bcda0349b8cb2b72783";
|
||||
sha256 = "168ppjmicfdh4i1l0l25s86mdbrz9fgxmiq1rx33x79mph41scfz";
|
||||
};
|
||||
"third_party/zlib" = fetchgit {
|
||||
url = "${git_url}/chromium/src/third_party/zlib.git";
|
||||
rev = "156be8c52f80cde343088b4a69a80579101b6e67";
|
||||
sha256 = "0hxbkkzmlv714fjq2jlp5dd2jc339xyh6gkjx1sz3srwv33mlk92";
|
||||
};
|
||||
};
|
||||
|
||||
in
|
||||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "v8";
|
||||
version = "7.4.255";
|
||||
version = "8.4.255";
|
||||
|
||||
doCheck = true;
|
||||
|
||||
patches = [
|
||||
(fetchpatch {
|
||||
url = "https://raw.githubusercontent.com/RPi-Distro/chromium-browser/master/debian/patches/revert-Xclang-instcombine-lower-dbg-declare.patch";
|
||||
sha256 = "02hczcg43m36q8j1kv5j3hq9czj9niiil9w13w22vzv2f3c67dvn";
|
||||
})
|
||||
./darwin.patch
|
||||
./gcc_arm.patch # Fix building zlib with gcc on aarch64, from https://gist.github.com/Adenilson/d973b6fd96c7709d33ddf08cf1dcb149
|
||||
];
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "v8";
|
||||
repo = "v8";
|
||||
rev = version;
|
||||
sha256 = "14i0c71hmffzqnq9n73dh9dnabdxhbjhzkhqpk5yv9y90bwrzi2n";
|
||||
sha256 = "07ymw4kqbz7kv311gpk5bs5q90wj73n2q7jkyfhqk4hvhs1q5bw7";
|
||||
};
|
||||
|
||||
postUnpack = ''
|
||||
@ -97,9 +99,7 @@ stdenv.mkDerivation rec {
|
||||
''v8_snapshot_toolchain="//build/toolchain/linux/unbundle:default"''
|
||||
] ++ lib.optional stdenv.cc.isClang ''clang_base_path="${stdenv.cc}"'';
|
||||
|
||||
# with gcc8, -Wclass-memaccess became part of -Wall and causes logging limit
|
||||
# to be exceeded
|
||||
NIX_CFLAGS_COMPILE = lib.optionalString stdenv.cc.isGNU "-Wno-class-memaccess";
|
||||
NIX_CFLAGS_COMPILE = "-O2";
|
||||
|
||||
nativeBuildInputs = [ gn ninja pkg-config python ]
|
||||
++ lib.optionals stdenv.isDarwin [ xcbuild darwin.DarwinTools ];
|
||||
|
31
pkgs/development/libraries/v8/gcc_arm.patch
Normal file
31
pkgs/development/libraries/v8/gcc_arm.patch
Normal file
@ -0,0 +1,31 @@
|
||||
diff --git a/third_party/zlib/contrib/optimizations/insert_string.h b/third_party/zlib/contrib/optimizations/insert_string.h
|
||||
index 1826601..d123305 100644
|
||||
--- a/third_party/zlib/contrib/optimizations/insert_string.h
|
||||
+++ b/third_party/zlib/contrib/optimizations/insert_string.h
|
||||
@@ -26,15 +26,23 @@
|
||||
#define _cpu_crc32_u32 _mm_crc32_u32
|
||||
|
||||
#elif defined(CRC32_ARMV8_CRC32)
|
||||
- #if defined(__clang__)
|
||||
+ #if defined(__GNUC__) || defined(__clang__)
|
||||
#undef TARGET_CPU_WITH_CRC
|
||||
- #define __crc32cw __builtin_arm_crc32cw
|
||||
+ #if defined(__clang__)
|
||||
+ #define __crc32cw __builtin_arm_crc32cw
|
||||
+ #elif defined(__GNUC__)
|
||||
+ #define __crc32cw __builtin_aarch64_crc32cw
|
||||
+ #endif
|
||||
#endif
|
||||
|
||||
#define _cpu_crc32_u32 __crc32cw
|
||||
|
||||
#if defined(__aarch64__)
|
||||
- #define TARGET_CPU_WITH_CRC __attribute__((target("crc")))
|
||||
+ #if defined(__clang__)
|
||||
+ #define TARGET_CPU_WITH_CRC __attribute__((target("crc")))
|
||||
+ #elif defined(__GNUC__)
|
||||
+ #define TARGET_CPU_WITH_CRC __attribute__((target("+crc")))
|
||||
+ #endif
|
||||
#else // !defined(__aarch64__)
|
||||
#define TARGET_CPU_WITH_CRC __attribute__((target("armv8-a,crc")))
|
||||
#endif // defined(__aarch64__)
|
12
pkgs/servers/web-apps/discourse/action_mailer_ca_cert.patch
Normal file
12
pkgs/servers/web-apps/discourse/action_mailer_ca_cert.patch
Normal file
@ -0,0 +1,12 @@
|
||||
diff --git a/config/environments/production.rb b/config/environments/production.rb
|
||||
index 75c3a69512..7fc374cd9d 100644
|
||||
--- a/config/environments/production.rb
|
||||
+++ b/config/environments/production.rb
|
||||
@@ -32,6 +32,7 @@ Discourse::Application.configure do
|
||||
user_name: GlobalSetting.smtp_user_name,
|
||||
password: GlobalSetting.smtp_password,
|
||||
authentication: GlobalSetting.smtp_authentication,
|
||||
+ ca_file: "/etc/ssl/certs/ca-certificates.crt",
|
||||
enable_starttls_auto: GlobalSetting.smtp_enable_start_tls
|
||||
}
|
||||
|
48
pkgs/servers/web-apps/discourse/admin_create.patch
Normal file
48
pkgs/servers/web-apps/discourse/admin_create.patch
Normal file
@ -0,0 +1,48 @@
|
||||
diff --git a/lib/tasks/admin.rake b/lib/tasks/admin.rake
|
||||
index 80c403616d..cba01202ac 100644
|
||||
--- a/lib/tasks/admin.rake
|
||||
+++ b/lib/tasks/admin.rake
|
||||
@@ -107,3 +107,43 @@ task "admin:create" => :environment do
|
||||
end
|
||||
|
||||
end
|
||||
+
|
||||
+desc "Creates a forum administrator noninteractively"
|
||||
+task "admin:create_noninteractively" => :environment do
|
||||
+ email = ENV["ADMIN_EMAIL"]
|
||||
+ existing_user = User.find_by_email(email)
|
||||
+
|
||||
+ # check if user account already exixts
|
||||
+ if existing_user
|
||||
+ admin = existing_user
|
||||
+ else
|
||||
+ # create new user
|
||||
+ admin = User.new
|
||||
+ end
|
||||
+
|
||||
+ admin.email = email
|
||||
+ admin.name = ENV["ADMIN_NAME"]
|
||||
+ admin.username = ENV["ADMIN_USERNAME"]
|
||||
+
|
||||
+ password = ENV["ADMIN_PASSWORD"]
|
||||
+ unless admin.confirm_password?(password)
|
||||
+ admin.password = password
|
||||
+ puts "Admin password set!"
|
||||
+ end
|
||||
+
|
||||
+ admin.active = true
|
||||
+
|
||||
+ # save/update user account
|
||||
+ saved = admin.save
|
||||
+ raise admin.errors.full_messages.join("\n") unless saved
|
||||
+
|
||||
+ puts "Account created successfully with username #{admin.username}" unless existing_user
|
||||
+
|
||||
+ # grant admin privileges
|
||||
+ admin.grant_admin!
|
||||
+ if admin.trust_level < 1
|
||||
+ admin.change_trust_level!(1)
|
||||
+ end
|
||||
+ admin.email_tokens.update_all confirmed: true
|
||||
+ admin.activate
|
||||
+end
|
234
pkgs/servers/web-apps/discourse/default.nix
Normal file
234
pkgs/servers/web-apps/discourse/default.nix
Normal file
@ -0,0 +1,234 @@
|
||||
{ stdenv, makeWrapper, runCommandNoCC, lib, nixosTests
|
||||
, fetchFromGitHub, bundlerEnv, ruby, replace, gzip, gnutar, git
|
||||
, util-linux, gawk, imagemagick, optipng, pngquant, libjpeg, jpegoptim
|
||||
, gifsicle, libpsl, redis, postgresql, which, brotli, procps
|
||||
, nodePackages, v8
|
||||
}:
|
||||
|
||||
let
|
||||
version = "2.6.3";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "discourse";
|
||||
repo = "discourse";
|
||||
rev = "v${version}";
|
||||
sha256 = "sha256-lAIhVxvmjxEiru1KNxbFV+eDMLUGza/Dma3WU0ex0xs=";
|
||||
};
|
||||
|
||||
runtimeDeps = [
|
||||
# For backups, themes and assets
|
||||
rubyEnv.wrappedRuby
|
||||
gzip
|
||||
gnutar
|
||||
git
|
||||
brotli
|
||||
|
||||
# Misc required system utils
|
||||
which
|
||||
procps # For ps and kill
|
||||
util-linux # For renice
|
||||
gawk
|
||||
|
||||
# Image optimization
|
||||
imagemagick
|
||||
optipng
|
||||
pngquant
|
||||
libjpeg
|
||||
jpegoptim
|
||||
gifsicle
|
||||
nodePackages.svgo
|
||||
];
|
||||
|
||||
runtimeEnv = {
|
||||
HOME = "/run/discourse/home";
|
||||
RAILS_ENV = "production";
|
||||
UNICORN_LISTENER = "/run/discourse/sockets/unicorn.sock";
|
||||
};
|
||||
|
||||
rake = runCommandNoCC "discourse-rake" {
|
||||
nativeBuildInputs = [ makeWrapper ];
|
||||
} ''
|
||||
mkdir -p $out/bin
|
||||
makeWrapper ${rubyEnv}/bin/rake $out/bin/discourse-rake \
|
||||
${lib.concatStrings (lib.mapAttrsToList (name: value: "--set ${name} '${value}' ") runtimeEnv)} \
|
||||
--prefix PATH : ${lib.makeBinPath runtimeDeps} \
|
||||
--set RAKEOPT '-f ${discourse}/share/discourse/Rakefile' \
|
||||
--run 'cd ${discourse}/share/discourse'
|
||||
'';
|
||||
|
||||
rubyEnv = bundlerEnv {
|
||||
name = "discourse-ruby-env-${version}";
|
||||
inherit version ruby;
|
||||
gemdir = ./rubyEnv;
|
||||
gemset =
|
||||
let
|
||||
gems = import ./rubyEnv/gemset.nix;
|
||||
in
|
||||
gems // {
|
||||
mini_racer = gems.mini_racer // {
|
||||
buildInputs = [ v8 ];
|
||||
dontBuild = false;
|
||||
# The Ruby extension makefile generator assumes the source
|
||||
# is C, when it's actually C++ ¯\_(ツ)_/¯
|
||||
postPatch = ''
|
||||
substituteInPlace ext/mini_racer_extension/extconf.rb \
|
||||
--replace '" -std=c++0x"' \
|
||||
'" -x c++ -std=c++0x"'
|
||||
'';
|
||||
};
|
||||
mini_suffix = gems.mini_suffix // {
|
||||
propagatedBuildInputs = [ libpsl ];
|
||||
dontBuild = false;
|
||||
# Use our libpsl instead of the vendored one, which isn't
|
||||
# available for aarch64
|
||||
postPatch = ''
|
||||
cp $(readlink -f ${libpsl}/lib/libpsl.so) vendor/libpsl.so
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
groups = [
|
||||
"default" "assets" "development" "test"
|
||||
];
|
||||
};
|
||||
|
||||
assets = stdenv.mkDerivation {
|
||||
pname = "discourse-assets";
|
||||
inherit version src;
|
||||
|
||||
nativeBuildInputs = [
|
||||
rubyEnv.wrappedRuby
|
||||
postgresql
|
||||
redis
|
||||
which
|
||||
brotli
|
||||
procps
|
||||
nodePackages.uglify-js
|
||||
];
|
||||
|
||||
# We have to set up an environment that is close enough to
|
||||
# production ready or the assets:precompile task refuses to
|
||||
# run. This means that Redis and PostgreSQL has to be running and
|
||||
# database migrations performed.
|
||||
preBuild = ''
|
||||
redis-server >/dev/null &
|
||||
|
||||
initdb -A trust $NIX_BUILD_TOP/postgres >/dev/null
|
||||
postgres -D $NIX_BUILD_TOP/postgres -k $NIX_BUILD_TOP >/dev/null &
|
||||
export PGHOST=$NIX_BUILD_TOP
|
||||
|
||||
echo "Waiting for Redis and PostgreSQL to be ready.."
|
||||
while ! redis-cli --scan >/dev/null || ! psql -l >/dev/null; do
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
psql -d postgres -tAc 'CREATE USER "discourse"'
|
||||
psql -d postgres -tAc 'CREATE DATABASE "discourse" OWNER "discourse"'
|
||||
psql 'discourse' -tAc "CREATE EXTENSION IF NOT EXISTS pg_trgm"
|
||||
psql 'discourse' -tAc "CREATE EXTENSION IF NOT EXISTS hstore"
|
||||
|
||||
# Create a temporary home dir to stop bundler from complaining
|
||||
mkdir $NIX_BUILD_TOP/tmp_home
|
||||
export HOME=$NIX_BUILD_TOP/tmp_home
|
||||
|
||||
export RAILS_ENV=production
|
||||
|
||||
bundle exec rake db:migrate >/dev/null
|
||||
rm -r tmp/*
|
||||
'';
|
||||
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
|
||||
bundle exec rake assets:precompile
|
||||
|
||||
runHook postBuild
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
mv public/assets $out
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
};
|
||||
|
||||
discourse = stdenv.mkDerivation {
|
||||
pname = "discourse";
|
||||
inherit version src;
|
||||
|
||||
buildInputs = [
|
||||
rubyEnv rubyEnv.wrappedRuby rubyEnv.bundler
|
||||
];
|
||||
|
||||
patches = [
|
||||
# Load a separate NixOS site settings file
|
||||
./nixos_defaults.patch
|
||||
|
||||
# Add a noninteractive admin creation task
|
||||
./admin_create.patch
|
||||
|
||||
# Disable jhead, which is currently marked as vulnerable
|
||||
./disable_jhead.patch
|
||||
|
||||
# Add the path to the CA cert bundle to make TLS work
|
||||
./action_mailer_ca_cert.patch
|
||||
|
||||
# Log Unicorn messages to the journal and make request timeout
|
||||
# configurable
|
||||
./unicorn_logging_and_timeout.patch
|
||||
];
|
||||
|
||||
postPatch = ''
|
||||
# Always require lib-files and application.rb through their store
|
||||
# path, not their relative state directory path. This gets rid of
|
||||
# warnings and means we don't have to link back to lib from the
|
||||
# state directory.
|
||||
find config -type f -execdir sed -Ei "s,(\.\./)+(lib|app)/,$out/share/discourse/\2/," {} \;
|
||||
|
||||
${replace}/bin/replace-literal -f -r -e 'File.rename(temp_destination, destination)' "FileUtils.mv(temp_destination, destination)" .
|
||||
'';
|
||||
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
|
||||
mv config config.dist
|
||||
mv public public.dist
|
||||
mv plugins plugins.dist
|
||||
|
||||
runHook postBuild
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
mkdir -p $out/share
|
||||
cp -r . $out/share/discourse
|
||||
rm -r $out/share/discourse/log
|
||||
ln -sf /var/log/discourse $out/share/discourse/log
|
||||
ln -sf /run/discourse/tmp $out/share/discourse/tmp
|
||||
ln -sf /run/discourse/config $out/share/discourse/config
|
||||
ln -sf /run/discourse/assets/javascripts/plugins $out/share/discourse/app/assets/javascripts/plugins
|
||||
ln -sf /run/discourse/public $out/share/discourse/public
|
||||
ln -sf /run/discourse/plugins $out/share/discourse/plugins
|
||||
ln -sf ${assets} $out/share/discourse/public.dist/assets
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
homepage = "https://www.discourse.org/";
|
||||
platforms = platforms.linux;
|
||||
maintainers = with maintainers; [ talyz ];
|
||||
license = licenses.gpl2Plus;
|
||||
description = "Discourse is an open source discussion platform";
|
||||
};
|
||||
|
||||
passthru = {
|
||||
inherit rubyEnv runtimeEnv runtimeDeps rake;
|
||||
ruby = rubyEnv.wrappedRuby;
|
||||
tests = nixosTests.discourse;
|
||||
};
|
||||
};
|
||||
in discourse
|
12
pkgs/servers/web-apps/discourse/disable_jhead.patch
Normal file
12
pkgs/servers/web-apps/discourse/disable_jhead.patch
Normal file
@ -0,0 +1,12 @@
|
||||
diff --git a/lib/file_helper.rb b/lib/file_helper.rb
|
||||
index 162de9a40b..9ac8807e9d 100644
|
||||
--- a/lib/file_helper.rb
|
||||
+++ b/lib/file_helper.rb
|
||||
@@ -124,6 +124,7 @@ class FileHelper
|
||||
jpegoptim: { strip: strip_image_metadata ? "all" : "none" },
|
||||
jpegtran: false,
|
||||
jpegrecompress: false,
|
||||
+ jhead: false,
|
||||
)
|
||||
end
|
||||
end
|
39
pkgs/servers/web-apps/discourse/mail_receiver/default.nix
Normal file
39
pkgs/servers/web-apps/discourse/mail_receiver/default.nix
Normal file
@ -0,0 +1,39 @@
|
||||
{ stdenv, lib, fetchFromGitHub, ruby, makeWrapper, replace }:
|
||||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "discourse-mail-receiver";
|
||||
version = "4.0.7";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "discourse";
|
||||
repo = "mail-receiver";
|
||||
rev = "v${version}";
|
||||
sha256 = "0grifm5qyqazq63va3w26xjqnxwmfixhx0fx0zy7kd39378wwa6i";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [ replace ];
|
||||
buildInputs = [ ruby makeWrapper ];
|
||||
|
||||
dontBuild = true;
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/bin
|
||||
|
||||
replace-literal -f -r -e /etc/postfix /run/discourse-mail-receiver .
|
||||
|
||||
cp -r receive-mail discourse-smtp-fast-rejection $out/bin/
|
||||
cp -r lib $out/
|
||||
|
||||
wrapProgram $out/bin/receive-mail --set RUBYLIB $out/lib
|
||||
wrapProgram $out/bin/discourse-smtp-fast-rejection --set RUBYLIB $out/lib
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
homepage = "https://www.discourse.org/";
|
||||
platforms = platforms.linux;
|
||||
maintainers = with maintainers; [ talyz ];
|
||||
license = licenses.mit;
|
||||
description = "A helper program which receives incoming mail for Discourse";
|
||||
};
|
||||
|
||||
}
|
13
pkgs/servers/web-apps/discourse/nixos_defaults.patch
Normal file
13
pkgs/servers/web-apps/discourse/nixos_defaults.patch
Normal file
@ -0,0 +1,13 @@
|
||||
diff --git a/app/models/site_setting.rb b/app/models/site_setting.rb
|
||||
index 89a5e923fc..b60754f50a 100644
|
||||
--- a/app/models/site_setting.rb
|
||||
+++ b/app/models/site_setting.rb
|
||||
@@ -26,6 +26,8 @@ class SiteSetting < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
+ load_settings(File.join(Rails.root, 'config', 'nixos_site_settings.json'))
|
||||
+
|
||||
setup_deprecated_methods
|
||||
client_settings << :available_locales
|
||||
|
248
pkgs/servers/web-apps/discourse/rubyEnv/Gemfile
Normal file
248
pkgs/servers/web-apps/discourse/rubyEnv/Gemfile
Normal file
@ -0,0 +1,248 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
source 'https://rubygems.org'
|
||||
# if there is a super emergency and rubygems is playing up, try
|
||||
#source 'http://production.cf.rubygems.org'
|
||||
|
||||
gem 'bootsnap', require: false, platform: :mri
|
||||
|
||||
def rails_master?
|
||||
ENV["RAILS_MASTER"] == '1'
|
||||
end
|
||||
|
||||
if rails_master?
|
||||
gem 'arel', git: 'https://github.com/rails/arel.git'
|
||||
gem 'rails', git: 'https://github.com/rails/rails.git'
|
||||
else
|
||||
# NOTE: Until rubygems gives us optional dependencies we are stuck with this needing to be explicit
|
||||
# this allows us to include the bits of rails we use without pieces we do not.
|
||||
#
|
||||
# To issue a rails update bump the version number here
|
||||
gem 'actionmailer', '6.0.3.3'
|
||||
gem 'actionpack', '6.0.3.3'
|
||||
gem 'actionview', '6.0.3.3'
|
||||
gem 'activemodel', '6.0.3.3'
|
||||
gem 'activerecord', '6.0.3.3'
|
||||
gem 'activesupport', '6.0.3.3'
|
||||
gem 'railties', '6.0.3.3'
|
||||
gem 'sprockets-rails'
|
||||
end
|
||||
|
||||
gem 'json'
|
||||
|
||||
# TODO: At the moment Discourse does not work with Sprockets 4, we would need to correct internals
|
||||
# This is a desired upgrade we should get to.
|
||||
gem 'sprockets', '3.7.2'
|
||||
|
||||
# this will eventually be added to rails,
|
||||
# allows us to precompile all our templates in the unicorn master
|
||||
gem 'actionview_precompiler', require: false
|
||||
|
||||
gem 'seed-fu'
|
||||
|
||||
gem 'mail', require: false
|
||||
gem 'mini_mime'
|
||||
gem 'mini_suffix'
|
||||
|
||||
gem 'redis'
|
||||
|
||||
# This is explicitly used by Sidekiq and is an optional dependency.
|
||||
# We tell Sidekiq to use the namespace "sidekiq" which triggers this
|
||||
# gem to be used. There is no explicit dependency in sidekiq cause
|
||||
# redis namespace support is optional
|
||||
# We already namespace stuff in DiscourseRedis, so we should consider
|
||||
# just using a single implementation in core vs having 2 namespace implementations
|
||||
gem 'redis-namespace'
|
||||
|
||||
# NOTE: AM serializer gets a lot slower with recent updates
|
||||
# we used an old branch which is the fastest one out there
|
||||
# are long term goal here is to fork this gem so we have a
|
||||
# better maintained living fork
|
||||
gem 'active_model_serializers', '~> 0.8.3'
|
||||
|
||||
gem 'onebox'
|
||||
|
||||
gem 'http_accept_language', require: false
|
||||
|
||||
# Ember related gems need to be pinned cause they control client side
|
||||
# behavior, we will push these versions up when upgrading ember
|
||||
gem 'discourse-ember-rails', '0.18.6', require: 'ember-rails'
|
||||
gem 'discourse-ember-source', '~> 3.12.2'
|
||||
gem 'ember-handlebars-template', '0.8.0'
|
||||
gem 'discourse-fonts'
|
||||
|
||||
gem 'barber'
|
||||
|
||||
gem 'message_bus'
|
||||
|
||||
gem 'rails_multisite'
|
||||
|
||||
gem 'fast_xs', platform: :ruby
|
||||
|
||||
gem 'xorcist'
|
||||
|
||||
gem 'fastimage'
|
||||
|
||||
gem 'aws-sdk-s3', require: false
|
||||
gem 'aws-sdk-sns', require: false
|
||||
gem 'excon', require: false
|
||||
gem 'unf', require: false
|
||||
|
||||
gem 'email_reply_trimmer'
|
||||
|
||||
# Forked until https://github.com/toy/image_optim/pull/162 is merged
|
||||
# https://github.com/discourse/image_optim
|
||||
gem 'discourse_image_optim', require: 'image_optim'
|
||||
gem 'multi_json'
|
||||
gem 'mustache'
|
||||
gem 'nokogiri'
|
||||
gem 'css_parser', require: false
|
||||
|
||||
gem 'omniauth'
|
||||
gem 'omniauth-facebook'
|
||||
gem 'omniauth-twitter'
|
||||
gem 'omniauth-github'
|
||||
|
||||
gem 'omniauth-oauth2', require: false
|
||||
|
||||
gem 'omniauth-google-oauth2'
|
||||
|
||||
gem 'oj'
|
||||
gem 'pg'
|
||||
gem 'mini_sql'
|
||||
gem 'pry-rails', require: false
|
||||
gem 'pry-byebug', require: false
|
||||
gem 'r2', require: false
|
||||
gem 'rake'
|
||||
|
||||
gem 'thor', require: false
|
||||
gem 'diffy', require: false
|
||||
gem 'rinku'
|
||||
gem 'sidekiq'
|
||||
gem 'mini_scheduler'
|
||||
|
||||
gem 'execjs', require: false
|
||||
gem 'mini_racer'
|
||||
|
||||
gem 'highline', require: false
|
||||
|
||||
gem 'rack'
|
||||
|
||||
gem 'rack-protection' # security
|
||||
gem 'cbor', require: false
|
||||
gem 'cose', require: false
|
||||
gem 'addressable'
|
||||
|
||||
# Gems used only for assets and not required in production environments by default.
|
||||
# Allow everywhere for now cause we are allowing asset debugging in production
|
||||
group :assets do
|
||||
gem 'uglifier'
|
||||
gem 'rtlit', require: false # for css rtling
|
||||
end
|
||||
|
||||
group :test do
|
||||
gem 'webmock', require: false
|
||||
gem 'fakeweb', require: false
|
||||
gem 'minitest', require: false
|
||||
gem 'simplecov', require: false
|
||||
gem "test-prof"
|
||||
end
|
||||
|
||||
group :test, :development do
|
||||
gem 'rspec'
|
||||
gem 'mock_redis'
|
||||
gem 'listen', require: false
|
||||
gem 'certified', require: false
|
||||
gem 'fabrication', require: false
|
||||
gem 'mocha', require: false
|
||||
|
||||
gem 'rb-fsevent', require: RUBY_PLATFORM =~ /darwin/i ? 'rb-fsevent' : false
|
||||
|
||||
gem 'rspec-rails'
|
||||
|
||||
gem 'shoulda-matchers', require: false
|
||||
gem 'rspec-html-matchers'
|
||||
gem 'byebug', require: ENV['RM_INFO'].nil?, platform: :mri
|
||||
gem "rubocop-discourse", require: false
|
||||
gem 'parallel_tests'
|
||||
|
||||
gem 'rswag-specs'
|
||||
end
|
||||
|
||||
group :development do
|
||||
gem 'ruby-prof', require: false, platform: :mri
|
||||
gem 'bullet', require: !!ENV['BULLET']
|
||||
gem 'better_errors', platform: :mri, require: !!ENV['BETTER_ERRORS']
|
||||
gem 'binding_of_caller'
|
||||
gem 'yaml-lint'
|
||||
gem 'annotate'
|
||||
end
|
||||
|
||||
# this is an optional gem, it provides a high performance replacement
|
||||
# to String#blank? a method that is called quite frequently in current
|
||||
# ActiveRecord, this may change in the future
|
||||
gem 'fast_blank', platform: :ruby
|
||||
|
||||
# this provides a very efficient lru cache
|
||||
gem 'lru_redux'
|
||||
|
||||
gem 'htmlentities', require: false
|
||||
|
||||
# IMPORTANT: mini profiler monkey patches, so it better be required last
|
||||
# If you want to amend mini profiler to do the monkey patches in the railties
|
||||
# we are open to it. by deferring require to the initializer we can configure discourse installs without it
|
||||
|
||||
gem 'flamegraph', require: false
|
||||
gem 'rack-mini-profiler', require: ['enable_rails_patches']
|
||||
|
||||
gem 'unicorn', require: false, platform: :ruby
|
||||
gem 'puma', require: false
|
||||
gem 'rbtrace', require: false, platform: :mri
|
||||
gem 'gc_tracer', require: false, platform: :mri
|
||||
|
||||
# required for feed importing and embedding
|
||||
gem 'ruby-readability', require: false
|
||||
|
||||
gem 'stackprof', require: false, platform: :mri
|
||||
gem 'memory_profiler', require: false, platform: :mri
|
||||
|
||||
gem 'cppjieba_rb', require: false
|
||||
|
||||
gem 'lograge', require: false
|
||||
gem 'logstash-event', require: false
|
||||
gem 'logstash-logger', require: false
|
||||
gem 'logster'
|
||||
|
||||
# NOTE: later versions of sassc are causing a segfault, possibly dependent on processer architecture
|
||||
# and until resolved should be locked at 2.0.1
|
||||
gem 'sassc', '2.0.1', require: false
|
||||
gem "sassc-rails"
|
||||
|
||||
gem 'rotp', require: false
|
||||
|
||||
gem 'rqrcode'
|
||||
|
||||
gem 'rubyzip', require: false
|
||||
|
||||
gem 'sshkey', require: false
|
||||
|
||||
gem 'rchardet', require: false
|
||||
gem 'lz4-ruby', require: false, platform: :ruby
|
||||
|
||||
if ENV["IMPORT"] == "1"
|
||||
gem 'mysql2'
|
||||
gem 'redcarpet'
|
||||
|
||||
# NOTE: in import mode the version of sqlite can matter a lot, so we stick it to a specific one
|
||||
gem 'sqlite3', '~> 1.3', '>= 1.3.13'
|
||||
gem 'ruby-bbcode-to-md', git: 'https://github.com/nlalonde/ruby-bbcode-to-md'
|
||||
gem 'reverse_markdown'
|
||||
gem 'tiny_tds'
|
||||
gem 'csv'
|
||||
end
|
||||
|
||||
gem 'webpush', require: false
|
||||
gem 'colored2', require: false
|
||||
gem 'maxminddb'
|
||||
|
||||
gem 'rails_failover', require: false
|
561
pkgs/servers/web-apps/discourse/rubyEnv/Gemfile.lock
Normal file
561
pkgs/servers/web-apps/discourse/rubyEnv/Gemfile.lock
Normal file
@ -0,0 +1,561 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
actionmailer (6.0.3.3)
|
||||
actionpack (= 6.0.3.3)
|
||||
actionview (= 6.0.3.3)
|
||||
activejob (= 6.0.3.3)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
actionpack (6.0.3.3)
|
||||
actionview (= 6.0.3.3)
|
||||
activesupport (= 6.0.3.3)
|
||||
rack (~> 2.0, >= 2.0.8)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||
actionview (6.0.3.3)
|
||||
activesupport (= 6.0.3.3)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
||||
actionview_precompiler (0.2.3)
|
||||
actionview (>= 6.0.a)
|
||||
active_model_serializers (0.8.4)
|
||||
activemodel (>= 3.0)
|
||||
activejob (6.0.3.3)
|
||||
activesupport (= 6.0.3.3)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (6.0.3.3)
|
||||
activesupport (= 6.0.3.3)
|
||||
activerecord (6.0.3.3)
|
||||
activemodel (= 6.0.3.3)
|
||||
activesupport (= 6.0.3.3)
|
||||
activesupport (6.0.3.3)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 0.7, < 2)
|
||||
minitest (~> 5.1)
|
||||
tzinfo (~> 1.1)
|
||||
zeitwerk (~> 2.2, >= 2.2.2)
|
||||
addressable (2.7.0)
|
||||
public_suffix (>= 2.0.2, < 5.0)
|
||||
annotate (3.1.1)
|
||||
activerecord (>= 3.2, < 7.0)
|
||||
rake (>= 10.4, < 14.0)
|
||||
ast (2.4.1)
|
||||
aws-eventstream (1.1.0)
|
||||
aws-partitions (1.390.0)
|
||||
aws-sdk-core (3.109.2)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
aws-partitions (~> 1, >= 1.239.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
jmespath (~> 1.0)
|
||||
aws-sdk-kms (1.39.0)
|
||||
aws-sdk-core (~> 3, >= 3.109.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-s3 (1.83.2)
|
||||
aws-sdk-core (~> 3, >= 3.109.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sdk-sns (1.35.0)
|
||||
aws-sdk-core (~> 3, >= 3.109.0)
|
||||
aws-sigv4 (~> 1.1)
|
||||
aws-sigv4 (1.2.2)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
barber (0.12.2)
|
||||
ember-source (>= 1.0, < 3.1)
|
||||
execjs (>= 1.2, < 3)
|
||||
better_errors (2.9.1)
|
||||
coderay (>= 1.0.0)
|
||||
erubi (>= 1.0.0)
|
||||
rack (>= 0.9.0)
|
||||
binding_of_caller (0.8.0)
|
||||
debug_inspector (>= 0.0.1)
|
||||
bootsnap (1.5.1)
|
||||
msgpack (~> 1.0)
|
||||
builder (3.2.4)
|
||||
bullet (6.1.0)
|
||||
activesupport (>= 3.0.0)
|
||||
uniform_notifier (~> 1.11)
|
||||
byebug (11.1.3)
|
||||
cbor (0.5.9.6)
|
||||
certified (1.0.0)
|
||||
chunky_png (1.3.14)
|
||||
coderay (1.1.3)
|
||||
colored2 (3.1.2)
|
||||
concurrent-ruby (1.1.7)
|
||||
connection_pool (2.2.3)
|
||||
cose (1.2.0)
|
||||
cbor (~> 0.5.9)
|
||||
openssl-signature_algorithm (~> 1.0)
|
||||
cppjieba_rb (0.3.3)
|
||||
crack (0.4.4)
|
||||
crass (1.0.6)
|
||||
css_parser (1.7.1)
|
||||
addressable
|
||||
debug_inspector (0.0.3)
|
||||
diff-lcs (1.4.4)
|
||||
diffy (3.4.0)
|
||||
discourse-ember-rails (0.18.6)
|
||||
active_model_serializers
|
||||
ember-data-source (>= 1.0.0.beta.5)
|
||||
ember-handlebars-template (>= 0.1.1, < 1.0)
|
||||
ember-source (>= 1.1.0)
|
||||
jquery-rails (>= 1.0.17)
|
||||
railties (>= 3.1)
|
||||
discourse-ember-source (3.12.2.2)
|
||||
discourse-fonts (0.0.5)
|
||||
discourse_image_optim (0.26.2)
|
||||
exifr (~> 1.2, >= 1.2.2)
|
||||
fspath (~> 3.0)
|
||||
image_size (~> 1.5)
|
||||
in_threads (~> 1.3)
|
||||
progress (~> 3.0, >= 3.0.1)
|
||||
docile (1.3.2)
|
||||
email_reply_trimmer (0.1.13)
|
||||
ember-data-source (3.0.2)
|
||||
ember-source (>= 2, < 3.0)
|
||||
ember-handlebars-template (0.8.0)
|
||||
barber (>= 0.11.0)
|
||||
sprockets (>= 3.3, < 4.1)
|
||||
ember-source (2.18.2)
|
||||
erubi (1.10.0)
|
||||
excon (0.78.0)
|
||||
execjs (2.7.0)
|
||||
exifr (1.3.9)
|
||||
fabrication (2.21.1)
|
||||
fakeweb (1.3.0)
|
||||
faraday (1.1.0)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
ruby2_keywords
|
||||
fast_blank (1.0.0)
|
||||
fast_xs (0.8.0)
|
||||
fastimage (2.2.0)
|
||||
ffi (1.13.1)
|
||||
flamegraph (0.9.5)
|
||||
fspath (3.1.2)
|
||||
gc_tracer (1.5.1)
|
||||
globalid (0.4.2)
|
||||
activesupport (>= 4.2.0)
|
||||
guess_html_encoding (0.0.11)
|
||||
hashdiff (1.0.1)
|
||||
hashie (4.1.0)
|
||||
highline (2.0.3)
|
||||
hkdf (0.3.0)
|
||||
htmlentities (4.3.4)
|
||||
http_accept_language (2.1.1)
|
||||
i18n (1.8.5)
|
||||
concurrent-ruby (~> 1.0)
|
||||
image_size (1.5.0)
|
||||
in_threads (1.5.4)
|
||||
jmespath (1.4.0)
|
||||
jquery-rails (4.4.0)
|
||||
rails-dom-testing (>= 1, < 3)
|
||||
railties (>= 4.2.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
json (2.3.1)
|
||||
json-schema (2.8.1)
|
||||
addressable (>= 2.4)
|
||||
jwt (2.2.2)
|
||||
kgio (2.11.3)
|
||||
libv8 (8.4.255.0)
|
||||
listen (3.3.1)
|
||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||
rb-inotify (~> 0.9, >= 0.9.10)
|
||||
lograge (0.11.2)
|
||||
actionpack (>= 4)
|
||||
activesupport (>= 4)
|
||||
railties (>= 4)
|
||||
request_store (~> 1.0)
|
||||
logstash-event (1.2.02)
|
||||
logstash-logger (0.26.1)
|
||||
logstash-event (~> 1.2)
|
||||
logster (2.9.4)
|
||||
loofah (2.8.0)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.5.9)
|
||||
lru_redux (1.1.0)
|
||||
lz4-ruby (0.3.3)
|
||||
mail (2.7.1)
|
||||
mini_mime (>= 0.1.1)
|
||||
maxminddb (0.1.22)
|
||||
memory_profiler (0.9.14)
|
||||
message_bus (3.3.4)
|
||||
rack (>= 1.1.3)
|
||||
method_source (1.0.0)
|
||||
mini_mime (1.0.2)
|
||||
mini_portile2 (2.4.0)
|
||||
mini_racer (0.3.1)
|
||||
libv8 (~> 8.4.255)
|
||||
mini_scheduler (0.12.3)
|
||||
sidekiq
|
||||
mini_sql (0.3)
|
||||
mini_suffix (0.3.0)
|
||||
ffi (~> 1.9)
|
||||
minitest (5.14.2)
|
||||
mocha (1.11.2)
|
||||
mock_redis (0.26.0)
|
||||
msgpack (1.3.3)
|
||||
multi_json (1.15.0)
|
||||
multi_xml (0.6.0)
|
||||
multipart-post (2.1.1)
|
||||
mustache (1.1.1)
|
||||
nio4r (2.5.4)
|
||||
nokogiri (1.10.10)
|
||||
mini_portile2 (~> 2.4.0)
|
||||
nokogumbo (2.0.2)
|
||||
nokogiri (~> 1.8, >= 1.8.4)
|
||||
oauth (0.5.4)
|
||||
oauth2 (1.4.4)
|
||||
faraday (>= 0.8, < 2.0)
|
||||
jwt (>= 1.0, < 3.0)
|
||||
multi_json (~> 1.3)
|
||||
multi_xml (~> 0.5)
|
||||
rack (>= 1.2, < 3)
|
||||
oj (3.10.16)
|
||||
omniauth (1.9.1)
|
||||
hashie (>= 3.4.6)
|
||||
rack (>= 1.6.2, < 3)
|
||||
omniauth-facebook (8.0.0)
|
||||
omniauth-oauth2 (~> 1.2)
|
||||
omniauth-github (1.4.0)
|
||||
omniauth (~> 1.5)
|
||||
omniauth-oauth2 (>= 1.4.0, < 2.0)
|
||||
omniauth-google-oauth2 (0.8.0)
|
||||
jwt (>= 2.0)
|
||||
omniauth (>= 1.1.1)
|
||||
omniauth-oauth2 (>= 1.6)
|
||||
omniauth-oauth (1.1.0)
|
||||
oauth
|
||||
omniauth (~> 1.0)
|
||||
omniauth-oauth2 (1.7.0)
|
||||
oauth2 (~> 1.4)
|
||||
omniauth (~> 1.9)
|
||||
omniauth-twitter (1.4.0)
|
||||
omniauth-oauth (~> 1.1)
|
||||
rack
|
||||
onebox (2.2.1)
|
||||
addressable (~> 2.7.0)
|
||||
htmlentities (~> 4.3)
|
||||
multi_json (~> 1.11)
|
||||
mustache
|
||||
nokogiri (~> 1.7)
|
||||
sanitize
|
||||
openssl-signature_algorithm (1.0.0)
|
||||
optimist (3.0.1)
|
||||
parallel (1.20.1)
|
||||
parallel_tests (3.4.0)
|
||||
parallel
|
||||
parser (2.7.2.0)
|
||||
ast (~> 2.4.1)
|
||||
pg (1.2.3)
|
||||
progress (3.5.2)
|
||||
pry (0.13.1)
|
||||
coderay (~> 1.1)
|
||||
method_source (~> 1.0)
|
||||
pry-byebug (3.9.0)
|
||||
byebug (~> 11.0)
|
||||
pry (~> 0.13.0)
|
||||
pry-rails (0.3.9)
|
||||
pry (>= 0.10.4)
|
||||
public_suffix (4.0.6)
|
||||
puma (5.0.4)
|
||||
nio4r (~> 2.0)
|
||||
r2 (0.2.7)
|
||||
rack (2.2.3)
|
||||
rack-mini-profiler (2.2.0)
|
||||
rack (>= 1.2.0)
|
||||
rack-protection (2.1.0)
|
||||
rack
|
||||
rack-test (1.1.0)
|
||||
rack (>= 1.0, < 3)
|
||||
rails-dom-testing (2.0.3)
|
||||
activesupport (>= 4.2.0)
|
||||
nokogiri (>= 1.6)
|
||||
rails-html-sanitizer (1.3.0)
|
||||
loofah (~> 2.3)
|
||||
rails_failover (0.6.2)
|
||||
activerecord (~> 6.0)
|
||||
concurrent-ruby
|
||||
railties (~> 6.0)
|
||||
rails_multisite (2.5.0)
|
||||
activerecord (> 5.0, < 7)
|
||||
railties (> 5.0, < 7)
|
||||
railties (6.0.3.3)
|
||||
actionpack (= 6.0.3.3)
|
||||
activesupport (= 6.0.3.3)
|
||||
method_source
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.20.3, < 2.0)
|
||||
rainbow (3.0.0)
|
||||
raindrops (0.19.1)
|
||||
rake (13.0.1)
|
||||
rb-fsevent (0.10.4)
|
||||
rb-inotify (0.10.1)
|
||||
ffi (~> 1.0)
|
||||
rbtrace (0.4.14)
|
||||
ffi (>= 1.0.6)
|
||||
msgpack (>= 0.4.3)
|
||||
optimist (>= 3.0.0)
|
||||
rchardet (1.8.0)
|
||||
redis (4.2.5)
|
||||
redis-namespace (1.8.0)
|
||||
redis (>= 3.0.4)
|
||||
regexp_parser (2.0.0)
|
||||
request_store (1.5.0)
|
||||
rack (>= 1.4)
|
||||
rexml (3.2.4)
|
||||
rinku (2.0.6)
|
||||
rotp (6.2.0)
|
||||
rqrcode (1.1.2)
|
||||
chunky_png (~> 1.0)
|
||||
rqrcode_core (~> 0.1)
|
||||
rqrcode_core (0.1.2)
|
||||
rspec (3.10.0)
|
||||
rspec-core (~> 3.10.0)
|
||||
rspec-expectations (~> 3.10.0)
|
||||
rspec-mocks (~> 3.10.0)
|
||||
rspec-core (3.10.0)
|
||||
rspec-support (~> 3.10.0)
|
||||
rspec-expectations (3.10.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.10.0)
|
||||
rspec-html-matchers (0.9.4)
|
||||
nokogiri (~> 1)
|
||||
rspec (>= 3.0.0.a, < 4)
|
||||
rspec-mocks (3.10.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.10.0)
|
||||
rspec-rails (4.0.1)
|
||||
actionpack (>= 4.2)
|
||||
activesupport (>= 4.2)
|
||||
railties (>= 4.2)
|
||||
rspec-core (~> 3.9)
|
||||
rspec-expectations (~> 3.9)
|
||||
rspec-mocks (~> 3.9)
|
||||
rspec-support (~> 3.9)
|
||||
rspec-support (3.10.0)
|
||||
rswag-specs (2.3.1)
|
||||
activesupport (>= 3.1, < 7.0)
|
||||
json-schema (~> 2.2)
|
||||
railties (>= 3.1, < 7.0)
|
||||
rtlit (0.0.5)
|
||||
rubocop (1.4.2)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 2.7.1.5)
|
||||
rainbow (>= 2.2.2, < 4.0)
|
||||
regexp_parser (>= 1.8)
|
||||
rexml
|
||||
rubocop-ast (>= 1.1.1)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 1.4.0, < 2.0)
|
||||
rubocop-ast (1.2.0)
|
||||
parser (>= 2.7.1.5)
|
||||
rubocop-discourse (2.4.1)
|
||||
rubocop (>= 1.1.0)
|
||||
rubocop-rspec (>= 2.0.0)
|
||||
rubocop-rspec (2.0.0)
|
||||
rubocop (~> 1.0)
|
||||
rubocop-ast (>= 1.1.0)
|
||||
ruby-prof (1.4.2)
|
||||
ruby-progressbar (1.10.1)
|
||||
ruby-readability (0.7.0)
|
||||
guess_html_encoding (>= 0.0.4)
|
||||
nokogiri (>= 1.6.0)
|
||||
ruby2_keywords (0.0.2)
|
||||
rubyzip (2.3.0)
|
||||
sanitize (5.2.1)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.8.0)
|
||||
nokogumbo (~> 2.0)
|
||||
sassc (2.0.1)
|
||||
ffi (~> 1.9)
|
||||
rake
|
||||
sassc-rails (2.1.2)
|
||||
railties (>= 4.0.0)
|
||||
sassc (>= 2.0)
|
||||
sprockets (> 3.0)
|
||||
sprockets-rails
|
||||
tilt
|
||||
seed-fu (2.3.9)
|
||||
activerecord (>= 3.1)
|
||||
activesupport (>= 3.1)
|
||||
shoulda-matchers (4.4.1)
|
||||
activesupport (>= 4.2.0)
|
||||
sidekiq (6.1.2)
|
||||
connection_pool (>= 2.2.2)
|
||||
rack (~> 2.0)
|
||||
redis (>= 4.2.0)
|
||||
simplecov (0.20.0)
|
||||
docile (~> 1.1)
|
||||
simplecov-html (~> 0.11)
|
||||
simplecov_json_formatter (~> 0.1)
|
||||
simplecov-html (0.12.3)
|
||||
simplecov_json_formatter (0.1.2)
|
||||
sprockets (3.7.2)
|
||||
concurrent-ruby (~> 1.0)
|
||||
rack (> 1, < 3)
|
||||
sprockets-rails (3.2.2)
|
||||
actionpack (>= 4.0)
|
||||
activesupport (>= 4.0)
|
||||
sprockets (>= 3.0.0)
|
||||
sshkey (2.0.0)
|
||||
stackprof (0.2.16)
|
||||
test-prof (0.12.2)
|
||||
thor (1.0.1)
|
||||
thread_safe (0.3.6)
|
||||
tilt (2.0.10)
|
||||
tzinfo (1.2.8)
|
||||
thread_safe (~> 0.1)
|
||||
uglifier (4.2.0)
|
||||
execjs (>= 0.3.0, < 3)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.7.7)
|
||||
unicode-display_width (1.7.0)
|
||||
unicorn (5.7.0)
|
||||
kgio (~> 2.6)
|
||||
raindrops (~> 0.7)
|
||||
uniform_notifier (1.13.0)
|
||||
webmock (3.10.0)
|
||||
addressable (>= 2.3.6)
|
||||
crack (>= 0.3.2)
|
||||
hashdiff (>= 0.4.0, < 2.0.0)
|
||||
webpush (1.1.0)
|
||||
hkdf (~> 0.2)
|
||||
jwt (~> 2.0)
|
||||
xorcist (1.1.2)
|
||||
yaml-lint (0.0.10)
|
||||
zeitwerk (2.4.1)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
actionmailer (= 6.0.3.3)
|
||||
actionpack (= 6.0.3.3)
|
||||
actionview (= 6.0.3.3)
|
||||
actionview_precompiler
|
||||
active_model_serializers (~> 0.8.3)
|
||||
activemodel (= 6.0.3.3)
|
||||
activerecord (= 6.0.3.3)
|
||||
activesupport (= 6.0.3.3)
|
||||
addressable
|
||||
annotate
|
||||
aws-sdk-s3
|
||||
aws-sdk-sns
|
||||
barber
|
||||
better_errors
|
||||
binding_of_caller
|
||||
bootsnap
|
||||
bullet
|
||||
byebug
|
||||
cbor
|
||||
certified
|
||||
colored2
|
||||
cose
|
||||
cppjieba_rb
|
||||
css_parser
|
||||
diffy
|
||||
discourse-ember-rails (= 0.18.6)
|
||||
discourse-ember-source (~> 3.12.2)
|
||||
discourse-fonts
|
||||
discourse_image_optim
|
||||
email_reply_trimmer
|
||||
ember-handlebars-template (= 0.8.0)
|
||||
excon
|
||||
execjs
|
||||
fabrication
|
||||
fakeweb
|
||||
fast_blank
|
||||
fast_xs
|
||||
fastimage
|
||||
flamegraph
|
||||
gc_tracer
|
||||
highline
|
||||
htmlentities
|
||||
http_accept_language
|
||||
json
|
||||
listen
|
||||
lograge
|
||||
logstash-event
|
||||
logstash-logger
|
||||
logster
|
||||
lru_redux
|
||||
lz4-ruby
|
||||
mail
|
||||
maxminddb
|
||||
memory_profiler
|
||||
message_bus
|
||||
mini_mime
|
||||
mini_racer
|
||||
mini_scheduler
|
||||
mini_sql
|
||||
mini_suffix
|
||||
minitest
|
||||
mocha
|
||||
mock_redis
|
||||
multi_json
|
||||
mustache
|
||||
nokogiri
|
||||
oj
|
||||
omniauth
|
||||
omniauth-facebook
|
||||
omniauth-github
|
||||
omniauth-google-oauth2
|
||||
omniauth-oauth2
|
||||
omniauth-twitter
|
||||
onebox
|
||||
parallel_tests
|
||||
pg
|
||||
pry-byebug
|
||||
pry-rails
|
||||
puma
|
||||
r2
|
||||
rack
|
||||
rack-mini-profiler
|
||||
rack-protection
|
||||
rails_failover
|
||||
rails_multisite
|
||||
railties (= 6.0.3.3)
|
||||
rake
|
||||
rb-fsevent
|
||||
rbtrace
|
||||
rchardet
|
||||
redis
|
||||
redis-namespace
|
||||
rinku
|
||||
rotp
|
||||
rqrcode
|
||||
rspec
|
||||
rspec-html-matchers
|
||||
rspec-rails
|
||||
rswag-specs
|
||||
rtlit
|
||||
rubocop-discourse
|
||||
ruby-prof
|
||||
ruby-readability
|
||||
rubyzip
|
||||
sassc (= 2.0.1)
|
||||
sassc-rails
|
||||
seed-fu
|
||||
shoulda-matchers
|
||||
sidekiq
|
||||
simplecov
|
||||
sprockets (= 3.7.2)
|
||||
sprockets-rails
|
||||
sshkey
|
||||
stackprof
|
||||
test-prof
|
||||
thor
|
||||
uglifier
|
||||
unf
|
||||
unicorn
|
||||
webmock
|
||||
webpush
|
||||
xorcist
|
||||
yaml-lint
|
||||
|
||||
BUNDLED WITH
|
||||
2.1.4
|
2272
pkgs/servers/web-apps/discourse/rubyEnv/gemset.nix
Normal file
2272
pkgs/servers/web-apps/discourse/rubyEnv/gemset.nix
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,25 @@
|
||||
diff --git a/config/unicorn.conf.rb b/config/unicorn.conf.rb
|
||||
index 373e235b3f..57d4d7a55b 100644
|
||||
--- a/config/unicorn.conf.rb
|
||||
+++ b/config/unicorn.conf.rb
|
||||
@@ -27,18 +27,10 @@ pid (ENV["UNICORN_PID_PATH"] || "#{discourse_path}/tmp/pids/unicorn.pid")
|
||||
|
||||
if ENV["RAILS_ENV"] == "development" || !ENV["RAILS_ENV"]
|
||||
logger Logger.new($stdout)
|
||||
- # we want a longer timeout in dev cause first request can be really slow
|
||||
- timeout (ENV["UNICORN_TIMEOUT"] && ENV["UNICORN_TIMEOUT"].to_i || 60)
|
||||
-else
|
||||
- # By default, the Unicorn logger will write to stderr.
|
||||
- # Additionally, some applications/frameworks log to stderr or stdout,
|
||||
- # so prevent them from going to /dev/null when daemonized here:
|
||||
- stderr_path "#{discourse_path}/log/unicorn.stderr.log"
|
||||
- stdout_path "#{discourse_path}/log/unicorn.stdout.log"
|
||||
- # nuke workers after 30 seconds instead of 60 seconds (the default)
|
||||
- timeout 30
|
||||
end
|
||||
|
||||
+timeout (ENV["UNICORN_TIMEOUT"] && ENV["UNICORN_TIMEOUT"].to_i || 60)
|
||||
+
|
||||
# important for Ruby 2.0
|
||||
preload_app true
|
||||
|
164
pkgs/servers/web-apps/discourse/update.py
Executable file
164
pkgs/servers/web-apps/discourse/update.py
Executable file
@ -0,0 +1,164 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#! nix-shell -i python3 -p bundix bundler nix-update python3 python3Packages.requests python3Packages.click python3Packages.click-log
|
||||
|
||||
import click
|
||||
import click_log
|
||||
import shutil
|
||||
import tempfile
|
||||
import re
|
||||
import logging
|
||||
import subprocess
|
||||
import pathlib
|
||||
from distutils.version import LooseVersion
|
||||
from typing import Iterable
|
||||
|
||||
import requests
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DiscourseRepo:
|
||||
version_regex = re.compile(r'^v\d+\.\d+\.\d+$')
|
||||
def __init__(self, owner: str = 'discourse', repo: str = 'discourse'):
|
||||
self.owner = owner
|
||||
self.repo = repo
|
||||
|
||||
@property
|
||||
def tags(self) -> Iterable[str]:
|
||||
r = requests.get(f'https://api.github.com/repos/{self.owner}/{self.repo}/git/refs/tags').json()
|
||||
tags = [x['ref'].replace('refs/tags/', '') for x in r]
|
||||
|
||||
# filter out versions not matching version_regex
|
||||
versions = list(filter(self.version_regex.match, tags))
|
||||
|
||||
# sort, but ignore v for sorting comparisons
|
||||
versions.sort(key=lambda x: LooseVersion(x.replace('v', '')), reverse=True)
|
||||
return versions
|
||||
|
||||
@staticmethod
|
||||
def rev2version(tag: str) -> str:
|
||||
"""
|
||||
normalize a tag to a version number.
|
||||
This obviously isn't very smart if we don't pass something that looks like a tag
|
||||
:param tag: the tag to normalize
|
||||
:return: a normalized version number
|
||||
"""
|
||||
# strip v prefix
|
||||
return re.sub(r'^v', '', tag)
|
||||
|
||||
def get_file(self, filepath, rev):
|
||||
"""returns file contents at a given rev :param filepath: the path to
|
||||
the file, relative to the repo root :param rev: the rev to
|
||||
fetch at :return:
|
||||
|
||||
"""
|
||||
return requests.get(f'https://raw.githubusercontent.com/{self.owner}/{self.repo}/{rev}/{filepath}').text
|
||||
|
||||
|
||||
def _call_nix_update(pkg, version):
|
||||
"""calls nix-update from nixpkgs root dir"""
|
||||
nixpkgs_path = pathlib.Path(__file__).parent / '../../../../'
|
||||
return subprocess.check_output(['nix-update', pkg, '--version', version], cwd=nixpkgs_path)
|
||||
|
||||
|
||||
def _get_current_package_version(pkg: str):
|
||||
nixpkgs_path = pathlib.Path(__file__).parent / '../../../../'
|
||||
return subprocess.check_output(['nix', 'eval', '--raw', f'nixpkgs.{pkg}.version'], text=True)
|
||||
|
||||
|
||||
def _diff_file(filepath: str, old_version: str, new_version: str):
|
||||
repo = DiscourseRepo()
|
||||
|
||||
current_dir = pathlib.Path(__file__).parent
|
||||
|
||||
old = repo.get_file(filepath, 'v' + old_version)
|
||||
new = repo.get_file(filepath, 'v' + new_version)
|
||||
|
||||
if old == new:
|
||||
click.secho(f'{filepath} is unchanged', fg='green')
|
||||
return
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode='w') as o, tempfile.NamedTemporaryFile(mode='w') as n:
|
||||
o.write(old), n.write(new)
|
||||
width = shutil.get_terminal_size((80, 20)).columns
|
||||
diff_proc = subprocess.run(
|
||||
['diff', '--color=always', f'--width={width}', '-y', o.name, n.name],
|
||||
stdout=subprocess.PIPE,
|
||||
cwd=current_dir,
|
||||
text=True
|
||||
)
|
||||
|
||||
click.secho(f'Diff for {filepath} ({old_version} -> {new_version}):', fg='bright_blue', bold=True)
|
||||
click.echo(diff_proc.stdout + '\n')
|
||||
return
|
||||
|
||||
|
||||
@click_log.simple_verbosity_option(logger)
|
||||
|
||||
|
||||
@click.group()
|
||||
def cli():
|
||||
pass
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.argument('rev', default='latest')
|
||||
@click.option('--reverse/--no-reverse', default=False, help='Print diffs from REV to current.')
|
||||
def print_diffs(rev, reverse):
|
||||
"""Print out diffs for files used as templates for the NixOS module.
|
||||
|
||||
The current package version found in the nixpkgs worktree the
|
||||
script is run from will be used to download the "from" file and
|
||||
REV used to download the "to" file for the diff, unless the
|
||||
'--reverse' flag is specified.
|
||||
|
||||
REV should be the git rev to find changes in ('vX.Y.Z') or
|
||||
'latest'; defaults to 'latest'.
|
||||
|
||||
"""
|
||||
if rev == 'latest':
|
||||
repo = DiscourseRepo()
|
||||
rev = repo.tags[0]
|
||||
|
||||
old_version = _get_current_package_version('discourse')
|
||||
new_version = DiscourseRepo.rev2version(rev)
|
||||
|
||||
if reverse:
|
||||
old_version, new_version = new_version, old_version
|
||||
|
||||
for f in ['config/nginx.sample.conf', 'config/discourse_defaults.conf']:
|
||||
_diff_file(f, old_version, new_version)
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.argument('rev', default='latest')
|
||||
def update(rev):
|
||||
"""Update gem files and version.
|
||||
|
||||
REV should be the git rev to update to ('vX.Y.Z') or 'latest';
|
||||
defaults to 'latest'.
|
||||
|
||||
"""
|
||||
repo = DiscourseRepo()
|
||||
|
||||
if rev == 'latest':
|
||||
rev = repo.tags[0]
|
||||
logger.debug(f"Using rev {rev}")
|
||||
|
||||
version = repo.rev2version(rev)
|
||||
logger.debug(f"Using version {version}")
|
||||
|
||||
rubyenv_dir = pathlib.Path(__file__).parent / "rubyEnv"
|
||||
|
||||
for fn in ['Gemfile.lock', 'Gemfile']:
|
||||
with open(rubyenv_dir / fn, 'w') as f:
|
||||
f.write(repo.get_file(fn, rev))
|
||||
|
||||
subprocess.check_output(['bundle', 'lock'], cwd=rubyenv_dir)
|
||||
subprocess.check_output(['bundix'], cwd=rubyenv_dir)
|
||||
|
||||
_call_nix_update('discourse', repo.rev2version(rev))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
cli()
|
@ -2252,6 +2252,14 @@ in
|
||||
|
||||
discount = callPackage ../tools/text/discount { };
|
||||
|
||||
discourse = callPackage ../servers/web-apps/discourse {
|
||||
ruby = ruby_2_7;
|
||||
};
|
||||
|
||||
discourse-mail-receiver = callPackage ../servers/web-apps/discourse/mail_receiver {
|
||||
ruby = ruby_2_7;
|
||||
};
|
||||
|
||||
discocss = callPackage ../tools/misc/discocss { };
|
||||
|
||||
disfetch = callPackage ../tools/misc/disfetch { };
|
||||
@ -17625,12 +17633,8 @@ in
|
||||
stdenv = gcc6Stdenv;
|
||||
});
|
||||
|
||||
v8_6_x = v8;
|
||||
v8 = callPackage ../development/libraries/v8 {
|
||||
inherit (python2Packages) python;
|
||||
} // lib.optionalAttrs stdenv.isLinux {
|
||||
# doesn't build with gcc7
|
||||
stdenv = gcc6Stdenv;
|
||||
};
|
||||
|
||||
vaapiIntel = callPackage ../development/libraries/vaapi-intel { };
|
||||
|
@ -146,8 +146,8 @@ lib.makeScope pkgs.newScope (self: with self; {
|
||||
|
||||
sha256 = "103nys7zkpi1hifqp9miyl0m1mn07xqshw3sapyz365nb35g5q71";
|
||||
|
||||
buildInputs = [ pkgs.v8_6_x ];
|
||||
configureFlags = [ "--with-v8=${pkgs.v8_6_x}" ];
|
||||
buildInputs = [ pkgs.v8 ];
|
||||
configureFlags = [ "--with-v8=${pkgs.v8}" ];
|
||||
|
||||
meta.maintainers = lib.teams.php.members;
|
||||
meta.broken = true;
|
||||
@ -159,8 +159,8 @@ lib.makeScope pkgs.newScope (self: with self; {
|
||||
|
||||
sha256 = "0g63dyhhicngbgqg34wl91nm3556vzdgkq19gy52gvmqj47rj6rg";
|
||||
|
||||
buildInputs = [ pkgs.v8_6_x ];
|
||||
configureFlags = [ "--with-v8js=${pkgs.v8_6_x}" ];
|
||||
buildInputs = [ pkgs.v8 ];
|
||||
configureFlags = [ "--with-v8js=${pkgs.v8}" ];
|
||||
|
||||
meta.maintainers = lib.teams.php.members;
|
||||
meta.broken = true;
|
||||
|
Loading…
Reference in New Issue
Block a user