Skip to content

Commit ba44eb1

Browse files
committed
4.7.0 Release
2 parents 1f9c684 + 9e6f824 commit ba44eb1

File tree

106 files changed

+6287
-1005
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

106 files changed

+6287
-1005
lines changed

.github/workflows/ci.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ jobs:
1717
runs-on: ubuntu-latest
1818

1919
services:
20+
redis:
21+
image: redis
22+
options: >-
23+
--health-cmd "redis-cli ping"
24+
--health-interval 10s
25+
--health-timeout 5s
26+
--health-retries 5
27+
ports:
28+
- 6379
2029
postgres:
2130
image: postgres
2231
env:
@@ -108,6 +117,8 @@ jobs:
108117
DB_DATABASE: test
109118
DB_USERNAME: root
110119
DB_PASSWORD: password
120+
REDIS_HOST: 127.0.0.1
121+
REDIS_PORT: ${{ job.services.redis.ports[6379] }}
111122
LOG_CHANNEL: stack
112123
run: php artisan test --parallel --testsuite=Unit,Feature --coverage-clover=coverage.xml
113124
- name: Execute tests (Unit, Feature and Integration tests) via PHPUnit
@@ -118,6 +129,8 @@ jobs:
118129
DB_DATABASE: test
119130
DB_USERNAME: root
120131
DB_PASSWORD: password
132+
REDIS_HOST: 127.0.0.1
133+
REDIS_PORT: ${{ job.services.redis.ports[6379] }}
121134
LOG_CHANNEL: stack
122135
BBB_TEST_SERVER_HOST: ${{ secrets.BBB_TEST_SERVER_HOST }}
123136
BBB_TEST_SERVER_SECRET: ${{ secrets.BBB_TEST_SERVER_SECRET }}
@@ -132,6 +145,8 @@ jobs:
132145
DB_DATABASE: test
133146
DB_USERNAME: user
134147
DB_PASSWORD: password
148+
REDIS_HOST: 127.0.0.1
149+
REDIS_PORT: ${{ job.services.redis.ports[6379] }}
135150
LOG_CHANNEL: stack
136151
run: php artisan test --parallel --testsuite=Unit,Feature
137152
- name: Upload coverage
@@ -311,6 +326,9 @@ jobs:
311326
steps:
312327
- name: Checkout
313328
uses: actions/checkout@v4
329+
- name: Fetch develop branch
330+
if: github.ref != 'refs/heads/develop'
331+
run: git fetch origin develop:develop
314332
- name: Download artifact
315333
uses: actions/download-artifact@v4
316334
with:
@@ -351,6 +369,8 @@ jobs:
351369
NODE_OPTIONS: "--experimental-require-module"
352370
HAPPO_API_KEY: ${{ secrets.HAPPO_API_KEY }}
353371
HAPPO_API_SECRET: ${{ secrets.HAPPO_API_SECRET }}
372+
HAPPO_DELETE_OLD_COMMENTS: true
373+
BASE_BRANCH: origin/develop
354374
CYPRESS_PROJECT_ID: ${{ env.CYPRESS_PROJECT_ID }}
355375
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
356376
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

CHANGELOG.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [v4.7.0] - 2025-07-21
11+
12+
### Added
13+
14+
- Show meeting ended reason ([#2223])
15+
- Show BBB join errors ([#2223])
16+
- Pass color-scheme preference to BigBlueButton ([#2153], [#2154])
17+
- Metrics endpoint (`/metrics`) ([#2165])
18+
- Virus Scanning using ClamAV for all file uploads ([#77], [#1133])
19+
20+
### Fixed
21+
22+
- Logout session_expired warning message style ([68abce8](https://github.com/THM-Health/PILOS/commit/68abce87bcd241db3261a448cf53e430bd639e28))
23+
- Show unavailable room types in create room dialog ([#2265], [#2279])
24+
- Show unavailable room types in change room type dialog ([#2265], [#2279])
25+
- Infinite loading when navigating back after logout redirect due to bfcache ([#2282])
26+
1027
## [v4.6.1] - 2025-06-16
1128

1229
### Fixed
@@ -354,6 +371,7 @@ You can find the changelog for older versions there [here](https://github.com/TH
354371

355372
[#31]: https://github.com/THM-Health/PILOS/issues/31
356373
[#75]: https://github.com/THM-Health/PILOS/issues/75
374+
[#77]: https://github.com/THM-Health/PILOS/issues/77
357375
[#315]: https://github.com/THM-Health/PILOS/issues/315
358376
[#372]: https://github.com/THM-Health/PILOS/issues/372
359377
[#373]: https://github.com/THM-Health/PILOS/pull/373
@@ -401,6 +419,7 @@ You can find the changelog for older versions there [here](https://github.com/TH
401419
[#1102]: https://github.com/THM-Health/PILOS/pull/1102
402420
[#1120]: https://github.com/THM-Health/PILOS/pull/1120
403421
[#1126]: https://github.com/THM-Health/PILOS/pull/1126
422+
[#1133]: https://github.com/THM-Health/PILOS/pull/1133
404423
[#1150]: https://github.com/THM-Health/PILOS/issues/1150
405424
[#1159]: https://github.com/THM-Health/PILOS/pull/1159
406425
[#1166]: https://github.com/THM-Health/PILOS/pull/1166
@@ -495,8 +514,15 @@ You can find the changelog for older versions there [here](https://github.com/TH
495514
[#2134]: https://github.com/THM-Health/PILOS/pull/2134
496515
[#2150]: https://github.com/THM-Health/PILOS/pull/2150
497516
[#2151]: https://github.com/THM-Health/PILOS/pull/2151
517+
[#2153]: https://github.com/THM-Health/PILOS/issues/2153
518+
[#2154]: https://github.com/THM-Health/PILOS/pull/2154
519+
[#2165]: https://github.com/THM-Health/PILOS/pull/2165
498520
[#2222]: https://github.com/THM-Health/PILOS/pull/2222
499-
[unreleased]: https://github.com/THM-Health/PILOS/compare/v4.6.1...develop
521+
[#2223]: https://github.com/THM-Health/PILOS/pull/2223
522+
[#2265]: https://github.com/THM-Health/PILOS/issues/2265
523+
[#2279]: https://github.com/THM-Health/PILOS/pull/2279
524+
[#2282]: https://github.com/THM-Health/PILOS/pull/2282
525+
[unreleased]: https://github.com/THM-Health/PILOS/compare/v4.7.0...develop
500526
[v3.0.0]: https://github.com/THM-Health/PILOS/releases/tag/v3.0.0
501527
[v3.0.1]: https://github.com/THM-Health/PILOS/releases/tag/v3.0.1
502528
[v3.0.2]: https://github.com/THM-Health/PILOS/releases/tag/v3.0.2
@@ -512,3 +538,4 @@ You can find the changelog for older versions there [here](https://github.com/TH
512538
[v4.5.0]: https://github.com/THM-Health/PILOS/releases/tag/v4.5.0
513539
[v4.6.0]: https://github.com/THM-Health/PILOS/releases/tag/v4.6.0
514540
[v4.6.1]: https://github.com/THM-Health/PILOS/releases/tag/v4.6.1
541+
[v4.7.0]: https://github.com/THM-Health/PILOS/releases/tag/v4.7.0

app/Auth/LDAP/LDAPController.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use App\Auth\MissingAttributeException;
66
use App\Http\Controllers\Controller;
7+
use App\Prometheus\Counter;
78
use Illuminate\Foundation\Auth\AuthenticatesUsers;
89
use Illuminate\Http\Request;
910
use Illuminate\Support\Facades\Auth;
@@ -59,6 +60,8 @@ public function login(Request $request)
5960
return $this->ldapLogin($request);
6061
} catch (MissingAttributeException $e) {
6162
// If an attribute is missing during the login process, return error
63+
Counter::get('login_failed_total')->inc('ldap');
64+
6265
return abort(500, __('auth.error.missing_attributes'));
6366
}
6467
}
@@ -72,6 +75,7 @@ public function login(Request $request)
7275
protected function authenticated(Request $request, $user)
7376
{
7477
// Log successful authentication
78+
Counter::get('login_total')->inc('ldap');
7579
Log::info('External user {user} has been successfully authenticated.', ['user' => $user->getLogLabel(), 'type' => 'ldap']);
7680

7781
// Update the last login timestamp

app/Auth/Shibboleth/ShibbolethController.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use App\Auth\MissingAttributeException;
66
use App\Http\Controllers\Controller;
7+
use App\Prometheus\Counter;
78
use Illuminate\Http\Request;
89
use Illuminate\Support\Facades\Log;
910

@@ -46,12 +47,15 @@ public function callback(Request $request)
4647
try {
4748
$user = $this->provider->login($request);
4849
} catch (MissingAttributeException $e) {
50+
Counter::get('login_failed_total')->inc('shibboleth');
51+
4952
return redirect('/external_login?error=missing_attributes');
5053
} catch (ShibbolethSessionDuplicateException $e) {
5154
// Prevented login attempt with duplicate shibboleth session, redirect to logout to kill SP session
5255
return redirect($this->provider->logout(url('/external_login?error=shibboleth_session_duplicate_exception')));
5356
}
5457

58+
Counter::get('login_total')->inc('shibboleth');
5559
Log::info('External user {user} has been successfully authenticated.', ['user' => $user->getLogLabel(), 'type' => 'shibboleth']);
5660

5761
// Update the last login timestamp
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace App\Console\Commands;
4+
5+
use App\Prometheus\CollectorRegistry;
6+
use Illuminate\Console\Command;
7+
8+
class ClearMetricsCommand extends Command
9+
{
10+
protected $signature = 'metrics:clear';
11+
12+
protected $description = 'Clear metric data';
13+
14+
public function handle(CollectorRegistry $registry): void
15+
{
16+
$registry->wipeStorage();
17+
$this->info('Metrics cleared successfully.');
18+
}
19+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace App\Http\Controllers;
4+
5+
use App\Prometheus\CollectorRegistry;
6+
use App\Providers\MetricsServiceProvider;
7+
use Prometheus\RenderTextFormat;
8+
9+
class MetricsController extends Controller
10+
{
11+
public function __invoke(CollectorRegistry $registry)
12+
{
13+
foreach (MetricsServiceProvider::$collectors as $collector) {
14+
(new $collector)->collect();
15+
}
16+
17+
$renderer = new RenderTextFormat;
18+
$result = $renderer->render($registry->getMetricFamilySamples());
19+
20+
return response($result)
21+
->header('Content-Type', RenderTextFormat::MIME_TYPE);
22+
}
23+
}

app/Http/Controllers/api/v1/auth/LoginController.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use App\Auth\Shibboleth\ShibbolethProvider;
66
use App\Http\Controllers\Controller;
7+
use App\Prometheus\Counter;
78
use Illuminate\Foundation\Auth\AuthenticatesUsers;
89
use Illuminate\Http\Request;
910
use Illuminate\Support\Facades\Log;
@@ -57,6 +58,7 @@ protected function credentials(Request $request)
5758
*/
5859
protected function authenticated(Request $request, $user)
5960
{
61+
Counter::get('login_total')->inc('local');
6062
Log::info('Local user {user} has been successfully authenticated.', ['user' => $user->getLogLabel()]);
6163

6264
// Update the last login timestamp

app/Http/Kernel.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use App\Http\Middleware\EnsureModelNotStale;
66
use App\Http\Middleware\LogContext;
7+
use App\Http\Middleware\RequestMetricsMiddleware;
78
use App\Http\Middleware\RoomAuthenticate;
89
use App\Http\Middleware\RouteEnableIfConfig;
910
use App\Http\Middleware\StoreSessionData;
@@ -20,13 +21,15 @@ class Kernel extends HttpKernel
2021
* @var array
2122
*/
2223
protected $middleware = [
24+
\Illuminate\Foundation\Http\Middleware\InvokeDeferredCallbacks::class,
2325
\App\Http\Middleware\TrustHosts::class,
2426
\App\Http\Middleware\TrustProxies::class,
2527
\Illuminate\Http\Middleware\HandleCors::class,
2628
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
2729
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
2830
\App\Http\Middleware\TrimStrings::class,
2931
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
32+
RequestMetricsMiddleware::class,
3033
];
3134

3235
/**
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
namespace App\Http\Middleware;
4+
5+
use App\Prometheus\Counter;
6+
use App\Prometheus\Summary;
7+
use Closure;
8+
use Illuminate\Http\Request;
9+
use Illuminate\Support\Str;
10+
11+
class RequestMetricsMiddleware
12+
{
13+
public function handle(Request $request, Closure $next)
14+
{
15+
return $next($request);
16+
}
17+
18+
public function terminate(Request $request, $response)
19+
{
20+
// If metrics are disabled, skip the whole collection
21+
if (! config('metrics.enabled')) {
22+
return;
23+
}
24+
25+
$startTime = defined('LARAVEL_START') ? LARAVEL_START : $request->server('REQUEST_TIME_FLOAT');
26+
27+
$route = $request->route()?->uri() ?? 'unknown';
28+
29+
if (config('metrics.collectors.request_duration_seconds.enabled') && ! in_array($route, config('metrics.collectors.request_duration_seconds.exclude_routes'))) {
30+
$duration = microtime(true) - $startTime;
31+
Summary::get('request_duration_seconds')->observe($duration);
32+
}
33+
34+
if (config('metrics.collectors.request_memory_bytes.enabled') && ! in_array($route, config('metrics.collectors.request_memory_bytes.exclude_routes'))) {
35+
$memoryUsage = memory_get_peak_usage(true);
36+
Summary::get('request_memory_bytes')->observe($memoryUsage);
37+
}
38+
39+
if (config('metrics.collectors.request_total.enabled') && ! in_array($route, config('metrics.collectors.request_total.exclude_routes'))) {
40+
$status = $response->getStatusCode();
41+
Counter::get('request_total')->inc([Str::of($status)->charAt(0).'xx']);
42+
}
43+
}
44+
}

app/Http/Middleware/RoomAuthenticate.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use App\Models\Room;
66
use App\Models\RoomToken;
7+
use App\Prometheus\Counter;
78
use App\Services\RoomAuthService;
89
use Closure;
910
use Illuminate\Support\Facades\Auth;
@@ -47,6 +48,7 @@ public function handle($request, Closure $next, $allowUnAuthenticated = false)
4748
$token = RoomToken::where('token', $request->header('Token'))->where('room_id', $room->id)->first();
4849

4950
if ($token == null) {
51+
Counter::get('room_authentication_errors_total')->inc('token');
5052
Log::notice('Room token authentication failed for room {room}', ['room' => $room->getLogLabel()]);
5153
abort(401, 'invalid_token');
5254
}
@@ -58,6 +60,8 @@ public function handle($request, Closure $next, $allowUnAuthenticated = false)
5860

5961
// user is not authenticated and room is not allowed for guests
6062
if (! $room->getRoomSetting('allow_guests') && ! $authenticated && ! Auth::user()) {
63+
Counter::get('room_authentication_errors_total')->inc('guest_access');
64+
6165
Log::notice('Room guest access failed for room {room}', ['room' => $room->getLogLabel()]);
6266

6367
abort(403, 'guests_not_allowed');
@@ -84,6 +88,7 @@ public function handle($request, Closure $next, $allowUnAuthenticated = false)
8488
if (is_numeric($accessCode) && $room->access_code == $accessCode) {
8589
$authenticated = true;
8690
} else {
91+
Counter::get('room_authentication_errors_total')->inc('access_code_invalid');
8792
Log::notice('Room access code authentication failed for room {room}', ['room' => $room->getLogLabel()]);
8893

8994
// Increment counter for failed access code attempts

0 commit comments

Comments
 (0)