aboutsummaryrefslogtreecommitdiff
path: root/Backend
diff options
context:
space:
mode:
Diffstat (limited to 'Backend')
-rw-r--r--Backend/Api/Api/Api.csproj1
-rw-r--r--Backend/Api/Api/Controllers/PostController.cs53
-rw-r--r--Backend/Api/Api/Interfaces/IPostService.cs9
-rw-r--r--Backend/Api/Api/Models/Post.cs36
-rw-r--r--Backend/Api/Api/Program.cs14
-rw-r--r--Backend/Api/Api/Services/PostService.cs182
6 files changed, 278 insertions, 17 deletions
diff --git a/Backend/Api/Api/Api.csproj b/Backend/Api/Api/Api.csproj
index 80898fd..24c41b7 100644
--- a/Backend/Api/Api/Api.csproj
+++ b/Backend/Api/Api/Api.csproj
@@ -13,6 +13,7 @@
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.10" />
<PackageReference Include="MongoDB.Driver" Version="2.18.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
+ <PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="7.0.5" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.24.0" />
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
<PackageReference Include="MailKit" Version="3.4.2" />
diff --git a/Backend/Api/Api/Controllers/PostController.cs b/Backend/Api/Api/Controllers/PostController.cs
index a61ee2e..27823bc 100644
--- a/Backend/Api/Api/Controllers/PostController.cs
+++ b/Backend/Api/Api/Controllers/PostController.cs
@@ -14,10 +14,12 @@ namespace Api.Controllers
{
private readonly IPostService _postService;
private readonly IFileService _fileService;
- public PostController(IPostService postService, IFileService fileService)
+ private readonly IUserService _userService;
+ public PostController(IPostService postService, IFileService fileService,IUserService userService)
{
_postService = postService;
_fileService = fileService;
+ _userService = userService;
}
[HttpPost("add")]
@@ -46,7 +48,8 @@ namespace Api.Controllers
[Authorize(Roles = "User")]
public async Task<ActionResult<PostSend>> getPostByid(string id)
{
- var res = await _postService.getPostById(id);
+ var userid = await _userService.UserIdFromJwt();
+ var res = await _postService.getPostById(id,userid);
if (res != null)
{
return Ok(res);
@@ -62,10 +65,56 @@ namespace Api.Controllers
if (f == null || !System.IO.File.Exists(f.path))
return BadRequest("Slika ne postoji");
return File(System.IO.File.ReadAllBytes(f.path), "image/*", Path.GetFileName(f.path));
+ }
+ [HttpPost("posts/{id}/addrating")]
+ [Authorize(Roles = "User")]
+ public async Task<ActionResult> addRating([FromBody] RatingReceive rating,string id)
+ {
+ var userid = await _userService.UserIdFromJwt();
+ if (await _postService.AddOrReplaceRating(rating, userid))
+ return Ok();
+ return BadRequest();
+ }
+ [HttpDelete("posts/{id}/removerating")]
+ [Authorize(Roles = "User")]
+ public async Task<ActionResult> removeRating(string id)
+ {
+ var userid = await _userService.UserIdFromJwt();
+ if (await _postService.RemoveRating(id,userid))
+ return Ok();
+ return BadRequest();
}
+ [HttpPost("posts/{id}/addcomment")]
+ [Authorize(Roles = "User")]
+ public async Task<ActionResult> addComment([FromBody] CommentReceive cmnt,string id)
+ {
+ var userid = await _userService.UserIdFromJwt();
+ if (await _postService.AddComment(cmnt,userid,id))
+ return Ok();
+ return BadRequest();
+ }
+
+ [HttpGet("posts/{id}/listcomments")]
+ [Authorize(Roles = "User")]
+ public async Task<ActionResult<List<CommentSend>>> listComments(string id)
+ {
+ var ret = await _postService.ListComments(id);
+ if(ret != null)
+ return Ok(ret);
+ return BadRequest();
+ }
+ [HttpDelete("posts/{id}/removecomment/{cmntid}")]
+ [Authorize(Roles = "User")]
+ public async Task<ActionResult> removeRating(string id,string cmntid)
+ {
+ var userid = await _userService.UserIdFromJwt();
+ if (await _postService.DeleteComments(id,cmntid,userid))
+ return Ok();
+ return BadRequest();
+ }
}
}
diff --git a/Backend/Api/Api/Interfaces/IPostService.cs b/Backend/Api/Api/Interfaces/IPostService.cs
index 29a824a..daeee92 100644
--- a/Backend/Api/Api/Interfaces/IPostService.cs
+++ b/Backend/Api/Api/Interfaces/IPostService.cs
@@ -6,7 +6,14 @@ namespace Api.Interfaces
{
Task<PostSend> addPost(PostReceive post);
Task<List<PostSend>> getAllPosts();
- Task<PostSend> getPostById(string id);
+ Task<PostSend> getPostById(string id,string userid);
Task<PostSend> postToPostSend(Post post);
+ Task<Boolean> AddOrReplaceRating(RatingReceive rating, string userid);
+ Task<Boolean> RemoveRating(string postid, string userid);
+ Task<Boolean> AddComment(CommentReceive cmnt, string userid, string postid);
+ Task<List<CommentSend>> ListComments(string postid);
+ Task<List<CommentSend>> CascadeComments(string parentid, Post p);
+ Task<Boolean> DeleteComments(string postid, string cmntid,string userid);
+ Task CascadeDeleteComments(string cmntid, Post p);
}
} \ No newline at end of file
diff --git a/Backend/Api/Api/Models/Post.cs b/Backend/Api/Api/Models/Post.cs
index ee84e0f..c832d23 100644
--- a/Backend/Api/Api/Models/Post.cs
+++ b/Backend/Api/Api/Models/Post.cs
@@ -20,9 +20,7 @@ namespace Api.Models
}
public class PostReceive
{
- [BsonId]
- [BsonRepresentation(BsonType.ObjectId)]
- public string _id { get; set; }
+ public string? _id { get; set; }
public string locationId { get; set; }
public string description { get; set; }
public List<IFormFile> images { get; set; }
@@ -31,15 +29,13 @@ namespace Api.Models
}
public class PostSend
{
- [BsonId]
- [BsonRepresentation(BsonType.ObjectId)]
public string _id { get; set; }
public string ownerId { get; set; }
public Location location { get; set; }
public string description { get; set; }
public int views { get; set; }
- public float ratings { get; set; }
- public List<Comment> comments { get; set; }
+ public double ratings { get; set; }
+ public List<CommentSend> comments { get; set; }
public List<File> images { get; set; }
}
public class Rating
@@ -49,9 +45,33 @@ namespace Api.Models
}
public class Comment
{
+ [BsonId]
+ [BsonRepresentation(BsonType.ObjectId)]
+ public string _id { get; set; }
+ public string userId { get; set; }
+ public string comment { get; set; }
+ public string parentId { get; set; }
+ public DateTime timestamp { get; set; }
+ }
+
+ public class RatingReceive
+ {
+ public int rating { get; set; }
+ public string postId { get; set; }
+ }
+ public class CommentSend
+ {
+ public string _id { get; set; }
public string userId { get; set; }
public string comment { get; set; }
- public Comment parent { get; set; }
+ public string? parentId { get; set; }
public DateTime timestamp { get; set; }
+ public string username { get; set; }
+ public List<CommentSend> replies { get; set; }
+ }
+ public class CommentReceive
+ {
+ public string comment { get; set; }
+ public string parentId { get; set; }
}
}
diff --git a/Backend/Api/Api/Program.cs b/Backend/Api/Api/Program.cs
index 16b0241..7d6b03e 100644
--- a/Backend/Api/Api/Program.cs
+++ b/Backend/Api/Api/Program.cs
@@ -4,7 +4,9 @@ using Api.Services;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
+using Microsoft.OpenApi.Models;
using MongoDB.Driver;
+using Swashbuckle.AspNetCore.Filters;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
@@ -50,7 +52,17 @@ builder.Services.AddAuthentication(
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
-builder.Services.AddSwaggerGen();
+builder.Services.AddSwaggerGen(options => {
+ options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
+ {
+ Description = "Standard Authorization header using the Bearer scheme (\"bearer {token}\")",
+ In = ParameterLocation.Header,
+ Name = "Authorization",
+ Type = SecuritySchemeType.ApiKey
+ });
+
+ options.OperationFilter<SecurityRequirementsOperationFilter>();
+});
builder.Services.AddCors(options =>
{
diff --git a/Backend/Api/Api/Services/PostService.cs b/Backend/Api/Api/Services/PostService.cs
index e9a56d2..78167bd 100644
--- a/Backend/Api/Api/Services/PostService.cs
+++ b/Backend/Api/Api/Services/PostService.cs
@@ -2,6 +2,8 @@
using Api.Interfaces;
using Api.Models;
using MongoDB.Driver;
+using MongoDB.Bson.Serialization.Attributes;
+using MongoDB.Bson;
namespace Api.Services
{
@@ -12,10 +14,12 @@ namespace Api.Services
private readonly IHttpContextAccessor _httpContext;
private readonly IFileService _fileService;
private readonly ILocationService _locationService;
+ private readonly IMongoCollection<User> _users;
public PostService(IDatabaseConnection settings, IMongoClient mongoClient, IHttpContextAccessor httpContext, IFileService fileService,ILocationService locationService)
{
var database = mongoClient.GetDatabase(settings.DatabaseName);
_posts = database.GetCollection<Post>(settings.PostCollectionName);
+ _users = database.GetCollection<User>(settings.UserCollectionName);
_httpContext = httpContext;
_fileService = fileService;
_locationService = locationService;
@@ -25,7 +29,7 @@ namespace Api.Services
{
Post p = new Post();
p._id = "";
- p.ownerId = _httpContext.HttpContext.User.FindFirstValue("id").ToString();
+ p.ownerId = _httpContext.HttpContext.User.FindFirstValue("id");
p.locationId = post.locationId;
p.description = post.description;
@@ -77,8 +81,16 @@ namespace Api.Services
p.description = post.description;
p.location = await _locationService.getById(post.locationId);
p.images = post.images;
- p.views = 1;//Default values todo
- p.ratings = 1;
+ p.views = post.views.Count();
+ if (post.ratings.Count() > 0)
+ {
+ List<int> ratings = new List<int>();
+ foreach (var r in post.ratings)
+ ratings.Add(r.rating);
+ p.ratings = ratings.Average();
+ }
+ else
+ p.ratings = 0;
p.comments = null;
@@ -96,12 +108,172 @@ namespace Api.Services
return temp;
}
- public async Task<PostSend> getPostById(string id)
+ public async Task<PostSend> getPostById(string id,string userid)
{
Post p = await _posts.Find(post => post._id == id).FirstOrDefaultAsync();
+ if (p != null)
+ {
+ if (!p.views.Any(x => x == userid))
+ {
+ p.views.Add(userid);
+ await _posts.ReplaceOneAsync(x => x._id == id, p);
+ }
+ }
return await postToPostSend(p);
+ }
+
+ public async Task<Boolean> AddOrReplaceRating(RatingReceive rating,string userid)
+ {
+ Post p = await _posts.Find(post => post._id == rating.postId).FirstOrDefaultAsync();
+ if (p != null)
+ {
+ if (p.ownerId == userid)
+ return false;
+ if(!p.ratings.Any(x => x.userId == userid))
+ {
+ Rating r = new Rating();
+ r.rating = rating.rating;
+ r.userId = userid;
+ p.ratings.Add(r);
+ await _posts.ReplaceOneAsync(x => x._id == p._id, p);
+ }
+ else
+ {
+ var r = p.ratings.Find(x => x.userId == userid);
+ p.ratings.Remove(r);
+ r.rating = rating.rating;
+ p.ratings.Add(r);
+ await _posts.ReplaceOneAsync(x => x._id == p._id, p);
+ }
+ return true;
+ }
+ return false;
+ }
+ public async Task<Boolean> RemoveRating(string postid, string userid)
+ {
+ Post p = await _posts.Find(post => post._id == postid).FirstOrDefaultAsync();
+ if (p != null)
+ {
+ if (p.ratings.Any(x => x.userId == userid))
+ {
+ var r = p.ratings.Find(x => x.userId == userid);
+ p.ratings.Remove(r);
+ await _posts.ReplaceOneAsync(x => x._id == postid, p);
+ return true;
+ }
+ }
+ return false;
+ }
+ public async Task<Boolean> AddComment(CommentReceive cmnt,string userid,string postid)
+ {
+ Post p = await _posts.Find(post => post._id == postid).FirstOrDefaultAsync();
+ if (p != null)
+ {
+ Comment c= new Comment();
+ c.parentId = cmnt.parentId;
+ c.userId = userid;
+ c.comment = cmnt.comment;
+ c.timestamp = DateTime.Now.ToUniversalTime();
+ c._id = ObjectId.GenerateNewId().ToString();
+ p.comments.Add(c);
+ await _posts.ReplaceOneAsync(x => x._id == postid, p);
+ return true;
+ }
+ return false;
+ }
+ public async Task<List<CommentSend>> ListComments(string postid)
+ {
+ Post p = await _posts.Find(post => post._id == postid).FirstOrDefaultAsync();
+ if (p != null)
+ {
+ List<Comment> lista = new List<Comment>();
+ lista = p.comments.FindAll(x => x.parentId == null || x.parentId == "");
+ if (lista.Count() > 0)
+ {
+ List<CommentSend> tosend = new List<CommentSend>();
+ foreach(var comment in lista)
+ {
+ CommentSend c = new CommentSend();
+ c.userId = comment.userId;
+ c._id = comment._id;
+ c.parentId = comment.parentId;
+ c.comment = comment.comment;
+ c.timestamp = comment.timestamp;
+
+ var user = await _users.Find(x => x._id == comment.userId).FirstOrDefaultAsync();
+ if (user != null)
+ c.username = user.username;
+ else c.username = "Deleted user";
+
+ c.replies = await CascadeComments(comment._id, p);
+
+ tosend.Add(c);
+ }
+ return tosend;
+ }
+ }
+ return null;
+ }
+ public async Task<List<CommentSend>> CascadeComments(string parentid,Post p)
+ {
+ List<Comment> lista = new List<Comment>();
+ lista = p.comments.FindAll(x => x.parentId == parentid);
+ if (lista.Count()>0)
+ {
+ List<CommentSend> replies = new List<CommentSend>();
+ foreach (var comment in lista)
+ {
+ CommentSend c = new CommentSend();
+ c.userId = comment.userId;
+ c._id = comment._id;
+ c.parentId = comment.parentId;
+ c.comment = comment.comment;
+ c.timestamp = comment.timestamp;
+
+ var user= await _users.Find(x => x._id == comment.userId).FirstOrDefaultAsync();
+ if (user != null)
+ c.username = user.username;
+ else c.username = "Deleted user";
+
+ c.replies = await CascadeComments(comment._id, p);
+
+ replies.Add(c);
+ }
+ return replies;
+ }
+ return null;
+ }
+ public async Task<Boolean> DeleteComments(string postid,string cmntid,string userid)
+ {
+ Post p = await _posts.Find(post => post._id == postid).FirstOrDefaultAsync();
+ if (p != null)
+ {
+ var com = p.comments.Find(x => x._id == cmntid);
+ if (com != null && com.userId == userid)
+ {
+ var comment = p.comments.Find(x => x._id == cmntid);
+ p.comments.Remove(comment);
+ await _posts.ReplaceOneAsync(x => x._id == p._id, p);
+ await CascadeDeleteComments(cmntid, p);
+ return true;
+ }
+ }
+ return false;
+ }
+ public async Task CascadeDeleteComments(string cmntid,Post p)
+ {
+ List<Comment> lista = new List<Comment>();
+ lista = p.comments.FindAll(x => x.parentId == cmntid);
+ if (lista.Count() > 0)
+ {
+ foreach (var comment in lista)
+ {
+ p.comments.Remove(comment);
+ await _posts.ReplaceOneAsync(x => x._id == p._id, p);
+ await CascadeDeleteComments(comment._id, p);
+ }
+ }
}
- //(TODO) ADD Delete and update
}
}