···
1
+
# This tests Discourse by:
2
+
# 1. logging in as the admin user
3
+
# 2. sending a private message to the admin user through the API
4
+
# 3. replying to that message via email.
6
+
import ./make-test-python.nix (
9
+
certs = import ./common/acme/server/snakeoil-certs.nix;
10
+
clientDomain = "client.fake.domain";
11
+
discourseDomain = certs.domain;
12
+
adminPassword = "eYAX85qmMJ5GZIHLaXGDAoszD7HSZp5d";
13
+
secretKeyBase = "381f4ac6d8f5e49d804dae72aa9c046431d2f34c656a705c41cd52fed9b4f6f76f51549f0b55db3b8b0dded7a00d6a381ebe9a4367d2d44f5e743af6628b4d42";
15
+
email = "alice@${clientDomain}";
17
+
fullName = "Alice Admin";
18
+
passwordFile = "${pkgs.writeText "admin-pass" adminPassword}";
23
+
meta = with pkgs.lib.maintainers; {
24
+
maintainers = [ talyz ];
30
+
virtualisation.memorySize = 2048;
32
+
imports = [ common/user-account.nix ];
34
+
security.pki.certificateFiles = [
38
+
networking.extraHosts = ''
39
+
127.0.0.1 ${discourseDomain}
40
+
${nodes.client.config.networking.primaryIPAddress} ${clientDomain}
43
+
services.postfix = {
44
+
enableSubmission = true;
45
+
enableSubmissions = true;
46
+
submissionsOptions = {
47
+
smtpd_sasl_auth_enable = "yes";
48
+
smtpd_client_restrictions = "permit";
52
+
environment.systemPackages = [ pkgs.jq ];
54
+
services.discourse = {
57
+
hostname = discourseDomain;
58
+
sslCertificate = "${certs.${discourseDomain}.cert}";
59
+
sslCertificateKey = "${certs.${discourseDomain}.key}";
60
+
secretKeyBaseFile = "${pkgs.writeText "secret-key-base" secretKeyBase}";
62
+
mail.outgoing.serverAddress = clientDomain;
63
+
mail.incoming.enable = true;
66
+
min_post_length = 5;
67
+
min_first_post_length = 5;
68
+
min_personal_message_post_length = 5;
71
+
unicornTimeout = 900;
74
+
networking.firewall.allowedTCPPorts = [ 25 465 ];
80
+
imports = [ common/user-account.nix ];
82
+
security.pki.certificateFiles = [
86
+
networking.extraHosts = ''
87
+
127.0.0.1 ${clientDomain}
88
+
${nodes.discourse.config.networking.primaryIPAddress} ${discourseDomain}
91
+
services.dovecot2 = {
93
+
protocols = [ "imap" ];
94
+
modules = [ pkgs.dovecot_pigeonhole ];
97
+
services.postfix = {
99
+
origin = clientDomain;
100
+
relayDomains = [ clientDomain ];
102
+
compatibility_level = "2";
103
+
smtpd_banner = "ESMTP server";
104
+
myhostname = clientDomain;
105
+
mydestination = clientDomain;
109
+
environment.systemPackages =
111
+
replyToEmail = pkgs.writeScriptBin "reply-to-email" ''
112
+
#!${pkgs.python3.interpreter}
116
+
import email.header
117
+
from email import message_from_bytes
118
+
from email.message import EmailMessage
120
+
with imaplib.IMAP4('localhost') as imap:
121
+
imap.login('alice', 'foobar')
123
+
status, data = imap.search(None, 'ALL')
124
+
assert status == 'OK'
126
+
nums = data[0].split()
127
+
assert len(nums) == 1
129
+
status, msg_data = imap.fetch(nums[0], '(RFC822)')
130
+
assert status == 'OK'
132
+
msg = email.message_from_bytes(msg_data[0][1])
133
+
subject = str(email.header.make_header(email.header.decode_header(msg['Subject'])))
134
+
reply_to = email.header.decode_header(msg['Reply-To'])[0][0]
135
+
message_id = email.header.decode_header(msg['Message-ID'])[0][0]
136
+
date = email.header.decode_header(msg['Date'])[0][0]
138
+
ctx = ssl.create_default_context()
139
+
with smtplib.SMTP_SSL(host='${discourseDomain}', context=ctx) as smtp:
140
+
reply = EmailMessage()
141
+
reply['Subject'] = 'Re: ' + subject
142
+
reply['To'] = reply_to
143
+
reply['From'] = 'alice@${clientDomain}'
144
+
reply['In-Reply-To'] = message_id
145
+
reply['References'] = message_id
146
+
reply['Date'] = date
147
+
reply.set_content("Test reply.")
149
+
smtp.send_message(reply)
155
+
networking.firewall.allowedTCPPorts = [ 25 ];
159
+
testScript = { nodes }:
161
+
request = builtins.toJSON {
162
+
title = "Private message";
163
+
raw = "This is a test message.";
164
+
target_usernames = admin.username;
165
+
archetype = "private_message";
171
+
discourse.wait_for_unit("discourse.service")
172
+
discourse.wait_for_file("/run/discourse/sockets/unicorn.sock")
173
+
discourse.wait_until_succeeds("curl -sS -f https://${discourseDomain}")
175
+
"curl -sS -f https://${discourseDomain}/session/csrf -c cookie -b cookie -H 'Accept: application/json' | jq -r '\"X-CSRF-Token: \" + .csrf' > csrf_token",
176
+
"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}\"'",
177
+
"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}",
180
+
client.wait_for_unit("postfix.service")
181
+
client.wait_for_unit("dovecot2.service")
184
+
"sudo -u discourse discourse-rake api_key:create_master[master] >api_key",
185
+
'curl -sS -f https://${discourseDomain}/posts -X POST -H "Content-Type: application/json" -H "Api-Key: $(<api_key)" -H "Api-Username: system" -d \'${request}\' ',
188
+
client.wait_until_succeeds("reply-to-email")
190
+
discourse.wait_until_succeeds(
191
+
'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'
194
+
'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\' '