22using exercise . wwwapi . DTOs ;
33using exercise . wwwapi . DTOs . GetUsers ;
44using exercise . wwwapi . DTOs . Posts ;
5+ using exercise . wwwapi . Helpers ;
56using exercise . wwwapi . Models ;
67using exercise . wwwapi . Repository ;
8+ using Microsoft . AspNetCore . Authorization ;
79using Microsoft . AspNetCore . Mvc ;
810using Microsoft . EntityFrameworkCore ;
11+ using System . Security . Claims ;
912
1013namespace exercise . wwwapi . Endpoints
1114{
@@ -16,68 +19,101 @@ public static void ConfigurePostEndpoints(this WebApplication app)
1619 var posts = app . MapGroup ( "posts" ) ;
1720 posts . MapPost ( "/" , CreatePost ) . WithSummary ( "Create post" ) ;
1821 posts . MapGet ( "/" , GetAllPosts ) . WithSummary ( "Get all posts" ) ;
19- posts . MapPatch ( "/{id}" , UpdatePost ) . WithSummary ( "Update a certain post" ) ;
20- posts . MapDelete ( "/{id}" , DeletePost ) . WithSummary ( "Remove a certain post" ) ;
22+ posts . MapPatch ( "/{postid}" , UpdatePost ) . WithSummary ( "Update a certain post" ) ;
23+ posts . MapDelete ( "/{postid}" , DeletePost ) . WithSummary ( "Remove a certain post" ) ;
24+
25+ posts . MapPost ( "/{postId}/comments" , AddCommentToPost ) . WithSummary ( "Add a new comment to a post" ) ;
26+ posts . MapGet ( "/{postId}/comments" , GetCommentsForPost ) . WithSummary ( "Get comments for a specific post" ) ;
27+
28+ // Standalone comment endpoints for editing/deleting
29+ var comments = app . MapGroup ( "comments" ) ;
30+ comments . MapPatch ( "/{commentId}" , UpdateComment ) . WithSummary ( "Edit an existing comment" ) ;
31+ comments . MapDelete ( "/{commentId}" , DeleteCommentById ) . WithSummary ( "Remove an existing comment" ) ;
32+
33+ // Endpoints to get by user
34+ posts . MapGet ( "/user/{userId}" , GetPostsByUser ) . WithSummary ( "Get posts by a specific user" ) ;
35+ comments . MapGet ( "/user/{userId}" , GetCommentsByUser ) . WithSummary ( "Get comments by a specific user" ) ;
2136 }
2237
38+ [ Authorize ]
2339 [ ProducesResponseType ( StatusCodes . Status200OK ) ]
2440 [ ProducesResponseType ( StatusCodes . Status404NotFound ) ]
2541 [ ProducesResponseType ( StatusCodes . Status400BadRequest ) ]
26- public static IResult CreatePost ( IRepository < User > userservice , IRepository < Post > postservice , IMapper mapper , CreatePostDTO request )
42+ public static IResult CreatePost (
43+ IRepository < User > userservice ,
44+ IRepository < Post > postservice ,
45+ IMapper mapper ,
46+ ClaimsPrincipal user ,
47+ CreatePostDTO request
48+ )
2749 {
28-
29- User ? user = userservice . GetById ( request . Userid ) ;
50+ int ? userid = user . UserRealId ( ) ;
51+ User ? dbUser = userservice . GetById ( userid ) ;
3052 if ( user == null )
3153 return Results . NotFound ( new ResponseDTO < Object > { Message = "Invalid userID" } ) ;
3254
3355 if ( string . IsNullOrWhiteSpace ( request . Content ) )
3456 return Results . BadRequest ( new ResponseDTO < Object > { Message = "Content cannot be empty" } ) ;
3557
36- Post post = new Post ( ) { CreatedAt = DateTime . UtcNow , NumLikes = 0 , UserId = request . Userid , Content = request . Content } ;
58+ Post post = new Post ( ) { CreatedAt = DateTime . UtcNow , NumLikes = 0 , UserId = dbUser . Id , Content = request . Content } ;
3759
3860 // is a try catch needed here?
3961 postservice . Insert ( post ) ;
4062 postservice . Save ( ) ;
4163
4264
43- UserBasicDTO userBasicDTO = mapper . Map < UserBasicDTO > ( user ) ;
65+ UserBasicDTO userBasicDTO = mapper . Map < UserBasicDTO > ( dbUser ) ;
4466 PostDTO postDTO = mapper . Map < PostDTO > ( post ) ;
4567 postDTO . User = userBasicDTO ;
4668
4769 ResponseDTO < PostDTO > response = new ResponseDTO < PostDTO >
4870 {
49- Message = "success " ,
71+ Message = "Success " ,
5072 Data = postDTO
5173 } ;
5274
5375 return Results . Created ( $ "/posts/{ post . Id } ", response ) ;
5476 }
77+ [ Authorize ]
5578 [ ProducesResponseType ( StatusCodes . Status200OK ) ]
5679 public static IResult GetAllPosts ( IRepository < Post > service , IMapper mapper )
5780 {
5881 IEnumerable < Post > results = service . GetWithIncludes ( q => q . Include ( p => p . User ) . Include ( p => p . Comments ) . ThenInclude ( c => c . User ) ) ;
5982 IEnumerable < PostDTO > postDTOs = mapper . Map < IEnumerable < PostDTO > > ( results ) ;
6083 ResponseDTO < IEnumerable < PostDTO > > response = new ResponseDTO < IEnumerable < PostDTO > > ( )
6184 {
62- Message = "success " ,
85+ Message = "Success " ,
6386 Data = postDTOs
6487 } ;
6588 return TypedResults . Ok ( response ) ;
6689 }
6790
91+ [ Authorize ]
6892 [ ProducesResponseType ( StatusCodes . Status200OK ) ]
6993 [ ProducesResponseType ( StatusCodes . Status400BadRequest ) ]
70- public static IResult UpdatePost ( IRepository < Post > service , IMapper mapper , int id , UpdatePostDTO request )
71- {
72- if ( string . IsNullOrWhiteSpace ( request . Content ) ) return TypedResults . BadRequest ( new ResponseDTO < object >
73- {
74- Message = "Content cannot be empty"
75- } ) ;
94+ [ ProducesResponseType ( StatusCodes . Status403Forbidden ) ]
7695
77- Post ? post = service . GetById ( id , q => q . Include ( p => p . User ) ) ;
96+ public static IResult UpdatePost ( IRepository < Post > service , IMapper mapper , ClaimsPrincipal user , int postid , UpdatePostDTO request )
97+ {
98+ if ( string . IsNullOrWhiteSpace ( request . Content ) ) return TypedResults . BadRequest ( new ResponseDTO < object > {
99+ Message = "Content cannot be empty"
100+ } ) ;
101+
102+ Post ? post = service . GetById ( postid , q=> q . Include ( p => p . User ) ) ;
78103
79104 if ( post == null ) return TypedResults . NotFound ( new ResponseDTO < Object > { Message = "Post not found" } ) ;
80105
106+ Console . WriteLine ( $ "Role:{ user . Role ( ) } { Roles . student } | { post . UserId } { user . UserRealId ( ) } ") ;
107+ if ( post . UserId != user . UserRealId ( ) && user . Role ( ) == ( int ) Roles . student )
108+ {
109+ var forbiddenResponse = new ResponseDTO < object >
110+ {
111+ Message = "You are not authorized to edit this post."
112+ } ;
113+ return TypedResults . Json ( forbiddenResponse , statusCode : StatusCodes . Status403Forbidden ) ;
114+ }
115+
116+
81117 post . Content = request . Content ;
82118 post . UpdatedAt = DateTime . UtcNow ;
83119
@@ -90,17 +126,186 @@ public static IResult UpdatePost(IRepository<Post> service, IMapper mapper, int
90126 return TypedResults . Ok ( new ResponseDTO < PostDTO > { Message = "Success" , Data = postDTO } ) ;
91127 }
92128
129+ [ Authorize ]
93130 [ ProducesResponseType ( StatusCodes . Status200OK ) ]
94131 [ ProducesResponseType ( StatusCodes . Status404NotFound ) ]
95- private static IResult DeletePost ( IRepository < Post > service , int id )
132+ [ ProducesResponseType ( StatusCodes . Status403Forbidden ) ]
133+ private static IResult DeletePost ( IRepository < Post > service , ClaimsPrincipal user , int postid )
96134 {
97- Post ? post = service . GetById ( id , q => q . Include ( p => p . User ) . Include ( p => p . Comments ) . ThenInclude ( c => c . User ) ) ;
135+ Post ? post = service . GetById ( postid , q => q . Include ( p => p . User ) . Include ( p => p . Comments ) . ThenInclude ( c => c . User ) ) ;
98136 if ( post == null ) return TypedResults . NotFound ( new ResponseDTO < Object > { Message = "Post not found" } ) ;
99137
100- service . Delete ( id ) ;
138+ if ( user . Role ( ) == ( int ) Roles . student && post . UserId != user . UserRealId ( ) )
139+ {
140+ var forbiddenResponse = new ResponseDTO < object >
141+ {
142+ Message = "You are not authorized to delete this post."
143+ } ;
144+ return TypedResults . Json ( forbiddenResponse , statusCode : StatusCodes . Status403Forbidden ) ;
145+ }
146+ service . Delete ( postid ) ;
101147 service . Save ( ) ;
102148
103149 return TypedResults . Ok ( new ResponseDTO < PostDTO > { Message = "Success" } ) ;
104150 }
151+
152+ [ Authorize ]
153+ [ ProducesResponseType ( StatusCodes . Status201Created ) ]
154+ [ ProducesResponseType ( StatusCodes . Status404NotFound ) ]
155+ [ ProducesResponseType ( StatusCodes . Status400BadRequest ) ]
156+ private static IResult AddCommentToPost (
157+ IRepository < PostComment > commentService ,
158+ IRepository < Post > postService ,
159+ IRepository < User > userService ,
160+ IMapper mapper ,
161+ ClaimsPrincipal user ,
162+ int postId ,
163+ CreatePostCommentDTO request )
164+ {
165+ // Check if post exists
166+ var post = postService . GetById ( postId ) ;
167+ if ( post == null )
168+ {
169+ return TypedResults . NotFound ( new ResponseDTO < object > { Message = "Post not found." } ) ;
170+ }
171+
172+ // Check if user exists
173+ var dbUser = userService . GetById ( user . UserRealId ( ) ) ;
174+ if ( dbUser == null )
175+ {
176+ return TypedResults . NotFound ( new ResponseDTO < object > { Message = "User not found." } ) ;
177+ }
178+
179+ // Validate content
180+ if ( string . IsNullOrWhiteSpace ( request . Content ) )
181+ {
182+ return TypedResults . BadRequest ( new ResponseDTO < object > { Message = "Comment content cannot be empty." } ) ;
183+ }
184+
185+ var comment = new PostComment
186+ {
187+ Content = request . Content ,
188+ UserId = dbUser . Id ,
189+ PostId = postId ,
190+ CreatedAt = DateTime . UtcNow
191+ } ;
192+
193+ commentService . Insert ( comment ) ;
194+ commentService . Save ( ) ;
195+
196+ var createdComment = commentService . GetById ( comment . Id , q => q . Include ( c => c . User ) ) ;
197+ var commentDto = mapper . Map < PostCommentDTO > ( createdComment ) ;
198+
199+ return TypedResults . Created ( $ "/comments/{ comment . Id } ", new ResponseDTO < PostCommentDTO > { Message = "Success" , Data = commentDto } ) ;
200+ }
201+
202+ [ Authorize ]
203+ [ ProducesResponseType ( StatusCodes . Status200OK ) ]
204+ private static IResult GetCommentsForPost ( IRepository < Post > postservice , IMapper mapper , int postId )
205+ {
206+ Post ? post = postservice . GetById ( postId , q => q . Include ( p => p . User ) . Include ( p => p . Comments ) . ThenInclude ( c => c . User ) ) ;
207+ if ( post == null ) return TypedResults . NotFound ( new ResponseDTO < Object > { Message = "Post not found" } ) ;
208+ List < PostComment > comments = [ .. post . Comments ] ;
209+ List < PostCommentDTO > commentsDTO = mapper . Map < List < PostCommentDTO > > ( comments ) ;
210+ return TypedResults . Ok ( new ResponseDTO < List < PostCommentDTO > > { Message = "Success" , Data = commentsDTO } ) ;
211+ }
212+
213+ [ ProducesResponseType ( StatusCodes . Status200OK ) ]
214+ [ ProducesResponseType ( StatusCodes . Status404NotFound ) ]
215+ [ ProducesResponseType ( StatusCodes . Status400BadRequest ) ]
216+ private static IResult UpdateComment (
217+ IRepository < PostComment > service ,
218+ IMapper mapper ,
219+ ClaimsPrincipal user ,
220+ int commentId ,
221+ CreatePostCommentDTO request )
222+ {
223+ if ( string . IsNullOrWhiteSpace ( request . Content ) )
224+ {
225+ return TypedResults . BadRequest ( new ResponseDTO < object > { Message = "Content cannot be empty." } ) ;
226+ }
227+
228+ var comment = service . GetById ( commentId , q => q . Include ( c => c . User ) ) ;
229+ if ( comment == null ) return TypedResults . NotFound ( new ResponseDTO < object > { Message = "Comment not found." } ) ;
230+
231+ //Console.WriteLine($"Role:{user.Role()} {Roles.student.ToString()}| {comment.UserId} {user.UserRealId()}");
232+ if ( comment . UserId != user . UserRealId ( ) && user . Role ( ) == ( int ) Roles . student )
233+ {
234+ var forbiddenResponse = new ResponseDTO < object >
235+ {
236+ Message = "You are not authorized to edit this comment."
237+ } ;
238+ return TypedResults . Json ( forbiddenResponse , statusCode : StatusCodes . Status403Forbidden ) ;
239+ }
240+
241+ comment . Content = request . Content ;
242+ comment . UpdatedAt = DateTime . UtcNow ;
243+
244+ service . Update ( comment ) ;
245+ service . Save ( ) ;
246+
247+ var commentDto = mapper . Map < PostComment > ( comment ) ;
248+ return TypedResults . Ok ( new ResponseDTO < PostComment > { Message = "Comment updated successfully." , Data = commentDto } ) ;
249+ }
250+
251+ [ Authorize ]
252+ [ ProducesResponseType ( StatusCodes . Status200OK ) ]
253+ [ ProducesResponseType ( StatusCodes . Status404NotFound ) ]
254+ private static IResult DeleteCommentById ( IRepository < PostComment > service , ClaimsPrincipal user , int commentId )
255+ {
256+ var comment = service . GetById ( commentId ) ;
257+ if ( comment == null )
258+ {
259+ return TypedResults . NotFound ( new ResponseDTO < object > { Message = "Comment not found." } ) ;
260+ }
261+
262+ if ( user . Role ( ) == ( int ) Roles . student && comment . UserId != user . UserRealId ( ) )
263+ {
264+ var forbiddenResponse = new ResponseDTO < object >
265+ {
266+ Message = "You are not authorized to delete this comment."
267+ } ;
268+ return TypedResults . Json ( forbiddenResponse , statusCode : StatusCodes . Status403Forbidden ) ;
269+ }
270+
271+ service . Delete ( commentId ) ;
272+ service . Save ( ) ;
273+
274+ return TypedResults . Ok ( new ResponseDTO < object > { Message = "Comment deleted successfully." } ) ;
275+ }
276+
277+ [ Authorize ]
278+ [ ProducesResponseType ( StatusCodes . Status200OK ) ]
279+ [ ProducesResponseType ( StatusCodes . Status404NotFound ) ]
280+ private static IResult GetPostsByUser ( IRepository < Post > service , IMapper mapper , int userid )
281+ {
282+ IEnumerable < Post > results = service . GetWithIncludes ( q => q . Where ( p => p . UserId == userid ) . Include ( p => p . User ) . Include ( p => p . Comments ) . ThenInclude ( c => c . User ) ) ;
283+ if ( results . Count ( ) == 0 ) return TypedResults . NotFound ( new ResponseDTO < Object > { Message = "No posts found for this user" } ) ;
284+
285+ IEnumerable < PostDTO > postDTOs = mapper . Map < IEnumerable < PostDTO > > ( results ) ;
286+ ResponseDTO < IEnumerable < PostDTO > > response = new ResponseDTO < IEnumerable < PostDTO > > ( )
287+ {
288+ Message = "Success" ,
289+ Data = postDTOs
290+ } ;
291+ return TypedResults . Ok ( response ) ;
292+ }
293+
294+ [ Authorize ]
295+ [ ProducesResponseType ( StatusCodes . Status200OK ) ]
296+ [ ProducesResponseType ( StatusCodes . Status404NotFound ) ]
297+ private static IResult GetCommentsByUser ( IRepository < PostComment > service , IMapper mapper , int userid )
298+ {
299+ IEnumerable < PostComment > results = service . GetWithIncludes ( q => q . Where ( p => p . UserId == userid ) . Include ( p => p . User ) ) ;
300+ if ( results . Count ( ) == 0 ) return TypedResults . NotFound ( new ResponseDTO < Object > { Message = "No comments found for this user" } ) ;
301+
302+ IEnumerable < PostCommentDTO > PostCommentDTOs = mapper . Map < IEnumerable < PostCommentDTO > > ( results ) ;
303+ ResponseDTO < IEnumerable < PostCommentDTO > > response = new ResponseDTO < IEnumerable < PostCommentDTO > > ( )
304+ {
305+ Message = "Success" ,
306+ Data = PostCommentDTOs
307+ } ;
308+ return TypedResults . Ok ( response ) ;
309+ }
105310 }
106311}
0 commit comments