Premier commit
This commit is contained in:
36
app/Http/Controllers/Admin/LicenseLevelController.php
Normal file
36
app/Http/Controllers/Admin/LicenseLevelController.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
use App\Models\LicenseLevel;
|
||||
|
||||
class LicenseLevelController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$levels = LicenseLevel::all();
|
||||
return view('admin.license_levels.index', compact('levels'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate(['name' => 'required|unique:license_levels,name']);
|
||||
LicenseLevel::create($request->only('name'));
|
||||
return back()->with('success', 'Niveau de licence ajouté.');
|
||||
}
|
||||
|
||||
public function toggle(LicenseLevel $licenseLevel)
|
||||
{
|
||||
$licenseLevel->update(['is_active' => !$licenseLevel->is_active]);
|
||||
return back()->with('success', 'Statut mis à jour.');
|
||||
}
|
||||
|
||||
public function destroy(LicenseLevel $licenseLevel)
|
||||
{
|
||||
$licenseLevel->delete();
|
||||
return back()->with('success', 'Niveau de licence supprimé.');
|
||||
}
|
||||
}
|
||||
63
app/Http/Controllers/Admin/LinkController.php
Normal file
63
app/Http/Controllers/Admin/LinkController.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Link;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class LinkController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$links = Link::orderBy('order', 'asc')->get();
|
||||
return view('admin.links.index', compact('links'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'title' => 'required|string|max:255',
|
||||
'url' => 'required|url',
|
||||
'icon' => 'nullable|string',
|
||||
'color' => 'nullable|string',
|
||||
'order' => 'integer',
|
||||
]);
|
||||
|
||||
Link::create($validated);
|
||||
|
||||
return back()->with('success', 'Lien ajouté.');
|
||||
}
|
||||
|
||||
public function edit(Link $link)
|
||||
{
|
||||
return view('admin.links.edit', compact('link'));
|
||||
}
|
||||
|
||||
public function update(Request $request, Link $link)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'title' => 'required|string|max:255',
|
||||
'url' => 'required|url',
|
||||
'icon' => 'nullable|string',
|
||||
'color' => 'nullable|string',
|
||||
'order' => 'integer',
|
||||
]);
|
||||
|
||||
$link->update($validated);
|
||||
|
||||
return redirect()->route('admin.links.index')->with('success', 'Lien mis à jour.');
|
||||
}
|
||||
|
||||
public function toggle(Link $link)
|
||||
{
|
||||
$link->update(['is_active' => !$link->is_active]);
|
||||
return back()->with('success', 'Statut mis à jour.');
|
||||
}
|
||||
|
||||
public function destroy(Link $link)
|
||||
{
|
||||
$link->delete();
|
||||
return back()->with('success', 'Lien supprimé.');
|
||||
}
|
||||
}
|
||||
23
app/Http/Controllers/Admin/MunicipalityController.php
Normal file
23
app/Http/Controllers/Admin/MunicipalityController.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
use App\Models\Municipality;
|
||||
|
||||
class MunicipalityController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$municipalities = Municipality::all();
|
||||
return view('admin.municipalities.index', compact('municipalities'));
|
||||
}
|
||||
|
||||
public function toggle(Municipality $municipality)
|
||||
{
|
||||
$municipality->update(['is_active' => !$municipality->is_active]);
|
||||
return back()->with('success', 'Statut de la commune mis à jour.');
|
||||
}
|
||||
}
|
||||
76
app/Http/Controllers/AuthController.php
Normal file
76
app/Http/Controllers/AuthController.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Validation\Defaults\Password;
|
||||
|
||||
class AuthController extends Controller
|
||||
{
|
||||
public function showLogin()
|
||||
{
|
||||
return view('auth.login');
|
||||
}
|
||||
|
||||
public function login(Request $request)
|
||||
{
|
||||
$credentials = $request->validate([
|
||||
'email' => ['required', 'email'],
|
||||
'password' => ['required'],
|
||||
]);
|
||||
|
||||
if (Auth::attempt($credentials, $request->boolean('remember'))) {
|
||||
$request->session()->regenerate();
|
||||
if (!Auth::user()->is_active) {
|
||||
Auth::logout();
|
||||
$request->session()->invalidate();
|
||||
$request->session()->regenerateToken();
|
||||
return back()->withErrors(['email' => 'Your account is pending approval by an administrator.']);
|
||||
}
|
||||
return redirect()->intended('/dashboard');
|
||||
}
|
||||
|
||||
return back()->withErrors([
|
||||
'email' => 'The provided credentials do not match our records.',
|
||||
])->onlyInput('email');
|
||||
}
|
||||
|
||||
public function showRegister()
|
||||
{
|
||||
return view('auth.register');
|
||||
}
|
||||
|
||||
public function register(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
|
||||
'password' => ['required', 'confirmed', Password::defaults()],
|
||||
]);
|
||||
|
||||
$user = User::create([
|
||||
'name' => $validated['name'],
|
||||
'email' => $validated['email'],
|
||||
'password' => Hash::make($validated['password']),
|
||||
'is_active' => false, // Require approval
|
||||
'role' => 'reader', // Default
|
||||
]);
|
||||
|
||||
Auth::login($user);
|
||||
|
||||
// Notify admin in real app
|
||||
|
||||
return redirect('/dashboard')->with('status', 'Account created. Wait for approval.');
|
||||
}
|
||||
|
||||
public function logout(Request $request)
|
||||
{
|
||||
Auth::logout();
|
||||
$request->session()->invalidate();
|
||||
$request->session()->regenerateToken();
|
||||
return redirect('/');
|
||||
}
|
||||
}
|
||||
148
app/Http/Controllers/ContractController.php
Normal file
148
app/Http/Controllers/ContractController.php
Normal file
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Contract;
|
||||
use App\Models\ContractMeta;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
class ContractController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$contracts = Contract::with('municipality')->latest()->paginate(10);
|
||||
return view('contracts.index', compact('contracts'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
if (!auth()->user()->isManager()) {
|
||||
abort(403);
|
||||
}
|
||||
$municipalities = \App\Models\Municipality::active()->orderBy('name')->get();
|
||||
$licenseLevels = \App\Models\LicenseLevel::active()->orderBy('name')->get();
|
||||
return view('contracts.create', compact('municipalities', 'licenseLevels'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
if (!auth()->user()->isManager()) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'reference' => 'nullable|string|unique:contracts',
|
||||
'provider' => 'required|string',
|
||||
'municipality_id' => 'nullable|exists:municipalities,id',
|
||||
'start_date' => 'required|date',
|
||||
'end_date' => 'nullable|date|after_or_equal:start_date',
|
||||
'amount' => 'nullable|numeric',
|
||||
'type' => 'required|string',
|
||||
'meta' => 'nullable|array', // key-value pairs
|
||||
]);
|
||||
|
||||
$contract = Contract::create($validated);
|
||||
|
||||
if ($request->has('meta')) {
|
||||
foreach ($request->meta as $key => $value) {
|
||||
if ($value) {
|
||||
$contract->meta()->create(['key' => $key, 'value' => $value]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->route('contracts.index')
|
||||
->with('success', 'Contract created successfully.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(Contract $contract)
|
||||
{
|
||||
$contract->load(['meta', 'documents', 'municipality']);
|
||||
return view('contracts.show', compact('contract'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(Contract $contract)
|
||||
{
|
||||
if (!auth()->user()->isManager()) {
|
||||
abort(403);
|
||||
}
|
||||
$contract->load('meta');
|
||||
$municipalities = \App\Models\Municipality::active()->orderBy('name')->get();
|
||||
$licenseLevels = \App\Models\LicenseLevel::active()->orderBy('name')->get();
|
||||
return view('contracts.edit', compact('contract', 'municipalities', 'licenseLevels'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, Contract $contract)
|
||||
{
|
||||
if (!auth()->user()->isManager()) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'reference' => 'nullable|string|unique:contracts,reference,' . $contract->id,
|
||||
'provider' => 'required|string',
|
||||
'municipality_id' => 'nullable|exists:municipalities,id',
|
||||
'start_date' => 'required|date',
|
||||
'end_date' => 'nullable|date|after_or_equal:start_date',
|
||||
'amount' => 'nullable|numeric',
|
||||
'status' => 'required|string',
|
||||
]);
|
||||
|
||||
$contract->update($validated);
|
||||
|
||||
// Handle Meta Data Update
|
||||
if ($request->has('meta')) {
|
||||
foreach ($request->meta as $key => $value) {
|
||||
if ($value) {
|
||||
$contract->meta()->updateOrCreate(
|
||||
['key' => $key],
|
||||
['value' => $value]
|
||||
);
|
||||
} else {
|
||||
// If value is empty, maybe delete? Or just leave null.
|
||||
// Let's delete if empty to keep clean
|
||||
$contract->meta()->where('key', $key)->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->route('contracts.index')
|
||||
->with('success', 'Contract updated successfully.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(Contract $contract)
|
||||
{
|
||||
if (!auth()->user()->isAdmin()) { // Only admin can delete? Or manager?
|
||||
abort(403);
|
||||
}
|
||||
|
||||
$contract->delete();
|
||||
|
||||
return redirect()->route('contracts.index')
|
||||
->with('success', 'Contract deleted.');
|
||||
}
|
||||
}
|
||||
8
app/Http/Controllers/Controller.php
Normal file
8
app/Http/Controllers/Controller.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
abstract class Controller
|
||||
{
|
||||
//
|
||||
}
|
||||
32
app/Http/Controllers/CortexXdrController.php
Normal file
32
app/Http/Controllers/CortexXdrController.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Services\CortexXdrService;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CortexXdrController extends Controller
|
||||
{
|
||||
protected $cortex;
|
||||
|
||||
public function __construct(CortexXdrService $cortex)
|
||||
{
|
||||
$this->cortex = $cortex;
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
// Return view effectively immediately with a loading state
|
||||
return view('cortex.index');
|
||||
}
|
||||
|
||||
public function getData(CortexXdrService $cortexService)
|
||||
{
|
||||
try {
|
||||
$summary = $cortexService->getSummary();
|
||||
return response()->json($summary);
|
||||
} catch (\Exception $e) {
|
||||
return response()->json(['error' => $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
54
app/Http/Controllers/DashboardController.php
Normal file
54
app/Http/Controllers/DashboardController.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Contract;
|
||||
use App\Models\AuditLog;
|
||||
use App\Models\GlobalSetting;
|
||||
use App\Models\Link;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class DashboardController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display the dashboard.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$contractStats = [
|
||||
'total' => Contract::count(),
|
||||
'active' => Contract::active()->count(),
|
||||
'expiring_soon' => Contract::expiringSoon(30)->count(),
|
||||
'expired' => Contract::where('status', 'expired')->count(),
|
||||
'by_type' => Contract::select('type', \DB::raw('count(*) as count'))->groupBy('type')->get()->keyBy('type'),
|
||||
];
|
||||
|
||||
// Recent logs
|
||||
$recentLogs = AuditLog::with('user')->latest()->take(10)->get();
|
||||
|
||||
// Upcoming Contracts (Timeline)
|
||||
$upcomingContracts = Contract::whereNotNull('end_date')
|
||||
->whereDate('end_date', '>=', now())
|
||||
->orderBy('end_date', 'asc')
|
||||
->take(6)
|
||||
->get();
|
||||
|
||||
// Dashboard Note
|
||||
$dashboardNote = GlobalSetting::get('dashboard_note');
|
||||
|
||||
// External Links
|
||||
$links = Link::active()->get();
|
||||
|
||||
return view('dashboard', compact('contractStats', 'recentLogs', 'upcomingContracts', 'dashboardNote', 'links'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the dashboard note.
|
||||
*/
|
||||
public function updateNote(Request $request)
|
||||
{
|
||||
GlobalSetting::set('dashboard_note', $request->input('note'));
|
||||
|
||||
return back()->with('success', 'Pense-bête mis à jour.');
|
||||
}
|
||||
}
|
||||
58
app/Http/Controllers/DocumentController.php
Normal file
58
app/Http/Controllers/DocumentController.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Contract;
|
||||
use App\Models\Document;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class DocumentController extends Controller
|
||||
{
|
||||
/**
|
||||
* Store a new document for a contract.
|
||||
*/
|
||||
public function store(Request $request, Contract $contract)
|
||||
{
|
||||
// Simple validation
|
||||
$request->validate([
|
||||
'file' => 'required|file|mimes:pdf,docx,jpg,png|max:10240', // 10MB limit
|
||||
'description' => 'nullable|string|max:255',
|
||||
]);
|
||||
|
||||
if ($request->hasFile('file')) {
|
||||
$path = $request->file('file')->store('contracts/' . $contract->id, 'public');
|
||||
|
||||
$contract->documents()->create([
|
||||
'filename' => $request->file('file')->getClientOriginalName(),
|
||||
'path' => $path,
|
||||
'mime_type' => $request->file('file')->getMimeType(),
|
||||
'size' => $request->file('file')->getSize(),
|
||||
'description' => $request->input('description'),
|
||||
'uploaded_by' => auth()->id(),
|
||||
]);
|
||||
|
||||
return back()->with('success', 'Document uploaded successfully.');
|
||||
}
|
||||
|
||||
return back()->with('error', 'No file uploaded.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a document.
|
||||
*/
|
||||
public function destroy(Document $document)
|
||||
{
|
||||
// Check permission (manager or admin or uploader?)
|
||||
if (!auth()->user()->isManager() && auth()->id() !== $document->uploaded_by) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
// Delete from storage
|
||||
Storage::disk('public')->delete($document->path);
|
||||
|
||||
$document->delete();
|
||||
|
||||
return back()->with('success', 'Document deleted.');
|
||||
}
|
||||
}
|
||||
46
app/Http/Controllers/MunicipalityController.php
Normal file
46
app/Http/Controllers/MunicipalityController.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class MunicipalityController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$municipalities = \App\Models\Municipality::active()->orderBy('name')->get();
|
||||
return view('municipalities.index', compact('municipalities'));
|
||||
}
|
||||
|
||||
public function show(\App\Models\Municipality $municipality)
|
||||
{
|
||||
if (!$municipality->is_active) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
$municipality->load(['contracts.meta']);
|
||||
|
||||
$contracts = $municipality->contracts;
|
||||
|
||||
// M365 Statistics
|
||||
$m365Contracts = $contracts->where('type', 'microsoft_365');
|
||||
|
||||
// Fetch all active license levels to initialize stats keys
|
||||
$licenseLevels = \App\Models\LicenseLevel::active()->pluck('name')->toArray();
|
||||
$m365Stats = array_fill_keys($licenseLevels, 0);
|
||||
$m365Stats['Autre'] = 0; // Fallback category
|
||||
|
||||
foreach ($m365Contracts as $contract) {
|
||||
$level = $contract->meta->where('key', 'm365_license_level')->first()?->value;
|
||||
$quantity = (int) $contract->meta->where('key', 'm365_quantity')->first()?->value ?? 0;
|
||||
|
||||
if ($level && array_key_exists($level, $m365Stats)) {
|
||||
$m365Stats[$level] += $quantity;
|
||||
} else {
|
||||
$m365Stats['Autre'] += $quantity;
|
||||
}
|
||||
}
|
||||
|
||||
return view('municipalities.show', compact('municipality', 'contracts', 'm365Stats'));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user