-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathREADME.org
252 lines (174 loc) · 8.23 KB
/
README.org
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
* Great Problems
** Editor Screenshot
#+html: <p align="center"><img src="assets/problem_editor_screenshot.png" /></p>
** Stages
#+html: <p align="center"><img src="assets/great_problems_architecture_trim.drawio.svg" /></p>
** Installing
To install and run this project:
- Install [[https://github.com/obsidiansystems/obelisk][Obelisk]]
- Clone this project
- Set up the database (see below)
- Go into the project directory and run ~ob run~. This will compile the project using GHC and run it locally on http://localhost:8000/.
*** Setting up the database (Ubuntu/Debian)
#+BEGIN_SRC
$ sudo apt install postgresql postgresql-contrib
$ sudo -u postgres psql
postgres=# create database great_problems;
postgres=# create user great_problems with encrypted password 'mypass';
postgres=# grant all privileges on database great_problems to great_problems;
postgres=# \c great_problems
great_problems=# CREATE EXTENSION citext;
great_problems=# \q
$ cp config/backend/db.env.example config/backend/db.env
#+END_SRC
Edit the environment variables in ~config/backend/db.env~ with the database connection settings.
Environment variables and their defaults:
#+BEGIN_SRC
DB_HOST=localhost
DB_PORT=5432
DB_USER=great_problems
DB_PASSWORD=mypass
DB_NAME=great_problems
#+END_SRC
To setup the database, use the repl:
#+BEGIN_SRC
$ ob repl
*Backend Obelisk.Run Frontend Backend> Database.migrate
#+END_SRC
This will run all the migrations in backend/src/Database/Migrations and insert the seeds defined in module Database.Seeds.
To reset the migrations, use the repl:
#+BEGIN_SRC
$ ob repl
*Backend Obelisk.Run Frontend Backend> Database.resetMigrations
#+END_SRC
This will reset the migration tracking (and not run any migrations).
To manually add a user, use the repl:
#+BEGIN_SRC
$ ob repl
*Backend Obelisk.Run Frontend Backend> Database.addUser "Gertrude Powell" "[email protected]" "mypassword123" "Basic"
#+END_SRC
This will add a verified user to the database and print the result.
*** Mailgun config
#+BEGIN_SRC
$ cp config/backend/email.env.example config/backend/email.env
#+END_SRC
Edit the environment variables in ~config/backend/email.env~ with the Mailgun settings.
** Settings
*** Meta settings
This project stores meta settings for special situations that can be configured by administrators.
| Meta setting | Example value | Description |
|------------------------+---------------+-----------------------------------------------------------------------------------------|
| ExampleProblemId | 3 | The ID of an existing problem to be shown as the example on the home page. |
| BasicDuplicateTopicIds | [0,3] | Basic users are only allowed to duplicate problems which belong to these topics. |
** Development
*** Explicit import style
All imports should be qualified except for Global. This helps with code clarity; it is easy to tell where a variable/function comes from (without the use of an IDE). It also allows for local variables and functions to be given meaningful yet short names.
Extra import information is outputted to ~imports/~ (ghc-options: ~-ddump-minimal-imports -dumpdir imports~).
*** Reflex variable naming
Reflex has three main data types: Event, Behavior, and Dynamic. Instead of giving variables of these types special prefixes (e.g., ~evProblemText~) or suffixes (e.g., ~problemTextE~), their type should be clear from context or explicit type signatures (e.g., ~problemText :: Event t Text~).
*** Module management
Remember to add any new modules (*.hs files) to their respective *.cabal file in the ~other-modules~ section. Explicit modules are needed for compilation (but not when running in development, i.e., with ~ob run~).
*** Adding dependencies
Add the dependency to the appropriate .cabal file (frontend.cabal or backend.cabal) in ~build-depends~. Only proceed to the following instructions if the dependency is not in Obelisk's curated list, that is, an error is produced upon ~ob run~ or building.
Add dependency thunk (replace "package-name" with the actual package name):
#+begin_src sh
$ mkdir dep
$ git clone <repo> dep/package-name
$ ob thunk pack dep/package-name
#+end_src
Add package to ~default.nix~:
#+begin_src sh
...
project ./. ({ pkgs, hackGet, ... }: {
...
packages = {
...
package-name = hackGet ./dep/package-name;
};
})
...
#+end_src
To disable running the package tests, put it in the "overrides" section instead, using the existing packages as a guide.
For more information:
- https://www.srid.ca/obelisk-tutorial
- https://github.com/obsidiansystems/obelisk-oauth#add-dependency-thunk
** Deployment
*** Managing the server
After setting up the systemd service (see below), starting and stopping the server can be done with systemd:
#+begin_src sh
systemctl start great-problems
systemctl stop great-problems
systemctl status great-problems
#+end_src
Enable on startup:
#+begin_src sh
systemctl enable great-problems
#+end_src
**** Scripts
Main user is assumed to be named "webserver".
Shell scripts were made for simplifying actions regarding deployment.
- deploy.sh: Stops the server, pulls latest code, rebuilds the app, then starts the server. Logs output to ~/var/log/great-problems/output.log~.
- startserver.sh: Starts the server. Prefer running deploy.sh instead.
- stopserver.sh: Stops the server by killing the process.
If the server is picky about line endings in the shell scripts, use dos2unix.
**** Setting up systemd service
Main user is assumed to be named "webserver".
Create ~/etc/systemd/system/great-problems.service~ with contents:
#+begin_src sh
[Unit]
Description=Great Problems
[Service]
Type=oneshot
RemainAfterExit=yes
User=webserver
ExecStart=/bin/bash /home/webserver/websites/great-problems/deploy.sh
ExecStop=/bin/bash /home/webserver/websites/great-problems/stopserver.sh
[Install]
WantedBy=default.target
#+end_src
*** Logging manually
#+begin_src sh
$ sudo mkdir -p /var/log/great-problems
$ sudo chown -R <username> /var/log/great-problems/
$ ./startserver.sh &>> /var/log/great-problems/output.log
#+end_src
Obelisk's backend exe parameters ~--access-log~ and ~--error-log~ don't seem to work, but we can still capture all the output as above.
*** Building manually
Build the app:
#+begin_src sh
$ nix-build -A exe --no-out-link
#+end_src
Copy the result and run:
#+begin_src sh
$ rm -rf dist
$ mkdir dist
$ ln -s $(nix-build -A exe --no-out-link)/* dist/
$ cp -r config dist
$ nix-shell -A shells.ghc
[nix-shell]$ cd dist
[nix-shell]$ sudo ./backend <parameters>
#+end_src
The importance of ~nix-shell -A shells.ghc~ is to be put into an environment with the external dependencies available (i.e., emacs, problem2tex, ltspice2svg).
*** Enabling SSL
1. Obtain an SSL certificate with Let's Encrypt.
2. Follow the instructions on [[https://www.linode.com/docs/guides/enabling-https-using-certbot-with-nginx-on-ubuntu/][Linode]] using Certbot with Ubuntu, with some modifications:
- No need to install NGINX. Use [[https://eff-certbot.readthedocs.io/en/stable/using.html#standalone][Certbot's standalone plugin]].
- Include the linode domain when registering domains. Full list should look something like: greatproblems.ca, www.greatproblems.ca, li1961-136.members.linode.com
3. Use hooks for restarting the server upon SSL certificate renewal:
#+begin_src sh
$ sudo ln -s ~/websites/great-problems/stopserver.sh /etc/letsencrypt/renewal-hooks/pre/stopserver.sh
$ sudo ln -s ~/websites/great-problems/startserver.sh /etc/letsencrypt/renewal-hooks/post/startserver.sh
#+end_src
4. Test automatic renewal:
#+begin_src sh
$ sudo certbot renew --dry-run
#+end_src
*** Database backup and restore
To backup (includes drop tables statements):
#+begin_src sh
pg_dump --clean --if-exists -U great_problems -h localhost -p 5432 -d great_problems > ~/backups/great_problems_dump.sql
#+end_src
To restore from backup:
#+begin_src sh
pg_restore --clean --if-exists -U great_problems -h localhost -p 5432 -d great_problems < ~/backups/great_problems_dump.sql
#+end_src