protected GlobalViewDataModel CreateGlobalViewDataAsync(CachedAccount cachedAccount, CommonUserAccountModel commonUserAccountModel = null) { var globalViewData = Mapper.Map <GlobalViewDataModel>(cachedAccount); if (commonUserAccountModel != null) { globalViewData.Permissions = commonUserAccountModel.Permissions; globalViewData.UserOwnsAnAccount = cachedAccount.OwnerUserId == commonUserAccountModel.UserId; } return(globalViewData); }
public async Task HandleMessageAsync(GuildConfig guild, CachedAccount account, IMessage message, bool doAutoProxy) { // Bail early if this isn't in a guild channel if (!(message.Channel is ITextChannel channel)) { return; } // Find a member with proxy tags matching the message var match = GetProxyTagMatch(message.Content, account.System, account.Members); // O(n) lookup since n is small (max ~100 in prod) and we're more constrained by memory (for a dictionary) here var systemSettingsForGuild = account.SettingsForGuild(channel.GuildId); // If we didn't get a match by proxy tags, try to get one by autoproxy // Also try if we *did* get a match, but there's no inner text. This happens if someone sends a message that // is equal to someone else's tags, and messages like these should be autoproxied if possible // All of this should only be done if this call allows autoproxy. // When a normal message is sent, autoproxy is enabled, but if this method is called from a message *edit* // event, then autoproxy is disabled. This is so AP doesn't "retrigger" when the original message was escaped. if (doAutoProxy && (match == null || (match.InnerText.Trim().Length == 0 && message.Attachments.Count == 0))) { match = await GetAutoproxyMatch(account, systemSettingsForGuild, message, channel); } // If we still haven't found any, just yeet if (match == null) { return; } // And make sure the channel's not blacklisted from proxying. if (guild.Blacklist.Contains(channel.Id)) { return; } // Make sure the system hasn't blacklisted the guild either if (!systemSettingsForGuild.ProxyEnabled) { return; } // We know message.Channel can only be ITextChannel as PK doesn't work in DMs/groups // Afterwards we ensure the bot has the right permissions, otherwise bail early if (!await EnsureBotPermissions(channel)) { return; } // Can't proxy a message with no content and no attachment if (match.InnerText.Trim().Length == 0 && message.Attachments.Count == 0) { return; } var memberSettingsForGuild = account.SettingsForMemberGuild(match.Member.Id, channel.GuildId); // Get variables in order and all var proxyName = match.Member.ProxyName(match.System.Tag, memberSettingsForGuild.DisplayName); var avatarUrl = memberSettingsForGuild.AvatarUrl ?? match.Member.AvatarUrl ?? match.System.AvatarUrl; // If the name's too long (or short), bail if (proxyName.Length < 2) { throw Errors.ProxyNameTooShort(proxyName); } if (proxyName.Length > Limits.MaxProxyNameLength) { throw Errors.ProxyNameTooLong(proxyName); } // Add the proxy tags into the proxied message if that option is enabled // Also check if the member has any proxy tags - some cases autoproxy can return a member with no tags var messageContents = (match.Member.KeepProxy && match.ProxyTags.HasValue) ? $"{match.ProxyTags.Value.Prefix}{match.InnerText}{match.ProxyTags.Value.Suffix}" : match.InnerText; // Sanitize @everyone, but only if the original user wouldn't have permission to messageContents = SanitizeEveryoneMaybe(message, messageContents); // Execute the webhook itself var hookMessageId = await _webhookExecutor.ExecuteWebhook( channel, proxyName, avatarUrl, messageContents, message.Attachments ); // Store the message in the database, and log it in the log channel (if applicable) await _data.AddMessage(message.Author.Id, hookMessageId, channel.GuildId, message.Channel.Id, message.Id, match.Member); await _logChannel.LogMessage(match.System, match.Member, hookMessageId, message.Id, message.Channel as IGuildChannel, message.Author, match.InnerText, guild); // Wait a second or so before deleting the original message await Task.Delay(1000); try { await message.DeleteAsync(); } catch (HttpException) { // If it's already deleted, we just log and swallow the exception _logger.Warning("Attempted to delete already deleted proxy trigger message {Message}", message.Id); } }
private async Task <ProxyMatch> GetAutoproxyMatch(CachedAccount account, SystemGuildSettings guildSettings, IMessage message, IGuildChannel channel) { // For now we use a backslash as an "escape character", subject to change later if ((message.Content ?? "").TrimStart().StartsWith("\\")) { return(null); } PKMember member = null; // Figure out which member to proxy as switch (guildSettings.AutoproxyMode) { case AutoproxyMode.Off: // Autoproxy off, bail return(null); case AutoproxyMode.Front: // Front mode: just use the current first fronter member = await _data.GetFirstFronter(account.System); break; case AutoproxyMode.Latch: // Latch mode: find last proxied message, use *that* member var msg = await _data.GetLastMessageInGuild(message.Author.Id, channel.GuildId); if (msg == null) { return(null); // No message found } // If the message is older than 6 hours, ignore it and force the sender to "refresh" a proxy // This can be revised in the future, it's a preliminary value. var timestamp = SnowflakeUtils.FromSnowflake(msg.Message.Mid).ToInstant(); var timeSince = SystemClock.Instance.GetCurrentInstant() - timestamp; if (timeSince > Duration.FromHours(6)) { return(null); } member = msg.Member; break; case AutoproxyMode.Member: // Member mode: just use that member // O(n) lookup since n is small (max 1000 de jure) and we're more constrained by memory (for a dictionary) here member = account.Members.FirstOrDefault(m => m.Id == guildSettings.AutoproxyMember); break; } // If we haven't found the member (eg. front mode w/ no fronter), bail again if (member == null) { return(null); } return(new ProxyMatch { System = account.System, Member = member, // Autoproxying members with no proxy tags is possible, return the correct result ProxyTags = member.ProxyTags.Count > 0 ? member.ProxyTags.First() : (ProxyTag?)null, InnerText = message.Content }); }
public async Task <string> SendEvidencePackage(CachedAccount cachedAccount, long citationNumber, string FTPURl, string FTPFolder, string FTPUsername, string FTPPassword, Citation citationAttachment, string awsAccessKey, string awsSecretKey, string bucketName) { var result = string.Empty; try { _cachedAccount = cachedAccount; // var FilePath = $"c:\\temp"; //var archivePath = $"c:\\temp\\{AccountNumber}-{citationNumber}.zip"; //Create folder if not Exists var FilePath = Path.Combine(_env.WebRootPath, @"upload"); var FileLocation = FilePath + @"\CitationReceipt.txt"; if (!Directory.Exists(FilePath)) { Directory.CreateDirectory(FilePath); } else { System.IO.DirectoryInfo di = new DirectoryInfo(FilePath); foreach (FileInfo file in di.GetFiles()) { file.Delete(); } } var archivePath = $"{FilePath}\\{cachedAccount.Number}-{citationNumber}.zip"; //Read the file and copy it to the temp directory if (citationAttachment.Attachments != null) { foreach (var attach in citationAttachment.Attachments) { var cityAppFile = await _fileService.ReadFile(attach.Attachment.Key, awsAccessKey, awsSecretKey, bucketName); if (cityAppFile.FileName != null) { //Download the file to temp path var newFile = $"{FilePath}\\{attach.Attachment.FileName}"; using (var fileStream = File.Create(newFile)) { cityAppFile.FileStream.Position = 0; cityAppFile.FileStream.CopyTo(fileStream); } } } } //Create Text file await CitationReceipt(citationAttachment, FileLocation, cachedAccount); //Zip all attachment result = await CreateArchive(FilePath, archivePath, FTPURl, FTPFolder, FTPUsername, FTPPassword); } catch (Exception ex) { _logger.Error(ex, $"Error SendEvidencePackage file To FTP: Exception: {ex}, InnerException: {ex.InnerException} "); throw ex; } return(result); }
public async Task <bool> CitationReceipt(Citation citation, string FileLocation, CachedAccount cachedAccount) { var commonAccount = await _commonCtx.CommonAccounts .Include(m => m.City) .Where(x => x.Id == citation.AccountId).SingleOrDefaultAsync(); if (commonAccount == null) { return(false); } var citationReceipt = new CitationReceiptModel() { CitationNumber = citation.CitationNumber, AccountNumber = cachedAccount.Number, AccountName = cachedAccount.Name, AccountCity = commonAccount.City.Name, AccountState = commonAccount.City.StateCode, ViolationCode = citation.Violation != null ? citation.Violation.Code : "", ViolationTitle = citation.Violation != null ? citation.Violation.Name : "", ViolationState = citation.State, ViolationCity = citation.City, LicensePlate = citation.LicensePlate, LicenseState = citation.LicenseState, ViolationLatitude = citation.Latitude, ViolationLongitude = citation.Longitude, ViolationCreatedUTC = citation.Violation != null ? citation.Violation.CreateUtc : DateTime.UtcNow, }; var data = JsonConvert.SerializeObject(citationReceipt); TextWriter tw = File.CreateText(FileLocation); tw.WriteLine(data); tw.Close(); return(true); }