using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Net; using System.Web; using System.Web.Mvc; using CPE.App.Web.Code; using CPE.App.Web.Connect; using CPE.App.Web.Helpers; using CPE.App.Web.Models; namespace CPE.App.Web.Controllers { public class RebroadcastController : BaseController { [HttpGet] public ActionResult RebroadcastSchedule(int meetingSessionKey) { var meetingSession = Database.MeetingSessions.Single(ms => ms.MeetingSessionKey == meetingSessionKey); return View(meetingSession); } [HttpGet] public ActionResult RebroadcastSessions(int meetingSessionKey) { var meetingScoId = Database.MeetingSessions.Single(ms => ms.MeetingSessionKey == meetingSessionKey) .SCO_ID; var recordingSessions = Database.RecordingSessions.Where(rs => rs.MeetingSCO_ID == meetingScoId) .OrderByDescending(rs => rs.StartTime) .ToList(); return PartialView(recordingSessions); } [HttpGet] public ActionResult RebroadcastPauses(int recordingKey) { var recording = Database.RecordingSessions.Single(r => r.RecordingKey == recordingKey); var meeting = Database.MeetingSessions.Single(ms => ms.MeetingSessionKey == recording.MeetingSessionKey); var recordingPauses = new RecordingPauses { Session = meeting, SessionPauses = meeting.MeetingSessionPauses.ToList() }; return View(recordingPauses); } [HttpPost] public JsonResult DeletePause(int pauseKey) { var result = false; try { var pause = Database.MeetingSessionPauses.Single(p => p.MesstingSessionPauseKey == pauseKey); Database.MeetingSessionPauses.DeleteOnSubmit(pause); Database.SubmitChanges(); result = true; } catch (Exception ex) { result = false; } return Json(result); } [HttpPost] public JsonResult UpdatePauses(MeetingSessionPause[] pauses) { var result = false; try { foreach (var meetingSessionPause in pauses) { var dbPause = Database.MeetingSessionPauses.Single( msp => msp.MesstingSessionPauseKey == meetingSessionPause.MesstingSessionPauseKey); dbPause.StartDate = meetingSessionPause.StartDate.ToUniversalTime(); dbPause.EndDate = meetingSessionPause.EndDate.Value.ToUniversalTime(); } Database.SubmitChanges(); result = true; } catch (Exception ex) { result = false; } return Json(result); } [HttpGet] public ActionResult ViewRecording(string meetingUrl, string d = null, string c = null) { meetingUrl = meetingUrl?.Trim(); d = d?.Trim(); c = c?.Trim(); Extensions.LogServiceCall("[RebroadcastController][ViewRecording]", string.Format("meetingUrl = {0} d (PurchaseDate) = {1} c (TicketFromUrl) = {2}", meetingUrl, d, c)); if(meetingUrl.ToLower() == "test_room") { var baseUrl = ConfigurationManager.AppSettings["Connect.Url"]; var testUrl = ConfigurationManager.AppSettings["Connect.AccessTestMeetingUrl"]; var accessTestUrl = baseUrl + '/' + testUrl; return Redirect(accessTestUrl); } var meeting = AdobeMeetingConnection.getAdobeMeeting(meetingUrl); if(meeting != null) { var sco_id = int.Parse(meeting.SelectSingleNode("//sco") .Attributes["sco-id"].Value); DateTime? startDate = null; DateTime? endDate = null; string msg = ""; bool isActive = false; var recordingSession = getActiveRecordingSession(sco_id); //this now returns a recording that starts within an hour, instead of now if(recordingSession == null) { recordingSession = getNextRecordingSession(sco_id); //this now returns the next recording that starts more than an hour from now if(recordingSession != null) { msg = "This webcast session is not currently available. The next scheduled session is: "; startDate = recordingSession.StartTime; endDate = recordingSession.EndTime; } else { msg = "There are no webcasts scheduled for this session"; } } else { isActive = true; startDate = recordingSession.StartTime; endDate = recordingSession.EndTime; } RestoreModelState(); var now = DateTime.UtcNow; return View("recordinglogin", new RecordingView { Name = meeting.SelectSingleNode("//sco/name") .InnerText, HasPassCode = recordingSession != null && recordingSession.Passcode != null, Url = meetingUrl, IsActive = isActive, Start = startDate, End = endDate, Message = msg, TicketFromUrl = c, PurchaseDate = d }); } return null; } [HttpPost] public ActionResult ViewRecordingLogin(string meetingUrl, string firstname, string lastname, string email, string ticket, string passcode, string ticketFromUrl, string purchaseDate) { meetingUrl = meetingUrl?.Trim(); firstname = firstname?.Trim(); lastname = lastname?.Trim(); email = email?.Trim(); passcode = passcode?.Trim(); ticket = ticket?.Trim(); ticketFromUrl = ticketFromUrl?.Trim(); purchaseDate = purchaseDate?.Trim(); Extensions.LogServiceCall("[RebroadcastController][ViewRecordingLogin]", string.Format("email = {0} meetingUrl = {1} ticket = {2} ticketFromUrl = {3} purchaseDate = {4} firstname = {5} lastname = {6} passcode = {7}", email, meetingUrl, ticket, ticketFromUrl, purchaseDate, firstname, lastname, passcode)); var loginInfo = new loginInfo { meetingUrl = meetingUrl, firstname = firstname, lastname = lastname, email = email, ticket = ticket, passcode = passcode, ticketFromUrl = ticketFromUrl, purchaseDate = purchaseDate, meetingSessionKey = 0 }; var magicTicketLogin = string.IsNullOrEmpty(ticketFromUrl); // I commented out the check of CPE.AdobeTicketingOn both because I didn't understand it and it complicated adding the else clause I added. //if ((ConfigurationManager.AppSettings["CPE.AdobeTicketingOn"].ToLower() == "true") & !magicTicketLogin) if(!magicTicketLogin) { if(!ticketFromUrl.Equals(ticket)) { ModelState.AddModelError("ticket", "You have entered an invalid pass code."); SaveModelState(); return RedirectToRoute("ViewRecording", new {meetingUrl}); } if(!VerifyAccess.VerifyTicket(ticket, meetingUrl, firstname, lastname, email, purchaseDate)) { ModelState.AddModelError("ticket", "Invalid Login. Please re-enter your information. If you continue to have trouble, please contact Customer Service at 1-800-544-1114 or email us at sswebcast@cpeincmail.com."); SaveModelState(); return RedirectToRoute("ViewRecording", new {meetingUrl}); } } else { if((passcode == null) || (passcode == "")) { Extensions.LogServiceCall("[RebroadcastController][ViewRecordingLogin]", string.Format("passcode found Empty! email = {0} meetingUrl = {1} ticket = {2} ticketFromUrl = {3} purchaseDate = {4} firstname = {5} lastname = {6} passcode = {7}", email, meetingUrl, ticket, ticketFromUrl, purchaseDate, firstname, lastname, passcode)); ModelState.AddModelError("passcode", "You have entered an invalid pass code."); SaveModelState(); return RedirectToRoute("ViewRecording", new {meetingUrl}); } if(passcode != (DateTime.UtcNow.ToString("MMM") + DateTime.UtcNow.Day.ToString("00")).ToLower()) { Extensions.LogServiceCall("[RebroadcastController][ViewRecordingLogin]", string.Format("passcode found incorrect! email = {0} meetingUrl = {1} ticket = {2} ticketFromUrl = {3} purchaseDate = {4} firstname = {5} lastname = {6} passcode = {7}", email, meetingUrl, ticket, ticketFromUrl, purchaseDate, firstname, lastname, passcode)); ModelState.AddModelError("passcode", "You have entered an invalid pass code."); SaveModelState(); return RedirectToRoute("ViewRecording", new {meetingUrl}); } } try { var principalId = getConnectUser(loginInfo); saveParticipant(loginInfo, principalId); var certificateId = 0; var recordingId = addAdobeConnectPermissions(loginInfo, principalId); var recordingResult = getRecording(ref loginInfo, recordingId); if(!magicTicketLogin) { certificateId = savePurchaseInfo(loginInfo, purchaseDate, principalId, ticketFromUrl, loginInfo.meetingSessionKey); } switch (recordingResult) { case recordingResult.Now: return RedirectToAction("GotoContent", new { loginInfo.meetingSessionKey, email, certificateId }); case recordingResult.Lobby: placeIntoLobby(loginInfo.meetingSessionKey, email, certificateId); break; } } catch (Exception ex) { Extensions.LogServiceError("[RebroadcastController][ViewRecordingLogin]", ex); return RedirectToRoute("ViewRecording", new {meetingUrl}); } return null; } [HttpGet] public ActionResult LobbyWait() { int meetingSessionKey = Convert.ToInt32(Request.QueryString["meetingSessionKey"]); string email = Request.QueryString["email"]; int certificateId = Convert.ToInt32(Request.QueryString["certificateId"]); var meeting = Database.MeetingSessions.FirstOrDefault(x => x.MeetingSessionKey == meetingSessionKey); var lobbyData = new LobbyModel { LobbyDuration = (DateTime.UtcNow - meeting.StartDate).TotalMilliseconds, Email = email, meetingSessionKey = meetingSessionKey, CertificateId = certificateId }; return View("lobby", lobbyData); } [HttpPost] public JsonResult PublishRecording(int meetingSessionKey, DateTime startTime, DateTime endTime, string surveyLink, string passcode) { surveyLink = surveyLink?.Trim(); passcode = passcode?.Trim(); var result = new JsonDataResult {Success = false, Data = new {Url = "", Message = ""}}; //return this.Json(result); var recordingsFolderId = ConfigurationManager.AppSettings["Connect.RecordingsFolderId"]; string recordingUrl = null; var moveToContentLibrary = false; var meeting = Database.MeetingSessions.Single(ms => ms.MeetingSessionKey == meetingSessionKey); var admin = AdobeMeetingConnection.GetAdobeAdminSession(); var request = new Request(admin, "sco-contents"); request.Parameters.Add("sco-id", meeting.SCO_ID.ToString()); request.Parameters.Add("filter-icon", "archive"); if(request.Execute() && request.Status == Status.OK) { var recordings = request.XmlResults.GetElementsByTagName("sco"); if(recordings.Count == 0) { //meeting room does not have any recordings present //look up recording in content library var contentRequest = new Request(admin, "sco-contents"); contentRequest.Parameters.Add("sco-id", recordingsFolderId); contentRequest.Parameters.Add("filter-description", meeting.SCO_ID.ToString()); if(contentRequest.Execute() && contentRequest.Status == Status.OK) { recordings = contentRequest.XmlResults.GetElementsByTagName("sco"); moveToContentLibrary = false; } else { Console.WriteLine("wtf"); } } else { //meeting room has recordings. Need to move to content library. moveToContentLibrary = true; } if(recordings.Count > 0) { var recordingId = recordings[0].Attributes["sco-id"].Value; var recordingName = recordings[0].SelectSingleNode("name") .InnerText; recordingUrl = recordings[0].SelectSingleNode("url-path") .InnerText.Replace("/", ""); var durationInSeconds = int.Parse(recordings[0].Attributes["duration"].Value); //create RecordingSession var recordingSession = new RecordingSession { MeetingSCO_ID = meeting.SCO_ID, RecordingSCO_ID = int.Parse(recordingId), StartTime = startTime.ToUniversalTime(), EndTime = endTime.ToUniversalTime(), Name = recordingName, RecordingUrl = recordingUrl, Duration = durationInSeconds, SurveyLink = Server.UrlDecode(surveyLink), Passcode = Server.UrlDecode(passcode) }; Database.RecordingSessions.InsertOnSubmit(recordingSession); Database.SubmitChanges(); var originalDate = meeting.StartDate.Date; var diffInDays = (startTime.ToUniversalTime() .Date - originalDate).Days; var origStartTime = meeting.StartDate.TimeOfDay; var origOnRebroadcastDate = startTime.Date + origStartTime; var diffInMs = (startTime.ToUniversalTime() - origOnRebroadcastDate).TotalMilliseconds; var createResult = Database.CreateRebroadcastSession(recordingSession.RecordingSCO_ID, meeting.SCO_ID, meeting.OwnerPrincipal_ID, startTime.ToUniversalTime(), endTime.ToUniversalTime(), diffInMs, diffInDays, recordingName); recordingSession.MeetingSessionKey = createResult.Single() .Column1; Database.SubmitChanges(); result.Success = true; result.Data = new {Url = recordingUrl, Message = ""}; if(moveToContentLibrary) { var moveRequest = new Request(admin, "sco-move"); moveRequest.Parameters.Add("folder-id", recordingsFolderId); moveRequest.Parameters.Add("sco-id", recordingId); if(moveRequest.Execute() && moveRequest.Status == Status.OK) { var updateRequest = new Request(admin, "sco-update"); updateRequest.Parameters.Add("sco-id", recordingId); updateRequest.Parameters.Add("description", meeting.SCO_ID.ToString()); if(updateRequest.Execute() && updateRequest.Status == Status.OK) { result.Success = true; result.Data = new {Url = recordingUrl, Message = ""}; } else { result.Success = false; result.Data = new {Url = "", Message = "Unable to update recording description."}; } } else { result.Success = false; result.Data = new { Url = "", Message = "Could not move recording to content library.", Error = moveRequest.Status.ToString() }; } } } else { result.Success = false; result.Data = new {Url = "", Message = "Meeting does not have any recordings."}; } } else { result.Success = false; result.Data = new {Url = "", Message = "Problem listing recordings.", Error = request.Status.ToString()}; } return Json(result, JsonRequestBehavior.AllowGet); } [HttpGet] public JsonResult DeleteRecording(int recordingSessionKey) { var success = false; var now = DateTime.UtcNow; var recordingSession = Database.RecordingSessions.SingleOrDefault(rs => rs.RecordingKey == recordingSessionKey); if(recordingSession != null) { if(recordingSession.MeetingSessionKey.HasValue) { var meeting = Database.MeetingSessions.Single( ms => ms.MeetingSessionKey == recordingSession.MeetingSessionKey.Value); if(meeting.StartDate > now) { Database.DeleteSession(meeting.MeetingSessionKey); } } if(recordingSession.StartTime > now) { Database.RecordingSessions.DeleteOnSubmit(recordingSession); Database.SubmitChanges(); success = true; } } return Json(success, JsonRequestBehavior.AllowGet); } [HttpGet] public JsonResult RebroadcastActive(string recordingUrl) { recordingUrl = recordingUrl?.Trim(); var active = false; var recording = AdobeMeetingConnection.getAdobeMeeting(recordingUrl); if(recording != null) { var sco_id = int.Parse(recording.SelectSingleNode("//sco") .Attributes["sco-id"].Value); var recordingSession = getActiveRecordingSession(sco_id); active = recordingSession != null; } return Json(active, JsonRequestBehavior.AllowGet); } [HttpGet] public ActionResult Wufoo() { var client = new WebClient(); var response = client.DownloadString( "http://intesolvtest.wufoo.com/forms/submit-a-question/def/field1=Course+Title&field2=Course+Code&field5=today,field3=Jason&field4=McIntosh&field2=jason.wigginton@gmail.com"); return Content(response); } /// /// /// /// /// /// /// private string getWufooQAlink(RecordingSession recordingSession, string email, string firstname, string lastname) { firstname = firstname?.Trim(); lastname = lastname?.Trim(); email = email?.Trim(); var meetingDetails = Database.MeetingDetails.SingleOrDefault(md => md.MeetingKey == recordingSession.MeetingSCO_ID); var code = meetingDetails != null ? meetingDetails.CourseCode : ""; var instructor = meetingDetails != null ? meetingDetails.Instructor : ""; var url = recordingSession.SurveyLink; if(url.EndsWith("/")) { url = url.Remove(url.LastIndexOf("/"), 1); } //1=Course Title,2=Course Code,3=Date,4=Firstname,5=Lastname,8=email //return url + String.Format("/def/field1={0}&field2={1}&field3={2}&field4={3}&field5={4}&field8={5}", recordingSession.Name, code, "today", firstname, lastname,email); //1 = first name, 2 = lastname, 3 = email, 5 = Course return url + string.Format("/def/field1={0}&field2={1}&field3={2}&field5={3}&field7={4}&field8={5}&field9={6}", firstname, lastname, email, recordingSession.Name, code, instructor, "today"); } private void TrackUserEntrance(MeetingSession session, int principalId, string firstName, string lastName, string email) { firstName = firstName?.Trim(); lastName = lastName?.Trim(); email = email?.Trim(); //participant isnt getting tracked for the test rebroadcast -> is this a real problem or a test-data problem? var now = DateTime.UtcNow; var context = Database; Extensions.LogServiceCall("TrackUser", string.Format( "Parameters: meetingSessionKey = {0} principal_id= {1} firstname = {2}, lastname = {3} email = {4}, type = 0", session.MeetingSessionKey, principalId, firstName, lastName, email)); try { if(principalId > 0) { if(session != null) { var user = context.Participants.SingleOrDefault(p => p.Principal_ID == principalId); if(user == null) { //create new user user = new Participant { Principal_ID = principalId, FirstName = firstName, LastName = lastName, Email = email }; context.Participants.InsertOnSubmit(user); } //JM 9/27/2012 - changed to grab first participant session found. Weird issue where some users were getting multiple sesions var existingMeetingParticipantSession = session.MeetingParticipantSessions.OrderBy(mps => mps.MeetingParticipantSessionKey) . FirstOrDefault(mps => mps.ParticipantKey == principalId); if(existingMeetingParticipantSession == null) { //create new session for user existingMeetingParticipantSession = new MeetingParticipantSession { MeetingSessionKey = session.MeetingSessionKey, ParticipantKey = principalId, PlaySound = true }; context.MeetingParticipantSessions.InsertOnSubmit(existingMeetingParticipantSession); context.SubmitChanges(); //JM-12/27/2012 Change to check for multiple meeting participant sessions CheckParticipantSessions(session, principalId); //make sure tracking gets assigned right key existingMeetingParticipantSession = context.MeetingParticipantSessions.OrderBy( p => p.MeetingParticipantSessionKey) .FirstOrDefault( p => p.MeetingSessionKey == session.MeetingSessionKey & p.ParticipantKey == principalId); } var existingParticipantTracking = context.ParticipantTrackings.FirstOrDefault( pt => pt.MeetingParticipantSessionKey == existingMeetingParticipantSession.MeetingParticipantSessionKey && pt.Principal_ID == principalId && !pt.EndDate.HasValue); if(existingParticipantTracking == null) { //add entrance time var pTrack = new ParticipantTracking { MeetingParticipantSessionKey = existingMeetingParticipantSession.MeetingParticipantSessionKey, Principal_ID = principalId, StartDate = now }; context.ParticipantTrackings.InsertOnSubmit(pTrack); } else { //track enter received when there is already an entrance with no exit //set exit on existing ParticipantEngagement lastEngagement = existingParticipantTracking.MeetingParticipantSession.ParticipantEngagements.OrderBy( e => e.DisplayTime) .LastOrDefault(); if(lastEngagement == null) existingParticipantTracking.EndDate = existingParticipantTracking.StartDate; else existingParticipantTracking.EndDate = lastEngagement.ResponseTime.HasValue ? lastEngagement.ResponseTime.Value : lastEngagement.DisplayTime; //existingParticipantTracking.EndDate = now; //add new entrance time var pTrack = new ParticipantTracking { MeetingParticipantSessionKey = existingMeetingParticipantSession.MeetingParticipantSessionKey, Principal_ID = principalId, StartDate = now }; context.ParticipantTrackings.InsertOnSubmit(pTrack); } context.SubmitChanges(); } } else { throw new ArgumentException("Principal ID: " + principalId + " is not valid"); } } catch (Exception ex) { Extensions.LogServiceError("TrackUser", ex); } } private void CheckParticipantSessions(MeetingSession session, int principal_id) { try { var context = Database; var participantSessionCount = session.MeetingParticipantSessions.Count(mps => mps.ParticipantKey == principal_id); if(participantSessionCount > 1) { var participantSessions = session.MeetingParticipantSessions.Where(mps => mps.ParticipantKey == principal_id) .OrderBy( mps => mps.MeetingParticipantSessionKey); var psToKeep = participantSessions.First(); var psessionsToDelete = participantSessions.Where( ps => ps.MeetingParticipantSessionKey != psToKeep.MeetingParticipantSessionKey); foreach (var meetingParticipantSession in psessionsToDelete) { context.MeetingParticipantSessions.DeleteOnSubmit(meetingParticipantSession); } context.SubmitChanges(); } } catch (Exception ex) { Extensions.LogServiceError("CheckParticipanSessions", ex); } } private RecordingSession getActiveRecordingSession(int recordingScoId) { //for SP3 if rs.StartTime < now + 1hr., recording considered "active", user will be placed into lobby var now = DateTime.UtcNow; var recording = Database.RecordingSessions.SingleOrDefault(rs => rs.RecordingSCO_ID == recordingScoId && rs.StartTime <= now.AddHours(1) && rs.EndTime > now); return recording; } private RecordingSession getNextRecordingSession(int recordingScoId) { //for SP3 a user can wait in the lobby for an hour, so the next (not currently active) recording session will have start > than now+1hr var now = DateTime.UtcNow; var recording = Database.RecordingSessions.Where(rs => rs.RecordingSCO_ID == recordingScoId && rs.StartTime > now.AddHours(1)) .OrderBy(rs => rs.StartTime) .FirstOrDefault(); return recording; } private void SaveModelState() { TempData["ModelState"] = ModelState; } private void RestoreModelState() { var previousModelState = TempData["ModelState"] as ModelStateDictionary; if(previousModelState != null) { foreach (KeyValuePair kvp in previousModelState) if(!ModelState.ContainsKey(kvp.Key)) ModelState.Add(kvp.Key, kvp.Value); TempData["ModelState"] = ModelState; //Add back into TempData } } /// /// private void placeIntoLobby(int meetingSessionKey, string email, int certificateId) { email = email?.Trim(); //rebroadcast/LobbyWait Response.Redirect("/rebroadcast/LobbyWait?meetingSessionKey=" + meetingSessionKey + "&email=" + email + "&certificateId=" + certificateId, true); } [HttpGet] public ActionResult GotoContent(int meetingSessionKey, string email, int certificateId) { email = email?.Trim(); var now = DateTime.UtcNow; var connectUrl = ConfigurationManager.AppSettings["Connect.Url"]; var accountId = int.Parse(ConfigurationManager.AppSettings["Connect.AccountId"]); var password = Guid.NewGuid() .ToString() .Replace("{", "") .Replace("}", "") .Substring(0, 8); var participant = Database.Participants.FirstOrDefault(p => p.Email == email); if(participant == null) { Extensions.LogServiceCall("[RebroadcastController][GotoContent]", string.Format("participant found null; meetingSessionKey = {0} email = {1} certificateId = {2}", meetingSessionKey, email, certificateId)); throw new Exception("Login failed! " + email); } var recording = Database.RecordingSessions.FirstOrDefault( rs => rs.MeetingSessionKey == meetingSessionKey && rs.StartTime <= now && rs.EndTime > now); if(recording == null) { Extensions.LogServiceCall("[RebroadcastController][GotoContent]", string.Format("recording found null; meetingSessionKey = {0} email = {1} certificateId = {2}", meetingSessionKey, email, certificateId)); throw new Exception("Login failed! " + email); } var meeting = Database.MeetingSessions.FirstOrDefault(y => y.MeetingSessionKey == meetingSessionKey); if(meeting == null) { Extensions.LogServiceCall("[RebroadcastController][GotoContent]", string.Format("meeting found null; meetingSessionKey = {0} email = {1} certificateId = {2}", meetingSessionKey, email, certificateId)); throw new Exception("Login failed! " + email); } var admin = AdobeMeetingConnection.GetAdobeAdminSession(); Login.ResetPassword(admin, participant.Principal_ID, password); var session = Login.UserLogin(participant.Email, password, connectUrl, accountId); var differenceInMilliseconds = (now - meeting.StartDate).TotalMilliseconds; var recordingView = new RecordingView { Name = AdobeMeetingConnection.getAdobeMeetingName(recording.RecordingUrl), PrincipalId = participant.Principal_ID, MeetingSessionKey = meeting.MeetingSessionKey, FirstName = participant.FirstName, LastName = participant.LastName, Email = participant.Email, QAlink = getWufooQAlink(recording, participant.Email, participant.FirstName, participant.LastName), Url = string.Format( "{0}/{1}?session={2}&launcher=false&pbEIOpen=false&archiveOffset={3}", connectUrl, recording.RecordingUrl, session.SessionKey, differenceInMilliseconds), //+ //((passcode == null) ? "" : "&meeting-passcode=" + passcode) CertificateId = certificateId }; admin = AdobeMeetingConnection.GetAdobeAdminSession(); var request = new Request(admin, "principal-update"); request.Parameters.Add("first-name", participant.FirstName); request.Parameters.Add("last-name", participant.LastName); request.Parameters.Add("principal-id", participant.Principal_ID.ToString()); request.Execute(); var idCookie = new HttpCookie("id") { Value = participant.Principal_ID.ToString(), Expires = DateTime.UtcNow.AddDays(1) }; Response.Cookies.Add(idCookie); TrackUserEntrance(meeting, participant.Principal_ID, participant.FirstName, participant.LastName, participant.Email); return View("recording", recordingView); } //public string SendCert(int meetingSessionKey, int certificate_id, int principal_id) //{ // //TODO make outcome dictionary to return pass, fail, ineligible, or wonky:contact cust serv // string _fail = "http://localhost:11038/Certificate?a=1179512338&b=20160128&c=1d633b"; // //string _fail = "FAIL"; // var meeting = Database.MeetingSessions.FirstOrDefault(x => x.MeetingSessionKey == meetingSessionKey); // if (certificate_id > 0) // { // ParticipantPurchase purchase = // Database.ParticipantPurchases.FirstOrDefault(p => p.Purchase_ID == certificate_id && p.PrincipalID == principal_id); // if (purchase == null) // { // //if the certificate_id is >0 then purchase would only be null because of record being deleted while user was in the meeting, or the principalID got mis-matched // return _fail; // TODO probably return wonky, contact cust service message // } // if (!purchase.EarnedCertificate) // { // MeetingParticipantSession meetingParticipantSession = // Database.MeetingParticipantSessions.FirstOrDefault( // m => m.MeetingSessionKey == meetingSessionKey && m.ParticipantKey == principal_id); // if (meetingParticipantSession == null) // { // return _fail;//TODO return wonky // } // List participantSessionsDataResult = // Database.ParticipantSessionsData(meetingSessionKey) // .ToList(); // var participantSessionsData = // participantSessionsDataResult.OrderBy(p => p.MeetingParticipantSessionKey) // .FirstOrDefault( // p => // p.MeetingParticipantSessionKey == // meetingParticipantSession.MeetingParticipantSessionKey); // if (participantSessionsData == null) // { // return _fail;//TODO is this a return wonky? it means they weren't tracked // } // MeetingSessionsDataResult meetingSession = Database.MeetingSessionsData().FirstOrDefault(m => m.MeetingSessionKey == meetingSessionKey); // if (meetingSession == null) // { // return _fail;//TODO return wonky // } // var courseLength = meetingSession.ActualSessionTime.GetValueOrDefault(); //in minutes // double courseCredits = courseLength / 50.0; //1 credit per 50 minutes // List maxCourseCredits = ConfigurationManager.AppSettings["MaxCourseCreditList"].Split(';').Select(s => double.Parse(s)).ToList(); //max credits cut list // int mx = maxCourseCredits.BinarySearch(courseCredits); //find appropriate max for this course // double maxCredits = maxCourseCredits[mx >= 0 ? mx : ~mx - 1];//...by rounding down // double realCredits = participantSessionsData.SessionCredit == null ? 0 : (double)participantSessionsData.SessionCredit.Value; //users credits per adobe // purchase.Credits = Math.Min(maxCredits, realCredits); //user awarded no more than max possible credits for the course // MeetingDetail meetingDetail = // Database.MeetingDetails.FirstOrDefault(m => m.MeetingKey == purchase.MeetingSco); // purchase.Presenter = meetingDetail == null ? "" : meetingDetail.Instructor; // double percentComplete = (participantSessionsData.SessionEngagementCount.GetValueOrDefault() == 0 ? // 1 : (participantSessionsData.SessionHeartbeatCount.GetValueOrDefault() / participantSessionsData.SessionEngagementCount.Value)); // if (percentComplete >= .75) //threshold for earning a certificate is 75% response rate // { // purchase.EarnedCertificate = true; // } // Database.SubmitChanges(); // if (purchase.EarnedCertificate) // { // //TODO with return Pass dictionary value as string.format with replace of certUrl // //string certUrl = AdobeCertificateHelper.SendWebcastCert(purchase); // //format the outcome.pass.value message with certUrl replace // //return outcome.pass with its value // return AdobeCertificateHelper.SendWebcastCert(purchase); // } // //TODO return outcome.fail // return AdobeCertificateHelper.SendFailNotice(purchase); // } // } // return _fail;// TODO return ineligible. need to make AdobeCertificateHelper.SendIneligibleNotice(principalId) //} /// /// /// /// private int getConnectUser(loginInfo loginInfo) { var password = Guid.NewGuid() .ToString() .Replace("{", "") .Replace("}", "") .Substring(0, 8); var admin = AdobeMeetingConnection.GetAdobeAdminSession(); var request = new Request(admin, "principal-list"); request.Parameters.Add("filter-type", "guest"); request.Parameters.Add("filter-type", "user"); request.Parameters.Add("filter-login", loginInfo.email); if(request.Execute() && request.Status == Status.OK) { int principalId; if(request.XmlResults.SelectSingleNode("//principal") == null) { // Not found principalId = Login.CreateGuest(admin, loginInfo.email, password, loginInfo.email, loginInfo.firstname, loginInfo.lastname); } else { // Found principalId = int.Parse(request.XmlResults.SelectSingleNode("//principal") .Attributes["principal-id"].Value); loginInfo.email = request.XmlResults.SelectSingleNode("//principal/login") .InnerText; if(request.XmlResults.SelectSingleNode("//principal") .Attributes["type"].Value == "user") { ModelState.AddModelError("email", "Invalid email."); SaveModelState(); throw new Exception("Login failed!"); } } if(principalId < 1) { throw new Exception("Login failed!"); } Login.ResetPassword(admin, principalId, password); return principalId; } throw new Exception("Login failed!"); } /// /// /// /// /// private int addAdobeConnectPermissions(loginInfo loginInfo, int principalId) { var admin = AdobeMeetingConnection.GetAdobeAdminSession(); var meetingXml = AdobeMeetingConnection.getAdobeMeeting(loginInfo.meetingUrl); var recordingId = int.Parse(meetingXml.SelectSingleNode("//sco") .Attributes["sco-id"].Value); var request = new Request(admin, "permissions-update"); request.Parameters.Add("acl-id", recordingId.ToString()); request.Parameters.Add("principal-id", principalId.ToString()); request.Parameters.Add("permission-id", "view"); if(request.Execute() && request.Status == Status.OK) { return recordingId; } throw new Exception("Login failed!"); } /// /// /// /// /// private recordingResult getRecording(ref loginInfo loginInfo, int recordingId) { var now = DateTime.UtcNow; var recording = Database.RecordingSessions.SingleOrDefault( rs => rs.RecordingSCO_ID == recordingId && rs.StartTime <= now && rs.EndTime > now); if(recording == null) { recording = Database.RecordingSessions.SingleOrDefault( rs => rs.RecordingSCO_ID == recordingId && rs.StartTime <= now.AddHours(1) && rs.StartTime > now); if(recording == null) { loginInfo.meetingSessionKey = 0; return recordingResult.None; } loginInfo.meetingSessionKey = recording.MeetingSessionKey.Value; return recordingResult.Lobby; } loginInfo.meetingSessionKey = recording.MeetingSessionKey.Value; return recordingResult.Now; } /// /// /// /// private void saveParticipant(loginInfo loginInfo, int principalId) { var participant = Database.Participants.SingleOrDefault(p => p.Principal_ID == principalId); if(participant == null) { participant = new Participant { Principal_ID = principalId, FirstName = loginInfo.firstname, LastName = loginInfo.lastname, Email = loginInfo.email }; Database.Participants.InsertOnSubmit(participant); } else { participant.FirstName = loginInfo.firstname; participant.LastName = loginInfo.lastname; } Database.SubmitChanges(); } private int savePurchaseInfo(loginInfo loginInfo, string purchaseDate, int principalId, string ticketFromUrl, int meetingSessionKey) { purchaseDate = purchaseDate?.Trim(); ticketFromUrl = ticketFromUrl?.Trim(); //purchase indicates hashed-ticket login that could earn a certificate. storing this info separate since participant name info gets updated based on adobe info //and per cpe, a cert can only be earned in the exact name of purchaser. var meeting = Database.MeetingSessions.SingleOrDefault( ms => ms.MeetingSessionKey == meetingSessionKey); string formattedPdate = purchaseDate.Substring(0, 4) + '-' + purchaseDate.Substring(4, 2) + '-' + purchaseDate.Substring(6, 2); DateTime pDate = Convert.ToDateTime(formattedPdate); ParticipantPurchase purchase = Database.ParticipantPurchases.SingleOrDefault( p => p.PrincipalID == principalId & p.Ticket == ticketFromUrl & p.MeetingSco == meeting.SCO_ID); if(purchase == null) { purchase = new ParticipantPurchase { FirstName = loginInfo.firstname, LastName = loginInfo.lastname, Email = loginInfo.email, PrincipalID = principalId, MeetingName = meeting.Name, MeetingDate = meeting.StartDate, MeetingSco = meeting.SCO_ID, Ticket = ticketFromUrl, PurchaseDate = pDate, EarnedCertificate = false, Credits = 0 }; Database.ParticipantPurchases.InsertOnSubmit(purchase); } Database.SubmitChanges(); return purchase.Purchase_ID; } } /// /// public class loginInfo { //string meetingUrl, string firstname, string lastname, string email, // string ticket, string passcode, string ticketFromUrl, string purchaseDate public string meetingUrl { get; set; } public string firstname { get; set; } public string lastname { get; set; } public string email { get; set; } public string ticket { get; set; } public string passcode { get; set; } public string ticketFromUrl { get; set; } public string purchaseDate { get; set; } public int meetingSessionKey { get; set; } } /// /// public enum recordingResult { Now, Lobby, None } }