feat: implement barangay system phases 2-14
Complete adaptation from BukidBountyApp to Philippine barangay governance: - Barangay models: Resident, Household, HouseholdMember, Blotter, BlotterHearing, DocumentRequest, RequestPayment, RequestType, BarangayProject, BarangayBudget - Controllers: ResidentController, HouseholdController, BlotterController, BlotterHearingController, DocumentRequestController, RequestTypeController, ProjectController, BudgetController, QRPHController, AdminConsoleController, UserController, FileController, ChapterController, LoginController - Vue pages: Home, ManageResidents, ResidentProfile, ManageHouseholds, ManageBlotters, BlotterDetail, RequestDocument, ManageDocumentRequests, DocumentRequestDetail, ManageRequestTypes, ManageProjects, BudgetLedger, AdminConsole - Barangay roles: PunongBarangay, Kagawad, Secretary, Treasurer, SK, Tanod, BHW, Staff, Resident - UserPermissions matrix rewritten with barangay-specific permission mappings - VueRouteMap replaced with barangay SPA routes - UserActions enum references corrected across all controllers - Removed all market/cooperative/POS/subscription code and models
This commit is contained in:
162
app/Http/Controllers/Admin/AdminConsoleController.php
Normal file
162
app/Http/Controllers/Admin/AdminConsoleController.php
Normal file
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Enums\UserActions;
|
||||
use App\Enums\UserTypes;
|
||||
use App\Http\Controllers\Helpers\Permissions\UserPermissions;
|
||||
use App\Http\Controllers\Helpers\ResponseHelper;
|
||||
use App\Models\User;
|
||||
use App\Models\DbBackup;
|
||||
use Hyperf\Stringable\Str;
|
||||
use Hypervel\Http\Request;
|
||||
use Hypervel\Support\Facades\Auth;
|
||||
use Hypervel\Support\Facades\DB;
|
||||
use Hypervel\Support\Facades\Redis;
|
||||
use Hypervel\Support\Facades\Response;
|
||||
|
||||
class AdminConsoleController
|
||||
{
|
||||
private function checkAccess(): bool
|
||||
{
|
||||
if (!Auth::check()) return false;
|
||||
return UserPermissions::isActionPermitted(Auth::user()->acct_type, UserActions::UltimateConsole);
|
||||
}
|
||||
|
||||
public function getSystemStats()
|
||||
{
|
||||
if (!$this->checkAccess()) return ResponseHelper::returnUnauthorized();
|
||||
|
||||
$globalMessage = Redis::get('system:global_message');
|
||||
$redisStatus = ['connected' => false, 'ping_ms' => null, 'used_memory_human' => null, 'version' => null, 'error' => null];
|
||||
|
||||
try {
|
||||
$start = microtime(true);
|
||||
$pong = Redis::ping();
|
||||
$redisStatus['ping_ms'] = round((microtime(true) - $start) * 1000, 2);
|
||||
$redisStatus['connected'] = in_array($pong, [true, 'PONG', '+PONG'], true) || (is_string($pong) && stripos($pong, 'PONG') !== false);
|
||||
$info = Redis::info();
|
||||
if (is_array($info)) {
|
||||
$flat = isset($info['Memory']) ? $info['Memory'] : $info;
|
||||
$redisStatus['used_memory_human'] = $flat['used_memory_human'] ?? null;
|
||||
$serverInfo = isset($info['Server']) ? $info['Server'] : $info;
|
||||
$redisStatus['version'] = $serverInfo['redis_version'] ?? null;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$redisStatus['error'] = $e->getMessage();
|
||||
}
|
||||
|
||||
$stats = [
|
||||
'users' => User::count(),
|
||||
'active_users' => User::where('active', true)->count(),
|
||||
'residents' => DB::table('barangay_residents')->count(),
|
||||
'households' => DB::table('barangay_households')->count(),
|
||||
'blotters' => DB::table('barangay_blotters')->count(),
|
||||
'document_requests' => DB::table('barangay_document_requests')->count(),
|
||||
'projects' => DB::table('barangay_projects')->count(),
|
||||
'announcements' => DB::table('announcements')->count(),
|
||||
'php_version' => PHP_VERSION,
|
||||
'server_time' => date('Y-m-d H:i:s'),
|
||||
'maintenance_mode' => Redis::get('system:maintenance_mode') === 'true',
|
||||
'global_message' => $globalMessage ? json_decode($globalMessage, true) : null,
|
||||
'logs_count' => DB::table('logs')->count(),
|
||||
'table_logs_count' => DB::table('table_logs')->count(),
|
||||
'redis' => $redisStatus,
|
||||
];
|
||||
|
||||
return Response::json(['success' => true, 'data' => $stats]);
|
||||
}
|
||||
|
||||
public function runQuery(Request $request)
|
||||
{
|
||||
if (Auth::user()->acct_type !== UserTypes::SUPER_ADMIN || !UserPermissions::isActionPermitted(Auth::user()->acct_type, UserActions::UltimateQuery)) {
|
||||
return ResponseHelper::returnUnauthorized();
|
||||
}
|
||||
|
||||
$query = $request->input('query');
|
||||
if (empty($query)) return ResponseHelper::returnError('Query cannot be empty');
|
||||
|
||||
$lower = strtolower(trim($query));
|
||||
$allowed = str_starts_with($lower, 'select') || str_starts_with($lower, 'show') || str_starts_with($lower, 'describe') || str_starts_with($lower, 'explain');
|
||||
if (!$allowed) {
|
||||
return ResponseHelper::returnError('Only SELECT, SHOW, DESCRIBE, EXPLAIN queries are allowed');
|
||||
}
|
||||
|
||||
try {
|
||||
$results = DB::select($query);
|
||||
return Response::json(['success' => true, 'data' => $results, 'count' => count($results)]);
|
||||
} catch (\Throwable $e) {
|
||||
return ResponseHelper::returnError('Query error: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function setMaintenanceMode(Request $request)
|
||||
{
|
||||
if (!$this->checkAccess()) return ResponseHelper::returnUnauthorized();
|
||||
$enabled = (bool) $request->input('enabled', false);
|
||||
Redis::set('system:maintenance_mode', $enabled ? 'true' : 'false');
|
||||
return Response::json(['success' => true, 'maintenance_mode' => $enabled]);
|
||||
}
|
||||
|
||||
public function setGlobalMessage(Request $request)
|
||||
{
|
||||
if (!$this->checkAccess()) return ResponseHelper::returnUnauthorized();
|
||||
$message = $request->input('message');
|
||||
if ($message) {
|
||||
Redis::set('system:global_message', json_encode([
|
||||
'text' => $message,
|
||||
'type' => $request->input('type', 'info'),
|
||||
'updated_at' => now()->toDateTimeString(),
|
||||
]));
|
||||
} else {
|
||||
Redis::del('system:global_message');
|
||||
}
|
||||
return Response::json(['success' => true]);
|
||||
}
|
||||
|
||||
public function clearCache(Request $request)
|
||||
{
|
||||
if (!$this->checkAccess()) return ResponseHelper::returnUnauthorized();
|
||||
Redis::flushDB();
|
||||
return Response::json(['success' => true, 'message' => 'Cache cleared']);
|
||||
}
|
||||
|
||||
public function getLogs(Request $request)
|
||||
{
|
||||
if (!$this->checkAccess()) return ResponseHelper::returnUnauthorized();
|
||||
$limit = min((int) $request->input('limit', 50), 200);
|
||||
$logs = DB::table('logs')->orderByDesc('id')->limit($limit)->get();
|
||||
return Response::json(['success' => true, 'data' => $logs]);
|
||||
}
|
||||
|
||||
public function getTableLogs(Request $request)
|
||||
{
|
||||
if (!$this->checkAccess()) return ResponseHelper::returnUnauthorized();
|
||||
$limit = min((int) $request->input('limit', 50), 200);
|
||||
$logs = DB::table('table_logs')->orderByDesc('id')->limit($limit)->get();
|
||||
return Response::json(['success' => true, 'data' => $logs]);
|
||||
}
|
||||
|
||||
public function backupDatabase(Request $request)
|
||||
{
|
||||
if (!$this->checkAccess()) return ResponseHelper::returnUnauthorized();
|
||||
|
||||
$name = $request->input('name', 'backup_' . date('Y_m_d_His'));
|
||||
$backup = DbBackup::create([
|
||||
'name' => $name,
|
||||
'status' => 'pending',
|
||||
'created_by' => Auth::id(),
|
||||
]);
|
||||
|
||||
return Response::json(['success' => true, 'data' => $backup, 'message' => 'Backup queued']);
|
||||
}
|
||||
|
||||
public function listBackups()
|
||||
{
|
||||
if (!$this->checkAccess()) return ResponseHelper::returnUnauthorized();
|
||||
$backups = DbBackup::orderByDesc('id')->limit(20)->get();
|
||||
return Response::json(['success' => true, 'data' => $backups]);
|
||||
}
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Helpers\ResponseHelper;
|
||||
use App\Models\Market\PosAccessKey;
|
||||
use App\Models\Market\Store;
|
||||
use App\Models\User;
|
||||
use Hypervel\Http\Request;
|
||||
use Hypervel\Support\Facades\Auth;
|
||||
use Hyperf\Stringable\Str;
|
||||
use App\Http\Controllers\Helpers\Permissions\UserPermissions;
|
||||
use App\Enums\UserActions;
|
||||
|
||||
class PosAccessKeyController
|
||||
{
|
||||
/**
|
||||
* List POS access keys. Auto-expires any past-due keys first.
|
||||
* - Ultimate/super operator/operator: see all keys
|
||||
* - Store owner/manager: see keys for stores they own or manage
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
if (!UserPermissions::isActionPermitted(Auth::user()->acct_type, UserActions::ViewPosAccessKeys)) {
|
||||
return ResponseHelper::returnUnauthorized();
|
||||
}
|
||||
|
||||
// Auto-deactivate any expired keys
|
||||
PosAccessKey::autoExpire();
|
||||
|
||||
$user = Auth::user();
|
||||
$acctType = $user->acct_type->value ?? $user->acct_type ?? '';
|
||||
|
||||
// Ultimate, Super Operator, and Operator see everything
|
||||
if (in_array($acctType, ['ult', 'super operator', 'operator'])) {
|
||||
$query = PosAccessKey::with(['store:id,name,hashkey,owner_id', 'store.owner:id,name,nickname,hashkey'])
|
||||
->orderBy('id', 'desc');
|
||||
} else {
|
||||
// Non-ultimate users see their own and their descendants' stores' keys
|
||||
$descendants = $user->getAllDescendants();
|
||||
$descendantIds = $descendants->pluck('id')->push($user->id)->toArray();
|
||||
|
||||
$storeIds = Store::whereIn('owner_id', $descendantIds)
|
||||
->orWhereIn('manager_id', $descendantIds)
|
||||
->pluck('id')
|
||||
->toArray();
|
||||
|
||||
$query = PosAccessKey::with(['store:id,name,hashkey,owner_id', 'store.owner:id,name,nickname,hashkey'])
|
||||
->whereIn('store_id', $storeIds)
|
||||
->orderBy('id', 'desc');
|
||||
}
|
||||
|
||||
$keys = $query->get();
|
||||
|
||||
return ResponseHelper::returnSuccessResponse($keys, 'pos_access_keys');
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
if (!UserPermissions::isActionPermitted(Auth::user()->acct_type, UserActions::CreatePosAccessKey)) {
|
||||
return ResponseHelper::returnUnauthorized();
|
||||
}
|
||||
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'store_hash' => 'required|string',
|
||||
'expires_at' => 'nullable|string',
|
||||
]);
|
||||
|
||||
$store = Store::where('hashkey', $validated['store_hash'])->first();
|
||||
if (!$store) {
|
||||
return ResponseHelper::returnError('Store not found', 404);
|
||||
}
|
||||
|
||||
$user = Auth::user();
|
||||
$acctType = $user->acct_type->value ?? $user->acct_type ?? '';
|
||||
if (!in_array($acctType, ['ult', 'super operator', 'operator'])) {
|
||||
$descendants = $user->getAllDescendants();
|
||||
$allowedIds = $descendants->pluck('id')->push($user->id)->toArray();
|
||||
if (!in_array($store->owner_id, $allowedIds) && !in_array($store->manager_id, $allowedIds)) {
|
||||
return ResponseHelper::returnError('Unauthorized to create keys for this store', 403);
|
||||
}
|
||||
}
|
||||
|
||||
$data = [
|
||||
'access_key' => 'PK-' . Str::upper(Str::random(16)),
|
||||
'store_id' => $store->id,
|
||||
'name' => $validated['name'],
|
||||
'created_by' => Auth::id(),
|
||||
'status' => 'active',
|
||||
];
|
||||
|
||||
// Set expiry if provided
|
||||
if (!empty($validated['expires_at'])) {
|
||||
$data['expires_at'] = $validated['expires_at'];
|
||||
}
|
||||
|
||||
$key = PosAccessKey::create($data);
|
||||
|
||||
return ResponseHelper::returnSuccessResponse($key, $key->hashkey, 'POS Access Key created');
|
||||
}
|
||||
|
||||
public function destroy(Request $request)
|
||||
{
|
||||
if (!UserPermissions::isActionPermitted(Auth::user()->acct_type, UserActions::DeletePosAccessKey)) {
|
||||
return ResponseHelper::returnUnauthorized();
|
||||
}
|
||||
|
||||
$hashkey = $request->input('target');
|
||||
$key = PosAccessKey::with('store')->where('hashkey', $hashkey)->first();
|
||||
|
||||
if (!$key) {
|
||||
return ResponseHelper::returnError('Key not found', 404);
|
||||
}
|
||||
|
||||
if (!$this->userOwnsKeyStore($key)) {
|
||||
return ResponseHelper::returnError('Unauthorized to delete this key', 403);
|
||||
}
|
||||
|
||||
$key->delete();
|
||||
return ResponseHelper::returnSuccessResponse([], $hashkey, 'Key deleted');
|
||||
}
|
||||
|
||||
public function toggleStatus(Request $request)
|
||||
{
|
||||
if (!UserPermissions::isActionPermitted(Auth::user()->acct_type, UserActions::TogglePosAccessKey)) {
|
||||
return ResponseHelper::returnUnauthorized();
|
||||
}
|
||||
|
||||
$hashkey = $request->input('target');
|
||||
$key = PosAccessKey::with('store')->where('hashkey', $hashkey)->first();
|
||||
|
||||
if (!$key) {
|
||||
return ResponseHelper::returnError('Key not found', 404);
|
||||
}
|
||||
|
||||
if (!$this->userOwnsKeyStore($key)) {
|
||||
return ResponseHelper::returnError('Unauthorized to modify this key', 403);
|
||||
}
|
||||
|
||||
$key->status = $key->status === 'active' ? 'inactive' : 'active';
|
||||
$key->save();
|
||||
return ResponseHelper::returnSuccessResponse($key, $hashkey, 'Status updated');
|
||||
}
|
||||
|
||||
/**
|
||||
* Ownership gate shared by destroy/toggleStatus: Big 3 always pass;
|
||||
* everyone else must own or manage (directly or via descendants) the
|
||||
* store the key belongs to.
|
||||
*/
|
||||
private function userOwnsKeyStore(PosAccessKey $key): bool
|
||||
{
|
||||
$user = Auth::user();
|
||||
if (!$user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$acctType = $user->acct_type->value ?? $user->acct_type ?? '';
|
||||
if (in_array($acctType, ['ult', 'super operator', 'operator'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$store = $key->store;
|
||||
if (!$store) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$allowedIds = $user->getAllDescendants()->pluck('id')->push($user->id)->toArray();
|
||||
return in_array($store->owner_id, $allowedIds) || in_array($store->manager_id, $allowedIds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,42 +155,9 @@ class SystemSettingsController
|
||||
$settings['app_logo_url'] = cdn_asset('vendor/assets/icons/192x192.png'); // Fallback to PWA icon on the CDN
|
||||
}
|
||||
|
||||
// Resolve main organization hashkey to a usable data object
|
||||
$settings['main_organization_data'] = null;
|
||||
if (!empty($settings['main_organization'])) {
|
||||
$org = \App\Models\Market\Organization::where('hashkey', $settings['main_organization'])->first();
|
||||
if ($org) {
|
||||
$settings['main_organization_data'] = [
|
||||
'hashkey' => $org->hashkey,
|
||||
'name' => $org->name,
|
||||
'type' => $org->type,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* List organizations available for selection as the main cooperative/organization.
|
||||
*/
|
||||
public function listOrganizations()
|
||||
{
|
||||
if (!Auth::user()->isUltimate()) {
|
||||
return ResponseHelper::returnUnauthorized();
|
||||
}
|
||||
|
||||
$orgs = \App\Models\Market\Organization::where('is_active', true)
|
||||
->orderBy('type')
|
||||
->orderBy('name')
|
||||
->get(['hashkey', 'name', 'type']);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => $orgs,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all modules with their effective state, env/config default, and
|
||||
* any DB-stored override. Used by the Ultimate Console module manager.
|
||||
|
||||
207
app/Http/Controllers/Admin/UserController.php
Normal file
207
app/Http/Controllers/Admin/UserController.php
Normal file
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Enums\UserActions;
|
||||
use App\Enums\UserTypes;
|
||||
use App\Http\Controllers\Helpers\Permissions\UserPermissions;
|
||||
use App\Http\Controllers\Helpers\ResponseHelper;
|
||||
use App\Models\User;
|
||||
use Hypervel\Http\Request;
|
||||
use Hypervel\Support\Facades\Auth;
|
||||
use Hypervel\Support\Facades\Hash;
|
||||
use Hypervel\Support\Facades\Redis;
|
||||
use Hypervel\Support\Facades\Validator;
|
||||
|
||||
class UserController
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
if (!UserPermissions::isActionPermitted(Auth::user()->acct_type, UserActions::ListAllUsersAsParentforUserCreation)) {
|
||||
return ResponseHelper::returnUnauthorized();
|
||||
}
|
||||
|
||||
$query = User::orderByDesc('id');
|
||||
|
||||
if ($search = $request->input('search')) {
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->where('name', 'like', "%{$search}%")
|
||||
->orWhere('mobile_number', 'like', "%{$search}%")
|
||||
->orWhere('username', 'like', "%{$search}%");
|
||||
});
|
||||
}
|
||||
|
||||
if ($acctType = $request->input('acct_type')) $query->where('acct_type', $acctType);
|
||||
if ($request->input('active_only')) $query->where('active', true);
|
||||
|
||||
$users = $query->paginate((int) $request->input('per_page', 25));
|
||||
|
||||
return response()->json(['success' => true, 'data' => $users]);
|
||||
}
|
||||
|
||||
public function show(Request $request)
|
||||
{
|
||||
$target = $request->input('target');
|
||||
$user = is_numeric($target)
|
||||
? User::find($target)
|
||||
: User::where('hashkey', $target)->first();
|
||||
|
||||
if (!$user) return ResponseHelper::returnError('User not found', 404);
|
||||
|
||||
if (!UserPermissions::isActionPermitted(Auth::user()->acct_type, UserActions::ViewUserInfo)) {
|
||||
return ResponseHelper::returnUnauthorized();
|
||||
}
|
||||
|
||||
return response()->json(['success' => true, 'data' => $this->present($user)]);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
if (!UserPermissions::isActionPermitted(Auth::user()->acct_type, UserActions::CreateUser)) {
|
||||
return ResponseHelper::returnUnauthorized();
|
||||
}
|
||||
|
||||
$validator = Validator::make($request->all(), [
|
||||
'name' => 'required|string|max:255',
|
||||
'mobile_number' => 'required|string|max:20|unique:users,mobile_number',
|
||||
'username' => 'nullable|string|max:100|unique:users,username',
|
||||
'password' => 'required|string|min:6',
|
||||
'acct_type' => 'required|string',
|
||||
'parentuid' => 'nullable|integer|exists:users,id',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->json(['success' => false, 'errors' => $validator->errors()], 422);
|
||||
}
|
||||
|
||||
$acctType = UserTypes::tryFrom($request->input('acct_type'));
|
||||
if (!$acctType) {
|
||||
return ResponseHelper::returnError('Invalid account type', 422);
|
||||
}
|
||||
|
||||
$user = User::create([
|
||||
'name' => $request->input('name'),
|
||||
'mobile_number' => $request->input('mobile_number'),
|
||||
'username' => $request->input('username'),
|
||||
'password' => Hash::make($request->input('password')),
|
||||
'acct_type' => $acctType,
|
||||
'parentuid' => $request->input('parentuid', Auth::id()),
|
||||
'hashkey' => hash('sha256', uniqid((string) now(), true)),
|
||||
'active' => true,
|
||||
]);
|
||||
|
||||
return response()->json(['success' => true, 'data' => $this->present($user), 'message' => 'User created']);
|
||||
}
|
||||
|
||||
public function update(Request $request)
|
||||
{
|
||||
$target = $request->input('target');
|
||||
$user = User::where('hashkey', $target)->first();
|
||||
if (!$user) return ResponseHelper::returnError('User not found', 404);
|
||||
|
||||
if (!UserPermissions::isActionPermitted($target, UserActions::ModifyUser)) {
|
||||
return ResponseHelper::returnUnauthorized();
|
||||
}
|
||||
|
||||
$allowedFields = ['name', 'username', 'acct_type', 'nickname', 'fullname'];
|
||||
$data = $request->only($allowedFields);
|
||||
if (isset($data['acct_type'])) {
|
||||
$acctType = UserTypes::tryFrom($data['acct_type']);
|
||||
if (!$acctType) return ResponseHelper::returnError('Invalid account type', 422);
|
||||
$data['acct_type'] = $acctType;
|
||||
}
|
||||
|
||||
$user->update($data);
|
||||
|
||||
return response()->json(['success' => true, 'data' => $this->present($user), 'message' => 'User updated']);
|
||||
}
|
||||
|
||||
public function setActive(Request $request)
|
||||
{
|
||||
$target = $request->input('target');
|
||||
$user = User::where('hashkey', $target)->first();
|
||||
if (!$user) return ResponseHelper::returnError('User not found', 404);
|
||||
|
||||
$active = (bool) $request->input('active', true);
|
||||
$action = $active ? UserActions::SetActiveUser : UserActions::SetInActiveUser;
|
||||
|
||||
if (!UserPermissions::isActionPermitted($target, $action)) {
|
||||
return ResponseHelper::returnUnauthorized();
|
||||
}
|
||||
|
||||
$user->update(['active' => $active]);
|
||||
|
||||
return response()->json(['success' => true, 'data' => $this->present($user)]);
|
||||
}
|
||||
|
||||
public function changePassword(Request $request)
|
||||
{
|
||||
$target = $request->input('target');
|
||||
$user = User::where('hashkey', $target)->first();
|
||||
if (!$user) return ResponseHelper::returnError('User not found', 404);
|
||||
|
||||
if (!UserPermissions::isActionPermitted($target, UserActions::ChangeUserPassword)) {
|
||||
return ResponseHelper::returnUnauthorized();
|
||||
}
|
||||
|
||||
$validator = Validator::make($request->all(), [
|
||||
'password' => 'required|string|min:6',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->json(['success' => false, 'errors' => $validator->errors()], 422);
|
||||
}
|
||||
|
||||
$user->update(['password' => Hash::make($request->input('password'))]);
|
||||
|
||||
// Force logout all sessions for this user
|
||||
Redis::del("user_session:{$user->id}");
|
||||
|
||||
return response()->json(['success' => true, 'message' => 'Password changed']);
|
||||
}
|
||||
|
||||
public function forceLogout(Request $request)
|
||||
{
|
||||
$target = $request->input('target');
|
||||
$user = User::where('hashkey', $target)->first();
|
||||
if (!$user) return ResponseHelper::returnError('User not found', 404);
|
||||
|
||||
if (!UserPermissions::isActionPermitted($target, UserActions::ForceLogoutUser)) {
|
||||
return ResponseHelper::returnUnauthorized();
|
||||
}
|
||||
|
||||
Redis::del("user_session:{$user->id}");
|
||||
|
||||
return response()->json(['success' => true, 'message' => 'User session cleared']);
|
||||
}
|
||||
|
||||
public function accountTypes()
|
||||
{
|
||||
$types = collect(UserTypes::cases())->map(fn ($t) => [
|
||||
'value' => $t->value,
|
||||
'label' => ucwords(str_replace('_', ' ', $t->value)),
|
||||
]);
|
||||
|
||||
return response()->json(['success' => true, 'data' => $types]);
|
||||
}
|
||||
|
||||
private function present(User $user): array
|
||||
{
|
||||
return [
|
||||
'id' => $user->id,
|
||||
'hashkey' => $user->hashkey,
|
||||
'name' => $user->name,
|
||||
'fullname' => $user->fullname,
|
||||
'nickname' => $user->nickname,
|
||||
'username' => $user->username,
|
||||
'mobile_number' => $user->mobile_number,
|
||||
'acct_type' => $user->acct_type,
|
||||
'active' => (bool) $user->active,
|
||||
'parentuid' => $user->parentuid,
|
||||
'created_at' => $user->created_at,
|
||||
'updated_at' => $user->updated_at,
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user