[Verify+Complaints] Facility document review + facility complaints; card location line
CI/CD / CI · dotnet build (push) Successful in 1m27s
CI/CD / Deploy · hamkadr (push) Successful in 1m13s

Card: move location to its own line above the date in the shift card (job card already did). Verification workflow: employers upload documents (license/permit) on a new Employer/Verify page; uploading marks the facility Pending. Admins see pending facilities with their documents on Admin/Facilities, can download each doc, and approve (تأیید شد) or reject with a reason. Documents stored as bytea in the DB (survives deploys via the existing volume); served only to the owner or an admin via /facility-doc/{id}. Facility model gains Verification status enum + note + requested-at; IsVerified kept in sync. Complaints: registered users/visitors can file a شکایت about a facility from shift/job detail pages (targets ReportTargetType.Facility, surfaces in Admin/Reports as مرکز). Migration backfills existing verified facilities to Verified.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-04 16:26:15 +03:30
parent 962196d5cb
commit 1f34fd126f
16 changed files with 1632 additions and 24 deletions
+11
View File
@@ -208,6 +208,17 @@ app.MapGet("/notifications/stream", async (HttpContext ctx, NotificationHub hub)
finally { unsubscribe(); }
}).RequireAuthorization();
// Serve a facility verification document — only the facility owner or an admin may read it.
app.MapGet("/facility-doc/{id:int}", async (int id, HttpContext ctx, AppDbContext db) =>
{
var doc = await db.FacilityDocuments.Include(d => d.Facility).FirstOrDefaultAsync(d => d.Id == id);
if (doc is null) return Results.NotFound();
var isAdmin = ctx.User.IsInRole("Admin");
var uid = int.TryParse(ctx.User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value, out var n) ? n : (int?)null;
if (!isAdmin && doc.Facility.OwnerUserId != uid) return Results.Forbid();
return Results.File(doc.Data, doc.ContentType, doc.FileName);
}).RequireAuthorization();
// User-submitted report against a listing (abuse/fake/wrong info).
app.MapPost("/report", async (HttpContext ctx, AppDbContext db, VisitorContext vc,
[FromForm] string targetType, [FromForm] int targetId, [FromForm] string reason,