Skip to content

Commit

Permalink
feat: adjust to qppe changes
Browse files Browse the repository at this point in the history
  • Loading branch information
janbritz committed Aug 20, 2024
1 parent 06e630e commit f0f07ab
Show file tree
Hide file tree
Showing 20 changed files with 685 additions and 547 deletions.
23 changes: 3 additions & 20 deletions classes/api/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use moodle_exception;
use qtype_questionpy\array_converter\array_converter;
use qtype_questionpy\package\package_raw;
use qtype_questionpy\package\package_versions_info;
use stored_file;
use TypeError;

Expand All @@ -33,7 +34,7 @@ class api {
/**
* Retrieves QuestionPy packages from the application server.
*
* @return package_raw[]
* @return package_versions_info[]
* @throws moodle_exception
*/
public function get_packages(): array {
Expand All @@ -45,7 +46,7 @@ public function get_packages(): array {
$result = [];
foreach ($packages as $package) {
try {
$result[] = array_converter::from_array(package_raw::class, $package);
$result[] = array_converter::from_array(package_versions_info::class, $package);
} catch (TypeError $e) {
// TODO: decide what to do with faulty package.
debugging($e->getMessage());
Expand All @@ -55,24 +56,6 @@ public function get_packages(): array {
return $result;
}

/**
* Retrieves the package with the given hash, returns null if not found.
*
* @param string $hash the hash of the package to get
* @return ?package_raw the package with the given hash or null if not found
* @throws moodle_exception
*/
public function get_package(string $hash): ?package_raw {
$connector = connector::default();
$response = $connector->get("/packages/$hash");

if ($response->code === 404) {
return null;
}
$response->assert_2xx();
return array_converter::from_array(package_raw::class, $response->get_data());
}

/**
* Returns the {@see package_api} of a specific package.
*
Expand Down
26 changes: 19 additions & 7 deletions classes/external/load_packages.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
use external_value;
use moodle_exception;
use qtype_questionpy\api\api;
use qtype_questionpy\package\package;
use qtype_questionpy\package\package_version;

/**
Expand Down Expand Up @@ -60,17 +61,28 @@ public static function execute(): array {

$transaction = $DB->start_delegated_transaction();

// Remove every package version.
$versions = package_version::get_many();
foreach ($versions as $version) {
$version->delete();
}

// Load and store packages from the application server.
$api = new api();
$packages = $api->get_packages();
$incomingpackageids = [];
foreach ($packages as $package) {
$package->store();
[$incomingpackageids[], ] = $package->upsert();
}

// Remove old packages.
if (empty($incomingpackageids)) {
// There are no incoming packages -> remove every package.
$packages = package::get_records();
foreach ($packages as $package) {
$package->delete();
}
} else {
[$sql, $params] = $DB->get_in_or_equal($incomingpackageids, SQL_PARAMS_NAMED, 'packageid', false);
$removedpackageids = $DB->get_fieldset_select('qtype_questionpy_package', 'id', "id $sql", $params);
foreach ($removedpackageids as $id) {
[$package] = package::get_records(['id' => $id]);
$package->delete();
}
}

$transaction->allow_commit();
Expand Down
24 changes: 12 additions & 12 deletions classes/package/package_base.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,57 +30,57 @@ class package_base {
/**
* @var string package shortname
*/
protected string $shortname;
public readonly string $shortname;

/**
* @var string package namespace
*/
protected string $namespace;
public readonly string $namespace;

/**
* @var array package name
*/
protected array $name;
public readonly array $name;

/**
* @var string package type
*/
protected string $type;
public readonly string $type;

/**
* @var string|null package author
*/
protected ?string $author;
public readonly ?string $author;

/**
* @var string|null package url
*/
protected ?string $url;
public readonly ?string $url;

/**
* @var array|null package languages
*/
protected ?array $languages;
public readonly ?array $languages;

/**
* @var array|null package description
*/
protected ?array $description;
public readonly ?array $description;

/**
* @var string|null package icon
*/
protected ?string $icon;
public readonly ?string $icon;

/**
* @var string|null package license
*/
protected ?string $license;
public readonly ?string $license;

/**
* @var array|null package tags
*/
protected ?array $tags;
public readonly ?array $tags;

/**
* Constructs package class.
Expand Down Expand Up @@ -118,7 +118,7 @@ public function __construct(string $shortname, string $namespace, array $name, s
/**
* Creates a localized array representation of the package.
*
* @param array|null $languages
* @param array $languages
* @return array array representation of the package
* @throws moodle_exception
*/
Expand Down
179 changes: 179 additions & 0 deletions classes/package/package_info.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
<?php
// This file is part of the QuestionPy Moodle plugin - https://questionpy.org
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

namespace qtype_questionpy\package;

defined('MOODLE_INTERNAL') || die;

use moodle_exception;
use qtype_questionpy\array_converter\array_converter;
use qtype_questionpy\array_converter\converter_config;

/**
* Represents an overview of available QuestionPy packages on the application server.
*
* @package qtype_questionpy
* @copyright 2024 Jan Britz, TU Berlin, innoCampus - www.questionpy.org
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class package_info extends package_base {
/**
* Checks whether this package exists or not.
*
* @return bool|int either false or the DB id
* @throws moodle_exception
*/
public function exists(): bool|int {
global $DB;
return $DB->get_field('qtype_questionpy_package', 'id', [
'shortname' => $this->shortname,
'namespace' => $this->namespace,
]);
}

/**
* Persists a package tag in the database.
*
* @param string $tag
* @return int
* @throws moodle_exception
*/
private function store_tag(string $tag): int {
global $DB;

$record = ['tag' => strtolower($tag)];

$id = $DB->get_field('qtype_questionpy_tag', 'id', $record);
if ($id === false) {
return $DB->insert_record('qtype_questionpy_tag', $record);
}
return $id;
}

/**
* Inserts new package data.
*
* @param int $timestamp
* @return int
* @throws moodle_exception
*/
public function insert(int $timestamp): int {
global $DB;
$transaction = $DB->start_delegated_transaction();
$id = $DB->insert_record('qtype_questionpy_package', [
'shortname' => $this->shortname,
'namespace' => $this->namespace,
'type' => $this->type,
'author' => $this->author,
'url' => $this->url,
'icon' => $this->icon,
'license' => $this->license,
'timemodified' => $timestamp,
'timecreated' => $timestamp,
]);

if ($this->languages) {
// For each language store the localized package data as a separate record.
$languagedata = [];
foreach ($this->languages as $language) {
$languagedata[] = [
'packageid' => $id,
'language' => $language,
'name' => $this->get_localized_name([$language]),
'description' => $this->get_localized_description([$language]),
];
}
$DB->insert_records('qtype_questionpy_language', $languagedata);
}

if ($this->tags) {
// Store each tag with the package id in the tag table.
$tagsdata = [];
foreach ($this->tags as $tag) {
$tagsdata[] = [
'packageid' => $id,
'tagid' => $this->store_tag($tag),
];
}
$DB->insert_records('qtype_questionpy_pkgtag', $tagsdata);
}

$transaction->allow_commit();
return $id;
}

/**
* Updates existing package info.
*
* @param int $id
* @param int $timestamp
* @throws moodle_exception
*/
public function update(int $id, int $timestamp): void {
global $DB;
$transaction = $DB->start_delegated_transaction();
$DB->update_record('qtype_questionpy_package', [
'id' => $id,
'type' => $this->type,
'author' => $this->author,
'url' => $this->url,
'icon' => $this->icon,
'license' => $this->license,
'timemodified' => $timestamp,
]);

// We remove every language and tag entry and insert the new ones for simplicity.
$DB->delete_records('qtype_questionpy_language', ['packageid' => $id]);
foreach ($this->languages as $language) {
$DB->insert_record('qtype_questionpy_language', [
'packageid' => $id,
'language' => $language,
'name' => $this->get_localized_name([$language]),
'description' => $this->get_localized_description([$language]),
]);
}

$DB->delete_records('qtype_questionpy_pkgtag', ['packageid' => $id]);
// Store each tag with the package id in the tag table.
$tagsdata = [];
foreach ($this->tags as $tag) {
$tagsdata[] = [
'packageid' => $id,
'tagid' => $this->store_tag($tag),
];
}
$DB->insert_records('qtype_questionpy_pkgtag', $tagsdata);
$DB->execute("
DELETE
FROM {qtype_questionpy_tag}
WHERE id NOT IN (
SELECT tagid
FROM {qtype_questionpy_pkgtag}
)
");

$transaction->allow_commit();
}
}

array_converter::configure(package_info::class, function (converter_config $config) {
$config
->rename("hash", "package_hash")
->rename("shortname", "short_name")
// The DB rows are also read using array_converter, but their columns are named differently to the json fields.
->alias("hash", "hash")
->alias("shortname", "shortname");
});
Loading

0 comments on commit f0f07ab

Please sign in to comment.