+1
doc/todo.md
+1
doc/todo.md
···
26
26
- [x] post:likes/dislikes
27
27
- [x] post:mentioning ('tagging') other users in posts
28
28
- [x] post:mentioning:who mentioned you (send notifications when a user mentions you)
29
+
- [x] post:editing
29
30
- [ ] ~~site:stylesheet (and a toggle for html-only mode)~~
30
31
- replaced with per-user optional stylesheets
31
32
- [x] site:message of the day (admins can add a welcome message displayed on index.html)
+26
src/api.v
+26
src/api.v
···
490
490
return ctx.text(post.title)
491
491
}
492
492
493
+
@['/api/post/edit'; post]
494
+
fn (mut app App) api_post_edit(mut ctx Context, id int, title string, body string) veb.Result {
495
+
user := app.whoami(mut ctx) or {
496
+
ctx.error('not logged in!')
497
+
return ctx.redirect('/login')
498
+
}
499
+
post := app.get_post_by_id(id) or {
500
+
ctx.error('no such post')
501
+
return ctx.redirect('/')
502
+
}
503
+
if post.author_id != user.id {
504
+
ctx.error('insufficient permissions')
505
+
return ctx.redirect('/')
506
+
}
507
+
508
+
sql app.db {
509
+
update Post set body = body, title = title where id == id
510
+
} or {
511
+
eprintln('failed to update post')
512
+
ctx.error('failed to update post')
513
+
return ctx.redirect('/')
514
+
}
515
+
516
+
return ctx.redirect('/post/${id}')
517
+
}
518
+
493
519
////// site //////
494
520
495
521
@['/api/site/set_motd'; post]
+12
-6
src/app.v
+12
-6
src/app.v
···
61
61
return posts
62
62
}
63
63
64
-
// pub fn (app &App) get_popular_posts() []Post {
65
-
// posts := sql app.db {
66
-
// select from Post order by likes desc limit 10
67
-
// } or { [] }
68
-
// return posts
69
-
// }
64
+
pub fn (app &App) get_popular_posts() []Post {
65
+
cached_likes := sql app.db {
66
+
select from LikeCache order by likes desc limit 10
67
+
} or { [] }
68
+
posts := cached_likes.map(fn [app] (it LikeCache) Post {
69
+
return app.get_post_by_id(it.post_id) or {
70
+
eprintln('cached like ${it} does not have a post related to it (from get_popular_posts)')
71
+
return Post{}
72
+
}
73
+
}).filter(it.id != 0)
74
+
return posts
75
+
}
70
76
71
77
pub fn (app &App) get_posts_from_user(user_id int) []Post {
72
78
posts := sql app.db {
+18
src/pages.v
+18
src/pages.v
···
70
70
user := app.whoami(mut ctx) or { User{} }
71
71
return $veb.html()
72
72
}
73
+
74
+
@['/post/:post_id/edit']
75
+
fn (mut app App) edit(mut ctx Context, post_id int) veb.Result {
76
+
user := app.whoami(mut ctx) or {
77
+
ctx.error('not logged in')
78
+
return ctx.redirect('/login')
79
+
}
80
+
post := app.get_post_by_id(post_id) or {
81
+
ctx.error('no such post')
82
+
return ctx.redirect('/')
83
+
}
84
+
if post.author_id != user.id {
85
+
ctx.error('insufficient permissions')
86
+
return ctx.redirect('/post/${post_id}')
87
+
}
88
+
ctx.title = '${app.config.instance.name} - editing ${post.title}'
89
+
return $veb.html()
90
+
}
+48
src/templates/edit.html
+48
src/templates/edit.html
···
1
+
@include 'partial/header.html'
2
+
3
+
<script src="/static/js/post.js"></script>
4
+
<script src="/static/js/render_body.js"></script>
5
+
6
+
<h1>edit post</h1>
7
+
8
+
<div class="post post-full">
9
+
<form action="/api/post/edit" method="post">
10
+
<input
11
+
type="number"
12
+
name="id"
13
+
id="id"
14
+
placeholder="post id"
15
+
value="@post.id"
16
+
required
17
+
readonly
18
+
hidden
19
+
aria-hidden
20
+
>
21
+
<input
22
+
type="text"
23
+
name="title"
24
+
id="title"
25
+
minlength="@app.config.post.title_min_len"
26
+
maxlength="@app.config.post.title_max_len"
27
+
pattern="@app.config.post.title_pattern"
28
+
placeholder="title"
29
+
value="@post.title"
30
+
required
31
+
>
32
+
<br>
33
+
<textarea
34
+
name="body"
35
+
id="body"
36
+
minlength="@app.config.post.body_min_len"
37
+
maxlength="@app.config.post.body_max_len"
38
+
rows="10"
39
+
cols="30"
40
+
placeholder="body"
41
+
required
42
+
>@post.body</textarea>
43
+
<br>
44
+
<input type="submit" value="save">
45
+
</form>
46
+
</div>
47
+
48
+
@include 'partial/footer.html'
+14
-5
src/templates/post.html
+14
-5
src/templates/post.html
···
9
9
<p><em>likes: @{app.get_net_likes_for_post(post.id)}</em></p>
10
10
<p><em>posted at: @post.posted_at</em></p>
11
11
12
+
@if ctx.is_logged_in() && post.author_id == user.id
13
+
<p><a href="/post/@{post.id}/edit">edit post</a></p>
14
+
@end
15
+
12
16
@if ctx.is_logged_in()
13
17
<br>
14
18
<div>
···
29
33
</div>
30
34
@end
31
35
32
-
@if (ctx.is_logged_in() && user.admin) || (ctx.is_logged_in() && post.author_id == user.id)
33
-
<hr>
34
-
@if user.admin
36
+
@if ctx.is_logged_in() && (post.author_id == user.id || user.admin)
37
+
<br>
38
+
<div>
39
+
40
+
@if post.author_id == user.id
41
+
<h4>manage post:</h4>
42
+
@else if user.admin
35
43
<h4>admin powers:</h4>
36
-
@else if post.author_id == user.id
37
-
<h4>manage post:</h4>
38
44
@end
45
+
39
46
<form action="/api/post/delete" method="post">
40
47
<input
41
48
type="number"
···
50
57
>
51
58
<input type="submit" value="delete">
52
59
</form>
60
+
61
+
</div>
53
62
@end
54
63
</div>
55
64