public void Send(RosterSummary roster) { var(address, port, username, password, templateFilename) = EmailServerDetailsFromEnvironment(); Console.WriteLine($"Using template file {templateFilename}"); var message = new MimeMessage(); message.From.Add(new MailboxAddress("Student IT and eLearning Support", "*****@*****.**")); foreach (var emailAddress in RecipientEmails) { message.To.Add(new MailboxAddress(emailAddress)); } // Take 1 day off the enddate as it's configured to search up to midnight on the last day, which means effectively // the roster is up to the end of the day before. Display like this for clarity message.Subject = $"Shift Summary ({roster.StartDate.ToString("yyyy-MM-dd")} - {roster.EndDate.AddDays(-1).ToString("yyyy-MM-dd")})"; var tableHeader = new List <string>(); DateTime curDate = roster.StartDate; while (curDate < roster.EndDate) { tableHeader.Add(curDate.ToString("dd-MM")); curDate = curDate.AddDays(1); } roster.Employees.Sort((a, b) => a.Name.CompareTo(b.Name)); var model = new { Employees = roster.Employees, Header = tableHeader }; Template.RegisterSafeType(typeof(Employee), new[] { "Name", "TotalHours", "Shifts" }); Template.RegisterFilter(typeof(HoursFilter)); Template.RegisterFilter(typeof(ShiftStyleFilter)); Template template = Template.Parse(File.ReadAllText(Path.Combine("extra", templateFilename))); var bodyText = template.Render(Hash.FromAnonymousObject(model)); message.Body = new TextPart("html") { Text = bodyText }; using (var client = new SmtpClient()) { Console.WriteLine("Sending email"); client.Timeout = 10000; client.Connect(address, port); client.AuthenticationMechanisms.Remove("XOAUTH2"); client.Authenticate(username, password); client.Send(message); client.Disconnect(true); } }
private Employee EmployeeByName(string name, RosterSummary rosterSummary) { Employee employeeWithName = null; foreach (Employee employee in rosterSummary.Employees) { if (employee.Name == name) { employeeWithName = employee; } } if (employeeWithName == null) { employeeWithName = new Employee(name, rosterSummary.Days); rosterSummary.Employees.Add(employeeWithName); } return(employeeWithName); }
public void MakeSummary() { CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture; CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture; Console.WriteLine("Getting roster bounds"); var(periodStart, periodEnd, shouldRun) = GetRosterBounds(); if (!shouldRun) { // Workaround the fact that you cannot schedule a lambda to run every 2 weeks Console.WriteLine("Cancelling summary as it's not the end of a pay period"); return; } Console.WriteLine($"Loading summary for period {periodStart} - {periodEnd}"); RosterSummary rosterSummary = new RosterSummary(periodStart, periodEnd); var service = GcalProvider.MakeService(); var internProvider = new InternProvider(); // Define parameters of request. foreach (var calendarId in _calendars) { var request = service.Events.List(calendarId); request.TimeMin = periodStart; request.TimeMax = periodEnd; request.ShowDeleted = false; request.SingleEvents = true; request.MaxResults = 2500; request.OrderBy = EventsResource.ListRequest.OrderByEnum.StartTime; Events events = request.Execute(); if (events.Items != null) { Console.WriteLine($"Got {events.Items.Count} events from {calendarId}"); foreach (var eventItem in events.Items) { // Location will be a string of either BEE/Baillieu/ERC // It's irrelevant for hours calculation but helpful for logging var startTime = eventItem.Start.DateTime; var endTime = eventItem.End.DateTime; var location = eventItem.Location; if (eventItem.Status == "cancelled") { // Ignore cancelled events since it means the shift was not actully worked Console.WriteLine($"Skipping cancelled event {startTime} - {endTime} @ {location}"); continue; } if (eventItem.Attendees.Count == 0) { // This event is probably a valid shift, but we have no way of knowing // Who owns it. Log it and continue Console.WriteLine($"Skipping event with 0 attendees {startTime} - {endTime} @ {location}"); continue; } if (startTime < rosterSummary.StartDate || endTime > rosterSummary.EndDate) { Console.WriteLine($"Skipping event which is outside of roster timeframe {startTime} - {endTime} @ {location}"); } var internEmail = eventItem.Attendees[0].Email; if (eventItem.Attendees.Count > 1) { // People sometimes add personal and work emails to shifts. This shouldn't // be a problem, but good to log it just in case Console.WriteLine($"Found event with multiple attendees {startTime}-{endTime} @ {location}. Using {internEmail}"); } var internName = internProvider.NameFromEmail(internEmail); var employee = EmployeeByName(internName ?? internEmail, rosterSummary); var hours = (endTime - startTime).Value.TotalHours; DateTime curDate = rosterSummary.StartDate; for (var i = 0; i < rosterSummary.Days; i++) { if (curDate.Date == endTime.Value.Date) { employee.Shifts[i] += hours; break; } curDate = curDate.AddDays(1); } } } else { Console.WriteLine($"Got no events from {calendarId}. Is the selected time period correct? {request.TimeMin}-{request.TimeMax}"); } } var report = new EmailReport(); report.Send(rosterSummary); }