Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stage #358

Merged
merged 12 commits into from
Sep 18, 2024
Merged

Stage #358

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions app/Http/Controllers/BffController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

namespace App\Http\Controllers;

use App\Http\Responses\ErrorResponse;
use App\Http\Responses\SuccessResponse;
use App\Services\CanvasService;
use App\Repositories\CourseSettingsRepository;

class BffController extends Controller
{
/**
* @var CanvasService
*/
protected $canvasService;

public function __construct(CanvasService $canvasService)
{
$this->canvasService = $canvasService;
}

// V2: SWR caching of response to speed up endpoint
// V2: Run all calls to get courses, settings, filters and highligthed course in parallel
// V2: Remove unused fields to reduce payload size for client side to download
public function getCoursesForFrontpage(bool $skip_cache = false)
{
try {
$accountIds = [99, 100, 102, 103, 137, 138, 139, 145];
$courseSettingsRepository = new CourseSettingsRepository();
$returnData = [
"courses" => [],
"settings" => [],
"filters" => [],
"highligthed" => []
];

$courses = $this->canvasService->getAllPublishedCourses();
$courseSettings = $courseSettingsRepository->getCourseSettingsForAllCourses();
$courseFilters = $courseSettingsRepository->getFilters();
$highligthedCourse = $courseSettingsRepository->getHighLightedCourse();

$coursesFiltered = [];
foreach ($courses as $courseKey => $courseItem) {
$courseObject = $courseItem->course;
$courseAccountId = $courseObject->account_id;
if (in_array($courseAccountId, $accountIds)) {
array_push($coursesFiltered, $courseItem);
}
}

$returnData["courses"] = $coursesFiltered;
$returnData["settings"] = $courseSettings;
$returnData["filters"] = $courseFilters;
$returnData["highligthed"] = $highligthedCourse;

$this->cachedCourses = $returnData;
return new SuccessResponse($returnData);
} catch (\Exception $e) {
return new ErrorResponse($e->getMessage());
}
}
}
72 changes: 33 additions & 39 deletions app/Http/Controllers/Lti3Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use App\Exceptions\LtiException;
use App\Ltiv3\LTI3_Database;
use App\Services\CanvasService;
use App\Services\DiplomaService;
use App\Services\DiplomaV2Service;
use App\Services\StatisticsService;
use App\Services\AdminDashboardService;
use App\Services\DashboardService;
Expand Down Expand Up @@ -131,40 +131,36 @@ public function launch(Request $request)
$logoList = $request->query("logo", $noLogoList);
Arr::set($settings_new, 'settings.custom_diploma_logo_list', $logoList);
}
session(['settings' => $settings_new['settings']]);

session(['settings' => $settings_new['settings']]);
logger("Lti3Middleware has settings.");

$settings = session()->get('settings');

if ($kpasMode == $diplomaMode) {
$downloadLink = true;
logger("embed diploma");

$diplomaService = new DiplomaService();
$hasDeservedDiploma = $diplomaService->hasDeservedDiploma($settings);
if(!$hasDeservedDiploma) {
$downloadLink = false;
}
$userId = $settings["custom_canvas_user_id"];
$userName = $settings['custom_canvas_user_display_name'];
$courseId = $settings["custom_canvas_course_id"];
$courseName = $settings['custom_canvas_course_name'];
$courseUserRoles = $settings['custom_canvas_roles'];
$courseDiplomaLogos = $settings['custom_diploma_logo_list'];

return $diplomaService->getDiplomaHtml($settings, $downloadLink, $hasDeservedDiploma);
}
else if($kpasMode == $statisticsMode) {
$diplomaV2Service = new DiplomaV2Service($userId, $userName, $courseId, $courseName, $courseUserRoles, $courseDiplomaLogos);
return $diplomaV2Service->render();
} else if ($kpasMode == $statisticsMode) {
$statisticsService = new StatisticsService();
return $statisticsService->getStatisticsHtml($settings);
}
else if($kpasMode == $dashboardMode) {
} else if ($kpasMode == $dashboardMode) {
$dashboardService = new DashboardService();
return $dashboardService->getDashboardHtml($settings);
}
else if($kpasMode == $surveyMode){
} else if ($kpasMode == $surveyMode){
$surveyService = new SurveyService();
return $surveyService->getSurveyBlade($settings);
}
else if($kpasMode == $adminDashboardMode){
} else if ($kpasMode == $adminDashboardMode){
$adminDashboardService = new AdminDashboardService();
return $adminDashboardService->getAdminDashboardBlade($settings);
}
else if($kpasMode == $courseSettingsMode) {
} else if ($kpasMode == $courseSettingsMode) {
$courseSettingsService = new CourseSettingsService();
return $courseSettingsService->getCourseSettingsBlade($settings);
}
Expand Down Expand Up @@ -264,30 +260,28 @@ public function kpas_settings()

public function diplomaPdf(Request $request)
{
logger("Diploma");
logger("DiplomaPDF");
$settings = session()->get('settings');
logger($settings);

$diplomaService = new DiplomaService();
$hasDeservedDiploma = $diplomaService->hasDeservedDiploma($settings);
if($hasDeservedDiploma) {
$dompdf = new Dompdf();
$userId = $settings["custom_canvas_user_id"];
$userName = $settings['custom_canvas_user_display_name'];
$courseId = $settings["custom_canvas_course_id"];
$courseName = $settings['custom_canvas_course_name'];
$courseUserRoles = $settings['custom_canvas_roles'];
$courseDiplomaLogos = $settings['custom_diploma_logo_list'];

//To make images/ references work.
$dompdf->getOptions()->setChroot(public_path());
$diplomaV2Service = new DiplomaV2Service($userId, $userName, $courseId, $courseName, $courseUserRoles, $courseDiplomaLogos);
if (!$diplomaV2Service->isCourseCompleted()) return (new ErrorResponse("Alle krav må fullføres før diplom kan lastes ned.", 403))->toResponse($request);

//To make external references to css etc. work.
$dompdf->getOptions()->set('isRemoteEnabled', true);
$downloadLink = false;
$noLogoList = [];
$logoList = $request->query("logo", $noLogoList);
$dompdf = new Dompdf();
$dompdf->getOptions()->setChroot(public_path());
$dompdf->getOptions()->set('isRemoteEnabled', true); // To make external references to css etc. work.

$html = $diplomaService->getDiplomaHtml($settings, $downloadLink, $hasDeservedDiploma);
$dompdf->loadHtml($html);
$dompdf->render();
$dompdf->stream("Diplom.pdf");
} else {
return (new ErrorResponse("Alle krav må fullføres før diplom kan lastes ned.", 403))->toResponse($request);
}
$html = $diplomaV2Service->render();
$dompdf->loadHtml($html);

$dompdf->render();
$dompdf->stream("Diplom.pdf");
}
}
15 changes: 8 additions & 7 deletions app/Services/CanvasService.php
Original file line number Diff line number Diff line change
Expand Up @@ -319,9 +319,8 @@ public function getAllCourses()

public function getAllPublishedCourses()
{
$accountId = config('canvas.account_id');
$url = "accounts/{$accountId}/courses";
return $this->request($url, 'GET', [], [], true);
$url = "/search/all_courses?open_enrollment_only=true&per_page=999";
return $this->request($url, 'GET', [], [], true, true);
}

public function getCourseModules($courseId)
Expand Down Expand Up @@ -445,13 +444,15 @@ public function removeUserFromGroup(int $groupId, int $userId)
return $this->request("groups/{$groupId}/users/{$userId}", 'DELETE');
}

protected function request(string $url, string $method = 'GET', array $data = [], array $headers = [], bool $paginable = false)
protected function request(string $url, string $method = 'GET', array $data = [], array $headers = [], bool $paginable = false, bool $skip_auth = false)
{
$fullUrl = "{$this->domain}/{$url}";

$headers = array_merge([
'Authorization' => 'Bearer ' . $this->accessKey,
], $headers);
if ($skip_auth != true) {
$headers = array_merge([
'Authorization' => 'Bearer ' . $this->accessKey,
], $headers);
}

$isFinished = false;

Expand Down
141 changes: 141 additions & 0 deletions app/Services/DiplomaV2Service.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<?php
namespace App\Services;

use GuzzleHttp\Client;

use App\Services\CanvasService;
use App\Models\Kompetansepakke;
use App\Models\Diploma;

class DiplomaV2Service {
public $userId;
public $userName;

public $courseId;
public $courseName;
public $courseUserRoles;

public $courseDiplomaDate;
public $courseDiplomaLogos;
public $courseDiplomaDescription;
public $courseDiplomaBy;

public $principalRoleName = "Skoleleder";
public $totalRequirements = 0;
public $totalRequirementsCompleted = 0;
public $modules = [];

public function __construct($userId, $userName, $courseId, $courseName, $courseUserRoles, $courseDiplomaLogos) {
$this->userId = $userId;
$this->userName = $userName;

$this->courseId = $courseId;
$this->courseName = $courseName;
$this->courseUserRoles = !empty($courseUserRoles) ? explode(",", $courseUserRoles) : [];

$kpasCourseSettings = Kompetansepakke::where('course_id', $this->courseId)->first();
$this->courseDiplomaDate = date("d.m.Y");
$this->courseDiplomaLogos = !empty($courseDiplomaLogos) && is_array($courseDiplomaLogos) ? $courseDiplomaLogos : [];
$this->courseDiplomaDescription = !empty($kpasCourseSettings) && !empty($kpasCourseSettings->diplom_beskrivelse) ? $kpasCourseSettings->diplom_beskrivelse : "";
$this->courseDiplomaBy = !empty($kpasCourseSettings) && !empty($kpasCourseSettings->utviklet_av) ? $kpasCourseSettings->utviklet_av : "";

$this->principalRoleName = config('canvas.principal_role');
$this->getCourseProgress();
}

private function getCourseProgress() {
$httpClient = new Client();
$canvasService = new CanvasService($httpClient);

$modulesForUser = $canvasService->getModulesForCourse($this->courseId, $this->userId);
$lastModuleKey = key(array_slice($modulesForUser, -1, 1, true));

foreach ($modulesForUser as $moduleKey => $moduleItem) {
$moduleObject = new DiplomaModule($moduleItem->id, $moduleItem->name, $moduleItem->completed_at);
$modulePages = $moduleItem->items;
$lastPageKey = key(array_slice($modulePages, -1, 1, true));

foreach ($modulePages as $pageKey => $pageItem) {
$pageCompleted = false;
$pageCompletionType = null;
$pageCompletionRequirement = $pageItem->completion_requirement ?? null;
$isLastModulesAndPage = false; // Pages should be marked as optional instead of this hotfix as diploma might not be the last page: $moduleKey == $lastModuleKey && $pageKey == $lastPageKey;

if (!$isLastModulesAndPage && !empty($pageCompletionRequirement)) {
$isPageIndented = !empty($pageItem->indent) && $pageItem->indent != 0;
$isPrincipal = in_array($this->principalRoleName, $this->courseUserRoles);
$includeNormalRequirements = !$isPageIndented;
$includeLeaderRequirements = $isPageIndented && $isPrincipal;

if ($includeNormalRequirements || $includeLeaderRequirements) {
$pageCompleted = $pageCompletionRequirement->completed == true;
if ($pageCompleted) $this->totalRequirementsCompleted++;

$pageCompletionType = $pageCompletionRequirement->type;
$this->totalRequirements++;
}
}

$pageObject = new DiplomaPage($pageItem->id, $pageItem->title, $pageItem->type, $pageItem->indent, $pageCompleted, $pageCompletionType);
array_push($moduleObject->pages, $pageObject);
}

array_push($this->modules, $moduleObject);
}

if (!$this->skipValidations() && $this->isCourseCompleted()) $this->storeDiplomaCompletion();
}

private function skipValidations() {
$skipSaveOnRoles = ["TeacherEnrollment", "Account Admin", "Udir-Innholdsprodusent", "Udir-forvalter"];
if (empty(array_intersect($skipSaveOnRoles, $this->courseUserRoles))) return false;
return true;
}

private function storeDiplomaCompletion() {
Diploma::updateOrCreate(["user_id" => $this->userId], ["course_id" => $this->courseId]);
}

public function isCourseCompleted() {
if ($this->skipValidations()) return true;
return $this->totalRequirementsCompleted == $this->totalRequirements;
}

public function render() {
logger("getDiplomaHtml");

return view('main.diploma-v2')
->withUserName($this->userName)
->withCourseName($this->courseName)
->withCourseDiplomaDate($this->courseDiplomaDate)
->withCourseDiplomaLogos($this->courseDiplomaLogos)
->withCourseDiplomaDescription($this->courseDiplomaDescription)
->withCourseDiplomaBy($this->courseDiplomaBy)

->withTotalRequirements($this->totalRequirements)
->withTotalRequirementsCompleted($this->totalRequirementsCompleted)
->withModules($this->modules)

->withIsCourseCompleted($this->isCourseCompleted());
}
}

class DiplomaModule {
public function __construct(
public int $id,
public string $title,
public ?string $completedAt = null,
public array $pages = []
) {}
}

class DiplomaPage {
public function __construct(
public int $id,
public string $title,
public string $type,
public string $indent,
public bool $completed,
public ?string $completionType = null
) {}
}
14 changes: 6 additions & 8 deletions resources/js/components/CourseSettingsCategoryCreate.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
<template>
<h2>Opprett ny kategori </h2>
<p>Navn: <input type="text" v-model="category_name"/></p>
<p>Posisjon: <input type="number" default=0 v-model="position"/></p>
<p>Tema: <input type="text" v-model="category_color"/> (theme_*number* må finnes som tema i frontend)</p>

<p>Kategorinavn: <input type="text" v-model="category_name"/></p>
<p>Kategoriposisjon: <input type="number" default=0 v-model="position"/></p>
<p>Kategoritema: <input type="text" v-model="category_color"/> (Kategoritema theme_*number* må finnes som tema i frontend)</p>

<button @click="createCategory">Opprett kategori</button>
<button class="kpas-button" @click="createCategory">Opprett fargetema</button>
<Message type="success" v-if="responseCode == 200" class='alert alert-success kpasAlert'>Oppdateringen var vellykket!</Message>
<Message type="error" v-if="error" class='alert alert-danger kpasAlert'>{{ error }}</Message>
</template>
Expand Down Expand Up @@ -33,11 +31,11 @@ export default{
let response = undefined;
this.error = undefined;
if(this.category_name == '' || this.category_name == null){
this.error = "Kategorinavn kan ikke være tomt"
this.error = "Navn kan ikke være tomt"
return;
}
if(this.category_color == '' || this.category_color == null){
this.error = "Kategoritema kan ikke være tomt"
this.error = "Tema kan ikke være tomt"
return;
}
try {
Expand Down
Loading
Loading