public function videoRecommendationsAction($scope = 'all', $groupingId = 'all', $debug = false)
 {
     $this->view->disable();
     // Get our context (this takes care of starting the session, too)
     $context = $this->getDI()->getShared('ltiContext');
     if (!$context->valid) {
         echo '[{"error":"Invalid lti context"}]';
         return;
     }
     if (!isset($groupingId)) {
         echo '[{"error":"No scope grouping ID specified"}]';
         return;
     }
     // Get the list of videos associated with concepts for the given scope and grouping ID
     $videos = [];
     switch ($scope) {
         case "concept":
             // Filter based on concept
             $videos = MappingHelper::videosForConcept($groupingId);
             break;
         case "unit":
             // Filter based on unit
             $videos = MappingHelper::videosForConcepts(MappingHelper::conceptsInUnit($groupingId));
             break;
         default:
             // All videos
             $videos = MappingHelper::videosForConcepts(MappingHelper::allConcepts());
             break;
     }
     // Find percentage watched for each video
     foreach ($videos as $key => $video) {
         $percentageWatched = MasteryHelper::calculateUniqueVideoPercentageForVideo($context->getUserName(), $video, $debug);
         // Add the percentage to the video
         $video["percentageWatched"] = $percentageWatched;
         // Add the modified video back to the original array
         $videos[$key] = $video;
     }
     // Format each video for the frontend
     $formatted = [];
     foreach ($videos as $video) {
         $formatted[] = $video;
     }
     if ($debug) {
         echo "<pre>Getting information for these video IDs in scope {$scope} and ID {$groupingId}\n";
         foreach ($videos as $video) {
             echo $video["Video ID"] . "\n";
         }
     }
     echo json_encode($formatted);
 }
 public function mappingsAction()
 {
     echo "<pre>";
     echo "All units\n";
     print_r(MappingHelper::allUnits());
     echo "<hr>Concepts in unit 4\n";
     print_r(MappingHelper::conceptsInUnit("4"));
     echo "<hr>Questions in concept (lecture number) 1\n";
     print_r(MappingHelper::questionsInConcept("1"));
     echo "<hr>Question info for question 78.4\n";
     print_r(MappingHelper::questionInformation("78.4"));
     echo "<hr>Videos for concept 9\n";
     print_r(MappingHelper::videosForConcept("9"));
     echo "<hr>Resources for concept 1\n";
     print_r(MappingHelper::resourcesForConcept("1"));
     echo "<hr>Concepts within the past 2 weeks: \n";
     print_r(MappingHelper::conceptsWithin2Weeks());
 }
 public static function videosInConceptLength($concept)
 {
     $videos = MappingHelper::videosForConcept($concept);
     $length = 0;
     foreach ($videos as $vid) {
         $length += $vid["Video Length"];
     }
     return $length;
 }
 public function resourcesAction()
 {
     $this->tag->setTitle('Course Resources | Student Dashboard');
     $this->view->pageTitle = 'Course Resources | Student Dashboard';
     // Get our context (this takes care of starting the session, too)
     $context = $this->getDI()->getShared('ltiContext');
     // Get list of concepts
     $conceptsMapping = MappingHelper::allConcepts();
     $concepts = [];
     $resources = [];
     // Get list of resources for each concept
     foreach ($conceptsMapping as $c) {
         // Formatting for view
         $concepts[] = ["id" => $c["Lecture Number"], "title" => $c["Concept Title"], "date" => $c["Date"]];
         // Get resources for each of the concepts
         $conceptId = $c["Lecture Number"];
         $resourceLists[$conceptId] = MappingHelper::resourcesForConcept($conceptId);
         // Get videos for each of the concepts
         $videos = MappingHelper::videosForConcept($conceptId);
         // Format videos to be the same format as ayamel links from the resources.csv mapping
         foreach ($videos as $video) {
             $resourceLists[$conceptId][] = ["Lecture Number" => $video["Lecture Number"], "Resource Type" => "ayamel", "Resource Title" => $video["Video Title"], "Resource Link" => $video["Video ID"], "Resource Tracking Number" => $video["Video ID"]];
         }
     }
     // Figure out which concept to position the list at (based on the current day)
     $currentConceptID = $conceptsMapping[0]["Date"];
     // This is assuming that every concept has a date, and that they are listed in concepts.csv in chronological non-descending order
     // Find the first concept that's past today, and then use the previous concept
     $today = strtotime("today");
     foreach ($conceptsMapping as $concept) {
         if (strtotime($concept["Date"]) > $today) {
             break;
         } else {
             $currentConceptID = $concept["Lecture Number"];
             // If this concept has a date of today, then stop
             if (strtotime($concept["Date"]) == $today) {
                 break;
             }
         }
     }
     $this->view->concepts = $concepts;
     $this->view->resources = $resourceLists;
     $this->view->currentConceptID = $currentConceptID;
 }
 public static function calculateUniqueVideoPercentageForConcept($studentId, $conceptId, $debug = false)
 {
     // Length of each statement in video seconds
     $watchedStatementLength = 10;
     // Find the videos related to this concept
     $relatedVideos = MappingHelper::videosForConcept($conceptId);
     $possibleWatchedStatementCount = 0;
     $userWatchedStatementCount = 0;
     $videoIds = array();
     foreach ($relatedVideos as $video) {
         // Length of video divided by 10 rounded down will be the total number of possible unique watched statements for that video
         $possibleWatchedStatementCount += floor($video["Video Length"] / $watchedStatementLength);
         // Add its ID to a list that we'll fetch watched statements for
         $videoIds[] = 'https://ayamel.byu.edu/content/' . $video["Video ID"];
     }
     // Calculate how much time these videos were watched
     // This is more efficient by using an $in query for all videos, rather than querying for each individual video as previously done
     $statementHelper = new StatementHelper();
     $statements = $statementHelper->getStatements("ayamel", ['statement.actor.name' => $studentId, 'statement.verb.id' => 'https://ayamel.byu.edu/watched', 'statement.object.id' => array('$in' => $videoIds)], ['statement.object.id' => true, 'statement.object.definition.extensions' => true]);
     if ($statements["error"]) {
         $userWatchedStatementCount = 0;
         if ($debug) {
             echo "Error in fetching watched statements for concept {$conceptId} and videos: \n";
             print_r($videoIds);
         }
     } else {
         // We need to track unique statements, so student can't get 100% video watched by watching the first half twice
         $videoTrackers = [];
         $watchStatementCount = $statements["cursor"]->count();
         foreach ($statements["cursor"] as $statement) {
             // We need to get rid of encoded "."s in extension names
             $statement = StatementHelper::replaceHtmlEntity($statement["statement"], true);
             // Set a flag for each rounded timestamp for each video
             $videoId = $statement["object"]["id"];
             $roundedTime = round($statement["object"]["definition"]["extensions"]["https://ayamel.byu.edu/playerTime"] / $watchedStatementLength);
             if (!isset($videoTrackers[$videoId])) {
                 $videoTrackers[$videoId] = [];
             }
             // See if a statement with the same rounded timestamp was already tracked
             if (isset($videoTrackers[$videoId][$roundedTime]) && $videoTrackers[$videoId][$roundedTime] == true) {
                 $isUnique = false;
             } else {
                 $isUnique = true;
                 $userWatchedStatementCount++;
                 // Track this statement
                 $videoTrackers[$videoId][$roundedTime] = true;
             }
             if ($debug) {
                 print_r($statement);
                 echo "Video id: {$videoId}, rounded time: {$roundedTime}, unique: {$isUnique} \n<hr>";
             }
         }
     }
     if ($debug) {
         echo "Videos for concept {$conceptId} : {$userWatchedStatementCount} unique watched statements out of {$possibleWatchedStatementCount} possible for the following videos: \n";
         print_r($videoIds);
     }
     // Return percentage (0-100) of videos watched, avoiding division by 0
     $percentage = $possibleWatchedStatementCount != 0 ? $userWatchedStatementCount / $possibleWatchedStatementCount : 0;
     $percentage = round($percentage * 100);
     return min($percentage, 100);
 }