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