initial commit
[CPE_learningsite] / CPE / CPE.App / CPE.App.NotifyConsole / Helpers / SessionHelper.cs
1 /*
2 Developer: Tyler Allen
3 Date Created: 08/24/2016
4 ---------------------------------------------------
5 */
6
7 using System;
8 using System.Collections.Generic;
9 using System.Configuration;
10 using System.Linq;
11 using CPE.App.NotifyConsole.Extensions;
12 using CPE.App.NotifyConsole.Models;
13 using CPE.App.NotifyConsole.Models.Enums;
14
15 namespace CPE.App.NotifyConsole.Helpers {
16     public static class SessionHelper {
17         private static readonly CPEWebDataContext _database = CPEWebDataContext.GetContext();
18
19
20         // Get meeting session
21         public static MeetingSession getMeetingSession(int meetingSessionKey) {
22             MeetingSession meetingSession = null;
23             meetingSession = _database
24                 .MeetingSessions.FirstOrDefault(x => x.MeetingSessionKey == meetingSessionKey);
25             return meetingSession.Log(key: meetingSessionKey);
26         }
27
28         // Get first meeting participant session
29         public static MeetingParticipantSession getMeetingParticipantSession(int meetingParticipantSessionKey) {
30             var meetingParticipantSession = _database
31                 .MeetingParticipantSessions.FirstOrDefault(x => x.MeetingParticipantSessionKey == meetingParticipantSessionKey)
32                 .Log();
33             return meetingParticipantSession.Log(key: meetingParticipantSessionKey);
34         }
35
36         // Get first meeting participant session
37         public static MeetingParticipantSession getMeetingParticipantSession(int meetingSessionKey, long participantKey) {
38             var meetingParticipantSession = _database
39                 .MeetingParticipantSessions
40                 .FirstOrDefault(mps => (mps.MeetingSessionKey == meetingSessionKey) && (mps.ParticipantKey == participantKey));
41             return meetingParticipantSession.Log(key: participantKey);
42         }
43
44         // Get meeting participant sessions
45         public static List<MeetingParticipantSession> getMeetingParticipantSessions(int meetingSessionKey) {
46             var listOfMeetingParticipantSessions = _database
47                 .MeetingParticipantSessions.Where(m => m.MeetingSessionKey == meetingSessionKey)
48                 .ToList();
49             return listOfMeetingParticipantSessions.Log(key: meetingSessionKey);
50         }
51
52         // Get participant purchase
53         public static ParticipantPurchase getParticipantPurchase(long participantKey, long scoId) {
54             var purchase = getParticipantPurchases(participantKey, scoId)
55                 .FirstOrDefault();
56             return purchase.Log(key: participantKey);
57         }
58
59         // Get participant purchase
60         public static ParticipantPurchase getParticipantPurchase(long scoId, DispositionProcessingStates dispositionProcessingState) {
61             var purchase = _database
62                 .ParticipantPurchases.FirstOrDefault(pp => (pp.MeetingSco == scoId) && (pp.DispositionProcessingState == (int) dispositionProcessingState));
63             return purchase.Log(key: scoId);
64         }
65
66         // Get participant purchase
67         public static List<ParticipantPurchase> getParticipantPurchases(long participantKey, long scoId) {
68             var purchases = _database
69                 .ParticipantPurchases
70                 .Where(pp => (pp.PrincipalID == participantKey) && (pp.MeetingSco == scoId))
71                 .ToList();
72             return purchases.Log(key: participantKey);
73         }
74
75         // Get participant tracking results
76         public static List<GetParticipantTrackingsResult> getParticipantTrackingResults(int meetingParticipantSessionKey) {
77             var participantTrackings = _database
78                 .GetParticipantTrackings()
79                 .Where(pt => pt.MeetingParticipantSessionKey == meetingParticipantSessionKey)
80                 .ToList();
81             return participantTrackings.Log(key: meetingParticipantSessionKey);
82         }
83
84         // Get participant session data result
85         public static ParticipantSessionsDataResult getParticipantSessionsDataResult(int meetingSessionKey, int meetingParticipantSessionKey) {
86             var participantSessionDataResult = _database.ParticipantSessionsData(meetingSessionKey)
87                                                         .FirstOrDefault(
88                                                                         psd =>
89                                                                             psd.MeetingParticipantSessionKey ==
90                                                                             meetingParticipantSessionKey);
91             return participantSessionDataResult.Log(key: meetingSessionKey);
92         }
93
94         public static IQueryable<GetRecordingCandidatesResult> getRecordingCandidates(int meetingSessionKey) {
95             return _database.GetRecordingCandidates(meetingSessionKey).Log(key: meetingSessionKey);
96         }
97
98         /// <summary>
99         /// </summary>
100         /// <param name="meetingParticipantSession"></param>
101         /// <param name="toEmail"></param>
102         /// <param name="meetingSco"></param>
103         /// <param name="purchaseDate"></param>
104         /// <param name="purchaseTicket"></param>
105         /// <returns></returns>
106         private static ParticipantResults processEndOfMeetingSessionAdobeConnectResultsForParticipant(MeetingParticipantSession meetingParticipantSession, out string toEmail, out int meetingSco, out DateTime purchaseDate, out string purchaseTicket) {
107             "Begin ProcessEndOfMeetingSessionAdobeConnectResultsForParticipant...".Log(key: meetingParticipantSession.MeetingParticipantSessionKey);
108
109             $"ProcessEndOfMeetingSessionAdobeConnectResultsForParticipant received the meetingParticipantSession {meetingParticipantSession}".Log(LoggingLevels.Info, key: meetingParticipantSession.MeetingParticipantSessionKey);
110
111             var result = ParticipantResults.Wonky;
112             toEmail = null;
113             meetingSco = -1;
114             purchaseDate = DateTime.MinValue;
115             purchaseTicket = null;
116
117             var principalid = meetingParticipantSession.ParticipantKey;
118             var meetingSessionKey = meetingParticipantSession.MeetingSessionKey;
119
120             var meeting = meetingParticipantSession.MeetingSession;
121             $"Meeting session was found {meeting}".Log(key: meetingParticipantSession.MeetingParticipantSessionKey);
122
123             var scoId = meeting.SCO_ID;
124
125             var participantTrackings = getParticipantTrackingResults(meetingParticipantSession.MeetingParticipantSessionKey)
126                 .ToList()
127                 .Log(key: meetingParticipantSession.MeetingParticipantSessionKey);
128             var participantSession =
129                 getParticipantSessionsDataResult(meetingSessionKey, meetingParticipantSession.MeetingParticipantSessionKey)
130                     .Log(key: meetingParticipantSession.MeetingParticipantSessionKey);
131
132             ParticipantPurchase purchase = null;
133             if(participantSession != null) {
134                 purchase = getParticipantPurchase(principalid, scoId)
135                     .Log(key: meetingParticipantSession.MeetingParticipantSessionKey);
136
137                 if(purchase == null) {
138                     result = ParticipantResults.Ineligible;
139                 } else {
140                     purchase.DispositionProcessingState = (int) DispositionProcessingStates.InProgress;
141                     _database.SubmitChanges();
142
143                     toEmail = purchase.Email;
144                     meetingSco = purchase.MeetingSco;
145                     purchaseDate = purchase.PurchaseDate;
146                     purchaseTicket = purchase.Ticket;
147
148                     var minutesInSessionHour = 50;
149
150                     var meetingSession =
151                         _database.MeetingSessionsData()
152                                  .FirstOrDefault(m => m.MeetingSessionKey == meetingSessionKey)
153                                  .Log(key: meetingParticipantSession.MeetingParticipantSessionKey);
154                     if(meetingSession != null) {
155                         double maxSessionTimePossibleRoundedDown = -1;
156                         if(meetingSession.ActualSessionTime != null) {
157                             // one of these integers needs to be cast to a double to get a double as an answer, that's how .NET math works.
158                             var maxSessionTimePossible = ((double) meetingSession.ActualSessionTime/minutesInSessionHour).Log(key: meetingParticipantSession.MeetingParticipantSessionKey);
159                             maxSessionTimePossibleRoundedDown = (Math.Floor(maxSessionTimePossible/.5)*.5).Log(key: meetingParticipantSession.MeetingParticipantSessionKey);
160                         }
161
162                         double sessionCreditRoundedDown = 0;
163                         if(participantSession.SessionCredit.HasValue) {
164                             var dbSessionCredit = Convert.ToDouble(participantSession.SessionCredit)
165                                                             .Log(key: meetingParticipantSession.MeetingParticipantSessionKey);
166
167                             sessionCreditRoundedDown = (Math.Floor(dbSessionCredit/.5)*.5).Log(key: meetingParticipantSession.MeetingParticipantSessionKey);
168                         }
169
170                         var validCourseCreditsValues =
171                             ConfigurationManager.AppSettings["MaxCourseCreditList"].Split(';')
172                                                 .Select(double.Parse)
173                                                 .ToList()
174                                                 .Log(key: meetingParticipantSession.MeetingParticipantSessionKey); //max credits cut list
175
176                         var mx = validCourseCreditsValues.BinarySearch(maxSessionTimePossibleRoundedDown);
177                         //find appropriate valid value for this course
178                         //user awarded no more than max possible credits for the course
179                         var arrayPosition = mx >= 0 ? mx : ~mx - 1; //...by rounding down
180                         var maxValidCourseCredit = validCourseCreditsValues[arrayPosition];
181
182                         if(sessionCreditRoundedDown < 1) {
183                             purchase.Credits = 0;
184                         } else {
185                             if(sessionCreditRoundedDown > maxSessionTimePossibleRoundedDown) {
186                                 purchase.Credits = maxSessionTimePossibleRoundedDown;
187                             } else if(sessionCreditRoundedDown > maxValidCourseCredit) {
188                                 purchase.Credits = maxValidCourseCredit;
189                             } else {
190                                 purchase.Credits = sessionCreditRoundedDown;
191                             }
192                         }
193
194                         var meetingDetail =
195                             _database.MeetingDetails.FirstOrDefault(m => m.MeetingKey == purchase.MeetingSco)
196                                      .Log(key: meetingParticipantSession.MeetingParticipantSessionKey);
197
198                         purchase.Presenter = meetingDetail == null ? "" : meetingDetail.Instructor;
199
200                         // 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.
201                         purchase.MeetingDate = DateTime.Now.Date;
202
203
204                         double sessionHeartbeatCountAsDouble = participantSession.SessionHeartbeatCount.GetValueOrDefault()
205                                                                                  .Log(message: "sessionHeartbeatCountAsDouble", key: meetingParticipantSession.MeetingParticipantSessionKey);
206                         double sessionEngagementCountAsDouble = participantSession.SessionEngagementCount.GetValueOrDefault()
207                                                                                   .Log(message: "sessionEngagementCountAsDouble", key: meetingParticipantSession.MeetingParticipantSessionKey);
208
209                         var percentComplete = (Math.Abs(Math.Abs(sessionHeartbeatCountAsDouble)) < 1 ? 1 : sessionEngagementCountAsDouble/sessionHeartbeatCountAsDouble).Log(message: "percentComplete", key: meetingParticipantSession.MeetingParticipantSessionKey);
210
211                         if((purchase.Credits >= 1.0) && (percentComplete >= .75)) //threshold for earning a certificate is 75% response rate
212                         {
213                             purchase.EarnedCertificate = true;
214                             result = ParticipantResults.Pass;
215                         } else {
216                             result = ParticipantResults.Fail;
217                         }
218
219
220                         purchase.DispositionProcessingState = (int) DispositionProcessingStates.Finished;
221
222                         _database.SubmitChanges();
223                     }
224                 }
225             }
226             if(purchase == null) {
227                 result = ParticipantResults.Ineligible;
228             }
229
230             $"Participant result returned {result}".Log(key: meetingParticipantSession.MeetingParticipantSessionKey);
231
232             "End ProcessEndOfMeetingSessionAdobeConnectResultsForParticipant...".Log(key: meetingParticipantSession.MeetingParticipantSessionKey);
233             return result;
234         }
235
236         /// <summary>
237         /// </summary>
238         /// <param name="meetingSessionKey"></param>
239         /// <param name="isUnitTest">Bypasses sending an email for testing purposes</param>
240         public static bool StopSession(int meetingSessionKey, bool isUnitTest = false) {
241             "Begin StopSession...".Log(key:meetingSessionKey);
242
243             $"StopSession received the meetingSessionKey {meetingSessionKey}".Log(LoggingLevels.Info, key: meetingSessionKey);
244
245             var boolResult = false;
246             try {
247                 var meetingSession = getMeetingSession(meetingSessionKey)
248                     .Log(key: meetingSessionKey);
249
250                 if(meetingSession == null) {
251                     $"Meeting session was not found for key - {meetingSessionKey}".Log(LoggingLevels.Error, key: meetingSessionKey);
252                 } else {
253                     try {
254                         // Is there a need to write a test for this?
255                         var adobeHelper = new AdobeHelper();
256                         if(adobeHelper.GetAdobeTransactions(meetingSession, _database)) {
257                             "Adobe transactions were found and processed".Log(key: meetingSessionKey);
258                             _database.SubmitChanges();
259                         } else {
260                             "No Adobe transactions were found".Log(LoggingLevels.Warn, key: meetingSessionKey);
261                         }
262
263
264                         var listOfMeetingParticipantSessions = getMeetingParticipantSessions(meetingSession.MeetingSessionKey)
265                             .Log(key: meetingSessionKey);
266                         foreach (var meetingParticipantSession in listOfMeetingParticipantSessions) {
267                             var purchase = getParticipantPurchase(meetingParticipantSession.ParticipantKey, meetingSession.SCO_ID)
268                                 .Log(key: meetingSessionKey);
269                             if(purchase != null) {
270                                 "A purchase was found and will be processed for a certificate".Log(key: meetingSessionKey);
271                                 string toEmail = null;
272                                 var meetingSco = -1;
273                                 DateTime purchaseDate;
274                                 string purchaseTicket = null;
275                                 "Begin ProcessEndOfMeetingSessionAdobeConnectResultsForParticipant...".Log(key: meetingSessionKey);
276                                 var passFailResult = processEndOfMeetingSessionAdobeConnectResultsForParticipant(meetingParticipantSession, out toEmail, out meetingSco, out purchaseDate, out purchaseTicket);
277                                 $"ProcessEndOfMeetingSessionAdobeConnectResultsForParticipant returned a result of {passFailResult}".Log(key: meetingSessionKey);
278                                 switch (passFailResult) {
279                                     case ParticipantResults.Ineligible:
280                                         break;
281                                     case ParticipantResults.Fail:
282                                         "Begin SendFailNotice...".Log(key: meetingSessionKey);
283                                         if(!isUnitTest) {
284                                             toEmail.Log(key: meetingSessionKey);
285                                             EmailCertificateHelper.SendFailNotice(toEmail);
286                                         }
287                                         "End SendFailNotice...".Log(key: meetingSessionKey);
288                                         break;
289                                     case ParticipantResults.Pass:
290                                         "Begin SendWebcastCert...".Log(key: meetingSessionKey);
291                                         if(!isUnitTest) {
292                                             toEmail.Log(key: meetingSessionKey);
293                                             EmailCertificateHelper.SendWebcastCert(toEmail, meetingSco, purchaseDate, purchaseTicket);
294                                         }
295                                         "End SendWebcastCert...".Log(key: meetingSessionKey);
296                                         break;
297                                     case ParticipantResults.Wonky:
298                                         break;
299                                 }
300                             }
301                         }
302                     } catch (Exception exception) {
303                         exception.Log(LoggingLevels.Fatal, key: meetingSessionKey);
304                     }
305                 }
306                 boolResult = true;
307             } catch (Exception exception) {
308                 exception.Log(LoggingLevels.Fatal, key: meetingSessionKey);
309             }
310
311             "End StopSession...".Log(key: meetingSessionKey);
312
313             return boolResult.Log(key: meetingSessionKey);
314         }
315
316         /// <summary>
317         /// </summary>
318         /// <param name="meetingParticipantSessionKey"></param>
319         /// <param name="isUnitTest">Bypasses sending an email for testing purposes</param>
320         public static bool ArchiveSession(int meetingParticipantSessionKey, bool isUnitTest = false) {
321             "Begin ArchiveSession...".Log(key: meetingParticipantSessionKey);
322
323             var boolResult = false;
324             try {
325                 var meetingParticipantSession = getMeetingParticipantSession(meetingParticipantSessionKey)
326                     .Log(key: meetingParticipantSessionKey);
327
328                 var meetingSession = getMeetingSession(meetingParticipantSession.MeetingSessionKey)
329                     .Log(key: meetingParticipantSessionKey);
330
331                 var purchase = getParticipantPurchase(meetingParticipantSession.ParticipantKey, meetingSession.SCO_ID)
332                     .Log(key: meetingParticipantSessionKey);
333                 if(purchase != null) {
334                     // Is there a need to write a test for this?
335                     var adobeHelper = new AdobeHelper();
336                     if(adobeHelper.GetAdobeTransactions(meetingSession, _database)) {
337                         "Adobe transactions were found and processed".Log(key: meetingParticipantSessionKey);
338                         _database.SubmitChanges();
339                     } else {
340                         "No Adobe transactions were found".Log(LoggingLevels.Warn, key: meetingParticipantSessionKey);
341                     }
342
343                     string toEmail = null;
344                     var meetingSco = -1;
345                     var purchaseDate = DateTime.MinValue;
346                     string purchaseTicket = null;
347                     var passFailResult = processEndOfMeetingSessionAdobeConnectResultsForParticipant(meetingParticipantSession, out toEmail, out meetingSco, out purchaseDate, out purchaseTicket)
348                         .Log(key: meetingParticipantSessionKey);
349                     switch (passFailResult) {
350                         case ParticipantResults.Ineligible:
351                             break;
352                         case ParticipantResults.Fail:
353                             "Begin SendFailNotice...".Log(key: meetingParticipantSessionKey);
354                             if(!isUnitTest) {
355                                 toEmail.Log();
356                                 EmailCertificateHelper.SendFailNotice(toEmail)
357                                                       .Log(key: meetingParticipantSessionKey);
358                             }
359                             "End SendFailNotice...".Log(key: meetingParticipantSessionKey);
360                             break;
361                         case ParticipantResults.Pass:
362                             "Begin SendWebcastCert...".Log(key: meetingParticipantSessionKey);
363                             if(!isUnitTest) {
364                                 toEmail.Log();
365                                 EmailCertificateHelper.SendWebcastCert(toEmail, meetingSco, purchaseDate, purchaseTicket)
366                                                       .Log(key: meetingParticipantSessionKey);
367                             }
368                             "End SendWebcastCert...".Log(key: meetingParticipantSessionKey);
369                             break;
370                         case ParticipantResults.Wonky:
371                             break;
372                     }
373                 }
374                 boolResult = true;
375             } catch (Exception exception) {
376                 exception.Log(LoggingLevels.Fatal, key: meetingParticipantSessionKey);
377             }
378             "End ArchiveSession...".Log(key: meetingParticipantSessionKey);
379             return boolResult;
380         }
381
382         /// <summary>
383         /// Pass a meeting session to process all recordings.
384         /// </summary>
385         /// <param name="meetingSessionKey"></param>
386         /// <param name="isUnitTest"></param>
387         /// <returns></returns>
388         public static bool ArchiveSessionByMeetingSession(int meetingSessionKey, bool isUnitTest = false) {
389             var returnResult = true;
390             var sessions = getRecordingCandidates(meetingSessionKey);
391             if(sessions.Any()) {
392                 foreach (var session in sessions) {
393                     if(!ArchiveSession(session.MeetingParticipantSessionKey, isUnitTest)) {
394                         returnResult = false;
395                     }
396                 }
397             }
398             return returnResult;
399         }
400     }
401 }