ggdgsdbsdbbb / discussion_routes.v
160 lines · 149 sloc · 6.15 KB · d230c5a6e59810a96cb2862c844cc11574f7eb07
Raw
1// Copyright (c) 2019-2026 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by a GPL license that can be found in the LICENSE file.
3module main
4
5import veb
6import validation
7
8struct DiscussionWithUser {
9 item Discussion
10 user User
11}
12
13struct DiscussionCommentWithUser {
14 item DiscussionComment
15 user User
16}
17
18@['/:username/:repo_name/discussions']
19pub fn (mut app App) handle_get_repo_discussions(mut ctx Context, username string, repo_name string) veb.Result {
20 repo := app.find_repo_by_name_and_username(repo_name, username) or { return ctx.not_found() }
21 if !app.has_user_repo_read_access(ctx, ctx.user.id, repo.id) && !repo.is_public {
22 return ctx.not_found()
23 }
24 discussions := app.list_repo_discussions(repo.id)
25 mut rows := []DiscussionWithUser{}
26 for d in discussions {
27 u := app.get_user_by_id(d.author_id) or { continue }
28 rows << DiscussionWithUser{
29 item: d
30 user: u
31 }
32 }
33 return $veb.html('templates/discussions.html')
34}
35
36@['/:username/:repo_name/discussions/new']
37pub fn (mut app App) new_discussion(mut ctx Context, username string, repo_name string) veb.Result {
38 if !ctx.logged_in {
39 return ctx.redirect_to_login()
40 }
41 repo := app.find_repo_by_name_and_username(repo_name, username) or { return ctx.not_found() }
42 if !app.has_user_repo_read_access(ctx, ctx.user.id, repo.id) && !repo.is_public {
43 return ctx.not_found()
44 }
45 return $veb.html('templates/new/discussion.html')
46}
47
48@['/:username/:repo_name/discussions'; post]
49pub fn (mut app App) handle_create_discussion(mut ctx Context, username string, repo_name string) veb.Result {
50 if !ctx.logged_in {
51 return ctx.redirect_to_login()
52 }
53 repo := app.find_repo_by_name_and_username(repo_name, username) or { return ctx.not_found() }
54 title := ctx.form['title']
55 body := ctx.form['body']
56 category := ctx.form['category']
57 if validation.is_string_empty(title) {
58 return ctx.redirect('/${username}/${repo_name}/discussions/new')
59 }
60 cat := if category in ['general', 'qa', 'announcement', 'idea'] { category } else { 'general' }
61 id := app.add_discussion(repo.id, ctx.user.id, title, body, cat) or {
62 ctx.error('Could not create discussion')
63 return ctx.redirect('/${username}/${repo_name}/discussions/new')
64 }
65 return ctx.redirect('/${username}/${repo_name}/discussions/${id}')
66}
67
68@['/:username/:repo_name/discussions/:id']
69pub fn (mut app App) view_discussion(mut ctx Context, username string, repo_name string, id string) veb.Result {
70 repo := app.find_repo_by_name_and_username(repo_name, username) or { return ctx.not_found() }
71 if !app.has_user_repo_read_access(ctx, ctx.user.id, repo.id) && !repo.is_public {
72 return ctx.not_found()
73 }
74 discussion := app.find_discussion(id.int()) or { return ctx.not_found() }
75 if discussion.repo_id != repo.id {
76 return ctx.not_found()
77 }
78 author := app.get_user_by_id(discussion.author_id) or { return ctx.not_found() }
79 raw_comments := app.get_discussion_comments(discussion.id)
80 mut comments := []DiscussionCommentWithUser{}
81 for c in raw_comments {
82 u := app.get_user_by_id(c.author_id) or { continue }
83 comments << DiscussionCommentWithUser{
84 item: c
85 user: u
86 }
87 }
88 is_owner := ctx.logged_in
89 && (repo.user_id == ctx.user.id || discussion.author_id == ctx.user.id)
90 return $veb.html('templates/discussion.html')
91}
92
93@['/:username/:repo_name/discussions/:id/comments'; post]
94pub fn (mut app App) handle_add_discussion_comment(mut ctx Context, username string, repo_name string, id string) veb.Result {
95 if !ctx.logged_in {
96 return ctx.redirect_to_login()
97 }
98 repo := app.find_repo_by_name_and_username(repo_name, username) or { return ctx.not_found() }
99 discussion := app.find_discussion(id.int()) or { return ctx.not_found() }
100 if discussion.repo_id != repo.id || discussion.is_locked {
101 return ctx.redirect('/${username}/${repo_name}/discussions/${id}')
102 }
103 text := ctx.form['text']
104 if validation.is_string_empty(text) {
105 return ctx.redirect('/${username}/${repo_name}/discussions/${id}')
106 }
107 app.add_discussion_comment(discussion.id, ctx.user.id, text) or {}
108 return ctx.redirect('/${username}/${repo_name}/discussions/${id}')
109}
110
111@['/:username/:repo_name/discussions/:id/lock'; post]
112pub fn (mut app App) handle_lock_discussion(mut ctx Context, username string, repo_name string, id string) veb.Result {
113 if !ctx.logged_in {
114 return ctx.redirect_to_login()
115 }
116 repo := app.find_repo_by_name_and_username(repo_name, username) or { return ctx.not_found() }
117 discussion := app.find_discussion(id.int()) or { return ctx.not_found() }
118 if discussion.repo_id != repo.id {
119 return ctx.not_found()
120 }
121 if repo.user_id != ctx.user.id {
122 return ctx.redirect('/${username}/${repo_name}/discussions/${id}')
123 }
124 app.set_discussion_lock(discussion.id, !discussion.is_locked) or {}
125 return ctx.redirect('/${username}/${repo_name}/discussions/${id}')
126}
127
128@['/:username/:repo_name/discussions/:id/delete'; post]
129pub fn (mut app App) handle_delete_discussion(mut ctx Context, username string, repo_name string, id string) veb.Result {
130 if !ctx.logged_in {
131 return ctx.redirect_to_login()
132 }
133 repo := app.find_repo_by_name_and_username(repo_name, username) or { return ctx.not_found() }
134 discussion := app.find_discussion(id.int()) or { return ctx.not_found() }
135 if discussion.repo_id != repo.id {
136 return ctx.not_found()
137 }
138 if repo.user_id != ctx.user.id && discussion.author_id != ctx.user.id {
139 return ctx.redirect('/${username}/${repo_name}/discussions/${id}')
140 }
141 app.delete_discussion(discussion.id) or {}
142 return ctx.redirect('/${username}/${repo_name}/discussions')
143}
144
145@['/:username/:repo_name/discussions/:id/answer/:cid'; post]
146pub fn (mut app App) handle_mark_answer(mut ctx Context, username string, repo_name string, id string, cid string) veb.Result {
147 if !ctx.logged_in {
148 return ctx.redirect_to_login()
149 }
150 repo := app.find_repo_by_name_and_username(repo_name, username) or { return ctx.not_found() }
151 discussion := app.find_discussion(id.int()) or { return ctx.not_found() }
152 if discussion.repo_id != repo.id {
153 return ctx.not_found()
154 }
155 if discussion.author_id != ctx.user.id && repo.user_id != ctx.user.id {
156 return ctx.redirect('/${username}/${repo_name}/discussions/${id}')
157 }
158 app.mark_discussion_answer(discussion.id, cid.int()) or {}
159 return ctx.redirect('/${username}/${repo_name}/discussions/${id}')
160}
161