示例#1
0
        public async Task <ActionResult <LootListDto> > PostLootList(long characterId, byte phase, [FromBody] LootListSubmissionDto dto, [FromServices] IdGen.IIdGenerator <long> idGenerator)
        {
            var authorizationResult = await _authorizationService.AuthorizeAsync(User, characterId, AppPolicies.CharacterOwnerOrAdmin);

            if (!authorizationResult.Succeeded)
            {
                return(Unauthorized());
            }

            var bracketTemplates = await _context.Brackets.AsNoTracking().Where(b => b.Phase == phase).OrderBy(b => b.Index).ToListAsync();

            if (bracketTemplates.Count == 0)
            {
                return(NotFound());
            }

            if (!ModelState.IsValid)
            {
                return(ValidationProblem());
            }

            var character = await _context.Characters.FindAsync(characterId);

            if (character is null)
            {
                return(NotFound());
            }

            if (character.Deactivated)
            {
                return(Problem("Character has been deactivated."));
            }

            if (await _context.CharacterLootLists.AsNoTracking().AnyAsync(ll => ll.CharacterId == character.Id && ll.Phase == phase))
            {
                return(Problem("A loot list for that character and phase already exists."));
            }

            if (!dto.MainSpec.IsClass(character.Class))
            {
                ModelState.AddModelError(nameof(dto.MainSpec), "Selected specialization does not fit the player's class.");
                return(ValidationProblem());
            }

            if (dto.OffSpec != default && !dto.OffSpec.IsClass(character.Class))
            {
                ModelState.AddModelError(nameof(dto.OffSpec), "Selected specialization does not fit the player's class.");
                return(ValidationProblem());
            }

            var list = new CharacterLootList
            {
                CharacterId = character.Id,
                Character   = character,
                Entries     = new List <LootListEntry>(28),
                Status      = LootListStatus.Editing,
                MainSpec    = dto.MainSpec,
                OffSpec     = dto.OffSpec,
                Phase       = phase
            };

            var entries = new List <LootListEntry>();

            var brackets = await _context.Brackets
                           .AsNoTracking()
                           .Where(b => b.Phase == phase)
                           .OrderBy(b => b.Index)
                           .ToListAsync();

            foreach (var bracket in brackets)
            {
                for (byte rank = bracket.MinRank; rank <= bracket.MaxRank; rank++)
                {
                    for (int col = 0; col < bracket.MaxItems; col++)
                    {
                        var entry = new LootListEntry(idGenerator.CreateId())
                        {
                            LootList = list,
                            Rank     = rank
                        };
                        _context.LootListEntries.Add(entry);
                        entries.Add(entry);
                    }
                }
            }

            _context.CharacterLootLists.Add(list);

            await _context.SaveChangesAsync();

            _telemetry.TrackEvent("LootListCreated", User, props =>
            {
                props["CharacterId"]   = character.Id.ToString();
                props["CharacterName"] = character.Name;
                props["Phase"]         = list.Phase.ToString();
            });

            var scope = await _context.GetCurrentPriorityScopeAsync();

            var observedDates = await _context.Raids
                                .AsNoTracking()
                                .Where(r => r.RaidTeamId == character.TeamId)
                                .OrderByDescending(r => r.StartedAt)
                                .Select(r => r.StartedAt.Date)
                                .Distinct()
                                .Take(scope.ObservedAttendances)
                                .ToListAsync();

            var attendance = await _context.RaidAttendees
                             .AsNoTracking()
                             .Where(x => !x.IgnoreAttendance && x.RemovalId == null && x.CharacterId == character.Id && x.Raid.RaidTeamId == character.TeamId)
                             .Select(x => x.Raid.StartedAt.Date)
                             .Where(date => observedDates.Contains(date))
                             .Distinct()
                             .CountAsync();

            var now            = _serverTimeZoneInfo.TimeZoneNow();
            var donationMatrix = await _context.GetDonationMatrixAsync(d => d.CharacterId == characterId, scope);

            var donations = donationMatrix.GetCreditForMonth(characterId, now);

            var returnDto = new LootListDto
            {
                ApprovedBy            = null,
                Bonuses               = PrioCalculator.GetListBonuses(scope, attendance, character.MemberStatus, donations).ToList(),
                CharacterId           = character.Id,
                CharacterMemberStatus = character.MemberStatus,
                CharacterName         = character.Name,
                MainSpec              = list.MainSpec,
                OffSpec               = list.OffSpec,
                Phase     = list.Phase,
                Status    = list.Status,
                TeamId    = character.TeamId,
                Timestamp = list.Timestamp
            };

            if (returnDto.TeamId.HasValue)
            {
                returnDto.TeamName = await _context.RaidTeams.AsNoTracking().Where(t => t.Id == returnDto.TeamId).Select(t => t.Name).FirstOrDefaultAsync();
            }

            foreach (var entry in entries)
            {
                var bracket = brackets.Find(b => entry.Rank >= b.MinRank && entry.Rank <= b.MaxRank);
                Debug.Assert(bracket is not null);
                returnDto.Entries.Add(new LootListEntryDto
                {
                    Bracket = bracket.Index,
                    BracketAllowsOffspec        = bracket.AllowOffspec,
                    BracketAllowsTypeDuplicates = bracket.AllowTypeDuplicates,
                    Id   = entry.Id,
                    Rank = entry.Rank
                });
            }

            return(CreatedAtAction(nameof(Get), new { characterId = character.Id, phase }, returnDto));
        }
        public async Task <ActionResult <TeamDto> > Put(long id, [FromBody] TeamSubmissionDto dto, [FromServices] IdGen.IIdGenerator <long> idGenerator)
        {
            if (!ModelState.IsValid)
            {
                return(ValidationProblem());
            }

            Debug.Assert(dto.Name?.Length > 1);

            if (dto.Schedules.Count == 0)
            {
                ModelState.AddModelError(nameof(dto.Schedules), "At least one raid day schedule must be entered.");
            }

            var team = await _context.RaidTeams.FindAsync(id);

            team.Name = dto.Name;

            var schedules = await _context.RaidTeamSchedules.AsTracking().Where(s => s.RaidTeam == team).OrderBy(s => s.Id).ToListAsync();

            for (int i = 0, count = Math.Max(schedules.Count, dto.Schedules.Count); i < count; i++)
            {
                switch ((i < schedules.Count, i < dto.Schedules.Count))
                {
示例#3
0
        public async Task <ActionResult <LootListDto> > ResetLootList(long characterId, byte phase, [FromServices] IdGen.IIdGenerator <long> idGenerator)
        {
            var authorizationResult = await _authorizationService.AuthorizeAsync(User, characterId, AppPolicies.CharacterOwnerOrAdmin);

            if (!authorizationResult.Succeeded)
            {
                return(Unauthorized());
            }

            var list = await _context.CharacterLootLists.FindAsync(characterId, phase);

            if (list is null)
            {
                return(NotFound());
            }

            if (list.Status != LootListStatus.Editing)
            {
                return(Problem("Loot list is not editable."));
            }

            var character = await _context.Characters.FindAsync(characterId);

            if (character is null)
            {
                return(NotFound());
            }

            if (character.Deactivated)
            {
                return(Problem("Character has been deactivated."));
            }

            var entriesToRemove = await _context.LootListEntries
                                  .AsTracking()
                                  .Where(e => e.LootList == list)
                                  .ToListAsync();

            var entries = new List <LootListEntry>();

            var brackets = await _context.Brackets
                           .AsNoTracking()
                           .Where(b => b.Phase == phase)
                           .OrderBy(b => b.Index)
                           .ToListAsync();

            foreach (var bracket in brackets)
            {
                for (byte rank = bracket.MinRank; rank <= bracket.MaxRank; rank++)
                {
                    int processed = 0;

                    foreach (var entry in entriesToRemove.Where(e => e.Rank == rank))
                    {
                        if (entry.DropId.HasValue)
                        {
                            entries.Add(entry);
                            processed++;
                        }
                        else if (processed < bracket.MaxItems)
                        {
                            entry.ItemId        = null;
                            entry.Justification = null;
                            entries.Add(entry);
                            processed++;
                        }
                    }

                    for (; processed < bracket.MaxItems; processed++)
                    {
                        var entry = new LootListEntry(idGenerator.CreateId())
                        {
                            LootList = list,
                            Rank     = rank
                        };
                        _context.LootListEntries.Add(entry);
                        entries.Add(entry);
                    }
                }
            }

            entriesToRemove.RemoveAll(entries.Contains);

            _context.LootListEntries.RemoveRange(entriesToRemove);

            await _context.SaveChangesAsync();

            _telemetry.TrackEvent("LootListReset", User, props =>
            {
                props["CharacterId"]   = character.Id.ToString();
                props["CharacterName"] = character.Name;
                props["Phase"]         = list.Phase.ToString();
            });

            var lootLists = await CreateDtosAsync(characterId, null, phase);

            Debug.Assert(lootLists?.Count == 1);
            return(lootLists[0]);
        }
        public async Task <ActionResult <TeamDto> > Post([FromBody] TeamSubmissionDto dto, [FromServices] IdGen.IIdGenerator <long> idGenerator)
        {
            if (!ModelState.IsValid)
            {
                return(ValidationProblem());
            }

            Debug.Assert(dto.Name?.Length > 1);

            if (dto.Schedules.Count == 0)
            {
                ModelState.AddModelError(nameof(dto.Schedules), "At least one raid day schedule must be entered.");
            }

            var team = new RaidTeam(idGenerator.CreateId())
            {
                Name = dto.Name
            };

            foreach (var scheduleDto in dto.Schedules)
            {
                Debug.Assert(scheduleDto.Day.HasValue);
                Debug.Assert(scheduleDto.StartTime.HasValue);
                Debug.Assert(scheduleDto.Duration.HasValue);

                team.Schedules.Add(new RaidTeamSchedule(idGenerator.CreateId())
                {
                    Day            = scheduleDto.Day.Value,
                    Duration       = TimeSpan.FromHours(scheduleDto.Duration.Value),
                    RealmTimeStart = scheduleDto.StartTime.Value,
                    RaidTeam       = team
                });
            }

            _context.RaidTeams.Add(team);

            await _context.SaveChangesAsync();

            _telemetry.TrackEvent("TeamAdded", User, props =>
            {
                props["TeamId"]   = team.Id.ToString();
                props["TeamName"] = team.Name;
            });

            return(CreatedAtAction(nameof(Get), new { id = team.Id }, new TeamDto
            {
                Id = team.Id,
                Name = team.Name,
                Schedules = team.Schedules.Select(s => new ScheduleDto
                {
                    Day = s.Day,
                    RealmTimeStart = s.RealmTimeStart,
                    Duration = s.Duration
                }).ToList()
            }));
        }