Пример #1
0
        public static void Main(string[] args)
        {
            string file = "testdata\\Probenplan Orchester St. Pankratius Sommer 2019.ics";

            using (var stream = File.Open(file, FileMode.Open))
            {
                var serializer = new CalendarSerializer();
                var parsedData = serializer.Deserialize(stream);
            }
        }
Пример #2
0
        /// <summary>
        /// Creates the iCalendar object and populates it with events
        /// </summary>
        /// <param name="calendarProps">The calendar props.</param>
        /// <returns></returns>
        private Calendar CreateICalendar(CalendarProps calendarProps)
        {
            // Get a list of Rock Calendar Events filtered by calendarProps
            List <EventItem> eventItems = GetEventItems(calendarProps);

            // Create the iCalendar.
            // Allow ICal to create the VTimeZone object from the local time zone to ensure that we get the correct name and daylight saving offset.
            var icalendar = new Calendar();

            var vtz = VTimeZone.FromLocalTimeZone();

            icalendar.AddTimeZone(vtz);

            var timeZoneId = vtz.TzId;

            // Create each of the events for the calendar(s)
            foreach (EventItem eventItem in eventItems)
            {
                foreach (EventItemOccurrence occurrence in eventItem.EventItemOccurrences)
                {
                    if (occurrence.Schedule == null)
                    {
                        continue;
                    }

                    var serializer = new CalendarSerializer();
                    var ical       = (CalendarCollection)serializer.Deserialize(occurrence.Schedule.iCalendarContent.ToStreamReader());

                    foreach (var icalEvent in ical[0].Events)
                    {
                        // We get all of the schedule info from Schedule.iCalendarContent
                        var ievent = icalEvent.Copy <Ical.Net.Event>();

                        ievent.Summary  = !string.IsNullOrEmpty(eventItem.Name) ? eventItem.Name : string.Empty;
                        ievent.Location = !string.IsNullOrEmpty(occurrence.Location) ? occurrence.Location : string.Empty;

                        // Create the list of exceptions.
                        // Exceptions must meet RFC 5545 iCalendar specifications to be correctly processed by third-party calendar applications
                        // such as Microsoft Outlook and Google Calendar. Specifically, an exception must have exactly the same start time
                        // and time zone as the template event, and the time zone must be expressed as an IANA name.
                        // The most recent version of iCal.Net (v2.3.5) that supports .NET framework v4.5.2 has some inconsistencies in the
                        // iCalendar serialization process, so we need to force the Start, End and Exception dates to render in exactly the same format.
                        ievent.Start = new CalDateTime(icalEvent.Start.Value, timeZoneId);
                        ievent.Start.IsUniversalTime = false;

                        ievent.End = new CalDateTime(icalEvent.End.Value, timeZoneId);
                        ievent.End.IsUniversalTime = false;

                        var eventStartTime = new TimeSpan(ievent.DtStart.Hour, ievent.DtStart.Minute, ievent.DtStart.Second);

                        var newExceptionDatesList = new List <Ical.Net.Interfaces.DataTypes.IPeriodList>();

                        foreach (var exceptionDateList in ievent.ExceptionDates)
                        {
                            var newDateList = new PeriodList()
                            {
                                TzId = timeZoneId
                            };

                            foreach (var exceptionDate in exceptionDateList)
                            {
                                var newDateTime = exceptionDate.StartTime.HasTime ? exceptionDate.StartTime.Value : exceptionDate.StartTime.Value.Add(eventStartTime);

                                newDateTime = new DateTime(newDateTime.Year, newDateTime.Month, newDateTime.Day, newDateTime.Hour, newDateTime.Minute, newDateTime.Second, newDateTime.Millisecond, DateTimeKind.Local);

                                var newDate = new CalDateTime(newDateTime);
                                newDate.IsUniversalTime = false;

                                newDateList.Add(newDate);
                            }

                            newExceptionDatesList.Add(newDateList);
                        }

                        ievent.ExceptionDates = newExceptionDatesList;

                        // Rock has more descriptions than iCal so lets concatenate them
                        string description = CreateEventDescription(eventItem, occurrence);

                        // Don't set the description prop for outlook to force it to use the X-ALT-DESC property which can have markup.
                        if (interactionDeviceType != "Outlook")
                        {
                            ievent.Description = description.ConvertBrToCrLf()
                                                 .Replace("</P>", "")
                                                 .Replace("</p>", "")
                                                 .Replace("<P>", Environment.NewLine)
                                                 .Replace("<p>", Environment.NewLine)
                                                 .Replace("&nbsp;", " ")
                                                 .SanitizeHtml();
                        }

                        // HTML version of the description for outlook
                        ievent.AddProperty("X-ALT-DESC;FMTTYPE=text/html", "<html>" + description + "</html>");

                        // classification: "PUBLIC", "PRIVATE", "CONFIDENTIAL"
                        ievent.Class = "PUBLIC";

                        if (!string.IsNullOrEmpty(eventItem.DetailsUrl))
                        {
                            Uri result;
                            if (Uri.TryCreate(eventItem.DetailsUrl, UriKind.Absolute, out result))
                            {
                                ievent.Url = result;
                            }
                            else if (Uri.TryCreate("http://" + eventItem.DetailsUrl, UriKind.Absolute, out result))
                            {
                                ievent.Url = result;
                            }
                        }

                        // add contact info if it exists
                        if (occurrence.ContactPersonAlias != null)
                        {
                            ievent.Organizer            = new Organizer(string.Format("MAILTO:{0}", occurrence.ContactPersonAlias.Person.Email));
                            ievent.Organizer.CommonName = occurrence.ContactPersonAlias.Person.FullName;

                            // Outlook doesn't seems to use Contacts or Comments
                            string contactName  = !string.IsNullOrEmpty(occurrence.ContactPersonAlias.Person.FullName) ? "Name: " + occurrence.ContactPersonAlias.Person.FullName : string.Empty;
                            string contactEmail = !string.IsNullOrEmpty(occurrence.ContactEmail) ? ", Email: " + occurrence.ContactEmail : string.Empty;
                            string contactPhone = !string.IsNullOrEmpty(occurrence.ContactPhone) ? ", Phone: " + occurrence.ContactPhone : string.Empty;
                            string contactInfo  = contactName + contactEmail + contactPhone;

                            ievent.Contacts.Add(contactInfo);
                            ievent.Comments.Add(contactInfo);
                        }

                        // TODO: categories - comma delimited list of whatever, might use audience
                        foreach (var a in eventItem.EventItemAudiences)
                        {
                            ievent.Categories.Add(a.DefinedValue.Value);
                        }

                        //// No attachments for now.
                        ////if ( eventItem.PhotoId != null )
                        ////{
                        ////    // The DDay Attachment obj doesn't allow you to name the attachment. Nice huh? So just add prop manually...
                        ////    ievent.AddProperty( "ATTACH;VALUE=BINARY;ENCODING=BASE64;X-FILENAME=\"" + eventItem.Photo.FileName + "\"", Convert.ToBase64String( eventItem.Photo.ContentStream.ReadBytesToEnd().ToArray() ) );
                        ////}

                        icalendar.Events.Add(ievent);
                    }
                }
            }

            return(icalendar);
        }
Пример #3
0
        /// <summary>
        /// Creates the iCalendar object and populates it with events
        /// </summary>
        /// <param name="calendarProps">The calendar props.</param>
        /// <returns></returns>
        private Calendar CreateICalendar(CalendarProps calendarProps, string interactionDeviceType)
        {
            // Get a list of confirmed attendances filtered by calendarProps
            List <Attendance> attendances = GetAttendances(calendarProps);

            // Create the iCalendar
            var icalendar = new Calendar();

            icalendar.AddTimeZone(TimeZoneInfo.Local);
            TimeSpan duration          = TimeSpan.MinValue;
            int      currentScheduleId = -1;

            // Create each of the attendances
            foreach (var attendance in attendances)
            {
                using (var rockContext = new RockContext())
                {
                    var attendanceOccurrenceService = new AttendanceOccurrenceService(rockContext);

                    var schedule = attendanceOccurrenceService
                                   .Queryable()
                                   .AsNoTracking()
                                   .Where(a => a.Id == attendance.OccurrenceId)
                                   .Select(a => a.Schedule)
                                   .FirstOrDefault();

                    string scheduleName = schedule.Name;

                    // TODO: Construct a description that includes the group leader contact info and the URL to the schedule toolbox.
                    string description = schedule.Description;

                    string locationName = attendanceOccurrenceService
                                          .Queryable()
                                          .AsNoTracking()
                                          .Where(a => a.Id == attendance.OccurrenceId)
                                          .Select(a => a.Location.Name)
                                          .FirstOrDefault() ?? string.Empty;

                    if (schedule.Id != currentScheduleId)
                    {
                        // We have to get the duration from Schedule.iCal for this attendance.
                        // Attendances are ordered by scheduleId so this only happens once for each unique schedule.
                        var serializer = new CalendarSerializer();
                        var ical       = ( CalendarCollection )serializer.Deserialize(schedule.iCalendarContent.ToStreamReader());
                        duration          = ical[0].Events[0].Duration;
                        currentScheduleId = schedule.Id;
                    }

                    var iCalEvent = new Event();
                    iCalEvent.Summary  = scheduleName;
                    iCalEvent.Location = locationName;
                    iCalEvent.DtStart  = new CalDateTime(attendance.StartDateTime, icalendar.TimeZones[0].TzId);
                    iCalEvent.Duration = duration;

                    // Don't set the description prop for outlook to force it to use the X-ALT-DESC property which can have markup.
                    if (interactionDeviceType != "Outlook")
                    {
                        iCalEvent.Description = description.ConvertBrToCrLf().SanitizeHtml();
                    }

                    // HTML version of the description for outlook
                    iCalEvent.AddProperty("X-ALT-DESC;FMTTYPE=text/html", "<html>" + description + "</html>");

                    // classification: "PUBLIC", "PRIVATE", "CONFIDENTIAL"
                    iCalEvent.Class = "PUBLIC";

                    //Add contact info for the group leader
                    int groupId = attendanceOccurrenceService
                                  .Queryable()
                                  .AsNoTracking()
                                  .Where(a => a.Id == attendance.OccurrenceId)
                                  .Select(a => a.GroupId)
                                  .FirstOrDefault() ?? -1;

                    Person groupLeader = new GroupMemberService(rockContext).GetLeaders(groupId).AsNoTracking().Select(m => m.Person).FirstOrDefault() ?? null;

                    if (groupLeader != null)
                    {
                        iCalEvent.Organizer            = new Organizer(string.Format("MAILTO:{0}", groupLeader.Email));
                        iCalEvent.Organizer.CommonName = groupLeader.FullName;

                        // Outlook doesn't seem to use Contacts or Comments
                        string contactName  = !string.IsNullOrEmpty(groupLeader.FullName) ? "Name: " + groupLeader.FullName : string.Empty;
                        string contactEmail = !string.IsNullOrEmpty(groupLeader.Email) ? ", Email: " + groupLeader.Email : string.Empty;
                        string contactInfo  = contactName + contactEmail;

                        iCalEvent.Contacts.Add(contactInfo);
                        iCalEvent.Comments.Add(contactInfo);
                    }

                    icalendar.Events.Add(iCalEvent);
                }
            }

            return(icalendar);
        }
Пример #4
0
 private void Load()
 {
     lock (_fileLock)
     {
         _calendars.Clear();
         var serializer = new CalendarSerializer(new SerializationContext());
         using (var file = ZipFile.OpenRead(Path))
         {
             foreach (var c in file.Entries)
             {
                 if (!c.Name.EndsWith(".ics"))
                 {
                     continue;
                 }
                 using (var f = c.Open())
                 {
                     AddOrUpdate(c.Name.Substring(0, c.Name.Length - 4), (Calendar)serializer.Deserialize(f, CalendarEncoding));
                 }
             }
         }
         _lastSaved = DateTime.Now;
         Saved      = true;
     }
 }