Page MenuHomePhorge

D1123.1775328006.diff
No OneTemporary

Authored By
Unknown
Size
29 KB
Referenced Files
None
Subscribers
None

D1123.1775328006.diff

diff --git a/src/.gitignore b/src/.gitignore
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -3,10 +3,11 @@
package-lock.json
public/css/app.css
public/hot
-public/js/app.js
+public/js/*.js
public/storage/
storage/*.key
storage/export/
+tests/report/
vendor
.env
.env.backup
diff --git a/src/app/Auth/SecondFactor.php b/src/app/Auth/SecondFactor.php
--- a/src/app/Auth/SecondFactor.php
+++ b/src/app/Auth/SecondFactor.php
@@ -227,8 +227,6 @@
*/
public function read($key)
{
- \Log::debug(__METHOD__ . ' ' . $key);
-
if (!isset($this->cache[$key])) {
$factors = $this->getFactors();
$this->cache[$key] = isset($factors[$key]) ? $factors[$key] : null;
diff --git a/src/app/Backends/LDAP.php b/src/app/Backends/LDAP.php
--- a/src/app/Backends/LDAP.php
+++ b/src/app/Backends/LDAP.php
@@ -430,6 +430,10 @@
if (!in_array("groupware", $roles)) {
$entry['nsroledn'][] = "cn=imap-user,{$hostedRootDN}";
}
+
+ if (empty($entry['nsroledn'])) {
+ unset($entry['nsroledn']);
+ }
}
/**
diff --git a/src/app/Domain.php b/src/app/Domain.php
--- a/src/app/Domain.php
+++ b/src/app/Domain.php
@@ -356,16 +356,9 @@
throw new \Exception("Failed to get DNS record for {$this->namespace}");
}
- // It may happen that result contains other domains depending on the host
- // DNS setup
- $hosts = array_map(
- function ($record) {
- return $record['host'];
- },
- $records
- );
-
- if (in_array($this->namespace, $hosts)) {
+ // It may happen that result contains other domains depending on the host DNS setup
+ // that's why in_array() and not just !empty()
+ if (in_array($this->namespace, array_column($records, 'host'))) {
$this->status |= Domain::STATUS_VERIFIED;
$this->save();
@@ -380,8 +373,11 @@
*
* @return \App\Wallet A wallet object
*/
- public function wallet(): Wallet
+ public function wallet(): ?Wallet
{
- return $this->entitlement()->first()->wallet;
+ // Note: Not all domains have a entitlement/wallet
+ $entitlement = $this->entitlement()->first();
+
+ return $entitlement ? $entitlement->wallet : null;
}
}
diff --git a/src/app/Handlers/Activesync.php b/src/app/Handlers/Activesync.php
--- a/src/app/Handlers/Activesync.php
+++ b/src/app/Handlers/Activesync.php
@@ -18,4 +18,9 @@
return true;
}
+
+ public static function priority(): int
+ {
+ return 70;
+ }
}
diff --git a/src/app/Handlers/Auth2F.php b/src/app/Handlers/Auth2F.php
--- a/src/app/Handlers/Auth2F.php
+++ b/src/app/Handlers/Auth2F.php
@@ -18,4 +18,9 @@
return true;
}
+
+ public static function priority(): int
+ {
+ return 60;
+ }
}
diff --git a/src/app/Http/Controllers/API/V4/Admin/UsersController.php b/src/app/Http/Controllers/API/V4/Admin/UsersController.php
--- a/src/app/Http/Controllers/API/V4/Admin/UsersController.php
+++ b/src/app/Http/Controllers/API/V4/Admin/UsersController.php
@@ -2,16 +2,62 @@
namespace App\Http\Controllers\API\V4\Admin;
+use App\Domain;
+use App\User;
+use App\UserSetting;
+
class UsersController extends \App\Http\Controllers\API\V4\UsersController
{
+ /**
+ * Searching of user accounts.
+ *
+ * @return \Illuminate\Http\JsonResponse
+ */
public function index()
{
- $result = \App\User::orderBy('email')->get()->map(function ($user) {
+ $search = trim(request()->input('search'));
+ $result = collect([]);
+
+ if (strpos($search, '@')) {
+ // Search by email
+ if ($user = User::findByEmail($search, false)) {
+ $result->push($user);
+ } else {
+ // Search by an external email
+ // TODO: This is not optimal (external email should be in users table)
+ $user_ids = UserSetting::where('key', 'external_email')->where('value', $search)
+ ->get()->pluck('user_id');
+
+ // TODO: Sort order
+ $result = User::find($user_ids);
+ }
+ } elseif (is_numeric($search)) {
+ // Search by user ID
+ if ($user = User::find($search)) {
+ $result->push($user);
+ }
+ } elseif (!empty($search)) {
+ // Search by domain
+ if ($domain = Domain::where('namespace', $search)->first()) {
+ if ($wallet = $domain->wallet()) {
+ $result->push($wallet->owner);
+ }
+ }
+ }
+
+ // Process the result
+ $result = $result->map(function ($user) {
$data = $user->toArray();
$data = array_merge($data, self::userStatuses($user));
return $data;
});
+ $result = [
+ 'list' => $result,
+ 'count' => count($result),
+ 'message' => \trans('app.search-foundxusers', ['x' => count($result)]),
+ ];
+
return response()->json($result);
}
}
diff --git a/src/app/User.php b/src/app/User.php
--- a/src/app/User.php
+++ b/src/app/User.php
@@ -355,11 +355,12 @@
* Helper to find user by email address, whether it is
* main email address, alias or external email
*
- * @param string $email Email address
+ * @param string $email Email address
+ * @param bool $external Search also by an external email
*
* @return \App\User User model object if found
*/
- public static function findByEmail(string $email): ?User
+ public static function findByEmail(string $email, bool $external = false): ?User
{
if (strpos($email, '@') === false) {
return null;
diff --git a/src/resources/js/fontawesome.js b/src/resources/js/fontawesome.js
--- a/src/resources/js/fontawesome.js
+++ b/src/resources/js/fontawesome.js
@@ -14,6 +14,7 @@
faLock,
faKey,
faPlus,
+ faSearch,
faSignInAlt,
faSyncAlt,
faTrashAlt,
@@ -32,6 +33,7 @@
faLock,
faKey,
faPlus,
+ faSearch,
faSignInAlt,
faSquare,
faSyncAlt,
diff --git a/src/resources/js/routes-admin.js b/src/resources/js/routes-admin.js
--- a/src/resources/js/routes-admin.js
+++ b/src/resources/js/routes-admin.js
@@ -8,6 +8,7 @@
import LoginComponent from '../vue/Login'
import LogoutComponent from '../vue/Logout'
import PasswordResetComponent from '../vue/PasswordReset'
+import UserComponent from '../vue/Admin/User'
import store from './store'
@@ -37,6 +38,12 @@
name: 'password-reset',
component: PasswordResetComponent
},
+ {
+ path: '/user/:user',
+ name: 'user',
+ component: UserComponent,
+ meta: { requiresAuth: true }
+ },
{
name: '404',
path: '*',
diff --git a/src/resources/lang/en/app.php b/src/resources/lang/en/app.php
--- a/src/resources/lang/en/app.php
+++ b/src/resources/lang/en/app.php
@@ -24,4 +24,6 @@
'user-update-success' => 'User data updated successfully.',
'user-create-success' => 'User created successfully.',
'user-delete-success' => 'User deleted successfully.',
+
+ 'search-foundxusers' => ':x user accounts have been found.',
];
diff --git a/src/resources/vue/Admin/Dashboard.vue b/src/resources/vue/Admin/Dashboard.vue
--- a/src/resources/vue/Admin/Dashboard.vue
+++ b/src/resources/vue/Admin/Dashboard.vue
@@ -1,5 +1,36 @@
<template>
<div v-if="!$root.isLoading" class="container" dusk="dashboard-component">
+ <div id="search-box" class="card">
+ <div class="card-body">
+ <form @submit.prevent="searchUser" class="row justify-content-center">
+ <div class="input-group col-sm-8">
+ <input class="form-control" type="text" placeholder="User ID, email or domain" v-model="search">
+ <div class="input-group-append">
+ <button type="submit" class="btn btn-primary"><svg-icon icon="search"></svg-icon> Search</button>
+ </div>
+ </div>
+ </form>
+ <table v-if="users.length" class="table table-sm table-hover mt-4">
+ <thead class="thead-light">
+ <tr>
+ <th scope="col">Primary Email</th>
+ <th scope="col">ID</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr v-for="user in users" :id="'user' + user.id" :key="user.id">
+ <td>
+ <svg-icon icon="user" :class="$root.userStatusClass(user)" :title="$root.userStatusText(user)"></svg-icon>
+ <router-link :to="{ path: 'user/' + user.id }">{{ user.email }}</router-link>
+ </td>
+ <td>
+ <router-link :to="{ path: 'user/' + user.id }">{{ user.id }}</router-link>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
<div id="dashboard-nav"></div>
</div>
</template>
@@ -8,25 +39,45 @@
export default {
data() {
return {
- isReady: true
+ search: '',
+ users: []
}
},
mounted() {
const authInfo = this.$store.state.isLoggedIn ? this.$store.state.authInfo : null
if (authInfo) {
-
+ $('#search-box input').focus()
} else {
this.$root.startLoading()
axios.get('/api/auth/info')
.then(response => {
this.$store.state.authInfo = response.data
this.$root.stopLoading()
+ setTimeout(() => { $('#search-box input').focus() }, 10)
})
.catch(this.$root.errorHandler)
}
},
methods: {
+ searchUser() {
+ this.users = []
+
+ axios.get('/api/v4/users', { params: { search: this.search } })
+ .then(response => {
+ if (response.data.count == 1) {
+ this.$router.push({ name: 'user', params: { user: response.data.list[0].id } })
+ return
+ }
+
+ if (response.data.message) {
+ this.$toastr('info', response.data.message)
+ }
+
+ this.users = response.data.list
+ })
+ .catch(this.$root.errorHandler)
+ }
}
}
</script>
diff --git a/src/resources/vue/Admin/User.vue b/src/resources/vue/Admin/User.vue
new file mode 100644
--- /dev/null
+++ b/src/resources/vue/Admin/User.vue
@@ -0,0 +1,107 @@
+<template>
+ <div class="container">
+ <div class="card" id="user-info">
+ <div class="card-body">
+ <div class="card-title">{{ user.email }}</div>
+ <div class="card-text">
+ <form @submit.prevent="submit">
+ <div class="form-group row mb-0">
+ <label for="first_name" class="col-sm-4 col-form-label">Status</label>
+ <div class="col-sm-8">
+ <span :class="$root.userStatusClass(user) + ' form-control-plaintext'" id="status">{{ $root.userStatusText(user) }}</span>
+ </div>
+ </div>
+ <div class="form-group row mb-0" v-if="user.first_name">
+ <label for="first_name" class="col-sm-4 col-form-label">First name</label>
+ <div class="col-sm-8">
+ <span class="form-control-plaintext" id="first_name">{{ user.first_name }}</span>
+ </div>
+ </div>
+ <div class="form-group row mb-0" v-if="user.last_name">
+ <label for="last_name" class="col-sm-4 col-form-label">Last name</label>
+ <div class="col-sm-8">
+ <span class="form-control-plaintext" id="last_name">{{ user.last_name }}</span>
+ </div>
+ </div>
+ <div class="form-group row mb-0" v-if="user.phone">
+ <label for="phone" class="col-sm-4 col-form-label">Phone</label>
+ <div class="col-sm-8">
+ <span class="form-control-plaintext" id="phone">{{ user.phone }}</span>
+ </div>
+ </div>
+ <div class="form-group row mb-0">
+ <label for="external_email" class="col-sm-4 col-form-label">External email</label>
+ <div class="col-sm-8">
+ <span class="form-control-plaintext" id="external_email">{{ user.external_email }}</span>
+ </div>
+ </div>
+ <div class="form-group row mb-0" v-if="user.billing_address">
+ <label for="billing_address" class="col-sm-4 col-form-label">Address</label>
+ <div class="col-sm-8">
+ <span class="form-control-plaintext" style="white-space:pre" id="billing_address">{{ user.billing_address }}</span>
+ </div>
+ </div>
+ <div class="form-group row mb-0">
+ <label for="country" class="col-sm-4 col-form-label">Country</label>
+ <div class="col-sm-8">
+ <span class="form-control-plaintext" id="country">{{ user.country }}</span>
+ </div>
+ </div>
+ </form>
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script>
+ export default {
+ data() {
+ return {
+ discount: 0,
+ discount_description: '',
+ user: {},
+ skus: []
+ }
+ },
+ created() {
+ let user_id = this.$route.params.user
+
+ this.$root.startLoading()
+
+ axios.get('/api/v4/users/' + user_id)
+ .then(response => {
+ this.user = response.data
+
+ let keys = ['first_name', 'last_name', 'external_email', 'billing_address']
+ let country = this.user.settings.country
+
+ if (country) {
+ this.user.country = window.config.countries[country][1]
+ }
+
+ keys.forEach(key => { this.user[key] = this.user.settings[key] })
+
+ this.discount = this.user.wallet.discount
+ this.discount_description = this.user.wallet.discount_description
+
+ this.$root.stopLoading()
+ })
+ .catch(this.$root.errorHandler)
+ },
+ mounted() {
+ },
+ methods: {
+ price(cost, units = 1) {
+ let index = ''
+
+ if (this.discount) {
+ cost = Math.floor(cost * ((100 - this.discount) / 100))
+ index = '\u00B9'
+ }
+
+ return this.$root.price(cost * units) + '/month' + index
+ }
+ }
+ }
+</script>
diff --git a/src/tests/Browser/Admin/DashboardTest.php b/src/tests/Browser/Admin/DashboardTest.php
new file mode 100644
--- /dev/null
+++ b/src/tests/Browser/Admin/DashboardTest.php
@@ -0,0 +1,77 @@
+<?php
+
+namespace Tests\Browser\Admin;
+
+use Tests\Browser;
+use Tests\Browser\Components\Toast;
+use Tests\Browser\Pages\Dashboard;
+use Tests\Browser\Pages\Home;
+use Tests\TestCaseDusk;
+use Illuminate\Foundation\Testing\DatabaseMigrations;
+
+class DashboardTest extends TestCaseDusk
+{
+ /**
+ * {@inheritDoc}
+ */
+ public function setUp(): void
+ {
+ parent::setUp();
+ self::useAdminUrl();
+
+ $jack = $this->getTestUser('jack@kolab.org');
+ $jack->setSetting('external_email', null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function tearDown(): void
+ {
+ $jack = $this->getTestUser('jack@kolab.org');
+ $jack->setSetting('external_email', null);
+
+ parent::tearDown();
+ }
+
+ /**
+ * Test user search
+ */
+ public function testSearch(): void
+ {
+ $this->browse(function (Browser $browser) {
+ $browser->visit(new Home())
+ ->submitLogon('jeroen@jeroen.jeroen', 'jeroen', true)
+ ->on(new Dashboard())
+ ->assertFocused('@search input')
+ ->assertMissing('@search table');
+
+ // Test search with no results
+ $browser->type('@search input', 'unknown')
+ ->click('@search form button')
+ ->assertToast(Toast::TYPE_INFO, '', '0 user accounts have been found.')
+ ->assertMissing('@search table');
+
+ $john = $this->getTestUser('john@kolab.org');
+ $jack = $this->getTestUser('jack@kolab.org');
+ $jack->setSetting('external_email', 'john.doe.external@gmail.com');
+
+ // Test search with multiple results
+ $browser->type('@search input', 'john.doe.external@gmail.com')
+ ->click('@search form button')
+ ->assertToast(Toast::TYPE_INFO, '', '2 user accounts have been found.')
+ ->whenAvailable('@search table', function (Browser $browser) {
+ $browser->assertElementsCount('tbody tr', 2);
+ // TODO: Assert table content
+ });
+
+ // Test search with single record result -> redirect to user page
+ $browser->type('@search input', 'kolab.org')
+ ->click('@search form button')
+ ->assertMissing('@search table')
+ ->waitForLocation('/user/' . $john->id)
+ ->waitFor('#user-info')
+ ->assertVisible('#user-info .card-title', $john->email);
+ });
+ }
+}
diff --git a/src/tests/Browser/Admin/LogonTest.php b/src/tests/Browser/Admin/LogonTest.php
--- a/src/tests/Browser/Admin/LogonTest.php
+++ b/src/tests/Browser/Admin/LogonTest.php
@@ -18,11 +18,7 @@
public function setUp(): void
{
parent::setUp();
-
- // This will set baseURL for all tests in this file
- // If we wanted to visit both user and admin in one test
- // we can also just call visit() with full url
- Browser::$baseUrl = str_replace('//', '//admin.', \config('app.url'));
+ self::useAdminUrl();
}
/**
diff --git a/src/tests/Browser/Pages/Dashboard.php b/src/tests/Browser/Pages/Dashboard.php
--- a/src/tests/Browser/Pages/Dashboard.php
+++ b/src/tests/Browser/Pages/Dashboard.php
@@ -52,6 +52,7 @@
'@app' => '#app',
'@links' => '#dashboard-nav',
'@status' => '#status-box',
+ '@search' => '#search-box',
];
}
}
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
@@ -261,25 +261,25 @@
'tbody tr:nth-child(3) td.buttons button',
'Groupware functions like Calendar, Tasks, Notes, etc.'
)
- // 2FA SKU
- ->assertSeeIn('tbody tr:nth-child(4) td.name', '2-Factor Authentication')
- ->assertSeeIn('tbody tr:nth-child(4) td.price', '0,00 CHF/month')
+ // ActiveSync SKU
+ ->assertSeeIn('tbody tr:nth-child(4) td.name', 'Activesync')
+ ->assertSeeIn('tbody tr:nth-child(4) td.price', '1,00 CHF/month')
->assertNotChecked('tbody tr:nth-child(4) td.selection input')
->assertEnabled('tbody tr:nth-child(4) td.selection input')
->assertTip(
'tbody tr:nth-child(4) td.buttons button',
- 'Two factor authentication for webmail and administration panel'
+ 'Mobile synchronization'
)
- // ActiveSync SKU
- ->assertSeeIn('tbody tr:nth-child(5) td.name', 'Activesync')
- ->assertSeeIn('tbody tr:nth-child(5) td.price', '1,00 CHF/month')
+ // 2FA SKU
+ ->assertSeeIn('tbody tr:nth-child(5) td.name', '2-Factor Authentication')
+ ->assertSeeIn('tbody tr:nth-child(5) td.price', '0,00 CHF/month')
->assertNotChecked('tbody tr:nth-child(5) td.selection input')
->assertEnabled('tbody tr:nth-child(5) td.selection input')
->assertTip(
'tbody tr:nth-child(5) td.buttons button',
- 'Mobile synchronization'
+ 'Two factor authentication for webmail and administration panel'
)
- ->click('tbody tr:nth-child(5) td.selection input');
+ ->click('tbody tr:nth-child(4) td.selection input');
})
->assertMissing('@skus table + .hint')
->click('button[type=submit]');
@@ -561,10 +561,10 @@
->assertSeeIn('tr:nth-child(2) td.price', '21,56 CHF/month¹')
// groupware SKU
->assertSeeIn('tbody tr:nth-child(3) td.price', '4,99 CHF/month¹')
- // 2FA SKU
- ->assertSeeIn('tbody tr:nth-child(4) td.price', '0,00 CHF/month¹')
// ActiveSync SKU
- ->assertSeeIn('tbody tr:nth-child(5) td.price', '0,90 CHF/month¹');
+ ->assertSeeIn('tbody tr:nth-child(4) td.price', '0,90 CHF/month¹')
+ // 2FA SKU
+ ->assertSeeIn('tbody tr:nth-child(5) td.price', '0,00 CHF/month¹');
})
->assertSeeIn('@skus table + .hint', '¹ applied discount: 10% - Test voucher');
});
diff --git a/src/tests/Feature/Controller/Admin/UsersTest.php b/src/tests/Feature/Controller/Admin/UsersTest.php
--- a/src/tests/Feature/Controller/Admin/UsersTest.php
+++ b/src/tests/Feature/Controller/Admin/UsersTest.php
@@ -2,8 +2,6 @@
namespace Tests\Feature\Controller\Admin;
-use App\Domain;
-use App\User;
use Tests\TestCase;
class UsersTest extends TestCase
@@ -14,11 +12,10 @@
public function setUp(): void
{
parent::setUp();
+ self::useAdminUrl();
- // This will set base URL for all tests in this file
- // If we wanted to access both user and admin in one test
- // we can also just call post/get/whatever with full url
- \config(['app.url' => str_replace('//', '//admin.', \config('app.url'))]);
+ $jack = $this->getTestUser('jack@kolab.org');
+ $jack->setSetting('external_email', null);
}
/**
@@ -26,24 +23,101 @@
*/
public function tearDown(): void
{
+ $jack = $this->getTestUser('jack@kolab.org');
+ $jack->setSetting('external_email', null);
+
parent::tearDown();
}
/**
- * Test (/api/v4/index)
+ * Test users searching (/api/v4/users)
*/
public function testIndex(): void
{
$user = $this->getTestUser('john@kolab.org');
$admin = $this->getTestUser('jeroen@jeroen.jeroen');
+ // Non-admin user
$response = $this->actingAs($user)->get("api/v4/users");
$response->assertStatus(403);
+ // Search with no search criteria
$response = $this->actingAs($admin)->get("api/v4/users");
$response->assertStatus(200);
- // TODO: Test the response
- $this->markTestIncomplete();
+ $json = $response->json();
+
+ $this->assertSame(0, $json['count']);
+ $this->assertSame([], $json['list']);
+
+ // Search with no matches expected
+ $response = $this->actingAs($admin)->get("api/v4/users?search=abcd1234efgh5678");
+ $response->assertStatus(200);
+
+ $json = $response->json();
+
+ $this->assertSame(0, $json['count']);
+ $this->assertSame([], $json['list']);
+
+ // Search by domain
+ $response = $this->actingAs($admin)->get("api/v4/users?search=kolab.org");
+ $response->assertStatus(200);
+
+ $json = $response->json();
+
+ $this->assertSame(1, $json['count']);
+ $this->assertCount(1, $json['list']);
+ $this->assertSame($user->id, $json['list'][0]['id']);
+ $this->assertSame($user->email, $json['list'][0]['email']);
+
+ // Search by user ID
+ $response = $this->actingAs($admin)->get("api/v4/users?search={$user->id}");
+ $response->assertStatus(200);
+
+ $json = $response->json();
+
+ $this->assertSame(1, $json['count']);
+ $this->assertCount(1, $json['list']);
+ $this->assertSame($user->id, $json['list'][0]['id']);
+ $this->assertSame($user->email, $json['list'][0]['email']);
+
+ // Search by email (primary)
+ $response = $this->actingAs($admin)->get("api/v4/users?search=john@kolab.org");
+ $response->assertStatus(200);
+
+ $json = $response->json();
+
+ $this->assertSame(1, $json['count']);
+ $this->assertCount(1, $json['list']);
+ $this->assertSame($user->id, $json['list'][0]['id']);
+ $this->assertSame($user->email, $json['list'][0]['email']);
+
+ // Search by email (alias)
+ $response = $this->actingAs($admin)->get("api/v4/users?search=john.doe@kolab.org");
+ $response->assertStatus(200);
+
+ $json = $response->json();
+
+ $this->assertSame(1, $json['count']);
+ $this->assertCount(1, $json['list']);
+ $this->assertSame($user->id, $json['list'][0]['id']);
+ $this->assertSame($user->email, $json['list'][0]['email']);
+
+ // Search by email (external), expect two users in a result
+ $jack = $this->getTestUser('jack@kolab.org');
+ $jack->setSetting('external_email', 'john.doe.external@gmail.com');
+
+ $response = $this->actingAs($admin)->get("api/v4/users?search=john.doe.external@gmail.com");
+ $response->assertStatus(200);
+
+ $json = $response->json();
+
+ $this->assertSame(2, $json['count']);
+ $this->assertCount(2, $json['list']);
+
+ $emails = array_column($json['list'], 'email');
+
+ $this->assertContains($user->email, $emails);
+ $this->assertContains($jack->email, $emails);
}
}
diff --git a/src/tests/TestCase.php b/src/tests/TestCase.php
--- a/src/tests/TestCase.php
+++ b/src/tests/TestCase.php
@@ -16,4 +16,15 @@
$entitlement->save();
}
}
+
+ /**
+ * Set baseURL to the admin UI location
+ */
+ protected static function useAdminUrl(): void
+ {
+ // This will set base URL for all tests in a file.
+ // If we wanted to access both user and admin in one test
+ // we can also just call post/get/whatever with full url
+ \config(['app.url' => str_replace('//', '//admin.', \config('app.url'))]);
+ }
}
diff --git a/src/tests/TestCaseDusk.php b/src/tests/TestCaseDusk.php
--- a/src/tests/TestCaseDusk.php
+++ b/src/tests/TestCaseDusk.php
@@ -33,7 +33,6 @@
'--lang=en_US',
'--disable-gpu',
'--headless',
- '--window-size=1280,720',
]);
// For file download handling
@@ -57,7 +56,7 @@
$options->setExperimentalOption('mobileEmulation', ['userAgent' => $ua]);
$options->addArguments(['--window-size=800,640']);
} else {
- $options->addArguments(['--window-size=1280,720']);
+ $options->addArguments(['--window-size=2560,1440']);
}
// Make sure downloads dir exists and is empty
@@ -85,4 +84,15 @@
{
return new Browser($driver);
}
+
+ /**
+ * Set baseURL to the admin UI location
+ */
+ protected static function useAdminUrl(): void
+ {
+ // This will set baseURL for all tests in this file
+ // If we wanted to visit both user and admin in one test
+ // we can also just call visit() with full url
+ Browser::$baseUrl = str_replace('//', '//admin.', \config('app.url'));
+ }
}

File Metadata

Mime Type
text/plain
Expires
Sat, Apr 4, 6:40 PM (19 h, 13 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18830779
Default Alt Text
D1123.1775328006.diff (29 KB)

Event Timeline