Skip to content

Commit 40f262d

Browse files
committed
merge with master
2 parents 834b01b + 576214a commit 40f262d

File tree

9 files changed

+159
-56
lines changed

9 files changed

+159
-56
lines changed

app/V1Module/presenters/GroupsPresenter.php

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
use App\Model\Entity\LocalizedGroup;
1717
use App\Model\Entity\GroupMembership;
1818
use App\Model\Entity\AssignmentSolution;
19-
use App\Model\Entity\SecurityEvent;
2019
use App\Model\Repository\Assignments;
2120
use App\Model\Repository\Groups;
2221
use App\Model\Repository\GroupExams;
@@ -194,6 +193,36 @@ public function actionDefault(
194193
$this->sendSuccessResponse($this->groupViewFactory->getGroups($groups, false));
195194
}
196195

196+
/**
197+
* Helper method that handles updating points limit and threshold to a group entity (from a request).
198+
* @param Request $req request data
199+
* @param Group $group to be updated
200+
*/
201+
private function setGroupPoints(Request $req, Group $group): void
202+
{
203+
$threshold = $req->getPost("threshold");
204+
$pointsLimit = $req->getPost("pointsLimit");
205+
if ($threshold !== null && $pointsLimit !== null) {
206+
throw new InvalidArgumentException("A group may have either a threshold or points limit, not both.");
207+
}
208+
if ($threshold !== null) {
209+
if ($threshold <= 0 || $threshold > 100) {
210+
throw new InvalidArgumentException("A threshold must be in the (0, 100] (%) range.");
211+
}
212+
$group->setThreshold($threshold / 100);
213+
} else {
214+
$group->setThreshold(null);
215+
}
216+
if ($pointsLimit !== null) {
217+
if ($pointsLimit <= 0) {
218+
throw new InvalidArgumentException("A points limit must be a positive number.");
219+
}
220+
$group->setPointsLimit($pointsLimit);
221+
} else {
222+
$group->setPointsLimit(null);
223+
}
224+
}
225+
197226
/**
198227
* Create a new group
199228
* @POST
@@ -215,10 +244,10 @@ public function actionDefault(
215244
* description="Whether the group is an exam group.")
216245
* @Param(type="post", name="localizedTexts", validation="array", required=false,
217246
* description="Localized names and descriptions")
218-
* @Param(type="post", name="hasThreshold", validation="bool",
219-
* description="True if threshold was given, false if it should be unset")
220247
* @Param(type="post", name="threshold", validation="numericint", required=false,
221248
* description="A minimum percentage of points needed to pass the course")
249+
* @Param(type="post", name="pointsLimit", validation="numericint", required=false,
250+
* description="A minimum of (absolute) points needed to pass the course")
222251
* @Param(type="post", name="noAdmin", validation="bool", required=false,
223252
* description="If true, no admin is assigned to group (current user is assigned as admin by default.")
224253
* @throws ForbiddenRequestException
@@ -249,7 +278,6 @@ public function actionAddGroup()
249278
$isPublic = filter_var($req->getPost("isPublic"), FILTER_VALIDATE_BOOLEAN);
250279
$isOrganizational = filter_var($req->getPost("isOrganizational"), FILTER_VALIDATE_BOOLEAN);
251280
$isExam = filter_var($req->getPost("isExam"), FILTER_VALIDATE_BOOLEAN);
252-
$hasThreshold = filter_var($req->getPost("hasThreshold"), FILTER_VALIDATE_BOOLEAN);
253281
$noAdmin = filter_var($req->getPost("noAdmin"), FILTER_VALIDATE_BOOLEAN);
254282

255283
if ($isOrganizational && $isExam) {
@@ -267,12 +295,8 @@ public function actionAddGroup()
267295
$detaining,
268296
$isExam,
269297
);
270-
if ($hasThreshold) {
271-
$threshold = $req->getPost("threshold") !== null
272-
? $req->getPost("threshold") / 100
273-
: $group->getThreshold();
274-
$group->setThreshold($threshold);
275-
}
298+
299+
$this->setGroupPoints($req, $group);
276300
$this->updateLocalizations($req, $group);
277301

278302
$this->groups->persist($group, false);
@@ -329,10 +353,10 @@ public function checkUpdateGroup(string $id)
329353
* required=false, description="Are students prevented from leaving the group on their own?")
330354
* @Param(type="post", name="isPublic", validation="bool",
331355
* description="Should the group be visible to all student?")
332-
* @Param(type="post", name="hasThreshold", validation="bool",
333-
* description="True if threshold was given, false if it should be unset")
334356
* @Param(type="post", name="threshold", validation="numericint", required=false,
335357
* description="A minimum percentage of points needed to pass the course")
358+
* @Param(type="post", name="pointsLimit", validation="numericint", required=false,
359+
* description="A minimum of (absolute) points needed to pass the course")
336360
* @Param(type="post", name="localizedTexts", validation="array", description="Localized names and descriptions")
337361
* @param string $id An identifier of the updated group
338362
* @throws InvalidArgumentException
@@ -343,22 +367,14 @@ public function actionUpdateGroup(string $id)
343367
$publicStats = filter_var($req->getPost("publicStats"), FILTER_VALIDATE_BOOLEAN);
344368
$detaining = filter_var($req->getPost("detaining"), FILTER_VALIDATE_BOOLEAN);
345369
$isPublic = filter_var($req->getPost("isPublic"), FILTER_VALIDATE_BOOLEAN);
346-
$hasThreshold = filter_var($req->getPost("hasThreshold"), FILTER_VALIDATE_BOOLEAN);
347370

348371
$group = $this->groups->findOrThrow($id);
349372
$group->setExternalId($req->getPost("externalId"));
350373
$group->setPublicStats($publicStats);
351374
$group->setDetaining($detaining);
352375
$group->setIsPublic($isPublic);
353376

354-
if ($hasThreshold) {
355-
$threshold = $req->getPost("threshold") !== null ? $req->getPost("threshold") / 100 : $group->getThreshold(
356-
);
357-
$group->setThreshold($threshold);
358-
} else {
359-
$group->setThreshold(null);
360-
}
361-
377+
$this->setGroupPoints($req, $group);
362378
$this->updateLocalizations($req, $group);
363379

364380
$this->groups->persist($group);

app/commands/runtimes/RuntimeImport.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ protected static function validate(array $obj, array $schema, array $prefix = []
153153
{
154154
foreach ($schema as $key => $desc) {
155155
// check existence
156-
$path = $prefix ? ("'" . join($prefix, "' / '") . "'") : '<root>';
156+
$path = $prefix ? ("'" . join("' / '", $prefix) . "'") : '<root>';
157157
if (!array_key_exists($key, $obj)) {
158158
throw new RuntimeException("Property '$key' is missing in $path structure.");
159159
}

app/helpers/Emails/Notifications/Reviews/reviewClosed_en.latte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
{if !$issues && !$comments}
1111
<p>
12-
There are no issues to be resolved no comments in the review.
12+
There are no issues to be resolved and no comments in the review.
1313
</p>
1414
{else}
1515
<p>

app/model/entity/Group.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ public function __construct(
102102
*/
103103
protected $threshold;
104104

105+
/**
106+
* @ORM\Column(type="integer", nullable=true)
107+
*/
108+
protected $pointsLimit;
109+
105110
/**
106111
* @ORM\Column(type="boolean")
107112
*/
@@ -944,6 +949,16 @@ public function setThreshold(?float $threshold): void
944949
$this->threshold = $threshold;
945950
}
946951

952+
public function getPointsLimit(): ?int
953+
{
954+
return $this->pointsLimit;
955+
}
956+
957+
public function setPointsLimit(?int $pointsLimit): void
958+
{
959+
$this->pointsLimit = $pointsLimit;
960+
}
961+
947962
public function getPublicStats(): bool
948963
{
949964
return $this->publicStats;

app/model/view/GroupViewFactory.php

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,16 +158,25 @@ private function getStudentStatsInternal(
158158
];
159159
}
160160

161+
$passesLimit = null; // null = no limit
162+
$limit = null;
163+
if ($group->getPointsLimit() !== null && $group->getPointsLimit() > 0) {
164+
$limit = $group->getPointsLimit();
165+
$passesLimit = $gainedPoints >= $limit;
166+
} elseif ($group->getThreshold() !== null && $group->getThreshold() > 0) {
167+
$limit = $maxPoints * $group->getThreshold();
168+
$passesLimit = $gainedPoints >= $limit;
169+
}
161170
return [
162171
"userId" => $student->getId(),
163172
"groupId" => $group->getId(),
164173
"points" => [
165174
"total" => $maxPoints,
166-
"gained" => $gainedPoints
175+
"limit" => $limit,
176+
"gained" => $gainedPoints,
167177
],
168-
"hasLimit" => $group->getThreshold() !== null && $group->getThreshold() > 0,
169-
"passesLimit" => $group->getThreshold(
170-
) === null ? true : $gainedPoints >= $maxPoints * $group->getThreshold(),
178+
"hasLimit" => $passesLimit !== null,
179+
"passesLimit" => $passesLimit ?? true,
171180
"assignments" => $assignments,
172181
"shadowAssignments" => $shadowAssignments
173182
];
@@ -251,6 +260,7 @@ function (ShadowAssignment $assignment) {
251260
"publicStats" => $group->getPublicStats(),
252261
"detaining" => $group->isDetaining(),
253262
"threshold" => $group->getThreshold(),
263+
"pointsLimit" => $group->getPointsLimit(),
254264
"bindings" => $this->bindings->getBindingsForGroup($group),
255265
"examBegin" => $group->hasExamPeriodSet() ? $group->getExamBegin()?->getTimestamp() : null,
256266
"examEnd" => $group->hasExamPeriodSet() ? $group->getExamEnd()?->getTimestamp() : null,

composer.lock

Lines changed: 15 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Migrations;
6+
7+
use Doctrine\DBAL\Schema\Schema;
8+
use Doctrine\Migrations\AbstractMigration;
9+
10+
/**
11+
* Auto-generated Migration: Please modify to your needs!
12+
*/
13+
final class Version20241010152436 extends AbstractMigration
14+
{
15+
public function getDescription(): string
16+
{
17+
return '';
18+
}
19+
20+
public function up(Schema $schema): void
21+
{
22+
// this up() migration is auto-generated, please modify it to your needs
23+
$this->addSql('ALTER TABLE `group` ADD points_limit INT DEFAULT NULL');
24+
}
25+
26+
public function down(Schema $schema): void
27+
{
28+
// this down() migration is auto-generated, please modify it to your needs
29+
$this->addSql('ALTER TABLE `group` DROP points_limit');
30+
}
31+
}

recodex-api.spec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
%define name recodex-core
22
%define short_name api
33
%define install_dir /opt/%{name}
4-
%define version 2.13.1
5-
%define unmangled_version 3c5ea577c73f1a6b9144ad8a6e898626ba57c0b2
4+
%define version 2.13.2
5+
%define unmangled_version 3a6cad864701ff518ec5ed93f0f7988175c825f4
66
%define release 1
77

88
Summary: ReCodEx core API component

0 commit comments

Comments
 (0)