2 using System.Collections.Generic;
3 using System.Configuration;
8 using CPE.App.Web.Code;
9 using CPE.App.Web.Connect;
10 using CPE.App.Web.Helpers;
11 using CPE.App.Web.Models;
13 namespace CPE.App.Web.Controllers {
14 public class RebroadcastController : BaseController {
16 public ActionResult RebroadcastSchedule(int meetingSessionKey) {
17 var meetingSession = Database.MeetingSessions.Single(ms => ms.MeetingSessionKey == meetingSessionKey);
18 return View(meetingSession);
22 public ActionResult RebroadcastSessions(int meetingSessionKey) {
23 var meetingScoId = Database.MeetingSessions.Single(ms => ms.MeetingSessionKey == meetingSessionKey)
25 var recordingSessions =
26 Database.RecordingSessions.Where(rs => rs.MeetingSCO_ID == meetingScoId)
27 .OrderByDescending(rs => rs.StartTime)
30 return PartialView(recordingSessions);
34 public ActionResult RebroadcastPauses(int recordingKey) {
35 var recording = Database.RecordingSessions.Single(r => r.RecordingKey == recordingKey);
36 var meeting = Database.MeetingSessions.Single(ms => ms.MeetingSessionKey == recording.MeetingSessionKey);
37 var recordingPauses = new RecordingPauses {
39 SessionPauses = meeting.MeetingSessionPauses.ToList()
42 return View(recordingPauses);
46 public JsonResult DeletePause(int pauseKey) {
49 var pause = Database.MeetingSessionPauses.Single(p => p.MesstingSessionPauseKey == pauseKey);
50 Database.MeetingSessionPauses.DeleteOnSubmit(pause);
51 Database.SubmitChanges();
53 } catch (Exception ex) {
60 public JsonResult UpdatePauses(MeetingSessionPause[] pauses) {
63 foreach (var meetingSessionPause in pauses) {
65 Database.MeetingSessionPauses.Single(
66 msp => msp.MesstingSessionPauseKey == meetingSessionPause.MesstingSessionPauseKey);
67 dbPause.StartDate = meetingSessionPause.StartDate.ToUniversalTime();
68 dbPause.EndDate = meetingSessionPause.EndDate.Value.ToUniversalTime();
70 Database.SubmitChanges();
72 } catch (Exception ex) {
79 public ActionResult ViewRecording(string meetingUrl, string d = null, string c = null) {
80 meetingUrl = meetingUrl?.Trim();
84 Extensions.LogServiceCall("[RebroadcastController][ViewRecording]", string.Format("meetingUrl = {0} d (PurchaseDate) = {1} c (TicketFromUrl) = {2}", meetingUrl, d, c));
86 if(meetingUrl.ToLower() == "test_room") {
87 var baseUrl = ConfigurationManager.AppSettings["Connect.Url"];
88 var testUrl = ConfigurationManager.AppSettings["Connect.AccessTestMeetingUrl"];
89 var accessTestUrl = baseUrl + '/' + testUrl;
90 return Redirect(accessTestUrl);
93 var meeting = AdobeMeetingConnection.getAdobeMeeting(meetingUrl);
95 var sco_id = int.Parse(meeting.SelectSingleNode("//sco")
96 .Attributes["sco-id"].Value);
97 DateTime? startDate = null;
98 DateTime? endDate = null;
100 bool isActive = false;
101 var recordingSession = getActiveRecordingSession(sco_id);
102 //this now returns a recording that starts within an hour, instead of now
103 if(recordingSession == null) {
104 recordingSession = getNextRecordingSession(sco_id);
105 //this now returns the next recording that starts more than an hour from now
106 if(recordingSession != null) {
108 "This webcast session is not currently available. The next scheduled session is: ";
109 startDate = recordingSession.StartTime;
110 endDate = recordingSession.EndTime;
112 msg = "There are no webcasts scheduled for this session";
116 startDate = recordingSession.StartTime;
117 endDate = recordingSession.EndTime;
121 var now = DateTime.UtcNow;
122 return View("recordinglogin",
124 Name = meeting.SelectSingleNode("//sco/name")
126 HasPassCode = recordingSession != null && recordingSession.Passcode != null,
140 public ActionResult ViewRecordingLogin(string meetingUrl, string firstname, string lastname, string email,
141 string ticket, string passcode, string ticketFromUrl, string purchaseDate) {
142 meetingUrl = meetingUrl?.Trim();
143 firstname = firstname?.Trim();
144 lastname = lastname?.Trim();
145 email = email?.Trim();
146 passcode = passcode?.Trim();
147 ticket = ticket?.Trim();
148 ticketFromUrl = ticketFromUrl?.Trim();
149 purchaseDate = purchaseDate?.Trim();
151 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));
153 var loginInfo = new loginInfo {
154 meetingUrl = meetingUrl,
155 firstname = firstname,
160 ticketFromUrl = ticketFromUrl,
161 purchaseDate = purchaseDate,
162 meetingSessionKey = 0
165 var magicTicketLogin = string.IsNullOrEmpty(ticketFromUrl);
167 // I commented out the check of CPE.AdobeTicketingOn both because I didn't understand it and it complicated adding the else clause I added.
168 //if ((ConfigurationManager.AppSettings["CPE.AdobeTicketingOn"].ToLower() == "true") & !magicTicketLogin)
169 if(!magicTicketLogin) {
170 if(!ticketFromUrl.Equals(ticket)) {
171 ModelState.AddModelError("ticket", "You have entered an invalid pass code.");
173 return RedirectToRoute("ViewRecording", new {meetingUrl});
176 if(!VerifyAccess.VerifyTicket(ticket, meetingUrl, firstname, lastname, email, purchaseDate)) {
177 ModelState.AddModelError("ticket",
178 "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.");
180 return RedirectToRoute("ViewRecording", new {meetingUrl});
183 if((passcode == null) || (passcode == "")) {
184 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));
186 ModelState.AddModelError("passcode", "You have entered an invalid pass code.");
188 return RedirectToRoute("ViewRecording", new {meetingUrl});
191 if(passcode != (DateTime.UtcNow.ToString("MMM") + DateTime.UtcNow.Day.ToString("00")).ToLower()) {
192 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));
194 ModelState.AddModelError("passcode", "You have entered an invalid pass code.");
196 return RedirectToRoute("ViewRecording", new {meetingUrl});
201 var principalId = getConnectUser(loginInfo);
202 saveParticipant(loginInfo, principalId);
203 var certificateId = 0;
205 var recordingId = addAdobeConnectPermissions(loginInfo, principalId);
206 var recordingResult = getRecording(ref loginInfo, recordingId);
208 if(!magicTicketLogin) {
209 certificateId = savePurchaseInfo(loginInfo, purchaseDate, principalId, ticketFromUrl,
210 loginInfo.meetingSessionKey);
213 switch (recordingResult) {
214 case recordingResult.Now:
215 return RedirectToAction("GotoContent",
217 loginInfo.meetingSessionKey, email, certificateId
219 case recordingResult.Lobby:
220 placeIntoLobby(loginInfo.meetingSessionKey, email, certificateId);
223 } catch (Exception ex) {
224 Extensions.LogServiceError("[RebroadcastController][ViewRecordingLogin]", ex);
226 return RedirectToRoute("ViewRecording", new {meetingUrl});
234 public ActionResult LobbyWait() {
235 int meetingSessionKey = Convert.ToInt32(Request.QueryString["meetingSessionKey"]);
236 string email = Request.QueryString["email"];
237 int certificateId = Convert.ToInt32(Request.QueryString["certificateId"]);
239 var meeting = Database.MeetingSessions.FirstOrDefault(x => x.MeetingSessionKey == meetingSessionKey);
240 var lobbyData = new LobbyModel {
241 LobbyDuration = (DateTime.UtcNow - meeting.StartDate).TotalMilliseconds,
243 meetingSessionKey = meetingSessionKey,
244 CertificateId = certificateId
246 return View("lobby", lobbyData);
251 public JsonResult PublishRecording(int meetingSessionKey, DateTime startTime, DateTime endTime,
252 string surveyLink, string passcode) {
254 surveyLink = surveyLink?.Trim();
255 passcode = passcode?.Trim();
257 var result = new JsonDataResult {Success = false, Data = new {Url = "", Message = ""}};
258 //return this.Json(result);
259 var recordingsFolderId = ConfigurationManager.AppSettings["Connect.RecordingsFolderId"];
260 string recordingUrl = null;
261 var moveToContentLibrary = false;
262 var meeting = Database.MeetingSessions.Single(ms => ms.MeetingSessionKey == meetingSessionKey);
263 var admin = AdobeMeetingConnection.GetAdobeAdminSession();
264 var request = new Request(admin, "sco-contents");
265 request.Parameters.Add("sco-id", meeting.SCO_ID.ToString());
266 request.Parameters.Add("filter-icon", "archive");
269 if(request.Execute() && request.Status == Status.OK) {
270 var recordings = request.XmlResults.GetElementsByTagName("sco");
272 if(recordings.Count == 0) {
273 //meeting room does not have any recordings present
274 //look up recording in content library
275 var contentRequest = new Request(admin, "sco-contents");
276 contentRequest.Parameters.Add("sco-id", recordingsFolderId);
277 contentRequest.Parameters.Add("filter-description", meeting.SCO_ID.ToString());
279 if(contentRequest.Execute() && contentRequest.Status == Status.OK) {
280 recordings = contentRequest.XmlResults.GetElementsByTagName("sco");
281 moveToContentLibrary = false;
283 Console.WriteLine("wtf");
286 //meeting room has recordings. Need to move to content library.
287 moveToContentLibrary = true;
290 if(recordings.Count > 0) {
291 var recordingId = recordings[0].Attributes["sco-id"].Value;
292 var recordingName = recordings[0].SelectSingleNode("name")
294 recordingUrl = recordings[0].SelectSingleNode("url-path")
295 .InnerText.Replace("/", "");
296 var durationInSeconds = int.Parse(recordings[0].Attributes["duration"].Value);
298 //create RecordingSession
299 var recordingSession = new RecordingSession {
300 MeetingSCO_ID = meeting.SCO_ID,
301 RecordingSCO_ID = int.Parse(recordingId),
302 StartTime = startTime.ToUniversalTime(),
303 EndTime = endTime.ToUniversalTime(),
304 Name = recordingName,
305 RecordingUrl = recordingUrl,
306 Duration = durationInSeconds,
307 SurveyLink = Server.UrlDecode(surveyLink),
308 Passcode = Server.UrlDecode(passcode)
310 Database.RecordingSessions.InsertOnSubmit(recordingSession);
311 Database.SubmitChanges();
313 var originalDate = meeting.StartDate.Date;
314 var diffInDays = (startTime.ToUniversalTime()
315 .Date - originalDate).Days;
316 var origStartTime = meeting.StartDate.TimeOfDay;
317 var origOnRebroadcastDate = startTime.Date + origStartTime;
318 var diffInMs = (startTime.ToUniversalTime() - origOnRebroadcastDate).TotalMilliseconds;
320 var createResult = Database.CreateRebroadcastSession(recordingSession.RecordingSCO_ID,
322 meeting.OwnerPrincipal_ID, startTime.ToUniversalTime(), endTime.ToUniversalTime(), diffInMs,
323 diffInDays, recordingName);
325 recordingSession.MeetingSessionKey = createResult.Single()
327 Database.SubmitChanges();
329 result.Success = true;
330 result.Data = new {Url = recordingUrl, Message = ""};
332 if(moveToContentLibrary) {
333 var moveRequest = new Request(admin, "sco-move");
334 moveRequest.Parameters.Add("folder-id", recordingsFolderId);
335 moveRequest.Parameters.Add("sco-id", recordingId);
337 if(moveRequest.Execute() && moveRequest.Status == Status.OK) {
338 var updateRequest = new Request(admin, "sco-update");
339 updateRequest.Parameters.Add("sco-id", recordingId);
340 updateRequest.Parameters.Add("description", meeting.SCO_ID.ToString());
341 if(updateRequest.Execute() && updateRequest.Status == Status.OK) {
342 result.Success = true;
343 result.Data = new {Url = recordingUrl, Message = ""};
345 result.Success = false;
346 result.Data = new {Url = "", Message = "Unable to update recording description."};
349 result.Success = false;
353 Message = "Could not move recording to content library.",
354 Error = moveRequest.Status.ToString()
359 result.Success = false;
360 result.Data = new {Url = "", Message = "Meeting does not have any recordings."};
363 result.Success = false;
364 result.Data = new {Url = "", Message = "Problem listing recordings.", Error = request.Status.ToString()};
367 return Json(result, JsonRequestBehavior.AllowGet);
371 public JsonResult DeleteRecording(int recordingSessionKey) {
373 var now = DateTime.UtcNow;
374 var recordingSession =
375 Database.RecordingSessions.SingleOrDefault(rs => rs.RecordingKey == recordingSessionKey);
377 if(recordingSession != null) {
378 if(recordingSession.MeetingSessionKey.HasValue) {
380 Database.MeetingSessions.Single(
381 ms => ms.MeetingSessionKey == recordingSession.MeetingSessionKey.Value);
382 if(meeting.StartDate > now) {
383 Database.DeleteSession(meeting.MeetingSessionKey);
387 if(recordingSession.StartTime > now) {
388 Database.RecordingSessions.DeleteOnSubmit(recordingSession);
389 Database.SubmitChanges();
393 return Json(success, JsonRequestBehavior.AllowGet);
397 public JsonResult RebroadcastActive(string recordingUrl) {
399 recordingUrl = recordingUrl?.Trim();
402 var recording = AdobeMeetingConnection.getAdobeMeeting(recordingUrl);
403 if(recording != null) {
404 var sco_id = int.Parse(recording.SelectSingleNode("//sco")
405 .Attributes["sco-id"].Value);
406 var recordingSession = getActiveRecordingSession(sco_id);
407 active = recordingSession != null;
410 return Json(active, JsonRequestBehavior.AllowGet);
414 public ActionResult Wufoo() {
415 var client = new WebClient();
416 var response = client.DownloadString(
417 "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");
419 return Content(response);
425 /// <param name="recordingSession"></param>
426 /// <param name="email"></param>
427 /// <param name="firstname"></param>
428 /// <param name="lastname"></param>
429 /// <returns></returns>
430 private string getWufooQAlink(RecordingSession recordingSession, string email, string firstname, string lastname) {
431 firstname = firstname?.Trim();
432 lastname = lastname?.Trim();
433 email = email?.Trim();
436 Database.MeetingDetails.SingleOrDefault(md => md.MeetingKey == recordingSession.MeetingSCO_ID);
438 var code = meetingDetails != null ? meetingDetails.CourseCode : "";
439 var instructor = meetingDetails != null ? meetingDetails.Instructor : "";
440 var url = recordingSession.SurveyLink;
441 if(url.EndsWith("/")) {
442 url = url.Remove(url.LastIndexOf("/"), 1);
444 //1=Course Title,2=Course Code,3=Date,4=Firstname,5=Lastname,8=email
445 //return url + String.Format("/def/field1={0}&field2={1}&field3={2}&field4={3}&field5={4}&field8={5}", recordingSession.Name, code, "today", firstname, lastname,email);
446 //1 = first name, 2 = lastname, 3 = email, 5 = Course
448 string.Format("/def/field1={0}&field2={1}&field3={2}&field5={3}&field7={4}&field8={5}&field9={6}",
449 firstname, lastname, email, recordingSession.Name, code, instructor, "today");
453 private void TrackUserEntrance(MeetingSession session, int principalId, string firstName, string lastName,
455 firstName = firstName?.Trim();
456 lastName = lastName?.Trim();
457 email = email?.Trim();
459 //participant isnt getting tracked for the test rebroadcast -> is this a real problem or a test-data problem?
460 var now = DateTime.UtcNow;
461 var context = Database;
462 Extensions.LogServiceCall("TrackUser",
464 "Parameters: meetingSessionKey = {0} principal_id= {1} firstname = {2}, lastname = {3} email = {4}, type = 0",
465 session.MeetingSessionKey, principalId, firstName, lastName, email));
468 if(principalId > 0) {
469 if(session != null) {
470 var user = context.Participants.SingleOrDefault(p => p.Principal_ID == principalId);
474 user = new Participant {
475 Principal_ID = principalId,
476 FirstName = firstName,
480 context.Participants.InsertOnSubmit(user);
483 //JM 9/27/2012 - changed to grab first participant session found. Weird issue where some users were getting multiple sesions
484 var existingMeetingParticipantSession =
485 session.MeetingParticipantSessions.OrderBy(mps => mps.MeetingParticipantSessionKey)
487 FirstOrDefault(mps => mps.ParticipantKey == principalId);
489 if(existingMeetingParticipantSession == null) {
490 //create new session for user
491 existingMeetingParticipantSession = new MeetingParticipantSession {
492 MeetingSessionKey = session.MeetingSessionKey,
493 ParticipantKey = principalId,
496 context.MeetingParticipantSessions.InsertOnSubmit(existingMeetingParticipantSession);
497 context.SubmitChanges();
498 //JM-12/27/2012 Change to check for multiple meeting participant sessions
499 CheckParticipantSessions(session, principalId);
500 //make sure tracking gets assigned right key
501 existingMeetingParticipantSession = context.MeetingParticipantSessions.OrderBy(
502 p => p.MeetingParticipantSessionKey)
505 p.MeetingSessionKey == session.MeetingSessionKey &
506 p.ParticipantKey == principalId);
509 var existingParticipantTracking =
510 context.ParticipantTrackings.FirstOrDefault(
512 pt.MeetingParticipantSessionKey ==
513 existingMeetingParticipantSession.MeetingParticipantSessionKey &&
514 pt.Principal_ID == principalId && !pt.EndDate.HasValue);
516 if(existingParticipantTracking == null) {
519 var pTrack = new ParticipantTracking {
520 MeetingParticipantSessionKey =
521 existingMeetingParticipantSession.MeetingParticipantSessionKey,
522 Principal_ID = principalId,
525 context.ParticipantTrackings.InsertOnSubmit(pTrack);
527 //track enter received when there is already an entrance with no exit
528 //set exit on existing
529 ParticipantEngagement lastEngagement =
530 existingParticipantTracking.MeetingParticipantSession.ParticipantEngagements.OrderBy(
533 if(lastEngagement == null)
534 existingParticipantTracking.EndDate = existingParticipantTracking.StartDate;
536 existingParticipantTracking.EndDate = lastEngagement.ResponseTime.HasValue
537 ? lastEngagement.ResponseTime.Value
538 : lastEngagement.DisplayTime;
539 //existingParticipantTracking.EndDate = now;
540 //add new entrance time
542 var pTrack = new ParticipantTracking {
543 MeetingParticipantSessionKey =
544 existingMeetingParticipantSession.MeetingParticipantSessionKey,
545 Principal_ID = principalId,
548 context.ParticipantTrackings.InsertOnSubmit(pTrack);
550 context.SubmitChanges();
553 throw new ArgumentException("Principal ID: " + principalId + " is not valid");
555 } catch (Exception ex) {
556 Extensions.LogServiceError("TrackUser", ex);
560 private void CheckParticipantSessions(MeetingSession session, int principal_id) {
562 var context = Database;
563 var participantSessionCount =
564 session.MeetingParticipantSessions.Count(mps => mps.ParticipantKey == principal_id);
565 if(participantSessionCount > 1) {
566 var participantSessions =
567 session.MeetingParticipantSessions.Where(mps => mps.ParticipantKey == principal_id)
569 mps => mps.MeetingParticipantSessionKey);
570 var psToKeep = participantSessions.First();
571 var psessionsToDelete =
572 participantSessions.Where(
573 ps => ps.MeetingParticipantSessionKey != psToKeep.MeetingParticipantSessionKey);
575 foreach (var meetingParticipantSession in psessionsToDelete) {
576 context.MeetingParticipantSessions.DeleteOnSubmit(meetingParticipantSession);
578 context.SubmitChanges();
580 } catch (Exception ex) {
581 Extensions.LogServiceError("CheckParticipanSessions", ex);
585 private RecordingSession getActiveRecordingSession(int recordingScoId) {
586 //for SP3 if rs.StartTime < now + 1hr., recording considered "active", user will be placed into lobby
587 var now = DateTime.UtcNow;
588 var recording = Database.RecordingSessions.SingleOrDefault(rs => rs.RecordingSCO_ID == recordingScoId
589 && rs.StartTime <= now.AddHours(1) &&
595 private RecordingSession getNextRecordingSession(int recordingScoId) {
596 //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
597 var now = DateTime.UtcNow;
598 var recording = Database.RecordingSessions.Where(rs => rs.RecordingSCO_ID == recordingScoId
599 && rs.StartTime > now.AddHours(1))
600 .OrderBy(rs => rs.StartTime)
607 private void SaveModelState() {
608 TempData["ModelState"] = ModelState;
611 private void RestoreModelState() {
612 var previousModelState = TempData["ModelState"] as ModelStateDictionary;
613 if(previousModelState != null) {
614 foreach (KeyValuePair<string, ModelState> kvp in previousModelState)
615 if(!ModelState.ContainsKey(kvp.Key))
616 ModelState.Add(kvp.Key, kvp.Value);
619 TempData["ModelState"] = ModelState; //Add back into TempData
626 private void placeIntoLobby(int meetingSessionKey, string email, int certificateId) {
627 email = email?.Trim();
628 //rebroadcast/LobbyWait
629 Response.Redirect("/rebroadcast/LobbyWait?meetingSessionKey=" + meetingSessionKey + "&email=" + email + "&certificateId=" + certificateId, true);
634 public ActionResult GotoContent(int meetingSessionKey, string email, int certificateId) {
635 email = email?.Trim();
637 var now = DateTime.UtcNow;
638 var connectUrl = ConfigurationManager.AppSettings["Connect.Url"];
639 var accountId = int.Parse(ConfigurationManager.AppSettings["Connect.AccountId"]);
640 var password = Guid.NewGuid()
646 var participant = Database.Participants.FirstOrDefault(p => p.Email == email);
647 if(participant == null) {
648 Extensions.LogServiceCall("[RebroadcastController][GotoContent]", string.Format("participant found null; meetingSessionKey = {0} email = {1} certificateId = {2}", meetingSessionKey, email, certificateId));
649 throw new Exception("Login failed! " + email);
653 Database.RecordingSessions.FirstOrDefault(
654 rs => rs.MeetingSessionKey == meetingSessionKey && rs.StartTime <= now && rs.EndTime > now);
655 if(recording == null) {
656 Extensions.LogServiceCall("[RebroadcastController][GotoContent]", string.Format("recording found null; meetingSessionKey = {0} email = {1} certificateId = {2}", meetingSessionKey, email, certificateId));
657 throw new Exception("Login failed! " + email);
660 var meeting = Database.MeetingSessions.FirstOrDefault(y => y.MeetingSessionKey == meetingSessionKey);
661 if(meeting == null) {
662 Extensions.LogServiceCall("[RebroadcastController][GotoContent]", string.Format("meeting found null; meetingSessionKey = {0} email = {1} certificateId = {2}", meetingSessionKey, email, certificateId));
663 throw new Exception("Login failed! " + email);
666 var admin = AdobeMeetingConnection.GetAdobeAdminSession();
667 Login.ResetPassword(admin, participant.Principal_ID, password);
669 var session = Login.UserLogin(participant.Email, password, connectUrl, accountId);
671 var differenceInMilliseconds = (now - meeting.StartDate).TotalMilliseconds;
673 var recordingView = new RecordingView {
674 Name = AdobeMeetingConnection.getAdobeMeetingName(recording.RecordingUrl),
675 PrincipalId = participant.Principal_ID,
676 MeetingSessionKey = meeting.MeetingSessionKey,
677 FirstName = participant.FirstName,
678 LastName = participant.LastName,
679 Email = participant.Email,
680 QAlink = getWufooQAlink(recording, participant.Email, participant.FirstName, participant.LastName),
683 "{0}/{1}?session={2}&launcher=false&pbEIOpen=false&archiveOffset={3}",
685 recording.RecordingUrl,
686 session.SessionKey, differenceInMilliseconds), //+
687 //((passcode == null) ? "" : "&meeting-passcode=" + passcode)
688 CertificateId = certificateId
691 admin = AdobeMeetingConnection.GetAdobeAdminSession();
692 var request = new Request(admin, "principal-update");
693 request.Parameters.Add("first-name", participant.FirstName);
694 request.Parameters.Add("last-name", participant.LastName);
695 request.Parameters.Add("principal-id", participant.Principal_ID.ToString());
698 var idCookie = new HttpCookie("id") {
699 Value = participant.Principal_ID.ToString(),
700 Expires = DateTime.UtcNow.AddDays(1)
702 Response.Cookies.Add(idCookie);
704 TrackUserEntrance(meeting, participant.Principal_ID, participant.FirstName, participant.LastName,
706 return View("recording", recordingView);
709 //public string SendCert(int meetingSessionKey, int certificate_id, int principal_id)
711 // //TODO make outcome dictionary to return pass, fail, ineligible, or wonky:contact cust serv
712 // string _fail = "http://localhost:11038/Certificate?a=1179512338&b=20160128&c=1d633b";
713 // //string _fail = "FAIL";
715 // var meeting = Database.MeetingSessions.FirstOrDefault(x => x.MeetingSessionKey == meetingSessionKey);
718 // if (certificate_id > 0)
720 // ParticipantPurchase purchase =
721 // Database.ParticipantPurchases.FirstOrDefault(p => p.Purchase_ID == certificate_id && p.PrincipalID == principal_id);
723 // if (purchase == null)
725 // //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
726 // return _fail; // TODO probably return wonky, contact cust service message
729 // if (!purchase.EarnedCertificate)
731 // MeetingParticipantSession meetingParticipantSession =
732 // Database.MeetingParticipantSessions.FirstOrDefault(
733 // m => m.MeetingSessionKey == meetingSessionKey && m.ParticipantKey == principal_id);
734 // if (meetingParticipantSession == null)
736 // return _fail;//TODO return wonky
739 // List<ParticipantSessionsDataResult> participantSessionsDataResult =
740 // Database.ParticipantSessionsData(meetingSessionKey)
743 // var participantSessionsData =
744 // participantSessionsDataResult.OrderBy(p => p.MeetingParticipantSessionKey)
747 // p.MeetingParticipantSessionKey ==
748 // meetingParticipantSession.MeetingParticipantSessionKey);
750 // if (participantSessionsData == null)
752 // return _fail;//TODO is this a return wonky? it means they weren't tracked
756 // MeetingSessionsDataResult meetingSession = Database.MeetingSessionsData().FirstOrDefault(m => m.MeetingSessionKey == meetingSessionKey);
757 // if (meetingSession == null)
759 // return _fail;//TODO return wonky
762 // var courseLength = meetingSession.ActualSessionTime.GetValueOrDefault(); //in minutes
763 // double courseCredits = courseLength / 50.0; //1 credit per 50 minutes
764 // List<double> maxCourseCredits = ConfigurationManager.AppSettings["MaxCourseCreditList"].Split(';').Select(s => double.Parse(s)).ToList(); //max credits cut list
765 // int mx = maxCourseCredits.BinarySearch(courseCredits); //find appropriate max for this course
766 // double maxCredits = maxCourseCredits[mx >= 0 ? mx : ~mx - 1];//...by rounding down
767 // double realCredits = participantSessionsData.SessionCredit == null ? 0 : (double)participantSessionsData.SessionCredit.Value; //users credits per adobe
768 // purchase.Credits = Math.Min(maxCredits, realCredits); //user awarded no more than max possible credits for the course
770 // MeetingDetail meetingDetail =
771 // Database.MeetingDetails.FirstOrDefault(m => m.MeetingKey == purchase.MeetingSco);
773 // purchase.Presenter = meetingDetail == null ? "" : meetingDetail.Instructor;
775 // double percentComplete = (participantSessionsData.SessionEngagementCount.GetValueOrDefault() == 0 ?
776 // 1 : (participantSessionsData.SessionHeartbeatCount.GetValueOrDefault() / participantSessionsData.SessionEngagementCount.Value));
778 // if (percentComplete >= .75) //threshold for earning a certificate is 75% response rate
780 // purchase.EarnedCertificate = true;
783 // Database.SubmitChanges();
785 // if (purchase.EarnedCertificate)
787 // //TODO with return Pass dictionary value as string.format with replace of certUrl
788 // //string certUrl = AdobeCertificateHelper.SendWebcastCert(purchase);
789 // //format the outcome.pass.value message with certUrl replace
790 // //return outcome.pass with its value
791 // return AdobeCertificateHelper.SendWebcastCert(purchase);
793 // //TODO return outcome.fail
794 // return AdobeCertificateHelper.SendFailNotice(purchase);
798 // return _fail;// TODO return ineligible. need to make AdobeCertificateHelper.SendIneligibleNotice(principalId)
803 /// <param name="loginInfo"></param>
804 /// <returns></returns>
805 private int getConnectUser(loginInfo loginInfo) {
806 var password = Guid.NewGuid()
811 var admin = AdobeMeetingConnection.GetAdobeAdminSession();
812 var request = new Request(admin, "principal-list");
813 request.Parameters.Add("filter-type", "guest");
814 request.Parameters.Add("filter-type", "user");
815 request.Parameters.Add("filter-login", loginInfo.email);
816 if(request.Execute() && request.Status == Status.OK) {
818 if(request.XmlResults.SelectSingleNode("//principal") == null) {
820 principalId = Login.CreateGuest(admin, loginInfo.email, password, loginInfo.email, loginInfo.firstname, loginInfo.lastname);
824 int.Parse(request.XmlResults.SelectSingleNode("//principal")
825 .Attributes["principal-id"].Value);
826 loginInfo.email = request.XmlResults.SelectSingleNode("//principal/login")
828 if(request.XmlResults.SelectSingleNode("//principal")
829 .Attributes["type"].Value == "user") {
830 ModelState.AddModelError("email", "Invalid email.");
833 throw new Exception("Login failed!");
836 if(principalId < 1) {
837 throw new Exception("Login failed!");
840 Login.ResetPassword(admin, principalId, password);
844 throw new Exception("Login failed!");
849 /// <param name="loginInfo"></param>
850 /// <param name="principalId"></param>
851 /// <returns></returns>
852 private int addAdobeConnectPermissions(loginInfo loginInfo, int principalId) {
853 var admin = AdobeMeetingConnection.GetAdobeAdminSession();
854 var meetingXml = AdobeMeetingConnection.getAdobeMeeting(loginInfo.meetingUrl);
855 var recordingId = int.Parse(meetingXml.SelectSingleNode("//sco")
856 .Attributes["sco-id"].Value);
857 var request = new Request(admin, "permissions-update");
858 request.Parameters.Add("acl-id", recordingId.ToString());
859 request.Parameters.Add("principal-id", principalId.ToString());
860 request.Parameters.Add("permission-id", "view");
861 if(request.Execute() && request.Status == Status.OK) {
864 throw new Exception("Login failed!");
869 /// <param name="loginInfo"></param>
870 /// <param name="recordingId"></param>
871 /// <returns></returns>
872 private recordingResult getRecording(ref loginInfo loginInfo, int recordingId) {
873 var now = DateTime.UtcNow;
875 Database.RecordingSessions.SingleOrDefault(
876 rs => rs.RecordingSCO_ID == recordingId && rs.StartTime <= now && rs.EndTime > now);
878 if(recording == null) {
880 Database.RecordingSessions.SingleOrDefault(
882 rs.RecordingSCO_ID == recordingId && rs.StartTime <= now.AddHours(1) &&
885 if(recording == null) {
886 loginInfo.meetingSessionKey = 0;
887 return recordingResult.None;
889 loginInfo.meetingSessionKey = recording.MeetingSessionKey.Value;
890 return recordingResult.Lobby;
892 loginInfo.meetingSessionKey = recording.MeetingSessionKey.Value;
893 return recordingResult.Now;
898 /// <param name="loginInfo"></param>
899 /// <param name="principalId"></param>
900 private void saveParticipant(loginInfo loginInfo, int principalId) {
902 Database.Participants.SingleOrDefault(p => p.Principal_ID == principalId);
903 if(participant == null) {
904 participant = new Participant {
905 Principal_ID = principalId,
906 FirstName = loginInfo.firstname,
907 LastName = loginInfo.lastname,
908 Email = loginInfo.email
910 Database.Participants.InsertOnSubmit(participant);
912 participant.FirstName = loginInfo.firstname;
913 participant.LastName = loginInfo.lastname;
915 Database.SubmitChanges();
918 private int savePurchaseInfo(loginInfo loginInfo, string purchaseDate, int principalId, string ticketFromUrl, int meetingSessionKey) {
919 purchaseDate = purchaseDate?.Trim();
920 ticketFromUrl = ticketFromUrl?.Trim();
922 //purchase indicates hashed-ticket login that could earn a certificate. storing this info separate since participant name info gets updated based on adobe info
923 //and per cpe, a cert can only be earned in the exact name of purchaser.
925 Database.MeetingSessions.SingleOrDefault(
926 ms => ms.MeetingSessionKey == meetingSessionKey);
927 string formattedPdate = purchaseDate.Substring(0, 4) + '-' +
928 purchaseDate.Substring(4, 2) +
929 '-' + purchaseDate.Substring(6, 2);
930 DateTime pDate = Convert.ToDateTime(formattedPdate);
932 ParticipantPurchase purchase =
933 Database.ParticipantPurchases.SingleOrDefault(
935 p.PrincipalID == principalId & p.Ticket == ticketFromUrl &
936 p.MeetingSco == meeting.SCO_ID);
937 if(purchase == null) {
938 purchase = new ParticipantPurchase {
939 FirstName = loginInfo.firstname,
940 LastName = loginInfo.lastname,
941 Email = loginInfo.email,
942 PrincipalID = principalId,
943 MeetingName = meeting.Name,
944 MeetingDate = meeting.StartDate,
945 MeetingSco = meeting.SCO_ID,
946 Ticket = ticketFromUrl,
947 PurchaseDate = pDate,
948 EarnedCertificate = false,
951 Database.ParticipantPurchases.InsertOnSubmit(purchase);
953 Database.SubmitChanges();
955 return purchase.Purchase_ID;
961 public class loginInfo {
962 //string meetingUrl, string firstname, string lastname, string email,
963 // string ticket, string passcode, string ticketFromUrl, string purchaseDate
965 public string meetingUrl { get; set; }
966 public string firstname { get; set; }
967 public string lastname { get; set; }
968 public string email { get; set; }
969 public string ticket { get; set; }
970 public string passcode { get; set; }
971 public string ticketFromUrl { get; set; }
972 public string purchaseDate { get; set; }
973 public int meetingSessionKey { get; set; }
978 public enum recordingResult {