diff --git a/bin/phpunit-fast b/bin/phpunit-fast
--- a/bin/phpunit-fast
+++ b/bin/phpunit-fast
@@ -5,6 +5,7 @@
pushd ${cwd}/../src/
php vendor/bin/phpunit \
+ --no-coverage \
--stop-on-defect \
--stop-on-error \
--stop-on-failure $*
diff --git a/src/app/Http/Controllers/API/V4/Admin/DomainsController.php b/src/app/Http/Controllers/API/V4/Admin/DomainsController.php
--- a/src/app/Http/Controllers/API/V4/Admin/DomainsController.php
+++ b/src/app/Http/Controllers/API/V4/Admin/DomainsController.php
@@ -4,6 +4,7 @@
use App\Domain;
use App\User;
+use Illuminate\Http\Request;
class DomainsController extends \App\Http\Controllers\API\V4\DomainsController
{
@@ -52,4 +53,52 @@
return response()->json($result);
}
+
+ /**
+ * Suspend the domain
+ *
+ * @param \Illuminate\Http\Request $request The API request.
+ * @params string $id Domain identifier
+ *
+ * @return \Illuminate\Http\JsonResponse The response
+ */
+ public function suspend(Request $request, $id)
+ {
+ $domain = Domain::find($id);
+
+ if (empty($domain) || $domain->isPublic()) {
+ return $this->errorResponse(404);
+ }
+
+ $domain->suspend();
+
+ return response()->json([
+ 'status' => 'success',
+ 'message' => __('app.domain-suspend-success'),
+ ]);
+ }
+
+ /**
+ * Un-Suspend the domain
+ *
+ * @param \Illuminate\Http\Request $request The API request.
+ * @params string $id Domain identifier
+ *
+ * @return \Illuminate\Http\JsonResponse The response
+ */
+ public function unsuspend(Request $request, $id)
+ {
+ $domain = Domain::find($id);
+
+ if (empty($domain) || $domain->isPublic()) {
+ return $this->errorResponse(404);
+ }
+
+ $domain->unsuspend();
+
+ return response()->json([
+ 'status' => 'success',
+ 'message' => __('app.domain-unsuspend-success'),
+ ]);
+ }
}
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
@@ -31,6 +31,8 @@
'domain-verify-success' => 'Domain verified successfully.',
'domain-verify-error' => 'Domain ownership verification failed.',
+ 'domain-suspend-success' => 'Domain suspended successfully.',
+ 'domain-unsuspend-success' => 'Domain unsuspended successfully.',
'user-update-success' => 'User data updated successfully.',
'user-create-success' => 'User created successfully.',
diff --git a/src/resources/vue/Admin/Domain.vue b/src/resources/vue/Admin/Domain.vue
--- a/src/resources/vue/Admin/Domain.vue
+++ b/src/resources/vue/Admin/Domain.vue
@@ -22,6 +22,10 @@
+
+
+
+
@@ -64,6 +68,24 @@
.catch(this.$root.errorHandler)
},
methods: {
+ suspendDomain() {
+ axios.post('/api/v4/domains/' + this.domain.id + '/suspend', {})
+ .then(response => {
+ if (response.data.status == 'success') {
+ this.$toast.success(response.data.message)
+ this.domain = Object.assign({}, this.domain, { isSuspended: true })
+ }
+ })
+ },
+ unsuspendDomain() {
+ axios.post('/api/v4/domains/' + this.domain.id + '/unsuspend', {})
+ .then(response => {
+ if (response.data.status == 'success') {
+ this.$toast.success(response.data.message)
+ this.domain = Object.assign({}, this.domain, { isSuspended: false })
+ }
+ })
+ }
}
}
diff --git a/src/routes/api.php b/src/routes/api.php
--- a/src/routes/api.php
+++ b/src/routes/api.php
@@ -101,6 +101,8 @@
function () {
Route::apiResource('domains', API\V4\Admin\DomainsController::class);
Route::get('domains/{id}/confirm', 'API\V4\Admin\DomainsController@confirm');
+ Route::post('domains/{id}/suspend', 'API\V4\Admin\DomainsController@suspend');
+ Route::post('domains/{id}/unsuspend', 'API\V4\Admin\DomainsController@unsuspend');
Route::apiResource('entitlements', API\V4\Admin\EntitlementsController::class);
Route::apiResource('packages', API\V4\Admin\PackagesController::class);
diff --git a/src/tests/Browser/Admin/DomainTest.php b/src/tests/Browser/Admin/DomainTest.php
--- a/src/tests/Browser/Admin/DomainTest.php
+++ b/src/tests/Browser/Admin/DomainTest.php
@@ -2,7 +2,7 @@
namespace Tests\Browser\Admin;
-use App\Discount;
+use App\Domain;
use Tests\Browser;
use Tests\Browser\Components\Toast;
use Tests\Browser\Pages\Admin\Domain as DomainPage;
@@ -86,4 +86,34 @@
});
});
}
+
+ /**
+ * Test suspending/unsuspending a domain
+ *
+ * @depends testDomainInfo
+ */
+ public function testSuspendAndUnsuspend(): void
+ {
+ $this->browse(function (Browser $browser) {
+ $domain = $this->getTestDomain('domainscontroller.com', [
+ 'status' => Domain::STATUS_NEW | Domain::STATUS_ACTIVE
+ | Domain::STATUS_LDAP_READY | Domain::STATUS_CONFIRMED
+ | Domain::STATUS_VERIFIED,
+ 'type' => Domain::TYPE_EXTERNAL,
+ ]);
+
+ $browser->visit(new DomainPage($domain->id))
+ ->assertVisible('@domain-info #button-suspend')
+ ->assertMissing('@domain-info #button-unsuspend')
+ ->click('@domain-info #button-suspend')
+ ->assertToast(Toast::TYPE_SUCCESS, 'Domain suspended successfully.')
+ ->assertSeeIn('@domain-info #status span.text-warning', 'Suspended')
+ ->assertMissing('@domain-info #button-suspend')
+ ->click('@domain-info #button-unsuspend')
+ ->assertToast(Toast::TYPE_SUCCESS, 'Domain unsuspended successfully.')
+ ->assertSeeIn('@domain-info #status span.text-success', 'Active')
+ ->assertVisible('@domain-info #button-suspend')
+ ->assertMissing('@domain-info #button-unsuspend');
+ });
+ }
}
diff --git a/src/tests/Feature/Controller/Admin/DomainsTest.php b/src/tests/Feature/Controller/Admin/DomainsTest.php
--- a/src/tests/Feature/Controller/Admin/DomainsTest.php
+++ b/src/tests/Feature/Controller/Admin/DomainsTest.php
@@ -2,6 +2,8 @@
namespace Tests\Feature\Controller\Admin;
+use App\Domain;
+use Illuminate\Support\Facades\Queue;
use Tests\TestCase;
class DomainsTest extends TestCase
@@ -13,6 +15,8 @@
{
parent::setUp();
self::useAdminUrl();
+
+ $this->deleteTestDomain('domainscontroller.com');
}
/**
@@ -20,6 +24,8 @@
*/
public function tearDown(): void
{
+ $this->deleteTestDomain('domainscontroller.com');
+
parent::tearDown();
}
@@ -84,4 +90,70 @@
$this->assertSame(0, $json['count']);
$this->assertCount(0, $json['list']);
}
+
+ /**
+ * Test domain suspending (POST /api/v4/domains//suspend)
+ */
+ public function testSuspend(): void
+ {
+ Queue::fake(); // disable jobs
+
+ $domain = $this->getTestDomain('domainscontroller.com', [
+ 'status' => Domain::STATUS_NEW,
+ 'type' => Domain::TYPE_EXTERNAL,
+ ]);
+ $user = $this->getTestUser('test@domainscontroller.com');
+ $admin = $this->getTestUser('jeroen@jeroen.jeroen');
+
+ // Test unauthorized access to admin API
+ $response = $this->actingAs($user)->post("/api/v4/domains/{$domain->id}/suspend", []);
+ $response->assertStatus(403);
+
+ $this->assertFalse($domain->fresh()->isSuspended());
+
+ // Test suspending the user
+ $response = $this->actingAs($admin)->post("/api/v4/domains/{$domain->id}/suspend", []);
+ $response->assertStatus(200);
+
+ $json = $response->json();
+
+ $this->assertSame('success', $json['status']);
+ $this->assertSame("Domain suspended successfully.", $json['message']);
+ $this->assertCount(2, $json);
+
+ $this->assertTrue($domain->fresh()->isSuspended());
+ }
+
+ /**
+ * Test user un-suspending (POST /api/v4/users//unsuspend)
+ */
+ public function testUnsuspend(): void
+ {
+ Queue::fake(); // disable jobs
+
+ $domain = $this->getTestDomain('domainscontroller.com', [
+ 'status' => Domain::STATUS_NEW | Domain::STATUS_SUSPENDED,
+ 'type' => Domain::TYPE_EXTERNAL,
+ ]);
+ $user = $this->getTestUser('test@domainscontroller.com');
+ $admin = $this->getTestUser('jeroen@jeroen.jeroen');
+
+ // Test unauthorized access to admin API
+ $response = $this->actingAs($user)->post("/api/v4/domains/{$domain->id}/unsuspend", []);
+ $response->assertStatus(403);
+
+ $this->assertTrue($domain->fresh()->isSuspended());
+
+ // Test suspending the user
+ $response = $this->actingAs($admin)->post("/api/v4/domains/{$domain->id}/unsuspend", []);
+ $response->assertStatus(200);
+
+ $json = $response->json();
+
+ $this->assertSame('success', $json['status']);
+ $this->assertSame("Domain unsuspended successfully.", $json['message']);
+ $this->assertCount(2, $json);
+
+ $this->assertFalse($domain->fresh()->isSuspended());
+ }
}