Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117819997
D1273.1775293968.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
10 KB
Referenced Files
None
Subscribers
None
D1273.1775293968.diff
View Options
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
@@ -68,6 +68,54 @@
return response()->json($result);
}
+ /**
+ * Suspend the user
+ *
+ * @param \Illuminate\Http\Request $request The API request.
+ * @params string $id User identifier
+ *
+ * @return \Illuminate\Http\JsonResponse The response
+ */
+ public function suspend(Request $request, $id)
+ {
+ $user = User::find($id);
+
+ if (empty($user)) {
+ return $this->errorResponse(404);
+ }
+
+ $user->suspend();
+
+ return response()->json([
+ 'status' => 'success',
+ 'message' => __('app.user-suspend-success'),
+ ]);
+ }
+
+ /**
+ * Un-Suspend the user
+ *
+ * @param \Illuminate\Http\Request $request The API request.
+ * @params string $id User identifier
+ *
+ * @return \Illuminate\Http\JsonResponse The response
+ */
+ public function unsuspend(Request $request, $id)
+ {
+ $user = User::find($id);
+
+ if (empty($user)) {
+ return $this->errorResponse(404);
+ }
+
+ $user->unsuspend();
+
+ return response()->json([
+ 'status' => 'success',
+ 'message' => __('app.user-unsuspend-success'),
+ ]);
+ }
+
/**
* Update user data.
*
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
@@ -28,9 +28,12 @@
'domain-verify-success' => 'Domain verified successfully.',
'domain-verify-error' => 'Domain ownership verification failed.',
+
'user-update-success' => 'User data updated successfully.',
'user-create-success' => 'User created successfully.',
'user-delete-success' => 'User deleted successfully.',
+ 'user-suspend-success' => 'User suspended successfully.',
+ 'user-unsuspend-success' => 'User unsuspended successfully.',
'search-foundxdomains' => ':x domains have been found.',
'search-foundxusers' => ':x user accounts have been found.',
diff --git a/src/resources/sass/_variables.scss b/src/resources/sass/_variables.scss
--- a/src/resources/sass/_variables.scss
+++ b/src/resources/sass/_variables.scss
@@ -12,12 +12,14 @@
$purple: #9561e2;
$pink: #f66d9b;
$red: #e3342f;
-$orange: #f6993f;
+$orange: #f1a539;
$yellow: #ffed4a;
$green: #38c172;
$teal: #4dc0b5;
$cyan: #6cb2eb;
+$warning: $orange;
+
// App colors
$menu-bg-color: #f6f5f3;
-$main-color: #f1a539;
+$main-color: $orange;
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
@@ -74,6 +74,8 @@
<span class="form-control-plaintext" id="country">{{ user.country }}</span>
</div>
</div>
+ <button v-if="!user.isSuspended" id="button-suspend" class="btn btn-warning" type="button" @click="suspendUser">Suspend</button>
+ <button v-if="user.isSuspended" id="button-unsuspend" class="btn btn-warning" type="button" @click="unsuspendUser">Unsuspend</button>
</form>
</div>
</div>
@@ -450,6 +452,24 @@
this.external_email = null // required because of Vue
}
})
+ },
+ suspendUser() {
+ axios.post('/api/v4/users/' + this.user.id + '/suspend', {})
+ .then(response => {
+ if (response.data.status == 'success') {
+ this.$toast.success(response.data.message)
+ this.user = Object.assign({}, this.user, { isSuspended: true })
+ }
+ })
+ },
+ unsuspendUser() {
+ axios.post('/api/v4/users/' + this.user.id + '/unsuspend', {})
+ .then(response => {
+ if (response.data.status == 'success') {
+ this.$toast.success(response.data.message)
+ this.user = Object.assign({}, this.user, { isSuspended: false })
+ }
+ })
}
}
}
diff --git a/src/routes/api.php b/src/routes/api.php
--- a/src/routes/api.php
+++ b/src/routes/api.php
@@ -96,6 +96,8 @@
Route::apiResource('packages', API\V4\Admin\PackagesController::class);
Route::apiResource('skus', API\V4\Admin\SkusController::class);
Route::apiResource('users', API\V4\Admin\UsersController::class);
+ Route::post('users/{id}/suspend', 'API\V4\Admin\UsersController@suspend');
+ Route::post('users/{id}/unsuspend', 'API\V4\Admin\UsersController@unsuspend');
Route::apiResource('wallets', API\V4\Admin\WalletsController::class);
Route::apiResource('discounts', API\V4\Admin\DiscountsController::class);
}
diff --git a/src/tests/Browser/Admin/UserTest.php b/src/tests/Browser/Admin/UserTest.php
--- a/src/tests/Browser/Admin/UserTest.php
+++ b/src/tests/Browser/Admin/UserTest.php
@@ -3,6 +3,7 @@
namespace Tests\Browser\Admin;
use App\Discount;
+use App\User;
use Tests\Browser;
use Tests\Browser\Components\Dialog;
use Tests\Browser\Components\Toast;
@@ -23,6 +24,7 @@
self::useAdminUrl();
$john = $this->getTestUser('john@kolab.org');
+ $john->update(['status' => $john->status ^= User::STATUS_SUSPENDED]);
$john->setSettings([
'phone' => '+48123123123',
'external_email' => 'john.doe.external@gmail.com',
@@ -40,6 +42,7 @@
public function tearDown(): void
{
$john = $this->getTestUser('john@kolab.org');
+ $john->update(['status' => $john->status ^= User::STATUS_SUSPENDED]);
$john->setSettings([
'phone' => null,
'external_email' => 'john.doe.external@gmail.com',
@@ -400,6 +403,29 @@
});
}
+ /**
+ * Test suspending/unsuspending the user
+ */
+ public function testSuspendAndUnsuspend(): void
+ {
+ $this->browse(function (Browser $browser) {
+ $john = $this->getTestUser('john@kolab.org');
+
+ $browser->visit(new UserPage($john->id))
+ ->assertVisible('@user-info #button-suspend')
+ ->assertMissing('@user-info #button-unsuspend')
+ ->click('@user-info #button-suspend')
+ ->assertToast(Toast::TYPE_SUCCESS, 'User suspended successfully.')
+ ->assertSeeIn('@user-info #status span.text-warning', 'Suspended')
+ ->assertMissing('@user-info #button-suspend')
+ ->click('@user-info #button-unsuspend')
+ ->assertToast(Toast::TYPE_SUCCESS, 'User unsuspended successfully.')
+ ->assertSeeIn('@user-info #status span.text-success', 'Active')
+ ->assertVisible('@user-info #button-suspend')
+ ->assertMissing('@user-info #button-unsuspend');
+ });
+ }
+
/**
* Test editing wallet discount
*
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,6 +2,7 @@
namespace Tests\Feature\Controller\Admin;
+use Illuminate\Support\Facades\Queue;
use Tests\TestCase;
class UsersTest extends TestCase
@@ -14,6 +15,8 @@
parent::setUp();
self::useAdminUrl();
+ $this->deleteTestUser('UsersControllerTest1@userscontroller.com');
+
$jack = $this->getTestUser('jack@kolab.org');
$jack->setSetting('external_email', null);
}
@@ -23,6 +26,8 @@
*/
public function tearDown(): void
{
+ $this->deleteTestUser('UsersControllerTest1@userscontroller.com');
+
$jack = $this->getTestUser('jack@kolab.org');
$jack->setSetting('external_email', null);
@@ -141,6 +146,66 @@
$this->assertCount(0, $json['list']);
}
+ /**
+ * Test user suspending (POST /api/v4/users/<user-id>/suspend)
+ */
+ public function testSuspend(): void
+ {
+ Queue::fake(); // disable jobs
+
+ $user = $this->getTestUser('UsersControllerTest1@userscontroller.com');
+ $admin = $this->getTestUser('jeroen@jeroen.jeroen');
+
+ // Test unauthorized access to admin API
+ $response = $this->actingAs($user)->post("/api/v4/users/{$user->id}/suspend", []);
+ $response->assertStatus(403);
+
+ $this->assertFalse($user->isSuspended());
+
+ // Test suspending the user
+ $response = $this->actingAs($admin)->post("/api/v4/users/{$user->id}/suspend", []);
+ $response->assertStatus(200);
+
+ $json = $response->json();
+
+ $this->assertSame('success', $json['status']);
+ $this->assertSame("User suspended successfully.", $json['message']);
+ $this->assertCount(2, $json);
+
+ $this->assertTrue($user->fresh()->isSuspended());
+ }
+
+ /**
+ * Test user un-suspending (POST /api/v4/users/<user-id>/unsuspend)
+ */
+ public function testUnsuspend(): void
+ {
+ Queue::fake(); // disable jobs
+
+ $user = $this->getTestUser('UsersControllerTest1@userscontroller.com');
+ $admin = $this->getTestUser('jeroen@jeroen.jeroen');
+
+ // Test unauthorized access to admin API
+ $response = $this->actingAs($user)->post("/api/v4/users/{$user->id}/unsuspend", []);
+ $response->assertStatus(403);
+
+ $this->assertFalse($user->isSuspended());
+ $user->suspend();
+ $this->assertTrue($user->isSuspended());
+
+ // Test suspending the user
+ $response = $this->actingAs($admin)->post("/api/v4/users/{$user->id}/unsuspend", []);
+ $response->assertStatus(200);
+
+ $json = $response->json();
+
+ $this->assertSame('success', $json['status']);
+ $this->assertSame("User unsuspended successfully.", $json['message']);
+ $this->assertCount(2, $json);
+
+ $this->assertFalse($user->fresh()->isSuspended());
+ }
+
/**
* Test user update (PUT /api/v4/users/<user-id>)
*/
@@ -150,7 +215,7 @@
$admin = $this->getTestUser('jeroen@jeroen.jeroen');
// Test unauthorized access to admin API
- $response = $this->actingAs($user)->get("/api/v4/users/{$user->id}", []);
+ $response = $this->actingAs($user)->put("/api/v4/users/{$user->id}", []);
$response->assertStatus(403);
// Test updatig the user data (empty data)
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Apr 4, 9:12 AM (3 h, 34 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18828754
Default Alt Text
D1273.1775293968.diff (10 KB)
Attached To
Mode
D1273: Support: Unsuspending/Suspending a user (Bifrost#T315890)
Attached
Detach File
Event Timeline