add chat and users

This commit is contained in:
2026-09-10 19:09:36 +03:30
parent 91ad61bdee
commit 8eb465c0e7
40 changed files with 4888 additions and 148 deletions

View File

@@ -0,0 +1,120 @@
using Microsoft.AspNetCore.Mvc;
using GreenHome.Application;
namespace GreenHome.Api.Controllers;
[ApiController]
[Route("api/[controller]")]
public class DeviceMembersController : ControllerBase
{
private readonly IDeviceMemberService _memberService;
private readonly IWebHostEnvironment _environment;
private readonly ILogger<DeviceMembersController> _logger;
public DeviceMembersController(
IDeviceMemberService memberService,
IWebHostEnvironment environment,
ILogger<DeviceMembersController> logger)
{
_memberService = memberService;
_environment = environment;
_logger = logger;
}
/// <summary>لیست اعضای تیم یک دستگاه</summary>
[HttpGet]
public async Task<ActionResult<IReadOnlyList<DeviceMemberDto>>> List(
[FromQuery] int deviceId,
CancellationToken cancellationToken)
{
var result = await _memberService.ListByDeviceAsync(deviceId, cancellationToken);
return Ok(result);
}
/// <summary>افزودن یا ویرایش عضو تیم</summary>
[HttpPost]
public async Task<ActionResult<DeviceMemberDto>> Upsert(
[FromBody] UpsertDeviceMemberRequest request,
CancellationToken cancellationToken)
{
try
{
var result = await _memberService.UpsertAsync(request, cancellationToken);
return Ok(result);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error upserting device member");
return BadRequest(new { error = ex.Message });
}
}
/// <summary>حذف عضو تیم</summary>
[HttpDelete]
public async Task<ActionResult> Delete(
[FromQuery] int deviceId,
[FromQuery] int userId,
CancellationToken cancellationToken)
{
try
{
await _memberService.DeleteAsync(deviceId, userId, cancellationToken);
return Ok(new { message = "عضو با موفقیت حذف شد" });
}
catch (InvalidOperationException ex)
{
return NotFound(new { error = ex.Message });
}
}
/// <summary>بررسی مجوز مدیریت تیم</summary>
[HttpGet("can-manage")]
public async Task<ActionResult<bool>> CanManage(
[FromQuery] int actorUserId,
[FromQuery] int deviceId,
CancellationToken cancellationToken)
{
var canManage = await _memberService.CanManageDeviceAsync(actorUserId, deviceId, cancellationToken);
return Ok(new { canManage });
}
/// <summary>آپلود آواتار عضو</summary>
[HttpPost("avatar")]
[Consumes("multipart/form-data")]
public async Task<ActionResult<string>> UploadAvatar(
[FromForm] IFormFile file,
CancellationToken cancellationToken)
{
try
{
if (file == null || file.Length == 0)
return BadRequest(new { error = "فایل انتخاب نشده است" });
var allowedTypes = new[] { "image/jpeg", "image/jpg", "image/png", "image/webp" };
if (!allowedTypes.Contains(file.ContentType.ToLower()))
return BadRequest(new { error = "فقط فایل‌های تصویری مجاز هستند" });
if (file.Length > 2 * 1024 * 1024)
return BadRequest(new { error = "حجم آواتار نباید بیشتر از 2 مگابایت باشد" });
var uploadsFolder = Path.Combine(_environment.WebRootPath ?? "wwwroot", "uploads", "avatars");
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/avatars/{fileName}";
return Ok(new { avatarPath = relativePath, message = "آواتار با موفقیت آپلود شد" });
}
catch (Exception ex)
{
_logger.LogError(ex, "Error uploading avatar");
return StatusCode(500, new { error = "خطا در آپلود آواتار" });
}
}
}

View File

@@ -208,5 +208,85 @@ public class DevicePostsController : ControllerBase
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 = "خطا در آپلود ویس" });
}
}
}