1 using CPE.App.Web.Models;
3 using System.Collections.Generic;
4 using System.Configuration;
7 namespace CPE.App.Web.Code
9 public enum participantResult
14 Wonky //instead of throwing an error if something is null, we'll ask the client to contact cust service
17 public enum DispositionProcessingState
24 public class SessionEnd
26 public static participantResult ProcessEndOfMeetingSessionHeartbeatResultsForParticipant(CPEWebDataContext Database, MeetingParticipantSession meetingParticipantSession)
28 participantResult result = participantResult.Wonky;
30 int principalid = meetingParticipantSession.ParticipantKey;
31 int msk = meetingParticipantSession.MeetingSessionKey;
33 var meeting = meetingParticipantSession.MeetingSession;
34 int scoid = meeting.SCO_ID;
36 var participantEngagements = Database.ParticipantEngagements.Where(pe => pe.MeetingParticipantSessionKey == meetingParticipantSession.MeetingParticipantSessionKey);
37 int SessionHeartbeatCount = participantEngagements.Count();
38 int SessionEngagementCount = participantEngagements.Where(pe => pe.ResponseTime != null).Count();
40 ParticipantPurchase purchase = null;
41 var purchases = Database.ParticipantPurchases.Where(pp => pp.PrincipalID == principalid && pp.MeetingSco == scoid);
42 purchase = purchases.FirstOrDefault();
46 Extensions.LogServiceCall("[SessionEnd][ProcessEndOfMeetingSessionHeartbeatResultsForParticipant]", String.Format("purchase is null: principalid = {0} scoid = {1}", principalid, scoid));
47 result = participantResult.Ineligible;
51 if (purchases.Count() > 1)
53 Extensions.LogServiceCall("[SessionEnd][ProcessEndOfMeetingSessionHeartbeatResultsForParticipant]", String.Format("purchases count unexpectedly found > 1 : principalid = {0} scoid = {1} purchases.Count = {2}", principalid, scoid, purchases.Count()));
57 Extensions.LogServiceCall("[SessionEnd][ProcessEndOfMeetingSessionHeartbeatResultsForParticipant]", String.Format(
58 "Before Percent Calc: principalid = {0} scoid = {1} SessionEngagementCount = {2} SessionHeartbeatCount = {3}",
59 principalid, scoid, SessionEngagementCount, SessionHeartbeatCount));
61 double sessionHeartbeatCountAsDouble = SessionHeartbeatCount;
62 double sessionEngagementCountAsDouble = SessionEngagementCount;
64 double percentComplete = (sessionHeartbeatCountAsDouble == 0 ? 1 : (sessionEngagementCountAsDouble / sessionHeartbeatCountAsDouble));
66 if (percentComplete >= .75) //threshold for earning a certificate is 75% response rate
68 result = participantResult.Pass;
72 result = participantResult.Fail;
75 Extensions.LogServiceCall("[SessionEnd][ProcessEndOfMeetingSessionHeartbeatResultsForParticipant]", String.Format(
76 "Before SubmitChanges: principalid = {0} scoid = {1} result = {2} percentComplete = {3} SessionEngagementCount = {4} SessionHeartbeatCount = {5}",
77 principalid, scoid, result, percentComplete, SessionEngagementCount, SessionHeartbeatCount));
84 public static participantResult ProcessEndOfMeetingSessionAdobeConnectResultsForParticipant(CPEWebDataContext Database, MeetingParticipantSession meetingParticipantSession, out string toEmail, out int meetingSco, out DateTime purchaseDate, out string purchaseTicket)
86 participantResult result = participantResult.Wonky;
89 purchaseDate = DateTime.MinValue;
90 purchaseTicket = null;
92 int principalid = meetingParticipantSession.ParticipantKey;
93 int msk = meetingParticipantSession.MeetingSessionKey;
95 var meeting = meetingParticipantSession.MeetingSession;
96 int scoid = meeting.SCO_ID;
99 int maxPollingCount = 40;
100 var partTrackingsForMpsk = Database.GetParticipantTrackings().Where(pt => pt.MeetingParticipantSessionKey == meetingParticipantSession.MeetingParticipantSessionKey);
101 while ((partTrackingsForMpsk.Count() < 1) && (pollingCount < maxPollingCount)) // Try for 2 minutes
103 System.Threading.Thread.Sleep(5000); // 5 seconds
105 //adobe.GetAdobeTransactions(meeting, Database);
106 //Database.SubmitChanges();
108 // Try to force refresh data context
111 Database.Refresh(System.Data.Linq.RefreshMode.KeepChanges, Database.AdobeTransactions);
115 // Unable to refresh the specified object. The object no longer exists in the database.
116 Extensions.LogServiceError("[SessionEnd][ProcessEndOfMeetingSessionAdobeConnectResultsForParticipant] 1 " + meetingParticipantSession.MeetingParticipantSessionKey, ex);
118 Database = new CPEWebDataContext();
119 partTrackingsForMpsk = Database.GetParticipantTrackings().Where(pt => pt.MeetingParticipantSessionKey == meetingParticipantSession.MeetingParticipantSessionKey);
123 if (pollingCount == maxPollingCount)
125 Extensions.LogServiceCall("[SessionEnd][ProcessEndOfMeetingSessionAdobeConnectResultsForParticipant]", String.Format("Hit max poll attempts while searching for ParticipantTracking: principalid = {0} scoid = {1} pollingCount = {2}", principalid, scoid, pollingCount));
129 Extensions.LogServiceCall("[SessionEnd][ProcessEndOfMeetingSessionAdobeConnectResultsForParticipant]", String.Format("ParticipantTracking record found: principalid = {0} scoid = {1} pollingCount = {2}", principalid, scoid, pollingCount));
132 // Try to force refresh data context
135 Database.Refresh(System.Data.Linq.RefreshMode.KeepChanges, Database.AdobeTransactions);
139 // Unable to refresh the specified object. The object no longer exists in the database.
140 Extensions.LogServiceError("[SessionEnd][ProcessEndOfMeetingSessionAdobeConnectResultsForParticipant] 2 " + meetingParticipantSession.MeetingParticipantSessionKey, ex);
142 Database = new CPEWebDataContext();
144 // Log the transactions that are used to make pass/fail and credit decisions
145 IQueryable<AdobeTransaction> adobeTransactionForUserInMeeting = Database.AdobeTransactions.Where(at => at.MeetingSessionKey == msk && at.Principal_ID == meetingParticipantSession.ParticipantKey);
146 foreach (AdobeTransaction at in adobeTransactionForUserInMeeting)
148 Extensions.LogServiceCall("[SessionEnd][ProcessEndOfMeetingSessionAdobeConnectResultsForParticipant]", String.Format("principalid = {0} scoid = {1} AdobeTransactionKey = {2} StartDate = {3} EndDate = {4} MeetingSessionKey = {5}", principalid, scoid, at.AdobeTransactionKey, at.StartDate, at.EndDate, at.MeetingSessionKey));
151 ParticipantSessionsDataResult psdr =
152 Database.ParticipantSessionsData(msk)
155 psd.MeetingParticipantSessionKey ==
156 meetingParticipantSession.MeetingParticipantSessionKey);
157 ParticipantPurchase purchase = null;
160 var purchases = Database.ParticipantPurchases.Where(pp => pp.PrincipalID == principalid && pp.MeetingSco == scoid);
161 purchase = purchases.FirstOrDefault();
163 if (purchase == null)
165 Extensions.LogServiceCall("[SessionEnd][ProcessEndOfMeetingSessionAdobeConnectResultsForParticipant]", String.Format("purchase is null: principalid = {0} scoid = {1}", principalid, scoid));
166 result = participantResult.Ineligible;
170 if (purchases.Count() > 1)
172 Extensions.LogServiceCall("[SessionEnd][ProcessEndOfMeetingSessionAdobeConnectResultsForParticipant]", String.Format("purchases count unexpectedly found > 1 : principalid = {0} scoid = {1} purchases.Count = {2}", principalid, scoid, purchases.Count()));
175 purchase.DispositionProcessingState = (int)DispositionProcessingState.InProgress;
176 Database.SubmitChanges();
178 toEmail = purchase.Email;
179 meetingSco = purchase.MeetingSco;
180 purchaseDate = purchase.PurchaseDate;
181 purchaseTicket = purchase.Ticket;
183 int minutesInSessionHour = 50;
185 MeetingSessionsDataResult meetingSession =
186 Database.MeetingSessionsData().FirstOrDefault(m => m.MeetingSessionKey == msk);
187 if (meetingSession != null)
189 double maxSessionTimePossible = -1;
190 double maxSessionTimePossibleRoundedDown = -1;
191 if (meetingSession.ActualSessionTime != null)
193 // one of these integers needs to be cast to a double to get a double as an answer, that's how .NET math works.
194 maxSessionTimePossible = ((double)meetingSession.ActualSessionTime) / minutesInSessionHour;
195 maxSessionTimePossibleRoundedDown = (Math.Floor(maxSessionTimePossible / .5)) * .5;
199 Extensions.LogServiceCall("[SessionEnd][ProcessEndOfMeetingSessionAdobeConnectResultsForParticipant]", String.Format("ActualSessionTime unexpectedly found == null : principalid = {0} scoid = {1} MeetingSessionKey = {2}", principalid, scoid, msk));
202 double dbSessionCredit = 0;
203 double sessionCreditRoundedDown = 0;
204 if (psdr.SessionCredit.HasValue)
206 dbSessionCredit = Convert.ToDouble(psdr.SessionCredit);
208 sessionCreditRoundedDown = (Math.Floor(dbSessionCredit / .5))*.5;
211 List<double> validCourseCreditsValues =
212 ConfigurationManager.AppSettings["MaxCourseCreditList"].Split(';')
213 .Select(s => double.Parse(s))
214 .ToList(); //max credits cut list
216 int mx = validCourseCreditsValues.BinarySearch(maxSessionTimePossibleRoundedDown);
217 //find appropriate valid value for this course
218 //user awarded no more than max possible credits for the course
219 int arrayPosition = mx >= 0 ? mx : ~mx - 1; //...by rounding down
220 double maxValidCourseCredit = validCourseCreditsValues[arrayPosition];
222 if (sessionCreditRoundedDown < 1)
224 purchase.Credits = 0;
228 if (sessionCreditRoundedDown > maxSessionTimePossibleRoundedDown)
230 purchase.Credits = maxSessionTimePossibleRoundedDown;
232 else if (sessionCreditRoundedDown > maxValidCourseCredit)
234 purchase.Credits = maxValidCourseCredit;
238 purchase.Credits = sessionCreditRoundedDown;
242 MeetingDetail meetingDetail =
243 Database.MeetingDetails.FirstOrDefault(m => m.MeetingKey == purchase.MeetingSco);
245 purchase.Presenter = meetingDetail == null ? "" : meetingDetail.Instructor;
247 // This value gets set on first login, which may not be the date the cerficate was earned on (this value gets displayed on the certificate). Ideally we would use the local user's time zone to figure the date.
248 purchase.MeetingDate = DateTime.Now.Date;
250 Extensions.LogServiceCall("[SessionEnd][ProcessEndOfMeetingSessionAdobeConnectResultsForParticipant]", String.Format(
251 "Before Percent Calc: principalid = {0} scoid = {1} SessionEngagementCount = {2} SessionHeartbeatCount = {3}",
252 principalid, scoid, psdr.SessionEngagementCount.GetValueOrDefault(), psdr.SessionHeartbeatCount.GetValueOrDefault()));
254 double sessionHeartbeatCountAsDouble = psdr.SessionHeartbeatCount.GetValueOrDefault();
255 double sessionEngagementCountAsDouble = psdr.SessionEngagementCount.GetValueOrDefault();
257 double percentComplete = (sessionHeartbeatCountAsDouble == 0 ? 1 : (sessionEngagementCountAsDouble / sessionHeartbeatCountAsDouble));
259 if ((purchase.Credits >= 1.0) && (percentComplete >= .75)) //threshold for earning a certificate is 75% response rate
261 purchase.EarnedCertificate = true;
262 result = participantResult.Pass;
266 result = participantResult.Fail;
269 Extensions.LogServiceCall("[SessionEnd][ProcessEndOfMeetingSessionAdobeConnectResultsForParticipant]", String.Format(
270 "Before SubmitChanges: principalid = {0} scoid = {1} result = {2} percentComplete = {3} dbSessionCredit = {4} sessionCreditRoundedDown = {5} purchase.Credits = {6} SessionEngagementCount = {7} SessionHeartbeatCount = {8}",
271 principalid, scoid, result, percentComplete, dbSessionCredit, sessionCreditRoundedDown, purchase.Credits, psdr.SessionEngagementCount.GetValueOrDefault(), psdr.SessionHeartbeatCount.GetValueOrDefault()));
273 purchase.DispositionProcessingState = (int)DispositionProcessingState.Finished;
275 Database.SubmitChanges();
277 // Comment this back out once things are working better
278 //Extensions.LogServiceCall("[SessionEnd][ProcessEndOfMeetingSessionAdobeConnectResultsForParticipant]", String.Format("After SubmitChanges: principalid = {0} scoid = {1}", principalid, scoid));
282 Extensions.LogServiceCall("[SessionEnd][ProcessEndOfMeetingSessionAdobeConnectResultsForParticipant]", String.Format(
283 "meetingSession is null: principalid = {0} scoid = {1} msk = {2}",
284 principalid, scoid, msk));
290 Extensions.LogServiceCall("[SessionEnd][ProcessEndOfMeetingSessionAdobeConnectResultsForParticipant]", String.Format(
291 "psdr is null A: principalid = {0} scoid = {1} msk = {2} meetingParticipantSession.MeetingParticipantSessionKey = {3} meeting.StartDate = {4} meeting.EndDate = {5}",
292 principalid, scoid, msk, meetingParticipantSession.MeetingParticipantSessionKey, meeting.StartDate, meeting.EndDate));
294 if (purchase == null)
296 result = participantResult.Ineligible;
299 //Extensions.LogServiceCall("[SessionEnd][ProcessEndOfMeetingSessionAdobeConnectResultsForParticipant]", String.Format("After switch statement: principalid = {0} scoid= {1}", principalid, scoid));