Skip to content

Commit 696a4dd

Browse files
authored
Merge pull request #28 from tuanle03/clr-57-create-discussion-api
[CLR-57] Add DiscussionsAPI for getting and manipulating discussions
2 parents 354263e + 7d581aa commit 696a4dd

File tree

9 files changed

+407
-11
lines changed

9 files changed

+407
-11
lines changed

app/api/web/discussions_api.rb

Lines changed: 340 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
1+
module API
2+
class Web::DiscussionsAPI < Grape::API
3+
4+
helpers do
5+
def format_discussion(discussion)
6+
{
7+
id: discussion.id,
8+
title: discussion.title,
9+
content: discussion.content,
10+
total_comments: discussion.total_comments,
11+
created_at: discussion.created_at.to_fs(:ymd_hms),
12+
user: {
13+
name: discussion.user.name,
14+
avatar_url: discussion.user.avatar_url
15+
}
16+
}
17+
end
18+
19+
def format_comment(comment)
20+
{
21+
id: comment.id,
22+
content: comment.content,
23+
created_at: comment.created_at.to_fs(:ymd_hms),
24+
user: {
25+
name: comment.user.name,
26+
avatar_url: comment.user.avatar_url
27+
}
28+
}
29+
end
30+
end
31+
32+
resource :discussions do
33+
34+
desc 'Get list of discussions'
35+
params do
36+
optional :limit, type: Integer, default: 10, desc: 'Limit the number of discussions'
37+
end
38+
get do
39+
status 200
40+
{
41+
success: true,
42+
discussions: Discussion.approved.limit(params[:limit]).map { |discussion| format_discussion(discussion) }
43+
}
44+
end
45+
46+
desc 'Get list of discussions by newest'
47+
params do
48+
optional :limit, type: Integer, default: 10, desc: 'Limit the number of discussions'
49+
end
50+
get '/newest' do
51+
discussions = Discussion.approved.newest.limit(params[:limit])
52+
status 200
53+
{
54+
success: true,
55+
discussions: discussions.map { |discussion| format_discussion(discussion) }
56+
}
57+
end
58+
59+
desc 'Get list of discussions by most commented'
60+
params do
61+
optional :limit, type: Integer, default: 10, desc: 'Limit the number of discussions'
62+
end
63+
get '/most_commented' do
64+
discussions = Discussion.approved.most_commented.limit(params[:limit])
65+
status 200
66+
{
67+
success: true,
68+
discussions: discussions.map { |discussion| format_discussion(discussion) }
69+
}
70+
end
71+
72+
desc 'Get a discussion'
73+
params do
74+
requires :id, type: Integer, desc: 'Discussion id'
75+
end
76+
get ':id' do
77+
discussion = Discussion.find(params[:id])
78+
if discussion
79+
status 200
80+
{
81+
discussion: format_discussion(discussion)
82+
}
83+
else
84+
status 400
85+
{
86+
success: false,
87+
error: 'Discussion not found'
88+
}
89+
end
90+
end
91+
92+
desc 'Create a discussion',
93+
security: [access_token: {}]
94+
params do
95+
requires :content, type: String, desc: 'Discussion content', allow_blank: false
96+
end
97+
post do
98+
authenticate_user!
99+
discussion = current_user.discussions.new(content: params[:content], status: 'approved')
100+
if discussion.save
101+
status 200
102+
{
103+
success: true,
104+
discussion: format_discussion(discussion)
105+
}
106+
else
107+
status 400
108+
{
109+
success: false,
110+
errors: discussion.errors.full_messages
111+
}
112+
end
113+
end
114+
115+
desc 'Update a discussion',
116+
security: [access_token: {}]
117+
params do
118+
requires :id, type: Integer, desc: 'Discussion id'
119+
requires :content, type: String, desc: 'Discussion content', allow_blank: false
120+
end
121+
put ':id' do
122+
authenticate_user!
123+
discussion = current_user.discussions.find_by(id: params[:id])
124+
if discussion.update(content: params[:content])
125+
status 200
126+
{
127+
success: true,
128+
message: 'Discussion updated successfully'
129+
}
130+
else
131+
status 400
132+
{
133+
success: false,
134+
errors: discussion.errors.full_messages
135+
}
136+
end
137+
end
138+
139+
desc 'Reject a discussion',
140+
security: [access_token: {}]
141+
params do
142+
requires :id, type: Integer, desc: 'Discussion id'
143+
end
144+
put ':id/reject' do
145+
authenticate_user!
146+
discussion = current_user.discussions.approved.find_by(id: params[:id])
147+
if discussion.update(status: 'rejected')
148+
status 200
149+
{
150+
success: true,
151+
message: 'Discussion rejected successfully'
152+
}
153+
else
154+
status 400
155+
{
156+
success: false,
157+
errors: discussion.errors.full_messages
158+
}
159+
end
160+
end
161+
162+
desc 'Delete a discussion',
163+
security: [access_token: {}]
164+
params do
165+
requires :id, type: Integer, desc: 'Discussion id'
166+
end
167+
delete ':id' do
168+
authenticate_user!
169+
discussion = current_user.discussions.find_by(id: params[:id])
170+
if discussion.destroy
171+
status 200
172+
{
173+
success: true,
174+
message: 'Discussion deleted successfully'
175+
}
176+
else
177+
status 400
178+
{
179+
success: false,
180+
errors: discussion.errors.full_messages
181+
}
182+
end
183+
end
184+
185+
desc 'Get all comments of a discussion'
186+
params do
187+
requires :id, type: Integer, desc: 'Discussion id'
188+
end
189+
get ':id/comments' do
190+
discussion = Discussion.approved.find_by(id: params[:id])
191+
if discussion
192+
status 200
193+
{
194+
success: true,
195+
comments: discussion.comments.approved.map { |comment| format_comment(comment) }
196+
}
197+
else
198+
status 400
199+
{
200+
success: false,
201+
error: 'Discussion not found'
202+
}
203+
end
204+
end
205+
206+
desc 'Create a comment of a discussion',
207+
security: [access_token: {}]
208+
params do
209+
requires :id, type: Integer, desc: 'Discussion id'
210+
requires :content, type: String, desc: 'Comment content', allow_blank: false
211+
end
212+
post ':id/comments' do
213+
authenticate_user!
214+
discussion = Discussion.approved.find_by(id: params[:id])
215+
if discussion
216+
comment = discussion.comments.new(user: current_user, content: params[:content], status: 'approved')
217+
if comment.save
218+
status 200
219+
{
220+
success: true,
221+
message: 'Comment created successfully',
222+
}
223+
else
224+
status 400
225+
{
226+
success: false,
227+
errors: comment.errors.full_messages
228+
}
229+
end
230+
else
231+
status 400
232+
{
233+
success: false,
234+
error: 'Discussion not found'
235+
}
236+
end
237+
end
238+
239+
desc 'Update a comment of a discussion',
240+
security: [access_token: {}]
241+
params do
242+
requires :id, type: Integer, desc: 'Discussion id'
243+
requires :comment_id, type: Integer, desc: 'Comment id'
244+
requires :content, type: String, desc: 'Comment content', allow_blank: false
245+
end
246+
put ':id/comments/:comment_id' do
247+
authenticate_user!
248+
discussion = Discussion.approved.find_by(id: params[:id])
249+
if discussion
250+
comment = discussion.comments.find_by(id: params[:comment_id])
251+
if comment.update(content: params[:content])
252+
status 200
253+
{
254+
success: true,
255+
message: 'Comment updated successfully',
256+
}
257+
else
258+
status 400
259+
{
260+
success: false,
261+
errors: comment.errors.full_messages
262+
}
263+
end
264+
else
265+
status 400
266+
{
267+
success: false,
268+
error: 'Discussion not found'
269+
}
270+
end
271+
end
272+
273+
desc 'Reject a comment of a discussion',
274+
security: [access_token: {}]
275+
params do
276+
requires :id, type: Integer, desc: 'Discussion id'
277+
requires :comment_id, type: Integer, desc: 'Comment id'
278+
end
279+
put ':id/comments/:comment_id/reject' do
280+
authenticate_user!
281+
discussion = Discussion.approved.find_by(id: params[:id])
282+
if discussion
283+
comment = discussion.comments.approved.find_by(id: params[:comment_id]).update(status: 'rejected')
284+
if comment
285+
status 200
286+
{
287+
success: true,
288+
message: 'Comment rejected successfully',
289+
}
290+
else
291+
status 400
292+
{
293+
success: false,
294+
errors: comment.errors.full_messages
295+
}
296+
end
297+
else
298+
status 400
299+
{
300+
success: false,
301+
error: 'Discussion not found'
302+
}
303+
end
304+
end
305+
306+
desc 'Delete a comment of a discussion',
307+
security: [access_token: {}]
308+
params do
309+
requires :id, type: Integer, desc: 'Discussion id'
310+
requires :comment_id, type: Integer, desc: 'Comment id'
311+
end
312+
delete ':id/comments/:comment_id' do
313+
authenticate_user!
314+
discussion = Discussion.approved.find_by(id: params[:id])
315+
if discussion
316+
comment = discussion.comments.find_by(id: params[:comment_id])
317+
if comment.destroy
318+
status 200
319+
{
320+
success: true,
321+
message: 'Comment deleted successfully',
322+
}
323+
else
324+
status 400
325+
{
326+
success: false,
327+
errors: comment.errors.full_messages
328+
}
329+
end
330+
else
331+
status 400
332+
{
333+
success: false,
334+
error: 'Discussion not found'
335+
}
336+
end
337+
end
338+
end
339+
end
340+
end

app/api/web_api.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ class WebAPI < Grape::API
44

55
helpers ::Helpers::AuthenticationHelper
66

7-
mount Web::FeedbacksAPI
8-
mount Web::PostsAPI
97
mount Web::SessionsAPI
108
mount Web::RegistrationsAPI
9+
mount Web::FeedbacksAPI
10+
mount Web::DiscussionsAPI
11+
mount Web::PostsAPI
1112

1213
add_swagger_documentation(
1314
format: :json,

app/models/comment.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ class Comment < ApplicationRecord
22
belongs_to :user
33
belongs_to :linked_object, polymorphic: true
44

5-
validates :body, presence: true
5+
validates :content, presence: true
66
validates :user_id, presence: true
77
validates :linked_object_id, presence: true
88
validates :linked_object_type, presence: true
99

10+
scope :approved, -> { where(status: 'approved') }
11+
1012
def self.create_comment(user, linked_object, body)
1113
comment = Comment.new
1214
comment.user = user

app/models/discussion.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,20 @@ class Discussion < ApplicationRecord
33

44
has_many :comments, as: :linked_object
55
has_many :votes, as: :linked_object
6+
7+
validates :content, presence: true
8+
9+
scope :newest, -> { order(created_at: :desc) }
10+
scope :approved, -> { where(status: 'approved') }
11+
scope :most_commented, -> {
12+
joins(:comments)
13+
.select('discussions.*, COUNT(comments.id) AS comments_count')
14+
.group('discussions.id')
15+
.order('comments_count DESC')
16+
}
17+
18+
def total_comments
19+
comments.count
20+
end
21+
622
end

app/models/user.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ class User < ApplicationRecord
99

1010
has_many :posts, dependent: :destroy
1111
has_many :feedbacks, dependent: :destroy
12+
has_many :comments, dependent: :destroy
13+
has_many :discussions, dependent: :destroy
1214

1315
def generate_jwt
1416
payload = { user_id: id, exp: 1.day.from_now.to_i }

0 commit comments

Comments
 (0)