Skip to content
Open

1 #98

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
c41f264
Merge pull request #96 from Den1s-coder/developer
Den1s-coder Dec 6, 2025
1420b06
feat: add azure blob storage and profile user photo update (#67)
Den1s-coder Dec 6, 2025
cf43f65
feat: sort messages and split by users
Den1s-coder Dec 8, 2025
9a84d36
chore: update chat page
Den1s-coder Dec 9, 2025
4a4d7bb
feat: split chat messages on current user and others
Den1s-coder Dec 9, 2025
42e1fd2
feat: add avatar picture in profile page and change avatar button
Den1s-coder Dec 9, 2025
4258280
chore: update saved image url in DB
Den1s-coder Dec 9, 2025
b0b844c
feat: add FriendService and Dto
Den1s-coder Dec 16, 2025
07ac483
feat: add FriendService and Dto (#101)
Den1s-coder Dec 16, 2025
7878052
feat: Realise Friend service
Den1s-coder Dec 17, 2025
b6c5366
feat: add Friend controller
Den1s-coder Dec 17, 2025
d520acc
feat: Realise Friend proffile
Den1s-coder Dec 17, 2025
2bcbdb4
chore: add Created to Friendship
Den1s-coder Dec 17, 2025
1c6badc
feat: add GetUserFriendshipsAsync method
Den1s-coder Dec 17, 2025
c7c33dc
feat: Realise Friend service (#102)
Den1s-coder Dec 17, 2025
249ae83
feat: Realise Friend controller
Den1s-coder Dec 22, 2025
21680e5
chore: Remove username from DTO
Den1s-coder Dec 22, 2025
851bca3
chore: Remove CreatedAt from FriendShip because BaseEntity already ha…
Den1s-coder Dec 22, 2025
2c03eda
Feat: Realise friend controller (#103)
Den1s-coder Dec 22, 2025
48b3f67
chore: add DI for Friend repository and service
Den1s-coder Dec 23, 2025
b017a75
feat: Clicking on the username redirects to the user's profile page
Den1s-coder Dec 23, 2025
8603e14
feat: Add another user page (#64)
Den1s-coder Dec 23, 2025
909efd2
chore: add route for another user profile
Den1s-coder Dec 23, 2025
74adcd0
feat: other user profile (#64)
Den1s-coder Dec 23, 2025
40c9cf8
chore: add Login responce with tokens
Den1s-coder Dec 25, 2025
1805949
feat: update AuthService for work with Refresh Tokens
Den1s-coder Dec 25, 2025
b4c50d2
feat: add RefreshToken Entity (#75)
Den1s-coder Dec 25, 2025
76ee1e0
feat: add GenearateRefreshToken method in JwtProvider (#75)
Den1s-coder Dec 25, 2025
0d52ce8
feat: add RefreshToken Repository (#75)
Den1s-coder Dec 25, 2025
f7ffe17
chore: RefreshToken migrations
Den1s-coder Dec 25, 2025
2a69de7
feat: add RefreshToken endpoint (#75)
Den1s-coder Dec 25, 2025
a46337a
chore: add DI for RefreshToken Repository (#75)
Den1s-coder Dec 25, 2025
48304ea
feat: add refresh token (#75)
Den1s-coder Dec 25, 2025
a44a820
chore: update mobile AuthService for new login responce
Den1s-coder Dec 29, 2025
5ef7cfe
chore: add login responce DTO
Den1s-coder Dec 29, 2025
4d4d544
chore: Update mobile Auth service for new login responce (#107)
Den1s-coder Dec 29, 2025
dd44215
feat: add friendList page (#83)
Den1s-coder Dec 30, 2025
e17412e
feat: add friendList page (#83)
Den1s-coder Dec 30, 2025
c662b29
chore: new login responce token
Den1s-coder Jan 4, 2026
212b4c2
feat: add mediatr extension
Den1s-coder Jan 4, 2026
1d7d714
feat: add mediator extension
Den1s-coder Jan 4, 2026
6f7016c
feat: add PostCreated Event and Handler
Den1s-coder Jan 4, 2026
80e5655
feat: add EventDispatcher
Den1s-coder Jan 4, 2026
91f789d
chore: refactor create post method
Den1s-coder Jan 4, 2026
4b1b884
chore: refactor create method with mediatr (#109)
Den1s-coder Jan 4, 2026
278d027
feat: add createCommentEvent
Den1s-coder Jan 5, 2026
a0e5c5f
chore: refactor CreateComment method
Den1s-coder Jan 5, 2026
cdee743
chore: add Canceletion Tokens
Den1s-coder Jan 5, 2026
81147e8
chore: refactor Comment create (#110)
Den1s-coder Jan 5, 2026
a8ec85d
chore: DI in layers
Den1s-coder Jan 5, 2026
c92172c
chore: add pagineted result
Den1s-coder Jan 6, 2026
14e700a
feat: add GetPaged Async in PostService
Den1s-coder Jan 6, 2026
acb3a31
chore: add canceletion token in chat repo
Den1s-coder Jan 6, 2026
e5fcaf6
feat: add GetPagedAsync in Post repo
Den1s-coder Jan 6, 2026
6c05059
feat: add endpoint what return paged result
Den1s-coder Jan 6, 2026
a9b2fac
feat: add pagination for posts (#111)
Den1s-coder Jan 6, 2026
0eab775
feat: add pagination for comments (#112)
Den1s-coder Jan 8, 2026
1fb3cde
feat: add pagination for comments (#112)
Den1s-coder Jan 8, 2026
4c1029b
chore: change page on pageNumber
Den1s-coder Jan 13, 2026
b2ac012
feat: change loaing from load all on load paged
Den1s-coder Jan 13, 2026
a2e496d
feat: when access token is expired call refresh token endpoint
Den1s-coder Jan 14, 2026
ec844ee
chore: change fetch on authFetch
Den1s-coder Jan 14, 2026
7c72ab3
feat: change navbar
Den1s-coder Jan 14, 2026
1abe781
feat: paged load and update NavBar (#114)
Den1s-coder Jan 14, 2026
0c602f5
chore: chat controller and message service now return message dto
Den1s-coder Jan 15, 2026
b1a0c90
chore: add Profile picture url for dto
Den1s-coder Jan 15, 2026
e5e56fe
chore: message repository return message entitires include user
Den1s-coder Jan 15, 2026
b830d0e
feat: add Avatar component
Den1s-coder Jan 15, 2026
682a404
chore: update ChatHub hook
Den1s-coder Jan 15, 2026
ff144a6
feat: add avatars on Main,Post,ChatList and Chat pages
Den1s-coder Jan 15, 2026
036b800
feat: add user avatar in pages (#100, #82)
Den1s-coder Jan 15, 2026
42b1d99
chore: add side bar
Den1s-coder Jan 16, 2026
76361ea
feat: Realise Friends page
Den1s-coder Jan 20, 2026
29a57b9
chore: add Route for friends page
Den1s-coder Jan 20, 2026
b7fbbec
feat: update UI and add Friends page (#117)
Den1s-coder Jan 21, 2026
ad869f8
feat: realise accept and decline friendship in service
Den1s-coder Jan 26, 2026
209b2f7
feat: add canceletion tokens to friendship repository
Den1s-coder Jan 26, 2026
c01b1f7
chore: update authExtension for notificationHub
Den1s-coder Jan 27, 2026
ccde57f
feat: add notification Hub
Den1s-coder Jan 27, 2026
f60bbe7
feat: add notification publisher
Den1s-coder Jan 27, 2026
e667d52
feat: update Create post event for send notification
Den1s-coder Jan 27, 2026
14b483d
chore: migrations for notifications
Den1s-coder Jan 27, 2026
5e9788a
chore: add notifications config
Den1s-coder Jan 27, 2026
b99211b
feat: add notifications repository
Den1s-coder Jan 27, 2026
13dbc50
chore: add injections for notification
Den1s-coder Jan 27, 2026
7d7c20d
feat: add notification entity
Den1s-coder Jan 27, 2026
3820abf
feat: add notification service
Den1s-coder Jan 27, 2026
8930f1d
feat: update home page add create post space
Den1s-coder Jan 27, 2026
6c14b66
feat: add notification bell on navbar
Den1s-coder Jan 27, 2026
36f99c7
feat: add hook for notification hub
Den1s-coder Jan 27, 2026
8225e96
chore: update post DTO
Den1s-coder Jan 29, 2026
06cca16
chore: update post mapping profile
Den1s-coder Jan 29, 2026
13d1098
feat: add comment notification for post owner
Den1s-coder Jan 29, 2026
b924442
feat: add place for sending comments
Den1s-coder Jan 29, 2026
835eddb
Friends & Notification update (#121)
Den1s-coder Jan 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions backend/SocialNetwork.API/Controllers/AuthController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,39 @@ public AuthController(ILogger<AuthController> logger, IAuthService authService )
}

[HttpPost("register")]
public async Task<IActionResult> Register([FromBody] RegisterDto createUserDto)
public async Task<IActionResult> Register([FromBody] RegisterDto createUserDto, CancellationToken cancellationToken = default)
{
_logger.LogInformation("Register endpoint called");

await _authService.RegisterAsync(createUserDto);
await _authService.RegisterAsync(createUserDto, cancellationToken);

_logger.LogInformation("User Succesfully registered");

return Ok();
}

[HttpPost("login")]
public async Task<IActionResult> Login([FromBody] LoginDto loginDto)
public async Task<IActionResult> Login([FromBody] LoginDto loginDto, CancellationToken cancellationToken = default)
{
_logger.LogInformation("Login endpoint called");

var token = await _authService.LoginAsync(loginDto);
var responce = await _authService.LoginAsync(loginDto, cancellationToken);

_logger.LogInformation("User Succesfully login");

return Ok(token);
return Ok(responce);
}

[HttpPost("refresh-token")]
public async Task<IActionResult> RefreshToken([FromBody] string refreshToken)
{
_logger.LogInformation("Refresh token endpoint called");

var responce = await _authService.LoginWithRefreshTokenAsync(refreshToken);

_logger.LogInformation("Token successfully refreshed");

return Ok(responce);
}
}
}
16 changes: 9 additions & 7 deletions backend/SocialNetwork.API/Controllers/ChatController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Authorization;
using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SocialNetwork.Application.Interfaces;
using System.Security.Claims;
Expand All @@ -13,6 +14,7 @@ public class ChatController : ControllerBase
private readonly ILogger<ChatController> _logger;
private readonly IChatService _chatService;
private readonly IMessageService _messageService;
private readonly IMapper _mapper;

public ChatController(ILogger<ChatController> logger,
IMessageService messageService,
Expand All @@ -24,25 +26,25 @@ public ChatController(ILogger<ChatController> logger,
}

[HttpGet("chats")]
public async Task<IActionResult> MyChats()
public async Task<IActionResult> MyChats(CancellationToken cancellationToken = default)
{
var userId = Guid.Parse(User.Claims.First(c => c.Type == ClaimTypes.Sid).Value);
var chats = await _chatService.GetChatsByUserIdAsync(userId);
var chats = await _chatService.GetChatsByUserIdAsync(userId, cancellationToken);
return Ok(chats);
}

[HttpGet("chats/{chatId:guid}/messages")]
public async Task<IActionResult> GetMessages(Guid chatId)
public async Task<IActionResult> GetMessages(Guid chatId, CancellationToken cancellationToken = default)
{
var messages = await _messageService.GetMessageByChatIdAsync(chatId);
var messages = await _messageService.GetMessageByChatIdAsync(chatId, cancellationToken);
return Ok(messages);
}

[HttpPost("private/{secondUserId:guid}")]
public async Task<IActionResult> CreatePrivateChat(Guid secondUserId)
public async Task<IActionResult> CreatePrivateChat(Guid secondUserId, CancellationToken cancellationToken = default)
{
var userId = Guid.Parse(User.Claims.First(c => c.Type == ClaimTypes.Sid).Value);
var chat = await _chatService.CreatePrivateChatAsync(userId, secondUserId);
var chat = await _chatService.CreatePrivateChatAsync(userId, secondUserId, cancellationToken);
_logger.LogInformation("Private chat created between users {UserId1} and {UserId2} with Chat ID: {ChatId}", userId, secondUserId, chat.Id);
return Ok(new { chatId = chat.Id });
}
Expand Down
13 changes: 7 additions & 6 deletions backend/SocialNetwork.API/Controllers/CommentController.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using SocialNetwork.Application.DTO;
using SocialNetwork.Application.Interfaces;
using SocialNetwork.Domain.Entities;
Expand All @@ -21,16 +22,16 @@ public CommentController(ICommentService commentService, ILogger<CommentControll
}

[HttpGet("{postId:guid}/comments")]
public async Task<IActionResult> Get(Guid postId)
public async Task<IActionResult> GetPaged([FromQuery]int pageNumber, [FromQuery]int pageSize ,Guid postId, CancellationToken cancellationToken = default)
{
var comments = await _commentService.GetPostCommentsAsync(postId);
var comments = await _commentService.GetPostCommentsPagedAsync(postId, pageNumber, pageSize, cancellationToken);

return Ok(comments);
}

[Authorize]
[HttpPost("CreateComment")]
public async Task<IActionResult> Create([FromBody] CreateCommentDto createCommentDto)
public async Task<IActionResult> Create([FromBody] CreateCommentDto createCommentDto, CancellationToken cancellationToken = default)
{
if (!ModelState.IsValid)
{
Expand All @@ -42,17 +43,17 @@ public async Task<IActionResult> Create([FromBody] CreateCommentDto createCommen

createCommentDto.UserId = UserIdClaim;

await _commentService.CreateAsync(createCommentDto);
await _commentService.CreateAsync(createCommentDto, cancellationToken);

return Ok();
}


[Authorize(Roles = "Admin")]
[HttpDelete("{commentId:guid}")]
public async Task<IActionResult> Ban(Guid commentId)
public async Task<IActionResult> Ban(Guid commentId, CancellationToken cancellationToken = default)
{
await _commentService.BanComment(commentId);
await _commentService.BanComment(commentId, cancellationToken);

return Ok();
}
Expand Down
50 changes: 45 additions & 5 deletions backend/SocialNetwork.API/Controllers/FileController.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using SocialNetwork.Domain.Interfaces;
using Azure.Storage.Blobs;
using Microsoft.Extensions.Configuration;
using System.IO;
using System.Threading.Tasks;
using System;

namespace SocialNetwork.API.Controllers
{
Expand All @@ -9,26 +14,61 @@ namespace SocialNetwork.API.Controllers
public class FileController : ControllerBase
{
private readonly ICloudStorageService _storage;
private readonly BlobServiceClient _blobServiceClient;
private readonly string _containerName;

public FileController(ICloudStorageService storage)
public FileController(ICloudStorageService storage, BlobServiceClient blobServiceClient, IConfiguration configuration)
{
_storage = storage;
_blobServiceClient = blobServiceClient;
_containerName = configuration.GetValue<string>("AzureStorage:ContainerName");
}

[HttpPost("upload")]
public async Task<IActionResult> UploadFile(IFormFile file)
{
if (file == null || file.Length == 0)
{
return BadRequest("No file uploaded.");
}

var extension = Path.GetExtension(file.FileName);
var filename = $"{Guid.NewGuid()}{extension}";

using var stream = file.OpenReadStream();
var fileUrl = await _storage.UploadFileAsync(stream, filename, file.ContentType);
await _storage.UploadFileAsync(stream, filename, file.ContentType);

var fileUrl = $"{Request.Scheme}://{Request.Host}/api/File/{filename}";
return Ok(new { filename, fileUrl });
}

[HttpGet("{filename}")]
public async Task<IActionResult> GetFile(string filename)
{
if (string.IsNullOrWhiteSpace(filename))
return BadRequest();

var containerClient = _blobServiceClient.GetBlobContainerClient(_containerName);
var blobClient = containerClient.GetBlobClient(filename);

var exists = await blobClient.ExistsAsync();
if (!exists.Value) return NotFound();

var download = await blobClient.DownloadAsync();
var contentType = download.Value.ContentType ?? "application/octet-stream";
var stream = download.Value.Content;

Response.Headers["Cache-Control"] = "public, max-age=3600";

return File(stream, contentType);
}

[HttpDelete("{filename}")]
public async Task<IActionResult> DeleteFile(string filename)
{
if (string.IsNullOrWhiteSpace(filename))
return BadRequest();

await _storage.DeleteFileAsync(filename);
return NoContent();
}
}
}
}
120 changes: 120 additions & 0 deletions backend/SocialNetwork.API/Controllers/FriendController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using SocialNetwork.Application.DTO;
using SocialNetwork.Application.Interfaces;
using System.Security.Claims;

namespace SocialNetwork.API.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class FriendController : ControllerBase
{
private readonly ILogger<FriendController> _logger;
private readonly IFriendService _friendService;
public FriendController(ILogger<FriendController> logger, IFriendService friendService)
{
_logger = logger;
_friendService = friendService;
}

[HttpGet("GetAllFriends")]
public async Task<IActionResult> GetAllFriends(CancellationToken cancellationToken = default)
{
var friends = await _friendService.GetAllFriends(cancellationToken);
return Ok(friends);
}

[HttpGet("{userId}/Friends")]
public async Task<IActionResult> GetFriendsOfUser(Guid userId, CancellationToken cancellationToken = default)
{
var friends = await _friendService.GetFriendsOfUser(userId, cancellationToken);
return Ok(friends);
}

[Authorize]
[HttpGet("PendingRequests")]
public async Task<IActionResult> GetPendingFriendRequests(CancellationToken cancellationToken = default)
{
var UserIdClaim = Guid.Parse(User.Claims.First(c => c.Type == ClaimTypes.Sid).Value);

if (UserIdClaim == Guid.Empty)
{
_logger.LogWarning("UserId claim is missing or invalid.");
return Unauthorized();
}

var requests = await _friendService.GetPendingFriendRequests(UserIdClaim, cancellationToken);
return Ok(requests);
}

[Authorize]
[HttpGet("MyFriends")]
public async Task<IActionResult> GetMyFriends(CancellationToken cancellationToken = default)
{
var UserIdClaim = Guid.Parse(User.Claims.First(c => c.Type == ClaimTypes.Sid).Value);
if (UserIdClaim == Guid.Empty)
{
_logger.LogWarning("UserId claim is missing or invalid.");
return Unauthorized();
}
var friends = await _friendService.GetFriendsOfUser(UserIdClaim, cancellationToken);
return Ok(friends);
}

[Authorize]
[HttpPost("SendFriendRequest")]
public async Task<IActionResult> SendFriendRequest([FromBody] Guid addresseeId, CancellationToken cancellationToken = default)
{
var UserIdClaim = Guid.Parse(User.Claims.First(c => c.Type == ClaimTypes.Sid).Value);
if (UserIdClaim == Guid.Empty)
{
_logger.LogWarning("UserId claim is missing or invalid.");
return Unauthorized();
}

var request = new FriendRequestDto
{
RequesterId = UserIdClaim,
ReceiverId = addresseeId,
RequestedAt = DateTime.UtcNow
};

await _friendService.SendFriendRequest(request, cancellationToken);
return Ok();

}

[Authorize]
[HttpPost("AcceptFriendRequest/{requestId:guid}")]
public async Task<IActionResult> AcceptFriendRequest(Guid requestId, CancellationToken cancellationToken = default)
{
await _friendService.AcceptFriendRequest(requestId, cancellationToken);
return Ok();
}

[Authorize]
[HttpPost("DeclineFriendRequest/{requestId:guid}")]
public async Task<IActionResult> DeclineFriendRequest(Guid requestId, CancellationToken cancellationToken = default)
{
await _friendService.DeclineFriendRequest(requestId, cancellationToken);
return Ok();
}

[Authorize]
[HttpDelete("RemoveFriend/{friendId:guid}")]
public async Task<IActionResult> RemoveFriend(Guid friendId, CancellationToken cancellationToken = default)
{
var UserIdClaim = Guid.Parse(User.Claims.First(c => c.Type == ClaimTypes.Sid).Value);
if (UserIdClaim == Guid.Empty)
{
_logger.LogWarning("UserId claim is missing or invalid.");
return Unauthorized();
}

await _friendService.RemoveFriend(UserIdClaim, friendId);
return Ok();
}
}
}
Loading