Ejemplo n.º 1
0
        public static Calendar CreateCourseAppointment(Course course, IIdentity currentUser)
        {
            TimeZoneInfo tzi = course.Department.Institution.TimeZone;
            var currentCal = CreateCal(course);
            // Create the event, and add it to the iCalendar
            //
            Event courseEvt = new Event
            {
                Class = "PRIVATE",
                Created = new CalDateTime(course.CreatedUtc),
                LastModified = new CalDateTime(course.CourseDatesLastModified),
                Sequence = course.EmailSequence,
                Transparency = TransparencyType.Opaque,
                Status = course.Cancelled ? EventStatus.Cancelled : EventStatus.Confirmed,
                Uid = "course" + course.Id.ToString(),
                Priority = 5,
                Location = course.Room.ShortDescription,
                Attendees = course.CourseParticipants.Select(MapCourseParticipantToAttendee).ToList(),
                Summary = course.Department.Abbreviation + " " + course.CourseFormat.CourseType.Abbreviation,
                IsAllDay = false,
                Description = course.Department.Name + " " + course.CourseFormat.CourseType.Description,
                GeographicLocation = GetGeoLocation(course),
                Organizer = GetOrganizer(course),
                //DtStamp = - this is probably being inserted - check
            };
            System.Diagnostics.Debug.WriteLine(courseEvt.Organizer);
            foreach (var cd in course.AllDays().Take(course.CourseFormat.DaysDuration))
            {
                var dayEvt = courseEvt.Copy<Event>();
                dayEvt.Start = new CalDateTime(course.StartLocal, tzi.Id);
                dayEvt.Description += " - " + course.StartLocal.ToString("g");
                dayEvt.Duration = TimeSpan.FromMinutes(cd.DurationMins);
                if (course.CourseFormat.DaysDuration > 1)
                {
                    string dayNo = $" (day {cd.Day})";
                    dayEvt.Summary += dayNo;
                    dayEvt.Description += dayNo;
                }
                currentCal.Events.Add(dayEvt);
            }

            // Create a serialization context and serializer factory.
            // These will be used to build the serializer for our object.

            //set alarm
            Alarm alarm = new Alarm
            {
                Action = AlarmAction.Display,
                Summary = course.Department.Abbreviation + ' ' + course.CourseFormat.CourseType.Abbreviation,
                Trigger = new Trigger(TimeSpan.FromHours(-1))
            };

            // Add the alarm to the event
            courseEvt.Alarms.Add(alarm);

            return currentCal;
        }
Ejemplo n.º 2
0
 public static void AppendFacultyMeetingEvent(Calendar cal, Course course)
 {
     if (!course.FacultyMeetingUtc.HasValue) { return; }
     //CalendarMethods.Request is only valid for single event per calendar
     cal.Method = course.Cancelled ? CalendarMethods.Cancel : CalendarMethods.Publish;
     var courseEvent = cal.Events.First();
     var facultyMeet = CreateFacultyMeetingEvent(course);
     cal.Events.Add(facultyMeet);
 }
Ejemplo n.º 3
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="course"></param>
        /// <param name="user"></param>
        /// <returns>a lookup true = successfully emailed, false = email failed</returns>
        public static async Task<ILookup<bool, CourseParticipant>> SendEmail(Course course, IPrincipal user)
        {
            using (var cal = Appointment.CreateCourseAppointment(course, user.Identity))
            {
                using (var appt = new AppointmentStream(cal))
                {
                    var map = ((Expression<Func<CourseParticipant, CourseParticipantDto>>)new CourseParticipantMaps().MapToDto).Compile();
                    var faculty = course.CourseParticipants.Where(cp => !map(cp).IsEmailed)
                        .ToLookup(cp => cp.IsFaculty);

                    IEnumerable<Attachment> attachments = new Attachment[0];
                    using (var client = new SmtpClient())
                    {
                        var mailMessages = new List<ParticipantMail>();
                        var sendMail = new Action<CourseParticipant>(cp =>
                        {
                            var mail = new MailMessage();
                            mail.To.AddParticipants(cp.Participant);
                            var confirmEmail = new CourseInvite { CourseParticipant = cp };
                            mail.CreateHtmlBody(confirmEmail);
                            appt.AddAppointmentsTo(mail);
                            foreach (var a in attachments)
                            {
                                a.ContentStream.Position = 0;
                                mail.Attachments.Add(a);
                            }
                            mailMessages.Add(new ParticipantMail { Message = mail, SendTask = client.SendMailAsync(mail), CourseParticipant = cp });
                        });

                        foreach (var cp in faculty[false])
                        {
                            sendMail(cp);
                        }
                        if (faculty[true].Any())
                        {
                            if (course.FacultyMeetingUtc.HasValue)
                            {
                                using (var fm = Appointment.CreateFacultyCalendar(course))
                                {
                                    appt.Add(fm);
                                }
                            }
                            attachments = GetFilePaths(course).Select(fp => new Attachment(fp.Value, System.Net.Mime.MediaTypeNames.Application.Zip) { Name = fp.Key })
                                .Concat(new[] { new Attachment(CreateDocxTimetable.CreateTimetableDocx(course, WebApiConfig.DefaultTimetableTemplatePath), OpenXmlDocxExtensions.DocxMimeType) { Name = CreateDocxTimetable.TimetableName(course)} });
                            foreach (var cp in faculty[true])
                            {
                                sendMail(cp);
                            }
                        }
                        await Task.WhenAll(mailMessages.Select(mm => mm.SendTask));
                        mailMessages.ForEach(mm => mm.Message.Dispose());
                        return mailMessages.ToLookup(k => k.SendTask.Status == TaskStatus.RanToCompletion, v => v.CourseParticipant);
                    }
                }
            }
        }
Ejemplo n.º 4
0
 private static IEnumerable<KeyValuePair<string, string>> GetFilePaths(Course course)
 {
     return (from s in course.CourseSlotActivities
             let sr = s.Scenario.ScenarioResources.FirstOrDefault(ssr => ssr.FileName != null)
             where sr != null
             select new KeyValuePair<string, string>(s.Scenario.BriefDescription, sr.GetServerPath()))
            .Concat(from ctr in course.CourseSlotActivities
                    let atr = ctr.Activity
                    where atr.FileName != null
                    select new KeyValuePair<string, string>(atr.Description, atr.GetServerPath()));
 }
Ejemplo n.º 5
0
        static IList<TimetableRow> GetTimeTableRows(Course course)
        {
            var start = course.StartLocal;
            int scenarioCount = 0;
            var csps = course.CourseSlotPresenters.ToLookup(c=>c.CourseSlotId);
            //var csfrs = course.CourseScenarioFacultyRoles.ToLookup(c => c.CourseSlotId);
            var csas = course.CourseSlotActivities.ToDictionary(c => c.CourseSlotId);
            var emptyStringArray = new string[0];

            var returnVar = course.CourseFormat.CourseSlots.Where(cs=>cs.IsActive)
                .OrderBy(cs=>cs.Order).Select(cs=> {
                    var ttr = new TimetableRow
                    {
                        LocalStart = start,
                    };
                    CourseSlotActivity activity;
                    csas.TryGetValue(cs.Id, out activity);
                    if (cs.ActivityId.HasValue)
                    {
                        ttr.IsScenario = false;
                        ttr.SlotName = cs.Activity.Name;
                        ttr.SlotActivity = activity?.Activity?.Description;
                        ttr.Faculty = csps[cs.Id]?.Select(csp => csp.Participant.FullName)
                            ?? emptyStringArray;
                    }
                    else
                    {
                        ttr.IsScenario = false;
                        ttr.SlotName = "Scenario " + (++scenarioCount).ToString();
                        ttr.SlotActivity = activity?.Scenario?.BriefDescription;
                        ttr.Faculty = emptyStringArray;//csfrs[cs.Id]?.Select(csfr => csfr.Participant.FullName)
                        //    ?? emptyStringArray;
                    }
                    start += TimeSpan.FromMinutes(cs.MinutesDuration);
                    return ttr;
            }).ToList();
            returnVar.Add(new TimetableRow { LocalStart = start, SlotName = "Finish", Faculty=new string[0]});
            return returnVar;
        }
Ejemplo n.º 6
0
 static void UpdateMetadata(WordprocessingDocument doc, Course course)
 {
     //doc.AddCoreProperty();
     throw new NotImplementedException();
 }
Ejemplo n.º 7
0
 public static string TimetableName(Course course)
 {
     return CourseNameWithoutExt(course) + "Timetable.docx";
 }
Ejemplo n.º 8
0
 internal static string CourseNameWithoutExt(Course course)
 {
     string dateString = course.StartLocal.ToString("d", course.Department.Institution.Culture.CultureInfo).Replace('/', '-');
     return $"{course.Department.Abbreviation} {course.CourseFormat.CourseType.Abbreviation} - {dateString}";
 }
Ejemplo n.º 9
0
        private static void AddScenarios(MainDocumentPart doc, Course course)
        {
            var firstParaWithSectionBreak = doc.RootElement.Descendants<Paragraph>()
                .First(p => p.Descendants<SectionProperties>().Any());

            var allScenarioEls = firstParaWithSectionBreak.Parent.ChildElements
                .SkipWhile(c => c != firstParaWithSectionBreak)
                .TakeWhile(c => c.GetType() != typeof(SectionProperties))
                .ToList();

            var csas = course.CourseSlotActivities
                .Where(ca => ca.ScenarioId != null)
                .ToDictionary(ca => ca.CourseSlotId);

            var manikins = course.CourseSlotManikins
                .ToLookup(m => m.CourseSlotId);

            var roles = course.CourseScenarioFacultyRoles
                .ToLookup(k => k.CourseSlotId);
            int i = 0;
            var csss = (from cs in course.CourseFormat.CourseSlots.OrderBy(c=>c.Order)
                        let scenarioNo = ++i
                        where cs.IsActive && (csas.ContainsKey(cs.Id) || manikins[cs.Id].Any() || roles[cs.Id].Any())
                        select new { cs, scenarioNo}).ToList();

            var roleFacultyEls = new List<ScenarioRoleEl>();
            allScenarioEls.CloneElements(csss, (mergeFieldName, css, elements) =>
            {
                switch (mergeFieldName)
                {
                    case "ScenarioRole":
                    case "ScenarioRoleFaculty":
                        if (roleFacultyEls.Count == 0 || roleFacultyEls[roleFacultyEls.Count - 1].SlotId != css.cs.Id)
                        {
                            roleFacultyEls.Add(new ScenarioRoleEl { Row = elements.First().FindFirstAncestor<TableRow>(), SlotId = css.cs.Id });
                        }
                        return null;
                    case "ScenarioNo":
                        return "Scenario " + css.scenarioNo.ToString();
                    case "ScenarioName":
                    case "ScenarioBriefDescription":
                        CourseSlotActivity csab;
                        if (csas.TryGetValue(css.cs.Id, out csab))
                        {
                            return csab.Scenario?.BriefDescription ?? string.Empty;
                        }
                        return string.Empty;
                    case "ScenarioFullDescription":
                        CourseSlotActivity csaf;
                        if (csas.TryGetValue(css.cs.Id, out csaf))
                        {
                            return csaf.Scenario?.FullDescription ?? string.Empty;
                        }
                        return string.Empty;
                    case "Manikins":
                        return string.Join("\t",manikins[css.cs.Id].Select(m=>m.Manikin.Description));
                    default:
                        return $"[Value Not Found - \'{ mergeFieldName }\']";
                }
            });

            foreach (var sre in roleFacultyEls)
            {
                var scenarioRoles = roles[sre.SlotId].OrderBy(csfr => csfr.FacultyScenarioRole.Order)
                    .ToLookup(csfr => csfr.FacultyScenarioRole);


                if (scenarioRoles.Count == 0)
                {
                    sre.Row.FindFirstAncestor<Table>().Remove();
                }
                else
                {
                    sre.Row.CloneElement(scenarioRoles, (mergeFieldName, role) =>
                    {
                        switch (mergeFieldName)
                        {
                            case "ScenarioRole":
                                return role.Key.Description;
                            case "ScenarioRoleFaculty":
                                return string.Join("\n", role.Select(r => r.Participant.FullName));
                            default:
                                return $"[Value Not Found - \'{ mergeFieldName }\']";
                        }
                    });
                }
            }
        }
Ejemplo n.º 10
0
 public static IEnumerable<KeyValuePair<Guid, string>> GetBookedManikins(MedSimDbContext context, Course course)
 {
     var refStart = course.StartUtc;
     var refFinish = course.FinishCourseUtc();
     return (from csm in context.CourseSlotManikins
             let c = csm.Course
             let lastDay = c.CourseDays.FirstOrDefault(cd => cd.Day == c.CourseFormat.DaysDuration)
             let cFinish = lastDay == null
                 ? DbFunctions.AddMinutes(c.StartUtc, c.DurationMins)
                 : DbFunctions.AddMinutes(lastDay.StartUtc, lastDay.DurationMins)
             where c.Id != course.Id && c.StartUtc < refFinish && refStart < cFinish
             select new { csm.ManikinId, c.CourseFormat.Description, c.Department.Abbreviation })
             .ToKeyValuePairList(a => a.ManikinId, a => a.Abbreviation + '-' + a.Description);
 }
Ejemplo n.º 11
0
 public static string CertificateName(Course course) {
     return CreateDocxTimetable.CourseNameWithoutExt(course) + " Certificates.pptx";
 }
Ejemplo n.º 12
0
 private static Calendar CreateCal(Course course)
 {
     var currentCal = new Calendar
     {
         Method = course.Cancelled ? CalendarMethods.Cancel : CalendarMethods.Request,
     };
     var timezone = VTimeZone.FromSystemTimeZone(course.Department.Institution.TimeZone);
     currentCal.AddTimeZone(timezone);
     return currentCal;
 }
Ejemplo n.º 13
0
 public static Calendar CreateFacultyCalendar(Course course)
 {
     var currentCal = CreateCal(course);
     var facultyMeet = CreateFacultyMeetingEvent(course);
     currentCal.Events.Add(facultyMeet);
     return currentCal;
 }
Ejemplo n.º 14
0
 private static Organizer GetOrganizer(Course course)
 {
     const string SimPlannerInfo = mailto + "*****@*****.**"; //ToDo read from web.config mail settings
     return new Organizer() { Value = new Uri(SimPlannerInfo), CommonName = "sim-planner.com" };
 }
Ejemplo n.º 15
0
 private static GeographicLocation GetGeoLocation(Course course)
 {
     if (course.Department.Institution.Latitude.HasValue && course.Department.Institution.Longitude.HasValue)
     {
         return new GeographicLocation(course.Department.Institution.Latitude.Value, course.Department.Institution.Longitude.Value);
     }
     return null;
 }
Ejemplo n.º 16
0
        public static MemoryStream CreatePptxCertificates(Course course, string sourceFile)
        {
            const string fullNameTxt = "FullName";
            byte[] byteArray = File.ReadAllBytes(sourceFile);
            MemoryStream stream = new MemoryStream();
            stream.Write(byteArray, 0, byteArray.Length);
            using (PresentationDocument document = PresentationDocument.Open(stream, true))
            {
                var master1LayoutPart = document.PresentationPart.SlideMasterParts.First()
                    .SlideLayoutParts.First();

                #region MasterSlide
                var formattedDate = course.StartLocal.ToString("dddd, MMMM dd, yyyy", course.Department.Institution.Culture.CultureInfo);

                var organisers = course.CourseParticipants.Where(cp => cp.IsOrganiser).ToList();
                var organiserCells = new List<OrganiserXml>(organisers.Count);
                organiserCells.Add(new OrganiserXml());
                Draw.Text fullName = null;
                foreach (var t in master1LayoutPart.SlideLayout.Descendants<Draw.Text>())
                {
                    t.Text = t.Text
                    .Replace("CourseTypeDescription", course.CourseFormat.CourseType.Description)
                    .Replace("CourseTypeAbbreviation", course.CourseFormat.CourseType.Abbreviation)
                    .Replace("CourseFormatDescription", course.CourseFormat.Description)
                    .Replace("DepartmentName", course.Department.Name)
                    .Replace("DepartmentAbbreviation", course.Department.Abbreviation)
                    .Replace("InstitutionName", course.Department.Institution.Name)
                    .Replace("InstitutionAbbreviation", course.Department.Institution.Abbreviation)
                    .Replace("StartDate", formattedDate);

                    if (t.Text.Contains(organiserName))
                    {
                        organiserCells[0].NameCell = t.FindFirstAncestor<Draw.TableCell>();
                    }
                    if (t.Text.Contains(organiserRole))
                    {
                        organiserCells[0].RoleCell = t.FindFirstAncestor<Draw.TableCell>();
                    }
                    if (t.Text.Contains(fullNameTxt)) { fullName = t; }
                }
                if (organisers.Count > 0)
                {
                    var parentTable = (organiserCells[0].NameCell ?? organiserCells[0].RoleCell).FindFirstAncestor<Draw.Table>();
                    var grid = parentTable.ChildElements<Draw.TableGrid>().First();
                    var gridCols = grid.ChildElements<Draw.GridColumn>().ToList();

                    var tableWidth = gridCols.Sum(gc => gc.Width);
                    var requiredColWidths = (tableWidth / organisers.Count);

                    //assuming for now table with 1 col
                    for (int i = 1; i < organisers.Count; i++)
                    {
                        grid.AppendChild(new Draw.GridColumn() { Width = requiredColWidths });
                        organiserCells.Add(organiserCells[0].Clone());
                    }

                    for (int i = 0; i < organisers.Count; i++)
                    {
                        organiserCells[i].SetText(organisers[i].Participant.FullName, organisers[i].Participant.ProfessionalRole.Description);
                    }
                };
                #endregion //MasterSlide
                #region certificates
                var participants = (from cp in course.CourseParticipants
                                    where !cp.IsFaculty
                                    orderby cp.Participant.FullName
                                    select cp.Participant.FullName).ToList();

                //find equivalent id in first slide
                document.PresentationPart.DeleteParts(document.PresentationPart.SlideParts);
                SlideIdList slideIdList = document.PresentationPart.Presentation.SlideIdList;
                foreach (var c in slideIdList.ChildElements)
                {
                    c.Remove();
                }
                document.PresentationPart.Presentation.Save();

                foreach (var part in participants)
                {
                    IEnumerable<Shape> placeholderShapes;
                    AppendNewSlide(document.PresentationPart, master1LayoutPart, out placeholderShapes);

                    foreach (var r in (from phs in placeholderShapes
                                         from dr in phs.Descendants<Draw.Run>()
                                         where dr.Text.Text.IndexOf(fullNameTxt, StringComparison.OrdinalIgnoreCase) > -1
                                         select dr))
                    {
                        //should probably be using innerText and xml powertools regex replace
                        r.Text.Text = r.Text.Text.Replace(fullNameTxt, part);
                    }
                }

                document.PresentationPart.Presentation.Save();

                //find equivalent id in 1st slide

                #endregion //certificates


            }
            return stream;
        }
Ejemplo n.º 17
0
        public static MemoryStream CreateTimetableDocx(Course course, string sourceFile)
        {
            byte[] byteArray = File.ReadAllBytes(sourceFile);
            MemoryStream stream = new MemoryStream();
            stream.Write(byteArray, 0, byteArray.Length);
            using (WordprocessingDocument document = WordprocessingDocument.Open(stream, true))
            {
                IFormatProvider prov = course.Department.Institution.Culture.CultureInfo;

                // If your sourceFile is a different type (e.g., .DOTX), you will need to change the target type like so:
                document.ChangeDocumentType(WordprocessingDocumentType.Document);

                // Get the MainPart of the document
                MainDocumentPart mainPart = document.MainDocumentPart;

                var mergeFields = mainPart.HeaderParts.Cast<OpenXmlPart>()
                    .Concat(mainPart.FooterParts.Cast<OpenXmlPart>())
                    .Concat(new OpenXmlPart[] { mainPart })
                    .Select(x => x.RootElement)
                    .GetMergeFieldDict();

                var mergeClassDict = Enum.GetValues(typeof(MergeClassification))
                    .Cast<MergeClassification>()
                    .ToDictionary(k => k.ToString());
                var names = mergeClassDict.Keys.OrderByDescending(k => k).ToList(); //descending so that longer (more precise) names come first

                var defaultType = MergeClassification.General.ToString();
                names.Remove(defaultType);

                var classifiedMergeFields = mergeFields
                    .ToLookup(fc => mergeClassDict[names.FirstOrDefault(n => fc.Key.StartsWith(n)) ?? defaultType]);

                var faculty = course.CourseParticipants.ToLookup(cp => cp.IsFaculty);

                foreach (var mf in classifiedMergeFields[MergeClassification.General])
                {
                    string replaceVal;
                    switch (mf.Key.Replace(".",string.Empty).Replace(" ", string.Empty))
                    {
                        case "CourseFormatDescription":
                            replaceVal = course.CourseFormat.Description ;
                            break;
                        case "CourseStart":
                            replaceVal = course.StartLocal.ToString("D", prov) ;
                            break;
                        case "CourseTypeAbbreviation":
                            replaceVal = course.CourseFormat.CourseType.Abbreviation ;
                            break;
                        case "CourseTypeDescription":
                            replaceVal = course.CourseFormat.CourseType.Description ;
                            break;
                        case "Department":
                        case "DepartmentAbbreviation":
                            replaceVal = course.Department.Abbreviation ;
                            break;
                        case "DepartmentName":
                            replaceVal = course.Department.Name ;
                            break;
                        case "Faculty":
                            replaceVal = string.Join("\t",faculty[true].Select(cp => cp.Participant.FullName));
                            break;
                        case "Institution":
                        case "InstitutionAbbreviation":
                            replaceVal = course.Department.Institution.Abbreviation ;
                            break;
                        case "InstitutionName":
                            replaceVal = course.Department.Institution.Name ;
                            break;
                        case "Participants":
                            replaceVal = string.Join("\t",faculty[false].Select(cp => cp.Participant.FullName));
                            break;
                        default:
                            replaceVal = $"[Value Not Found - \'{ mf.Key }\']" ;
                            break;
                    }
                    foreach (var m in mf)
                    {
                        m.InsertMergeFieldText(replaceVal);
                    }
                }

                //the first first() will be any of the elements starting with the name slot
                //the second first is assuming each slot, eg slotStart only occurs once in the doc
                //could at a later date come up with some fancy ancestors() to find matching subgroup
                TableRow slotRow = classifiedMergeFields[MergeClassification.Slot].First().First().FindFirstAncestor<TableRow>();
                var ttrs = GetTimeTableRows(course);

                slotRow.CloneElement(ttrs, (mergeFieldName, ttr) =>
                {
                    switch (mergeFieldName)
                    {
                        case "SlotStart":
                            return ttr.LocalStart.ToString("t", prov);
                        case "SlotActivity":
                            return ttr.SlotActivity ?? string.Empty;
                        case "SlotName":
                            return ttr.SlotName;
                        case "SlotFaculty":
                            return string.Join("\n", ttr.Faculty);
                        default:
                            return $"[Value Not Found - \'{ mergeFieldName }\']";
                    }
                });

                AddScenarios(mainPart, course);
                return stream; 
            }
        }
Ejemplo n.º 18
0
        public static Event CreateFacultyMeetingEvent(Course course)
        {
            Event meeting = new Event
            {
                Class = "PRIVATE",
                Created = new CalDateTime(course.CreatedUtc),
                LastModified = new CalDateTime(course.FacultyMeetingDatesLastModified),
                Sequence = course.EmailSequence,
                Uid = "planning" + course.Id.ToString(),
                Priority = 5,
                Organizer = GetOrganizer(course),
                Transparency = TransparencyType.Opaque,
                Status = course.Cancelled ? EventStatus.Cancelled : EventStatus.Confirmed,
                Description = "planning meeting for " + course.Department.Name + " " + course.CourseFormat.CourseType.Description + " - " + course.StartLocal.ToString("g"),
                Summary = course.Department.Abbreviation + " " + course.CourseFormat.CourseType.Abbreviation + " planning meeting for " + course.StartLocal.ToString("d"),
                Attendees = course.CourseParticipants.Where(cp => cp.IsFaculty).Select(MapCourseParticipantToAttendee).ToList(),
                Start = new CalDateTime(course.FacultyMeetingLocal.Value, course.Department.Institution.StandardTimeZone),
                GeographicLocation = GetGeoLocation(course)
            };

            // Set information about the event
            if (course.FacultyMeetingDuration.HasValue)
                meeting.Duration = TimeSpan.FromMinutes(course.FacultyMeetingDuration.Value);
            //evt.Name = course.Department.Abbreviation + " " + course.CourseFormat.CourseType.Abbreviation;
            //evt.Description = course.Department.Name + " " + course.CourseFormat.CourseType.Description;
            if (course.FacultyMeetingRoom != null)
                meeting.Location = course.FacultyMeetingRoom.ShortDescription;

            Alarm alarm = new Alarm
            {
                Action = AlarmAction.Display,
                Summary = meeting.Summary,
                Trigger = new Trigger(TimeSpan.FromHours(-1))
            };

            // Add the alarm to the event
            meeting.Alarms.Add(alarm);

            return meeting;
        }