Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117902611
D1045.1775383562.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
35 KB
Referenced Files
None
Subscribers
None
D1045.1775383562.diff
View Options
diff --git a/src/app/Domain.php b/src/app/Domain.php
--- a/src/app/Domain.php
+++ b/src/app/Domain.php
@@ -91,11 +91,9 @@
*/
public static function getPublicDomains(): array
{
- $where = sprintf('(type & %s) AND (status & %s)', Domain::TYPE_PUBLIC, Domain::STATUS_ACTIVE);
+ $where = sprintf('(type & %s)', Domain::TYPE_PUBLIC);
- return self::whereRaw($where)->get(['namespace'])->map(function ($domain) {
- return $domain->namespace;
- })->toArray();
+ return self::whereRaw($where)->get(['namespace'])->pluck('namespace')->toArray();
}
/**
diff --git a/src/app/Http/Controllers/API/DomainsController.php b/src/app/Http/Controllers/API/DomainsController.php
--- a/src/app/Http/Controllers/API/DomainsController.php
+++ b/src/app/Http/Controllers/API/DomainsController.php
@@ -21,7 +21,9 @@
foreach ($user->domains() as $domain) {
if (!$domain->isPublic()) {
- $list[] = $domain->toArray();
+ $data = $domain->toArray();
+ $data = array_merge($data, self::domainStatuses($domain));
+ $list[] = $data;
}
}
@@ -60,6 +62,7 @@
return response()->json([
'status' => 'success',
+ 'statusInfo' => self::statusInfo($domain),
'message' => __('app.domain-verify-success'),
]);
}
@@ -127,7 +130,10 @@
$response['dns'] = self::getDNSConfig($domain);
$response['config'] = self::getMXConfig($domain->namespace);
- $response['confirmed'] = $domain->isConfirmed();
+ // Status info
+ $response['statusInfo'] = self::statusInfo($domain);
+
+ $response = array_merge($response, self::domainStatuses($domain));
return response()->json($response);
}
@@ -205,4 +211,69 @@
"@ 3600 TXT \"{$hash_txt}\"",
];
}
+
+ /**
+ * Prepare domain statuses for the UI
+ *
+ * @param \App\Domain $domain Domain object
+ *
+ * @return array Statuses array
+ */
+ protected static function domainStatuses(Domain $domain): array
+ {
+ return [
+ 'isLdapReady' => $domain->isLdapReady(),
+ 'isConfirmed' => $domain->isConfirmed(),
+ 'isVerified' => $domain->isVerified(),
+ 'isSuspended' => $domain->isSuspended(),
+ 'isActive' => $domain->isActive(),
+ 'isDeleted' => $domain->isDeleted() || $domain->trashed(),
+ ];
+ }
+
+ /**
+ * Domain status (extended) information.
+ *
+ * @param \App\Domain $domain Domain object
+ *
+ * @return array Status information
+ */
+ public static function statusInfo(Domain $domain): array
+ {
+ $process = [];
+
+ // If that is not a public domain, add domain specific steps
+ $steps = [
+ 'domain-new' => true,
+ 'domain-ldap-ready' => $domain->isLdapReady(),
+ 'domain-verified' => $domain->isVerified(),
+ 'domain-confirmed' => $domain->isConfirmed(),
+ ];
+
+ $count = count($steps);
+
+ // Create a process check list
+ foreach ($steps as $step_name => $state) {
+ $step = [
+ 'label' => $step_name,
+ 'title' => \trans("app.process-{$step_name}"),
+ 'state' => $state,
+ ];
+
+ if ($step_name == 'domain-confirmed' && !$state) {
+ $step['link'] = "/domain/{$domain->id}";
+ }
+
+ $process[] = $step;
+
+ if ($state) {
+ $count--;
+ }
+ }
+
+ return [
+ 'process' => $process,
+ 'isReady' => $count === 0,
+ ];
+ }
}
diff --git a/src/app/Http/Controllers/API/UsersController.php b/src/app/Http/Controllers/API/UsersController.php
--- a/src/app/Http/Controllers/API/UsersController.php
+++ b/src/app/Http/Controllers/API/UsersController.php
@@ -85,7 +85,11 @@
{
$user = $this->guard()->user();
- $result = $user->users()->orderBy('email')->get();
+ $result = $user->users()->orderBy('email')->get()->map(function ($user) {
+ $data = $user->toArray();
+ $data = array_merge($data, self::userStatuses($user));
+ return $data;
+ });
return response()->json($result);
}
@@ -220,53 +224,42 @@
*/
public static function statusInfo(User $user): array
{
- $status = 'new';
$process = [];
$steps = [
'user-new' => true,
- 'user-ldap-ready' => 'isLdapReady',
- 'user-imap-ready' => 'isImapReady',
+ 'user-ldap-ready' => $user->isLdapReady(),
+ 'user-imap-ready' => $user->isImapReady(),
];
- if ($user->isDeleted()) {
- $status = 'deleted';
- } elseif ($user->isSuspended()) {
- $status = 'suspended';
- } elseif ($user->isActive()) {
- $status = 'active';
+ // Create a process check list
+ foreach ($steps as $step_name => $state) {
+ $step = [
+ 'label' => $step_name,
+ 'title' => \trans("app.process-{$step_name}"),
+ 'state' => $state,
+ ];
+
+ $process[] = $step;
}
+
list ($local, $domain) = explode('@', $user->email);
$domain = Domain::where('namespace', $domain)->first();
// If that is not a public domain, add domain specific steps
if ($domain && !$domain->isPublic()) {
- $steps['domain-new'] = true;
- $steps['domain-ldap-ready'] = 'isLdapReady';
- $steps['domain-verified'] = 'isVerified';
- $steps['domain-confirmed'] = 'isConfirmed';
+ $domain_status = DomainsController::statusInfo($domain);
+ $process = array_merge($process, $domain_status['process']);
}
- // Create a process check list
- foreach ($steps as $step_name => $func) {
- $object = strpos($step_name, 'user-') === 0 ? $user : $domain;
-
- $step = [
- 'label' => $step_name,
- 'title' => __("app.process-{$step_name}"),
- 'state' => is_bool($func) ? $func : $object->{$func}(),
- ];
-
- if ($step_name == 'domain-confirmed' && !$step['state']) {
- $step['link'] = "/domain/{$domain->id}";
- }
-
- $process[] = $step;
- }
+ $all = count($process);
+ $checked = count(array_filter($process, function ($v) {
+ return $v['state'];
+ }));
return [
'process' => $process,
- 'status' => $status,
+ 'isReady' => $all === $checked,
];
}
@@ -480,6 +473,8 @@
// Status info
$response['statusInfo'] = self::statusInfo($user);
+ $response = array_merge($response, self::userStatuses($user));
+
// Information about wallets and accounts for access checks
$response['wallets'] = $user->wallets->toArray();
$response['accounts'] = $user->accounts->toArray();
@@ -489,6 +484,24 @@
}
/**
+ * Prepare user statuses for the UI
+ *
+ * @param \App\User $user User object
+ *
+ * @return array Statuses array
+ */
+ protected static function userStatuses(User $user): array
+ {
+ return [
+ 'isImapReady' => $user->isImapReady(),
+ 'isLdapReady' => $user->isLdapReady(),
+ 'isSuspended' => $user->isSuspended(),
+ 'isActive' => $user->isActive(),
+ 'isDeleted' => $user->isDeleted() || $user->trashed(),
+ ];
+ }
+
+ /**
* Validate user input
*
* @param \Illuminate\Http\Request $request The API request.
diff --git a/src/app/Observers/DomainObserver.php b/src/app/Observers/DomainObserver.php
--- a/src/app/Observers/DomainObserver.php
+++ b/src/app/Observers/DomainObserver.php
@@ -24,7 +24,7 @@
}
}
- $domain->status |= Domain::STATUS_NEW;
+ $domain->status |= Domain::STATUS_NEW | Domain::STATUS_ACTIVE;
}
/**
diff --git a/src/app/Observers/UserObserver.php b/src/app/Observers/UserObserver.php
--- a/src/app/Observers/UserObserver.php
+++ b/src/app/Observers/UserObserver.php
@@ -28,7 +28,7 @@
}
}
- $user->status |= User::STATUS_NEW;
+ $user->status |= User::STATUS_NEW | User::STATUS_ACTIVE;
// can't dispatch job here because it'll fail serialization
}
diff --git a/src/resources/js/app.js b/src/resources/js/app.js
--- a/src/resources/js/app.js
+++ b/src/resources/js/app.js
@@ -213,7 +213,9 @@
errorHandler(error) {
this.stopLoading()
- if (error.response.status === 401) {
+ if (!error.response) {
+ // TODO: probably network connection error
+ } else if (error.response.status === 401) {
this.logoutUser()
} else {
this.errorPage(error.response.status, error.response.statusText)
@@ -221,6 +223,66 @@
},
price(price) {
return (price/100).toLocaleString('de-DE', { style: 'currency', currency: 'CHF' })
+ },
+ domainStatusClass(domain) {
+ if (domain.isDeleted) {
+ return 'text-muted'
+ }
+
+ if (domain.isSuspended) {
+ return 'text-warning'
+ }
+
+ if (!domain.isVerified || !domain.isLdapReady || !domain.isConfirmed) {
+ return 'text-danger'
+ }
+
+ return 'text-success'
+ },
+ domainStatusText(domain) {
+ if (domain.isDeleted) {
+ return 'Deleted'
+ }
+
+ if (domain.isSuspended) {
+ return 'Suspended'
+ }
+
+ if (!domain.isVerified || !domain.isLdapReady || !domain.isConfirmed) {
+ return 'Not Ready'
+ }
+
+ return 'Active'
+ },
+ userStatusClass(user) {
+ if (user.isDeleted) {
+ return 'text-muted'
+ }
+
+ if (user.isSuspended) {
+ return 'text-warning'
+ }
+
+ if (!user.isImapReady || !user.isLdapReady) {
+ return 'text-danger'
+ }
+
+ return 'text-success'
+ },
+ userStatusText(user) {
+ if (user.isDeleted) {
+ return 'Deleted'
+ }
+
+ if (user.isSuspended) {
+ return 'Suspended'
+ }
+
+ if (!user.isImapReady || !user.isLdapReady) {
+ return 'Not Ready'
+ }
+
+ return 'Active'
}
}
})
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
@@ -1,9 +1,13 @@
import { library } from '@fortawesome/fontawesome-svg-core'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
-//import { } from '@fortawesome/free-regular-svg-icons'
//import { } from '@fortawesome/free-brands-svg-icons'
import {
+ faCheckSquare,
+ faSquare,
+} from '@fortawesome/free-regular-svg-icons'
+
+import {
faCheck,
faGlobe,
faInfoCircle,
@@ -17,6 +21,8 @@
// Register only these icons we need
library.add(
+ faCheckSquare,
+ faSquare,
faCheck,
faGlobe,
faInfoCircle,
diff --git a/src/resources/sass/app.scss b/src/resources/sass/app.scss
--- a/src/resources/sass/app.scss
+++ b/src/resources/sass/app.scss
@@ -139,6 +139,21 @@
}
}
+ul.status-list {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+
+ svg {
+ width: 1.25rem !important;
+ height: 1.25rem;
+ }
+
+ span {
+ vertical-align: top;
+ }
+}
+
#dashboard-nav {
display: flex;
flex-wrap: wrap;
diff --git a/src/resources/sass/menu.scss b/src/resources/sass/menu.scss
--- a/src/resources/sass/menu.scss
+++ b/src/resources/sass/menu.scss
@@ -5,6 +5,7 @@
.navbar-brand {
padding: 0;
+ outline: 0;
> img {
display: inline;
diff --git a/src/resources/vue/Dashboard.vue b/src/resources/vue/Dashboard.vue
--- a/src/resources/vue/Dashboard.vue
+++ b/src/resources/vue/Dashboard.vue
@@ -1,12 +1,16 @@
<template>
- <div class="container" dusk="dashboard-component">
- <div v-if="!$root.isLoading" id="status-box" class="card">
+ <div v-if="!$root.isLoading" class="container" dusk="dashboard-component">
+ <div v-if="!isReady" id="status-box" class="card">
<div class="card-body">
- <div class="card-title">Status</div>
+ <div class="card-title">Account status: <span class="text-danger">Not ready</span></div>
<div class="card-text">
- <ul style="list-style: none; padding: 0;">
+ <p>The process to create your account have not been completed yet.
+ Some features may be disabled or readonly.</p>
+ <ul class="status-list">
<li v-for="item in statusProcess" :key="item.label">
- <span v-if="item.state">✓</span><span v-else>○</span>
+ <svg-icon :icon="['far', item.state ? 'check-square' : 'square']"
+ :class="item.state ? 'text-success' : 'text-muted'"
+ ></svg-icon>
<router-link v-if="item.link" :to="{ path: item.link }">{{ item.title }}</router-link>
<span v-if="!item.link">{{ item.title }}</span>
</li>
@@ -36,6 +40,7 @@
export default {
data() {
return {
+ isReady: true,
statusProcess: [],
request: null,
balance: 0
@@ -44,8 +49,6 @@
mounted() {
const authInfo = this.$store.state.isLoggedIn ? this.$store.state.authInfo : null
- clearTimeout(window.infoRequest)
-
if (authInfo) {
this.parseStatusInfo(authInfo.statusInfo)
this.getBalance(authInfo)
@@ -65,12 +68,14 @@
// Displays account status information
parseStatusInfo(info) {
this.statusProcess = info.process
+ this.isReady = info.isReady
// Update status process info every 10 seconds
// FIXME: This probably should have some limit, or the interval
// should grow (well, until it could be done with websocket notifications)
- if (info.status != 'active') {
+ if (!info.isReady && !window.infoRequest) {
window.infoRequest = setTimeout(() => {
+ delete window.infoRequest
// Stop updates after user logged out
if (!this.$store.state.isLoggedIn) {
return;
diff --git a/src/resources/vue/Domain/Info.vue b/src/resources/vue/Domain/Info.vue
--- a/src/resources/vue/Domain/Info.vue
+++ b/src/resources/vue/Domain/Info.vue
@@ -1,6 +1,24 @@
<template>
<div class="container">
- <div v-if="domain && !is_confirmed" class="card" id="domain-verify">
+ <div v-if="!isReady" id="domain-status-box" class="card">
+ <div class="card-body">
+ <div class="card-title">Domain status: <span class="text-danger">Not ready</span></div>
+ <div class="card-text">
+ <p>The process to create the domain have not been completed yet.
+ Some features may be disabled or readonly.</p>
+ <ul class="status-list">
+ <li v-for="item in statusProcess" :key="item.label">
+ <svg-icon :icon="['far', item.state ? 'check-square' : 'square']"
+ :class="item.state ? 'text-success' : 'text-muted'"
+ ></svg-icon>
+ <router-link v-if="item.link" :to="{ path: item.link }">{{ item.title }}</router-link>
+ <span v-if="!item.link">{{ item.title }}</span>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <div v-if="domain && !domain.isConfirmed" class="card" id="domain-verify">
<div class="card-body">
<div class="card-title">Domain verification</div>
<div class="card-text">
@@ -17,7 +35,7 @@
</div>
</div>
</div>
- <div v-if="domain && is_confirmed" class="card" id="domain-config">
+ <div v-if="domain && domain.isConfirmed" class="card" id="domain-config">
<div class="card-body">
<div class="card-title">Domain configuration</div>
<div class="card-text">
@@ -40,35 +58,61 @@
return {
domain_id: null,
domain: null,
- is_confirmed: false,
- app_name: window.config['app.name']
+ app_name: window.config['app.name'],
+ isReady: true,
+ statusProcess: []
}
},
created() {
if (this.domain_id = this.$route.params.domain) {
axios.get('/api/v4/domains/' + this.domain_id)
.then(response => {
- this.is_confirmed = response.data.confirmed
this.domain = response.data
- if (!this.is_confirmed) {
+ if (!this.domain.isConfirmed) {
$('#domain-verify button').focus()
}
+ this.parseStatusInfo(response.data.statusInfo)
})
.catch(this.$root.errorHandler)
} else {
this.$root.errorPage(404)
}
},
+ destroyed() {
+ clearTimeout(window.domainRequest)
+ },
methods: {
confirm() {
axios.get('/api/v4/domains/' + this.domain_id + '/confirm')
.then(response => {
if (response.data.status == 'success') {
- this.is_confirmed = true
+ this.domain.isConfirmed = true
+ this.parseStatusInfo(response.data.statusInfo)
this.$toastr('success', response.data.message)
}
})
- }
+ },
+ // Displays domain status information
+ parseStatusInfo(info) {
+ this.statusProcess = info.process
+ this.isReady = info.isReady
+
+ // Update status process info every 10 seconds
+ // FIXME: This probably should have some limit, or the interval
+ // should grow (well, until it could be done with websocket notifications)
+ if (!info.isReady) {
+ window.domainRequest = setTimeout(() => {
+ axios.get('/api/v4/domains/' + this.domain_id)
+ .then(response => {
+ this.domain = response.data
+ this.parseStatusInfo(this.domain.statusInfo)
+ })
+ .catch(error => {
+ this.parseStatusInfo(info)
+ })
+ }, 10000);
+ }
+ },
}
}
</script>
diff --git a/src/resources/vue/Domain/List.vue b/src/resources/vue/Domain/List.vue
--- a/src/resources/vue/Domain/List.vue
+++ b/src/resources/vue/Domain/List.vue
@@ -13,7 +13,10 @@
</thead>
<tbody>
<tr v-for="domain in domains" :key="domain.id">
- <td><router-link :to="{ path: 'domain/' + domain.id }">{{ domain.namespace }}</router-link></td>
+ <td>
+ <svg-icon icon="globe" :class="$root.domainStatusClass(domain)" :title="$root.domainStatusText(domain)"></svg-icon>
+ <router-link :to="{ path: 'domain/' + domain.id }">{{ domain.namespace }}</router-link>
+ </td>
<td class="buttons"></td>
</tr>
</tbody>
diff --git a/src/resources/vue/User/Info.vue b/src/resources/vue/User/Info.vue
--- a/src/resources/vue/User/Info.vue
+++ b/src/resources/vue/User/Info.vue
@@ -6,6 +6,12 @@
<div class="card-title" v-if="user_id === 'new'">New user account</div>
<div class="card-text">
<form @submit.prevent="submit">
+ <div v-if="user_id !== 'new'" class="form-group row">
+ <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">
<label for="first_name" class="col-sm-4 col-form-label">First name</label>
<div class="col-sm-8">
diff --git a/src/resources/vue/User/List.vue b/src/resources/vue/User/List.vue
--- a/src/resources/vue/User/List.vue
+++ b/src/resources/vue/User/List.vue
@@ -19,6 +19,7 @@
<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 class="buttons">
diff --git a/src/tests/Browser/DomainTest.php b/src/tests/Browser/DomainTest.php
--- a/src/tests/Browser/DomainTest.php
+++ b/src/tests/Browser/DomainTest.php
@@ -59,6 +59,7 @@
$browser->visit('/domain/' . $domain->id)
->on(new DomainInfo())
+ // TODO: Test domain status box
->whenAvailable('@verify', function ($browser) use ($domain) {
// Make sure the domain is confirmed now
// TODO: Test verification process failure
@@ -118,6 +119,7 @@
->click('@links a.link-domains')
// On Domains List page click the domain entry
->on(new DomainList())
+ // TODO: Assert domain status icon
->assertSeeIn('@table tbody tr:first-child td:first-child', 'kolab.org')
->click('@table tbody tr:first-child td:first-child a')
// On Domain Info page verify that's the clicked domain
diff --git a/src/tests/Browser/Pages/DomainInfo.php b/src/tests/Browser/Pages/DomainInfo.php
--- a/src/tests/Browser/Pages/DomainInfo.php
+++ b/src/tests/Browser/Pages/DomainInfo.php
@@ -40,6 +40,7 @@
'@app' => '#app',
'@config' => '#domain-config',
'@verify' => '#domain-verify',
+ '@status' => '#domain-status-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
@@ -145,24 +145,26 @@
->assertSeeIn('#user-info .card-title', 'User account')
->with('@form', function (Browser $browser) {
// Assert form content
- $browser->assertFocused('div.row:nth-child(1) input')
- ->assertSeeIn('div.row:nth-child(1) label', 'First name')
- ->assertValue('div.row:nth-child(1) input[type=text]', $this->profile['first_name'])
- ->assertSeeIn('div.row:nth-child(2) label', 'Last name')
- ->assertValue('div.row:nth-child(2) input[type=text]', $this->profile['last_name'])
- ->assertSeeIn('div.row:nth-child(3) label', 'Email')
- ->assertValue('div.row:nth-child(3) input[type=text]', 'john@kolab.org')
- ->assertDisabled('div.row:nth-child(3) input[type=text]')
- ->assertSeeIn('div.row:nth-child(4) label', 'Email aliases')
- ->assertVisible('div.row:nth-child(4) .listinput-widget')
+ $browser->assertSeeIn('div.row:nth-child(1) label', 'Status')
+ ->assertSeeIn('div.row:nth-child(1) #status', 'Active')
+ ->assertFocused('div.row:nth-child(2) input')
+ ->assertSeeIn('div.row:nth-child(2) label', 'First name')
+ ->assertValue('div.row:nth-child(2) input[type=text]', $this->profile['first_name'])
+ ->assertSeeIn('div.row:nth-child(3) label', 'Last name')
+ ->assertValue('div.row:nth-child(3) input[type=text]', $this->profile['last_name'])
+ ->assertSeeIn('div.row:nth-child(4) label', 'Email')
+ ->assertValue('div.row:nth-child(4) input[type=text]', 'john@kolab.org')
+ ->assertDisabled('div.row:nth-child(4) input[type=text]')
+ ->assertSeeIn('div.row:nth-child(5) label', 'Email aliases')
+ ->assertVisible('div.row:nth-child(5) .listinput-widget')
->with(new ListInput('#aliases'), function (Browser $browser) {
$browser->assertListInputValue(['john.doe@kolab.org'])
->assertValue('@input', '');
})
- ->assertSeeIn('div.row:nth-child(5) label', 'Password')
- ->assertValue('div.row:nth-child(5) input[type=password]', '')
- ->assertSeeIn('div.row:nth-child(6) label', 'Confirm password')
+ ->assertSeeIn('div.row:nth-child(6) label', 'Password')
->assertValue('div.row:nth-child(6) input[type=password]', '')
+ ->assertSeeIn('div.row:nth-child(7) label', 'Confirm password')
+ ->assertValue('div.row:nth-child(7) input[type=password]', '')
->assertSeeIn('button[type=submit]', 'Submit');
// Clear some fields and submit
@@ -236,8 +238,8 @@
// Test subscriptions
$browser->with('@form', function (Browser $browser) {
- $browser->assertSeeIn('div.row:nth-child(7) label', 'Subscriptions')
- ->assertVisible('@skus.row:nth-child(7)')
+ $browser->assertSeeIn('div.row:nth-child(8) label', 'Subscriptions')
+ ->assertVisible('@skus.row:nth-child(8)')
->with('@skus', function ($browser) {
$browser->assertElementsCount('tbody tr', 4)
// groupware SKU
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
@@ -70,6 +70,7 @@
$this->assertEquals('success', $json['status']);
$this->assertEquals('Domain verified successfully.', $json['message']);
+ $this->assertTrue(is_array($json['statusInfo']));
// Not authorized access
$response = $this->actingAs($john)->get("api/v4/domains/{$domain->id}/confirm");
@@ -103,9 +104,15 @@
$response->assertStatus(200);
$json = $response->json();
-
$this->assertCount(1, $json);
$this->assertSame('kolab.org', $json[0]['namespace']);
+ // Values below are tested by Unit tests
+ $this->assertArrayHasKey('isConfirmed', $json[0]);
+ $this->assertArrayHasKey('isDeleted', $json[0]);
+ $this->assertArrayHasKey('isVerified', $json[0]);
+ $this->assertArrayHasKey('isSuspended', $json[0]);
+ $this->assertArrayHasKey('isActive', $json[0]);
+ $this->assertArrayHasKey('isLdapReady', $json[0]);
$response = $this->actingAs($ned)->get("api/v4/domains");
$response->assertStatus(200);
@@ -144,7 +151,6 @@
$this->assertEquals($domain->namespace, $json['namespace']);
$this->assertEquals($domain->status, $json['status']);
$this->assertEquals($domain->type, $json['type']);
- $this->assertTrue($json['confirmed'] === false);
$this->assertSame($domain->hash(Domain::HASH_TEXT), $json['hash_text']);
$this->assertSame($domain->hash(Domain::HASH_CNAME), $json['hash_cname']);
$this->assertSame($domain->hash(Domain::HASH_CODE), $json['hash_code']);
@@ -153,6 +159,14 @@
$this->assertCount(8, $json['dns']);
$this->assertTrue(strpos(implode("\n", $json['dns']), $domain->namespace) !== false);
$this->assertTrue(strpos(implode("\n", $json['dns']), $domain->hash()) !== false);
+ $this->assertTrue(is_array($json['statusInfo']));
+ // Values below are tested by Unit tests
+ $this->assertArrayHasKey('isConfirmed', $json);
+ $this->assertArrayHasKey('isDeleted', $json);
+ $this->assertArrayHasKey('isVerified', $json);
+ $this->assertArrayHasKey('isSuspended', $json);
+ $this->assertArrayHasKey('isActive', $json);
+ $this->assertArrayHasKey('isLdapReady', $json);
$john = $this->getTestUser('john@kolab.org');
$ned = $this->getTestUser('ned@kolab.org');
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
@@ -61,7 +61,7 @@
$this->assertEquals($user->id, $json['id']);
$this->assertEquals($user->email, $json['email']);
- $this->assertEquals(User::STATUS_NEW, $json['status']);
+ $this->assertEquals(User::STATUS_NEW | User::STATUS_ACTIVE, $json['status']);
$this->assertTrue(is_array($json['statusInfo']));
$this->assertTrue(is_array($json['settings']));
$this->assertTrue(is_array($json['aliases']));
@@ -202,6 +202,12 @@
$this->assertSame($jack->email, $json[0]['email']);
$this->assertSame($john->email, $json[1]['email']);
$this->assertSame($ned->email, $json[2]['email']);
+ // Values below are tested by Unit tests
+ $this->assertArrayHasKey('isDeleted', $json[0]);
+ $this->assertArrayHasKey('isSuspended', $json[0]);
+ $this->assertArrayHasKey('isActive', $json[0]);
+ $this->assertArrayHasKey('isLdapReady', $json[0]);
+ $this->assertArrayHasKey('isImapReady', $json[0]);
$response = $this->actingAs($ned)->get("/api/v4/users");
$response->assertStatus(200);
@@ -300,7 +306,7 @@
$result = UsersController::statusInfo($user);
- $this->assertSame('new', $result['status']);
+ $this->assertFalse($result['isReady']);
$this->assertCount(3, $result['process']);
$this->assertSame('user-new', $result['process'][0]['label']);
$this->assertSame(true, $result['process'][0]['state']);
@@ -314,7 +320,7 @@
$result = UsersController::statusInfo($user);
- $this->assertSame('new', $result['status']);
+ $this->assertTrue($result['isReady']);
$this->assertCount(3, $result['process']);
$this->assertSame('user-new', $result['process'][0]['label']);
$this->assertSame(true, $result['process'][0]['state']);
@@ -323,15 +329,13 @@
$this->assertSame('user-imap-ready', $result['process'][2]['label']);
$this->assertSame(true, $result['process'][2]['state']);
- $user->status |= User::STATUS_ACTIVE;
- $user->save();
$domain->status |= Domain::STATUS_VERIFIED;
$domain->type = Domain::TYPE_EXTERNAL;
$domain->save();
$result = UsersController::statusInfo($user);
- $this->assertSame('active', $result['status']);
+ $this->assertFalse($result['isReady']);
$this->assertCount(7, $result['process']);
$this->assertSame('user-new', $result['process'][0]['label']);
$this->assertSame(true, $result['process'][0]['state']);
@@ -347,13 +351,6 @@
$this->assertSame(true, $result['process'][5]['state']);
$this->assertSame('domain-confirmed', $result['process'][6]['label']);
$this->assertSame(false, $result['process'][6]['state']);
-
- $user->status |= User::STATUS_DELETED;
- $user->save();
-
- $result = UsersController::statusInfo($user);
-
- $this->assertSame('deleted', $result['status']);
}
/**
@@ -418,6 +415,12 @@
$this->assertTrue(is_array($json['settings']));
$this->assertTrue(is_array($json['aliases']));
$this->assertSame([], $json['skus']);
+ // Values below are tested by Unit tests
+ $this->assertArrayHasKey('isDeleted', $json);
+ $this->assertArrayHasKey('isSuspended', $json);
+ $this->assertArrayHasKey('isActive', $json);
+ $this->assertArrayHasKey('isLdapReady', $json);
+ $this->assertArrayHasKey('isImapReady', $json);
$john = $this->getTestUser('john@kolab.org');
$jack = $this->getTestUser('jack@kolab.org');
diff --git a/src/tests/Feature/DomainTest.php b/src/tests/Feature/DomainTest.php
--- a/src/tests/Feature/DomainTest.php
+++ b/src/tests/Feature/DomainTest.php
@@ -86,18 +86,17 @@
$domain = Domain::create([
'namespace' => 'public-active.com',
'status' => Domain::STATUS_NEW,
- 'type' => Domain::TYPE_PUBLIC,
+ 'type' => Domain::TYPE_EXTERNAL,
]);
- // Public but non-active domain should not be returned
+ // External domains should not be returned
$public_domains = Domain::getPublicDomains();
$this->assertNotContains('public-active.com', $public_domains);
$domain = Domain::where('namespace', 'public-active.com')->first();
- $domain->status = Domain::STATUS_ACTIVE;
+ $domain->type = Domain::TYPE_PUBLIC;
$domain->save();
- // Public and active domain should be returned
$public_domains = Domain::getPublicDomains();
$this->assertContains('public-active.com', $public_domains);
}
diff --git a/src/tests/Unit/Controller/DomainsTest.php b/src/tests/Unit/Controller/DomainsTest.php
new file mode 100644
--- /dev/null
+++ b/src/tests/Unit/Controller/DomainsTest.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace Tests\Unit\Controller;
+
+use App\Domain;
+use Tests\TestCase;
+
+class DomainsTest extends TestCase
+{
+ /**
+ * Test DomainsController::domainStatuses()
+ */
+ public function testDomainStatuses(): void
+ {
+ $this->markTestIncomplete();
+ }
+
+ /**
+ * Test DomainsController::statusInfo()
+ */
+ public function testStatusInfo(): void
+ {
+ $this->markTestIncomplete();
+ }
+}
diff --git a/src/tests/Unit/Controller/UsersTest.php b/src/tests/Unit/Controller/UsersTest.php
new file mode 100644
--- /dev/null
+++ b/src/tests/Unit/Controller/UsersTest.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace Tests\Unit\Controller;
+
+use App\User;
+use Tests\TestCase;
+
+class UsersTest extends TestCase
+{
+ /**
+ * Test UsersController::userStatuses()
+ */
+ public function testUserStatuses(): void
+ {
+ $this->markTestIncomplete();
+ }
+
+ /**
+ * Test UsersController::statusInfo()
+ */
+ public function testStatusInfo(): void
+ {
+ $this->markTestIncomplete();
+ }
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Apr 5, 10:06 AM (7 h, 27 m ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18829743
Default Alt Text
D1045.1775383562.diff (35 KB)
Attached To
Mode
D1045: Display user/domain status in UI, add Active status
Attached
Detach File
Event Timeline