protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { Page.Title = "Bulk Email Delete"; H1.InnerHtml = "Bulk Email Delete"; Master.MasterForm.Attributes.Add("enctype", "multipart/form-data"); } else { _Messages = new List <string>(); for (var i = 0; i < Request.Files.Count; i++) { var file = Request.Files[i]; if (file.ContentLength == 0) { continue; } try { var address = EmailUtility.ExtractUndeliverableEmailAddressFromMsg(file.InputStream); if (DeleteCheckBox.Checked) { DoDeletions(address); } else { AnalyzeDeletions(address); } } catch (Exception ex) { _Messages.Add( $"<p class=\"error\">Error processing file: {file.FileName}, {ex.Message}</p>"); } } foreach (var address in ExtraAddresses.Text.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries) .Select(a => a.Trim())) { if (DeleteCheckBox.Checked) { DoDeletions(address); } else { AnalyzeDeletions(address); } } SummaryPlaceHolder.Controls.Add(new LiteralControl(string.Join(string.Empty, _Messages))); SummaryContainer.RemoveCssClass("hidden"); } }
private void PostCsv() { var now = DateTime.UtcNow; var messages = new List <string>(); var good = 0; var bad = 0; try { if (Request.Files.Count != 1 || Request.Files[0].ContentLength == 0) { throw new VoteException("Could not find CSV file"); } using (var parser = new TextFieldParser(Request.Files[0].InputStream, Encoding.UTF8)) { parser.TextFieldType = FieldType.Delimited; parser.HasFieldsEnclosedInQuotes = true; parser.SetDelimiters(","); // look for the field names -- they aren't the first row so find a row whose // first column is "FirstName" string[] columnNames = null; while (!parser.EndOfData) { var row = parser.ReadFields(); // ReSharper disable once PossibleNullReferenceException //if (row.Length > 0 && row[0] == "FirstName") if (row.Length > 0 && new[] { "FirstName", "First Name" }.Contains(row[0])) { columnNames = row; break; } } if (columnNames == null) { throw new VoteException( "Could not find column names row (\"FirstName\" in first column"); } var maxColumnInx = -1; var firstNameInx = GetColumnIndex(columnNames, new[] { "FirstName", "First Name" }, ref maxColumnInx); var lastNameInx = GetColumnIndex(columnNames, new[] { "LastName", "Last Name" }, ref maxColumnInx); var address1Inx = GetColumnIndex(columnNames, "Address1", ref maxColumnInx); var address2Inx = GetColumnIndex(columnNames, "Address2", ref maxColumnInx); var cityInx = GetColumnIndex(columnNames, "City", ref maxColumnInx); var stateProvinceInx = GetColumnIndex(columnNames, new[] { "StateProvince", "State/Province" }, ref maxColumnInx); var zipCodeInx = GetColumnIndex(columnNames, new[] { "ZipCode", "Zip Code" }, ref maxColumnInx); var emailInx = GetColumnIndex(columnNames, "Email", ref maxColumnInx); var phoneInx = GetColumnIndex(columnNames, "Phone", ref maxColumnInx); var transactionDateInx = GetColumnIndex(columnNames, new[] { "TransactionDate", "Transaction Date" }, ref maxColumnInx); var totalChangedInx = GetColumnIndex(columnNames, new[] { "TotalCharged", "Total" }, ref maxColumnInx); while (!parser.EndOfData) { var row = parser.ReadFields(); try { // ReSharper disable once PossibleNullReferenceException if (row.Length <= maxColumnInx) { throw new VoteException( $"Contains only {row.Length} columns, {maxColumnInx + 1} required."); } var email = row[emailInx]; if (IsNullOrWhiteSpace(email)) { throw new VoteException("Email is missing"); } if (!Validation.IsValidEmailAddress(email)) { throw new VoteException($"Invalid Email: {email}"); } var firstName = row[firstNameInx]; var lastName = row[lastNameInx]; var fullName = firstName + " " + lastName; if (IsNullOrWhiteSpace(fullName)) { throw new VoteException("FirstName or LastName is missing"); } var address = row[address1Inx]; var address2 = row[address2Inx]; if (!IsNullOrWhiteSpace(address) && !IsNullOrWhiteSpace(address2)) { address += ", " + address2; } var city = row[cityInx]; if (IsNullOrWhiteSpace(city)) { throw new VoteException("City is missing"); } var stateCode = row[stateProvinceInx]; if (IsNullOrWhiteSpace(stateCode)) { throw new VoteException("StateProvince is missing"); } if (!StateCache.IsValidStateCode(stateCode)) { // might be state name stateCode = StateCache.GetStateCode(stateCode); if (!StateCache.IsValidStateCode(stateCode)) { throw new VoteException("Invaid state or state code"); } } var zipCode = row[zipCodeInx]; if (IsNullOrWhiteSpace(zipCode)) { NonFatalError(messages, parser.LineNumber, $"ZipCode is missing ({email})"); } var zipMatch = Regex.Match(zipCode, @"(?<zip5>\d{5})(?:\D?(?<zip4>\d{4}))?"); var zip5 = Empty; var zip4 = Empty; if (!zipMatch.Success) { NonFatalError(messages, parser.LineNumber, $"Could not parse ZipCode: {zipCode} ({email})"); } else { zip5 = zipMatch.Groups["zip5"].Value; zip4 = zipMatch.Groups["zip4"].Value; } var phone = row[phoneInx].NormalizePhoneNumber(); if (!DateTime.TryParse(row[transactionDateInx], out var transactionDate)) { throw new VoteException( $"Could not parse TransactionDate: {row[transactionDateInx]}"); } if (!decimal.TryParse(row[totalChangedInx], out var totalCharged)) { throw new VoteException( $"Could not parse TotalCharged: {row[totalChangedInx]}"); } if (totalCharged == 0) { continue; } //if (Donations.EmailDateExists(email, transactionDate)) // throw new VoteException( // "A donation for this email, date and time already exists" + // $" ({email}, {transactionDate:G}, {totalCharged:C})"); Donations.Insert(email, transactionDate, firstName, lastName, fullName, address, city, stateCode, zip5, zip4, phone, totalCharged, false, null); // Get the encoding var googleResult = GoogleMapsLookup.Lookup(address, city, stateCode, zip5); TigerLookupData tigerResult = null; if (googleResult.Status == "OK") { tigerResult = TigerLookup.Lookup(googleResult.Latitude, googleResult.Longitude); } var table = Addresses.GetDataByEmail(email); if (table.Count == 0) // Insert { Addresses.Insert(firstName, lastName, address, city, stateCode, zip5, zip4, email, phone, now, "DONR", false, false, false, DefaultDbDate, Empty, tigerResult?.Congress.SafeString(), tigerResult?.Upper.SafeString(), tigerResult?.Lower.SafeString(), tigerResult?.County.SafeString(), tigerResult?.District.SafeString(), tigerResult?.Place.SafeString(), tigerResult?.Elementary.SafeString(), tigerResult?.Secondary.SafeString(), tigerResult?.Unified.SafeString(), tigerResult?.CityCouncil.SafeString(), tigerResult?.CountySupervisors.SafeString(), tigerResult?.SchoolDistrictDistrict.SafeString(), googleResult.Latitude, googleResult.Longitude, googleResult.Status == "OK" ? now : DefaultDbDate, 0, DefaultDbDate, true); } else if (googleResult.Status == "OK") // update all matching Addresses { foreach (var r in table) { if (!IsNullOrWhiteSpace(firstName)) { r.FirstName = firstName; } if (!IsNullOrWhiteSpace(lastName)) { r.LastName = lastName; } if (!IsNullOrWhiteSpace(phone)) { r.Phone = phone; } r.IsDonor = true; if (tigerResult != null) { r.Address = address; r.City = city; r.StateCode = stateCode; r.Zip5 = zip5; r.Zip4 = zip4; r.CongressionalDistrict = tigerResult.Congress; r.StateSenateDistrict = tigerResult.Upper; r.StateHouseDistrict = tigerResult.Lower; r.County = tigerResult.County; r.District = tigerResult.District; r.Place = tigerResult.Place; r.Latitude = googleResult.Latitude; r.Longitude = googleResult.Longitude; r.DistrictLookupDate = now; } } Addresses.UpdateTable(table); } messages.Add( $"<p>{totalCharged:C} donation added for {fullName}<{email}> on {transactionDate:G}</p>"); good++; } catch (Exception ex) { messages.Add( $"<p class=\"error\">Error on row {parser.LineNumber}: {ex.Message}</p>"); bad++; } } } } catch (Exception ex) { messages.Add($"<p class=\"error\">Error: {ex.Message}</p>"); bad++; } messages.Add($"<p>{good} donations added. {bad} errors.</p>"); SummaryPlaceHolder.Controls.Add( new LiteralControl(Join(Empty, messages))); SummaryContainer.RemoveCssClass("hidden"); }
//private static void NonFatalError(ICollection<string> messages, long lineNumber, // string message) //{ // messages.Add( // $"<p class=\"error\">Non-fatal error on row {lineNumber}: {message}</p>"); //} private void PostCsv() { var now = DateTime.UtcNow; var messages = new List <string>(); var good = 0; var bad = 0; try { if (Request.Files.Count != 1 || Request.Files[0].ContentLength == 0) { throw new VoteException("Could not find CSV file"); } using (var parser = new TextFieldParser(Request.Files[0].InputStream, Encoding.UTF8)) { parser.TextFieldType = FieldType.Delimited; parser.HasFieldsEnclosedInQuotes = true; parser.SetDelimiters(","); // look for the field names -- they might not be in the first row so find a row // whose first column is "Date" string[] columnNames = null; while (!parser.EndOfData) { var row = parser.ReadFields(); // ReSharper disable once PossibleNullReferenceException if (row.Length > 0 && row[0] == "Date") { columnNames = row; break; } } if (columnNames == null) { throw new VoteException( "Could not find column names row (\"FirstName\" in first column"); } var maxColumnInx = -1; var nameInx = GetColumnIndex(columnNames, "Name", ref maxColumnInx); var address1Inx = GetColumnIndex(columnNames, "Address Line 1", ref maxColumnInx); var address2Inx = GetColumnIndex(columnNames, "Address Line 2/District/Neighborhood", ref maxColumnInx); var cityInx = GetColumnIndex(columnNames, "Town/City", ref maxColumnInx); var stateProvinceInx = GetColumnIndex(columnNames, "State/Province/Region/County/Territory/Prefecture/Republic", ref maxColumnInx); var zipCodeInx = GetColumnIndex(columnNames, "Zip/Postal Code", ref maxColumnInx); var emailInx = GetColumnIndex(columnNames, "From Email Address", ref maxColumnInx); var transactionDateInx = GetColumnIndex(columnNames, "Date", ref maxColumnInx); var totalChangedInx = GetColumnIndex(columnNames, "Gross", ref maxColumnInx); var transactionIdInx = GetColumnIndex(columnNames, "Transaction ID", ref maxColumnInx); var typeInx = GetColumnIndex(columnNames, "Type", ref maxColumnInx); while (!parser.EndOfData) { var row = parser.ReadFields(); if (row[typeInx] != "Donation Payment") { continue; } try { // ReSharper disable once PossibleNullReferenceException if (row.Length <= maxColumnInx) { throw new VoteException( $"Contains only {row.Length} columns, {maxColumnInx + 1} required."); } var email = row[emailInx]; if (IsNullOrWhiteSpace(email)) { throw new VoteException("Email is missing"); } if (!Validation.IsValidEmailAddress(email)) { throw new VoteException($"Invalid Email: {email}"); } // we try to split the single name into first and last var name = row[nameInx]; var nameParts = name.Split(new [] { ' ' }, StringSplitOptions.RemoveEmptyEntries); var firstName = Empty; var lastName = Empty; switch (nameParts.Length) { case 0: break; case 1: lastName = nameParts[0]; break; case 2: firstName = nameParts[0]; lastName = nameParts[1]; break; default: if (Validation.IsValidNameSuffix(nameParts.Last())) { firstName = Join(" ", nameParts.Take(nameParts.Length - 2)); lastName = Join(" ", nameParts.Skip(nameParts.Length - 2)); } else { firstName = Join(" ", nameParts.Take(nameParts.Length - 1)); lastName = nameParts.Last(); } break; } // var firstName = row[firstNameInx]; // var lastName = row[lastNameInx]; // var fullName = firstName + " " + lastName; // if (IsNullOrWhiteSpace(fullName)) // throw new VoteException("FirstName or LastName is missing"); var address = row[address1Inx]; var address2 = row[address2Inx]; if (!IsNullOrWhiteSpace(address) && !IsNullOrWhiteSpace(address2)) { address += ", " + address2; } var city = row[cityInx]; var stateCode = row[stateProvinceInx]; if (!StateCache.IsValidStateCode(stateCode)) { // might be state name stateCode = StateCache.GetStateCode(stateCode).SafeString(); } var zipCode = row[zipCodeInx]; var zipMatch = Regex.Match(zipCode, @"(?<zip5>\d{5})(?:\D?(?<zip4>\d{4}))?"); var zip5 = Empty; var zip4 = Empty; if (zipMatch.Success) { zip5 = zipMatch.Groups["zip5"].Value; zip4 = zipMatch.Groups["zip4"].Value; } var transactionId = row[transactionIdInx].Trim(); if (IsNullOrWhiteSpace(transactionId)) { throw new VoteException( $"Transaction ID is missing: {row[transactionDateInx]}"); } // var phone = row[phoneInx].NormalizePhoneNumber(); if (!DateTime.TryParse(row[transactionDateInx], out var transactionDate)) { throw new VoteException( $"Could not parse TransactionDate: {row[transactionDateInx]}"); } if (!decimal.TryParse(row[totalChangedInx], out var totalCharged)) { throw new VoteException( $"Could not parse TotalCharged: {row[totalChangedInx]}"); } if (totalCharged == 0) { continue; } if (Donations.PayPalTransactionIdExists(transactionId)) { throw new VoteException( "A donation for this PayPal Transaction Id already exists" + $" ({transactionId}, {email}, {transactionDate:G}, {totalCharged:C})"); } Donations.Insert(email, transactionDate, firstName, lastName, name, address, city, stateCode, zip5, zip4, Empty, totalCharged, false, transactionId); // Get the encoding var googleResult = IsNullOrWhiteSpace(stateCode) ? null : GoogleMapsLookup.Lookup(address, city, stateCode, zip5); TigerLookupData tigerResult = null; if (googleResult?.Status == "OK") { tigerResult = TigerLookup.Lookup(googleResult.Latitude, googleResult.Longitude); } var table = Addresses.GetDataByEmail(email); if (table.Count == 0) // Insert { Addresses.Insert(firstName, lastName, address, city, stateCode, zip5, zip4, email, Empty, now, "DONR", false, false, false, DefaultDbDate, Empty, tigerResult?.Congress ?? Empty, tigerResult?.Upper ?? Empty, tigerResult?.Lower ?? Empty, tigerResult?.County ?? Empty, tigerResult?.District ?? Empty, tigerResult?.Place ?? Empty, tigerResult?.Elementary ?? Empty, tigerResult?.Secondary ?? Empty, tigerResult?.Unified ?? Empty, tigerResult?.CityCouncil ?? Empty, tigerResult?.CountySupervisors ?? Empty, tigerResult?.SchoolDistrictDistrict ?? Empty, googleResult?.Latitude ?? 0, googleResult?.Longitude ?? 0, googleResult?.Status == "OK" ? now : DefaultDbDate, 0, DefaultDbDate, true); } else if (googleResult?.Status == "OK") // update all matching Addresses { foreach (var r in table) { if (!IsNullOrWhiteSpace(firstName)) { r.FirstName = firstName; } if (!IsNullOrWhiteSpace(lastName)) { r.LastName = lastName; } //if (!IsNullOrWhiteSpace(phone)) r.Phone = phone; r.IsDonor = true; if (tigerResult != null) { r.Address = address; r.City = city; r.StateCode = stateCode; r.Zip5 = zip5; r.Zip4 = zip4; r.CongressionalDistrict = tigerResult.Congress; r.StateSenateDistrict = tigerResult.Upper; r.StateHouseDistrict = tigerResult.Lower; r.County = tigerResult.County; r.District = tigerResult.District; r.Place = tigerResult.Place; r.Latitude = googleResult.Latitude; r.Longitude = googleResult.Longitude; r.DistrictLookupDate = now; } } Addresses.UpdateTable(table); } messages.Add( $"<p>{totalCharged:C} donation added for {name}<{email}> on {transactionDate.Date.ToShortDateString()}</p>"); good++; } catch (Exception ex) { messages.Add( $"<p class=\"error\">Error on row {parser.LineNumber}: {ex.Message}</p>"); bad++; } } } } catch (Exception ex) { messages.Add($"<p class=\"error\">Error: {ex.Message}</p>"); bad++; } messages.Add($"<p>{good} donations added. {bad} errors.</p>"); SummaryPlaceHolder.Controls.Add( new LiteralControl(Join(Empty, messages))); SummaryContainer.RemoveCssClass("hidden"); }