Files
GreenHomeBack/src/GreenHome.Api/Controllers/DevicePostsController.cs
2026-09-10 19:09:36 +03:30

293 lines
9.9 KiB
C#

using Microsoft.AspNetCore.Mvc;
using GreenHome.Application;
namespace GreenHome.Api.Controllers;
[ApiController]
[Route("api/[controller]")]
public class DevicePostsController : ControllerBase
{
private readonly IDevicePostService _postService;
private readonly ILogger<DevicePostsController> _logger;
private readonly IWebHostEnvironment _environment;
public DevicePostsController(
IDevicePostService postService,
ILogger<DevicePostsController> logger,
IWebHostEnvironment environment)
{
_postService = postService;
_logger = logger;
_environment = environment;
}
/// <summary>
/// دریافت پست‌های گروه مجازی دستگاه (تایم‌لاین)
/// </summary>
[HttpGet]
public async Task<ActionResult<PagedResult<DevicePostDto>>> GetPosts(
[FromQuery] int deviceId,
[FromQuery] int? authorUserId,
[FromQuery] int page = 1,
[FromQuery] int pageSize = 20,
CancellationToken cancellationToken = default)
{
var filter = new DevicePostFilter
{
DeviceId = deviceId,
AuthorUserId = authorUserId,
Page = page,
PageSize = pageSize
};
var result = await _postService.GetPostsAsync(filter, cancellationToken);
return Ok(result);
}
/// <summary>
/// دریافت جزئیات یک پست
/// </summary>
[HttpGet("{id}")]
public async Task<ActionResult<DevicePostDto>> GetPostById(int id, CancellationToken cancellationToken)
{
var result = await _postService.GetPostByIdAsync(id, cancellationToken);
if (result == null)
{
return NotFound(new { error = $"پست با شناسه {id} یافت نشد" });
}
return Ok(result);
}
/// <summary>
/// ایجاد پست جدید در گروه مجازی
/// </summary>
[HttpPost]
public async Task<ActionResult<int>> CreatePost(
CreateDevicePostRequest request,
CancellationToken cancellationToken)
{
try
{
var id = await _postService.CreatePostAsync(request, cancellationToken);
return Ok(new { id, message = "پست با موفقیت ایجاد شد" });
}
catch (UnauthorizedAccessException ex)
{
return Unauthorized(new { error = ex.Message });
}
}
/// <summary>
/// ویرایش پست
/// </summary>
[HttpPut]
public async Task<ActionResult> UpdatePost(
UpdateDevicePostRequest request,
CancellationToken cancellationToken)
{
try
{
await _postService.UpdatePostAsync(request, cancellationToken);
return Ok(new { message = "پست با موفقیت ویرایش شد" });
}
catch (InvalidOperationException ex)
{
return NotFound(new { error = ex.Message });
}
}
/// <summary>
/// حذف پست
/// </summary>
[HttpDelete("{id}")]
public async Task<ActionResult> DeletePost(int id, CancellationToken cancellationToken)
{
try
{
await _postService.DeletePostAsync(id, cancellationToken);
return Ok(new { message = "پست با موفقیت حذف شد" });
}
catch (InvalidOperationException ex)
{
return NotFound(new { error = ex.Message });
}
}
/// <summary>
/// آپلود تصویر برای پست
/// </summary>
[HttpPost("{postId}/images")]
[Consumes("multipart/form-data")]
public async Task<ActionResult<int>> UploadImage(
int postId,
[FromForm] IFormFile file,
CancellationToken cancellationToken)
{
try
{
if (file == null || file.Length == 0)
{
return BadRequest(new { error = "فایل انتخاب نشده است" });
}
// Validate file type
var allowedTypes = new[] { "image/jpeg", "image/jpg", "image/png", "image/gif", "image/webp" };
if (!allowedTypes.Contains(file.ContentType.ToLower()))
{
return BadRequest(new { error = "فقط فایل‌های تصویری مجاز هستند" });
}
// Validate file size (max 5MB)
if (file.Length > 5 * 1024 * 1024)
{
return BadRequest(new { error = "حجم فایل نباید بیشتر از 5 مگابایت باشد" });
}
// Create upload directory
var uploadsFolder = Path.Combine(_environment.WebRootPath ?? "wwwroot", "uploads", "posts");
Directory.CreateDirectory(uploadsFolder);
// Generate unique filename
var fileName = $"{Guid.NewGuid()}_{Path.GetFileName(file.FileName)}";
var filePath = Path.Combine(uploadsFolder, fileName);
// Save file
using (var stream = new FileStream(filePath, FileMode.Create))
{
await file.CopyToAsync(stream, cancellationToken);
}
// Save to database
var relativePath = $"/uploads/posts/{fileName}";
var imageId = await _postService.AddImageToPostAsync(
postId,
file.FileName,
relativePath,
file.ContentType,
file.Length,
cancellationToken);
_logger.LogInformation("Image uploaded for post {PostId}: {ImageId}", postId, imageId);
return Ok(new { imageId, filePath = relativePath, message = "تصویر با موفقیت آپلود شد" });
}
catch (InvalidOperationException ex)
{
return NotFound(new { error = ex.Message });
}
catch (Exception ex)
{
_logger.LogError(ex, "Error uploading image for post {PostId}", postId);
return StatusCode(500, new { error = "خطا در آپلود تصویر" });
}
}
/// <summary>
/// حذف تصویر از پست
/// </summary>
[HttpDelete("images/{imageId}")]
public async Task<ActionResult> DeleteImage(int imageId, CancellationToken cancellationToken)
{
try
{
await _postService.DeleteImageAsync(imageId, cancellationToken);
return Ok(new { message = "تصویر با موفقیت حذف شد" });
}
catch (InvalidOperationException ex)
{
return NotFound(new { error = ex.Message });
}
}
/// <summary>
/// بررسی دسترسی کاربر به دستگاه
/// </summary>
[HttpGet("access/{userId}/{deviceId}")]
public async Task<ActionResult<bool>> CheckAccess(int userId, int deviceId, CancellationToken cancellationToken)
{
var hasAccess = await _postService.CanUserAccessDeviceAsync(userId, deviceId, cancellationToken);
return Ok(new { hasAccess });
}
/// <summary>
/// ایجاد پست اسنپ‌شات وضعیت سنسورها و رله‌ها
/// </summary>
[HttpPost("sensor-snapshot")]
public async Task<ActionResult<int>> CreateSensorSnapshot(
CreateSensorSnapshotRequest request,
CancellationToken cancellationToken)
{
try
{
var id = await _postService.CreateSensorSnapshotAsync(request, cancellationToken);
return Ok(new { id, message = "وضعیت سنسورها و رله‌ها ارسال شد" });
}
catch (UnauthorizedAccessException ex)
{
return Unauthorized(new { error = ex.Message });
}
}
/// <summary>
/// آپلود فایل صوتی (ویس) برای پست
/// </summary>
[HttpPost("{postId}/voice")]
[Consumes("multipart/form-data")]
public async Task<ActionResult> UploadVoice(
int postId,
[FromForm] IFormFile file,
[FromForm] int? durationSeconds,
CancellationToken cancellationToken)
{
try
{
if (file == null || file.Length == 0)
return BadRequest(new { error = "فایل انتخاب نشده است" });
var allowedTypes = new[]
{
"audio/webm", "audio/ogg", "audio/mp4", "audio/mpeg",
"audio/wav", "audio/x-wav", "audio/amr", "audio/aac", "audio/m4a"
};
if (!allowedTypes.Contains(file.ContentType.ToLower()))
return BadRequest(new { error = "فرمت فایل صوتی مجاز نیست" });
if (file.Length > 10 * 1024 * 1024)
return BadRequest(new { error = "حجم فایل صوتی نباید بیشتر از 10 مگابایت باشد" });
var uploadsFolder = Path.Combine(_environment.WebRootPath ?? "wwwroot", "uploads", "voice");
Directory.CreateDirectory(uploadsFolder);
var fileName = $"{Guid.NewGuid()}{Path.GetExtension(file.FileName)}";
var filePath = Path.Combine(uploadsFolder, fileName);
await using (var stream = new FileStream(filePath, FileMode.Create))
{
await file.CopyToAsync(stream, cancellationToken);
}
var relativePath = $"/uploads/voice/{fileName}";
await _postService.SetPostVoiceAsync(
postId,
file.FileName,
relativePath,
file.ContentType,
file.Length,
durationSeconds,
cancellationToken);
return Ok(new { filePath = relativePath, message = "ویس با موفقیت آپلود شد" });
}
catch (InvalidOperationException ex)
{
return NotFound(new { error = ex.Message });
}
catch (Exception ex)
{
_logger.LogError(ex, "Error uploading voice for post {PostId}", postId);
return StatusCode(500, new { error = "خطا در آپلود ویس" });
}
}
}