Add Status Report to Info page

This commit is contained in:
Tom 2023-07-10 18:47:06 +02:00
parent cda68d3454
commit f5c5999f44
11 changed files with 361 additions and 20 deletions

View file

@ -0,0 +1,66 @@
package extras
import (
"context"
"github.com/FAU-CDI/wisski-distillery/internal/phpx"
"github.com/FAU-CDI/wisski-distillery/internal/status"
"github.com/FAU-CDI/wisski-distillery/internal/wisski/ingredient"
"github.com/FAU-CDI/wisski-distillery/internal/wisski/ingredient/php"
"golang.org/x/exp/slices"
_ "embed"
)
type Requirements struct {
ingredient.Base
Dependencies struct {
PHP *php.PHP
}
}
var (
_ ingredient.WissKIFetcher = (*Requirements)(nil)
)
//go:embed requirements.php
var requirementsPHP string
// Create creates a new block with the given title and html content
func (requirements *Requirements) Get(ctx context.Context, server *phpx.Server) (data []status.Requirement, err error) {
err = requirements.Dependencies.PHP.ExecScript(ctx, server, &data, requirementsPHP, "get_requirements", requirements.URL().String())
if err == nil {
// sort first by weight, then by id!
slices.SortFunc(data, func(a, b status.Requirement) bool {
// compare first by weight
if a.Weight < b.Weight {
return true
}
if a.Weight > b.Weight {
return false
}
// then by severity
if a.Severity < b.Severity {
return true
}
if a.Severity > b.Severity {
return false
}
// and finally by id
return a.ID < b.ID
})
}
return
}
// Fetch fetches information
func (requirements *Requirements) Fetch(flags ingredient.FetcherFlags, target *status.WissKI) error {
if flags.Quick {
return nil
}
target.Requirements, _ = requirements.Get(flags.Context, flags.Server)
return nil
}

View file

@ -0,0 +1,125 @@
<?php
/**
* Returns a well-typed array of all requirements.
* Relative URLs will be placed in the given domain.
*/
function get_requirements(string $public = ""): array {
$results = [];
$managerService = \Drupal::service('system.manager');
$rendererService = \Drupal::service('renderer');
$requirements = $managerService->listRequirements();
foreach($requirements as $id => $req) {
$title = $req['title'] ?? NULL;
$weight = $req['weight'] ?? NULL;
$severity = $req['severity'] ?? NULL;
$value = $req['value'] ?? NULL;
$description = $req['description'] ?? NULL;
$results[] = array(
"id" => $id,
"title" => strip_tags(ensure_html($rendererService, $title)),
"weight" => is_numeric($weight) ? $weight : 0,
"severity" => is_numeric($severity) ? $severity : 0,
"value" => clean_html(ensure_html($rendererService, $value), $public),
"description" => clean_html(ensure_html($rendererService, $description), $public),
);
}
return $results;
}
/**
* Ensures that the passed data is drupal html code.
*
* @param mixed $data
* @return string
*/
function ensure_html(mixed $renderer, mixed $data): string {
// already a string => return it!
if (is_string($data)) {
return $data;
}
// it is null => return the empty string
if ($data === NULL) {
return "";
}
// create a render array and render it!
$rary = is_array($data) ? $data : ["#markup" => $data];
return $renderer->renderPlain($rary);
}
/**
* Parses source as an html fragment.
* It then iterates over all '<a>' elements and performs the following modifications:
* - Setup the distillery redirector (/next/?next=...) on relative links according to $public
* - Make all links target="_blank" rel="noopener"
*/
function clean_html(string $source, string $public): string|bool {
// fast path: we don't have a source
if ($source === "" ) {
return $source;
}
// trim the trailing '/' from the public URL.
// this technically trims the beginning as well, but that should not be a problem
$public = trim($public, '/');
// attempt to parse a new document
$doc = new DOMDocument();
$ok = $doc->loadHTML('<?xml encoding="UTF-8">' . $source);
if ($ok === FALSE) {
return FALSE;
}
// replace all the <a href="..."> which are relative
$as = $doc->getElementsByTagName('a');
$modified = $as->count() > 0;
foreach($as as $a) {
// setup a link to open in a new tab
$a->setAttribute('rel', 'noopener noreferer');
$a->setAttribute('target', '_blank');
// if we don't have a domain don't even bother replacing hrefs.
if ($domain === "") {
continue;
}
// take only href="/" relative to the current domain.
$href = $a->getAttribute('href');
if (!is_string($href) || !str_starts_with($href, '/')) {
continue;
}
$a->setAttribute('href', $public . $href);
}
// we didn't modify the document => return as is
// (no need to re-serialize)
if (!$modified) {
return $source;
}
// find the body
$body = $doc->getElementsByTagName('body')->item(0);
if ($body === NULL) {
return FALSE;
}
// re-build the source document
$source = "";
// get the inner html§
$nodes = $body->childNodes;
foreach($nodes as $node) {
$source .= $doc->saveHTML($node);
}
// and turn it back into html
return $source;
}