version 3
This commit is contained in:
185
src/GreenHome.Infrastructure/DevicePostService.cs
Normal file
185
src/GreenHome.Infrastructure/DevicePostService.cs
Normal file
@@ -0,0 +1,185 @@
|
||||
using AutoMapper;
|
||||
using GreenHome.Application;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace GreenHome.Infrastructure;
|
||||
|
||||
public sealed class DevicePostService : IDevicePostService
|
||||
{
|
||||
private readonly GreenHomeDbContext _context;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public DevicePostService(GreenHomeDbContext context, IMapper mapper)
|
||||
{
|
||||
_context = context;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<PagedResult<DevicePostDto>> GetPostsAsync(
|
||||
DevicePostFilter filter,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var query = _context.DevicePosts
|
||||
.Include(p => p.AuthorUser)
|
||||
.Include(p => p.Images)
|
||||
.AsNoTracking()
|
||||
.Where(p => p.DeviceId == filter.DeviceId);
|
||||
|
||||
if (filter.AuthorUserId.HasValue)
|
||||
{
|
||||
query = query.Where(p => p.AuthorUserId == filter.AuthorUserId.Value);
|
||||
}
|
||||
|
||||
var totalCount = await query.CountAsync(cancellationToken);
|
||||
|
||||
var posts = await query
|
||||
.OrderByDescending(p => p.CreatedAt)
|
||||
.Skip((filter.Page - 1) * filter.PageSize)
|
||||
.Take(filter.PageSize)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var dtos = _mapper.Map<List<DevicePostDto>>(posts);
|
||||
|
||||
return new PagedResult<DevicePostDto>
|
||||
{
|
||||
Items = dtos,
|
||||
TotalCount = totalCount,
|
||||
Page = filter.Page,
|
||||
PageSize = filter.PageSize
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<DevicePostDto?> GetPostByIdAsync(int id, CancellationToken cancellationToken)
|
||||
{
|
||||
var post = await _context.DevicePosts
|
||||
.Include(p => p.AuthorUser)
|
||||
.Include(p => p.Images)
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(p => p.Id == id, cancellationToken);
|
||||
|
||||
return post != null ? _mapper.Map<DevicePostDto>(post) : null;
|
||||
}
|
||||
|
||||
public async Task<int> CreatePostAsync(
|
||||
CreateDevicePostRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
// Verify user has access to device
|
||||
var hasAccess = await CanUserAccessDeviceAsync(request.AuthorUserId, request.DeviceId, cancellationToken);
|
||||
if (!hasAccess)
|
||||
{
|
||||
throw new UnauthorizedAccessException("کاربر به این دستگاه دسترسی ندارد");
|
||||
}
|
||||
|
||||
var post = new Domain.DevicePost
|
||||
{
|
||||
DeviceId = request.DeviceId,
|
||||
AuthorUserId = request.AuthorUserId,
|
||||
Content = request.Content,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
|
||||
_context.DevicePosts.Add(post);
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return post.Id;
|
||||
}
|
||||
|
||||
public async Task UpdatePostAsync(
|
||||
UpdateDevicePostRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var post = await _context.DevicePosts
|
||||
.FirstOrDefaultAsync(p => p.Id == request.Id, cancellationToken);
|
||||
|
||||
if (post == null)
|
||||
{
|
||||
throw new InvalidOperationException($"پست با شناسه {request.Id} یافت نشد");
|
||||
}
|
||||
|
||||
post.Content = request.Content;
|
||||
post.UpdatedAt = DateTime.UtcNow;
|
||||
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public async Task DeletePostAsync(int id, CancellationToken cancellationToken)
|
||||
{
|
||||
var post = await _context.DevicePosts
|
||||
.Include(p => p.Images)
|
||||
.FirstOrDefaultAsync(p => p.Id == id, cancellationToken);
|
||||
|
||||
if (post == null)
|
||||
{
|
||||
throw new InvalidOperationException($"پست با شناسه {id} یافت نشد");
|
||||
}
|
||||
|
||||
_context.DevicePosts.Remove(post);
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<int> AddImageToPostAsync(
|
||||
int postId,
|
||||
string fileName,
|
||||
string filePath,
|
||||
string contentType,
|
||||
long fileSize,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var post = await _context.DevicePosts
|
||||
.FirstOrDefaultAsync(p => p.Id == postId, cancellationToken);
|
||||
|
||||
if (post == null)
|
||||
{
|
||||
throw new InvalidOperationException($"پست با شناسه {postId} یافت نشد");
|
||||
}
|
||||
|
||||
var image = new Domain.DevicePostImage
|
||||
{
|
||||
DevicePostId = postId,
|
||||
FileName = fileName,
|
||||
FilePath = filePath,
|
||||
ContentType = contentType,
|
||||
FileSize = fileSize,
|
||||
UploadedAt = DateTime.UtcNow
|
||||
};
|
||||
|
||||
_context.DevicePostImages.Add(image);
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return image.Id;
|
||||
}
|
||||
|
||||
public async Task DeleteImageAsync(int imageId, CancellationToken cancellationToken)
|
||||
{
|
||||
var image = await _context.DevicePostImages
|
||||
.FirstOrDefaultAsync(i => i.Id == imageId, cancellationToken);
|
||||
|
||||
if (image == null)
|
||||
{
|
||||
throw new InvalidOperationException($"تصویر با شناسه {imageId} یافت نشد");
|
||||
}
|
||||
|
||||
_context.DevicePostImages.Remove(image);
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<bool> CanUserAccessDeviceAsync(
|
||||
int userId,
|
||||
int deviceId,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
// Check if user is the device owner or has access through DeviceUsers
|
||||
var hasAccess = await _context.Devices
|
||||
.AnyAsync(d => d.Id == deviceId && d.UserId == userId, cancellationToken);
|
||||
|
||||
if (!hasAccess)
|
||||
{
|
||||
hasAccess = await _context.DeviceUsers
|
||||
.AnyAsync(du => du.DeviceId == deviceId && du.UserId == userId, cancellationToken);
|
||||
}
|
||||
|
||||
return hasAccess;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user