/// <inheritdoc /> public async Task RejectCampaignAsync(long campaignId) { AuthorizationService.RequireAuthenticatedUser(); AuthorizationService.RequireClaims(AuthorizationClaim.PromotionsCloseCampaign); if (!(await PromotionCampaignRepository.TryCloseAsync(campaignId, AuthorizationService.CurrentUserId.Value, PromotionCampaignOutcome.Rejected))) throw new InvalidOperationException($"Campaign {campaignId} doesn't exist or is already closed"); }
/// <inheritdoc /> public async Task AcceptCampaignAsync(long campaignId) { AuthorizationService.RequireAuthenticatedUser(); AuthorizationService.RequireClaims(AuthorizationClaim.PromotionsCloseCampaign); using (var transaction = await PromotionCampaignRepository.BeginCloseTransactionAsync()) { var campaign = await PromotionCampaignRepository.ReadDetailsAsync(campaignId); if (campaign is null) throw new InvalidOperationException($"Campaign {campaignId} does not exist"); if (!(campaign.CloseAction is null)) throw new InvalidOperationException($"Campaign {campaignId} is already closed"); var timeSince = DateTime.UtcNow - campaign.CreateAction.Created; if (timeSince < TimeSpan.FromHours(48)) throw new InvalidOperationException($"Campaign {campaignId} cannot be accepted until 48 hours after its creation ({48 - timeSince.TotalHours:#.##} hrs remain)"); try { var subject = await UserService.GetGuildUserAsync(campaign.GuildId, campaign.Subject.Id); if (subject.RoleIds.Contains(campaign.TargetRole.Id)) throw new InvalidOperationException($"User {campaign.Subject.DisplayName} is already a member of role {campaign.TargetRole.Name}"); var guild = await DiscordClient.GetGuildAsync(campaign.GuildId); var targetRole = guild.GetRole(campaign.TargetRole.Id); if (targetRole is null) throw new InvalidOperationException($"Role {campaign.TargetRole.Name} no longer exists"); await subject.AddRoleAsync(targetRole); foreach (var lowerRankRole in (await GetRankRolesAsync(AuthorizationService.CurrentGuildId.Value)) .TakeWhile(x => x.Id != targetRole.Id)) { var lowerRole = guild.GetRole(lowerRankRole.Id); if (!(lowerRole is null) && subject.RoleIds.Contains(lowerRole.Id)) await subject.RemoveRoleAsync(lowerRole); } await PromotionCampaignRepository.TryCloseAsync(campaignId, AuthorizationService.CurrentUserId.Value, PromotionCampaignOutcome.Accepted); } catch { await PromotionCampaignRepository.TryCloseAsync(campaignId, AuthorizationService.CurrentUserId.Value, PromotionCampaignOutcome.Failed); throw; } finally { transaction.Commit(); } } }
/// <inheritdoc /> public async Task AcceptCampaignAsync(long campaignId, bool force) { AuthorizationService.RequireAuthenticatedUser(); AuthorizationService.RequireClaims(AuthorizationClaim.PromotionsCloseCampaign); PromotionActionSummary resultAction; using (var transaction = await PromotionCampaignRepository.BeginCloseTransactionAsync()) { var campaign = await PromotionCampaignRepository.ReadDetailsAsync(campaignId); if (campaign is null) { throw new InvalidOperationException($"Campaign {campaignId} does not exist"); } if (!(campaign.CloseAction is null)) { throw new InvalidOperationException($"Campaign {campaignId} is already closed"); } var timeSince = DateTime.UtcNow - campaign.CreateAction.Created; if (timeSince < PromotionCampaignEntityExtensions.CampaignAcceptCooldown && !force) { throw new InvalidOperationException($"Campaign {campaignId} cannot be accepted until {PromotionCampaignEntityExtensions.CampaignAcceptCooldown.TotalHours} hours after its creation ({(PromotionCampaignEntityExtensions.CampaignAcceptCooldown - timeSince).Humanize(4)} remain)"); } try { var subject = await UserService.GetGuildUserAsync(campaign.GuildId, campaign.Subject.Id); if (subject.RoleIds.Contains(campaign.TargetRole.Id)) { throw new InvalidOperationException($"User {campaign.Subject.GetFullUsername()} is already a member of role {campaign.TargetRole.Name}"); } var guild = await DiscordClient.GetGuildAsync(campaign.GuildId); var targetRole = guild.GetRole(campaign.TargetRole.Id); if (targetRole is null) { throw new InvalidOperationException($"Role {campaign.TargetRole.Name} no longer exists"); } await subject.AddRoleAsync(targetRole); foreach (var lowerRankRole in (await GetRankRolesAsync(AuthorizationService.CurrentGuildId.Value)) .TakeWhile(x => x.Id != targetRole.Id)) { var lowerRole = guild.GetRole(lowerRankRole.Id); if (!(lowerRole is null) && subject.RoleIds.Contains(lowerRole.Id)) { await subject.RemoveRoleAsync(lowerRole); } } resultAction = await PromotionCampaignRepository.TryCloseAsync(campaignId, AuthorizationService.CurrentUserId.Value, PromotionCampaignOutcome.Accepted); } catch { resultAction = await PromotionCampaignRepository.TryCloseAsync(campaignId, AuthorizationService.CurrentUserId.Value, PromotionCampaignOutcome.Failed); PublishActionNotificationAsync(resultAction); throw; } finally { transaction.Commit(); } } PublishActionNotificationAsync(resultAction); }