using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Web;
using System.Web.Services;
using CPE.App.Web.Code;
using CPE.App.Web.Models;
/*
Tyler Allen - 08/22/2016
Change notes:
I have commented out the section that was executing the thread within the application pool process
The new method calls a console application with the session variables
This will run outside the application pool
*/
namespace CPE.App.Web.Static.services.engagement {
///
/// Summary description for engagement
///
[WebService(Namespace = "http://cpeengagement.com/static/services/engagement/service/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
// [System.Web.Script.Services.ScriptService]
public class service : BaseWebService {
private string notifyFilePath {
get { return ConfigurationManager.AppSettings["NotifyFilePath"]; }
}
[WebMethod]
public Setting GetMeetingSettings(int sco_id) {
Extensions.LogServiceCall("[service][GetMeetingSettings]", string.Format("Parameters: sco_id = {0}", sco_id));
var result = new Setting {
Interval = 15,
Text = "Respond",
Duration = 1
};
var meetingSetting = Database.MeetingSettings.SingleOrDefault(ms => ms.MeetingKey == sco_id);
if(meetingSetting != null) {
result.Interval = meetingSetting.Interval.HasValue
? meetingSetting.Interval.Value
: 15;
result.Text = meetingSetting.Text;
result.Duration = meetingSetting.Duration.HasValue
? meetingSetting.Duration.Value
: 1;
}
return result;
}
[WebMethod]
public ServiceStatus SetMeetingSettings(int sco_id, int interval, string text, int duration) {
Extensions.LogServiceCall("SetMeetingSettings", string.Format("Parameters: sco_id = {0} interval = {1} text = {2} duration = {3}", sco_id, interval, text, duration));
var result = new ServiceStatus {
Success = true,
Message = ""
};
try {
var context = Database;
var existing = context.Meetings.SingleOrDefault(m => m.SCO_ID == sco_id);
if(existing != null) {
if(existing.MeetingSetting == null) {
var meetingSetting = new MeetingSetting {
MeetingKey = sco_id,
Interval = interval,
Text = text,
Duration = duration
};
context.MeetingSettings.InsertOnSubmit(meetingSetting);
} else {
existing.MeetingSetting.Interval = interval;
existing.MeetingSetting.Text = text;
existing.MeetingSetting.Duration = duration;
}
} else {
var meeting = new Meeting {
SCO_ID = sco_id,
MeetingKey = sco_id
};
var meetingSetting = new MeetingSetting();
meetingSetting.Interval = interval;
meetingSetting.Text = text;
meetingSetting.Duration = duration;
meetingSetting.MeetingKey = sco_id;
context.Meetings.InsertOnSubmit(meeting);
context.MeetingSettings.InsertOnSubmit(meetingSetting);
}
context.SubmitChanges();
} catch (Exception ex) {
Extensions.LogServiceError("SetMeetingSettings", ex);
result.Success = false;
result.Message = ex.Message;
}
return result;
}
[WebMethod]
public SessionStatusClass SessionStatus(int sco_id) {
Extensions.LogServiceCall("[service][SessionStatus]", string.Format("Parameters: sco_id = {0}", sco_id));
var result = new SessionStatusClass {
MeetingSessionKey = -1,
OwnerPrincipalId = -1,
Status = "none"
};
try {
var context = Database;
var existingSession =
context.MeetingSessions.Where(ms => ms.SCO_ID == sco_id && !ms.EndDate.HasValue)
.OrderByDescending(ms => ms.StartDate)
.FirstOrDefault();
if(existingSession != null) {
result.MeetingSessionKey = existingSession.MeetingSessionKey;
result.OwnerPrincipalId = existingSession.OwnerPrincipal_ID;
var isPaused = existingSession.MeetingSessionPauses.Count(me => !me.EndDate.HasValue) > 0;
if(existingSession.EndDate.HasValue) {
result.Status = "complete";
} else if(!existingSession.EndDate.HasValue && existingSession.StartDate < DateTime.UtcNow && !isPaused) {
result.Status = "active";
} else if(isPaused) {
result.Status = "pause";
}
}
} catch (Exception ex) {
Extensions.LogServiceError("SessionStatus", ex);
result.OwnerPrincipalId = -1;
result.Status = "error";
}
return result;
}
[WebMethod]
public int StartSession(int sco_id, string name, int owner_principal_id) {
Extensions.LogServiceCall("StartSession", string.Format("Parameters: sco_id = {0} name= {1} owner_principal_id = {2}", sco_id, name, owner_principal_id));
var result = -1;
try {
var context = Database;
var existingSession =
context.MeetingSessions.Where(ms => ms.SCO_ID == sco_id && !ms.EndDate.HasValue)
.OrderByDescending(ms => ms.StartDate)
.FirstOrDefault();
if(existingSession == null) {
//create new session
var meeting = context.Meetings.SingleOrDefault(m => m.SCO_ID == sco_id);
if(meeting == null) {
meeting = new Meeting {
SCO_ID = sco_id,
MeetingKey = sco_id
};
context.Meetings.InsertOnSubmit(meeting);
var meetingSettings = new MeetingSetting {
Interval = 15,
MeetingKey = sco_id,
Text = "Respond"
};
context.MeetingSettings.InsertOnSubmit(meetingSettings);
var meetingDetails = new MeetingDetail {
MeetingKey = sco_id,
CourseCode = "",
Instructor = "",
Location = "",
TopicID = "",
TopicName = ""
};
context.MeetingDetails.InsertOnSubmit(meetingDetails);
}
var session = new MeetingSession {
SCO_ID = sco_id,
Name = name,
StartDate = DateTime.UtcNow, //start
OwnerPrincipal_ID = owner_principal_id
};
context.MeetingSessions.InsertOnSubmit(session);
context.SubmitChanges();
result = session.MeetingSessionKey;
//check for multiple sessions
var existingSessionCount = context.MeetingSessions.Count(ms => ms.SCO_ID == sco_id && !ms.EndDate.HasValue);
if(existingSessionCount > 1) {
//there should only be one session
var existingSessions = context.MeetingSessions.Where(ms => ms.SCO_ID == sco_id && !ms.EndDate.HasValue)
.OrderBy(ms => ms.MeetingSessionKey);
var sessionToKeep = existingSessions.First();
var sessionsToDelete =
existingSessions.Where(ms => ms.MeetingSessionKey != sessionToKeep.MeetingSessionKey);
foreach (var meetingSession in sessionsToDelete) {
if(meetingSession.MeetingParticipantSessions.Any() || meetingSession.MeetingSessionHeartbeats.Any()) {
//session has data, do not delete it
} else {
context.MeetingSessions.DeleteOnSubmit(meetingSession);
}
}
try {
context.SubmitChanges();
} catch (Exception ex) {
Extensions.LogServiceError("StartSession", ex);
}
}
} else {
//session already exists, this should not happen!
//string existingSessionKeys = string.Join(",", context.MeetingSessions.Where(ms => ms.SCO_ID == sco_id && !ms.EndDate.HasValue).Select(ms => ms.MeetingSessionKey).ToArray());
//throw new ArgumentException(String.Format("Trying to start a session which already exists. sco_id = {0}, meetingSessionKeys = {1}", sco_id, existingSessionKeys));
result = existingSession.MeetingSessionKey;
}
} catch (Exception ex) {
Extensions.LogServiceError("StartSession", ex);
result = -1;
}
return result;
}
private void startNotify(string args) {
var startinfo = new ProcessStartInfo
{
FileName = $"{notifyFilePath}",
CreateNoWindow = true,
UseShellExecute = false,
WindowStyle = ProcessWindowStyle.Hidden,
Arguments = args
};
var process = Process.Start(startinfo);
process.WaitForExit(0);
}
[WebMethod]
public int StopSession(int sessionKey, DateTime end) {
Extensions.LogServiceCall("[service.asmx][StopSession]", string.Format("Parameters: sessionKey = {0} end = {1}", sessionKey, end.ToString("yyyy-MM-dd HH:mm:ss.fff")));
var result = -1;
var session = Database.MeetingSessions.Single(ms => ms.MeetingSessionKey == sessionKey);
try
{
session.EndDate = DateTime.UtcNow; //end
var participants = Database.MeetingParticipantSessions.Where(m => m.MeetingSessionKey == session.MeetingSessionKey);
foreach (var participantSession in participants) {
foreach (var participantTracking in participantSession.ParticipantTrackings.Where(t => !t.EndDate.HasValue)) {
participantTracking.EndDate = session.EndDate;
}
}
adobe.GetAdobeTransactions(session, Database);
// Tyler Allen - 08/27/2016
// This is redundant and will cause deadlocks
//Database.SubmitChanges();
result = session.MeetingSessionKey;
CleanupSessionEngagements(session.MeetingSessionKey);
}
catch (Exception ex) {
Extensions.LogServiceError("[service.asmx][StopSession]", ex);
result = -1;
}
/* This is the new modifications created by Tyler Allen [08/22/2016] */
// TODO: Depricated for new Notify application
// Launch a non-blocking thread to wait for 30 minutes for adobe results then email certificates
// var waitForResultsThread = new Thread(() => StopSessionResultsThread(session));
// waitForResultsThread.Start();
// -u = unattended
// -s = stop session
try {
Extensions.LogServiceCall("[service.asmx][StopSession][CPE.App.Notify.exe]", $"Processing CPE.App.Notify.exe [{notifyFilePath} -u -s {session.MeetingSessionKey}]");
//Process.Start($"{notifyFilePath} -u -s {session.MeetingSessionKey}");
startNotify($"-u -s {session.MeetingSessionKey}");
Extensions.LogServiceCall("[service.asmx][StopSession][CPE.App.Notify.exe]", $"Started CPE.App.Notify.exe [{notifyFilePath} -u -s {session.MeetingSessionKey}]");
} catch (Exception exception) {
Extensions.LogServiceError("[service.asmx][StopSession][CPE.App.Notify.exe]", exception);
}
/* This is the new modifications created by Tyler Allen [08/22/2016] */
return sessionKey;
}
[WebMethod]
public int PauseSession(int sessionKey, DateTime start) {
Extensions.LogServiceCall("PauseSession", string.Format("Parameters: sessionKey = {0} start= {1}", sessionKey, start.ToString("yyyy-MM-dd HH:mm:ss.fff")));
var result = -1;
try {
var context = Database;
var sessionEvent = new MeetingSessionPause {
MeetingSessionKey = sessionKey,
StartDate = DateTime.UtcNow //start
};
context.MeetingSessionPauses.InsertOnSubmit(sessionEvent);
context.SubmitChanges();
result = sessionEvent.MesstingSessionPauseKey;
} catch (Exception ex) {
Extensions.LogServiceError("PauseSession", ex);
result = -1;
}
return result;
}
[WebMethod]
public int GetPauseKey(int sco_id) {
Extensions.LogServiceCall("GetPauseKey", string.Format("Parameters: sco_id = {0}", sco_id));
var result = -1;
try {
var context = Database;
var existingSession =
context.MeetingSessions.Where(ms => ms.SCO_ID == sco_id && !ms.EndDate.HasValue)
.OrderByDescending(ms => ms.StartDate)
.FirstOrDefault();
if(existingSession != null) {
var pause = existingSession.MeetingSessionPauses.Where(mse => !mse.EndDate.HasValue)
.OrderByDescending(
mse => mse.StartDate)
.First();
result = pause.MesstingSessionPauseKey;
}
;
} catch (Exception ex) {
Extensions.LogServiceError("GetPauseKey", ex);
result = -1;
}
return result;
}
[WebMethod]
public int ResumeSession(int eventKey, DateTime end) {
Extensions.LogServiceCall("ResumeSession", string.Format("Parameters: eventKey = {0} end = {1}", eventKey, end.ToString("yyyy-MM-dd HH:mm:ss.fff")));
var result = -1;
try {
var context = Database;
var sessionEvent = context.MeetingSessionPauses.Single(se => se.MesstingSessionPauseKey == eventKey);
sessionEvent.EndDate = DateTime.UtcNow; //end;
context.SubmitChanges();
result = sessionEvent.MesstingSessionPauseKey;
} catch (Exception ex) {
Extensions.LogServiceError("ResumeSession", ex);
result = -1;
}
return result;
}
[WebMethod]
public ServiceStatus LogEngagement(int meetingSessionKey) {
Extensions.LogServiceCall("LogEngagement", string.Format("Parameters: meetingSessionKey = {0}", meetingSessionKey));
var result = new ServiceStatus {
Success = true,
Message = ""
};
try {
var context = Database;
var record = new MeetingSessionHeartbeat {
MeetingSessionKey = meetingSessionKey,
Timestamp = DateTime.UtcNow
};
context.MeetingSessionHeartbeats.InsertOnSubmit(record);
context.SubmitChanges();
} catch (Exception ex) {
Extensions.LogServiceError("LogEngagement", ex);
result.Success = false;
result.Message = ex.Message;
}
return result;
}
[WebMethod]
public ServiceStatus TrackUser(int meetingSessionKey, int principal_id, string firstname, string lastname, string email, byte type) {
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")));
var result = new ServiceStatus {
Success = true,
Message = ""
};
try {
if(principal_id > 0) {
var context = Database;
//var meeting = context.Meetings.SingleOrDefault(m => m.SCO_ID == sco_id);
//JM - 9/27/2012 changed session to add a check for session not ended
//var session =
// context.MeetingSessions.SingleOrDefault(ms => ms.MeetingSessionKey == meetingSessionKey && !ms.EndDate.HasValue);
//JM - 11/20/2012 changed to allow for end dates existing for recordings
var session = getActiveSessionByKey(meetingSessionKey);
if(session != null) {
var user = context.Participants.SingleOrDefault(p => p.Principal_ID == principal_id);
if(user == null) {
//create new user
user = new Participant {
Principal_ID = principal_id,
FirstName = firstname,
LastName = lastname,
Email = email
};
context.Participants.InsertOnSubmit(user);
}
//else
//{
// user.FirstName = firstname;
// user.LastName = lastname;
// user.Email = email;
//}
//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 == principal_id);
if(existingMeetingParticipantSession == null) {
//create new session for user
existingMeetingParticipantSession = new MeetingParticipantSession {
MeetingSessionKey = session.MeetingSessionKey,
ParticipantKey = principal_id,
PlaySound = true,
Created = DateTime.UtcNow
};
context.MeetingParticipantSessions.InsertOnSubmit(existingMeetingParticipantSession);
context.SubmitChanges();
//JM-12/27/2012 Change to check for multiple meeting participant sessions
CheckParticipantSessions(session, principal_id);
//make sure tracking gets assigned right key
existingMeetingParticipantSession = context.MeetingParticipantSessions.OrderBy(p => p.MeetingParticipantSessionKey)
.FirstOrDefault(
p => p.MeetingSessionKey == session.MeetingSessionKey & p.ParticipantKey == principal_id);
}
var lastParticipantTracking =
context.ParticipantTrackings.Where(
pt =>
pt.MeetingParticipantSessionKey ==
existingMeetingParticipantSession.MeetingParticipantSessionKey &&
pt.Principal_ID == principal_id)
.OrderByDescending(p => p.StartDate)
.FirstOrDefault();
if(type == 0) {
// Start
if(lastParticipantTracking != null && !lastParticipantTracking.EndDate.HasValue) {
var lastEngagement = lastParticipantTracking.MeetingParticipantSession.ParticipantEngagements.OrderByDescending(e => e.DisplayTime)
.FirstOrDefault();
if(lastEngagement == null)
lastParticipantTracking.EndDate = lastParticipantTracking.StartDate;
else {
lastParticipantTracking.EndDate = lastEngagement.ResponseTime.HasValue
? lastEngagement.ResponseTime.Value
: lastEngagement.DisplayTime;
if(lastParticipantTracking.EndDate < lastParticipantTracking.StartDate)
lastParticipantTracking.EndDate = lastParticipantTracking.StartDate;
}
}
var pTrack = new ParticipantTracking {
MeetingParticipantSessionKey =
existingMeetingParticipantSession.MeetingParticipantSessionKey,
Principal_ID = principal_id,
StartDate = DateTime.UtcNow //timestamp
};
context.ParticipantTrackings.InsertOnSubmit(pTrack);
} else {
// End
if(lastParticipantTracking == null)
throw new ArgumentException(string.Format("Exiting user does not have an entrance time MeetingSessionKey = {0}, principalId = {1}", meetingSessionKey, principal_id));
lastParticipantTracking.EndDate = DateTime.UtcNow;
}
context.SubmitChanges();
CheckParticipantSessions(session, principal_id);
} else {
result.Success = false;
result.Message = "MeetingSessionKey: " + meetingSessionKey + " is not valid";
throw new ArgumentException(result.Message);
}
} else {
result.Success = false;
result.Message = "Principal ID: " + principal_id + " is not valid";
throw new ArgumentException(result.Message);
}
} catch (Exception ex) {
Extensions.LogServiceError("TrackUser", ex);
result.Success = false;
result.Message = ex.Message;
}
return result;
}
[WebMethod]
public int TrackEngagementReceived(int scoId, int principalId, double timeDelta) {
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")));
var result = -1;
var context = Database;
try {
if(principalId > 0) {
//var session = context.MeetingSessions.OrderByDescending(ms => ms.StartDate).FirstOrDefault(m => m.SCO_ID == scoId & !m.EndDate.HasValue);
//JM - 11/20/2012 changed to allow for session end dates existing for recordings
var session = getActiveSessionBySco(scoId);
if(session != null) {
CheckParticipantSessions(session, principalId);
var participantSession =
context.MeetingParticipantSessions.OrderBy(p => p.MeetingParticipantSessionKey)
.
FirstOrDefault(
p =>
p.MeetingSessionKey == session.MeetingSessionKey & p.ParticipantKey == principalId);
if(participantSession == null) {
participantSession = new MeetingParticipantSession {
MeetingSessionKey = session.MeetingSessionKey,
ParticipantKey = principalId,
PlaySound = true,
Created = DateTime.UtcNow
};
context.MeetingParticipantSessions.InsertOnSubmit(participantSession);
context.SubmitChanges();
//JM-12/27/2012 Change to check for multiple meeting participant sessions
CheckParticipantSessions(session, principalId);
participantSession = context.MeetingParticipantSessions.OrderBy(
p => p.MeetingParticipantSessionKey)
.FirstOrDefault(
p =>
p.MeetingSessionKey == session.MeetingSessionKey & p.ParticipantKey == principalId);
//Check Participant Tracking
CheckParticipantTracking(participantSession, principalId);
}
//else
//{
// //Check Participant Tracking
// CheckParticipantTracking(participantSession, principalId);
//}
var now = DateTime.UtcNow;
var engagementVerification = new ParticipantEngagementVerification {
MeetingParticipantSessionKey =
participantSession.MeetingParticipantSessionKey,
Principal_ID = principalId,
DisplayTime = now,
PreviousAlertDelta = timeDelta
};
context.ParticipantEngagementVerifications.InsertOnSubmit(engagementVerification);
context.SubmitChanges();
result = engagementVerification.TrackingKey;
} else {
throw new ArgumentException(string.Format("No session exists for sco = {0}, principal_id = {1}", scoId, principalId));
}
} else {
throw new ArgumentException("Principal ID: " + principalId + " is not valid");
}
} catch (Exception ex) {
Extensions.LogServiceError("TrackEngagementReceived", ex);
result = -1;
}
return result;
}
[WebMethod]
public int TrackEngagementDisplay(int scoId, int principalId) {
Extensions.LogServiceCall("TrackEngagementDisplay", string.Format("Parameters: scoId = {0} principalId = {1} DateTimeUtc = {2}", scoId, principalId, DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff")));
var result = -1;
try {
if(principalId > 0) {
var context = Database;
//var session = context.MeetingSessions.OrderByDescending(ms => ms.StartDate).FirstOrDefault(m => m.SCO_ID == scoId & !m.EndDate.HasValue);
//JM - 11/20/2012 changed to allow for session end dates existing for recordings
var session = getActiveSessionBySco(scoId);
if(session != null) {
CheckParticipantSessions(session, principalId);
var participantSession =
context.MeetingParticipantSessions.OrderBy(p => p.MeetingParticipantSessionKey)
.FirstOrDefault(
p => p.MeetingSessionKey == session.MeetingSessionKey & p.ParticipantKey == principalId);
if(participantSession == null) {
participantSession = new MeetingParticipantSession {
MeetingSessionKey = session.MeetingSessionKey,
ParticipantKey = principalId,
PlaySound = true,
Created = DateTime.UtcNow
};
context.MeetingParticipantSessions.InsertOnSubmit(participantSession);
context.SubmitChanges();
//JM-12/27/2012 Change to check for multiple meeting participant sessions
CheckParticipantSessions(session, principalId);
//make sure tracking gets assigned right key
participantSession = context.MeetingParticipantSessions.OrderBy(p => p.MeetingParticipantSessionKey)
.FirstOrDefault(
p => p.MeetingSessionKey == session.MeetingSessionKey & p.ParticipantKey == principalId);
//Check Participant Tracking
CheckParticipantTracking(participantSession, principalId);
} else {
//Check Participant Tracking
CheckParticipantTracking(participantSession, principalId);
}
//var validEngagement = false;
////Validate the engangement request to make sure it was sent by the host within the last 30 seconds
//var now = DateTime.UtcNow;
//var hostPoll = session.MeetingSessionHeartbeats.OrderByDescending(h => h.Timestamp).FirstOrDefault();
//if (hostPoll != null)
//{
// var timeDelta = Math.Abs((now - hostPoll.Timestamp).TotalSeconds);
// validEngagement = timeDelta <= 30.0;
//}
//if (validEngagement)
//{
// var engagement = new ParticipantEngagement()
// {
// MeetingParticipantSessionKey =
// participantSession.MeetingParticipantSessionKey,
// Principal_ID = principalId,
// DisplayTime = now
// };
// context.ParticipantEngagements.InsertOnSubmit(engagement);
// context.SubmitChanges();
// result = engagement.ParticipantEngagementKey;
//}
var lastHeartbeat = session.MeetingSessionHeartbeats.OrderBy(h => h.Timestamp)
.Last();
var lastEngagement = participantSession.ParticipantEngagements.Where(t => t.Principal_ID == principalId)
.OrderBy(t => t.DisplayTime)
.LastOrDefault();
if(lastEngagement == null || lastEngagement.DisplayTime < lastHeartbeat.Timestamp) {
var now = DateTime.UtcNow;
var engagement = new ParticipantEngagement {
MeetingParticipantSessionKey =
participantSession.MeetingParticipantSessionKey,
Principal_ID = principalId,
DisplayTime = now
};
context.ParticipantEngagements.InsertOnSubmit(engagement);
context.SubmitChanges();
result = engagement.ParticipantEngagementKey;
} else
result = lastEngagement.ParticipantEngagementKey;
} else {
throw new ArgumentException(string.Format("No session exists for sco = {0}, principal_id = {1}", scoId,
principalId));
}
} else {
throw new ArgumentException("Principal ID: " + principalId + " is not valid");
}
} catch (Exception ex) {
Extensions.LogServiceError("TrackEngagementDisplay", ex);
result = -99;
}
return result;
}
[WebMethod]
public int TrackEngagementResponse(int scoId, int principalId) //int engagementKey
{
Extensions.LogServiceCall("TrackEngagementResponse", string.Format("Parameters: scoId = {0} principalId = {1} DateTimeUtc = {2}", scoId, principalId, DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff")));
var result = -1;
try {
if(principalId > 0) {
var context = Database;
var now = DateTime.UtcNow;
//JM - 9-21-2012 changing to ignore key - will require updating pod
//var engagement = context.ParticipantEngagements.Single(pe => pe.ParticipantEngagementKey == engagementKey);
//var session =
// Database.MeetingSessions.OrderByDescending(ms => ms.StartDate).FirstOrDefault(ms => ms.SCO_ID == scoId && !ms.EndDate.HasValue);
//JM - 11/20/2012 changed to allow for session end dates existing for recordings
var session = getActiveSessionBySco(scoId);
if(session != null) {
CheckParticipantSessions(session, principalId);
//JM - 9-27-2012 Changed to grab first session. Fix for weird issue where some users were getting mutiple user sessions in a meeting.
var participantSession = context.MeetingParticipantSessions.Where(mps =>
mps.MeetingSessionKey == session.MeetingSessionKey &&
mps.ParticipantKey == principalId)
.OrderBy(mps => mps.MeetingParticipantSessionKey)
.FirstOrDefault();
//var participantSession =
// context.MeetingParticipantSessions.Single(
// mps =>
// mps.MeetingSessionKey == session.MeetingSessionKey && mps.ParticipantKey == principalId);
if(participantSession == null) {
//create participant session
participantSession = new MeetingParticipantSession {
MeetingSessionKey = session.MeetingSessionKey,
ParticipantKey = principalId,
PlaySound = true,
Created = DateTime.UtcNow
};
context.MeetingParticipantSessions.InsertOnSubmit(participantSession);
context.SubmitChanges();
//JM-12/27/2012 Change to check for multiple meeting participant sessions
CheckParticipantSessions(session, principalId);
participantSession = context.MeetingParticipantSessions.OrderBy(p => p.MeetingParticipantSessionKey)
.FirstOrDefault(
p => p.MeetingSessionKey == session.MeetingSessionKey & p.ParticipantKey == principalId);
//Check Participant Tracking
CheckParticipantTracking(participantSession, principalId);
} else {
//Check Participant Tracking
CheckParticipantTracking(participantSession, principalId);
}
//find last engagement without a response within 90 seconds
var participantEngagement = context.ParticipantEngagements.OrderByDescending(pe => pe.DisplayTime)
.
FirstOrDefault(
pe =>
pe.MeetingParticipantSessionKey == participantSession.MeetingParticipantSessionKey
&& (Math.Abs((now - pe.DisplayTime).TotalSeconds) <= 90)
&& !pe.ResponseTime.HasValue);
if(participantEngagement != null) {
//found it
participantEngagement.ResponseTime = now;
}
//else
//{
// //not found, create new engagement
// participantEngagement = new ParticipantEngagement()
// {
// MeetingParticipantSessionKey =
// participantSession.MeetingParticipantSessionKey,
// Principal_ID = principalId,
// DisplayTime = now,
// ResponseTime = now
// };
// context.ParticipantEngagements.InsertOnSubmit(participantEngagement);
//}
context.SubmitChanges();
result = 1; //participantEngagement.ParticipantEngagementKey;
} else {
throw new ArgumentException(string.Format("No session exists for sco = {0}, principal_id = {1}", scoId,
principalId));
}
} else {
throw new ArgumentException("Principal ID: " + principalId + " is not valid");
}
} catch (Exception ex) {
Extensions.LogServiceError("TrackEngagementResponse", ex);
result = -1;
}
return result;
}
[WebMethod]
public Detail GetMeetingDetails(int sco_id) {
Extensions.LogServiceCall("[service][GetMeetingDetails]", string.Format("Parameters: sco_id = {0}", sco_id));
var result = new Detail {
CourseCode = "",
Instructor = "",
Location = "",
TopicID = "",
Topic = ""
};
var meetingDetail = Database.MeetingDetails.SingleOrDefault(ms => ms.MeetingKey == sco_id);
if(meetingDetail != null) {
result.CourseCode = meetingDetail.CourseCode;
result.Instructor = meetingDetail.Instructor;
result.Location = meetingDetail.Location;
result.TopicID = meetingDetail.TopicID;
result.Topic = meetingDetail.TopicName;
}
return result;
}
[WebMethod]
public ServiceStatus SetMeetingDetails(int sco_id, string courseCode, string instructor, string location, string topicID, string topic) {
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));
var result = new ServiceStatus {
Success = true,
Message = ""
};
try {
var context = Database;
var existing = context.Meetings.SingleOrDefault(m => m.SCO_ID == sco_id);
if(existing != null) {
if(existing.MeetingDetail == null) {
var meetingDetail = new MeetingDetail {
MeetingKey = sco_id,
CourseCode = courseCode,
Instructor = instructor,
Location = location,
TopicID = topicID,
TopicName = topic
};
context.MeetingDetails.InsertOnSubmit(meetingDetail);
} else {
existing.MeetingDetail.CourseCode = courseCode;
existing.MeetingDetail.Instructor = instructor;
existing.MeetingDetail.Location = location;
existing.MeetingDetail.TopicID = topicID;
existing.MeetingDetail.TopicName = topic;
}
} else {
var meeting = new Meeting {
SCO_ID = sco_id,
MeetingKey = sco_id
};
var meetingDetail = new MeetingDetail();
meetingDetail.CourseCode = courseCode;
meetingDetail.Instructor = instructor;
meetingDetail.Location = location;
meetingDetail.TopicID = topicID;
meetingDetail.TopicName = topic;
meetingDetail.MeetingKey = sco_id;
context.Meetings.InsertOnSubmit(meeting);
context.MeetingDetails.InsertOnSubmit(meetingDetail);
}
context.SubmitChanges();
} catch (Exception ex) {
Extensions.LogServiceError("SetMeetingDetails", ex);
result.Success = false;
result.Message = ex.Message;
}
return result;
}
[WebMethod]
public long GetTotalSessionTime(int sco_id) {
Extensions.LogServiceCall("GetTotalSessionTime", string.Format("Parameters: sco_id = {0}", sco_id));
long result = -1;
try {
result = 0;
var context = Database;
var session = context.MeetingSessions.Where(ms => ms.SCO_ID == sco_id && !ms.EndDate.HasValue)
.OrderByDescending(ms => ms.StartDate)
.FirstOrDefault();
if(session != null) {
if(session.EndDate.HasValue) {
result = session.EndDate.Value.Ticks - session.StartDate.Ticks;
} else {
result = DateTime.UtcNow.Ticks - session.StartDate.Ticks;
}
var completedPauses = session.MeetingSessionPauses.Where(msp => msp.EndDate.HasValue);
result = completedPauses.Aggregate(result, (current, meetingSessionPause) => current - (meetingSessionPause.EndDate.Value.Ticks - meetingSessionPause.StartDate.Ticks));
var incompletePause = session.MeetingSessionPauses.Where(msp => !msp.EndDate.HasValue)
.OrderByDescending(msp => msp.StartDate)
.FirstOrDefault();
if(incompletePause != null) {
result -= DateTime.UtcNow.Ticks - incompletePause.StartDate.Ticks;
}
}
result = result/TimeSpan.TicksPerMillisecond;
} catch (Exception ex) {
Extensions.LogServiceError("GetTotalSessionTime", ex);
result = -1;
}
return result;
}
[WebMethod]
public int ActiveSessionCount(int sco_id) {
Extensions.LogServiceCall("ActiveSessionCount", string.Format("Parameters: sco_id = {0}", sco_id));
var result = 1;
try {
var context = Database;
result = context.MeetingSessions.Count(ms => ms.SCO_ID == sco_id && !ms.EndDate.HasValue);
} catch (Exception ex) {
Extensions.LogServiceError("ActiveSessionCount", ex);
result = -1;
}
return result;
}
[WebMethod]
public int EndAllActiveSessions(int sco_id) {
Extensions.LogServiceCall("EndAllActiveSessions", string.Format("Parameters: sco_id = {0}", sco_id));
var result = 1;
try {
var now = DateTime.UtcNow;
var context = Database;
var activeSessions = context.MeetingSessions.Where(ms => ms.SCO_ID == sco_id && !ms.EndDate.HasValue);
foreach (var meetingSession in activeSessions) {
meetingSession.EndDate = now;
}
context.SubmitChanges();
} catch (Exception ex) {
Extensions.LogServiceError("EndAllActveSessions", ex);
result = -1;
}
return result;
}
[WebMethod]
public int RecordHeartbeatTick(int meetingSessionKey, int principal_id, double previousInterval) {
Extensions.LogServiceCall("RecordHeartbeatTick", string.Format("Parameters: meetingSessionKey= {0}, principal_id = {1}, previousInterval = {2}", meetingSessionKey, principal_id, previousInterval));
var result = -1;
try {
var context = Database;
var tickRecord = new MeetingSessionHeartbeatTick {
MeetingSessionKey = meetingSessionKey,
Timestamp = DateTime.UtcNow,
Principal_ID = principal_id,
PreviousInterval = previousInterval
};
context.MeetingSessionHeartbeatTicks.InsertOnSubmit(tickRecord);
context.SubmitChanges();
result = 1;
} catch (Exception ex) {
Extensions.LogServiceError("RecordHeartbeatTick", ex);
result = -1;
}
return result;
}
[WebMethod]
public bool RecordParticipantLog(int scoId, int principalId, string details) {
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")));
try {
var context = Database;
var log = new ParticipantLog {
Sco_ID = scoId,
Principal_ID = principalId,
Details = HttpUtility.HtmlDecode(details.Replace("_cr_", "\r\n")),
Created = DateTime.UtcNow
};
context.ParticipantLogs.InsertOnSubmit(log);
context.SubmitChanges();
} catch (Exception ex) {
Extensions.LogServiceError("RecordParticipantLog", ex);
}
return true;
}
[WebMethod]
public bool RecordHostMessage(int scoId, int principalId, string message) {
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")));
try {
var context = Database;
var log = new HostMessageLog {
SCO_ID = scoId,
Principal_ID = principalId,
Message = message
};
context.HostMessageLogs.InsertOnSubmit(log);
context.SubmitChanges();
} catch (Exception ex) {
Extensions.LogServiceError("RecordHostMessage", ex);
}
return true;
}
[WebMethod]
public bool RecordParticipantMessage(int scoId, int principalId, string message) {
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")));
try {
var context = Database;
var log = new ParticipantMessageLog {
SCO_ID = scoId,
Principal_ID = principalId,
Message = message
};
context.ParticipantMessageLogs.InsertOnSubmit(log);
context.SubmitChanges();
} catch (Exception ex) {
Extensions.LogServiceError("RecordParticipantMessage", ex);
}
return true;
}
[WebMethod]
public ServiceStatus ArchiveSessionEnd(int scoId, int principalId, string firstname, string lastname, string email) {
Extensions.LogServiceCall("[service.asmx][ArchiveSessionEnd]", string.Format("Parameters: scoId = {0} principalId = {1} firstname = {2} lastname = {3} email = {4}", scoId, principalId, firstname, lastname, email));
var result = new ServiceStatus {
Success = true,
Message = ""
};
MeetingParticipantSession existingMeetingParticipantSession = null;
try {
if(principalId > 0) {
var context = Database;
//var meeting = context.Meetings.SingleOrDefault(m => m.SCO_ID == sco_id);
//JM - 9/27/2012 changed session to add a check for session not ended
var session = GetRecordingSession(scoId, context);
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
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,
Created = DateTime.UtcNow
};
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.OrderByDescending(pt => pt.StartDate)
.FirstOrDefault(
pt =>
pt.MeetingParticipantSessionKey ==
existingMeetingParticipantSession.MeetingParticipantSessionKey &&
pt.Principal_ID == principalId);
if(existingParticipantTracking != null) {
if(!existingParticipantTracking.EndDate.HasValue) {
//add exit time
existingParticipantTracking.EndDate = DateTime.UtcNow;
}
} else {
throw new ArgumentException(string.Format("Exiting user does not have an entrance time scoId = {0}, principalId = {1}, existingMeetingParticipantSession.MeetingParticipantSessionKey = {2}", scoId, principalId, existingMeetingParticipantSession.MeetingParticipantSessionKey));
}
adobe.GetAdobeTransactions(session, Database);
// Tyler Allen - 08/27/2016
// This is redundant and will cause deadlocks
//Database.SubmitChanges();
CheckParticipantSessions(session, principalId);
}
else {
result.Success = false;
result.Message = "Archive scoId: " + scoId + " is not a valid session.";
throw new ArgumentException(result.Message);
}
} else {
result.Success = false;
result.Message = "Principal ID: " + principalId + " is not valid";
throw new ArgumentException(result.Message);
}
} catch (Exception ex) {
Extensions.LogServiceError("[service.asmx][ArchiveSessionEnd]", ex);
result.Success = false;
result.Message = ex.Message;
} finally {
CloseArchiveSession(scoId);
}
/* This is the new modifications created by Tyler Allen [08/22/2016] */
// TODO: Depricated for new Notify application
// Launch a non-blocking thread to wait for 30 minutes for adobe results then email certificates
// System.Threading.Thread waitForResultsThread = new System.Threading.Thread(() => ArchiveSessionEndResultsThread(existingMeetingParticipantSession));
// waitForResultsThread.Start();
// -u = unattended
// -a = archive session
try {
Extensions.LogServiceCall("[service.asmx][ArchiveSessionEnd][Processing]", $"{notifyFilePath} -u -a {existingMeetingParticipantSession.MeetingParticipantSessionKey}");
//Process.Start($"{notifyFilePath} -u -a {existingMeetingParticipantSession.MeetingParticipantSessionKey}");
startNotify($"-u -a {existingMeetingParticipantSession.MeetingParticipantSessionKey}");
Extensions.LogServiceCall("[service.asmx][ArchiveSessionEnd][Started]", $"{notifyFilePath} -u -a {existingMeetingParticipantSession.MeetingParticipantSessionKey}");
}
catch (Exception exception) {
Extensions.LogServiceError("[service.asmx][ArchiveSessionEnd][CPE.App.Notify.exe]", exception);
//Extensions.LogServiceCall("[service.asmx][ArchiveSessionEnd]", $"There was an error processing CPE.App.Notify.exe [{notifyFilePath} -u -a {existingMeetingParticipantSession.MeetingParticipantSessionKey}] ({exception.Message}");
}
/* This is the new modifications created by Tyler Allen [08/22/2016] */
return result;
}
[WebMethod]
public bool CloseOpenUserSessions(int meetingSessionKey) {
Extensions.LogServiceCall("CloseOpenUserSessions", string.Format("Parameters: meetingSessionKey = {0}", meetingSessionKey));
var result = false;
try {
var session = Database.MeetingSessions.Single(ms => ms.MeetingSessionKey == meetingSessionKey);
var participants = Database.MeetingParticipantSessions.Where(m => m.MeetingSessionKey == session.MeetingSessionKey);
foreach (var participantSession in participants)
foreach (var participantTracking in participantSession.ParticipantTrackings.Where(t => !t.EndDate.HasValue)) {
// Tyler changed to get EndDate from the last engagement request.
//participantTracking.EndDate = session.EndDate;
var lastEngagement = participantTracking.MeetingParticipantSession.ParticipantEngagements.OrderByDescending(e => e.DisplayTime)
.FirstOrDefault();
if(lastEngagement == null)
participantTracking.EndDate = participantTracking.StartDate;
else
participantTracking.EndDate = lastEngagement.ResponseTime.HasValue
? lastEngagement.ResponseTime.Value
: lastEngagement.DisplayTime;
}
Database.SubmitChanges();
CleanupRebroadcastEngagements(meetingSessionKey);
result = true;
} catch (Exception ex) {
Extensions.LogServiceError("CloseOpenUserSessions", ex);
result = false;
}
return result;
}
private MeetingSession GetRecordingSession(int scoId, CPEWebDataContext context) {
var now = DateTime.UtcNow;
var twelveHoursAgo = now.AddHours(-12);
var session =
context.MeetingSessions.Where(ms => ms.SCO_ID == scoId && ms.StartDate >= twelveHoursAgo && ms.StartDate < now && ms.EndDate.HasValue)
.OrderByDescending(ms => ms.EndDate)
.FirstOrDefault() ??
getLastSession(scoId);
return session;
}
//static Dictionary> Tasks = new Dictionary>();
private void CloseArchiveSession(int scoId) {
var context = Database;
var session = GetRecordingSession(scoId, context);
if(session != null) {
//session.EndDate = endTime;
var participantSessions = context.MeetingParticipantSessions.Where(m => m.MeetingSessionKey == session.MeetingSessionKey);
foreach (var participantSession in participantSessions) {
var trackingsWithoutExit =
context.ParticipantTrackings.Where(
t => t.MeetingParticipantSessionKey == participantSession.MeetingParticipantSessionKey
&& !t.EndDate.HasValue)
.OrderByDescending(t => t.StartDate)
.FirstOrDefault();
//TODO: Try to catch logouts due to power failure
//look for las poll displayed and compare to logout time?
if(trackingsWithoutExit != null) {
// Tyler changed to get EndDate from the last engagement request.
//trackingsWithoutExit.EndDate = session.EndDate;
var lastEngagement = trackingsWithoutExit.MeetingParticipantSession.ParticipantEngagements.OrderByDescending(e => e.DisplayTime)
.FirstOrDefault();
if(lastEngagement == null)
trackingsWithoutExit.EndDate = trackingsWithoutExit.StartDate;
else
trackingsWithoutExit.EndDate = lastEngagement.ResponseTime.HasValue
? lastEngagement.ResponseTime.Value
: lastEngagement.DisplayTime;
}
//foreach (
// var participantTracking in
// participantSession.ParticipantTrackings.Where(t => !t.EndDate.HasValue))
// participantTracking.EndDate = session.EndDate;
}
context.SubmitChanges();
CleanupRebroadcastEngagements(session.MeetingSessionKey);
//CleanupSessionEngagements(session.MeetingSessionKey);
}
//string taskId = Guid.NewGuid().ToString();
//Tasks[taskId] = Task.Factory.StartNew(() => RunTask(scoId));
//return taskId;
}
//private bool RunTask(int scoId)
//{
// var result = false;
// //wait 10 seconds so all user logouts are tracked
// const int secondsToSleep = 2;
// Thread.Sleep(secondsToSleep * 1000);
// try
// {
// var context = Database;
// var session = getLastSession(scoId);
// if(session!= null)
// {
// //session.EndDate = endTime;
// var participants = context.MeetingParticipantSessions.Where(m => m.MeetingSessionKey == session.MeetingSessionKey);
// foreach (var participantSession in participants)
// foreach (var participantTracking in participantSession.ParticipantTrackings.Where(t => !t.EndDate.HasValue))
// participantTracking.EndDate = session.EndDate;
// context.SubmitChanges();
// //CleanupSessionEngagements(session.MeetingSessionKey);
// result = true;
// }
// }
// catch (Exception ex)
// {
// Extensions.LogServiceError("CloseArchiveSession", ex);
// result = false;
// }
// return result;
//}
[WebMethod]
public bool CleanupSession(int sessionKey) {
Extensions.LogServiceCall("CleanupSession", string.Format("Parameters: sessionKey = {0}", sessionKey));
CleanupSessionEngagements(sessionKey);
return true;
}
private void CleanupSessionEngagements(int sessionKey) {
try {
var context = Database;
Database.ArchiveSessionEngagements(sessionKey);
var session = context.MeetingSessions.Single(ms => ms.MeetingSessionKey == sessionKey);
//filter out engagements not sent by host
var engagementsToKeep = new List();
var heartbeats = session.MeetingSessionHeartbeats.Select(h => h.Timestamp)
.ToList();
foreach (var heartbeat in heartbeats) {
foreach (var ps in session.MeetingParticipantSessions) {
var validEngagements = context.ParticipantEngagements.Where(
pe => Math.Abs((pe.DisplayTime - heartbeat).TotalSeconds) < 30.0)
.Select(pe => pe.ParticipantEngagementKey)
.Distinct();
engagementsToKeep.AddRange(validEngagements);
}
}
engagementsToKeep = engagementsToKeep.Distinct()
.ToList();
var tooLarge = engagementsToKeep.Count >= 2000;
var meetingParticipantEngagementKeys = session.MeetingParticipantSessions.Select(mps => mps.MeetingParticipantSessionKey)
.ToList();
var allParticipantEngagements =
context.ParticipantEngagements.Where(
pe => meetingParticipantEngagementKeys.Contains(pe.MeetingParticipantSessionKey));
if(tooLarge) {
var allEngagementKeys = allParticipantEngagements.Select(pe => pe.ParticipantEngagementKey)
.ToList();
var engagementsToDelete = allEngagementKeys.Except(engagementsToKeep);
var query =
string.Format(
"DELETE FROM dbo.ParticipantEngagements WHERE ParticipantEngagementKey IN({0})",
string.Join(",", engagementsToDelete));
context.ExecuteCommand(query);
} else {
var engagementsToDelete =
allParticipantEngagements.Where(pe => !engagementsToKeep.Contains(pe.ParticipantEngagementKey));
context.ParticipantEngagements.DeleteAllOnSubmit(engagementsToDelete);
context.SubmitChanges();
}
//filter out duplicates
var duplicateKeys = new List();
foreach (var mps in session.MeetingParticipantSessions) {
var duplicateEngagements = context.GetDuplicateEngagements(mps.MeetingParticipantSessionKey)
.ToList();
if(duplicateEngagements.Any()) {
var keysProcessed = new List();
var keysToKeep = new List();
foreach (var getDuplicateEngagementsResult in duplicateEngagements) {
if(!keysProcessed.Contains(getDuplicateEngagementsResult.ParticipantEngagementKey)) {
var currentTime = getDuplicateEngagementsResult.DisplayTime;
var currentDuplicates =
duplicateEngagements.Where(
de => Math.Abs((de.DisplayTime - currentTime).TotalSeconds) <= 30.0);
var currentDuplicatesWithResponse = currentDuplicates.Where(cd => cd.ResponseTime.HasValue);
var currentDuplicatesWithoutResponse = currentDuplicates.Where(cd => !cd.ResponseTime.HasValue);
var dupKeyToKeep = currentDuplicatesWithResponse.Any()
? currentDuplicatesWithResponse.First()
.ParticipantEngagementKey
: currentDuplicatesWithoutResponse.First()
.ParticipantEngagementKey;
keysToKeep.Add(dupKeyToKeep);
keysProcessed.AddRange(currentDuplicates.Select(cd => cd.ParticipantEngagementKey));
}
}
duplicateKeys.AddRange(duplicateEngagements.Where(de => !keysToKeep.Contains(de.ParticipantEngagementKey))
.Select(de => de.ParticipantEngagementKey));
}
}
if(duplicateKeys.Any()) {
var distinctKeysToDelete = duplicateKeys.Distinct();
var duplicates =
context.ParticipantEngagements.Where(pe => distinctKeysToDelete.Contains(pe.ParticipantEngagementKey));
context.ParticipantEngagements.DeleteAllOnSubmit(duplicates);
}
context.SubmitChanges();
} catch (Exception ex) {
Extensions.LogServiceError("CleanupSessionEngagements", ex);
Console.WriteLine(ex.Message);
}
}
[WebMethod]
public bool CleanupRebroadcast(int sessionKey) {
Extensions.LogServiceCall("CleanupRebroadcast", string.Format("Parameters: sessionKey = {0}", sessionKey));
CleanupRebroadcastEngagements(sessionKey);
return true;
}
private void CleanupRebroadcastEngagements(int sessionKey) {
try {
var context = Database;
var meetingParticipantSessionKeys = context.MeetingParticipantSessions.Where(mps => mps.MeetingSessionKey == sessionKey)
.Select(mps => mps.MeetingParticipantSessionKey)
.ToArray();
var archived = context.ParticipantEngagementsArchives.Any(
pa => meetingParticipantSessionKeys.Contains(pa.MeetingParticipantSessionKey));
if(!archived)
Database.ArchiveSessionEngagements(sessionKey);
var session = context.MeetingSessions.Single(ms => ms.MeetingSessionKey == sessionKey);
//filter out duplicates
var duplicateKeys = new List();
foreach (var mps in session.MeetingParticipantSessions) {
var duplicateEngagements = context.GetDuplicateEngagements(mps.MeetingParticipantSessionKey)
.ToList();
if(duplicateEngagements.Any()) {
var keysProcessed = new List();
var keysToKeep = new List();
foreach (var getDuplicateEngagementsResult in duplicateEngagements) {
if(!keysProcessed.Contains(getDuplicateEngagementsResult.ParticipantEngagementKey)) {
var currentTime = getDuplicateEngagementsResult.DisplayTime;
var currentDuplicates =
duplicateEngagements.Where(
de => Math.Abs((de.DisplayTime - currentTime).TotalSeconds) <= 30.0);
var currentDuplicatesWithResponse = currentDuplicates.Where(cd => cd.ResponseTime.HasValue);
var currentDuplicatesWithoutResponse = currentDuplicates.Where(cd => !cd.ResponseTime.HasValue);
var dupKeyToKeep = currentDuplicatesWithResponse.Any()
? currentDuplicatesWithResponse.First()
.ParticipantEngagementKey
: currentDuplicatesWithoutResponse.First()
.ParticipantEngagementKey;
keysToKeep.Add(dupKeyToKeep);
keysProcessed.AddRange(currentDuplicates.Select(cd => cd.ParticipantEngagementKey));
}
}
duplicateKeys.AddRange(duplicateEngagements.Where(de => !keysToKeep.Contains(de.ParticipantEngagementKey))
.Select(de => de.ParticipantEngagementKey));
}
}
if(duplicateKeys.Any()) {
var distinctKeysToDelete = duplicateKeys.Distinct();
var duplicates =
context.ParticipantEngagements.Where(pe => distinctKeysToDelete.Contains(pe.ParticipantEngagementKey));
context.ParticipantEngagements.DeleteAllOnSubmit(duplicates);
}
context.SubmitChanges();
} catch (Exception ex) {
Extensions.LogServiceError("CleanupRebroadcastEngagements", ex);
Console.WriteLine(ex.Message);
}
}
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 MeetingSession getActiveSessionBySco(int sco_id) {
var now = DateTime.UtcNow;
var session =
Database.MeetingSessions.FirstOrDefault(
ms => ms.SCO_ID == sco_id && ms.StartDate <= now && (!ms.EndDate.HasValue || ms.EndDate.Value >= now));
return session;
}
private MeetingSession getActiveSessionByKey(int meetingSessionKey) {
var now = DateTime.UtcNow;
var session =
Database.MeetingSessions.SingleOrDefault(ms => ms.MeetingSessionKey == meetingSessionKey && ms.StartDate <= now);
// Tyler Allen - 09/01/2016
// Just send a session no matter what
// && (!ms.EndDate.HasValue || ms.EndDate.Value >= now));
return session;
}
private MeetingSession getLastSession(int sco_id) {
var now = DateTime.UtcNow;
var session =
Database.MeetingSessions.Where(
ms => ms.SCO_ID == sco_id && ms.StartDate <= now && ms.EndDate.HasValue && ms.EndDate.Value <= now)
.OrderByDescending(ms => ms.StartDate)
.FirstOrDefault();
return session;
}
private void CheckParticipantTracking(MeetingParticipantSession participantSession, int principalId) {
//Extensions.LogServiceCall("CheckParticipantTracking", String.Format("Parameters: participantSession.MeetingParticipantSessionKey = {0} principal_id = {1}", participantSession.MeetingParticipantSessionKey, principalId));
var context = Database;
var tracking = context.ParticipantTrackings.Where(t =>
t.Principal_ID == principalId &&
t.MeetingParticipantSessionKey == participantSession.MeetingParticipantSessionKey &&
!t.EndDate.HasValue)
.OrderByDescending(t => t.StartDate)
.FirstOrDefault();
if(tracking == null) {
tracking = new ParticipantTracking {
MeetingParticipantSessionKey =
participantSession.MeetingParticipantSessionKey,
Principal_ID = principalId,
StartDate = DateTime.UtcNow
};
context.ParticipantTrackings.InsertOnSubmit(tracking);
context.SubmitChanges();
}
}
}
public class SessionStatusClass {
public int MeetingSessionKey { get; set; }
public string Status { get; set; }
public int OwnerPrincipalId { get; set; }
}
public class ServiceStatus {
public bool Success { get; set; }
public string Message { get; set; }
}
public class Setting {
public int Interval { get; set; }
public string Text { get; set; }
public int Duration { get; set; }
}
public class Detail {
public string CourseCode { get; set; }
public string Instructor { get; set; }
public string Location { get; set; }
public string TopicID { get; set; }
public string Topic { get; set; }
}
}