Skip to content

Commit

Permalink
T&A: Participant Table Revision Adjustments (ILIAS-eLearning#8292)
Browse files Browse the repository at this point in the history
* T&A: Participant revision appendix: Adjust translations. Fix Client IP Range validation. Improve error messages

* T&A Add getSelectionErrorMessage to TableAction interface
  • Loading branch information
thojou authored Nov 7, 2024
1 parent 3e9a9e4 commit 5bc0e95
Show file tree
Hide file tree
Showing 11 changed files with 106 additions and 26 deletions.
13 changes: 12 additions & 1 deletion components/ILIAS/Test/src/Participants/ParticipantRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

use ILIAS\Data\Order;
use ILIAS\Data\Range;
use ILIAS\Test\Results\Data\StatusOfAttempt;

class ParticipantRepository
{
Expand Down Expand Up @@ -181,6 +180,18 @@ public function removeParticipants(array $selected_participants): void
\ilDBConstants::T_INTEGER
)
);
$this->database->manipulate(
"DELETE FROM tst_addtime WHERE test_fi = {$selected_participants[0]->getTestId()} AND "
. $this->database->in(
'user_fi',
array_map(
fn(Participant $participant): int => $participant->getUserId(),
$selected_participants
),
false,
\ilDBConstants::T_INTEGER
)
);
}

public function getFirstAndLastVisitForActiveId(int $active_id): array
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,11 @@ protected function showModal(
);

if ($selected_participants === []) {
$error_message = $action->getSelectionErrorMessage() ?? $this->lng->txt('no_valid_participant_selection');
$this->test_response->sendAsync(
$this->ui_renderer->renderAsync(
$this->ui_factory->messageBox()->failure(
$this->lng->txt('no_valid_participant_selection')
$error_message
)
)
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,9 @@ public function allowActionForRecord(Participant $record): bool
{
return $record->getActiveId() === null;
}

public function getSelectionErrorMessage(): ?string
{
return $this->lng->txt('delete_participants_no_valid_participants_selected');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,9 @@ private function resolveMessage(bool $all_participants_selected): string

return $this->lng->txt('delete_selected_user_data_confirmation');
}

public function getSelectionErrorMessage(): ?string
{
return $this->lng->txt('delete_result_no_valid_participants_selected');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -203,4 +203,9 @@ public function saveExtraTime(array $participants, int $minutes): void
);
}
}

public function getSelectionErrorMessage(): ?string
{
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -178,4 +178,9 @@ private function resolveMessage(

return $this->lng->txt('finish_test_multiple');
}

public function getSelectionErrorMessage(): ?string
{
return $this->lng->txt('finish_test_no_valid_participants_selected');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@
use Psr\Http\Message\ServerRequestInterface;
use ILIAS\Refinery\Factory as Refinery;

use function array_map;
use function array_unique;
use function count;

class ParticipantTableIpRangeAction implements TableAction
{
public const ACTION_ID = 'client_ip_range';
Expand Down Expand Up @@ -82,6 +78,30 @@ public function getModal(
|| filter_var($ip, FILTER_VALIDATE_IP) !== false,
$this->lng->txt('invalid_ip')
);
$validate_order = $this->refinery->custom()->constraint(
function (?array $vs): bool {
if ($vs === null) {
return true;
}
return $this->checkIpRangeValidity(
$vs['from'],
$vs['to']
);
},
sprintf($this->lng->txt('not_greater_than'), $this->lng->txt('max_ip_label'), $this->lng->txt('min_ip_label'))
);
$ip_range_group_trafo = $this->refinery->custom()->transformation(
static function (?array $vs): array {
if ($vs === null) {
$vs = [
'from' => null,
'to' => null
];
}
return $vs;
}
);


$participant_rows = array_map(
fn(Participant $participant) => sprintf(
Expand All @@ -92,8 +112,6 @@ public function getModal(
$selected_participants
);

$is_unique_ip_range = $this->isUniqueClientIp($selected_participants);

return $this->ui_factory->modal()->roundtrip(
$this->lng->txt('client_ip_range'),
[
Expand All @@ -111,22 +129,21 @@ public function getModal(
'ip_range' => $this->ui_factory->input()->field()->group([
'from' => $this->ui_factory->input()->field()->text(
$this->lng->txt('min_ip_label')
)->withAdditionalTransformation($valid_ip_constraint)
->withValue(
$is_unique_ip_range ?
$selected_participants[0]->getClientIpFrom() ?? '' :
''
),
)->withAdditionalTransformation($valid_ip_constraint),
'to' => $this->ui_factory->input()->field()->text(
$this->lng->txt('max_ip_label'),
$this->lng->txt('ip_range_byline')
)->withAdditionalTransformation($valid_ip_constraint)
->withValue(
$is_unique_ip_range ?
$selected_participants[0]->getClientIpTo() ?? '' :
''
),
])
)->withAdditionalTransformation($valid_ip_constraint),
])->withValue(
$this->isUniqueClientIp($selected_participants) ?
[
'from' => $selected_participants[0]->getClientIpFrom() ?? '',
'to' => $selected_participants[0]->getClientIpTo() ?? ''
] :
null
)
->withAdditionalTransformation($ip_range_group_trafo)
->withAdditionalTransformation($validate_order)
],
$url_builder->buildURI()->__toString()
)->withSubmitLabel($this->lng->txt('change'));
Expand Down Expand Up @@ -196,4 +213,23 @@ private function isUniqueClientIp(array $selected_participants): bool
$selected_participants
))) === 1;
}

private function checkIpRangeValidity(string $start, string $end): bool
{
if (filter_var($start, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false
&& filter_var($end, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false) {
return ip2long($start) <= ip2long($end);
}

if (filter_var($start, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false
&& filter_var($end, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false) {
return bin2hex(inet_pton($start)) <= bin2hex(inet_pton($end));
}
return false;
}

public function getSelectionErrorMessage(): ?string
{
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,9 @@ public function allowActionForRecord(Participant $record): bool
$this->test_obj->getTestId()
);
}

public function getSelectionErrorMessage(): ?string
{
return null;
}
}
1 change: 1 addition & 0 deletions components/ILIAS/Test/src/Participants/TableAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,5 @@ public function onSubmit(
bool $all_participants_selected
): ?Modal;
public function allowActionForRecord(Participant $record): bool;
public function getSelectionErrorMessage(): ?string;
}
13 changes: 8 additions & 5 deletions lang/ilias_de.lang
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@ assessment#:#checkbox_unchecked#:#Nicht ausgewählt
assessment#:#circle#:#Kreis
assessment#:#circle_click_center#:#Bitte klicken Sie auf den Mittelpunkt der gewünschten Region
assessment#:#circle_click_circle#:#Bitte klicken Sie auf einen Punkt auf dem Umkreis der gewünschten Region
assessment#:#client_ip_range#:#Client IP Range
assessment#:#client_ip_range#:#Client IP Bereich
assessment#:#clientip#:#Client IP
assessment#:#close_text_hint#:#Um eine Lücke in den Text einzufügen, setzen Sie den Cursor an die entsprechende Position und nutzen Sie die Schaltfläche "Textlücke". Anschließend stehen weiter unten entsprechende Bearbeitungsbereiche zur Verfügung. Ebenso können Sie die Lücken zur Bearbeitung im Lückentext direkt anklicken.
assessment#:#cloze_answer_text_info#:#Vorangestellte oder nachfolgende Leerzeichen werden beim Speichern aus der Antwort gelöscht.
Expand Down Expand Up @@ -611,6 +611,8 @@ assessment#:#deleteSuggestedSolution#:#Inhalte zur Wiederholung entfernen
assessment#:#delete_all_user_data_confirmation#:#Wollen Sie wirklich die Testergebnisse aller Teilnehmer löschen?
assessment#:#delete_image_header#:#Bild entfernen
assessment#:#delete_image_question#:#Möchten Sie das Bild wirklich entfernen?
assessment#:#delete_participant_no_valid_participants_selected#:#Für die gewählten Teilnehmer liegen bereits Testergebnisse vor und können deshalb nicht entfernt werden.
assessment#:#delete_result_no_valid_participants_selected#:#Für die gewählten Teilnehmer liegen keine Testergebnisse vor und können deshalb nicht entfernt werden.
assessment#:#delete_selected_user_data_confirmation#:#Sind Sie sicher, dass Sie alle Testdaten der ausgewählten Teilnehmenden entfernen wollen?
assessment#:#delete_user_data#:#Testergebnisse entfernen
assessment#:#description_maxchars#:#Wenn nichts eingegeben wird, ist die maximale Anzahl von Zeichen für diese Textantwort unbegrenzt.
Expand Down Expand Up @@ -745,6 +747,7 @@ assessment#:#finish_pass_for_user_in_processing_time#:#WARNUNG: die Bearbeitungs
assessment#:#finish_test#:#Test beenden
assessment#:#finish_test_all#:#Sind Sie sicher, dass die den Testdurchlauf für alle Teilnehmer beenden möchten?
assessment#:#finish_test_multiple#:#Sind Sie sicher, dass Sie den Testdurchlauf für folgende Teilnehmer beenden möchten?
assessment#:#finish_test_no_valid_participants_selected#:#Für die gewählten Teilnehmer gibt es keine aktiven Testdurchläufe und können daher nicht beendet werden.
assessment#:#finish_test_single#:#Sind Sie sicher, dass Sie den Testdurchlauf für den Teilnehmer "%s" beenden möchten?
assessment#:#finish_unfinished_passes#:#Beendet noch offene Testdurchläufe
assessment#:#finish_unfinished_passes_desc#:#Noch nicht beendete Testdurchläufe werden automatisch beendet – vorausgesetzt, es wurde für diese Tests ein Endzeitpunkt festgelegt oder Teilnehmende haben die maximale Bearbeitungsdauer überschritten.
Expand Down Expand Up @@ -789,10 +792,10 @@ assessment#:#internal_links#:#Interne Verweise
assessment#:#intprecision#:#Teilbar durch
assessment#:#intprecision_info#:#"Teilbar durch" hat nur Auswirkungen auf die Variablenerzeugung, wenn der Wert für die Präzision 0 beträgt. In diesem Fall legt "Teilbar durch" fest, durch welche ganze Zahl die erzeugte Variable teilbar sein muss. Ein Wert von 10 erzeugt also nur ganze Zahlen, die durch 10 teilbar sind, ein Wert von 5 erzeugt ganze Zahlen, die durch 5 teilbar sind usw. Bei einer Präzision von 0 ist "Teilbar durch" ein Pflichtfeld und muss eine positive, ganze Zahl enthalten. Voreingestellt ist der Wert 1 für beliebige ganze Zahlen.
assessment#:#invalid_ip#:#Ungültige IP
assessment#:#ip_range_byline#:#Nur IP Adressen die innerhalb der IP Range liegen, können den Test starten. Sie können entweder IPv4 ODER IPv6 verwenden.
assessment#:#ip_range_for_all_participants#:#Sie bearbeiten die IP Range für alle Teilnehmer.
assessment#:#ip_range_for_selected_participants#:#Sie bearbeiten die IP Range für die folgende Teilnehmer:
assessment#:#ip_range_for_single_participant#:#Sie bearbeiten die IP Range für folgenden Teilnehmer:
assessment#:#ip_range_byline#:#Nur IP Adressen die innerhalb der IP Bereich liegen, können den Test starten. Sie können entweder IPv4 ODER IPv6 verwenden.
assessment#:#ip_range_for_all_participants#:#Sie bearbeiten die IP Bereich für alle Teilnehmer.
assessment#:#ip_range_for_selected_participants#:#Sie bearbeiten die IP Bereich für die folgende Teilnehmer:
assessment#:#ip_range_for_single_participant#:#Sie bearbeiten die IP Bereich für folgenden Teilnehmer:
assessment#:#ip_range_info#:#Nur Geräte mit einer IP aus der festgelegten Spanne können den Test starten.
assessment#:#ip_range_label#:#Beschränkung auf IPs
assessment#:#ip_range_updated#:#Die IP-Rang wurde für die gewählten Teilnehmer aktualisiert.
Expand Down
3 changes: 3 additions & 0 deletions lang/ilias_en.lang
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,8 @@ assessment#:#deleteSuggestedSolution#:#Remove this content for recapitulation
assessment#:#delete_all_user_data_confirmation#:#Are you sure you want to delete the test results of all of the participants of this test?
assessment#:#delete_image_header#:#Remove image
assessment#:#delete_image_question#:#Do you really want to remove the image?
assessment#:#delete_participant_no_valid_participants_selected#:#Test results already exist for the selected participants, so they cannot be removed.
assessment#:#delete_result_no_valid_participants_selected#:#There are no test results for the selected participants, so they cannot be removed.
assessment#:#delete_selected_user_data_confirmation#:#Are you sure you want to remove the test data of the selected users?
assessment#:#delete_user_data#:#Remove Result(s)
assessment#:#description_maxchars#:#If nothing entered the maximum number of characters for this text answer is unlimited.
Expand Down Expand Up @@ -745,6 +747,7 @@ assessment#:#finish_pass_for_user_in_processing_time#:#WARNING: the processing t
assessment#:#finish_test#:#Finish Test
assessment#:#finish_test_all#:#Are you sure you want to finish the test attempts for all users?
assessment#:#finish_test_multiple#:#Are you sure you want to finish the test attempts for the following participants?
assessment#:#finish_test_no_valid_participants_selected#:#There are no active test runs for the selected participants, so they cannot be completed.
assessment#:#finish_test_single#:#Are you sure you want to finish the test attempt for the participant "%s"?
assessment#:#finish_unfinished_passes#:#Finish Uncompleted Attempts
assessment#:#finish_unfinished_passes_desc#:#Test attempts which have a set finishing time or a time limit will be closed by this cron job.
Expand Down

0 comments on commit 5bc0e95

Please sign in to comment.