Skip to content

Commit 8b94196

Browse files
committed
Nim v2 broke auto-setup due to strict types
1 parent 790afb4 commit 8b94196

File tree

8 files changed

+97
-19
lines changed

8 files changed

+97
-19
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,8 @@ nim c -d:release nimletter
320320

321321
### Option D) Systemd service file
322322
```sh
323+
cp postgres.service ~/.config/systemd/user/
324+
# (the same as below)
323325
cp nimletter.service ~/.config/systemd/user/
324326
podman pull ghcr.io/thomastjdev/nimletter:latest
325327
systemctl --user daemon-reload

nimletter-compose.yaml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ services:
33
postgres:
44
image: docker.io/postgres:17.2-alpine
55
container_name: postgres
6+
restart: unless-stopped
67
environment:
78
POSTGRES_USER: postgres
89
POSTGRES_PASSWORD: postgres
@@ -20,6 +21,10 @@ services:
2021
nimletter:
2122
image: ghcr.io/thomastjdev/nimletter:latest
2223
container_name: nimletter
24+
restart: unless-stopped
25+
depends_on:
26+
postgres:
27+
condition: service_healthy
2328
environment:
2429
PG_HOST: localhost:5432
2530
PG_USER: postgres
@@ -36,8 +41,6 @@ services:
3641
SMTP_MAILSPERSECOND: 1
3742
# Use a random long string - it's part of the route to the webhook
3843
SNS_WEBHOOK_SECRET: secret
39-
volumes:
40-
- ./src/database/db_schema.sql:/home/nimmer/src/database/db_schema.sql
4144
ports:
4245
- "5555:5555"
4346
network_mode: host

nimletter.nimble

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Package
22

3-
version = "0.3.4"
3+
version = "0.3.5"
44
author = "ThomasTJdev"
55
description = "Newsletter"
66
license = "AGPL v3"

postgres.service

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#
2+
# postgres.service for rootless deployment with podman and systemd
3+
#
4+
# Requires:
5+
# - podman
6+
# - systemd
7+
#
8+
# Can be updated with:
9+
# - podman auto-update
10+
# - podman auto-update --dry-run
11+
#
12+
# How to use:
13+
# $ cp postgres.service ~/.config/systemd/user/
14+
# $ podman pull docker.io/postgres:17.2-alpine
15+
# $ systemctl --user start postgres
16+
# $ systemctl --user status postgres
17+
# $ systemctl --user enable postgres
18+
#
19+
20+
[Unit]
21+
Description=Podman postgres.service
22+
Documentation=man:podman-generate-systemd(1)
23+
Wants=network-online.target
24+
After=network-online.target
25+
RequiresMountsFor=%t/containers
26+
27+
[Service]
28+
Environment=PODMAN_SYSTEMD_UNIT=%n
29+
Restart=always
30+
RestartSec=3
31+
TimeoutStopSec=70
32+
ExecStartPre=/bin/rm -f %t/%n.ctr-id
33+
ExecStart=/usr/bin/podman run \
34+
--cidfile=%t/%n.ctr-id \
35+
--cgroups=no-conmon \
36+
--rm \
37+
--sdnotify=conmon \
38+
-d \
39+
--replace \
40+
--name postgres \
41+
--init \
42+
--network host \
43+
--label io.containers.autoupdate=registry \
44+
--log-driver journald \
45+
--log-opt tag=postgres \
46+
--env POSTGRES_USER=postgres \
47+
--env POSTGRES_PASSWORD=postgres \
48+
--env POSTGRES_DB=nimletter_db \
49+
-v postgres_data:/var/lib/postgresql/data \
50+
-p 5432:5432 \
51+
docker.io/postgres:17.2-alpine
52+
ExecStop=/usr/bin/podman stop \
53+
--ignore \
54+
--cidfile=%t/%n.ctr-id
55+
ExecStopPost=/usr/bin/podman rm \
56+
-f \
57+
--ignore \
58+
--cidfile=%t/%n.ctr-id
59+
Type=notify
60+
NotifyAccess=all
61+
62+
[Install]
63+
WantedBy=multi-user.target default.target

src/database/database_connection.nim

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ else:
2222
echo "PostgreSQL: connecting ..."
2323
let
2424
pgHost = getEnv("PG_HOST", "localhost")
25-
pgUser* = getEnv("PG_USER", "nimletter")
26-
pgPassword* = getEnv("PG_PASSWORD", "nimletter")
25+
pgUser* = getEnv("PG_USER", "postgres")
26+
pgPassword* = getEnv("PG_PASSWORD", "postgres")
2727
pgDatabase* = getEnv("PG_DATABASE", "nimletter_db")
2828
pgWorkers = getEnv("PG_WORKERS", "3").parseInt()
2929
pg* = newPostgresPool(pgWorkers, pgHost, pgUser, pgPassword, pgDatabase)

src/database/database_setup.nim

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ GRANT ALL PRIVILEGES ON DATABASE $1 TO $2;
2525

2626

2727
proc databaseCreate*() =
28-
let dbSchema = readFile("./src/database/db_schema.sql")
28+
when defined(release):
29+
let dbSchema = readFile("./db_schema.sql")
30+
else:
31+
let dbSchema = readFile("./src/database/db_schema.sql")
2932

3033
let dbSplit = dbSchema.split(";\n")
3134

@@ -35,11 +38,15 @@ proc databaseCreate*() =
3538
continue
3639

3740
try:
41+
echo "Executing SQL: " & sqlItem
3842
exec(conn, sql(sqlItem.strip() & ";"))
3943
except:
4044
echo "Error executing SQL: " & sqlItem
4145
echo "Got this error code: " & getCurrentExceptionMsg()
4246

47+
exec(conn, sql("INSERT INTO mails (name, identifier, category, contentHTML, contentEditor, subject) VALUES (?, ?, ?, ?, ?, ?);"), "Double Opt-In", "double-opt-in", "template", "<div style=\"background-color:#F5F5F5;color:#262626;font-family:&quot;Helvetica Neue&quot;, &quot;Arial Nova&quot;, &quot;Nimbus Sans&quot;, Arial, sans-serif;font-size:16px;font-weight:400;letter-spacing:0.15008px;line-height:1.5;margin:0;padding:32px 0;min-height:100%;width:100%\"><table align=\"center\" width=\"100%\" style=\"margin:0 auto;max-width:600px;background-color:#FFFFFF\" role=\"presentation\" cellSpacing=\"0\" cellPadding=\"0\" border=\"0\"><tbody><tr style=\"width:100%\"><td><div style=\"padding:24px 32px 24px 32px\"><h2 style=\"font-weight:bold;margin:0;font-size:24px;padding:16px 24px 16px 24px\">Hi {{ firstname | there }}</h2><div style=\"font-weight:normal;padding:16px 24px 16px 24px\">We’re glad to have you with us at {{ pagename }}!</div><div style=\"font-weight:normal;padding:16px 24px 16px 24px\">To finish subscribing to our emails, just click the button below. You can unsubscribe anytime if you change your mind.</div><div style=\"text-align:center;padding:16px 24px 16px 24px\"><a href=\"{{ hostname }}/subscribe/optin?contactUUID={{ contactUUID }}\" style=\"color:#FFFFFF;font-size:16px;font-weight:bold;background-color:#4F46E5;border-radius:4px;display:block;padding:12px 20px;text-decoration:none\" target=\"_blank\"><span><!--[if mso]><i style=\"letter-spacing: 20px;mso-font-width:-100%;mso-text-raise:30\" hidden>&nbsp;</i><![endif]--></span><span>Subscribe!</span><span><!--[if mso]><i style=\"letter-spacing: 20px;mso-font-width:-100%\" hidden>&nbsp;</i><![endif]--></span></a></div></div></td></tr></tbody></table></div>", "{ \"root\": { \"type\": \"EmailLayout\", \"data\": { \"backdropColor\": \"#F5F5F5\", \"canvasColor\": \"#FFFFFF\", \"textColor\": \"#262626\", \"fontFamily\": \"MODERN_SANS\", \"childrenIds\": [ \"block-1737229372503\" ] } }, \"block-1737229372503\": { \"type\": \"Container\", \"data\": { \"style\": { \"padding\": { \"top\": 24, \"bottom\": 24, \"right\": 32, \"left\": 32 } }, \"props\": { \"childrenIds\": [ \"block-1737229386674\", \"block-1737229395871\", \"block-1737229536738\", \"block-1737229551815\" ] } } }, \"block-1737229386674\": { \"type\": \"Heading\", \"data\": { \"props\": { \"text\": \"Hi {{ firstname | there }}\" }, \"style\": { \"padding\": { \"top\": 16, \"bottom\": 16, \"right\": 24, \"left\": 24 } } } }, \"block-1737229395871\": { \"type\": \"Text\", \"data\": { \"style\": { \"fontWeight\": \"normal\", \"padding\": { \"top\": 16, \"bottom\": 16, \"right\": 24, \"left\": 24 } }, \"props\": { \"text\": \"We’re glad to have you with us at {{ pagename }}!\" } } }, \"block-1737229536738\": { \"type\": \"Text\", \"data\": { \"style\": { \"fontWeight\": \"normal\", \"padding\": { \"top\": 16, \"bottom\": 16, \"right\": 24, \"left\": 24 } }, \"props\": { \"text\": \"To finish subscribing to our emails, just click the button below. You can unsubscribe anytime if you change your mind.\" } } }, \"block-1737229551815\": { \"type\": \"Button\", \"data\": { \"style\": { \"fontWeight\": \"bold\", \"textAlign\": \"center\", \"padding\": { \"top\": 16, \"bottom\": 16, \"right\": 24, \"left\": 24 } }, \"props\": { \"buttonBackgroundColor\": \"#4F46E5\", \"fullWidth\": true, \"text\": \"Subscribe!\", \"url\": \"{{ hostname }}/subscribe/optin?contactUUID={{ contactUUID }}\" } } } }", "Confirm your email address")
48+
49+
exec(conn, sql("INSERT INTO settings (page_name, hostname, optin_email) VALUES (?, ?, ?) ON CONFLICT DO NOTHING;"), "Nimletter, drip it!", "https://nimletter.com", 1)
4350

4451
proc databaseDelete*() =
4552
pg.withConnection conn:

src/database/database_testdata.nim

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,28 +30,28 @@ proc insertTestData*() =
3030
"""))
3131

3232
exec(conn, sql("""
33-
INSERT INTO mails (name, created_at, updated_at, contentHTML, tags, category, editorType, uuid, identifier)
33+
INSERT INTO mails (name, contentHTML, tags, category, editorType, identifier)
3434
VALUES
35-
('Welcome Email', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 'Hey {{ firstname }}, Welcome to our service!', ARRAY['welcome', 'intro'], 'informational', 'html', uuid_generate_v4(), 'welcome-email'),
36-
('Follow-up Email', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 'Here is some {{ interest | important }} more information.', ARRAY['followup', 'info'], 'informational', 'html', uuid_generate_v4(), 'followup-email'),
37-
('Anything else?', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 'Anything else you want?', ARRAY['followup', 'info'], 'informational', 'html', uuid_generate_v4(), 'anything-else'),
38-
('Like it, then click', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 'Like it, then click', ARRAY['marketing', 'info'], 'drip', 'html', uuid_generate_v4(), 'like-it-then-click'),
39-
('Wee see you (EmailBuilder)', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 'Wee see you', ARRAY['marketing', 'info'], 'drip', 'emailbuilder', uuid_generate_v4(), 'wee-see-you');
35+
('Welcome Email', 'Hey {{ firstname }}, Welcome to our service!', ARRAY['welcome', 'intro'], 'informational', 'html', 'welcome-email'),
36+
('Follow-up Email', 'Here is some {{ interest | important }} more information.', ARRAY['followup', 'info'], 'informational', 'html', 'followup-email'),
37+
('Anything else', 'Anything else you want', ARRAY['followup', 'info'], 'informational', 'html', 'anything-else'),
38+
('Like it, then click', 'Like it, then click', ARRAY['marketing', 'info'], 'drip', 'html', 'like-it-then-click'),
39+
('Wee see you (EmailBuilder)', 'Wee see you', ARRAY['marketing', 'info'], 'drip', 'emailbuilder', 'wee-see-you');
4040
"""))
4141

4242
exec(conn, sql("""
43-
INSERT INTO flows (name, created_at, updated_at)
43+
INSERT INTO flows (name)
4444
VALUES
45-
('Welcome Flow', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP),
46-
('Click Open Flow', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
45+
('Welcome Flow'),
46+
('Click Open Flow');
4747
"""))
4848

4949
exec(conn, sql("""
5050
INSERT INTO flow_steps (flow_id, mail_id, step_number, trigger_type, delay_minutes, name, subject, created_at)
5151
VALUES
5252
((SELECT id FROM flows WHERE name = 'Welcome Flow'), (SELECT id FROM mails WHERE name = 'Welcome Email'), 1, 'delay', 1, 'Step 1', 'Welcome to our service!', CURRENT_TIMESTAMP),
5353
((SELECT id FROM flows WHERE name = 'Welcome Flow'), (SELECT id FROM mails WHERE name = 'Follow-up Email'), 2, 'delay', 1, 'Step 2', 'Follow-up Information', CURRENT_TIMESTAMP),
54-
((SELECT id FROM flows WHERE name = 'Welcome Flow'), (SELECT id FROM mails WHERE name = 'Anything else?'), 3, 'delay', 1, 'Step 3', 'Anything else subject?', CURRENT_TIMESTAMP),
54+
((SELECT id FROM flows WHERE name = 'Welcome Flow'), (SELECT id FROM mails WHERE name = 'Anything else'), 3, 'delay', 1, 'Step 3', 'Anything else subject', CURRENT_TIMESTAMP),
5555
((SELECT id FROM flows WHERE name = 'Click Open Flow'), (SELECT id FROM mails WHERE name = 'Like it, then click'), 1, 'delay', 0, 'Step 1', 'Like it, then click', CURRENT_TIMESTAMP),
5656
((SELECT id FROM flows WHERE name = 'Click Open Flow'), (SELECT id FROM mails WHERE name = 'Wee see you (EmailBuilder)'), 2, 'click', 0, 'Step 2', 'Wee see you', CURRENT_TIMESTAMP);
5757
"""))

src/database/db_schema.sql

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ CREATE TABLE IF NOT EXISTS mails (
1717
category TEXT, -- Category of the mail (e.g., promotional, informational)
1818
uuid UUID NOT NULL DEFAULT uuid_generate_v4() -- Unique identifier
1919
);
20-
INSERT INTO mails (name, identifier, category, contentHTML, contentEditor, subject) VALUES ('Double Opt-In', 'double-opt-in', 'template', '<div style="background-color:#F5F5F5;color:#262626;font-family:&quot;Helvetica Neue&quot;, &quot;Arial Nova&quot;, &quot;Nimbus Sans&quot;, Arial, sans-serif;font-size:16px;font-weight:400;letter-spacing:0.15008px;line-height:1.5;margin:0;padding:32px 0;min-height:100%;width:100%"><table align="center" width="100%" style="margin:0 auto;max-width:600px;background-color:#FFFFFF" role="presentation" cellSpacing="0" cellPadding="0" border="0"><tbody><tr style="width:100%"><td><div style="padding:24px 32px 24px 32px"><h2 style="font-weight:bold;margin:0;font-size:24px;padding:16px 24px 16px 24px">Hi {{ firstname | there }}</h2><div style="font-weight:normal;padding:16px 24px 16px 24px">We’re glad to have you with us at {{ pagename }}!</div><div style="font-weight:normal;padding:16px 24px 16px 24px">To finish subscribing to our emails, just click the button below. You can unsubscribe anytime if you change your mind.</div><div style="text-align:center;padding:16px 24px 16px 24px"><a href="{{ hostname }}/subscribe/optin?contactUUID={{ contactUUID }}" style="color:#FFFFFF;font-size:16px;font-weight:bold;background-color:#4F46E5;border-radius:4px;display:block;padding:12px 20px;text-decoration:none" target="_blank"><span><!--[if mso]><i style="letter-spacing: 20px;mso-font-width:-100%;mso-text-raise:30" hidden>&nbsp;</i><![endif]--></span><span>Subscribe!</span><span><!--[if mso]><i style="letter-spacing: 20px;mso-font-width:-100%" hidden>&nbsp;</i><![endif]--></span></a></div></div></td></tr></tbody></table></div>', '{ "root": { "type": "EmailLayout", "data": { "backdropColor": "#F5F5F5", "canvasColor": "#FFFFFF", "textColor": "#262626", "fontFamily": "MODERN_SANS", "childrenIds": [ "block-1737229372503" ] } }, "block-1737229372503": { "type": "Container", "data": { "style": { "padding": { "top": 24, "bottom": 24, "right": 32, "left": 32 } }, "props": { "childrenIds": [ "block-1737229386674", "block-1737229395871", "block-1737229536738", "block-1737229551815" ] } } }, "block-1737229386674": { "type": "Heading", "data": { "props": { "text": "Hi {{ firstname | there }}" }, "style": { "padding": { "top": 16, "bottom": 16, "right": 24, "left": 24 } } } }, "block-1737229395871": { "type": "Text", "data": { "style": { "fontWeight": "normal", "padding": { "top": 16, "bottom": 16, "right": 24, "left": 24 } }, "props": { "text": "We’re glad to have you with us at {{ pagename }}!" } } }, "block-1737229536738": { "type": "Text", "data": { "style": { "fontWeight": "normal", "padding": { "top": 16, "bottom": 16, "right": 24, "left": 24 } }, "props": { "text": "To finish subscribing to our emails, just click the button below. You can unsubscribe anytime if you change your mind." } } }, "block-1737229551815": { "type": "Button", "data": { "style": { "fontWeight": "bold", "textAlign": "center", "padding": { "top": 16, "bottom": 16, "right": 24, "left": 24 } }, "props": { "buttonBackgroundColor": "#4F46E5", "fullWidth": true, "text": "Subscribe!", "url": "{{ hostname }}/subscribe/optin?contactUUID={{ contactUUID }}" } } } }', 'Confirm your email address') ON CONFLICT DO NOTHING;
20+
2121

2222
-- Table for flows (campaigns or automated sequences)
2323
CREATE TABLE IF NOT EXISTS flows (
@@ -66,7 +66,7 @@ CREATE TABLE IF NOT EXISTS contacts (
6666
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
6767
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
6868
requires_double_opt_in BOOLEAN DEFAULT TRUE, -- Flag for double opt-in status
69-
double_opt_in_sent BOOLEAN DEFAULT FALSE, -- Has initial double opt-in email been sent?
69+
double_opt_in_sent BOOLEAN DEFAULT FALSE, -- Has initial double opt-in email been sent
7070
double_opt_in BOOLEAN DEFAULT FALSE, -- Flag for double opt-in status
7171
double_opt_in_data TEXT, -- IP address, timestamp, etc.
7272
pending_lists INT[], -- Pending lists to be signed up to until double_opt_in is complete
@@ -158,7 +158,7 @@ CREATE TABLE IF NOT EXISTS settings (
158158
optin_email INT NOT NULL REFERENCES mails(id),
159159
logo_url TEXT
160160
);
161-
INSERT INTO settings (page_name, hostname, optin_email) VALUES ('Nimletter, drip it!', 'https://nimletter.com', 1) ON CONFLICT DO NOTHING;
161+
162162

163163
-- Table for smtp
164164
CREATE TABLE IF NOT EXISTS smtp_settings (
@@ -223,5 +223,8 @@ CREATE TABLE IF NOT EXISTS sessions (
223223

224224
-- Indexes for efficient querying
225225
CREATE INDEX IF NOT EXISTS idx_pending_emails_scheduled_for ON pending_emails (scheduled_for);
226+
226227
CREATE INDEX IF NOT EXISTS idx_email_opens_user_id ON email_opens (user_id);
228+
227229
CREATE INDEX IF NOT EXISTS idx_email_clicks_user_id ON email_clicks (user_id);
230+

0 commit comments

Comments
 (0)