using GanjooRazor.Utils; using GSpotifyProxy.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Newtonsoft.Json; using RSecurityBackend.Models.Auth.Db; using RSecurityBackend.Models.Auth.ViewModels; using RSecurityBackend.Models.Generic; using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Text; using System.Threading.Tasks; namespace GanjooRazor.Areas.Admin.Pages { public class UsersModel : PageModel { /// /// Last Error /// public string LastError { get; set; } public PublicRAppUser[] Users { get; set; } public PaginationMetadata Paging { get; set; } public List PaginationLinks { get; set; } = new List(); public int PageNumber { get; set; } = 1; public int PageSize { get; set; } = 15; public string FilterByEmail { get; set; } public string FilterByNickName { get; set; } public async Task OnGetAsync(int pageNumber = 1, int pageSize = 15, string filterByEmail = null, string filterByNickName = null) { if (string.IsNullOrEmpty(Request.Cookies["Token"])) return Redirect("/"); PageNumber = pageNumber < 1 ? 1 : pageNumber; PageSize = pageSize; FilterByEmail = filterByEmail; FilterByNickName = filterByNickName; using (HttpClient secureClient = new HttpClient(new GanjoorReloginHandler(Request, Response))) { if (await GanjoorSessionChecker.PrepareClient(secureClient, Request, Response)) { var url = $"{APIRoot.Url}/api/users?PageNumber={PageNumber}&PageSize={PageSize}"; if (!string.IsNullOrEmpty(FilterByEmail)) url += $"&filterByEmail={Uri.EscapeDataString(FilterByEmail)}"; if (!string.IsNullOrEmpty(FilterByNickName)) url += $"&filterByNickName={Uri.EscapeDataString(FilterByNickName)}"; var response = await secureClient.GetAsync(url); if (response.IsSuccessStatusCode) { Users = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); if (response.Headers.TryGetValues("paging-headers", out var values)) { Paging = JsonConvert.DeserializeObject(values.FirstOrDefault()); if (Paging != null) { PaginationLinks = BuildPaginationLinks(PageNumber, Paging.totalPages, PageSize, FilterByEmail, FilterByNickName); } } } else { LastError = await response.Content.ReadAsStringAsync(); } } else { LastError = "لطفاً از گنجور خارج و مجددا به آن وارد شوید."; } } return Page(); } /// /// Builds a compact pager: first/prev, a window of page numbers around the /// current page (with first/last always included and "…" for gaps), next/last. /// Avoids listing every single page number when there are many pages. /// private static List BuildPaginationLinks(int currentPage, int totalPages, int pageSize, string filterByEmail, string filterByNickName) { var links = new List(); if (totalPages < 1) return links; string UrlFor(int p) { var u = $"?pageNumber={p}&pageSize={pageSize}"; if (!string.IsNullOrEmpty(filterByEmail)) u += $"&filterByEmail={Uri.EscapeDataString(filterByEmail)}"; if (!string.IsNullOrEmpty(filterByNickName)) u += $"&filterByNickName={Uri.EscapeDataString(filterByNickName)}"; return u; } // first / previous links.Add(new NameIdUrlImage() { Name = "▶▶ اول", Url = currentPage <= 1 ? "" : UrlFor(1) }); links.Add(new NameIdUrlImage() { Name = "▶ قبلی", Url = currentPage <= 1 ? "" : UrlFor(currentPage - 1) }); // window of page numbers around current, always including page 1 and totalPages const int windowRadius = 2; var pagesToShow = new SortedSet(); for (int p = Math.Max(1, currentPage - windowRadius); p <= Math.Min(totalPages, currentPage + windowRadius); p++) pagesToShow.Add(p); pagesToShow.Add(1); pagesToShow.Add(totalPages); int? previousShown = null; foreach (var p in pagesToShow) { if (previousShown.HasValue && p > previousShown.Value + 1) { links.Add(new NameIdUrlImage() { Name = "…", Url = "" }); } links.Add(new NameIdUrlImage() { Name = p.ToString(), Url = p == currentPage ? "" : UrlFor(p) }); previousShown = p; } // next / last links.Add(new NameIdUrlImage() { Name = "بعدی ◀", Url = currentPage >= totalPages ? "" : UrlFor(currentPage + 1) }); links.Add(new NameIdUrlImage() { Name = "آخر ◀◀", Url = currentPage >= totalPages ? "" : UrlFor(totalPages) }); return links; } /// /// role names for a specific user - ?handler=Roles&id=... /// public async Task OnGetRolesAsync(Guid id) { using (HttpClient secureClient = new HttpClient(new GanjoorReloginHandler(Request, Response))) { if (!await GanjoorSessionChecker.PrepareClient(secureClient, Request, Response)) return BadRequest("لطفاً از گنجور خارج و مجددا به آن وارد شوید."); var response = await secureClient.GetAsync($"{APIRoot.Url}/api/users/{id}/roles"); if (!response.IsSuccessStatusCode) return BadRequest(await response.Content.ReadAsStringAsync()); var roles = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); return new JsonResult(roles); } } /// /// all defined role names, for populating the "add role" picker - ?handler=AllRoles /// public async Task OnGetAllRolesAsync() { using (HttpClient secureClient = new HttpClient(new GanjoorReloginHandler(Request, Response))) { if (!await GanjoorSessionChecker.PrepareClient(secureClient, Request, Response)) return BadRequest("لطفاً از گنجور خارج و مجددا به آن وارد شوید."); var response = await secureClient.GetAsync($"{APIRoot.Url}/api/roles"); if (!response.IsSuccessStatusCode) return BadRequest(await response.Content.ReadAsStringAsync()); var roles = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); return new JsonResult(roles.Select(r => r.Name).ToArray()); } } /// /// add a role to a user - ?handler=AddRole /// public async Task OnPostAddRoleAsync(Guid id, string role) { using (HttpClient secureClient = new HttpClient(new GanjoorReloginHandler(Request, Response))) { if (!await GanjoorSessionChecker.PrepareClient(secureClient, Request, Response)) return BadRequest("لطفاً از گنجور خارج و مجددا به آن وارد شوید."); var response = await secureClient.PostAsync($"{APIRoot.Url}/api/users/{id}/roles/{Uri.EscapeDataString(role)}", null); if (!response.IsSuccessStatusCode) return BadRequest(await response.Content.ReadAsStringAsync()); return new JsonResult(true); } } /// /// remove a role from a user - ?handler=Role (DELETE) /// public async Task OnDeleteRoleAsync(Guid id, string role) { using (HttpClient secureClient = new HttpClient(new GanjoorReloginHandler(Request, Response))) { if (!await GanjoorSessionChecker.PrepareClient(secureClient, Request, Response)) return BadRequest("لطفاً از گنجور خارج و مجددا به آن وارد شوید."); var response = await secureClient.DeleteAsync($"{APIRoot.Url}/api/users/{id}/roles/{Uri.EscapeDataString(role)}"); if (!response.IsSuccessStatusCode) return BadRequest(await response.Content.ReadAsStringAsync()); return new JsonResult(true); } } /// /// toggle a user's active/inactive status - ?handler=ToggleStatus /// public async Task OnPostToggleStatusAsync(Guid id, bool active) { using (HttpClient secureClient = new HttpClient(new GanjoorReloginHandler(Request, Response))) { if (!await GanjoorSessionChecker.PrepareClient(secureClient, Request, Response)) return BadRequest("لطفاً از گنجور خارج و مجددا به آن وارد شوید."); var userInfoResponse = await secureClient.GetAsync($"{APIRoot.Url}/api/users/{id}"); if (!userInfoResponse.IsSuccessStatusCode) return BadRequest(await userInfoResponse.Content.ReadAsStringAsync()); var userInfo = JsonConvert.DeserializeObject(await userInfoResponse.Content.ReadAsStringAsync()); // ModifyUser rejects the request unless IsAdmin exactly matches the user's actual // current admin-role membership (this endpoint cannot itself change admin status), // so we need their real membership, not a guess. var rolesResponse = await secureClient.GetAsync($"{APIRoot.Url}/api/users/{id}/roles"); if (!rolesResponse.IsSuccessStatusCode) return BadRequest(await rolesResponse.Content.ReadAsStringAsync()); var currentRoles = JsonConvert.DeserializeObject(await rolesResponse.Content.ReadAsStringAsync()); bool isCurrentlyAdmin = currentRoles.Contains("Administrator"); var updateModel = new RegisterRAppUser() { Password = "", IsAdmin = isCurrentlyAdmin, Id = userInfo.Id, Username = userInfo.Username, Email = userInfo.Email, PhoneNumber = userInfo.PhoneNumber, FirstName = userInfo.FirstName, SurName = userInfo.SurName, Status = active ? RAppUserStatus.Active : RAppUserStatus.Inactive, RImageId = userInfo.RImageId, NickName = userInfo.NickName, Bio = userInfo.Bio, Website = userInfo.Website }; var response = await secureClient.PutAsync($"{APIRoot.Url}/api/users/{id}", new StringContent(JsonConvert.SerializeObject(updateModel), Encoding.UTF8, "application/json")); if (!response.IsSuccessStatusCode) return BadRequest(await response.Content.ReadAsStringAsync()); return new JsonResult(true); } } } }