public async Task <ActionResult <ApproveOrRejectLootListResponseDto> > PostApproveOrReject(long characterId, byte phase, [FromBody] ApproveOrRejectLootListDto dto, [FromServices] DiscordClientProvider dcp) { var character = await _context.Characters.FindAsync(characterId); if (character is null) { return(NotFound()); } var list = await _context.CharacterLootLists.FindAsync(characterId, phase); if (list is null) { return(NotFound()); } var team = await _context.RaidTeams.FindAsync(dto.TeamId); if (team is null) { ModelState.AddModelError(nameof(dto.TeamId), "Team does not exist."); return(ValidationProblem()); } var auth = await _authorizationService.AuthorizeAsync(User, team.Id, AppPolicies.RaidLeaderOrAdmin); if (!auth.Succeeded) { return(Unauthorized()); } if (!ValidateTimestamp(list, dto.Timestamp)) { return(Problem("Loot list has been changed. Refresh before trying to update the status again.")); } if (list.Status != LootListStatus.Submitted && character.TeamId.HasValue) { return(Problem("Can't approve or reject a list that isn't in the submitted state.")); } var submissions = await _context.LootListTeamSubmissions .AsTracking() .Where(s => s.LootListCharacterId == list.CharacterId && s.LootListPhase == list.Phase) .ToListAsync(); var teamSubmission = submissions.Find(s => s.TeamId == dto.TeamId); if (teamSubmission is null) { return(Unauthorized()); } MemberDto?member = null; if (dto.Approved) { _context.LootListTeamSubmissions.RemoveRange(submissions); if (character.TeamId.HasValue) { if (character.TeamId != dto.TeamId) { return(Problem("That character is not assigned to the specified raid team.")); } } else { var idString = character.Id.ToString(); var claim = await _context.UserClaims.AsNoTracking() .Where(c => c.ClaimType == AppClaimTypes.Character && c.ClaimValue == idString) .Select(c => new { c.UserId }) .FirstOrDefaultAsync(); if (claim is not null) { var otherClaims = await _context.UserClaims.AsNoTracking() .Where(c => c.ClaimType == AppClaimTypes.Character && c.UserId == claim.UserId) .Select(c => c.ClaimValue) .ToListAsync(); var characterIds = new List <long>(); foreach (var otherClaim in otherClaims) { if (long.TryParse(otherClaim, out var cid)) { characterIds.Add(cid); } } var existingCharacterName = await _context.Characters .AsNoTracking() .Where(c => characterIds.Contains(c.Id) && c.TeamId == team.Id) .Select(c => c.Name) .FirstOrDefaultAsync(); if (existingCharacterName?.Length > 0) { return(Problem($"The owner of this character is already on this team as {existingCharacterName}.")); } } character.TeamId = dto.TeamId; character.MemberStatus = RaidMemberStatus.FullTrial; character.JoinedTeamAt = _serverTimeZoneInfo.TimeZoneNow(); } list.ApprovedBy = User.GetDiscordId(); if (list.Status != LootListStatus.Locked) { list.Status = LootListStatus.Approved; } await _context.SaveChangesAsync(); var characterQuery = _context.Characters.AsNoTracking().Where(c => c.Id == character.Id); var scope = await _context.GetCurrentPriorityScopeAsync(); foreach (var m in await HelperQueries.GetMembersAsync(_context, _serverTimeZoneInfo, characterQuery, scope, team.Id, team.Name, true)) { member = m; break; } } else { _context.LootListTeamSubmissions.Remove(teamSubmission); if (character.TeamId == team.Id) { character.TeamId = null; } if (submissions.Count == 1) { if (list.Status != LootListStatus.Locked) { list.Status = LootListStatus.Editing; } list.ApprovedBy = null; } await _context.SaveChangesAsync(); } _telemetry.TrackEvent("LootListStatusChanged", User, props => { props["CharacterId"] = list.CharacterId.ToString(); props["Phase"] = list.Phase.ToString(); props["Status"] = list.Status.ToString(); props["Method"] = "ApproveOrReject"; }); var characterIdString = characterId.ToString(); var owner = await _context.UserClaims .AsNoTracking() .Where(c => c.ClaimType == AppClaimTypes.Character && c.ClaimValue == characterIdString) .Select(c => c.UserId) .FirstOrDefaultAsync(); if (owner > 0) { var sb = new StringBuilder("Your application to ") .Append(team.Name) .Append(" for ") .Append(character.Name) .Append(" was ") .Append(dto.Approved ? "approved!" : "rejected."); if (dto.Message?.Length > 0) { sb.AppendLine() .Append("<@") .Append(User.GetDiscordId()) .AppendLine("> said:") .Append("> ") .Append(dto.Message); } await dcp.SendDmAsync(owner, m => m.WithContent(sb.ToString())); } return(new ApproveOrRejectLootListResponseDto { Timestamp = list.Timestamp, Member = member, LootListStatus = list.Status }); }
public async Task <ActionResult <TimestampDto> > Reject(long characterId, byte phase, [FromBody] ApproveOrRejectLootListDto dto) { var list = await _context.CharacterLootLists.AsTracking() .Where(ll => ll.CharacterId == characterId && ll.Phase == phase) .Include(ll => ll.Character) .ThenInclude(c => c.Team) .SingleOrDefaultAsync(); if (list is null) { return(NotFound()); } if (list.Character.Team is null) { return(Problem("This action is only available for characters on a raid team.")); } if (!await AuthorizeTeamAsync(list.Character.Team, AppPolicies.RaidLeaderOrAdmin)) { return(Unauthorized()); } if (list.Character.Deactivated) { return(Problem("Character has been deactivated.")); } if (!ValidateTimestamp(list, dto.Timestamp)) { return(Problem("The loot list has been changed. Refresh before trying again.")); } switch (list.Status) { case LootListStatus.Editing: return(Problem("The loot list has not been submitted yet.")); case LootListStatus.Submitted: list.Status = LootListStatus.Editing; break; case LootListStatus.Approved: return(Problem("The loot list has already been approved.")); case LootListStatus.Locked: if (!list.ApprovedBy.HasValue) { return(Problem("The loot list is locked.")); } break; } list.ApprovedBy = null; var submissions = await _context.LootListTeamSubmissions .AsTracking() .Where(s => s.LootListCharacterId == characterId && s.LootListPhase == phase) .ToListAsync(); _context.LootListTeamSubmissions.RemoveRange(submissions); await _context.SaveChangesAsync(); TrackListStatusChange(list); await NotifyOwnerAsync(list.Character, list.Character.Team, approved : false, dto.Message); return(new TimestampDto { Timestamp = list.Timestamp }); }