Get iCal Feed Using Web Service and Adjust Event Times

Here’s some example code to fetch a token and then an iCal feed from a 3rd party service.  Unfortunately the times are in UTC and the plugin we are using doesn’t respect the VTIMEZONE attribute, so I have to use regex to individually adjust all event times.

            private readonly static string tokenUrl = "https://domain:8445/token";
private readonly static string calendarUrl = "https://domain:8445/api/Calendar/GetCalendar/c6d32f38-4c95-4e39-ab31-25340f6354a2";
private readonly static string userName = "";
private readonly static string password = "";
private readonly static string notificationEmail = "";
private readonly static string smtpServer = "smtp.colostate.edu";

        protected void Page_Load(object sender, EventArgs e)
        {
            // get token
            var token = GetAccessToken();

            // get calendar data
            var calendarData = GetCalendarData(token);

            // add in time zone adjustment
            calendarData = AddInGlobalTimeZoneInfo(calendarData);

            // adjust individual times - start
            calendarData = AdjustIndividualEventTimes(calendarData, "DTSTART:");

            // adjust individual times - end
            calendarData = AdjustIndividualEventTimes(calendarData, "DTEND:");

            // save updated ical file to server
            File.WriteAllText(Server.MapPath("~/feed/csurec.ics"), calendarData);

            lblResult.Text = ".ics file created!";
        }

        public string GetAccessToken()
        {
            try
            {
                var client = new RestClient(tokenUrl);
                var request = new RestRequest();
                request.Method = Method.Post;
                request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
                request.AddParameter("username", userName);
                request.AddParameter("password", password);
                request.AddParameter("grant_type", "password");
                RestResponse response = client.Execute(request);

                var result = JsonConvert.DeserializeObject<dynamic>(response.Content);
                var token = result.access_token;
                return token;
            }
            catch (Exception e)
            {
                string error = $"Error getting token: {e.ToString()}";

                if (!Request.IsLocal)
                    SendSingleEmail(new MailAddress(notificationEmail), new MailAddress(notificationEmail), "CSU Rec Fusion Feed Get Token Error", error, Encoding.UTF8, false);

                return null;
            }
        }

        public string GetCalendarData(string token)
        {
            try
            {
                var client = new RestClient(calendarUrl);
                var request = new RestRequest();
                request.Method = Method.Get;
                request.AddHeader("Authorization", "Bearer " + token);
                RestResponse response = client.Execute(request);

                return response.Content;
            }
            catch (Exception e)
            {
                string error = $"Error getting token: {e.ToString()}";

                if (!Request.IsLocal)
                    SendSingleEmail(new MailAddress(notificationEmail), new MailAddress(notificationEmail), "CSU Rec Fusion Feed Get Calendar Data Error", error, Encoding.UTF8, false);

                return null;
            }
        }

        public string AdjustIndividualEventTimes(string calendarData, string prefix)
        {
            // find the current hour difference between UTC and now
            var denver = TimeZoneInfo.FindSystemTimeZoneById("Mountain Standard Time");
            var now = DateTimeOffset.UtcNow;
            TimeSpan denverOffset = denver.GetUtcOffset(now);

            // now we have the hour offset, next use regex to match what needs replacing
            var regex = new Regex(@"^(" + prefix + @")\d{8}(T)\d{6}(Z)$");

            string[] lines = calendarData.Split(
                new string[] { Environment.NewLine },
                StringSplitOptions.None
            );

            for (int i = 0; i < lines.Length; i++)
            {
                if (regex.IsMatch(lines[i]))
                {
                    var line = lines[i];
                    var cleanedDate = line.Replace(prefix, "");
                    var newDate = DateTime.ParseExact(cleanedDate, "yyyyMMdd'T'HHmmss'Z'", CultureInfo.InvariantCulture);
                    line = newDate.AddHours(denverOffset.TotalHours).ToString("yyyyMMdd'T'HHmmss'Z'");
                    lines[i] = prefix + line;
                }
            }

            return String.Join(Environment.NewLine, lines);
        }

        public string AddInGlobalTimeZoneInfo(string calendarData)
        {
            var tzInfo = @"PRODID:-//InnoSoft Fusion
BEGIN:VTIMEZONE
TZID:America/Denver
BEGIN:STANDARD
DTSTART:20071104T020000
TZOFFSETFROM:-0600
TZOFFSETTO:-0700
TZNAME:MST
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:20070311T020000
TZOFFSETFROM:-0700
TZOFFSETTO:-0600
TZNAME:MDT
END:DAYLIGHT
END:VTIMEZONE";

            calendarData = calendarData.Replace("PRODID:-//InnoSoft Fusion", tzInfo);

            return calendarData;

        }

        public static bool SendSingleEmail(MailAddress from, MailAddress recipient, string subject, string body, Encoding encoding, bool isHtml)
        {
            bool sentSuccessfully;

            var smtp = new SmtpClient
            {
                Host = smtpServer,
                DeliveryMethod = SmtpDeliveryMethod.Network,
            };
            using (var message = new MailMessage(from, recipient)
            {
                Subject = subject,
                Body = body,
                IsBodyHtml = isHtml,
                SubjectEncoding = encoding,
                BodyEncoding = encoding
            })
            {
                try
                {
                    smtp.Send(message);
                    sentSuccessfully = true;
                }
                catch (Exception e)
                {
                    sentSuccessfully = false;
                }
            }

            return sentSuccessfully;
        }
    }