webmoney/backend/app/Http/Controllers/Api/UserManagementController.php

414 lines
15 KiB
PHP

<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\User;
use App\Models\Plan;
use App\Models\Subscription;
use App\Mail\WelcomeNewUser;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Mail;
use Illuminate\Validation\Rules\Password;
use Carbon\Carbon;
class UserManagementController extends Controller
{
/**
* Create a new user with specified role/plan
* user_type: 'free' | 'pro' | 'admin'
*/
public function store(Request $request)
{
$validated = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
'password' => 'nullable|string|min:8',
'language' => 'sometimes|string|in:es,pt-BR,en',
'currency' => 'sometimes|string|size:3',
'user_type' => 'sometimes|string|in:free,pro,admin',
'send_welcome_email' => 'sometimes|boolean',
]);
// Generate random password if not provided or empty
$password = !empty($validated['password']) ? $validated['password'] : bin2hex(random_bytes(8));
$userType = $validated['user_type'] ?? 'free';
$sendWelcomeEmail = $validated['send_welcome_email'] ?? true;
$user = User::create([
'name' => $validated['name'],
'email' => $validated['email'],
'password' => Hash::make($password),
'language' => $validated['language'] ?? 'es',
'currency' => $validated['currency'] ?? 'EUR',
'email_verified_at' => now(), // Auto-verify admin-created users
'is_admin' => $userType === 'admin',
]);
$subscriptionInfo = null;
// Create Pro subscription if user_type is 'pro' or 'admin'
if (in_array($userType, ['pro', 'admin'])) {
$proPlan = Plan::where('slug', 'pro-annual')->first();
if ($proPlan) {
$subscription = Subscription::create([
'user_id' => $user->id,
'plan_id' => $proPlan->id,
'status' => Subscription::STATUS_ACTIVE,
'current_period_start' => now(),
'current_period_end' => Carbon::create(2037, 12, 31, 23, 59, 59), // "Lifetime" subscription (max timestamp)
'paypal_subscription_id' => 'ADMIN_GRANTED_' . strtoupper(bin2hex(random_bytes(8))),
'paypal_status' => 'ACTIVE',
'price_paid' => 0,
'currency' => 'EUR',
]);
$subscriptionInfo = [
'plan' => $proPlan->name,
'status' => 'active',
'expires' => 'Nunca (otorgado por admin)',
];
}
}
// Send welcome email with temporary password
$emailSent = false;
if ($sendWelcomeEmail) {
try {
Mail::to($user->email)->send(new WelcomeNewUser($user, $password));
$emailSent = true;
} catch (\Exception $e) {
\Log::error('Failed to send welcome email: ' . $e->getMessage());
}
}
return response()->json([
'success' => true,
'message' => 'Usuario creado correctamente',
'data' => [
'user' => [
'id' => $user->id,
'name' => $user->name,
'email' => $user->email,
'is_admin' => $user->is_admin,
'language' => $user->language,
],
'user_type' => $userType,
'subscription' => $subscriptionInfo,
'temporary_password' => isset($validated['password']) ? null : $password,
'welcome_email_sent' => $emailSent,
],
], 201);
}
/**
* List all users with their subscription info
*/
public function index(Request $request)
{
$query = User::with(['subscription.plan'])
->withCount(['accounts', 'categories', 'budgets', 'transactions']);
// Search
if ($request->has('search') && $request->search) {
$search = $request->search;
$query->where(function ($q) use ($search) {
$q->where('name', 'like', "%{$search}%")
->orWhere('email', 'like', "%{$search}%");
});
}
// Filter by subscription status
if ($request->has('subscription_status')) {
if ($request->subscription_status === 'active') {
$query->whereHas('subscription');
} elseif ($request->subscription_status === 'free') {
$query->whereDoesntHave('subscription');
}
}
// Pagination
$perPage = $request->get('per_page', 20);
$users = $query->orderBy('created_at', 'desc')->paginate($perPage);
// Transform data
$users->getCollection()->transform(function ($user) {
return [
'id' => $user->id,
'name' => $user->name,
'email' => $user->email,
'language' => $user->language,
'currency' => $user->currency,
'is_admin' => (bool) $user->is_admin,
'created_at' => $user->created_at,
'last_login_at' => $user->last_login_at,
'email_verified_at' => $user->email_verified_at,
'subscription' => $user->subscription ? [
'plan_name' => $user->subscription->plan->name ?? 'Unknown',
'plan_slug' => $user->subscription->plan->slug ?? 'unknown',
'status' => $user->subscription->status,
'current_period_end' => $user->subscription->current_period_end,
] : null,
'usage' => [
'accounts' => $user->accounts_count,
'categories' => $user->categories_count,
'budgets' => $user->budgets_count,
'transactions' => $user->transactions_count,
],
];
});
return response()->json([
'success' => true,
'data' => $users->items(),
'pagination' => [
'current_page' => $users->currentPage(),
'last_page' => $users->lastPage(),
'per_page' => $users->perPage(),
'total' => $users->total(),
],
]);
}
/**
* Get single user details
*/
public function show($id)
{
$user = User::with(['subscription.plan', 'subscriptions.plan'])
->withCount(['accounts', 'categories', 'budgets', 'transactions', 'goals'])
->findOrFail($id);
return response()->json([
'success' => true,
'data' => [
'id' => $user->id,
'name' => $user->name,
'email' => $user->email,
'language' => $user->language,
'currency' => $user->currency,
'created_at' => $user->created_at,
'last_login_at' => $user->last_login_at,
'email_verified_at' => $user->email_verified_at,
'subscription' => $user->subscription ? [
'id' => $user->subscription->id,
'plan' => $user->subscription->plan,
'status' => $user->subscription->status,
'paypal_subscription_id' => $user->subscription->paypal_subscription_id,
'current_period_start' => $user->subscription->current_period_start,
'current_period_end' => $user->subscription->current_period_end,
'canceled_at' => $user->subscription->canceled_at,
] : null,
'subscription_history' => $user->subscriptions->map(function ($sub) {
return [
'plan_name' => $sub->plan->name ?? 'Unknown',
'status' => $sub->status,
'created_at' => $sub->created_at,
'canceled_at' => $sub->canceled_at,
];
}),
'usage' => [
'accounts' => $user->accounts_count,
'categories' => $user->categories_count,
'budgets' => $user->budgets_count,
'transactions' => $user->transactions_count,
'goals' => $user->goals_count,
],
],
]);
}
/**
* Update user
*/
public function update(Request $request, $id)
{
$user = User::findOrFail($id);
// Don't allow changing main admin's admin status
if ($user->email === 'marco@cnxifly.com' && $request->has('is_admin') && !$request->is_admin) {
return response()->json([
'success' => false,
'message' => 'No se puede remover permisos del administrador principal',
], 403);
}
$validated = $request->validate([
'name' => 'sometimes|string|max:255',
'email' => 'sometimes|email|unique:users,email,' . $id,
'language' => 'sometimes|string|in:es,pt-BR,en',
'currency' => 'sometimes|string|size:3',
'is_admin' => 'sometimes|boolean',
]);
$user->update($validated);
return response()->json([
'success' => true,
'message' => 'Usuario actualizado correctamente',
'data' => [
'id' => $user->id,
'name' => $user->name,
'email' => $user->email,
'language' => $user->language,
'currency' => $user->currency,
'is_admin' => $user->is_admin,
],
]);
}
/**
* Reset user password (generate random)
*/
public function resetPassword($id)
{
$user = User::findOrFail($id);
// Generate random password
$newPassword = bin2hex(random_bytes(8)); // 16 chars
$user->password = Hash::make($newPassword);
$user->save();
return response()->json([
'success' => true,
'message' => 'Contraseña restablecida correctamente',
'data' => [
'temporary_password' => $newPassword,
],
]);
}
/**
* Delete user and all their data
*/
public function destroy($id)
{
$user = User::findOrFail($id);
// Don't allow deleting admin
if ($user->email === 'marco@cnxifly.com') {
return response()->json([
'success' => false,
'message' => 'No se puede eliminar el usuario administrador',
], 403);
}
// Delete user (cascade will handle related data)
$user->delete();
return response()->json([
'success' => true,
'message' => 'Usuario eliminado correctamente',
]);
}
/**
* Change user subscription plan
*/
public function changePlan(Request $request, $id)
{
$user = User::findOrFail($id);
$validated = $request->validate([
'plan' => 'required|string|in:free,pro',
]);
// If changing to free, cancel any existing subscription
if ($validated['plan'] === 'free') {
$subscription = $user->subscription;
if ($subscription) {
$subscription->update([
'status' => Subscription::STATUS_CANCELED,
'canceled_at' => now(),
]);
}
return response()->json([
'success' => true,
'message' => 'Usuario cambiado a plan Free',
'data' => [
'plan' => 'free',
'subscription' => null,
],
]);
}
// If changing to pro, create or reactivate subscription
if ($validated['plan'] === 'pro') {
$proPlan = Plan::where('slug', 'pro-annual')->first();
if (!$proPlan) {
return response()->json([
'success' => false,
'message' => 'Plan Pro no encontrado en el sistema',
], 404);
}
// Check if user has existing subscription
$subscription = $user->subscription;
if ($subscription) {
// Reactivate existing subscription
$subscription->update([
'status' => Subscription::STATUS_ACTIVE,
'canceled_at' => null,
'current_period_start' => now(),
'current_period_end' => Carbon::create(2037, 12, 31, 23, 59, 59),
]);
} else {
// Create new subscription
$subscription = Subscription::create([
'user_id' => $user->id,
'plan_id' => $proPlan->id,
'status' => Subscription::STATUS_ACTIVE,
'current_period_start' => now(),
'current_period_end' => Carbon::create(2037, 12, 31, 23, 59, 59),
'paypal_subscription_id' => 'ADMIN_GRANTED_' . strtoupper(bin2hex(random_bytes(8))),
'paypal_status' => 'ACTIVE',
'price_paid' => 0,
'currency' => 'EUR',
]);
}
return response()->json([
'success' => true,
'message' => 'Usuario cambiado a plan Pro',
'data' => [
'plan' => 'pro',
'subscription' => [
'id' => $subscription->id,
'plan_name' => $proPlan->name,
'status' => $subscription->status,
'current_period_end' => $subscription->current_period_end,
],
],
]);
}
}
/**
* Get summary statistics
*/
public function summary()
{
$totalUsers = User::count();
$activeSubscribers = Subscription::where('status', 'active')->count();
$freeUsers = $totalUsers - $activeSubscribers;
$newUsersThisMonth = User::whereMonth('created_at', now()->month)
->whereYear('created_at', now()->year)
->count();
return response()->json([
'success' => true,
'data' => [
'total_users' => $totalUsers,
'active_subscribers' => $activeSubscribers,
'free_users' => $freeUsers,
'new_users_this_month' => $newUsersThisMonth,
],
]);
}
}