yavsc/src/Yavsc.Api/Controllers/Business/ActivityApiController.cs

310 lines
11 KiB
C#
Raw Normal View History

2023-03-19 17:57:55 +00:00
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
2026-08-30 23:55:09 +01:00
using Yavsc.Abstract.Workflow;
using Yavsc.Server.Helpers;
2019-01-01 16:28:47 +00:00
using Yavsc.Models;
using Yavsc.Models.Workflow;
namespace Yavsc.Controllers
{
2026-08-30 23:55:09 +01:00
[Authorize]
2019-01-01 16:28:47 +00:00
[Produces("application/json")]
2026-08-20 20:50:52 +01:00
[Route(Constants.APIPrefix + "/activity")]
2019-01-01 16:28:47 +00:00
public class ActivityApiController : Controller
{
private ApplicationDbContext _context;
public ActivityApiController(ApplicationDbContext context)
{
_context = context;
}
// GET: api/ActivityApi
[HttpGet]
public IEnumerable<Activity> GetActivities()
{
return _context.Activities.Include(a=>a.Forms).Where( a => !a.Hidden );
}
2026-08-30 23:55:09 +01:00
[HttpGet("catalog")]
public async Task<ActionResult<IEnumerable<ActivityBrowseItemDto>>> GetCatalog(
CancellationToken cancellationToken,
[FromQuery] string parentCode = null)
{
var activities = await _context.Activities
.AsNoTracking()
.Include(a => a.Forms)
.Include(a => a.Children)
.ThenInclude(c => c.Forms)
.Where(a => !a.Hidden && a.ParentCode == parentCode)
.OrderByDescending(a => a.Rate)
.ToListAsync(cancellationToken);
var codes = activities
.Select(a => a.Code)
2026-08-31 00:25:53 +01:00
.Concat(activities.SelectMany(a => (a.Children ?? new List<Activity>())
.Where(c => !c.Hidden)
.Select(c => c.Code)))
.Where(c => !string.IsNullOrWhiteSpace(c))
2026-08-30 23:55:09 +01:00
.Distinct()
.ToArray();
2026-08-31 00:25:53 +01:00
var performerCounts = await (
from ua in _context.UserActivities.AsNoTracking()
2026-08-31 02:14:04 +01:00
where !string.IsNullOrWhiteSpace(ua.DoesCode) && codes.Contains(ua.DoesCode)
2026-08-31 00:25:53 +01:00
group ua by ua.DoesCode into g
select new
{
Code = g.Key,
Count = g.Select(x => x.UserId).Distinct().Count()
})
2026-08-30 23:55:09 +01:00
.ToDictionaryAsync(x => x.Code, x => x.Count, cancellationToken);
2026-08-31 02:14:04 +01:00
var filteredActivities = activities
.Where(a =>
(performerCounts.TryGetValue(a.Code, out var ownCount) && ownCount > 0)
|| (a.Children ?? new List<Activity>())
.Where(c => !c.Hidden)
.Any(c => performerCounts.TryGetValue(c.Code, out var childCount) && childCount > 0))
.ToList();
return Ok(filteredActivities.Select(a => ToBrowseItem(a, performerCounts)).ToList());
2026-08-30 23:55:09 +01:00
}
2026-08-31 02:14:04 +01:00
[HttpGet("{id}/users")]
public async Task<ActionResult<IEnumerable<ActivityPerformerDto>>> GetUsers(
2026-08-30 23:55:09 +01:00
[FromRoute] string id,
CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(id))
{
return BadRequest("Activity code is required.");
}
var activity = await _context.Activities
.AsNoTracking()
.SingleOrDefaultAsync(a => a.Code == id, cancellationToken);
if (activity is null)
{
return NotFound();
}
2026-08-31 02:14:04 +01:00
var users = await QueryDeclaredUsersAsync(id, activity.Name, cancellationToken);
return Ok(users);
}
[HttpGet("{id}/performers")]
public Task<ActionResult<IEnumerable<ActivityPerformerDto>>> GetPerformers(
[FromRoute] string id,
CancellationToken cancellationToken)
{
// Backward-compatible alias kept for existing clients.
return GetUsers(id, cancellationToken);
}
private Task<List<ActivityPerformerDto>> QueryDeclaredUsersAsync(
string activityCode,
string activityName,
CancellationToken cancellationToken)
{
return (
from ua in _context.UserActivities.AsNoTracking()
join u in _context.ApplicationUser.AsNoTracking() on ua.UserId equals u.Id into users
2026-08-31 00:25:53 +01:00
from user in users.DefaultIfEmpty()
2026-08-31 02:14:04 +01:00
join p in _context.Performers.AsNoTracking() on ua.UserId equals p.PerformerId into performerProfiles
from performer in performerProfiles.DefaultIfEmpty()
where ua.DoesCode == activityCode
orderby user != null ? user.UserName : ua.UserId
2026-08-31 00:25:53 +01:00
select new ActivityPerformerDto
2026-08-30 23:55:09 +01:00
{
2026-08-31 02:14:04 +01:00
PerformerId = ua.UserId,
HasPerformerProfile = performer != null,
2026-08-31 00:25:53 +01:00
UserName = user != null ? (user.UserName ?? string.Empty) : string.Empty,
2026-08-31 02:14:04 +01:00
Active = performer != null && performer.Active,
AcceptNotifications = performer != null && performer.AcceptNotifications,
AcceptPublicContact = performer != null && performer.AcceptPublicContact,
WebSite = performer != null ? (performer.WebSite ?? string.Empty) : string.Empty,
ActivityCode = activityCode,
ActivityName = activityName,
2026-08-31 00:25:53 +01:00
SettingsClassName = _context.Activities
2026-08-31 02:14:04 +01:00
.Where(a => a.Code == activityCode)
2026-08-31 00:25:53 +01:00
.Select(a => a.SettingsClassName)
.FirstOrDefault() ?? string.Empty,
ExtraActivityCount = _context.UserActivities
2026-08-31 02:14:04 +01:00
.Where(x => x.UserId == ua.UserId && x.DoesCode != activityCode)
2026-08-31 00:25:53 +01:00
.Count()
2026-08-30 23:55:09 +01:00
})
2026-08-31 00:25:53 +01:00
.Distinct()
2026-08-30 23:55:09 +01:00
.ToListAsync(cancellationToken);
}
2019-01-01 16:28:47 +00:00
// GET: api/ActivityApi/5
[HttpGet("{id}", Name = "GetActivity")]
public async Task<IActionResult> GetActivity([FromRoute] string id)
{
if (!ModelState.IsValid)
{
2023-03-19 17:57:55 +00:00
return BadRequest(ModelState);
2019-01-01 16:28:47 +00:00
}
Activity activity = await _context.Activities.SingleAsync(m => m.Code == id);
if (activity == null)
{
2023-03-19 17:57:55 +00:00
return NotFound();
2019-01-01 16:28:47 +00:00
}
// Also return hidden ones
// hidden doesn't mean disabled
return Ok(activity);
}
// PUT: api/ActivityApi/5
[HttpPut("{id}"),Authorize("AdministratorOnly")]
public async Task<IActionResult> PutActivity([FromRoute] string id, [FromBody] Activity activity)
{
if (!ModelState.IsValid)
{
2023-03-19 17:57:55 +00:00
return BadRequest(ModelState);
2019-01-01 16:28:47 +00:00
}
if (id != activity.Code)
{
2023-03-19 17:57:55 +00:00
return BadRequest();
2019-01-01 16:28:47 +00:00
}
_context.Entry(activity).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync(User.GetUserId());
}
catch (DbUpdateConcurrencyException)
{
if (!ActivityExists(id))
{
2023-03-19 17:57:55 +00:00
return NotFound();
2019-01-01 16:28:47 +00:00
}
else
{
throw;
}
}
2023-03-19 17:57:55 +00:00
return new StatusCodeResult(StatusCodes.Status204NoContent);
2019-01-01 16:28:47 +00:00
}
// POST: api/ActivityApi
2026-08-10 18:12:59 +01:00
[HttpPost, Authorize("AdministratorOnly")]
2019-01-01 16:28:47 +00:00
public async Task<IActionResult> PostActivity([FromBody] Activity activity)
{
if (!ModelState.IsValid)
{
2023-03-19 17:57:55 +00:00
return BadRequest(ModelState);
2019-01-01 16:28:47 +00:00
}
_context.Activities.Add(activity);
try
{
await _context.SaveChangesAsync(User.GetUserId());
}
catch (DbUpdateException)
{
if (ActivityExists(activity.Code))
{
2023-03-19 17:57:55 +00:00
return new StatusCodeResult(StatusCodes.Status409Conflict);
2019-01-01 16:28:47 +00:00
}
else
{
throw;
}
}
return CreatedAtRoute("GetActivity", new { id = activity.Code }, activity);
}
// DELETE: api/ActivityApi/5
[HttpDelete("{id}"),Authorize("AdministratorOnly")]
public async Task<IActionResult> DeleteActivity([FromRoute] string id)
{
if (!ModelState.IsValid)
{
2023-03-19 17:57:55 +00:00
return BadRequest(ModelState);
2019-01-01 16:28:47 +00:00
}
Activity activity = await _context.Activities.SingleAsync(m => m.Code == id);
if (activity == null)
{
2023-03-19 17:57:55 +00:00
return NotFound();
2019-01-01 16:28:47 +00:00
}
_context.Activities.Remove(activity);
await _context.SaveChangesAsync(User.GetUserId());
return Ok(activity);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_context.Dispose();
}
base.Dispose(disposing);
}
private bool ActivityExists(string id)
{
return _context.Activities.Count(e => e.Code == id) > 0;
}
2026-08-30 23:55:09 +01:00
private static ActivityBrowseItemDto ToBrowseItem(
Activity activity,
IReadOnlyDictionary<string, int> performerCounts)
{
return new ActivityBrowseItemDto
{
Code = activity.Code,
Name = activity.Name,
ParentCode = activity.ParentCode,
Description = activity.Description,
Photo = activity.Photo,
Rate = activity.Rate,
PerformerCount = performerCounts.TryGetValue(activity.Code, out var count) ? count : 0,
2026-08-31 00:25:53 +01:00
Forms = (activity.Forms ?? Enumerable.Empty<CommandForm>())
2026-08-30 23:55:09 +01:00
.Select(f => new CommandFormSummaryDto
{
Id = f.Id,
ActionName = f.ActionName,
Title = f.Title,
})
.ToList(),
2026-08-31 00:25:53 +01:00
Children = (activity.Children ?? Enumerable.Empty<Activity>())
2026-08-30 23:55:09 +01:00
.Where(c => !c.Hidden)
2026-08-31 02:14:04 +01:00
.Where(c => performerCounts.TryGetValue(c.Code, out var childCount) && childCount > 0)
2026-08-30 23:55:09 +01:00
.OrderByDescending(c => c.Rate)
.Select(c => new ActivityBrowseItemDto
{
Code = c.Code,
Name = c.Name,
ParentCode = c.ParentCode,
Description = c.Description,
Photo = c.Photo,
Rate = c.Rate,
PerformerCount = performerCounts.TryGetValue(c.Code, out var childCount) ? childCount : 0,
2026-08-31 00:25:53 +01:00
Forms = (c.Forms ?? Enumerable.Empty<CommandForm>())
2026-08-30 23:55:09 +01:00
.Select(f => new CommandFormSummaryDto
{
Id = f.Id,
ActionName = f.ActionName,
Title = f.Title,
})
.ToList(),
})
.ToList(),
};
}
2019-01-01 16:28:47 +00:00
}
}