Page MenuHomePhorge

D5658.1775232005.diff
No OneTemporary

Authored By
Unknown
Size
94 KB
Referenced Files
None
Subscribers
None

D5658.1775232005.diff

diff --git a/src/app/Device.php b/src/app/Device.php
--- a/src/app/Device.php
+++ b/src/app/Device.php
@@ -127,7 +127,7 @@
DB::beginTransaction();
// Check if a device already exists
- $device = Device::withTrashed()->where('hash', $token)->first();
+ $device = self::withTrashed()->where('hash', $token)->first();
if ($device) {
// FIXME: Should we remove the user (if it's a role=device user)?
diff --git a/src/app/Entitlement.php b/src/app/Entitlement.php
--- a/src/app/Entitlement.php
+++ b/src/app/Entitlement.php
@@ -86,7 +86,7 @@
*
* @param object $object Entitleable object
*
- * @return array Skus list with some metadata
+ * @return array<string, array> Skus list with some metadata
*/
public static function objectEntitlementsSummary($object): array
{
diff --git a/src/app/Http/Controllers/API/V4/CompanionAppsController.php b/src/app/Http/Controllers/API/V4/CompanionAppsController.php
--- a/src/app/Http/Controllers/API/V4/CompanionAppsController.php
+++ b/src/app/Http/Controllers/API/V4/CompanionAppsController.php
@@ -54,8 +54,6 @@
*/
public function store(Request $request): JsonResponse
{
- $user = $this->guard()->user();
-
$v = Validator::make(
$request->all(),
[
@@ -64,12 +62,12 @@
);
if ($v->fails()) {
- return response()->json(['status' => 'error', 'errors' => $v->errors()], 422);
+ return response()->json(['status' => 'error', /* @var array */ 'errors' => $v->errors()], 422);
}
$app = CompanionApp::create([
'name' => $request->name,
- 'user_id' => $user->id,
+ 'user_id' => $this->guard()->user()->id,
]);
return response()->json([
@@ -98,7 +96,7 @@
);
if ($v->fails()) {
- return response()->json(['status' => 'error', 'errors' => $v->errors()], 422);
+ return response()->json(['status' => 'error', /* @var array */ 'errors' => $v->errors()], 422);
}
$notificationToken = $request->notificationToken;
@@ -184,7 +182,7 @@
*
* @param string $id Companion app identifier
*/
- public function show($id): CompanionAppResource|JsonResponse
+ public function show($id): JsonResponse
{
$result = CompanionApp::find($id);
if (!$result) {
@@ -196,7 +194,7 @@
return $this->errorResponse(403);
}
- return new CompanionAppResource($result);
+ return (new CompanionAppResource($result))->response();
}
/**
diff --git a/src/app/Http/Controllers/API/V4/MeetController.php b/src/app/Http/Controllers/API/V4/MeetController.php
--- a/src/app/Http/Controllers/API/V4/MeetController.php
+++ b/src/app/Http/Controllers/API/V4/MeetController.php
@@ -3,7 +3,9 @@
namespace App\Http\Controllers\API\V4;
use App\Http\Controllers\Controller;
+use App\Http\Resources\RoomSessionResource;
use App\Meet\Room;
+use Dedoc\Scramble\Attributes\BodyParameter;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
@@ -12,11 +14,18 @@
class MeetController extends Controller
{
/**
- * Join the room session. Each room has one owner, and the room isn't open until the owner
+ * Join the room session.
+ *
+ * Each room has one owner, and the room isn't open until the owner
* joins (and effectively creates the session).
*
* @param string $id Room identifier (name)
*/
+ #[BodyParameter('password', description: 'Room password', type: 'string')]
+ #[BodyParameter('requestId', description: 'Unique client identifier', type: 'string')]
+ #[BodyParameter('picture', description: 'User image', type: 'string')]
+ #[BodyParameter('nickname', description: 'User nickname', type: 'string')]
+ #[BodyParameter('canPublish', description: 'Client has media device(s)', type: 'bool')]
public function joinRoom($id): JsonResponse
{
$room = Room::where('name', $id)->first();
@@ -27,21 +36,27 @@
}
$user = Auth::guard()->user();
- $isOwner = $user && (
+ $init = !empty(request()->input('init'));
+ $settings = $room->getSettings(['locked', 'nomedia', 'password']);
+ $password = (string) $settings['password'];
+
+ $response = new RoomSessionResource($settings);
+ $response->isOwner = $user && (
$user->id == $wallet->owner->id || $room->permissions()->where('user', $user->email)->exists()
);
- $init = !empty(request()->input('init'));
// There's no existing session
if (!$room->hasSession()) {
// Participants can't join the room until the session is created by the owner
- if (!$isOwner) {
- return $this->errorResponse(422, self::trans('meet.session-not-found'), ['code' => 323]);
+ if (!$response->isOwner) {
+ $response->code = 323;
+ return $response->response()->setStatusCode(422);
}
// The room owner can create the session on request
if (!$init) {
- return $this->errorResponse(422, self::trans('meet.session-not-found'), ['code' => 324]);
+ $response->code = 324;
+ return $response->response()->setStatusCode(422);
}
$session = $room->createSession();
@@ -51,49 +66,37 @@
}
}
- $settings = $room->getSettings(['locked', 'nomedia', 'password']);
- $password = (string) $settings['password'];
-
- $config = [
- 'locked' => $settings['locked'] === 'true',
- 'nomedia' => $settings['nomedia'] === 'true',
- 'password' => $isOwner ? $password : '',
- 'requires_password' => !$isOwner && strlen($password),
- ];
-
- $response = ['config' => $config];
-
// Validate room password
- if (!$isOwner && strlen($password)) {
+ if (!$response->isOwner && strlen($password)) {
$request_password = request()->input('password');
if ($request_password !== $password) {
- $response['code'] = 325;
- return $this->errorResponse(422, self::trans('meet.session-password-error'), $response);
+ $response->code = 325;
+ return $response->response()->setStatusCode(422);
}
}
// Handle locked room
- if (!$isOwner && $config['locked']) {
+ if (!$response->isOwner && $settings['locked']) {
$nickname = request()->input('nickname');
$picture = request()->input('picture');
$requestId = request()->input('requestId');
$request = $requestId ? $room->requestGet($requestId) : null;
- $error = self::trans('meet.session-room-locked-error');
-
// Request already has been processed (not accepted yet, but it could be denied)
if (empty($request['status']) || $request['status'] != Room::REQUEST_ACCEPTED) {
if (!$request) {
if (empty($nickname) || empty($requestId) || !preg_match('/^[a-z0-9]{8,32}$/i', $requestId)) {
- return $this->errorResponse(422, $error, $response + ['code' => 326]);
+ $response->code = 326;
+ return $response->response()->setStatusCode(422);
}
if (empty($picture)) {
$svg = file_get_contents(resource_path('images/user.svg'));
$picture = 'data:image/svg+xml;base64,' . base64_encode($svg);
} elseif (!preg_match('|^data:image/png;base64,[a-zA-Z0-9=+/]+$|', $picture)) {
- return $this->errorResponse(422, $error, $response + ['code' => 326]);
+ $response->code = 326;
+ return $response->response()->setStatusCode(422);
}
// TODO: Resize when big/make safe the user picture?
@@ -102,43 +105,39 @@
if (!$room->requestSave($requestId, $request)) {
// FIXME: should we use error code 500?
- return $this->errorResponse(422, $error, $response + ['code' => 326]);
+ $response->code = 326;
+ return $response->response()->setStatusCode(422);
}
// Send the request (signal) to all moderators
- $result = $room->signal('joinRequest', $request, Room::ROLE_MODERATOR);
+ $room->signal('joinRequest', $request, Room::ROLE_MODERATOR);
}
- return $this->errorResponse(422, $error, $response + ['code' => 327]);
+ $response->code = 327;
+ return $response->response()->setStatusCode(422);
}
}
- // Initialize connection tokens
- if ($init) {
- // Choose the connection role
- $canPublish = !empty(request()->input('canPublish')) && (empty($config['nomedia']) || $isOwner);
- $role = $canPublish ? Room::ROLE_PUBLISHER : Room::ROLE_SUBSCRIBER;
- if ($isOwner) {
- $role |= Room::ROLE_MODERATOR;
- $role |= Room::ROLE_OWNER;
- }
+ if (!$init) {
+ $response->code = 322;
+ return $response->response()->setStatusCode(422);
+ }
- // Create session token for the current user/connection
- $response = $room->getSessionToken($role);
+ // Choose the connection role
+ $canPublish = !empty(request()->input('canPublish')) && (empty($settings['nomedia']) || $response->isOwner);
+ $response->role = $canPublish ? Room::ROLE_PUBLISHER : Room::ROLE_SUBSCRIBER;
+ if ($response->isOwner) {
+ $response->role |= Room::ROLE_MODERATOR | Room::ROLE_OWNER;
+ }
- if (empty($response)) {
- return $this->errorResponse(500, self::trans('meet.session-join-error'));
- }
+ // Create session token for the current user/connection
+ $response->token = $room->getSessionToken($response->role);
- $response_code = 200;
- $response['role'] = $role;
- $response['config'] = $config;
- } else {
- $response_code = 422;
- $response['code'] = 322;
+ if (empty($response->token)) {
+ return $this->errorResponse(500, self::trans('meet.session-join-error'));
}
- return response()->json($response, $response_code);
+ return $response->response();
}
/**
diff --git a/src/app/Http/Controllers/API/V4/PolicyController.php b/src/app/Http/Controllers/API/V4/PolicyController.php
--- a/src/app/Http/Controllers/API/V4/PolicyController.php
+++ b/src/app/Http/Controllers/API/V4/PolicyController.php
@@ -61,8 +61,9 @@
}
/**
- * Fetch the account policies for the current user account.
- * The result includes all supported policy rules.
+ * List the account policies.
+ *
+ * The result includes all supported policy rules for the current user account.
*/
public function index(Request $request): JsonResponse
{
@@ -114,7 +115,9 @@
return Mailfilter::handle($request);
}
- // Apply a sensible rate limitation to a request.
+ /**
+ * Apply a sensible rate limitation to a request.
+ */
public function ratelimit(): JsonResponse
{
$response = RateLimit::handle(\request()->input());
@@ -132,7 +135,9 @@
return $response->jsonResponse();
}
- // Apply the sender policy framework to a request.
+ /**
+ * Apply the sender policy framework to a request.
+ */
public function senderPolicyFramework(): JsonResponse
{
$response = SPF::handle(\request()->input());
@@ -140,7 +145,9 @@
return $response->jsonResponse();
}
- // Validate sender/recipients in an SMTP submission request.
+ /**
+ * Validate sender/recipients in an SMTP submission request.
+ */
public function submission(): JsonResponse
{
$response = SmtpAccess::submission(\request()->input());
diff --git a/src/app/Http/Controllers/API/V4/RoomsController.php b/src/app/Http/Controllers/API/V4/RoomsController.php
--- a/src/app/Http/Controllers/API/V4/RoomsController.php
+++ b/src/app/Http/Controllers/API/V4/RoomsController.php
@@ -2,10 +2,12 @@
namespace App\Http\Controllers\API\V4;
-use App\Entitlement;
use App\Http\Controllers\RelationController;
+use App\Http\Resources\RoomInfoResource;
+use App\Http\Resources\RoomResource;
use App\Meet\Room;
use App\Permission;
+use Dedoc\Scramble\Attributes\BodyParameter;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
@@ -28,7 +30,7 @@
/**
* Delete a room
*
- * @param string $id Room identifier
+ * @param int|string $id Room identifier (or name)
*/
public function destroy($id): JsonResponse
{
@@ -65,19 +67,16 @@
$room->assignToWallet($user->wallets()->first());
}
- $rooms = $user->rooms(true)
- ->union($shared)
- ->orderBy('name')
- ->get()
- ->map(function ($room) {
- return $this->objectToClient($room);
- });
+ $rooms = $user->rooms(true)->union($shared)->orderBy('name')->get();
$result = [
- // @var array List of rooms
- 'list' => $rooms,
+ 'status' => 'success',
+ // List of rooms
+ 'list' => RoomResource::collection($rooms),
// @var int Number of entries in the list
'count' => count($rooms),
+ // @var bool Indicates that there are more entries available
+ 'hasMore' => false,
];
return response()->json($result);
@@ -105,7 +104,7 @@
$errors = $room->setConfig($request);
if (!empty($errors)) {
- return response()->json(['status' => 'error', 'errors' => $errors], 422);
+ return response()->json(['status' => 'error', /* @var array */ 'errors' => $errors], 422);
}
return response()->json([
@@ -117,7 +116,7 @@
/**
* Get room information.
*
- * @param string $id Room identifier
+ * @param string $id Room identifier (or name)
*/
public function show($id): JsonResponse
{
@@ -126,41 +125,16 @@
return $this->errorResponse($room);
}
- $wallet = $room->wallet();
- $user = $this->guard()->user();
-
- $response = $this->objectToClient($room, true);
-
- unset($response['session_id']);
-
- $response['config'] = $room->getConfig();
-
- // Room sharees can't manage/see room ACL
- if ($permission) {
- unset($response['config']['acl']);
- }
-
- $response['skus'] = Entitlement::objectEntitlementsSummary($room);
- $response['wallet'] = $wallet->toArray();
+ $resource = new RoomInfoResource($room);
+ $resource->permission = $permission;
- if ($wallet->discount) {
- $response['wallet']['discount'] = $wallet->discount->discount;
- $response['wallet']['discount_description'] = $wallet->discount->description;
- }
-
- $isOwner = $user->canDelete($room);
- $response['canUpdate'] = $isOwner || $room->permissions()->where('user', $user->email)->exists();
- $response['canDelete'] = $isOwner && $user->wallet()->isController($user);
- $response['canShare'] = $isOwner && $room->hasSKU('group-room');
- $response['isOwner'] = $isOwner;
-
- return response()->json($response);
+ return $resource->response();
}
/**
* Get a list of SKUs available to the room.
*
- * @param int $id Room identifier
+ * @param int $id Room identifier (or name)
*/
public function skus($id): JsonResponse
{
@@ -173,10 +147,11 @@
}
/**
- * Create a new room.
+ * Create a room.
*
* @param Request $request the API request
*/
+ #[BodyParameter('skus', description: 'Enabled SKUs', type: 'array')]
public function store(Request $request): JsonResponse
{
$user = $this->guard()->user();
@@ -187,11 +162,12 @@
}
$v = Validator::make($request->all(), [
+ // Room description
'description' => 'nullable|string|max:191',
]);
if ($v->fails()) {
- return response()->json(['status' => 'error', 'errors' => $v->errors()], 422);
+ return response()->json(['status' => 'error', /* @var array */ 'errors' => $v->errors()], 422);
}
DB::beginTransaction();
@@ -220,6 +196,7 @@
* @param Request $request the API request
* @param string $id Room identifier
*/
+ #[BodyParameter('skus', description: 'Enabled SKUs', type: 'array')]
public function update(Request $request, $id): JsonResponse
{
$room = $this->inputRoom($id, Permission::ADMIN);
@@ -228,6 +205,7 @@
}
$v = Validator::make($request->all(), [
+ // Room description
'description' => 'nullable|string|max:191',
]);
@@ -242,7 +220,7 @@
SkusController::updateEntitlements($room, $request->skus);
- if (!$room->hasSKU('group-room')) {
+ if (!$room->hasSku('group-room')) {
$room->setSetting('acl', null);
}
diff --git a/src/app/Http/Controllers/API/V4/SkusController.php b/src/app/Http/Controllers/API/V4/SkusController.php
--- a/src/app/Http/Controllers/API/V4/SkusController.php
+++ b/src/app/Http/Controllers/API/V4/SkusController.php
@@ -4,6 +4,7 @@
use App\Handlers\Mailbox;
use App\Http\Controllers\ResourceController;
+use App\Http\Resources\SkuResource;
use App\Sku;
use App\Wallet;
use Dedoc\Scramble\Attributes\QueryParameter;
@@ -19,38 +20,26 @@
public function index(): JsonResponse
{
$type = request()->input('type');
+ $wallet = $this->guard()->user()->wallet();
// Note: Order by title for consistent ordering in tests
- $response = Sku::withSubjectTenantContext()->where('active', true)->orderBy('title')
+ $list = Sku::withSubjectTenantContext()->where('active', true)->orderBy('title')
->get()
- ->transform(function ($sku) {
- return $this->skuElement($sku);
+ ->transform(function ($sku, $type) {
+ return $this->skuElement($sku, $type);
})
->filter(static function ($sku) use ($type) {
- return $sku && (!$type || $sku['type'] === $type);
+ return $sku && (!$type || $sku->metadata['type'] === $type);
})
->sortByDesc('prio')
->values();
- if ($type) {
- $wallet = $this->guard()->user()->wallet();
-
- // Figure out the cost for a new object of the specified type
- $response = $response->map(static function ($sku) use ($wallet) {
- $sku['nextCost'] = $sku['cost'];
- if ($sku['cost'] && $sku['units_free']) {
- $count = $wallet->entitlements()->where('sku_id', $sku['id'])->count();
-
- if ($count < $sku['units_free']) {
- $sku['nextCost'] = 0;
- }
- }
-
- return $sku;
- });
- }
-
- return response()->json($response->all());
+ return response()->json([
+ // @var array<SkuResource> List of SKUs
+ 'list' => $list,
+ // @var int Number of entries in the list
+ 'count' => $list->count(),
+ ]);
}
/**
@@ -60,41 +49,31 @@
*/
public static function objectSkus($object): JsonResponse
{
- $response = [];
+ $user = Auth::guard()->user();
// Note: Order by title for consistent ordering in tests
- $skus = Sku::withObjectTenantContext($object)->orderBy('title')->get();
-
- foreach ($skus as $sku) {
- if (!class_exists($sku->handler_class)) {
- continue;
- }
-
- if ($object::class != $sku->handler_class::entitleableClass()) {
- continue;
- }
-
- if (!$sku->handler_class::isAvailable($sku, $object)) {
- continue;
- }
-
- if ($data = self::skuElement($sku)) {
- if (!empty($data['controllerOnly'])) {
- $user = Auth::guard()->user();
- if (!$user->wallet()->isController($user)) {
- continue;
- }
- }
-
- $response[] = $data;
- }
- }
-
- usort($response, static function ($a, $b) {
- return $b['prio'] <=> $a['prio'];
- });
+ $list = Sku::withObjectTenantContext($object)->orderBy('title')
+ ->get()
+ ->filter(static function ($sku) use ($object) {
+ return class_exists($sku->handler_class)
+ && $object::class == $sku->handler_class::entitleableClass()
+ && $sku->handler_class::isAvailable($sku, $object);
+ })
+ ->transform(function ($sku) {
+ return self::skuElement($sku);
+ })
+ ->filter(static function ($sku) use ($user) {
+ return !empty($sku) && (empty($sku->controllerOnly) || $user->wallet()->isController($user));
+ })
+ ->sortByDesc('prio')
+ ->values();
- return response()->json($response);
+ return response()->json([
+ // @var array<SkuResource> List of SKUs
+ 'list' => $list,
+ // @var int Number of entries in the list
+ 'count' => $list->count(),
+ ]);
}
/**
@@ -157,31 +136,26 @@
* Convert SKU information to metadata used by UI to
* display the form control
*
- * @param Sku $sku SKU object
- *
- * @return array|null Metadata
+ * @param Sku $sku SKU object
+ * @param string $type Type filter
*/
- protected static function skuElement($sku): ?array
+ protected static function skuElement($sku, $type = null): ?SkuResource
{
if (!class_exists($sku->handler_class)) {
\Log::warning("Missing handler {$sku->handler_class}");
return null;
}
- $data = array_merge($sku->toArray(), $sku->handler_class::metadata($sku));
+ $resource = new SkuResource($sku);
// ignore incomplete handlers
- if (empty($data['type'])) {
+ if (empty($resource->metadata['type'])) {
\Log::warning("Incomplete handler {$sku->handler_class}");
return null;
}
- // Use localized value, toArray() does not get them right
- $data['name'] = $sku->name;
- $data['description'] = $sku->description;
-
- unset($data['handler_class'], $data['created_at'], $data['updated_at'], $data['fee'], $data['tenant_id']);
+ $resource->type = $type;
- return $data;
+ return $resource;
}
}
diff --git a/src/app/Http/Controllers/API/V4/SupportController.php b/src/app/Http/Controllers/API/V4/SupportController.php
--- a/src/app/Http/Controllers/API/V4/SupportController.php
+++ b/src/app/Http/Controllers/API/V4/SupportController.php
@@ -32,7 +32,7 @@
]);
if ($v->fails()) {
- return response()->json(['status' => 'error', 'errors' => $v->errors()], 422);
+ return response()->json(['status' => 'error', /* @var array */ 'errors' => $v->errors()], 422);
}
$params = $request->only(array_keys($rules));
diff --git a/src/app/Http/Controllers/API/V4/VPNController.php b/src/app/Http/Controllers/API/V4/VPNController.php
--- a/src/app/Http/Controllers/API/V4/VPNController.php
+++ b/src/app/Http/Controllers/API/V4/VPNController.php
@@ -15,13 +15,13 @@
class VPNController extends Controller
{
/**
- * Token request from the vpn module
+ * Get a token from the VPN module
*/
public function token(Request $request): JsonResponse
{
- $signingKey = \config("app.vpn.token_signing_key");
+ $signingKey = \config('app.vpn.token_signing_key');
if (empty($signingKey)) {
- throw new \Exception("app.vpn.token_signing_key is not set");
+ throw new \Exception('app.vpn.token_signing_key is not set');
}
$tokenBuilder = (new Builder(new JoseEncoder(), ChainedFormatter::default()));
@@ -29,7 +29,7 @@
->issuedAt(Carbon::now()->toImmutable())
// The entitlement is hardcoded for now to default.
// Can be extended in the future based on user entitlements.
- ->withClaim('entitlement', "default")
+ ->withClaim('entitlement', 'default')
->getToken(new Rsa\Sha256(), InMemory::plainText($signingKey));
return response()->json(['status' => 'ok', 'token' => $token->toString()]);
diff --git a/src/app/Http/Controllers/API/V4/WalletsController.php b/src/app/Http/Controllers/API/V4/WalletsController.php
--- a/src/app/Http/Controllers/API/V4/WalletsController.php
+++ b/src/app/Http/Controllers/API/V4/WalletsController.php
@@ -4,6 +4,7 @@
use App\Documents\Receipt;
use App\Http\Controllers\ResourceController;
+use App\Http\Resources\TransactionResource;
use App\Http\Resources\WalletInfoResource;
use App\Payment;
use App\ReferralCode;
@@ -238,7 +239,6 @@
$pageSize = 10;
$page = (int) (request()->input('page')) ?: 1;
$hasMore = false;
- $isAdmin = $this instanceof Admin\WalletsController;
if ($transaction = request()->input('transaction')) {
// Get sub-transactions for the specified transaction ID, first
@@ -271,27 +271,15 @@
}
}
- $result = $result->map(static function ($item) use ($isAdmin, $wallet) {
- $entry = [
- 'id' => $item->id,
- 'createdAt' => $item->created_at->format('Y-m-d H:i'),
- 'type' => $item->type,
- 'description' => $item->shortDescription(),
- 'amount' => $item->amount,
- 'currency' => $wallet->currency,
- 'hasDetails' => !empty($item->cnt),
- ];
-
- if ($isAdmin && $item->user_email) {
- $entry['user'] = $item->user_email;
- }
-
+ $result = $result->map(static function ($item) use ($wallet) {
+ $entry = new TransactionResource($item);
+ $entry->wallet = $wallet;
return $entry;
});
return response()->json([
'status' => 'success',
- // @var array<array> List of transactions (properties: id, createdAt, type, description, amount, currency, hasDetails, user)
+ // @var array<TransactionResource> List of transactions
'list' => $result,
// @var int Number of entries in the list
'count' => count($result),
diff --git a/src/app/Http/Resources/ApiResource.php b/src/app/Http/Resources/ApiResource.php
--- a/src/app/Http/Resources/ApiResource.php
+++ b/src/app/Http/Resources/ApiResource.php
@@ -23,18 +23,16 @@
/**
* Include SKUs/Wallet information in the object's response.
- *
- * @param object $object User/Domain/etc object
*/
- public static function objectEntitlements($object): array
+ public function objectEntitlements(): array
{
- $wallet = $object->wallet();
+ $wallet = $this->resource->wallet();
return [
- // Entitlements information
- 'skus' => Entitlement::objectEntitlementsSummary($object),
+ // @var array<string, array> Entitlements information
+ 'skus' => Entitlement::objectEntitlementsSummary($this->resource),
// Wallet information
- 'wallet' => $wallet ? new WalletResource($wallet) : null,
+ 'wallet' => $this->when($wallet, new WalletResource($wallet)),
];
}
}
diff --git a/src/app/Http/Resources/DeviceInfoResource.php b/src/app/Http/Resources/DeviceInfoResource.php
--- a/src/app/Http/Resources/DeviceInfoResource.php
+++ b/src/app/Http/Resources/DeviceInfoResource.php
@@ -19,7 +19,10 @@
public function toArray(Request $request): array
{
return [
- // Device registration date-time
+ /*
+ * @var string Device registration date-time
+ * @format date-time
+ */
'created_at' => (string) $this->resource->created_at,
];
}
diff --git a/src/app/Http/Resources/DomainInfoResource.php b/src/app/Http/Resources/DomainInfoResource.php
--- a/src/app/Http/Resources/DomainInfoResource.php
+++ b/src/app/Http/Resources/DomainInfoResource.php
@@ -21,12 +21,6 @@
// @var int Domain status
'status' => $this->resource->status,
- // Domain creation date-time
- 'created_at' => (string) $this->resource->created_at,
- // Domain modification date-time
- 'updated_at' => (string) $this->resource->updated_at,
- // @var string|null Domain deletion date-time
- 'deleted_at' => (string) $this->resource->deleted_at,
// Domain DNS hash
'hash_text' => $this->resource->hash(Domain::HASH_TEXT),
@@ -47,7 +41,7 @@
'statusInfo' => DomainsController::statusInfo($this->resource),
// Entitlements/Wallet information
- $this->merge(self::objectEntitlements($this->resource)),
+ $this->merge($this->objectEntitlements()),
];
}
diff --git a/src/app/Http/Resources/DomainResource.php b/src/app/Http/Resources/DomainResource.php
--- a/src/app/Http/Resources/DomainResource.php
+++ b/src/app/Http/Resources/DomainResource.php
@@ -28,6 +28,19 @@
// Domain type
'type' => $this->resource->type,
+ $this->mergeWhen(self::isAdmin(), [
+ /*
+ * @var string Domain creation date-time
+ * @format date-time
+ */
+ 'created_at' => (string) $this->resource->created_at,
+ /*
+ * @var string Domain deletion date-time
+ * @format date-time
+ */
+ 'deleted_at' => (string) $this->resource->deleted_at,
+ ]),
+
// @var bool Is domain active?
'isActive' => $state['isActive'] ?? false,
// @var bool Is domain deleted?
diff --git a/src/app/Http/Resources/GroupInfoResource.php b/src/app/Http/Resources/GroupInfoResource.php
--- a/src/app/Http/Resources/GroupInfoResource.php
+++ b/src/app/Http/Resources/GroupInfoResource.php
@@ -21,12 +21,6 @@
// @var int Group status
'status' => $this->resource->status,
- // Group creation date-time
- 'created_at' => (string) $this->resource->created_at,
- // Group modification date-time
- 'updated_at' => (string) $this->resource->updated_at,
- // @var string|null Group deletion date-time
- 'deleted_at' => (string) $this->resource->deleted_at,
// @var array<string, mixed> Group configuration, e.g. spf whitelist
'config' => $this->resource->getConfig(),
@@ -38,7 +32,7 @@
'statusInfo' => GroupsController::statusInfo($this->resource),
// Entitlements/Wallet information
- $this->merge(self::objectEntitlements($this->resource)),
+ $this->merge($this->objectEntitlements()),
];
}
}
diff --git a/src/app/Http/Resources/GroupResource.php b/src/app/Http/Resources/GroupResource.php
--- a/src/app/Http/Resources/GroupResource.php
+++ b/src/app/Http/Resources/GroupResource.php
@@ -28,6 +28,19 @@
// Group name
'name' => $this->resource->name,
+ $this->mergeWhen(self::isAdmin(), [
+ /*
+ * @var string Group creation date-time
+ * @format date-time
+ */
+ 'created_at' => (string) $this->resource->created_at,
+ /*
+ * @var string Group deletion date-time
+ * @format date-time
+ */
+ 'deleted_at' => (string) $this->resource->deleted_at,
+ ]),
+
// @var bool Is group active?
'isActive' => $state['isActive'] ?? false,
// @var bool Is group deleted?
diff --git a/src/app/Http/Resources/ResourceInfoResource.php b/src/app/Http/Resources/ResourceInfoResource.php
--- a/src/app/Http/Resources/ResourceInfoResource.php
+++ b/src/app/Http/Resources/ResourceInfoResource.php
@@ -21,12 +21,6 @@
// @var int Resource status
'status' => $this->resource->status,
- // Resource creation date-time
- 'created_at' => (string) $this->resource->created_at,
- // Resource modification date-time
- 'updated_at' => (string) $this->resource->updated_at,
- // @var string|null Resource deletion date-time
- 'deleted_at' => (string) $this->resource->deleted_at,
// @var array<string, mixed> Resource configuration
'config' => $this->resource->getConfig(),
@@ -35,7 +29,7 @@
'statusInfo' => ResourcesController::statusInfo($this->resource),
// Entitlements/Wallet information
- $this->merge(self::objectEntitlements($this->resource)),
+ $this->merge($this->objectEntitlements()),
];
}
}
diff --git a/src/app/Http/Resources/ResourceResource.php b/src/app/Http/Resources/ResourceResource.php
--- a/src/app/Http/Resources/ResourceResource.php
+++ b/src/app/Http/Resources/ResourceResource.php
@@ -28,6 +28,19 @@
// Resource name
'name' => $this->resource->name,
+ $this->mergeWhen(self::isAdmin(), [
+ /*
+ * @var string Resource creation date-time
+ * @format date-time
+ */
+ 'created_at' => (string) $this->resource->created_at,
+ /*
+ * @var string Resource deletion date-time
+ * @format date-time
+ */
+ 'deleted_at' => (string) $this->resource->deleted_at,
+ ]),
+
// @var bool Is resource active?
'isActive' => $state['isActive'] ?? false,
// @var bool Is resource deleted?
diff --git a/src/app/Http/Resources/RoomInfoResource.php b/src/app/Http/Resources/RoomInfoResource.php
new file mode 100644
--- /dev/null
+++ b/src/app/Http/Resources/RoomInfoResource.php
@@ -0,0 +1,54 @@
+<?php
+
+namespace App\Http\Resources;
+
+use App\Meet\Room;
+use App\Permission;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
+
+/**
+ * Room information response
+ */
+class RoomInfoResource extends RoomResource
+{
+ // Current user permission
+ public ?Permission $permission = null;
+
+ /**
+ * Transform the resource into an array.
+ */
+ public function toArray(Request $request): array
+ {
+ $user = Auth::guard()->user();
+ $isOwner = $user->canDelete($this->resource);
+ $config = $this->resource->getConfig();
+
+ // Room sharees can't manage/see room ACL
+ if ($this->permission) {
+ unset($config['acl']);
+ }
+
+ return [
+ $this->merge(parent::toArray($request)),
+
+ // @var array<string, mixed> Room configuration
+ 'config' => $config,
+
+ // @var bool Can the user update the room?
+ 'canUpdate' => $isOwner || $this->resource->permissions()->where('user', $user->email)->exists(),
+
+ // @var bool Can the user delete the room?
+ 'canDelete' => $isOwner && $user->wallet()->isController($user),
+
+ // @var bool Can the user share the room?
+ 'canShare' => $isOwner && $this->resource->hasSku('group-room'),
+
+ // @var bool Is the user an owner of this room?
+ 'isOwner' => $isOwner,
+
+ // Entitlements/Wallet information
+ $this->merge($this->objectEntitlements()),
+ ];
+ }
+}
diff --git a/src/app/Http/Resources/RoomResource.php b/src/app/Http/Resources/RoomResource.php
new file mode 100644
--- /dev/null
+++ b/src/app/Http/Resources/RoomResource.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace App\Http\Resources;
+
+use App\Http\Controllers\RelationController;
+use App\Meet\Room;
+use Illuminate\Http\Request;
+
+/**
+ * Room response
+ *
+ * @mixin Room
+ */
+class RoomResource extends ApiResource
+{
+ /**
+ * Transform the resource into an array.
+ */
+ public function toArray(Request $request): array
+ {
+ $state = RelationController::objectState($this->resource);
+
+ return [
+ // Room identifier
+ 'id' => $this->resource->id,
+ // Room name
+ 'name' => $this->resource->name,
+ // Room description
+ 'description' => $this->resource->description,
+
+ $this->mergeWhen(self::isAdmin(), [
+ /*
+ * @var string Room creation date-time
+ * @format date-time
+ */
+ 'created_at' => (string) $this->resource->created_at,
+ /*
+ * @var string Room deletion date-time
+ * @format date-time
+ */
+ 'deleted_at' => (string) $this->resource->deleted_at,
+ ]),
+
+ // @var bool Is room deleted?
+ 'isDeleted' => $state['isDeleted'] ?? false,
+ // @var bool Readiness state
+ 'isReady' => $state['isReady'],
+ ];
+ }
+}
diff --git a/src/app/Http/Resources/RoomSessionResource.php b/src/app/Http/Resources/RoomSessionResource.php
new file mode 100644
--- /dev/null
+++ b/src/app/Http/Resources/RoomSessionResource.php
@@ -0,0 +1,66 @@
+<?php
+
+namespace App\Http\Resources;
+
+use App\Http\Controllers\Controller;
+use Illuminate\Http\Request;
+
+/**
+ * Meet room session response
+ */
+class RoomSessionResource extends ApiResource
+{
+ public ?int $code = null;
+ public bool $isOwner = false;
+ public ?string $token = null;
+ public ?int $role = null;
+
+ /**
+ * Transform the resource into an array.
+ */
+ public function toArray(Request $request): array
+ {
+ return [
+ // @var int Response status code
+ 'code' => $this->when(isset($this->code), $this->code),
+ // @var string Response message
+ 'message' => $this->when(isset($this->code), $this->message($this->code)),
+ // @var string Response status
+ 'status' => $this->code ? 'error' : 'success',
+ // Room configuration
+ 'config' => [
+ // @var bool Whether the room is locked
+ 'locked' => $this->resource['locked'] === 'true',
+ // @var bool Whether use of media is disabled in the room
+ 'nomedia' => $this->resource['nomedia'] === 'true',
+ // @var string Room password
+ 'password' => $this->isOwner ? (string) $this->resource['password'] : '',
+ // @var bool Whether the password is required or not
+ 'requires_password' => !$this->isOwner && strlen((string) $this->resource['password']),
+ ],
+ // @var int User role in the room
+ 'role' => $this->when(isset($this->role), $this->role),
+ // @var string Session token
+ 'token' => $this->when(isset($this->token), $this->token),
+ ];
+ }
+
+ /**
+ * Get a status message for the status code
+ */
+ private function message($code): ?string
+ {
+ switch ((int) $code) {
+ case 323:
+ case 324:
+ return Controller::trans('meet.session-not-found');
+ case 325:
+ return Controller::trans('meet.session-password-error');
+ case 326:
+ case 327:
+ return Controller::trans('meet.session-room-locked-error');
+ }
+
+ return null;
+ }
+}
diff --git a/src/app/Http/Resources/SharedFolderInfoResource.php b/src/app/Http/Resources/SharedFolderInfoResource.php
--- a/src/app/Http/Resources/SharedFolderInfoResource.php
+++ b/src/app/Http/Resources/SharedFolderInfoResource.php
@@ -20,12 +20,6 @@
// @var int Folder status
'status' => $this->resource->status,
- // Folder creation date-time
- 'created_at' => (string) $this->resource->created_at,
- // Folder modification date-time
- 'updated_at' => (string) $this->resource->updated_at,
- // @var string|null Folder deletion date-time
- 'deleted_at' => (string) $this->resource->deleted_at,
// @var array Folder aliases (email addresses)
'aliases' => $this->resource->aliases()->pluck('alias')->all(),
@@ -37,7 +31,7 @@
'statusInfo' => SharedFoldersController::statusInfo($this->resource),
// Entitlements/Wallet information
- $this->merge(self::objectEntitlements($this->resource)),
+ $this->merge($this->objectEntitlements()),
];
}
}
diff --git a/src/app/Http/Resources/SharedFolderResource.php b/src/app/Http/Resources/SharedFolderResource.php
--- a/src/app/Http/Resources/SharedFolderResource.php
+++ b/src/app/Http/Resources/SharedFolderResource.php
@@ -30,6 +30,19 @@
// Folder type
'type' => $this->resource->type,
+ $this->mergeWhen(self::isAdmin(), [
+ /*
+ * @var string Folder creation date-time
+ * @format date-time
+ */
+ 'created_at' => (string) $this->resource->created_at,
+ /*
+ * @var string Folder deletion date-time
+ * @format date-time
+ */
+ 'deleted_at' => (string) $this->resource->deleted_at,
+ ]),
+
// @var bool Is folder active?
'isActive' => $state['isActive'] ?? false,
// @var bool Is folder deleted?
diff --git a/src/app/Http/Resources/SkuResource.php b/src/app/Http/Resources/SkuResource.php
new file mode 100644
--- /dev/null
+++ b/src/app/Http/Resources/SkuResource.php
@@ -0,0 +1,99 @@
+<?php
+
+namespace App\Http\Resources;
+
+use App\Sku;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
+
+/**
+ * SKU response
+ *
+ * @mixin Sku
+ */
+class SkuResource extends ApiResource
+{
+ public bool $controllerOnly = false;
+ public ?string $type = null;
+ public int $prio = 0;
+ public array $metadata = [];
+
+ /**
+ * Create a new resource instance.
+ *
+ * @param mixed $resource
+ */
+ public function __construct($resource)
+ {
+ parent::__construct($resource);
+
+ $this->metadata = $resource->handler_class::metadata($resource);
+ $this->controllerOnly = !empty($this->metadata['controllerOnly']);
+ $this->prio = $this->metadata['prio'];
+ }
+
+ /**
+ * Transform the resource into an array.
+ */
+ public function toArray(Request $request): array
+ {
+ return [
+ // @var string SKU identifier
+ 'id' => $this->resource->id,
+ // @var string SKU identifier
+ 'title' => $this->resource->title,
+ // @var string SKU name
+ 'name' => $this->resource->name,
+ // @var string SKU description
+ 'description' => $this->resource->description,
+ // @var int SKU (monthly) cost (in cents)
+ 'cost' => $this->resource->cost,
+ // @var bool SKU is active
+ 'active' => $this->resource->active,
+ // @var string SKU period (monthly, yearly)
+ 'period' => $this->resource->period,
+ // @var int Number of free units
+ 'units_free' => $this->resource->units_free,
+
+ // @var string SKU type
+ 'type' => $this->metadata['type'],
+ // @var string SKU handler class
+ 'handler' => $this->metadata['handler'],
+ // @var bool Is the SKU readonly?
+ 'readonly' => $this->metadata['readonly'] ?? false,
+ // @var bool Is the SKU enabled?
+ 'enabled' => $this->metadata['enabled'] ?? false,
+ // @var int SKU priority (for list order)
+ 'prio' => $this->metadata['prio'],
+ // @var array<string> Forbidden SKUs (by handler name)
+ 'forbidden' => $this->metadata['forbidden'] ?? [],
+ // @var array<string> Exclusive SKUs (by handler name)
+ 'exclusive' => $this->metadata['exclusive'] ?? [],
+ // @var array<string> Required SKUs (by handler name)
+ 'required' => $this->metadata['required'] ?? [],
+ // @var array<string, mixed> SKU value range
+ 'range' => $this->when(isset($this->metadata['range']), $this->metadata['range'] ?? []),
+
+ // Cost for a new object of the specified type
+ 'nextCost' => $this->when(!empty($this->type), fn () => $this->nextCost()),
+ ];
+ }
+
+ /**
+ * Calculate SKU cost for a new object of the specified type
+ */
+ private function nextCost(): int
+ {
+ $wallet = Auth::guard()->user()->wallet();
+ $nextCost = $this->resource->cost;
+
+ if ($wallet && $this->resource->cost && $this->resource->units_free) {
+ $count = $wallet->entitlements()->where('sku_id', $this->resource->id)->count();
+ if ($count < $this->resource->units_free) {
+ $nextCost = 0;
+ }
+ }
+
+ return $nextCost;
+ }
+}
diff --git a/src/app/Http/Resources/TransactionResource.php b/src/app/Http/Resources/TransactionResource.php
new file mode 100644
--- /dev/null
+++ b/src/app/Http/Resources/TransactionResource.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace App\Http\Resources;
+
+use App\Transaction;
+use App\Wallet;
+use Illuminate\Http\Request;
+
+/**
+ * Transaction response
+ *
+ * @mixin Transaction
+ */
+class TransactionResource extends ApiResource
+{
+ public ?Wallet $wallet;
+
+ /**
+ * Transform the resource into an array.
+ */
+ public function toArray(Request $request): array
+ {
+ return [
+ // Transaction identifier
+ 'id' => $this->resource->id,
+ // Transaction date (Y-m-d H:i)
+ 'createdAt' => $this->resource->created_at->format('Y-m-d H:i'),
+ // Transaction type
+ 'type' => $this->resource->type,
+ // Transaction description
+ 'description' => $this->resource->shortDescription(),
+ // @var int Transaction amount (in cents)
+ 'amount' => $this->resource->amount,
+ // Transaction currency
+ 'currency' => $this->wallet->currency,
+
+ // @var bool Indicates that the entry has sub-transactions
+ 'hasDetails' => !empty($this->resource->cnt),
+
+ // Acting user email address
+ 'user' => $this->when(self::isAdmin(), $this->resource->user_email),
+ ];
+ }
+}
diff --git a/src/app/Http/Resources/UserInfoResource.php b/src/app/Http/Resources/UserInfoResource.php
--- a/src/app/Http/Resources/UserInfoResource.php
+++ b/src/app/Http/Resources/UserInfoResource.php
@@ -56,7 +56,7 @@
'statusInfo' => UsersController::statusInfo($this->resource),
// Entitlements/Wallet information
- $this->merge(self::objectEntitlements($this->resource)),
+ $this->merge($this->objectEntitlements()),
];
}
}
diff --git a/src/app/Http/Resources/UserResource.php b/src/app/Http/Resources/UserResource.php
--- a/src/app/Http/Resources/UserResource.php
+++ b/src/app/Http/Resources/UserResource.php
@@ -29,9 +29,15 @@
'status' => $this->resource->status,
$this->mergeWhen(self::isAdmin(), [
- // User creation date-time
+ /*
+ * @var string User creation date-time
+ * @format date-time
+ */
'created_at' => (string) $this->resource->created_at,
- // User deletion date-time
+ /*
+ * @var string User deletion date-time
+ * @format date-time
+ */
'deleted_at' => (string) $this->resource->deleted_at,
]),
diff --git a/src/app/Http/Resources/WalletMandateResource.php b/src/app/Http/Resources/WalletMandateResource.php
--- a/src/app/Http/Resources/WalletMandateResource.php
+++ b/src/app/Http/Resources/WalletMandateResource.php
@@ -29,10 +29,10 @@
'isPending' => $this->resource['isPending'] ?? false,
// @var bool Is the mandate existing and valid?
'isValid' => $this->resource['isValid'] ?? false,
- // @var string|null Payment method name
+ // @var string|null Payment method description
'method' => $this->resource['method'] ?? null,
// @var string|null Payment method identifier
- 'methodId' => $this->resource['method'] ?? null,
+ 'methodId' => $this->resource['methodId'] ?? null,
];
}
}
diff --git a/src/app/Meet/Room.php b/src/app/Meet/Room.php
--- a/src/app/Meet/Room.php
+++ b/src/app/Meet/Room.php
@@ -97,11 +97,11 @@
*
* @param int $role User role (see self::ROLE_* constants)
*
- * @return array|null Token data on success, NULL otherwise
+ * @return string|null Session token on success, NULL otherwise
*
* @throws \Exception if session does not exist
*/
- public function getSessionToken($role = self::ROLE_SUBSCRIBER): ?array
+ public function getSessionToken($role = self::ROLE_SUBSCRIBER): ?string
{
if (!$this->session_id) {
throw new \Exception("The room session does not exist");
@@ -115,10 +115,7 @@
$response = $this->client()->post($url, $post);
if ($response->status() == 200) {
- return [
- 'token' => $response->json('token'),
- 'role' => $role,
- ];
+ return $response->json('token');
}
$this->logError("Failed to create the meet peer connection", $response);
diff --git a/src/app/Providers/PaymentProvider.php b/src/app/Providers/PaymentProvider.php
--- a/src/app/Providers/PaymentProvider.php
+++ b/src/app/Providers/PaymentProvider.php
@@ -251,7 +251,7 @@
*
* @param string $type the payment type for which we require a method
*
- * @return array Array of methods
+ * @return array<array> Array of methods
*/
private static function applyMethodWhitelist($type, $availableMethods): array
{
@@ -274,15 +274,15 @@
* List supported payment methods for $wallet
*
* @param Wallet $wallet The wallet
- * @param string $type the payment type for which we require a method (oneoff/recurring)
+ * @param string $type The payment type for which we require a method (oneoff/recurring)
*
- * @return array Array of array with available payment methods:
- * - id: id of the method
- * - name: User readable name of the payment method
- * - minimumAmount: Minimum amount to be charged in cents
- * - currency: Currency used for the method
- * - exchangeRate: The projected exchange rate (actual rate is determined during payment)
- * - icon: An icon (icon name) representing the method
+ * @return array<array> Array of array with available payment methods:
+ * - id: id of the method
+ * - name: User readable name of the payment method
+ * - minimumAmount: Minimum amount to be charged in cents
+ * - currency: Currency used for the method
+ * - exchangeRate: The projected exchange rate (actual rate is determined during payment)
+ * - icon: An icon (icon name) representing the method
*/
public static function paymentMethods(Wallet $wallet, $type): array
{
diff --git a/src/app/Traits/Meet/RoomConfigTrait.php b/src/app/Traits/Meet/RoomConfigTrait.php
--- a/src/app/Traits/Meet/RoomConfigTrait.php
+++ b/src/app/Traits/Meet/RoomConfigTrait.php
@@ -43,7 +43,7 @@
} elseif ($key == 'locked' || $key == 'nomedia') {
$this->setSetting($key, $value ? 'true' : null);
} elseif ($key == 'acl') {
- if (!empty($value) && !$this->hasSKU('group-room')) {
+ if (!empty($value) && !$this->hasSku('group-room')) {
$errors[$key] = \trans('validation.invalid-config-parameter');
continue;
}
diff --git a/src/package-lock.json b/src/package-lock.json
--- a/src/package-lock.json
+++ b/src/package-lock.json
@@ -2255,6 +2255,29 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@lukeed/csprng": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz",
+ "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@lukeed/uuid": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/@lukeed/uuid/-/uuid-2.0.1.tgz",
+ "integrity": "sha512-qC72D4+CDdjGqJvkFMMEAtancHUQ7/d/tAiHf64z8MopFDmcrtbcJuerDtFceuAfQJ2pDSfCKCtbqoGBNnwg0w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@lukeed/csprng": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
"version": "5.1.1-v1",
"resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
@@ -2468,6 +2491,14 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/events-alias": {
+ "name": "@types/events",
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.3.tgz",
+ "integrity": "sha512-trOc4AAUThEz9hapPtSd7wf5tiQKvTtu5b371UxXdTuqzIh0ArcRspRP0i0Viu+LXstIQ1z96t1nsPxT9ol01g==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/express": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz",
@@ -2611,17 +2642,6 @@
"undici-types": "~5.26.4"
}
},
- "node_modules/@types/node-fetch": {
- "version": "2.6.12",
- "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz",
- "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/node": "*",
- "form-data": "^4.0.0"
- }
- },
"node_modules/@types/node-forge": {
"version": "1.3.11",
"resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz",
@@ -2632,14 +2652,6 @@
"@types/node": "*"
}
},
- "node_modules/@types/npm-events-package": {
- "name": "@types/events",
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.3.tgz",
- "integrity": "sha512-trOc4AAUThEz9hapPtSd7wf5tiQKvTtu5b371UxXdTuqzIh0ArcRspRP0i0Viu+LXstIQ1z96t1nsPxT9ol01g==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/@types/parse-json": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz",
@@ -3329,16 +3341,16 @@
}
},
"node_modules/awaitqueue": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/awaitqueue/-/awaitqueue-3.2.0.tgz",
- "integrity": "sha512-yFka1VP9+ucU7n3wGerwZ9OzrdxluWl6qngiOlSe+nQyn6PtrR2BQt6HEoShI6sjo1sXAYQHQlUtPXzXSYAJfA==",
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/awaitqueue/-/awaitqueue-3.3.0.tgz",
+ "integrity": "sha512-zLxDhzQbzHmOyvxi7g3OlfR7jLrcmElStPxfLPpJkrFSDm71RSrY/MvsDA8Btlx8X1nOHUzGhQvc6bdUjL2f2w==",
"dev": true,
"license": "ISC",
"dependencies": {
- "debug": "^4.4.0"
+ "debug": "^4.4.3"
},
"engines": {
- "node": ">=18"
+ "node": ">=20"
},
"funding": {
"type": "opencollective",
@@ -3346,9 +3358,9 @@
}
},
"node_modules/awaitqueue/node_modules/debug": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
- "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4805,27 +4817,6 @@
"npm": "1.2.8000 || >= 1.4.16"
}
},
- "node_modules/detect-europe-js": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/detect-europe-js/-/detect-europe-js-0.1.2.tgz",
- "integrity": "sha512-lgdERlL3u0aUdHocoouzT10d9I89VVhk0qNRmll7mXdGfJT1/wqZ2ZLA4oJAjeACPY5fT1wsbq2AT+GkuInsow==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/faisalman"
- },
- {
- "type": "opencollective",
- "url": "https://opencollective.com/ua-parser-js"
- },
- {
- "type": "paypal",
- "url": "https://paypal.me/faisalman"
- }
- ],
- "license": "MIT"
- },
"node_modules/detect-node": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz",
@@ -5624,6 +5615,17 @@
"node": ">=0.8.x"
}
},
+ "node_modules/events-alias": {
+ "name": "events",
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.x"
+ }
+ },
"node_modules/evp_bytestokey": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
@@ -5724,16 +5726,16 @@
"license": "MIT"
},
"node_modules/fake-mediastreamtrack": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fake-mediastreamtrack/-/fake-mediastreamtrack-2.1.0.tgz",
- "integrity": "sha512-A/xmNJtQxtwTQEZqYGE1SDbcA2rIm93TJtGnoaLqG+iL6JB7HdfoTzDZCSmmg3TvqE/xDbkcN0Mswv1rYjF0jw==",
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/fake-mediastreamtrack/-/fake-mediastreamtrack-2.2.1.tgz",
+ "integrity": "sha512-SITLc7UTDirSdgLGORrlmqjWLJtbtfIz/xO7DwVbJH3f0ds+NQok4ccl/WEzz49NSgiUlXf2wDW0+y5C+TO6EA==",
"dev": true,
"license": "ISC",
"dependencies": {
- "uuid": "^11.1.0"
+ "@lukeed/uuid": "^2.0.1"
},
"engines": {
- "node": ">=18"
+ "node": ">=20"
}
},
"node_modules/fast-deep-equal": {
@@ -6349,16 +6351,16 @@
"license": "MIT"
},
"node_modules/h264-profile-level-id": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/h264-profile-level-id/-/h264-profile-level-id-2.2.0.tgz",
- "integrity": "sha512-CwCzxvUWuOvJ0zI8Ltysq+7BBQ9kCoP2FnfYg5ZLLY3pZ2YfH+o6IqP9Eu8XHWqJM2JlmHMHfAApiQ5IDWSRQA==",
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/h264-profile-level-id/-/h264-profile-level-id-2.3.1.tgz",
+ "integrity": "sha512-x2P85PdoRsjCQE7sZjmQQDEf61vTTxOSPNFyqevXaiiq6DzvLVnd0VBq/C7wplrYEqTXvMW5CLIDUMBekNN4Vw==",
"dev": true,
"license": "ISC",
"dependencies": {
- "debug": "^4.4.0"
+ "debug": "^4.4.3"
},
"engines": {
- "node": ">=18"
+ "node": ">=20"
},
"funding": {
"type": "opencollective",
@@ -6366,9 +6368,9 @@
}
},
"node_modules/h264-profile-level-id/node_modules/debug": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
- "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -7114,27 +7116,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/is-standalone-pwa": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/is-standalone-pwa/-/is-standalone-pwa-0.1.1.tgz",
- "integrity": "sha512-9Cbovsa52vNQCjdXOzeQq5CnCbAcRk05aU62K20WO372NrTv0NxibLFCK6lQ4/iZEFdEA3p3t2VNOn8AJ53F5g==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/faisalman"
- },
- {
- "type": "opencollective",
- "url": "https://opencollective.com/ua-parser-js"
- },
- {
- "type": "paypal",
- "url": "https://paypal.me/faisalman"
- }
- ],
- "license": "MIT"
- },
"node_modules/is-stream": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
@@ -7803,25 +7784,24 @@
}
},
"node_modules/mediasoup-client": {
- "version": "3.11.0",
- "resolved": "https://registry.npmjs.org/mediasoup-client/-/mediasoup-client-3.11.0.tgz",
- "integrity": "sha512-MVKngePWhZ6AjHbHGvIf67XSJa3fEP5cvz2bCflfbY+6cGaM51oJIuYj73C4S3y+QRsrHJhPHYRz8swnovTH5g==",
+ "version": "3.16.7",
+ "resolved": "https://registry.npmjs.org/mediasoup-client/-/mediasoup-client-3.16.7.tgz",
+ "integrity": "sha512-MvuflyRMtdcR/+7Km18o4FdKfVb4GF5zdDFoIDx9dRtCH+K5jAU1n7LAs/Pl7ejIVC1BEWIalIH5Q31JdomtBQ==",
"dev": true,
"license": "ISC",
"dependencies": {
"@types/debug": "^4.1.12",
- "@types/npm-events-package": "npm:@types/events@^3.0.3",
- "awaitqueue": "^3.2.0",
- "debug": "^4.4.1",
- "fake-mediastreamtrack": "^2.1.0",
- "h264-profile-level-id": "^2.2.0",
- "npm-events-package": "npm:events@^3.3.0",
+ "@types/events-alias": "npm:@types/events@^3.0.3",
+ "awaitqueue": "^3.3.0",
+ "debug": "^4.4.3",
+ "events-alias": "npm:events@^3.3.0",
+ "fake-mediastreamtrack": "^2.2.1",
+ "h264-profile-level-id": "^2.3.1",
"sdp-transform": "^2.15.0",
- "supports-color": "^10.0.0",
- "ua-parser-js": "^2.0.3"
+ "supports-color": "^10.2.2"
},
"engines": {
- "node": ">=18"
+ "node": ">=20"
},
"funding": {
"type": "opencollective",
@@ -7829,9 +7809,9 @@
}
},
"node_modules/mediasoup-client/node_modules/debug": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
- "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -7854,9 +7834,9 @@
"license": "MIT"
},
"node_modules/mediasoup-client/node_modules/supports-color": {
- "version": "10.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.0.0.tgz",
- "integrity": "sha512-HRVVSbCCMbj7/kdWF9Q+bbckjBHLtHMEoJWlkmYzzdwhYMkjkOwubLM6t7NbWKjgKamGDrWL1++KrjUO1t9oAQ==",
+ "version": "10.2.2",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz",
+ "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==",
"dev": true,
"license": "MIT",
"engines": {
@@ -8173,27 +8153,6 @@
"tslib": "^2.0.3"
}
},
- "node_modules/node-fetch": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
- "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "whatwg-url": "^5.0.0"
- },
- "engines": {
- "node": "4.x || >=6.0.0"
- },
- "peerDependencies": {
- "encoding": "^0.1.0"
- },
- "peerDependenciesMeta": {
- "encoding": {
- "optional": true
- }
- }
- },
"node_modules/node-forge": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
@@ -8314,17 +8273,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/npm-events-package": {
- "name": "events",
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
- "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.8.x"
- }
- },
"node_modules/npm-run-path": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
@@ -11427,13 +11375,6 @@
"node": ">=0.6"
}
},
- "node_modules/tr46": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/tslib": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
@@ -11488,61 +11429,6 @@
"node": ">= 0.6"
}
},
- "node_modules/ua-is-frozen": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/ua-is-frozen/-/ua-is-frozen-0.1.2.tgz",
- "integrity": "sha512-RwKDW2p3iyWn4UbaxpP2+VxwqXh0jpvdxsYpZ5j/MLLiQOfbsV5shpgQiw93+KMYQPcteeMQ289MaAFzs3G9pw==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/faisalman"
- },
- {
- "type": "opencollective",
- "url": "https://opencollective.com/ua-parser-js"
- },
- {
- "type": "paypal",
- "url": "https://paypal.me/faisalman"
- }
- ],
- "license": "MIT"
- },
- "node_modules/ua-parser-js": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-2.0.3.tgz",
- "integrity": "sha512-LZyXZdNttONW8LjzEH3Z8+6TE7RfrEiJqDKyh0R11p/kxvrV2o9DrT2FGZO+KVNs3k+drcIQ6C3En6wLnzJGpw==",
- "dev": true,
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/ua-parser-js"
- },
- {
- "type": "paypal",
- "url": "https://paypal.me/faisalman"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/faisalman"
- }
- ],
- "license": "AGPL-3.0-or-later",
- "dependencies": {
- "@types/node-fetch": "^2.6.12",
- "detect-europe-js": "^0.1.2",
- "is-standalone-pwa": "^0.1.1",
- "node-fetch": "^2.7.0",
- "ua-is-frozen": "^0.1.2"
- },
- "bin": {
- "ua-parser-js": "script/cli.js"
- },
- "engines": {
- "node": "*"
- }
- },
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
@@ -11710,20 +11596,6 @@
"node": ">= 0.4.0"
}
},
- "node_modules/uuid": {
- "version": "11.1.0",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz",
- "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==",
- "dev": true,
- "funding": [
- "https://github.com/sponsors/broofa",
- "https://github.com/sponsors/ctavan"
- ],
- "license": "MIT",
- "bin": {
- "uuid": "dist/esm/bin/uuid"
- }
- },
"node_modules/v8-compile-cache": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz",
@@ -11969,13 +11841,6 @@
"minimalistic-assert": "^1.0.0"
}
},
- "node_modules/webidl-conversions": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
- "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
- "dev": true,
- "license": "BSD-2-Clause"
- },
"node_modules/webpack": {
"version": "5.99.9",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.9.tgz",
@@ -12515,17 +12380,6 @@
"node": ">=0.8.0"
}
},
- "node_modules/whatwg-url": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
- "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "tr46": "~0.0.3",
- "webidl-conversions": "^3.0.0"
- }
- },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
diff --git a/src/resources/vue/Admin/User.vue b/src/resources/vue/Admin/User.vue
--- a/src/resources/vue/Admin/User.vue
+++ b/src/resources/vue/Admin/User.vue
@@ -449,7 +449,7 @@
axios.get('/api/v4/users/' + user_id + '/skus')
.then(response => {
// "merge" SKUs with user entitlement-SKUs
- response.data.forEach(sku => {
+ response.data.list.forEach(sku => {
const userSku = this.user.skus[sku.id]
if (userSku) {
let cost = userSku.costs.reduce((sum, current) => sum + current)
diff --git a/src/resources/vue/Widgets/SubscriptionSelect.vue b/src/resources/vue/Widgets/SubscriptionSelect.vue
--- a/src/resources/vue/Widgets/SubscriptionSelect.vue
+++ b/src/resources/vue/Widgets/SubscriptionSelect.vue
@@ -81,11 +81,11 @@
axios.get(url, { loader: true })
.then(response => {
if (this.readonly && this.object.skus) {
- response.data = response.data.filter(sku => { return sku.id in this.object.skus })
+ response.data.list = response.data.list.filter(sku => { return sku.id in this.object.skus })
}
// "merge" SKUs with user entitlement-SKUs
- this.skus = response.data
+ this.skus = response.data.list
.map(sku => {
const objSku = this.object.skus ? this.object.skus[sku.id] : null
if (objSku) {
@@ -113,7 +113,7 @@
// Mark 'exclusive' SKUs as readonly, they can't be unchecked
this.skus.forEach(item => {
- if (item.exclusive && item.enabled) {
+ if (item.exclusive.length && item.enabled) {
$('#s' + item.id).find('input[type=checkbox]')[0].readOnly = true
}
})
@@ -148,7 +148,7 @@
if (input.checked) {
// Check if a required SKU is selected, alert the user if not
- (sku.required || []).forEach(handler => {
+ sku.required.forEach(handler => {
this.skus.forEach(item => {
if (item.handler == handler) {
if (!$('#s' + item.id).find('input[type=checkbox]:checked').length) {
@@ -164,7 +164,7 @@
}
// Make sure there must be only one of 'exclusive' SKUs
- if (sku.exclusive) {
+ if (sku.exclusive.length) {
input.readOnly = true
this.skus.forEach(item => {
@@ -187,7 +187,7 @@
}
// Uncheck+lock/unlock conflicting SKUs
- (sku.forbidden || []).forEach(handler => {
+ sku.forbidden.forEach(handler => {
this.skus.forEach(item => {
let checkbox
if (item.handler == handler && (checkbox = $('#s' + item.id).find('input[type=checkbox]')[0])) {
diff --git a/src/tests/Browser/Pages/Meet/Room.php b/src/tests/Browser/Pages/Meet/Room.php
--- a/src/tests/Browser/Pages/Meet/Room.php
+++ b/src/tests/Browser/Pages/Meet/Room.php
@@ -89,8 +89,8 @@
'@chat-list' => '#meet-chat .chat',
'@login-form' => '#meet-auth',
- '@login-email-input' => '#inputEmail',
- '@login-password-input' => '#inputPassword',
+ '@login-email-input' => '#email',
+ '@login-password-input' => '#password',
'@login-second-factor-input' => '#secondfactor',
'@login-button' => '#meet-auth button',
];
diff --git a/src/tests/Browser/PasswordResetTest.php b/src/tests/Browser/PasswordResetTest.php
--- a/src/tests/Browser/PasswordResetTest.php
+++ b/src/tests/Browser/PasswordResetTest.php
@@ -235,7 +235,8 @@
// Submit invalid data
$browser->with('@step3', static function ($step) use ($browser) {
- $step->assertFocused('#reset_password')
+ $step->waitFor('#reset_password')
+ ->assertFocused('#reset_password')
->whenAvailable('#reset_password_policy', static function (Browser $browser) {
$browser->assertElementsCount('li', 2)
->assertMissing('li:first-child svg.text-success')
diff --git a/src/tests/Browser/Reseller/UserTest.php b/src/tests/Browser/Reseller/UserTest.php
--- a/src/tests/Browser/Reseller/UserTest.php
+++ b/src/tests/Browser/Reseller/UserTest.php
@@ -28,6 +28,7 @@
$john->setSettings([
'phone' => '+48123123123',
'external_email' => 'john.doe.external@gmail.com',
+ 'greylist_enabled' => null,
'greylist_policy' => null,
]);
if ($john->isSuspended()) {
@@ -47,6 +48,8 @@
$john->setSettings([
'phone' => null,
'external_email' => 'john.doe.external@gmail.com',
+ 'greylist_enabled' => null,
+ 'greylist_policy' => null,
]);
if ($john->isSuspended()) {
User::where('email', $john->email)->update(['status' => $john->status - User::STATUS_SUSPENDED]);
@@ -189,7 +192,7 @@
->whenAvailable('@user-settings form', static function (Browser $browser) {
$browser->assertElementsCount('.row', 3)
->assertSeeIn('.row:first-child label', 'Greylisting')
- ->assertSeeIn('.row:first-child .text-success', 'enabled')
+ ->assertSeeIn('.row:first-child .text-danger', 'disabled')
->assertSeeIn('.row:nth-child(2) label', 'IMAP proxy')
->assertSeeIn('.row:nth-child(2) .text-danger', 'disabled')
->assertSeeIn('.row:nth-child(3) label', 'Geo-lockin')
diff --git a/src/tests/Browser/UsersTest.php b/src/tests/Browser/UsersTest.php
--- a/src/tests/Browser/UsersTest.php
+++ b/src/tests/Browser/UsersTest.php
@@ -224,7 +224,7 @@
$browser->assertQuotaValue(5)->setQuotaValue(6);
})
->assertSeeIn('tr:nth-child(2) td.price', '0,25 CHF/month')
- // groupware SKU
+ // Groupware SKU
->assertSeeIn('tbody tr:nth-child(3) td.name', 'Groupware Features')
->assertSeeIn('tbody tr:nth-child(3) td.price', '4,90 CHF/month')
->assertChecked('tbody tr:nth-child(3) td.selection input')
diff --git a/src/tests/Browser/WalletTest.php b/src/tests/Browser/WalletTest.php
--- a/src/tests/Browser/WalletTest.php
+++ b/src/tests/Browser/WalletTest.php
@@ -218,11 +218,10 @@
$browser->refresh()
->on(new WalletPage())
->click('@nav #tab-refprograms')
- ->whenAvailable('@refprograms-tab', static function (Browser $browser) use ($program, $user) {
+ ->whenAvailable('@refprograms-tab ul', static function (Browser $browser) use ($program, $user) {
$code = $program->codes()->where('user_id', $user->id)->first();
- $browser->waitFor('ul')
- ->assertElementsCount('ul > li', 1)
+ $browser->assertElementsCount('li', 1)
->assertVisible('li:nth-child(1) img')
->assertSeeIn('li:nth-child(1) p.name', $program->name)
->assertSeeIn('li:nth-child(1) p.description', $program->description)
diff --git a/src/tests/Feature/Controller/Admin/SkusTest.php b/src/tests/Feature/Controller/Admin/SkusTest.php
--- a/src/tests/Feature/Controller/Admin/SkusTest.php
+++ b/src/tests/Feature/Controller/Admin/SkusTest.php
@@ -48,7 +48,7 @@
$json = $response->json();
- $this->assertCount(1, $json);
+ $this->assertCount(1, $json['list']);
// Note: Details are tested where we test API\V4\SkusController
}
@@ -74,18 +74,18 @@
$json = $response->json();
- $this->assertCount(12, $json);
- $this->assertSame(100, $json[0]['prio']);
- $this->assertSame($sku->id, $json[0]['id']);
- $this->assertSame($sku->title, $json[0]['title']);
- $this->assertSame($sku->name, $json[0]['name']);
- $this->assertSame($sku->description, $json[0]['description']);
- $this->assertSame($sku->cost, $json[0]['cost']);
- $this->assertSame($sku->units_free, $json[0]['units_free']);
- $this->assertSame($sku->period, $json[0]['period']);
- $this->assertSame($sku->active, $json[0]['active']);
- $this->assertSame('user', $json[0]['type']);
- $this->assertSame('Mailbox', $json[0]['handler']);
+ $this->assertCount(12, $json['list']);
+ $this->assertSame(100, $json['list'][0]['prio']);
+ $this->assertSame($sku->id, $json['list'][0]['id']);
+ $this->assertSame($sku->title, $json['list'][0]['title']);
+ $this->assertSame($sku->name, $json['list'][0]['name']);
+ $this->assertSame($sku->description, $json['list'][0]['description']);
+ $this->assertSame($sku->cost, $json['list'][0]['cost']);
+ $this->assertSame($sku->units_free, $json['list'][0]['units_free']);
+ $this->assertSame($sku->period, $json['list'][0]['period']);
+ $this->assertSame($sku->active, $json['list'][0]['active']);
+ $this->assertSame('user', $json['list'][0]['type']);
+ $this->assertSame('Mailbox', $json['list'][0]['handler']);
}
/**
@@ -109,7 +109,7 @@
$json = $response->json();
- $this->assertCount(5, $json);
+ $this->assertCount(5, $json['list']);
// Note: Details are tested where we test API\V4\SkusController
}
}
diff --git a/src/tests/Feature/Controller/DomainsTest.php b/src/tests/Feature/Controller/DomainsTest.php
--- a/src/tests/Feature/Controller/DomainsTest.php
+++ b/src/tests/Feature/Controller/DomainsTest.php
@@ -414,8 +414,8 @@
$json = $response->json();
- $this->assertCount(1, $json);
- $this->assertSkuElement('domain-hosting', $json[0], [
+ $this->assertCount(1, $json['list']);
+ $this->assertSkuElement('domain-hosting', $json['list'][0], [
'prio' => 0,
'type' => 'domain',
'handler' => 'DomainHosting',
diff --git a/src/tests/Feature/Controller/GroupsTest.php b/src/tests/Feature/Controller/GroupsTest.php
--- a/src/tests/Feature/Controller/GroupsTest.php
+++ b/src/tests/Feature/Controller/GroupsTest.php
@@ -283,8 +283,8 @@
$json = $response->json();
- $this->assertCount(1, $json);
- $this->assertSkuElement('group', $json[0], [
+ $this->assertCount(1, $json['list']);
+ $this->assertSkuElement('group', $json['list'][0], [
'prio' => 0,
'type' => 'group',
'handler' => 'Group',
diff --git a/src/tests/Feature/Controller/MeetTest.php b/src/tests/Feature/Controller/MeetTest.php
--- a/src/tests/Feature/Controller/MeetTest.php
+++ b/src/tests/Feature/Controller/MeetTest.php
@@ -117,7 +117,6 @@
$json = $response->json();
- $this->assertCount(4, $json);
$this->assertSame(325, $json['code']);
$this->assertSame('error', $json['status']);
$this->assertSame('Failed to join the session. Invalid password.', $json['message']);
@@ -195,7 +194,6 @@
$json = $response->json();
- $this->assertCount(4, $json);
$this->assertSame(326, $json['code']);
$this->assertSame('error', $json['status']);
$this->assertSame('Failed to join the session. Room locked.', $json['message']);
diff --git a/src/tests/Feature/Controller/Reseller/SkusTest.php b/src/tests/Feature/Controller/Reseller/SkusTest.php
--- a/src/tests/Feature/Controller/Reseller/SkusTest.php
+++ b/src/tests/Feature/Controller/Reseller/SkusTest.php
@@ -59,7 +59,7 @@
$json = $response->json();
- $this->assertCount(1, $json);
+ $this->assertCount(1, $json['list']);
// Note: Details are tested where we test API\V4\SkusController
}
@@ -91,19 +91,19 @@
$json = $response->json();
- $this->assertCount(12, $json);
+ $this->assertCount(12, $json['list']);
- $this->assertSame(100, $json[0]['prio']);
- $this->assertSame($sku->id, $json[0]['id']);
- $this->assertSame($sku->title, $json[0]['title']);
- $this->assertSame($sku->name, $json[0]['name']);
- $this->assertSame($sku->description, $json[0]['description']);
- $this->assertSame($sku->cost, $json[0]['cost']);
- $this->assertSame($sku->units_free, $json[0]['units_free']);
- $this->assertSame($sku->period, $json[0]['period']);
- $this->assertSame($sku->active, $json[0]['active']);
- $this->assertSame('user', $json[0]['type']);
- $this->assertSame('Mailbox', $json[0]['handler']);
+ $this->assertSame(100, $json['list'][0]['prio']);
+ $this->assertSame($sku->id, $json['list'][0]['id']);
+ $this->assertSame($sku->title, $json['list'][0]['title']);
+ $this->assertSame($sku->name, $json['list'][0]['name']);
+ $this->assertSame($sku->description, $json['list'][0]['description']);
+ $this->assertSame($sku->cost, $json['list'][0]['cost']);
+ $this->assertSame($sku->units_free, $json['list'][0]['units_free']);
+ $this->assertSame($sku->period, $json['list'][0]['period']);
+ $this->assertSame($sku->active, $json['list'][0]['active']);
+ $this->assertSame('user', $json['list'][0]['type']);
+ $this->assertSame('Mailbox', $json['list'][0]['handler']);
// Test with another tenant
$sku = Sku::where('title', 'mailbox')->where('tenant_id', $reseller2->tenant_id)->first();
@@ -112,19 +112,19 @@
$json = $response->json();
- $this->assertCount(6, $json);
-
- $this->assertSame(100, $json[0]['prio']);
- $this->assertSame($sku->id, $json[0]['id']);
- $this->assertSame($sku->title, $json[0]['title']);
- $this->assertSame($sku->name, $json[0]['name']);
- $this->assertSame($sku->description, $json[0]['description']);
- $this->assertSame($sku->cost, $json[0]['cost']);
- $this->assertSame($sku->units_free, $json[0]['units_free']);
- $this->assertSame($sku->period, $json[0]['period']);
- $this->assertSame($sku->active, $json[0]['active']);
- $this->assertSame('user', $json[0]['type']);
- $this->assertSame('Mailbox', $json[0]['handler']);
+ $this->assertCount(6, $json['list']);
+
+ $this->assertSame(100, $json['list'][0]['prio']);
+ $this->assertSame($sku->id, $json['list'][0]['id']);
+ $this->assertSame($sku->title, $json['list'][0]['title']);
+ $this->assertSame($sku->name, $json['list'][0]['name']);
+ $this->assertSame($sku->description, $json['list'][0]['description']);
+ $this->assertSame($sku->cost, $json['list'][0]['cost']);
+ $this->assertSame($sku->units_free, $json['list'][0]['units_free']);
+ $this->assertSame($sku->period, $json['list'][0]['period']);
+ $this->assertSame($sku->active, $json['list'][0]['active']);
+ $this->assertSame('user', $json['list'][0]['type']);
+ $this->assertSame('Mailbox', $json['list'][0]['handler']);
}
/**
@@ -159,7 +159,7 @@
$json = $response->json();
- $this->assertCount(5, $json);
+ $this->assertCount(5, $json['list']);
// Note: Details are tested where we test API\V4\SkusController
}
}
diff --git a/src/tests/Feature/Controller/ResourcesTest.php b/src/tests/Feature/Controller/ResourcesTest.php
--- a/src/tests/Feature/Controller/ResourcesTest.php
+++ b/src/tests/Feature/Controller/ResourcesTest.php
@@ -277,8 +277,8 @@
$json = $response->json();
- $this->assertCount(1, $json);
- $this->assertSkuElement('resource', $json[0], [
+ $this->assertCount(1, $json['list']);
+ $this->assertSkuElement('resource', $json['list'][0], [
'prio' => 0,
'type' => 'resource',
'handler' => 'Resource',
diff --git a/src/tests/Feature/Controller/RoomsTest.php b/src/tests/Feature/Controller/RoomsTest.php
--- a/src/tests/Feature/Controller/RoomsTest.php
+++ b/src/tests/Feature/Controller/RoomsTest.php
@@ -321,11 +321,11 @@
$json = $response->json();
- $this->assertCount(2, $json);
- $this->assertSame('room', $json[0]['title']);
- $this->assertTrue($json[0]['enabled']);
- $this->assertSame('group-room', $json[1]['title']);
- $this->assertFalse($json[1]['enabled']);
+ $this->assertCount(2, $json['list']);
+ $this->assertSame('room', $json['list'][0]['title']);
+ $this->assertTrue($json['list'][0]['enabled']);
+ $this->assertSame('group-room', $json['list'][1]['title']);
+ $this->assertFalse($json['list'][1]['enabled']);
// Room's wallet controller, not owner
$response = $this->actingAs($ned)->get("api/v4/rooms/{$room->id}/skus");
@@ -333,11 +333,11 @@
$json = $response->json();
- $this->assertCount(2, $json);
- $this->assertSame('room', $json[0]['title']);
- $this->assertTrue($json[0]['enabled']);
- $this->assertSame('group-room', $json[1]['title']);
- $this->assertFalse($json[1]['enabled']);
+ $this->assertCount(2, $json['list']);
+ $this->assertSame('room', $json['list'][0]['title']);
+ $this->assertTrue($json['list'][0]['enabled']);
+ $this->assertSame('group-room', $json['list'][1]['title']);
+ $this->assertFalse($json['list'][1]['enabled']);
// Test non-controller user, expect no group-room SKU on the list
$room = $this->getTestRoom('test', $jack->wallets()->first());
@@ -347,9 +347,9 @@
$json = $response->json();
- $this->assertCount(1, $json);
- $this->assertSame('room', $json[0]['title']);
- $this->assertTrue($json[0]['enabled']);
+ $this->assertCount(1, $json['list']);
+ $this->assertSame('room', $json['list'][0]['title']);
+ $this->assertTrue($json['list'][0]['enabled']);
}
/**
diff --git a/src/tests/Feature/Controller/SharedFoldersTest.php b/src/tests/Feature/Controller/SharedFoldersTest.php
--- a/src/tests/Feature/Controller/SharedFoldersTest.php
+++ b/src/tests/Feature/Controller/SharedFoldersTest.php
@@ -281,8 +281,8 @@
$json = $response->json();
- $this->assertCount(1, $json);
- $this->assertSkuElement('shared-folder', $json[0], [
+ $this->assertCount(1, $json['list']);
+ $this->assertSkuElement('shared-folder', $json['list'][0], [
'prio' => 0,
'type' => 'sharedFolder',
'handler' => 'SharedFolder',
diff --git a/src/tests/Feature/Controller/SkusTest.php b/src/tests/Feature/Controller/SkusTest.php
--- a/src/tests/Feature/Controller/SkusTest.php
+++ b/src/tests/Feature/Controller/SkusTest.php
@@ -59,19 +59,19 @@
$json = $response->json();
- $this->assertCount(12, $json);
-
- $this->assertSame(100, $json[0]['prio']);
- $this->assertSame($sku->id, $json[0]['id']);
- $this->assertSame($sku->title, $json[0]['title']);
- $this->assertSame($sku->name, $json[0]['name']);
- $this->assertSame($sku->description, $json[0]['description']);
- $this->assertSame($sku->cost, $json[0]['cost']);
- $this->assertSame($sku->units_free, $json[0]['units_free']);
- $this->assertSame($sku->period, $json[0]['period']);
- $this->assertSame($sku->active, $json[0]['active']);
- $this->assertSame('user', $json[0]['type']);
- $this->assertSame('Mailbox', $json[0]['handler']);
+ $this->assertCount(12, $json['list']);
+
+ $this->assertSame(100, $json['list'][0]['prio']);
+ $this->assertSame($sku->id, $json['list'][0]['id']);
+ $this->assertSame($sku->title, $json['list'][0]['title']);
+ $this->assertSame($sku->name, $json['list'][0]['name']);
+ $this->assertSame($sku->description, $json['list'][0]['description']);
+ $this->assertSame($sku->cost, $json['list'][0]['cost']);
+ $this->assertSame($sku->units_free, $json['list'][0]['units_free']);
+ $this->assertSame($sku->period, $json['list'][0]['period']);
+ $this->assertSame($sku->active, $json['list'][0]['active']);
+ $this->assertSame('user', $json['list'][0]['type']);
+ $this->assertSame('Mailbox', $json['list'][0]['handler']);
// Test the type filter, and nextCost property (user with one domain)
$response = $this->actingAs($john)->get("api/v4/skus?type=domain");
@@ -79,9 +79,9 @@
$json = $response->json();
- $this->assertCount(1, $json);
- $this->assertSame('domain-hosting', $json[0]['title']);
- $this->assertSame(100, $json[0]['nextCost']); // second domain costs 100
+ $this->assertCount(1, $json['list']);
+ $this->assertSame('domain-hosting', $json['list'][0]['title']);
+ $this->assertSame(100, $json['list'][0]['nextCost']); // second domain costs 100
// Test the type filter, and nextCost property (user with no domain)
$jane = $this->getTestUser('jane@kolabnow.com');
@@ -92,9 +92,9 @@
$json = $response->json();
- $this->assertCount(1, $json);
- $this->assertSame('domain-hosting', $json[0]['title']);
- $this->assertSame(0, $json[0]['nextCost']); // first domain costs 0
+ $this->assertCount(1, $json['list']);
+ $this->assertSame('domain-hosting', $json['list'][0]['title']);
+ $this->assertSame(0, $json['list'][0]['nextCost']); // first domain costs 0
}
/**
diff --git a/src/tests/Feature/Controller/UsersTest.php b/src/tests/Feature/Controller/UsersTest.php
--- a/src/tests/Feature/Controller/UsersTest.php
+++ b/src/tests/Feature/Controller/UsersTest.php
@@ -464,9 +464,9 @@
$json = $response->json();
- $this->assertCount(5, $json);
+ $this->assertCount(5, $json['list']);
- $this->assertSkuElement('mailbox', $json[0], [
+ $this->assertSkuElement('mailbox', $json['list'][0], [
'prio' => 100,
'type' => 'user',
'handler' => 'Mailbox',
@@ -474,7 +474,7 @@
'readonly' => true,
]);
- $this->assertSkuElement('storage', $json[1], [
+ $this->assertSkuElement('storage', $json['list'][1], [
'prio' => 90,
'type' => 'user',
'handler' => 'Storage',
@@ -487,7 +487,7 @@
],
]);
- $this->assertSkuElement('groupware', $json[2], [
+ $this->assertSkuElement('groupware', $json['list'][2], [
'prio' => 80,
'type' => 'user',
'handler' => 'Groupware',
@@ -495,7 +495,7 @@
'readonly' => false,
]);
- $this->assertSkuElement('activesync', $json[3], [
+ $this->assertSkuElement('activesync', $json['list'][3], [
'prio' => 70,
'type' => 'user',
'handler' => 'Activesync',
@@ -504,7 +504,7 @@
'required' => ['Groupware'],
]);
- $this->assertSkuElement('2fa', $json[4], [
+ $this->assertSkuElement('2fa', $json['list'][4], [
'prio' => 60,
'type' => 'user',
'handler' => 'Auth2F',
@@ -521,9 +521,9 @@
$json = $response->json();
- $this->assertCount(6, $json);
+ $this->assertCount(6, $json['list']);
- $this->assertSkuElement('beta', $json[5], [
+ $this->assertSkuElement('beta', $json['list'][5], [
'prio' => 10,
'type' => 'user',
'handler' => 'Beta',
diff --git a/src/tests/TestCaseTrait.php b/src/tests/TestCaseTrait.php
--- a/src/tests/TestCaseTrait.php
+++ b/src/tests/TestCaseTrait.php
@@ -172,8 +172,6 @@
foreach ($other as $key => $value) {
$this->assertSame($value, $result[$key]);
}
-
- $this->assertCount(8 + count($other), $result);
}
/**

File Metadata

Mime Type
text/plain
Expires
Fri, Apr 3, 4:00 PM (21 h, 55 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18824611
Default Alt Text
D5658.1775232005.diff (94 KB)

Event Timeline