2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Configuration;
5 using System.Diagnostics;
7 using System.Threading;
9 using System.Web.Services;
10 using CPE.App.Web.Code;
11 using CPE.App.Web.Models;
16 Tyler Allen - 08/22/2016
18 I have commented out the section that was executing the thread within the application pool process
19 The new method calls a console application with the session variables
20 This will run outside the application pool
24 namespace CPE.App.Web.Static.services.engagement {
26 /// Summary description for engagement
28 [WebService(Namespace = "http://cpeengagement.com/static/services/engagement/service/")]
29 [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
31 // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
32 // [System.Web.Script.Services.ScriptService]
33 public class service : BaseWebService {
35 private string notifyFilePath {
36 get { return ConfigurationManager.AppSettings["NotifyFilePath"]; }
41 public Setting GetMeetingSettings(int sco_id) {
42 Extensions.LogServiceCall("[service][GetMeetingSettings]", string.Format("Parameters: sco_id = {0}", sco_id));
43 var result = new Setting {
48 var meetingSetting = Database.MeetingSettings.SingleOrDefault(ms => ms.MeetingKey == sco_id);
49 if(meetingSetting != null) {
50 result.Interval = meetingSetting.Interval.HasValue
51 ? meetingSetting.Interval.Value
53 result.Text = meetingSetting.Text;
54 result.Duration = meetingSetting.Duration.HasValue
55 ? meetingSetting.Duration.Value
62 public ServiceStatus SetMeetingSettings(int sco_id, int interval, string text, int duration) {
63 Extensions.LogServiceCall("SetMeetingSettings", string.Format("Parameters: sco_id = {0} interval = {1} text = {2} duration = {3}", sco_id, interval, text, duration));
64 var result = new ServiceStatus {
69 var context = Database;
70 var existing = context.Meetings.SingleOrDefault(m => m.SCO_ID == sco_id);
71 if(existing != null) {
72 if(existing.MeetingSetting == null) {
73 var meetingSetting = new MeetingSetting {
79 context.MeetingSettings.InsertOnSubmit(meetingSetting);
81 existing.MeetingSetting.Interval = interval;
82 existing.MeetingSetting.Text = text;
83 existing.MeetingSetting.Duration = duration;
86 var meeting = new Meeting {
90 var meetingSetting = new MeetingSetting();
91 meetingSetting.Interval = interval;
92 meetingSetting.Text = text;
93 meetingSetting.Duration = duration;
94 meetingSetting.MeetingKey = sco_id;
95 context.Meetings.InsertOnSubmit(meeting);
96 context.MeetingSettings.InsertOnSubmit(meetingSetting);
98 context.SubmitChanges();
99 } catch (Exception ex) {
100 Extensions.LogServiceError("SetMeetingSettings", ex);
101 result.Success = false;
102 result.Message = ex.Message;
108 public SessionStatusClass SessionStatus(int sco_id) {
109 Extensions.LogServiceCall("[service][SessionStatus]", string.Format("Parameters: sco_id = {0}", sco_id));
110 var result = new SessionStatusClass {
111 MeetingSessionKey = -1,
112 OwnerPrincipalId = -1,
116 var context = Database;
117 var existingSession =
118 context.MeetingSessions.Where(ms => ms.SCO_ID == sco_id && !ms.EndDate.HasValue)
119 .OrderByDescending(ms => ms.StartDate)
121 if(existingSession != null) {
122 result.MeetingSessionKey = existingSession.MeetingSessionKey;
123 result.OwnerPrincipalId = existingSession.OwnerPrincipal_ID;
124 var isPaused = existingSession.MeetingSessionPauses.Count(me => !me.EndDate.HasValue) > 0;
125 if(existingSession.EndDate.HasValue) {
126 result.Status = "complete";
127 } else if(!existingSession.EndDate.HasValue && existingSession.StartDate < DateTime.UtcNow && !isPaused) {
128 result.Status = "active";
129 } else if(isPaused) {
130 result.Status = "pause";
133 } catch (Exception ex) {
134 Extensions.LogServiceError("SessionStatus", ex);
135 result.OwnerPrincipalId = -1;
136 result.Status = "error";
142 public int StartSession(int sco_id, string name, int owner_principal_id) {
143 Extensions.LogServiceCall("StartSession", string.Format("Parameters: sco_id = {0} name= {1} owner_principal_id = {2}", sco_id, name, owner_principal_id));
146 var context = Database;
147 var existingSession =
148 context.MeetingSessions.Where(ms => ms.SCO_ID == sco_id && !ms.EndDate.HasValue)
149 .OrderByDescending(ms => ms.StartDate)
151 if(existingSession == null) {
153 var meeting = context.Meetings.SingleOrDefault(m => m.SCO_ID == sco_id);
154 if(meeting == null) {
155 meeting = new Meeting {
159 context.Meetings.InsertOnSubmit(meeting);
160 var meetingSettings = new MeetingSetting {
165 context.MeetingSettings.InsertOnSubmit(meetingSettings);
166 var meetingDetails = new MeetingDetail {
174 context.MeetingDetails.InsertOnSubmit(meetingDetails);
176 var session = new MeetingSession {
179 StartDate = DateTime.UtcNow, //start
180 OwnerPrincipal_ID = owner_principal_id
182 context.MeetingSessions.InsertOnSubmit(session);
183 context.SubmitChanges();
184 result = session.MeetingSessionKey;
185 //check for multiple sessions
186 var existingSessionCount = context.MeetingSessions.Count(ms => ms.SCO_ID == sco_id && !ms.EndDate.HasValue);
187 if(existingSessionCount > 1) {
188 //there should only be one session
189 var existingSessions = context.MeetingSessions.Where(ms => ms.SCO_ID == sco_id && !ms.EndDate.HasValue)
190 .OrderBy(ms => ms.MeetingSessionKey);
191 var sessionToKeep = existingSessions.First();
192 var sessionsToDelete =
193 existingSessions.Where(ms => ms.MeetingSessionKey != sessionToKeep.MeetingSessionKey);
194 foreach (var meetingSession in sessionsToDelete) {
195 if(meetingSession.MeetingParticipantSessions.Any() || meetingSession.MeetingSessionHeartbeats.Any()) {
196 //session has data, do not delete it
198 context.MeetingSessions.DeleteOnSubmit(meetingSession);
202 context.SubmitChanges();
203 } catch (Exception ex) {
204 Extensions.LogServiceError("StartSession", ex);
208 //session already exists, this should not happen!
209 //string existingSessionKeys = string.Join(",", context.MeetingSessions.Where(ms => ms.SCO_ID == sco_id && !ms.EndDate.HasValue).Select(ms => ms.MeetingSessionKey).ToArray());
210 //throw new ArgumentException(String.Format("Trying to start a session which already exists. sco_id = {0}, meetingSessionKeys = {1}", sco_id, existingSessionKeys));
211 result = existingSession.MeetingSessionKey;
213 } catch (Exception ex) {
214 Extensions.LogServiceError("StartSession", ex);
221 private void startNotify(string args) {
222 var startinfo = new ProcessStartInfo
224 FileName = $"{notifyFilePath}",
225 CreateNoWindow = true,
226 UseShellExecute = false,
227 WindowStyle = ProcessWindowStyle.Hidden,
230 var process = Process.Start(startinfo);
231 process.WaitForExit(0);
236 public int StopSession(int sessionKey, DateTime end) {
237 Extensions.LogServiceCall("[service.asmx][StopSession]", string.Format("Parameters: sessionKey = {0} end = {1}", sessionKey, end.ToString("yyyy-MM-dd HH:mm:ss.fff")));
239 var session = Database.MeetingSessions.Single(ms => ms.MeetingSessionKey == sessionKey);
242 session.EndDate = DateTime.UtcNow; //end
243 var participants = Database.MeetingParticipantSessions.Where(m => m.MeetingSessionKey == session.MeetingSessionKey);
244 foreach (var participantSession in participants) {
245 foreach (var participantTracking in participantSession.ParticipantTrackings.Where(t => !t.EndDate.HasValue)) {
246 participantTracking.EndDate = session.EndDate;
250 adobe.GetAdobeTransactions(session, Database);
251 // Tyler Allen - 08/27/2016
252 // This is redundant and will cause deadlocks
253 //Database.SubmitChanges();
255 result = session.MeetingSessionKey;
256 CleanupSessionEngagements(session.MeetingSessionKey);
262 catch (Exception ex) {
263 Extensions.LogServiceError("[service.asmx][StopSession]", ex);
267 /* This is the new modifications created by Tyler Allen [08/22/2016] */
269 // TODO: Depricated for new Notify application
270 // Launch a non-blocking thread to wait for 30 minutes for adobe results then email certificates
271 // var waitForResultsThread = new Thread(() => StopSessionResultsThread(session));
272 // waitForResultsThread.Start();
277 Extensions.LogServiceCall("[service.asmx][StopSession][CPE.App.Notify.exe]", $"Processing CPE.App.Notify.exe [{notifyFilePath} -u -s {session.MeetingSessionKey}]");
278 //Process.Start($"{notifyFilePath} -u -s {session.MeetingSessionKey}");
279 startNotify($"-u -s {session.MeetingSessionKey}");
280 Extensions.LogServiceCall("[service.asmx][StopSession][CPE.App.Notify.exe]", $"Started CPE.App.Notify.exe [{notifyFilePath} -u -s {session.MeetingSessionKey}]");
281 } catch (Exception exception) {
282 Extensions.LogServiceError("[service.asmx][StopSession][CPE.App.Notify.exe]", exception);
285 /* This is the new modifications created by Tyler Allen [08/22/2016] */
291 public int PauseSession(int sessionKey, DateTime start) {
292 Extensions.LogServiceCall("PauseSession", string.Format("Parameters: sessionKey = {0} start= {1}", sessionKey, start.ToString("yyyy-MM-dd HH:mm:ss.fff")));
295 var context = Database;
296 var sessionEvent = new MeetingSessionPause {
297 MeetingSessionKey = sessionKey,
298 StartDate = DateTime.UtcNow //start
300 context.MeetingSessionPauses.InsertOnSubmit(sessionEvent);
301 context.SubmitChanges();
302 result = sessionEvent.MesstingSessionPauseKey;
303 } catch (Exception ex) {
304 Extensions.LogServiceError("PauseSession", ex);
311 public int GetPauseKey(int sco_id) {
312 Extensions.LogServiceCall("GetPauseKey", string.Format("Parameters: sco_id = {0}", sco_id));
315 var context = Database;
316 var existingSession =
317 context.MeetingSessions.Where(ms => ms.SCO_ID == sco_id && !ms.EndDate.HasValue)
318 .OrderByDescending(ms => ms.StartDate)
320 if(existingSession != null) {
321 var pause = existingSession.MeetingSessionPauses.Where(mse => !mse.EndDate.HasValue)
323 mse => mse.StartDate)
325 result = pause.MesstingSessionPauseKey;
328 } catch (Exception ex) {
329 Extensions.LogServiceError("GetPauseKey", ex);
336 public int ResumeSession(int eventKey, DateTime end) {
337 Extensions.LogServiceCall("ResumeSession", string.Format("Parameters: eventKey = {0} end = {1}", eventKey, end.ToString("yyyy-MM-dd HH:mm:ss.fff")));
340 var context = Database;
341 var sessionEvent = context.MeetingSessionPauses.Single(se => se.MesstingSessionPauseKey == eventKey);
342 sessionEvent.EndDate = DateTime.UtcNow; //end;
343 context.SubmitChanges();
344 result = sessionEvent.MesstingSessionPauseKey;
345 } catch (Exception ex) {
346 Extensions.LogServiceError("ResumeSession", ex);
353 public ServiceStatus LogEngagement(int meetingSessionKey) {
354 Extensions.LogServiceCall("LogEngagement", string.Format("Parameters: meetingSessionKey = {0}", meetingSessionKey));
355 var result = new ServiceStatus {
360 var context = Database;
361 var record = new MeetingSessionHeartbeat {
362 MeetingSessionKey = meetingSessionKey,
363 Timestamp = DateTime.UtcNow
365 context.MeetingSessionHeartbeats.InsertOnSubmit(record);
366 context.SubmitChanges();
367 } catch (Exception ex) {
368 Extensions.LogServiceError("LogEngagement", ex);
369 result.Success = false;
370 result.Message = ex.Message;
376 public ServiceStatus TrackUser(int meetingSessionKey, int principal_id, string firstname, string lastname, string email, byte type) {
377 Extensions.LogServiceCall("TrackUser", string.Format("Parameters: meetingSessionKey = {0} principal_id= {1} firstname = {2}, lastname = {3} email = {4} type = {5} DateTimeUtc = {6}", meetingSessionKey, principal_id, firstname, lastname, email, type, DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff")));
378 var result = new ServiceStatus {
383 if(principal_id > 0) {
384 var context = Database;
385 //var meeting = context.Meetings.SingleOrDefault(m => m.SCO_ID == sco_id);
386 //JM - 9/27/2012 changed session to add a check for session not ended
388 // context.MeetingSessions.SingleOrDefault(ms => ms.MeetingSessionKey == meetingSessionKey && !ms.EndDate.HasValue);
389 //JM - 11/20/2012 changed to allow for end dates existing for recordings
390 var session = getActiveSessionByKey(meetingSessionKey);
391 if(session != null) {
392 var user = context.Participants.SingleOrDefault(p => p.Principal_ID == principal_id);
395 user = new Participant {
396 Principal_ID = principal_id,
397 FirstName = firstname,
401 context.Participants.InsertOnSubmit(user);
405 // user.FirstName = firstname;
406 // user.LastName = lastname;
407 // user.Email = email;
409 //JM 9/27/2012 - changed to grab first participant session found. Weird issue where some users were getting multiple sesions
410 var existingMeetingParticipantSession = session.MeetingParticipantSessions.OrderBy(mps => mps.MeetingParticipantSessionKey)
411 .FirstOrDefault(mps => mps.ParticipantKey == principal_id);
412 if(existingMeetingParticipantSession == null) {
413 //create new session for user
414 existingMeetingParticipantSession = new MeetingParticipantSession {
415 MeetingSessionKey = session.MeetingSessionKey,
416 ParticipantKey = principal_id,
418 Created = DateTime.UtcNow
420 context.MeetingParticipantSessions.InsertOnSubmit(existingMeetingParticipantSession);
421 context.SubmitChanges();
422 //JM-12/27/2012 Change to check for multiple meeting participant sessions
423 CheckParticipantSessions(session, principal_id);
424 //make sure tracking gets assigned right key
425 existingMeetingParticipantSession = context.MeetingParticipantSessions.OrderBy(p => p.MeetingParticipantSessionKey)
427 p => p.MeetingSessionKey == session.MeetingSessionKey & p.ParticipantKey == principal_id);
429 var lastParticipantTracking =
430 context.ParticipantTrackings.Where(
432 pt.MeetingParticipantSessionKey ==
433 existingMeetingParticipantSession.MeetingParticipantSessionKey &&
434 pt.Principal_ID == principal_id)
435 .OrderByDescending(p => p.StartDate)
439 if(lastParticipantTracking != null && !lastParticipantTracking.EndDate.HasValue) {
440 var lastEngagement = lastParticipantTracking.MeetingParticipantSession.ParticipantEngagements.OrderByDescending(e => e.DisplayTime)
442 if(lastEngagement == null)
443 lastParticipantTracking.EndDate = lastParticipantTracking.StartDate;
445 lastParticipantTracking.EndDate = lastEngagement.ResponseTime.HasValue
446 ? lastEngagement.ResponseTime.Value
447 : lastEngagement.DisplayTime;
448 if(lastParticipantTracking.EndDate < lastParticipantTracking.StartDate)
449 lastParticipantTracking.EndDate = lastParticipantTracking.StartDate;
452 var pTrack = new ParticipantTracking {
453 MeetingParticipantSessionKey =
454 existingMeetingParticipantSession.MeetingParticipantSessionKey,
455 Principal_ID = principal_id,
456 StartDate = DateTime.UtcNow //timestamp
458 context.ParticipantTrackings.InsertOnSubmit(pTrack);
461 if(lastParticipantTracking == null)
462 throw new ArgumentException(string.Format("Exiting user does not have an entrance time MeetingSessionKey = {0}, principalId = {1}", meetingSessionKey, principal_id));
463 lastParticipantTracking.EndDate = DateTime.UtcNow;
465 context.SubmitChanges();
466 CheckParticipantSessions(session, principal_id);
468 result.Success = false;
469 result.Message = "MeetingSessionKey: " + meetingSessionKey + " is not valid";
470 throw new ArgumentException(result.Message);
473 result.Success = false;
474 result.Message = "Principal ID: " + principal_id + " is not valid";
475 throw new ArgumentException(result.Message);
477 } catch (Exception ex) {
478 Extensions.LogServiceError("TrackUser", ex);
479 result.Success = false;
480 result.Message = ex.Message;
486 public int TrackEngagementReceived(int scoId, int principalId, double timeDelta) {
487 Extensions.LogServiceCall("TrackEngagementReceived", string.Format("Parameters: scoId = {0} principalId = {1} timeDelta = {2} DateTimeUtc = {3}", scoId, principalId, timeDelta, DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff")));
489 var context = Database;
491 if(principalId > 0) {
492 //var session = context.MeetingSessions.OrderByDescending(ms => ms.StartDate).FirstOrDefault(m => m.SCO_ID == scoId & !m.EndDate.HasValue);
493 //JM - 11/20/2012 changed to allow for session end dates existing for recordings
494 var session = getActiveSessionBySco(scoId);
495 if(session != null) {
496 CheckParticipantSessions(session, principalId);
497 var participantSession =
498 context.MeetingParticipantSessions.OrderBy(p => p.MeetingParticipantSessionKey)
502 p.MeetingSessionKey == session.MeetingSessionKey & p.ParticipantKey == principalId);
503 if(participantSession == null) {
504 participantSession = new MeetingParticipantSession {
505 MeetingSessionKey = session.MeetingSessionKey,
506 ParticipantKey = principalId,
508 Created = DateTime.UtcNow
510 context.MeetingParticipantSessions.InsertOnSubmit(participantSession);
511 context.SubmitChanges();
512 //JM-12/27/2012 Change to check for multiple meeting participant sessions
513 CheckParticipantSessions(session, principalId);
514 participantSession = context.MeetingParticipantSessions.OrderBy(
515 p => p.MeetingParticipantSessionKey)
518 p.MeetingSessionKey == session.MeetingSessionKey & p.ParticipantKey == principalId);
519 //Check Participant Tracking
520 CheckParticipantTracking(participantSession, principalId);
524 // //Check Participant Tracking
525 // CheckParticipantTracking(participantSession, principalId);
527 var now = DateTime.UtcNow;
528 var engagementVerification = new ParticipantEngagementVerification {
529 MeetingParticipantSessionKey =
530 participantSession.MeetingParticipantSessionKey,
531 Principal_ID = principalId,
533 PreviousAlertDelta = timeDelta
535 context.ParticipantEngagementVerifications.InsertOnSubmit(engagementVerification);
536 context.SubmitChanges();
537 result = engagementVerification.TrackingKey;
539 throw new ArgumentException(string.Format("No session exists for sco = {0}, principal_id = {1}", scoId, principalId));
542 throw new ArgumentException("Principal ID: " + principalId + " is not valid");
544 } catch (Exception ex) {
545 Extensions.LogServiceError("TrackEngagementReceived", ex);
552 public int TrackEngagementDisplay(int scoId, int principalId) {
553 Extensions.LogServiceCall("TrackEngagementDisplay", string.Format("Parameters: scoId = {0} principalId = {1} DateTimeUtc = {2}", scoId, principalId, DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff")));
556 if(principalId > 0) {
557 var context = Database;
558 //var session = context.MeetingSessions.OrderByDescending(ms => ms.StartDate).FirstOrDefault(m => m.SCO_ID == scoId & !m.EndDate.HasValue);
559 //JM - 11/20/2012 changed to allow for session end dates existing for recordings
560 var session = getActiveSessionBySco(scoId);
561 if(session != null) {
562 CheckParticipantSessions(session, principalId);
563 var participantSession =
564 context.MeetingParticipantSessions.OrderBy(p => p.MeetingParticipantSessionKey)
566 p => p.MeetingSessionKey == session.MeetingSessionKey & p.ParticipantKey == principalId);
567 if(participantSession == null) {
568 participantSession = new MeetingParticipantSession {
569 MeetingSessionKey = session.MeetingSessionKey,
570 ParticipantKey = principalId,
572 Created = DateTime.UtcNow
574 context.MeetingParticipantSessions.InsertOnSubmit(participantSession);
575 context.SubmitChanges();
576 //JM-12/27/2012 Change to check for multiple meeting participant sessions
577 CheckParticipantSessions(session, principalId);
578 //make sure tracking gets assigned right key
579 participantSession = context.MeetingParticipantSessions.OrderBy(p => p.MeetingParticipantSessionKey)
581 p => p.MeetingSessionKey == session.MeetingSessionKey & p.ParticipantKey == principalId);
582 //Check Participant Tracking
583 CheckParticipantTracking(participantSession, principalId);
585 //Check Participant Tracking
586 CheckParticipantTracking(participantSession, principalId);
588 //var validEngagement = false;
589 ////Validate the engangement request to make sure it was sent by the host within the last 30 seconds
590 //var now = DateTime.UtcNow;
591 //var hostPoll = session.MeetingSessionHeartbeats.OrderByDescending(h => h.Timestamp).FirstOrDefault();
592 //if (hostPoll != null)
594 // var timeDelta = Math.Abs((now - hostPoll.Timestamp).TotalSeconds);
595 // validEngagement = timeDelta <= 30.0;
597 //if (validEngagement)
599 // var engagement = new ParticipantEngagement()
601 // MeetingParticipantSessionKey =
602 // participantSession.MeetingParticipantSessionKey,
603 // Principal_ID = principalId,
606 // context.ParticipantEngagements.InsertOnSubmit(engagement);
607 // context.SubmitChanges();
608 // result = engagement.ParticipantEngagementKey;
610 var lastHeartbeat = session.MeetingSessionHeartbeats.OrderBy(h => h.Timestamp)
612 var lastEngagement = participantSession.ParticipantEngagements.Where(t => t.Principal_ID == principalId)
613 .OrderBy(t => t.DisplayTime)
615 if(lastEngagement == null || lastEngagement.DisplayTime < lastHeartbeat.Timestamp) {
616 var now = DateTime.UtcNow;
617 var engagement = new ParticipantEngagement {
618 MeetingParticipantSessionKey =
619 participantSession.MeetingParticipantSessionKey,
620 Principal_ID = principalId,
623 context.ParticipantEngagements.InsertOnSubmit(engagement);
624 context.SubmitChanges();
625 result = engagement.ParticipantEngagementKey;
627 result = lastEngagement.ParticipantEngagementKey;
629 throw new ArgumentException(string.Format("No session exists for sco = {0}, principal_id = {1}", scoId,
633 throw new ArgumentException("Principal ID: " + principalId + " is not valid");
635 } catch (Exception ex) {
636 Extensions.LogServiceError("TrackEngagementDisplay", ex);
643 public int TrackEngagementResponse(int scoId, int principalId) //int engagementKey
645 Extensions.LogServiceCall("TrackEngagementResponse", string.Format("Parameters: scoId = {0} principalId = {1} DateTimeUtc = {2}", scoId, principalId, DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff")));
648 if(principalId > 0) {
649 var context = Database;
650 var now = DateTime.UtcNow;
651 //JM - 9-21-2012 changing to ignore key - will require updating pod
652 //var engagement = context.ParticipantEngagements.Single(pe => pe.ParticipantEngagementKey == engagementKey);
654 // Database.MeetingSessions.OrderByDescending(ms => ms.StartDate).FirstOrDefault(ms => ms.SCO_ID == scoId && !ms.EndDate.HasValue);
655 //JM - 11/20/2012 changed to allow for session end dates existing for recordings
656 var session = getActiveSessionBySco(scoId);
657 if(session != null) {
658 CheckParticipantSessions(session, principalId);
659 //JM - 9-27-2012 Changed to grab first session. Fix for weird issue where some users were getting mutiple user sessions in a meeting.
660 var participantSession = context.MeetingParticipantSessions.Where(mps =>
661 mps.MeetingSessionKey == session.MeetingSessionKey &&
662 mps.ParticipantKey == principalId)
663 .OrderBy(mps => mps.MeetingParticipantSessionKey)
665 //var participantSession =
666 // context.MeetingParticipantSessions.Single(
668 // mps.MeetingSessionKey == session.MeetingSessionKey && mps.ParticipantKey == principalId);
669 if(participantSession == null) {
670 //create participant session
671 participantSession = new MeetingParticipantSession {
672 MeetingSessionKey = session.MeetingSessionKey,
673 ParticipantKey = principalId,
675 Created = DateTime.UtcNow
677 context.MeetingParticipantSessions.InsertOnSubmit(participantSession);
678 context.SubmitChanges();
679 //JM-12/27/2012 Change to check for multiple meeting participant sessions
680 CheckParticipantSessions(session, principalId);
681 participantSession = context.MeetingParticipantSessions.OrderBy(p => p.MeetingParticipantSessionKey)
683 p => p.MeetingSessionKey == session.MeetingSessionKey & p.ParticipantKey == principalId);
684 //Check Participant Tracking
685 CheckParticipantTracking(participantSession, principalId);
687 //Check Participant Tracking
688 CheckParticipantTracking(participantSession, principalId);
690 //find last engagement without a response within 90 seconds
691 var participantEngagement = context.ParticipantEngagements.OrderByDescending(pe => pe.DisplayTime)
695 pe.MeetingParticipantSessionKey == participantSession.MeetingParticipantSessionKey
696 && (Math.Abs((now - pe.DisplayTime).TotalSeconds) <= 90)
697 && !pe.ResponseTime.HasValue);
698 if(participantEngagement != null) {
700 participantEngagement.ResponseTime = now;
704 // //not found, create new engagement
705 // participantEngagement = new ParticipantEngagement()
707 // MeetingParticipantSessionKey =
708 // participantSession.MeetingParticipantSessionKey,
709 // Principal_ID = principalId,
710 // DisplayTime = now,
711 // ResponseTime = now
713 // context.ParticipantEngagements.InsertOnSubmit(participantEngagement);
715 context.SubmitChanges();
716 result = 1; //participantEngagement.ParticipantEngagementKey;
718 throw new ArgumentException(string.Format("No session exists for sco = {0}, principal_id = {1}", scoId,
722 throw new ArgumentException("Principal ID: " + principalId + " is not valid");
724 } catch (Exception ex) {
725 Extensions.LogServiceError("TrackEngagementResponse", ex);
732 public Detail GetMeetingDetails(int sco_id) {
733 Extensions.LogServiceCall("[service][GetMeetingDetails]", string.Format("Parameters: sco_id = {0}", sco_id));
734 var result = new Detail {
741 var meetingDetail = Database.MeetingDetails.SingleOrDefault(ms => ms.MeetingKey == sco_id);
742 if(meetingDetail != null) {
743 result.CourseCode = meetingDetail.CourseCode;
744 result.Instructor = meetingDetail.Instructor;
745 result.Location = meetingDetail.Location;
746 result.TopicID = meetingDetail.TopicID;
747 result.Topic = meetingDetail.TopicName;
753 public ServiceStatus SetMeetingDetails(int sco_id, string courseCode, string instructor, string location, string topicID, string topic) {
754 Extensions.LogServiceCall("SetMeetingDetails", string.Format("Parameters: sco_id = {0}, courseCode = {1} instructor = {2} location = {3} topicId = {4} topic = {5}", sco_id, courseCode, instructor, location, topicID, topic));
755 var result = new ServiceStatus {
760 var context = Database;
761 var existing = context.Meetings.SingleOrDefault(m => m.SCO_ID == sco_id);
762 if(existing != null) {
763 if(existing.MeetingDetail == null) {
764 var meetingDetail = new MeetingDetail {
766 CourseCode = courseCode,
767 Instructor = instructor,
772 context.MeetingDetails.InsertOnSubmit(meetingDetail);
774 existing.MeetingDetail.CourseCode = courseCode;
775 existing.MeetingDetail.Instructor = instructor;
776 existing.MeetingDetail.Location = location;
777 existing.MeetingDetail.TopicID = topicID;
778 existing.MeetingDetail.TopicName = topic;
781 var meeting = new Meeting {
785 var meetingDetail = new MeetingDetail();
786 meetingDetail.CourseCode = courseCode;
787 meetingDetail.Instructor = instructor;
788 meetingDetail.Location = location;
789 meetingDetail.TopicID = topicID;
790 meetingDetail.TopicName = topic;
791 meetingDetail.MeetingKey = sco_id;
792 context.Meetings.InsertOnSubmit(meeting);
793 context.MeetingDetails.InsertOnSubmit(meetingDetail);
795 context.SubmitChanges();
796 } catch (Exception ex) {
797 Extensions.LogServiceError("SetMeetingDetails", ex);
798 result.Success = false;
799 result.Message = ex.Message;
805 public long GetTotalSessionTime(int sco_id) {
806 Extensions.LogServiceCall("GetTotalSessionTime", string.Format("Parameters: sco_id = {0}", sco_id));
810 var context = Database;
811 var session = context.MeetingSessions.Where(ms => ms.SCO_ID == sco_id && !ms.EndDate.HasValue)
812 .OrderByDescending(ms => ms.StartDate)
814 if(session != null) {
815 if(session.EndDate.HasValue) {
816 result = session.EndDate.Value.Ticks - session.StartDate.Ticks;
818 result = DateTime.UtcNow.Ticks - session.StartDate.Ticks;
820 var completedPauses = session.MeetingSessionPauses.Where(msp => msp.EndDate.HasValue);
821 result = completedPauses.Aggregate(result, (current, meetingSessionPause) => current - (meetingSessionPause.EndDate.Value.Ticks - meetingSessionPause.StartDate.Ticks));
822 var incompletePause = session.MeetingSessionPauses.Where(msp => !msp.EndDate.HasValue)
823 .OrderByDescending(msp => msp.StartDate)
825 if(incompletePause != null) {
826 result -= DateTime.UtcNow.Ticks - incompletePause.StartDate.Ticks;
829 result = result/TimeSpan.TicksPerMillisecond;
830 } catch (Exception ex) {
831 Extensions.LogServiceError("GetTotalSessionTime", ex);
838 public int ActiveSessionCount(int sco_id) {
839 Extensions.LogServiceCall("ActiveSessionCount", string.Format("Parameters: sco_id = {0}", sco_id));
842 var context = Database;
843 result = context.MeetingSessions.Count(ms => ms.SCO_ID == sco_id && !ms.EndDate.HasValue);
844 } catch (Exception ex) {
845 Extensions.LogServiceError("ActiveSessionCount", ex);
852 public int EndAllActiveSessions(int sco_id) {
853 Extensions.LogServiceCall("EndAllActiveSessions", string.Format("Parameters: sco_id = {0}", sco_id));
856 var now = DateTime.UtcNow;
857 var context = Database;
858 var activeSessions = context.MeetingSessions.Where(ms => ms.SCO_ID == sco_id && !ms.EndDate.HasValue);
859 foreach (var meetingSession in activeSessions) {
860 meetingSession.EndDate = now;
862 context.SubmitChanges();
863 } catch (Exception ex) {
864 Extensions.LogServiceError("EndAllActveSessions", ex);
871 public int RecordHeartbeatTick(int meetingSessionKey, int principal_id, double previousInterval) {
872 Extensions.LogServiceCall("RecordHeartbeatTick", string.Format("Parameters: meetingSessionKey= {0}, principal_id = {1}, previousInterval = {2}", meetingSessionKey, principal_id, previousInterval));
875 var context = Database;
876 var tickRecord = new MeetingSessionHeartbeatTick {
877 MeetingSessionKey = meetingSessionKey,
878 Timestamp = DateTime.UtcNow,
879 Principal_ID = principal_id,
880 PreviousInterval = previousInterval
882 context.MeetingSessionHeartbeatTicks.InsertOnSubmit(tickRecord);
883 context.SubmitChanges();
885 } catch (Exception ex) {
886 Extensions.LogServiceError("RecordHeartbeatTick", ex);
893 public bool RecordParticipantLog(int scoId, int principalId, string details) {
894 Extensions.LogServiceCall("RecordParticipantLog", string.Format("Parameters: sco_id = {0} principal_id = {1} details = {2} DateTimeUtc = {3}", scoId, principalId, details, DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff")));
896 var context = Database;
897 var log = new ParticipantLog {
899 Principal_ID = principalId,
900 Details = HttpUtility.HtmlDecode(details.Replace("_cr_", "\r\n")),
901 Created = DateTime.UtcNow
903 context.ParticipantLogs.InsertOnSubmit(log);
904 context.SubmitChanges();
905 } catch (Exception ex) {
906 Extensions.LogServiceError("RecordParticipantLog", ex);
912 public bool RecordHostMessage(int scoId, int principalId, string message) {
913 Extensions.LogServiceCall("RecordHostMessage", string.Format("Parameters: sco_id = {0} principal_id = {1} message = {2} DateTimeUtc = {3}", scoId, principalId, message, DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff")));
915 var context = Database;
916 var log = new HostMessageLog {
918 Principal_ID = principalId,
921 context.HostMessageLogs.InsertOnSubmit(log);
922 context.SubmitChanges();
923 } catch (Exception ex) {
924 Extensions.LogServiceError("RecordHostMessage", ex);
930 public bool RecordParticipantMessage(int scoId, int principalId, string message) {
931 Extensions.LogServiceCall("RecordParticipantMessage", string.Format("Parameters: sco_id = {0} principal_id = {1} details = {2} DateTimeUtc = {3}", scoId, principalId, message, DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff")));
933 var context = Database;
934 var log = new ParticipantMessageLog {
936 Principal_ID = principalId,
939 context.ParticipantMessageLogs.InsertOnSubmit(log);
940 context.SubmitChanges();
941 } catch (Exception ex) {
942 Extensions.LogServiceError("RecordParticipantMessage", ex);
948 public ServiceStatus ArchiveSessionEnd(int scoId, int principalId, string firstname, string lastname, string email) {
949 Extensions.LogServiceCall("[service.asmx][ArchiveSessionEnd]", string.Format("Parameters: scoId = {0} principalId = {1} firstname = {2} lastname = {3} email = {4}", scoId, principalId, firstname, lastname, email));
950 var result = new ServiceStatus {
954 MeetingParticipantSession existingMeetingParticipantSession = null;
956 if(principalId > 0) {
957 var context = Database;
958 //var meeting = context.Meetings.SingleOrDefault(m => m.SCO_ID == sco_id);
959 //JM - 9/27/2012 changed session to add a check for session not ended
960 var session = GetRecordingSession(scoId, context);
961 if(session != null) {
962 var user = context.Participants.SingleOrDefault(p => p.Principal_ID == principalId);
965 user = new Participant {
966 Principal_ID = principalId,
967 FirstName = firstname,
971 context.Participants.InsertOnSubmit(user);
973 //JM 9/27/2012 - changed to grab first participant session found. Weird issue where some users were getting multiple sesions
974 existingMeetingParticipantSession =
975 session.MeetingParticipantSessions.OrderBy(mps => mps.MeetingParticipantSessionKey)
976 .FirstOrDefault(mps => mps.ParticipantKey == principalId);
977 if(existingMeetingParticipantSession == null) {
978 //create new session for user
979 existingMeetingParticipantSession = new MeetingParticipantSession {
980 MeetingSessionKey = session.MeetingSessionKey,
981 ParticipantKey = principalId,
983 Created = DateTime.UtcNow
985 context.MeetingParticipantSessions.InsertOnSubmit(existingMeetingParticipantSession);
986 context.SubmitChanges();
987 //JM-12/27/2012 Change to check for multiple meeting participant sessions
988 CheckParticipantSessions(session, principalId);
989 //make sure tracking gets assigned right key
990 existingMeetingParticipantSession = context.MeetingParticipantSessions.OrderBy(p => p.MeetingParticipantSessionKey)
992 p => p.MeetingSessionKey == session.MeetingSessionKey & p.ParticipantKey == principalId);
994 var existingParticipantTracking =
995 context.ParticipantTrackings.OrderByDescending(pt => pt.StartDate)
998 pt.MeetingParticipantSessionKey ==
999 existingMeetingParticipantSession.MeetingParticipantSessionKey &&
1000 pt.Principal_ID == principalId);
1001 if(existingParticipantTracking != null) {
1002 if(!existingParticipantTracking.EndDate.HasValue) {
1004 existingParticipantTracking.EndDate = DateTime.UtcNow;
1007 throw new ArgumentException(string.Format("Exiting user does not have an entrance time scoId = {0}, principalId = {1}, existingMeetingParticipantSession.MeetingParticipantSessionKey = {2}", scoId, principalId, existingMeetingParticipantSession.MeetingParticipantSessionKey));
1010 adobe.GetAdobeTransactions(session, Database);
1011 // Tyler Allen - 08/27/2016
1012 // This is redundant and will cause deadlocks
1013 //Database.SubmitChanges();
1014 CheckParticipantSessions(session, principalId);
1022 result.Success = false;
1023 result.Message = "Archive scoId: " + scoId + " is not a valid session.";
1024 throw new ArgumentException(result.Message);
1027 result.Success = false;
1028 result.Message = "Principal ID: " + principalId + " is not valid";
1029 throw new ArgumentException(result.Message);
1031 } catch (Exception ex) {
1032 Extensions.LogServiceError("[service.asmx][ArchiveSessionEnd]", ex);
1033 result.Success = false;
1034 result.Message = ex.Message;
1036 CloseArchiveSession(scoId);
1040 /* This is the new modifications created by Tyler Allen [08/22/2016] */
1042 // TODO: Depricated for new Notify application
1043 // Launch a non-blocking thread to wait for 30 minutes for adobe results then email certificates
1044 // System.Threading.Thread waitForResultsThread = new System.Threading.Thread(() => ArchiveSessionEndResultsThread(existingMeetingParticipantSession));
1045 // waitForResultsThread.Start();
1048 // -a = archive session
1050 Extensions.LogServiceCall("[service.asmx][ArchiveSessionEnd][Processing]", $"{notifyFilePath} -u -a {existingMeetingParticipantSession.MeetingParticipantSessionKey}");
1051 //Process.Start($"{notifyFilePath} -u -a {existingMeetingParticipantSession.MeetingParticipantSessionKey}");
1052 startNotify($"-u -a {existingMeetingParticipantSession.MeetingParticipantSessionKey}");
1053 Extensions.LogServiceCall("[service.asmx][ArchiveSessionEnd][Started]", $"{notifyFilePath} -u -a {existingMeetingParticipantSession.MeetingParticipantSessionKey}");
1055 catch (Exception exception) {
1056 Extensions.LogServiceError("[service.asmx][ArchiveSessionEnd][CPE.App.Notify.exe]", exception);
1057 //Extensions.LogServiceCall("[service.asmx][ArchiveSessionEnd]", $"There was an error processing CPE.App.Notify.exe [{notifyFilePath} -u -a {existingMeetingParticipantSession.MeetingParticipantSessionKey}] ({exception.Message}");
1060 /* This is the new modifications created by Tyler Allen [08/22/2016] */
1067 public bool CloseOpenUserSessions(int meetingSessionKey) {
1068 Extensions.LogServiceCall("CloseOpenUserSessions", string.Format("Parameters: meetingSessionKey = {0}", meetingSessionKey));
1071 var session = Database.MeetingSessions.Single(ms => ms.MeetingSessionKey == meetingSessionKey);
1072 var participants = Database.MeetingParticipantSessions.Where(m => m.MeetingSessionKey == session.MeetingSessionKey);
1073 foreach (var participantSession in participants)
1074 foreach (var participantTracking in participantSession.ParticipantTrackings.Where(t => !t.EndDate.HasValue)) {
1075 // Tyler changed to get EndDate from the last engagement request.
1076 //participantTracking.EndDate = session.EndDate;
1077 var lastEngagement = participantTracking.MeetingParticipantSession.ParticipantEngagements.OrderByDescending(e => e.DisplayTime)
1079 if(lastEngagement == null)
1080 participantTracking.EndDate = participantTracking.StartDate;
1082 participantTracking.EndDate = lastEngagement.ResponseTime.HasValue
1083 ? lastEngagement.ResponseTime.Value
1084 : lastEngagement.DisplayTime;
1086 Database.SubmitChanges();
1087 CleanupRebroadcastEngagements(meetingSessionKey);
1089 } catch (Exception ex) {
1090 Extensions.LogServiceError("CloseOpenUserSessions", ex);
1096 private MeetingSession GetRecordingSession(int scoId, CPEWebDataContext context) {
1097 var now = DateTime.UtcNow;
1098 var twelveHoursAgo = now.AddHours(-12);
1100 context.MeetingSessions.Where(ms => ms.SCO_ID == scoId && ms.StartDate >= twelveHoursAgo && ms.StartDate < now && ms.EndDate.HasValue)
1101 .OrderByDescending(ms => ms.EndDate)
1102 .FirstOrDefault() ??
1103 getLastSession(scoId);
1107 //static Dictionary<string, Task<bool>> Tasks = new Dictionary<string, Task<bool>>();
1108 private void CloseArchiveSession(int scoId) {
1109 var context = Database;
1110 var session = GetRecordingSession(scoId, context);
1111 if(session != null) {
1112 //session.EndDate = endTime;
1113 var participantSessions = context.MeetingParticipantSessions.Where(m => m.MeetingSessionKey == session.MeetingSessionKey);
1114 foreach (var participantSession in participantSessions) {
1115 var trackingsWithoutExit =
1116 context.ParticipantTrackings.Where(
1117 t => t.MeetingParticipantSessionKey == participantSession.MeetingParticipantSessionKey
1118 && !t.EndDate.HasValue)
1119 .OrderByDescending(t => t.StartDate)
1121 //TODO: Try to catch logouts due to power failure
1122 //look for las poll displayed and compare to logout time?
1123 if(trackingsWithoutExit != null) {
1124 // Tyler changed to get EndDate from the last engagement request.
1125 //trackingsWithoutExit.EndDate = session.EndDate;
1126 var lastEngagement = trackingsWithoutExit.MeetingParticipantSession.ParticipantEngagements.OrderByDescending(e => e.DisplayTime)
1128 if(lastEngagement == null)
1129 trackingsWithoutExit.EndDate = trackingsWithoutExit.StartDate;
1131 trackingsWithoutExit.EndDate = lastEngagement.ResponseTime.HasValue
1132 ? lastEngagement.ResponseTime.Value
1133 : lastEngagement.DisplayTime;
1136 // var participantTracking in
1137 // participantSession.ParticipantTrackings.Where(t => !t.EndDate.HasValue))
1138 // participantTracking.EndDate = session.EndDate;
1140 context.SubmitChanges();
1141 CleanupRebroadcastEngagements(session.MeetingSessionKey);
1142 //CleanupSessionEngagements(session.MeetingSessionKey);
1144 //string taskId = Guid.NewGuid().ToString();
1145 //Tasks[taskId] = Task.Factory.StartNew<bool>(() => RunTask(scoId));
1149 //private bool RunTask(int scoId)
1151 // var result = false;
1152 // //wait 10 seconds so all user logouts are tracked
1153 // const int secondsToSleep = 2;
1154 // Thread.Sleep(secondsToSleep * 1000);
1157 // var context = Database;
1158 // var session = getLastSession(scoId);
1159 // if(session!= null)
1161 // //session.EndDate = endTime;
1162 // var participants = context.MeetingParticipantSessions.Where(m => m.MeetingSessionKey == session.MeetingSessionKey);
1163 // foreach (var participantSession in participants)
1164 // foreach (var participantTracking in participantSession.ParticipantTrackings.Where(t => !t.EndDate.HasValue))
1165 // participantTracking.EndDate = session.EndDate;
1166 // context.SubmitChanges();
1167 // //CleanupSessionEngagements(session.MeetingSessionKey);
1171 // catch (Exception ex)
1173 // Extensions.LogServiceError("CloseArchiveSession", ex);
1179 public bool CleanupSession(int sessionKey) {
1180 Extensions.LogServiceCall("CleanupSession", string.Format("Parameters: sessionKey = {0}", sessionKey));
1181 CleanupSessionEngagements(sessionKey);
1185 private void CleanupSessionEngagements(int sessionKey) {
1187 var context = Database;
1188 Database.ArchiveSessionEngagements(sessionKey);
1189 var session = context.MeetingSessions.Single(ms => ms.MeetingSessionKey == sessionKey);
1190 //filter out engagements not sent by host
1191 var engagementsToKeep = new List<int>();
1192 var heartbeats = session.MeetingSessionHeartbeats.Select(h => h.Timestamp)
1194 foreach (var heartbeat in heartbeats) {
1195 foreach (var ps in session.MeetingParticipantSessions) {
1196 var validEngagements = context.ParticipantEngagements.Where(
1197 pe => Math.Abs((pe.DisplayTime - heartbeat).TotalSeconds) < 30.0)
1198 .Select(pe => pe.ParticipantEngagementKey)
1200 engagementsToKeep.AddRange(validEngagements);
1203 engagementsToKeep = engagementsToKeep.Distinct()
1205 var tooLarge = engagementsToKeep.Count >= 2000;
1206 var meetingParticipantEngagementKeys = session.MeetingParticipantSessions.Select(mps => mps.MeetingParticipantSessionKey)
1208 var allParticipantEngagements =
1209 context.ParticipantEngagements.Where(
1210 pe => meetingParticipantEngagementKeys.Contains(pe.MeetingParticipantSessionKey));
1212 var allEngagementKeys = allParticipantEngagements.Select(pe => pe.ParticipantEngagementKey)
1214 var engagementsToDelete = allEngagementKeys.Except(engagementsToKeep);
1217 "DELETE FROM dbo.ParticipantEngagements WHERE ParticipantEngagementKey IN({0})",
1218 string.Join(",", engagementsToDelete));
1219 context.ExecuteCommand(query);
1221 var engagementsToDelete =
1222 allParticipantEngagements.Where(pe => !engagementsToKeep.Contains(pe.ParticipantEngagementKey));
1223 context.ParticipantEngagements.DeleteAllOnSubmit(engagementsToDelete);
1224 context.SubmitChanges();
1226 //filter out duplicates
1227 var duplicateKeys = new List<int>();
1228 foreach (var mps in session.MeetingParticipantSessions) {
1229 var duplicateEngagements = context.GetDuplicateEngagements(mps.MeetingParticipantSessionKey)
1231 if(duplicateEngagements.Any()) {
1232 var keysProcessed = new List<int>();
1233 var keysToKeep = new List<int>();
1234 foreach (var getDuplicateEngagementsResult in duplicateEngagements) {
1235 if(!keysProcessed.Contains(getDuplicateEngagementsResult.ParticipantEngagementKey)) {
1236 var currentTime = getDuplicateEngagementsResult.DisplayTime;
1237 var currentDuplicates =
1238 duplicateEngagements.Where(
1239 de => Math.Abs((de.DisplayTime - currentTime).TotalSeconds) <= 30.0);
1240 var currentDuplicatesWithResponse = currentDuplicates.Where(cd => cd.ResponseTime.HasValue);
1241 var currentDuplicatesWithoutResponse = currentDuplicates.Where(cd => !cd.ResponseTime.HasValue);
1242 var dupKeyToKeep = currentDuplicatesWithResponse.Any()
1243 ? currentDuplicatesWithResponse.First()
1244 .ParticipantEngagementKey
1245 : currentDuplicatesWithoutResponse.First()
1246 .ParticipantEngagementKey;
1247 keysToKeep.Add(dupKeyToKeep);
1248 keysProcessed.AddRange(currentDuplicates.Select(cd => cd.ParticipantEngagementKey));
1251 duplicateKeys.AddRange(duplicateEngagements.Where(de => !keysToKeep.Contains(de.ParticipantEngagementKey))
1252 .Select(de => de.ParticipantEngagementKey));
1255 if(duplicateKeys.Any()) {
1256 var distinctKeysToDelete = duplicateKeys.Distinct();
1258 context.ParticipantEngagements.Where(pe => distinctKeysToDelete.Contains(pe.ParticipantEngagementKey));
1259 context.ParticipantEngagements.DeleteAllOnSubmit(duplicates);
1261 context.SubmitChanges();
1262 } catch (Exception ex) {
1263 Extensions.LogServiceError("CleanupSessionEngagements", ex);
1264 Console.WriteLine(ex.Message);
1269 public bool CleanupRebroadcast(int sessionKey) {
1270 Extensions.LogServiceCall("CleanupRebroadcast", string.Format("Parameters: sessionKey = {0}", sessionKey));
1271 CleanupRebroadcastEngagements(sessionKey);
1275 private void CleanupRebroadcastEngagements(int sessionKey) {
1277 var context = Database;
1278 var meetingParticipantSessionKeys = context.MeetingParticipantSessions.Where(mps => mps.MeetingSessionKey == sessionKey)
1279 .Select(mps => mps.MeetingParticipantSessionKey)
1281 var archived = context.ParticipantEngagementsArchives.Any(
1282 pa => meetingParticipantSessionKeys.Contains(pa.MeetingParticipantSessionKey));
1284 Database.ArchiveSessionEngagements(sessionKey);
1285 var session = context.MeetingSessions.Single(ms => ms.MeetingSessionKey == sessionKey);
1286 //filter out duplicates
1287 var duplicateKeys = new List<int>();
1288 foreach (var mps in session.MeetingParticipantSessions) {
1289 var duplicateEngagements = context.GetDuplicateEngagements(mps.MeetingParticipantSessionKey)
1291 if(duplicateEngagements.Any()) {
1292 var keysProcessed = new List<int>();
1293 var keysToKeep = new List<int>();
1294 foreach (var getDuplicateEngagementsResult in duplicateEngagements) {
1295 if(!keysProcessed.Contains(getDuplicateEngagementsResult.ParticipantEngagementKey)) {
1296 var currentTime = getDuplicateEngagementsResult.DisplayTime;
1297 var currentDuplicates =
1298 duplicateEngagements.Where(
1299 de => Math.Abs((de.DisplayTime - currentTime).TotalSeconds) <= 30.0);
1300 var currentDuplicatesWithResponse = currentDuplicates.Where(cd => cd.ResponseTime.HasValue);
1301 var currentDuplicatesWithoutResponse = currentDuplicates.Where(cd => !cd.ResponseTime.HasValue);
1302 var dupKeyToKeep = currentDuplicatesWithResponse.Any()
1303 ? currentDuplicatesWithResponse.First()
1304 .ParticipantEngagementKey
1305 : currentDuplicatesWithoutResponse.First()
1306 .ParticipantEngagementKey;
1307 keysToKeep.Add(dupKeyToKeep);
1308 keysProcessed.AddRange(currentDuplicates.Select(cd => cd.ParticipantEngagementKey));
1311 duplicateKeys.AddRange(duplicateEngagements.Where(de => !keysToKeep.Contains(de.ParticipantEngagementKey))
1312 .Select(de => de.ParticipantEngagementKey));
1315 if(duplicateKeys.Any()) {
1316 var distinctKeysToDelete = duplicateKeys.Distinct();
1318 context.ParticipantEngagements.Where(pe => distinctKeysToDelete.Contains(pe.ParticipantEngagementKey));
1319 context.ParticipantEngagements.DeleteAllOnSubmit(duplicates);
1321 context.SubmitChanges();
1322 } catch (Exception ex) {
1323 Extensions.LogServiceError("CleanupRebroadcastEngagements", ex);
1324 Console.WriteLine(ex.Message);
1328 private void CheckParticipantSessions(MeetingSession session, int principal_id) {
1330 var context = Database;
1331 var participantSessionCount =
1332 session.MeetingParticipantSessions.Count(mps => mps.ParticipantKey == principal_id);
1333 if(participantSessionCount > 1) {
1334 var participantSessions =
1335 session.MeetingParticipantSessions.Where(mps => mps.ParticipantKey == principal_id)
1337 mps => mps.MeetingParticipantSessionKey);
1338 var psToKeep = participantSessions.First();
1339 var psessionsToDelete =
1340 participantSessions.Where(
1341 ps => ps.MeetingParticipantSessionKey != psToKeep.MeetingParticipantSessionKey);
1342 foreach (var meetingParticipantSession in psessionsToDelete) {
1343 context.MeetingParticipantSessions.DeleteOnSubmit(meetingParticipantSession);
1345 context.SubmitChanges();
1347 } catch (Exception ex) {
1348 Extensions.LogServiceError("CheckParticipanSessions", ex);
1352 private MeetingSession getActiveSessionBySco(int sco_id) {
1353 var now = DateTime.UtcNow;
1355 Database.MeetingSessions.FirstOrDefault(
1356 ms => ms.SCO_ID == sco_id && ms.StartDate <= now && (!ms.EndDate.HasValue || ms.EndDate.Value >= now));
1360 private MeetingSession getActiveSessionByKey(int meetingSessionKey) {
1361 var now = DateTime.UtcNow;
1363 Database.MeetingSessions.SingleOrDefault(ms => ms.MeetingSessionKey == meetingSessionKey && ms.StartDate <= now);
1364 // Tyler Allen - 09/01/2016
1365 // Just send a session no matter what
1366 // && (!ms.EndDate.HasValue || ms.EndDate.Value >= now));
1370 private MeetingSession getLastSession(int sco_id) {
1371 var now = DateTime.UtcNow;
1373 Database.MeetingSessions.Where(
1374 ms => ms.SCO_ID == sco_id && ms.StartDate <= now && ms.EndDate.HasValue && ms.EndDate.Value <= now)
1375 .OrderByDescending(ms => ms.StartDate)
1380 private void CheckParticipantTracking(MeetingParticipantSession participantSession, int principalId) {
1381 //Extensions.LogServiceCall("CheckParticipantTracking", String.Format("Parameters: participantSession.MeetingParticipantSessionKey = {0} principal_id = {1}", participantSession.MeetingParticipantSessionKey, principalId));
1382 var context = Database;
1383 var tracking = context.ParticipantTrackings.Where(t =>
1384 t.Principal_ID == principalId &&
1385 t.MeetingParticipantSessionKey == participantSession.MeetingParticipantSessionKey &&
1386 !t.EndDate.HasValue)
1387 .OrderByDescending(t => t.StartDate)
1389 if(tracking == null) {
1390 tracking = new ParticipantTracking {
1391 MeetingParticipantSessionKey =
1392 participantSession.MeetingParticipantSessionKey,
1393 Principal_ID = principalId,
1394 StartDate = DateTime.UtcNow
1396 context.ParticipantTrackings.InsertOnSubmit(tracking);
1397 context.SubmitChanges();
1402 public class SessionStatusClass {
1403 public int MeetingSessionKey { get; set; }
1404 public string Status { get; set; }
1405 public int OwnerPrincipalId { get; set; }
1408 public class ServiceStatus {
1409 public bool Success { get; set; }
1410 public string Message { get; set; }
1413 public class Setting {
1414 public int Interval { get; set; }
1415 public string Text { get; set; }
1416 public int Duration { get; set; }
1419 public class Detail {
1420 public string CourseCode { get; set; }
1421 public string Instructor { get; set; }
1422 public string Location { get; set; }
1423 public string TopicID { get; set; }
1424 public string Topic { get; set; }