/// <summary> /// Import all in game ranks /// </summary> /// <param name="guildId">Id of the guild</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public async Task ImportGuildRanks(long?guildId) { using (var dbFactory = RepositoryFactory.CreateInstance()) { foreach (var guild in dbFactory.GetRepository <GuildRepository>() .GetQuery() .Where(obj => guildId == null || obj.Id == guildId) .Select(obj => new { obj.Id, obj.GuildId, obj.ApiKey }) .ToList()) { var connector = new GuidWars2ApiConnector(guild.ApiKey); await using (connector.ConfigureAwait(false)) { var members = await connector.GetGuildMembers(guild.GuildId) .ConfigureAwait(false); await dbFactory.GetRepository <GuildWarsGuildMemberRepository>() .BulkInsert(guild.Id, members.Select(obj => (obj.Name, obj.Rank))) .ConfigureAwait(false); } } } }
/// <summary> /// Return the message of element /// </summary> /// <returns>Message</returns> public override DiscordEmbedBuilder GetMessage() { var builder = new DiscordEmbedBuilder(); builder.WithTitle(LocalizationGroup.GetText("ChooseTitle", "In game rank selection")); builder.WithDescription(LocalizationGroup.GetText("ChooseDescription", "Please choose one of the following ranks:")); _ranks = new Dictionary <int, string>(); var stringBuilder = new StringBuilder(); var ranksCounter = 1; var fieldsCounter = 1; using (var dbFactory = RepositoryFactory.CreateInstance()) { var guild = dbFactory.GetRepository <GuildRepository>() .GetQuery() .Where(obj => obj.DiscordServerId == CommandContext.Guild.Id) .Select(obj => new { obj.GuildId, obj.ApiKey }) .First(); var connector = new GuidWars2ApiConnector(guild.ApiKey); foreach (var rank in connector.GetGuildRanks(guild.GuildId) .Result .OrderBy(obj => obj.Order)) { var currentLine = $"`{ranksCounter}` - {rank.Id}\n"; if (currentLine.Length + stringBuilder.Length > 1024) { builder.AddField(LocalizationGroup.GetText("RanksField", "Ranks") + " #" + fieldsCounter, stringBuilder.ToString()); stringBuilder.Clear(); fieldsCounter++; } stringBuilder.Append(currentLine); _ranks[ranksCounter] = rank.Id; ranksCounter++; } } if (stringBuilder.Length == 0) { stringBuilder.Append("\u200D"); } builder.AddField(LocalizationGroup.GetText("RanksField", "Ranks") + " #" + fieldsCounter, stringBuilder.ToString()); return(builder); }
/// <summary> /// Executes the job /// </summary> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public override async Task ExecuteAsync() { var date = DateTime.Today.AddDays(-1); using (var dbFactory = RepositoryFactory.CreateInstance()) { foreach (var account in dbFactory.GetRepository <AccountRepository>() .GetQuery() .Select(obj => new { obj.Name, obj.ApiKey, obj.LastAge, WordId = obj.WorldId }) .ToList()) { try { var connector = new GuidWars2ApiConnector(account.ApiKey); await using (connector.ConfigureAwait(false)) { var accountInformation = await connector.GetAccountInformationAsync() .ConfigureAwait(false); if (accountInformation.Age != account.LastAge) { dbFactory.GetRepository <AccountDailyLoginCheckRepository>() .Add(new GuildWarsAccountDailyLoginCheckEntity { Name = account.Name, Date = date }); dbFactory.GetRepository <AccountRepository>() .Refresh(obj => obj.Name == account.Name, obj => { obj.LastAge = accountInformation.Age; obj.WorldId = accountInformation.World; obj.DailyAchievementPoints = accountInformation.DailyAchievementPoints; obj.MonthlyAchievementPoints = accountInformation.MonthlyAchievementPoints; }); } } } catch (Exception ex) { LoggingService.AddJobLogEntry(LogEntryLevel.CriticalError, nameof(AccountLoginCheckJob), account.Name, ex.Message, ex.ToString()); } } } }
/// <summary> /// Import all achievement of an user /// </summary> /// <param name="accountName">Account name</param> /// <param name="apiKey">API-Key</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public async Task <bool> ImportAccountAchievements(string accountName, string apiKey) { var connector = new GuidWars2ApiConnector(apiKey); await using (connector.ConfigureAwait(false)) { var achievements = await connector.GetAccountAchievements() .ConfigureAwait(false); using (var dbFactory = RepositoryFactory.CreateInstance()) { return(await dbFactory.GetRepository <GuildWarsAccountAchievementRepository>() .BulkInsert(accountName, achievements) .ConfigureAwait(false)); } } }
/// <summary> /// Importing all achievements /// </summary> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public async Task <bool> ImportAchievements() { var connector = new GuidWars2ApiConnector(null); await using (connector.ConfigureAwait(false)) { var achievementIds = await connector.GetAllAchievementIds() .ConfigureAwait(false); var achievements = await connector.GetAchievements(achievementIds) .ConfigureAwait(false); using (var dbFactory = RepositoryFactory.CreateInstance()) { return(await dbFactory.GetRepository <GuildWarsAchievementRepository>() .BulkInsert(achievements) .ConfigureAwait(false)); } } }
/// <summary> /// Return the message of element /// </summary> /// <returns>Message</returns> public override DiscordEmbedBuilder GetMessage() { var builder = new DiscordEmbedBuilder(); builder.WithTitle(LocalizationGroup.GetText("ChooseGuildTitle", "Guild selection")); builder.WithDescription(LocalizationGroup.GetText("ChooseGuildDescription", "Please choose one of the following guilds:")); _guilds = new Dictionary <int, string>(); using (var connector = new GuidWars2ApiConnector(DialogContext.GetValue <string>("ApiKey"))) { var fieldText = new StringBuilder(); var i = 1; // TODO GetMessage -> GetMessageAsync var accountInformation = connector.GetAccountInformationAsync().Result; foreach (var guildId in accountInformation.GuildLeader) { var guildInformation = connector.GetGuildInformation(guildId).Result; fieldText.Append('`'); fieldText.Append(i); fieldText.Append("` - "); fieldText.Append(' '); fieldText.Append(guildInformation.Name); fieldText.Append('['); fieldText.Append(guildInformation.Tag); fieldText.Append(']'); fieldText.Append('\n'); _guilds[i] = guildId; i++; } builder.AddField(LocalizationGroup.GetText("GuildsField", "Guilds"), fieldText.ToString()); } return(builder); }
/// <summary> /// Import worlds /// </summary> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public async Task <bool> ImportWorlds() { var success = false; using (var dbFactory = RepositoryFactory.CreateInstance()) { try { var connector = new GuidWars2ApiConnector(null); await using (connector.ConfigureAwait(false)) { var worlds = await connector.GetWorlds().ConfigureAwait(false); success = true; foreach (var world in worlds) { if (dbFactory.GetRepository <GuildWarsWorldRepository>() .AddOrRefresh(obj => obj.Id == world.Id, obj => { obj.Id = world.Id; obj.Name = world.Name; }) == false) { success = false; break; } } } } catch (Exception ex) { LoggingService.AddServiceLogEntry(LogEntryLevel.Error, nameof(WorldsService), ex.Message, null, ex); } } return(success); }
/// <summary> /// Posting a random Quaggan /// </summary> /// <param name="commandContext">Command context</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public async Task PostRandomQuaggan(CommandContextContainer commandContext) { var connector = new GuidWars2ApiConnector(null); await using (connector.ConfigureAwait(false)) { var quaggans = await connector.GetQuaggans() .ConfigureAwait(false); var quagganName = quaggans[new Random(DateTime.Now.Millisecond).Next(0, quaggans.Count - 1)]; var quagganData = await connector.GetQuaggan(quagganName) .ConfigureAwait(false); await commandContext.Message .DeleteAsync() .ConfigureAwait(false); await commandContext.Channel .SendMessageAsync(quagganData.Url) .ConfigureAwait(false); } }
/// <summary> /// Importing all items /// </summary> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public async Task <bool> ImportItems() { using (var dbFactory = RepositoryFactory.CreateInstance()) { var connector = new GuidWars2ApiConnector(null); await using (connector.ConfigureAwait(false)) { var itemIds = await connector.GetAllItemIds() .ConfigureAwait(false); var items = await connector.GetItems(itemIds.Cast <int?>().ToList()) .ConfigureAwait(false); return(await dbFactory.GetRepository <GuildWarsItemRepository>() .BulkInsert(items) .ConfigureAwait(false) && await dbFactory.GetRepository <GuildWarsItemGuildUpgradeConversionRepository>() .BulkInsert(items.Where(obj => obj.Details?.GuildUpgradeId > 0) .Select(obj => new KeyValuePair <int, long>(obj.Id, obj.Details.GuildUpgradeId)) .ToList()) .ConfigureAwait(false)); } } }
/// <summary> /// Validation the guild bank /// </summary> /// <param name="commandContext">Command context</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public async Task CheckUnlocksDyes(CommandContextContainer commandContext) { using (var dbFactory = RepositoryFactory.CreateInstance()) { var guild = dbFactory.GetRepository <GuildRepository>() .GetQuery() .Where(obj => obj.DiscordServerId == commandContext.Guild.Id) .Select(obj => new { obj.ApiKey, obj.GuildId }) .FirstOrDefault(); if (string.IsNullOrWhiteSpace(guild?.ApiKey) == false) { var user = await commandContext.GetCurrentUser() .ConfigureAwait(false); var apiKeys = dbFactory.GetRepository <AccountRepository>() .GetQuery() .Where(obj => obj.UserId == user.Id) .Select(obj => new { obj.ApiKey, obj.Name }) .ToList(); if (apiKeys.Count > 0) { var guildConnector = new GuidWars2ApiConnector(guild.ApiKey); await using (guildConnector.ConfigureAwait(false)) { var vault = await guildConnector.GetGuildVault(guild.GuildId) .ConfigureAwait(false); var itemIds = vault.SelectMany(obj => obj.Slots) .Where(obj => obj != null) .Select(obj => (int?)obj.ItemId) .Distinct() .ToList(); var items = await guildConnector.GetItems(itemIds) .ConfigureAwait(false); foreach (var apiKey in apiKeys) { var accountConnector = new GuidWars2ApiConnector(apiKey.ApiKey); await using (accountConnector.ConfigureAwait(false)) { var dyes = await accountConnector.GetDyes() .ConfigureAwait(false); var builder = new DiscordEmbedBuilder().WithTitle(LocalizationGroup.GetFormattedText("DyeUnlocksTitle", "Dye unlocks {0}", apiKey.Name)) .WithColor(DiscordColor.Green) .WithFooter("Scruffy", "https://cdn.discordapp.com/app-icons/838381119585648650/823930922cbe1e5a9fa8552ed4b2a392.png?size=64") .WithTimestamp(DateTime.Now); var fieldBuilder = new StringBuilder(); var fieldCounter = 1; foreach (var item in items.Where(obj => obj.Type == "Consumable" && obj.Details?.Type == "Unlock" && obj.Details?.UnlockType == "Dye") .OrderBy(obj => obj.Name)) { var currentLine = dyes.Contains(item.Details.ColorId ?? 0) ? $"{DiscordEmojiService.GetCheckEmoji(commandContext.Client)} {item.Name}" : $"{DiscordEmojiService.GetCrossEmoji(commandContext.Client)} {item.Name}"; if (fieldBuilder.Length + currentLine.Length > 1024) { builder.AddField(LocalizationGroup.GetFormattedText("DyesFields", "Dyes #{0}", fieldCounter), fieldBuilder.ToString(), true); fieldBuilder = new StringBuilder(); fieldCounter++; } fieldBuilder.AppendLine(currentLine); } builder.AddField(LocalizationGroup.GetFormattedText("DyesFields", "Dyes #{0}", fieldCounter), fieldBuilder.ToString(), true); await commandContext.Message .RespondAsync(builder) .ConfigureAwait(false); } } } } else { await commandContext.Channel .SendMessageAsync(LocalizationGroup.GetText("NoAccountApiKey", "You don't have any api keys configured.")) .ConfigureAwait(false); } } else { await commandContext.Channel .SendMessageAsync(LocalizationGroup.GetText("NoApiKey", "The guild ist not configured.")) .ConfigureAwait(false); } } }
/// <summary> /// Exporting guild members /// </summary> /// <param name="commandContext">Command context</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public async Task ExportGuildMembers(CommandContextContainer commandContext) { using (var dbFactory = RepositoryFactory.CreateInstance()) { var guild = dbFactory.GetRepository <GuildRepository>() .GetQuery() .Where(obj => obj.DiscordServerId == commandContext.Guild.Id) .Select(obj => new { obj.GuildId, obj.ApiKey }) .FirstOrDefault(); var accounts = await dbFactory.GetRepository <AccountRepository>() .GetQuery() .Select(obj => new { Name = obj.Name.ToLower(), Permission = obj.Permissions }) .ToListAsync() .ConfigureAwait(false); var members = new List <(string Name, DateTime?Joined, bool IsApiKeyValid, bool HasAllPermissions)>(); var connector = new GuidWars2ApiConnector(guild.ApiKey); await using (connector.ConfigureAwait(false)) { foreach (var member in await connector.GetGuildMembers(guild.GuildId) .ConfigureAwait(false)) { var account = accounts.FirstOrDefault(obj => obj.Name == member.Name.ToLower()); members.Add((member.Name, member.Joined, account != null, account?.Permission.HasFlag(GuildWars2ApiPermission.RequiredPermissions) == true)); } } var memoryStream = new MemoryStream(); await using (memoryStream.ConfigureAwait(false)) { var writer = new StreamWriter(memoryStream); await using (writer.ConfigureAwait(false)) { await writer.WriteLineAsync("AccountName;Joined;API-Key;Permissions") .ConfigureAwait(false); foreach (var(name, joined, isApiKeyValid, hasAllPermissions) in members.OrderBy(obj => obj.IsApiKeyValid).ThenBy(obj => obj.Name)) { await writer.WriteLineAsync($"{name};{joined?.ToString("g", LocalizationGroup.CultureInfo)};{(isApiKeyValid ? "✔️" : "❌")};{(hasAllPermissions ? "✔️" : "❌")}") .ConfigureAwait(false); } await writer.FlushAsync() .ConfigureAwait(false); memoryStream.Position = 0; await commandContext.Channel .SendMessageAsync(new DiscordMessageBuilder().WithFile("members.csv", memoryStream)) .ConfigureAwait(false); } } } }
/// <summary> /// Returns the reactions which should be added to the message /// </summary> /// <returns>Reactions</returns> public override IReadOnlyList <ReactionData <bool> > GetReactions() { return(_reactions ??= new List <ReactionData <bool> > { new () { Emoji = DiscordEmojiService.GetEditEmoji(CommandContext.Client), CommandText = LocalizationGroup.GetFormattedText("EditApiKeyCommand", "{0} Edit api key", DiscordEmojiService.GetEditEmoji(CommandContext.Client)), Func = async() => { var success = false; var apiKey = await RunSubElement <AccountApiKeyDialogElement, string>().ConfigureAwait(false); apiKey = apiKey?.Trim(); if (string.IsNullOrWhiteSpace(apiKey) == false) { try { var connector = new GuidWars2ApiConnector(apiKey); await using (connector.ConfigureAwait(false)) { var tokenInformation = await connector.GetTokenInformationAsync() .ConfigureAwait(false); if (tokenInformation?.Permissions != null && tokenInformation.Permissions.Contains(TokenInformation.Permission.Account) && tokenInformation.Permissions.Contains(TokenInformation.Permission.Characters) && tokenInformation.Permissions.Contains(TokenInformation.Permission.Progression)) { var accountInformation = await connector.GetAccountInformationAsync() .ConfigureAwait(false); if (accountInformation.Name == DialogContext.GetValue <string>("AccountName")) { using (var dbFactory = RepositoryFactory.CreateInstance()) { var user = await CommandContext.GetCurrentUser() .ConfigureAwait(false); if (dbFactory.GetRepository <AccountRepository>() .Refresh(obj => obj.UserId == user.Id && obj.Name == accountInformation.Name, obj => { obj.ApiKey = apiKey; obj.Permissions = GuildWars2ApiPermissionConverter.ToPermission(tokenInformation.Permissions); })) { success = true; } } } else { await CommandContext.Channel .SendMessageAsync(LocalizationGroup.GetText("AccountNameMismatch", "The provided api key doesn't match the current account name.")) .ConfigureAwait(false); } } else { await CommandContext.Channel .SendMessageAsync(LocalizationGroup.GetText("InvalidToken", "The provided token is invalid or doesn't have the required permissions.")) .ConfigureAwait(false); } } } catch (HttpRequestException ex) when(ex.StatusCode is HttpStatusCode.Unauthorized or HttpStatusCode.Forbidden) { await CommandContext.Channel .SendMessageAsync(LocalizationGroup.GetText("InvalidToken", "The provided token is invalid or doesn't have the required permissions.")) .ConfigureAwait(false); } } return success; } }, new () { Emoji = DiscordEmojiService.GetEdit2Emoji(CommandContext.Client), CommandText = LocalizationGroup.GetFormattedText("EditDpsReportUserTokenCommand", "{0} Edit dps report user token", DiscordEmojiService.GetEdit2Emoji(CommandContext.Client)), Func = async() => { var token = await RunSubElement <AccountDpsReportUserTokenDialogElement, string>() .ConfigureAwait(false); using (var dbFactory = RepositoryFactory.CreateInstance()) { var accountName = DialogContext.GetValue <string>("AccountName"); var user = await CommandContext.GetCurrentUser() .ConfigureAwait(false); dbFactory.GetRepository <AccountRepository>() .Refresh(obj => obj.UserId == user.Id && obj.Name == accountName, obj => obj.DpsReportUserToken = token); } return true; } }, new () { Emoji = DiscordEmojiService.GetCrossEmoji(CommandContext.Client), CommandText = LocalizationGroup.GetFormattedText("CancelCommand", "{0} Cancel", DiscordEmojiService.GetCrossEmoji(CommandContext.Client)), Func = () => Task.FromResult(false) } });
/// <summary> /// Exporting stash data /// </summary> /// <param name="commandContext">Command context</param> /// <param name="sinceDate">Since date</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public async Task ExportUpgradesLogSummarized(CommandContextContainer commandContext, DateTime sinceDate) { using (var dbFactory = RepositoryFactory.CreateInstance()) { var logEntriesQuery = dbFactory.GetRepository <GuildLogEntryRepository>() .GetQuery() .Select(obj => obj); var logEntries = await dbFactory.GetRepository <GuildLogEntryRepository>() .GetQuery() .Where(obj => obj.Time > sinceDate && obj.User != null && obj.Type == "upgrade" && (obj.Action == "completed" // Cause of some items, who don't generate 'completed' we have to check also the 'queued' entries. || (obj.Action == "queued" && logEntriesQuery.Any(obj2 => obj2.Type == "upgrade" && obj2.UpgradeId == obj.UpgradeId && obj2.Action == "completed") == false)) && obj.Guild.DiscordServerId == commandContext.Guild.Id) .GroupBy(obj => new { obj.User, obj.ItemId, obj.UpgradeId }) .Select(obj => new { obj.Key.User, obj.Key.ItemId, obj.Key.UpgradeId, Count = obj.Sum(obj2 => obj2.Count ?? 1) }) .OrderBy(obj => obj.User) .ThenBy(obj => obj.ItemId) .ThenBy(obj => obj.UpgradeId) .ToListAsync() .ConfigureAwait(false); var itemIds = logEntries.Where(obj => obj.ItemId != null) .Select(obj => obj.ItemId) .Distinct() .ToList(); var upgradeIds = logEntries.Where(obj => obj.ItemId == null && obj.UpgradeId != null) .Select(obj => obj.UpgradeId) .Distinct() .ToList(); var connector = new GuidWars2ApiConnector(null); await using (connector.ConfigureAwait(false)) { var tradingsPostValues = await connector.GetTradingPostPrices(itemIds) .ConfigureAwait(false); var items = await connector.GetItems(itemIds) .ConfigureAwait(false); var upgrades = await connector.GetUpgrades(upgradeIds) .ConfigureAwait(false); var memoryStream = new MemoryStream(); await using (memoryStream.ConfigureAwait(false)) { var writer = new StreamWriter(memoryStream); await using (writer.ConfigureAwait(false)) { await writer.WriteLineAsync("User;ItemId;ItemName;Count;TradingPostValue;VendorValue") .ConfigureAwait(false); foreach (var entry in logEntries) { var item = items.FirstOrDefault(obj => obj.Id == entry.ItemId); var tradingPostPrice = tradingsPostValues.FirstOrDefault(obj => obj.Id == entry.ItemId); var itemName = entry.ItemId == null? upgrades.FirstOrDefault(obj => obj.Id == entry.UpgradeId)?.Name : item?.Name; await writer.WriteLineAsync($"{entry.User};{entry.ItemId};{itemName};{entry.Count};{tradingPostPrice?.TradingPostSellValue?.UnitPrice};{item?.VendorValue}") .ConfigureAwait(false); } await writer.FlushAsync() .ConfigureAwait(false); memoryStream.Position = 0; await commandContext.Channel .SendMessageAsync(new DiscordMessageBuilder().WithFile("upgrades_log.csv", memoryStream)) .ConfigureAwait(false); } } } } }
/// <summary> /// Post random guild emblems /// </summary> /// <param name="commandContext">Command context</param> /// <param name="count">Count</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public async Task PostRandomGuildEmblems(CommandContextContainer commandContext, int count) { var connector = new GuidWars2ApiConnector(null); await using (connector.ConfigureAwait(false)) { var random = new Random(DateTime.Now.Millisecond); var foregrounds = await connector.GetGuildEmblemForegrounds() .ConfigureAwait(false); var backgrounds = await connector.GetGuildEmblemBackgrounds() .ConfigureAwait(false); var colors = new List <Color> { new Rgba32(190, 186, 185), new Rgba32(136, 0, 10), new Rgba32(36, 65, 121), new Rgba32(157, 143, 108), new Rgba32(26, 24, 27), new Rgba32(31, 88, 45), new Rgba32(71, 69, 70), new Rgba32(117, 25, 66), new Rgba32(54, 5, 1), new Rgba32(137, 51, 4), new Rgba32(133, 36, 27), new Rgba32(137, 85, 1), new Rgba32(113, 72, 16), new Rgba32(36, 79, 0), new Rgba32(82, 69, 0), new Rgba32(24, 39, 0), new Rgba32(0, 108, 108), new Rgba32(0, 55, 49), new Rgba32(125, 136, 138), new Rgba32(0, 78, 109), new Rgba32(0, 31, 52), new Rgba32(199, 93, 103), new Rgba32(53, 53, 115), new Rgba32(95, 29, 101), new Rgba32(69, 39, 99), new Rgba32(70, 16, 66), }; for (var i = 0; i < count; i++) { var fileName = new StringBuilder(); fileName.Append("emblem_"); var foregroundId = foregrounds[random.Next(0, foregrounds.Count - 1)]; fileName.Append(foregroundId); var backgroundId = backgrounds[random.Next(0, backgrounds.Count - 1)]; fileName.Append('_'); fileName.Append(backgroundId); var foregroundLayers = await connector.GetGuildEmblemForegroundLayer(foregroundId) .ConfigureAwait(false); var backgroundLayers = await connector.GetGuildEmblemBackgroundLayer(backgroundId) .ConfigureAwait(false); var client = _httpClientFactory.CreateClient(); Image target = null; foreach (var layer in backgroundLayers.Layers) { var response = await client.GetAsync(layer) .ConfigureAwait(false); var stream = await response.Content .ReadAsStreamAsync() .ConfigureAwait(false); await using (stream.ConfigureAwait(false)) { stream.Position = 0; stream.Position = 0; var tempImage = await Image.LoadAsync <Rgba32>(stream) .ConfigureAwait(false); var colorIndex = random.Next(0, colors.Count - 1); fileName.Append('_'); fileName.Append(colorIndex); tempImage.Mutate(o => o.Fill(new RecolorBrush(new Color(new Rgba32(176, 35, 33)), colors[colorIndex], 0.3f))); if (target == null) { target = tempImage; } else { target.Mutate(o => o.DrawImage(tempImage, new Point(0, 0), 1f)); } } } var isFlipHorizontal = random.Next(0, 10) <= 2; var isFlipVertical = random.Next(0, 10) <= 2; if (isFlipHorizontal) { target.Mutate(o => o.Flip(FlipMode.Horizontal)); } if (isFlipVertical) { target.Mutate(o => o.Flip(FlipMode.Vertical)); } isFlipHorizontal = random.Next(0, 10) <= 2; isFlipVertical = random.Next(0, 10) <= 2; foreach (var layer in foregroundLayers.Layers.AsEnumerable() .Skip(1)) { var response = await client.GetAsync(layer) .ConfigureAwait(false); var stream = await response.Content .ReadAsStreamAsync() .ConfigureAwait(false); await using (stream.ConfigureAwait(false)) { stream.Position = 0; var tempImage = await Image.LoadAsync <Rgba32>(stream) .ConfigureAwait(false); if (layer != foregroundLayers.Layers.First()) { var colorIndex = random.Next(0, colors.Count - 1); fileName.Append('_'); fileName.Append(colorIndex); tempImage.Mutate(o => o.Fill(new GraphicsOptions { AlphaCompositionMode = PixelAlphaCompositionMode.SrcIn, }, new RecolorBrush(Color.White, colors[colorIndex], 0.26f))); } if (isFlipHorizontal) { tempImage.Mutate(o => o.Flip(FlipMode.Horizontal)); } if (isFlipVertical) { tempImage.Mutate(o => o.Flip(FlipMode.Vertical)); } target.Mutate(o => o.DrawImage(tempImage, new Point(0, 0), 1f)); } } var memoryStream = new MemoryStream(); await using (memoryStream.ConfigureAwait(false)) { await target.SaveAsPngAsync(memoryStream) .ConfigureAwait(false); memoryStream.Position = 0; fileName.Append(".png"); await commandContext.Channel .SendMessageAsync(new DiscordMessageBuilder().WithFile(fileName.ToString(), memoryStream, true)) .ConfigureAwait(false); } } } }
/// <summary> /// Validation the guild bank /// </summary> /// <param name="commandContext">Command context</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public async Task Check(CommandContextContainer commandContext) { using (var dbFactory = RepositoryFactory.CreateInstance()) { var guild = dbFactory.GetRepository <GuildRepository>() .GetQuery() .Where(obj => obj.DiscordServerId == commandContext.Guild.Id) .Select(obj => new { obj.ApiKey, obj.GuildId }) .FirstOrDefault(); if (string.IsNullOrWhiteSpace(guild?.ApiKey) == false) { var msg = new DiscordEmbedBuilder(); msg.WithTitle(LocalizationGroup.GetText("BankValidation", "Guild bank validation")); msg.WithDescription(LocalizationGroup.GetText("BankValidationResult", "In the following message you can see the results of the bank validation.")); msg.WithFooter("Scruffy", "https://cdn.discordapp.com/app-icons/838381119585648650/823930922cbe1e5a9fa8552ed4b2a392.png?size=64"); msg.WithTimestamp(DateTime.Now); var connector = new GuidWars2ApiConnector(guild.ApiKey); await using (connector.ConfigureAwait(false)) { var vault = await connector.GetGuildVault(guild.GuildId) .ConfigureAwait(false); foreach (var stash in vault) { var slots = new List <(int ItemId, int X, int Y)>(); var i = 0; foreach (var slot in stash.Slots) { if (slot != null && slot.Count < 250) { slots.Add((slot.ItemId, (i % 10) + 1, (i / 10) + 1)); } i++; } var stringBuilder = new StringBuilder(); foreach (var group in slots.ToLookup(obj => obj.ItemId, obj => (obj.X, obj.Y)) .Where(obj => obj.Count() > 1)) { var item = await connector.GetItem(group.Key) .ConfigureAwait(false); stringBuilder.AppendLine(item.Name); foreach (var(x, y) in group.OrderBy(obj => obj.X) .ThenBy(obj => obj.Y)) { stringBuilder.AppendLine($" - " + Formatter.InlineCode($"({x}/{y})")); } } if (stringBuilder.Length > 0) { stringBuilder.Insert(0, Formatter.Bold(LocalizationGroup.GetText("DuplicationCheck", "Duplication check")) + " \u200B " + DiscordEmojiService.GetCrossEmoji(commandContext.Client) + "\n"); } else { stringBuilder.AppendLine(Formatter.Bold(LocalizationGroup.GetText("DuplicationCheck", "Duplication check")) + " \u200B " + DiscordEmojiService.GetCheckEmoji(commandContext.Client)); } if (stash.Coins != 0 && stash.Coins % 10000 != 0) { var goldCoins = stash.Coins / 10000; var silverCoins = (stash.Coins - (goldCoins * 10000)) / 100; var copperCoins = stash.Coins % 100; stringBuilder.AppendLine(Formatter.Bold(LocalizationGroup.GetText("CoinCheck", "Coins check")) + " \u200B " + DiscordEmojiService.GetCrossEmoji(commandContext.Client)); stringBuilder.AppendLine($"{goldCoins} {DiscordEmojiService.GetGuildWars2GoldEmoji(commandContext.Client)} {silverCoins} {DiscordEmojiService.GetGuildWars2SilverEmoji(commandContext.Client)} {copperCoins} {DiscordEmojiService.GetGuildWars2CopperEmoji(commandContext.Client)}"); } else { stringBuilder.AppendLine(Formatter.Bold(LocalizationGroup.GetText("CoinCheck", "Coins check")) + " \u200B " + DiscordEmojiService.GetCheckEmoji(commandContext.Client)); } stringBuilder.Append("\u200B"); msg.AddField(stash.Note ?? "Stash", stringBuilder.ToString()); } } await commandContext.Channel .SendMessageAsync(msg) .ConfigureAwait(false); } else { await commandContext.Channel .SendMessageAsync(LocalizationGroup.GetText("NoApiKey", "The guild ist not configured.")) .ConfigureAwait(false); } } }
/// <summary> /// Adding a new account /// </summary> /// <param name="commandContextContainer">Command context</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public async Task Add(CommandContextContainer commandContextContainer) { if (commandContextContainer.Message.Channel.IsPrivate == false) { await commandContextContainer.Message .RespondAsync(LocalizationGroup.GetText("SwitchToPrivate", "I answered your command as a private message.")) .ConfigureAwait(false); } await commandContextContainer.SwitchToDirectMessageContext() .ConfigureAwait(false); var apiKey = await DialogHandler.Run <AccountApiKeyDialogElement, string>(commandContextContainer) .ConfigureAwait(false); apiKey = apiKey?.Trim(); if (string.IsNullOrWhiteSpace(apiKey) == false) { try { var connector = new GuidWars2ApiConnector(apiKey); await using (connector.ConfigureAwait(false)) { var tokenInformation = await connector.GetTokenInformationAsync() .ConfigureAwait(false); if (tokenInformation?.Permissions != null && tokenInformation.Permissions.Contains(TokenInformation.Permission.Account) && tokenInformation.Permissions.Contains(TokenInformation.Permission.Characters) && tokenInformation.Permissions.Contains(TokenInformation.Permission.Progression)) { var accountInformation = await connector.GetAccountInformationAsync() .ConfigureAwait(false); using (var dbFactory = RepositoryFactory.CreateInstance()) { var userId = dbFactory.GetRepository <DiscordAccountRepository>() .GetQuery() .Where(obj => obj.Id == commandContextContainer.User.Id) .Select(obj => obj.UserId) .First(); if (dbFactory.GetRepository <AccountRepository>() .AddOrRefresh(obj => obj.UserId == userId && obj.Name == accountInformation.Name, obj => { obj.UserId = userId; obj.Name = accountInformation.Name; obj.ApiKey = apiKey; obj.Permissions = GuildWars2ApiPermissionConverter.ToPermission(tokenInformation.Permissions); })) { await commandContextContainer.Channel .SendMessageAsync(LocalizationGroup.GetText("ApiKeyAdded", "Your API-Key has been added successfully.")) .ConfigureAwait(false); } else { throw dbFactory.LastError; } } } else { await commandContextContainer.Channel .SendMessageAsync(LocalizationGroup.GetText("InvalidToken", "The provided token is invalid or doesn't have the required permissions.")) .ConfigureAwait(false); } } } catch (HttpRequestException ex) when(ex.StatusCode is HttpStatusCode.Unauthorized or HttpStatusCode.Forbidden) { await commandContextContainer.Channel .SendMessageAsync(LocalizationGroup.GetText("InvalidToken", "The provided token is invalid or doesn't have the required permissions.")) .ConfigureAwait(false); } } }
/// <summary> /// Exporting stash data /// </summary> /// <param name="commandContext">Command context</param> /// <param name="sinceDate">Since date</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public async Task ExportStashLog(CommandContextContainer commandContext, DateTime sinceDate) { using (var dbFactory = RepositoryFactory.CreateInstance()) { var logEntries = await dbFactory.GetRepository <GuildLogEntryRepository>() .GetQuery() .Where(obj => obj.Time > sinceDate && obj.Type == "stash" && obj.Guild.DiscordServerId == commandContext.Guild.Id) .OrderBy(obj => obj.Time) .Select(obj => new { obj.Id, obj.Time, obj.User, obj.Operation, obj.ItemId, obj.Count, obj.Coins }) .ToListAsync() .ConfigureAwait(false); var itemIds = logEntries.Where(obj => obj.ItemId != null) .Select(obj => obj.ItemId) .Distinct() .ToList(); var connector = new GuidWars2ApiConnector(null); await using (connector.ConfigureAwait(false)) { var tradingsPostValues = await connector.GetTradingPostPrices(itemIds) .ConfigureAwait(false); var items = await connector.GetItems(itemIds) .ConfigureAwait(false); var memoryStream = new MemoryStream(); await using (memoryStream.ConfigureAwait(false)) { var writer = new StreamWriter(memoryStream); await using (writer.ConfigureAwait(false)) { await writer.WriteLineAsync("TimeStamp;User;Operation;ItemId;ItemName;Count;TradingPostValue;VendorValue") .ConfigureAwait(false); foreach (var entry in logEntries) { var item = items.FirstOrDefault(obj => obj.Id == entry.ItemId); var tradingPostPrice = tradingsPostValues.FirstOrDefault(obj => obj.Id == entry.ItemId); await writer.WriteLineAsync($"{entry.Time.ToString("g", LocalizationGroup.CultureInfo)};{entry.User};{entry.Operation};{entry.ItemId};{(entry.ItemId == null || entry.ItemId == 0 ? "Coins" : item?.Name)};{entry.Count};{tradingPostPrice?.TradingPostSellValue?.UnitPrice};{(entry.ItemId == null || entry.ItemId == 0 ? entry.Coins : item?.VendorValue)}") .ConfigureAwait(false); } await writer.FlushAsync() .ConfigureAwait(false); memoryStream.Position = 0; await commandContext.Channel .SendMessageAsync(new DiscordMessageBuilder().WithFile("stash_log.csv", memoryStream)) .ConfigureAwait(false); } } } } }
/// <summary> /// Exporting representation state /// </summary> /// <param name="commandContext">Command context</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public async Task ExportRepresentation(CommandContextContainer commandContext) { using (var dbFactory = RepositoryFactory.CreateInstance()) { var guildId = dbFactory.GetRepository <GuildRepository>() .GetQuery() .Where(obj => obj.DiscordServerId == commandContext.Guild.Id) .Select(obj => obj.GuildId) .FirstOrDefault(); var entries = await dbFactory.GetRepository <AccountRepository>() .GetQuery() .Select(obj => new { obj.Name, DiscordAccountId = obj.User .DiscordAccounts .Select(obj2 => obj2.Id) .FirstOrDefault(), obj.ApiKey }) .ToListAsync() .ConfigureAwait(false); var accounts = new List <(string User, string AccountName, int Characters, int?Representation)>(); foreach (var entry in entries) { DiscordMember user = null; try { user = await commandContext.Guild .GetMemberAsync(entry.DiscordAccountId) .ConfigureAwait(false); } catch { } if (user != null) { var connector = new GuidWars2ApiConnector(entry.ApiKey); await using (connector.ConfigureAwait(false)) { var characters = await connector.GetCharactersAsync() .ConfigureAwait(false); accounts.Add((user.TryGetDisplayName(), entry.Name, characters?.Count ?? 0, characters?.Count(obj => obj.Guild == guildId) ?? 0)); } } } var memoryStream = new MemoryStream(); await using (memoryStream.ConfigureAwait(false)) { var writer = new StreamWriter(memoryStream); await using (writer.ConfigureAwait(false)) { await writer.WriteLineAsync("User;AccountName;Characters;Representation;Percentage") .ConfigureAwait(false); foreach (var(user, accountName, characters, representation) in accounts.OrderBy(obj => obj.User) .ThenBy(obj => obj.AccountName)) { await writer.WriteLineAsync($"{user};{accountName};{characters};{representation};{(characters != 0 ? representation / (double)characters : 0)}") .ConfigureAwait(false); } await writer.FlushAsync() .ConfigureAwait(false); memoryStream.Position = 0; await commandContext.Channel .SendMessageAsync(new DiscordMessageBuilder().WithFile("representation.csv", memoryStream)) .ConfigureAwait(false); } } } }
/// <summary> /// Executes the job /// </summary> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public override async Task ExecuteAsync() { using (var dbFactory = RepositoryFactory.CreateInstance()) { var serviceProvider = GlobalServiceProvider.Current.GetServiceProvider(); await using (serviceProvider.ConfigureAwait(false)) { var discordClient = serviceProvider.GetService <DiscordClient>(); var guildRankService = new Lazy <GuildRankService>(() => serviceProvider.GetService <GuildRankService>()); var channels = dbFactory.GetRepository <GuildChannelConfigurationRepository>() .GetQuery() .Select(obj => obj); foreach (var guild in dbFactory.GetRepository <GuildRepository>() .GetQuery() .Select(obj => new { obj.Id, obj.ApiKey, obj.GuildId, LastLogEntryId = obj.GuildLogEntries .Select(obj2 => obj2.Id) .OrderByDescending(obj2 => obj2) .FirstOrDefault(), ChannelId = channels.Where(obj2 => obj2.GuildId == obj.Id && obj2.Type == GuildChannelConfigurationType.GuildLogNotification) .Select(obj2 => (ulong?)obj2.DiscordChannelId) .FirstOrDefault() }) .ToList()) { var discordChannel = guild.ChannelId != null ? await discordClient.GetChannelAsync(guild.ChannelId.Value) .ConfigureAwait(false) : null; var connector = new GuidWars2ApiConnector(guild.ApiKey); await using (connector.ConfigureAwait(false)) { try { foreach (var entry in (await connector.GetGuildLogEntries(guild.GuildId, guild.LastLogEntryId).ConfigureAwait(false)).OrderBy(obj => obj.Id)) { if (dbFactory.GetRepository <GuildLogEntryRepository>() .Add(new GuildLogEntryEntity { GuildId = guild.Id, Id = entry.Id, Time = entry.Time.ToLocalTime(), Type = entry.Type, User = entry.User, KickedBy = entry.KickedBy, InvitedBy = entry.InvitedBy, Operation = entry.Operation, ItemId = entry.ItemId, Count = entry.Count, Coins = entry.Coins, ChangedBy = entry.ChangedBy, OldRank = entry.OldRank, NewRank = entry.NewRank, UpgradeId = entry.UpgradeId, RecipeId = entry.RecipeId, Action = entry.Action, Activity = entry.Activity, TotalParticipants = entry.TotalParticipants, Participants = string.Join(';', entry.Participants?.Where(obj => string.IsNullOrWhiteSpace(obj) == false) ?? Array.Empty <string>()), MessageOfTheDay = entry.MessageOfTheDay })) { switch (entry.Type) { case GuildLogEntryEntity.Types.Joined: { await OnJoined(discordChannel, entry).ConfigureAwait(false); } break; case GuildLogEntryEntity.Types.Kick: { await OnKick(discordChannel, entry).ConfigureAwait(false); } break; case GuildLogEntryEntity.Types.RankChange: { await OnRankChanged(guildRankService.Value, guild.Id, entry).ConfigureAwait(false); } break; } } } } catch (Exception ex) { LoggingService.AddJobLogEntry(LogEntryLevel.Warning, nameof(GuildLogImportJob), ex.Message, null, ex); } } } } } }