using System.Text.Json; using System.Security.Claims; using IM.InitCommon.Management; using IM.Commons; using MessageService.Infrastructure; using MessageService.Domain.Enums; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace MessageService.WebApi.Controllers; [ApiController] public sealed class ManagementController(MessageDbContext db, InternalClient client) : ControllerBase { [HttpPost("api/message/report"), Authorize] public async Task Report(ClientReport input, CancellationToken ct) { var reporter = Guid.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!); JsonElement result; try { result = await client.Send("admin", "/internal/management/reports", new { ReporterId = reporter, input.Type, input.TargetId, input.Reason, input.Description, input.MessageIds }, ct); } catch (InternalServiceException e) { return StatusCode(e.Status, ManagementResult.Fail(e.Status switch { 429 => "举报次数已达上限或仍在重复举报冷却期", 403 => "没有访问举报对象或消息的权限", 400 => "举报内容无效,请检查分类和关联消息", _ => "举报服务暂不可用,请重试" })); } return Ok(ManagementResult.Ok(result)); } [HttpPost("internal/management/evidence")] public async Task Evidence(EvidenceRequest input, CancellationToken ct) { if (input.Type is not "user" and not "group" || input.MessageIds.Length > 20 || input.TargetId == input.ReporterId) return BadRequest(); string name; if (input.Type == "group") { var access = await client.Send("group", $"/internal/management/access/{input.TargetId}/{input.ReporterId}", ct: ct); if (!access.GetProperty("member").GetBoolean()) return Forbid(); var group = await client.Send("group", $"/internal/management/detail/{input.TargetId}", ct: ct); name = group.GetProperty("name").GetString()!; } else { var relation = await client.Send("contact", $"/internal/management/relation/{input.ReporterId}/{input.TargetId}", ct: ct); if (!relation.GetProperty("related").GetBoolean() && input.MessageIds.Length == 0) return Forbid(); var user = await client.Send("user", $"/internal/management/list?q={input.TargetId}&size=1", ct: ct); if (user.GetProperty("items").GetArrayLength() == 0) return NotFound(); name = user.GetProperty("items")[0].GetProperty("name").GetString()!; } var ids = input.MessageIds.Distinct().ToArray(); var messages = await db.Messages.AsNoTracking().Where(x => ids.Contains(x.Id)).ToListAsync(ct); if (messages.Count != ids.Length) return BadRequest(); var evidence = new List(); foreach (var m in messages) { var ownConversation = await db.Conversations.AnyAsync(x => x.UserId == input.ReporterId && x.StreamKey == m.StreamKey, ct); if (!ownConversation || (input.Type == "user" && m.SenderId != input.TargetId) || (input.Type == "group" && (m.ChatType != ChatType.GROUP || m.TargetId != input.TargetId))) return Forbid(); if (m.ChatType == ChatType.GROUP) { var access = await client.Send("group", $"/internal/management/access/{m.TargetId}/{input.ReporterId}", ct: ct); if (!access.GetProperty("member").GetBoolean()) return Forbid(); } using var body = JsonDocument.Parse(m.Content.RawBody ?? "{}"); Guid? fileId = null; if ((body.RootElement.TryGetProperty("FileId", out var file) || body.RootElement.TryGetProperty("fileId", out file)) && file.ValueKind == JsonValueKind.String && file.TryGetGuid(out var fid)) fileId = fid; evidence.Add(new(m.Id, m.SenderId, m.SenderId.ToString(), m.Content.Fallback, m.MsgType.ToString(), fileId, m.CreationTime)); } return Ok(new SubjectEvidence(name, evidence)); } } public record ClientReport(string Type, Guid TargetId, string Reason, string Description, Guid[] MessageIds);