+10
-20
src/api.v
+10
-20
src/api.v
···
2
3
import veb
4
import auth
5
-
import entity { Site, User, Post, Like, LikeCache }
6
7
////// Users //////
8
···
27
28
salt := auth.generate_salt()
29
mut user := User{
30
-
username: username
31
-
password: auth.hash_password_with_salt(password, salt)
32
password_salt: salt
33
}
34
···
277
278
@['/api/user/get_name']
279
fn (mut app App) api_user_get_name(mut ctx Context, username string) veb.Result {
280
-
user := app.get_user_by_name(username) or {
281
-
return ctx.server_error('no such user')
282
-
}
283
return ctx.text(user.get_name())
284
}
285
···
311
312
post := Post{
313
author_id: user.id
314
-
title: title
315
-
body: body
316
}
317
318
sql app.db {
···
358
359
@['/api/post/like']
360
fn (mut app App) api_post_like(mut ctx Context, id int) veb.Result {
361
-
user := app.whoami(mut ctx) or {
362
-
return ctx.unauthorized('not logged in')
363
-
}
364
365
-
post := app.get_post_by_id(id) or {
366
-
return ctx.server_error('post does not exist')
367
-
}
368
369
if app.does_user_like_post(user.id, post.id) {
370
sql app.db {
···
405
406
@['/api/post/dislike']
407
fn (mut app App) api_post_dislike(mut ctx Context, id int) veb.Result {
408
-
user := app.whoami(mut ctx) or {
409
-
return ctx.unauthorized('not logged in')
410
-
}
411
412
-
post := app.get_post_by_id(id) or {
413
-
return ctx.server_error('post does not exist')
414
-
}
415
416
if app.does_user_dislike_post(user.id, post.id) {
417
sql app.db {
···
2
3
import veb
4
import auth
5
+
import entity { Like, LikeCache, Post, Site, User }
6
7
////// Users //////
8
···
27
28
salt := auth.generate_salt()
29
mut user := User{
30
+
username: username
31
+
password: auth.hash_password_with_salt(password, salt)
32
password_salt: salt
33
}
34
···
277
278
@['/api/user/get_name']
279
fn (mut app App) api_user_get_name(mut ctx Context, username string) veb.Result {
280
+
user := app.get_user_by_name(username) or { return ctx.server_error('no such user') }
281
return ctx.text(user.get_name())
282
}
283
···
309
310
post := Post{
311
author_id: user.id
312
+
title: title
313
+
body: body
314
}
315
316
sql app.db {
···
356
357
@['/api/post/like']
358
fn (mut app App) api_post_like(mut ctx Context, id int) veb.Result {
359
+
user := app.whoami(mut ctx) or { return ctx.unauthorized('not logged in') }
360
361
+
post := app.get_post_by_id(id) or { return ctx.server_error('post does not exist') }
362
363
if app.does_user_like_post(user.id, post.id) {
364
sql app.db {
···
399
400
@['/api/post/dislike']
401
fn (mut app App) api_post_dislike(mut ctx Context, id int) veb.Result {
402
+
user := app.whoami(mut ctx) or { return ctx.unauthorized('not logged in') }
403
404
+
post := app.get_post_by_id(id) or { return ctx.server_error('post does not exist') }
405
406
if app.does_user_dislike_post(user.id, post.id) {
407
sql app.db {
+12
-14
src/app.v
+12
-14
src/app.v
···
3
import veb
4
import db.pg
5
import auth
6
-
import entity { Site, User, Post, Like, LikeCache }
7
8
pub struct App {
9
veb.StaticHandler
···
13
db pg.DB
14
auth auth.Auth[pg.DB]
15
validators struct {
16
-
pub:
17
username StringValidator
18
password StringValidator
19
nickname StringValidator
···
98
}
99
100
pub fn (app &App) whoami(mut ctx Context) ?User {
101
-
token := ctx.get_cookie('token') or {
102
-
return none
103
-
}.trim_space()
104
if token == '' {
105
return none
106
}
···
133
}
134
135
pub fn (app &App) get_unknown_user() User {
136
-
return User{ username: 'unknown' }
137
}
138
139
pub fn (app &App) logged_in_as(mut ctx Context, id int) bool {
···
204
}
205
206
// cache
207
-
cached := LikeCache {
208
post_id: post_id
209
-
likes: likes
210
}
211
sql app.db {
212
insert cached into LikeCache
···
223
224
pub fn (app &App) get_or_create_site_config() Site {
225
configs := sql app.db {
226
-
select from entity.Site
227
} or { [] }
228
if configs.len == 0 {
229
// make the site config
230
-
site_config := entity.Site{ }
231
sql app.db {
232
-
insert site_config into entity.Site
233
-
} or {
234
-
panic('failed to create site config (${err})')
235
-
}
236
} else if configs.len > 1 {
237
// this should never happen
238
panic('there are multiple site configs')
···
3
import veb
4
import db.pg
5
import auth
6
+
import entity { LikeCache, Like, Post, Site, User }
7
8
pub struct App {
9
veb.StaticHandler
···
13
db pg.DB
14
auth auth.Auth[pg.DB]
15
validators struct {
16
+
pub mut:
17
username StringValidator
18
password StringValidator
19
nickname StringValidator
···
98
}
99
100
pub fn (app &App) whoami(mut ctx Context) ?User {
101
+
token := ctx.get_cookie('token') or { return none }.trim_space()
102
if token == '' {
103
return none
104
}
···
131
}
132
133
pub fn (app &App) get_unknown_user() User {
134
+
return User{
135
+
username: 'unknown'
136
+
}
137
}
138
139
pub fn (app &App) logged_in_as(mut ctx Context, id int) bool {
···
204
}
205
206
// cache
207
+
cached := LikeCache{
208
post_id: post_id
209
+
likes: likes
210
}
211
sql app.db {
212
insert cached into LikeCache
···
223
224
pub fn (app &App) get_or_create_site_config() Site {
225
configs := sql app.db {
226
+
select from Site
227
} or { [] }
228
if configs.len == 0 {
229
// make the site config
230
+
site_config := Site{}
231
sql app.db {
232
+
insert site_config into Site
233
+
} or { panic('failed to create site config (${err})') }
234
} else if configs.len > 1 {
235
// this should never happen
236
panic('there are multiple site configs')
+12
-12
src/config.v
+12
-12
src/config.v
···
6
pub mut:
7
dev_mode bool
8
static_path string
9
-
instance struct {
10
pub mut:
11
name string
12
welcome string
13
default_theme string
14
allow_changing_theme bool
15
}
16
-
http struct {
17
pub mut:
18
port int
19
}
20
-
postgres struct {
21
pub mut:
22
-
host string
23
-
port int
24
-
user string
25
password string
26
-
db string
27
}
28
-
post struct {
29
pub mut:
30
title_min_len int
31
title_max_len int
32
title_pattern string
33
-
body_min_len int
34
-
body_max_len int
35
-
body_pattern string
36
}
37
-
user struct {
38
pub mut:
39
username_min_len int
40
username_max_len int
···
6
pub mut:
7
dev_mode bool
8
static_path string
9
+
instance struct {
10
pub mut:
11
name string
12
welcome string
13
default_theme string
14
allow_changing_theme bool
15
}
16
+
http struct {
17
pub mut:
18
port int
19
}
20
+
postgres struct {
21
pub mut:
22
+
host string
23
+
port int
24
+
user string
25
password string
26
+
db string
27
}
28
+
post struct {
29
pub mut:
30
title_min_len int
31
title_max_len int
32
title_pattern string
33
+
body_min_len int
34
+
body_max_len int
35
+
body_pattern string
36
}
37
+
user struct {
38
pub mut:
39
username_min_len int
40
username_max_len int
+3
-3
src/entity/likes.v
+3
-3
src/entity/likes.v
+2
-2
src/entity/post.v
+2
-2
src/entity/post.v
+1
-1
src/entity/site.v
+1
-1
src/entity/site.v
+12
-11
src/main.v
+12
-11
src/main.v
···
33
34
mut app := &App{
35
config: config
36
-
db: db
37
-
auth: auth.new(db)
38
-
validators: struct {
39
-
username: StringValidator.new(config.user.username_min_len, config.user.username_max_len, config.user.username_pattern)
40
-
password: StringValidator.new(config.user.username_min_len, config.user.username_max_len, config.user.username_pattern)
41
-
nickname: StringValidator.new(config.user.nickname_min_len, config.user.nickname_max_len, config.user.nickname_pattern)
42
-
user_bio: StringValidator.new(config.user.bio_min_len, config.user.bio_max_len, config.user.bio_pattern)
43
-
pronouns: StringValidator.new(config.user.pronouns_min_len, config.user.pronouns_max_len, config.user.pronouns_pattern)
44
-
post_title: StringValidator.new(config.post.title_min_len, config.post.title_max_len, config.post.title_pattern)
45
-
post_body: StringValidator.new(config.post.body_min_len, config.post.body_max_len, config.post.body_pattern)
46
-
}
47
}
48
49
app.mount_static_folder_at(app.config.static_path, '/static')!
50
init_db(db)!
···
33
34
mut app := &App{
35
config: config
36
+
db: db
37
+
auth: auth.new(db)
38
}
39
+
40
+
// vfmt off
41
+
app.validators.username = StringValidator.new(config.user.username_min_len, config.user.username_max_len, config.user.username_pattern)
42
+
app.validators.password = StringValidator.new(config.user.username_min_len, config.user.username_max_len, config.user.username_pattern)
43
+
app.validators.nickname = StringValidator.new(config.user.nickname_min_len, config.user.nickname_max_len, config.user.nickname_pattern)
44
+
app.validators.user_bio = StringValidator.new(config.user.bio_min_len, config.user.bio_max_len, config.user.bio_pattern)
45
+
app.validators.pronouns = StringValidator.new(config.user.pronouns_min_len, config.user.pronouns_max_len, config.user.pronouns_pattern)
46
+
app.validators.post_title = StringValidator.new(config.post.title_min_len, config.post.title_max_len, config.post.title_pattern)
47
+
app.validators.post_body = StringValidator.new(config.post.body_min_len, config.post.body_max_len, config.post.body_pattern)
48
+
// vfmt on
49
50
app.mount_static_folder_at(app.config.static_path, '/static')!
51
init_db(db)!
+1
-1
src/pages.v
+1
-1
src/pages.v
+2
-1
src/validation.v
+2
-1
src/validation.v