This commit is contained in:
Alexis Bruneteau 2025-06-04 03:32:12 +02:00
parent dce634e106
commit 0f751754b1
13 changed files with 1139 additions and 179 deletions

40
ansible/deploy_site.yml Normal file
View File

@ -0,0 +1,40 @@
- hosts: web
become: yes
vars:
static_site_local_path: "{{ lookup('env', 'PWD') }}/storage/app/private/portfolios/{{ sitename }}/{{ sitehost }}"
kube_manifest_local_path: "{{ lookup('env', 'PWD') }}/storage/app/kube/{{ sitename }}"
target_path: /var/www/{{ sitename }}/{{ sitehost }}
remote_kube_path: /tmp/kube/{{ sitename }}
tasks:
- name: Ensure target directory exists
file:
path: "{{ target_path }}"
state: directory
owner: root
group: root
mode: '0755'
- name: Copy static site files
copy:
src: "{{ static_site_local_path }}/"
dest: "{{ target_path }}/"
mode: '0644'
- name: Ensure remote kube directory exists
file:
path: "{{ remote_kube_path }}"
state: directory
mode: '0755'
- name: Copy kube manifests to remote server
copy:
src: "{{ kube_manifest_local_path }}/"
dest: "{{ remote_kube_path }}/"
mode: '0644'
- name: Apply Kubernetes manifests
shell: |
kubectl apply -f {{ remote_kube_path }} -n hosting-deploy
args:
executable: /bin/bash

View File

@ -0,0 +1,2 @@
[web]
192.168.1.35 ansible_user=root

View File

@ -0,0 +1,26 @@
<?php
namespace App\Helpers;
use Illuminate\Http\JsonResponse;
class ApiResponse
{
public static function success($data = null, string $message = 'OK', int $status = 200): JsonResponse
{
return response()->json([
'success' => true,
'message' => $message,
'data' => $data,
], $status);
}
public static function error(string $message = 'Error', int $status = 400, $errors = null): JsonResponse
{
return response()->json([
'success' => false,
'message' => $message,
'errors' => $errors,
], $status);
}
}

View File

@ -1,7 +1,5 @@
<?php <?php
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Models\User; use App\Models\User;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
@ -11,44 +9,68 @@ class AuthController extends Controller
{ {
public function register(Request $request) public function register(Request $request)
{ {
$fields = $request->validate([ $request->validate([
'name' => 'required|string|max:255', 'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email', 'email' => 'required|email|unique:users,email',
'password' => 'required|confirmed|min:6' 'password' => 'required|confirmed|min:6',
]);
$user = User::create([
'name' => $fields['name'],
'email' => $fields['email'],
'password' => Hash::make($fields['password']),
]); ]);
$token = $user->createToken('api-token')->plainTextToken; $user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
$token = $user->createToken('AppToken')->accessToken;;
return response()->json([ return response()->json([
'success' => true,
'data' => [
'user' => $user, 'user' => $user,
'token' => $token, 'token' => $token,
], 201); ]
]);
} }
public function login(Request $request) public function login(Request $request)
{ {
$fields = $request->validate([
'email' => 'required|email',
'password' => 'required',
]);
$credentials = $request->only('email', 'password'); $credentials = $request->only('email', 'password');
if (!Auth::attempt($credentials)) { if (!Auth::attempt($credentials)) {
return response()->json(['message' => 'Invalid credentials'], 401); return response()->json([
'success' => false,
'message' => 'Invalid credentials'
], 401);
} }
$user = Auth::user(); $user = Auth::user();
$token = $user->createToken('api-token')->plainTextToken; $token = $user->createToken('AppToken')->accessToken;
return response()->json([ return response()->json([
'token' => $token, 'success' => true,
'data' => [
'user' => $user, 'user' => $user,
'token' => $token,
]
]);
}
public function user(Request $request)
{
return response()->json([
'success' => true,
'data' => $request->user()
]);
}
public function logout(Request $request)
{
$request->user()->token()->revoke();
return response()->json([
'success' => true,
'message' => 'Logged out'
]); ]);
} }
} }

View File

@ -4,7 +4,7 @@ namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens; use Laravel\Passport\HasApiTokens;
class User extends Authenticatable class User extends Authenticatable
{ {
@ -20,4 +20,10 @@ class User extends Authenticatable
'password', 'password',
'remember_token', 'remember_token',
]; ];
public function portfolios()
{
return $this->hasMany(Portfolio::class);
}
} }

View File

@ -2,4 +2,5 @@
return [ return [
App\Providers\AppServiceProvider::class, App\Providers\AppServiceProvider::class,
App\Providers\AuthProvider::class,
]; ];

View File

@ -11,7 +11,7 @@
"require": { "require": {
"php": "^8.2", "php": "^8.2",
"laravel/framework": "^12.0", "laravel/framework": "^12.0",
"laravel/sanctum": "^4.1", "laravel/passport": "^13.0",
"laravel/tinker": "^2.10.1" "laravel/tinker": "^2.10.1"
}, },
"require-dev": { "require-dev": {

1067
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -37,7 +37,7 @@ return [
'guards' => [ 'guards' => [
'api' => [ 'api' => [
'driver' => 'sanctum', 'driver' => 'passport',
'provider' => 'users', 'provider' => 'users',
], ],
], ],

View File

@ -19,7 +19,7 @@ return [
'allowed_methods' => ['*'], 'allowed_methods' => ['*'],
'allowed_origins' => [env('FRONTEND_URL', 'http://localhost:3000')], 'allowed_origins' => [env('FRONTEND_URL', 'http://localhost:4200')],
'allowed_origins_patterns' => [], 'allowed_origins_patterns' => [],

View File

@ -1,84 +0,0 @@
<?php
use Laravel\Sanctum\Sanctum;
return [
/*
|--------------------------------------------------------------------------
| Stateful Domains
|--------------------------------------------------------------------------
|
| Requests from the following domains / hosts will receive stateful API
| authentication cookies. Typically, these should include your local
| and production domains which access your API via a backend SPA.
|
*/
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:3000,127.0.0.1:8000,::1',
Sanctum::currentApplicationUrlWithPort(),
env('FRONTEND_URL') ? ','.parse_url(env('FRONTEND_URL'), PHP_URL_HOST) : ''
))),
/*
|--------------------------------------------------------------------------
| Sanctum Guards
|--------------------------------------------------------------------------
|
| This array contains the authentication guards that will be checked when
| Sanctum is trying to authenticate a request. If none of these guards
| are able to authenticate the request, Sanctum will use the bearer
| token that's present on an incoming request for authentication.
|
*/
'guard' => ['web'],
/*
|--------------------------------------------------------------------------
| Expiration Minutes
|--------------------------------------------------------------------------
|
| This value controls the number of minutes until an issued token will be
| considered expired. This will override any values set in the token's
| "expires_at" attribute, but first-party sessions are not affected.
|
*/
'expiration' => null,
/*
|--------------------------------------------------------------------------
| Token Prefix
|--------------------------------------------------------------------------
|
| Sanctum can prefix new tokens in order to take advantage of numerous
| security scanning initiatives maintained by open source platforms
| that notify developers if they commit tokens into repositories.
|
| See: https://docs.github.com/en/code-security/secret-scanning/about-secret-scanning
|
*/
'token_prefix' => env('SANCTUM_TOKEN_PREFIX', ''),
/*
|--------------------------------------------------------------------------
| Sanctum Middleware
|--------------------------------------------------------------------------
|
| When authenticating your first-party SPA with Sanctum you may need to
| customize some of the middleware Sanctum uses while processing the
| request. You may change the middleware listed below as required.
|
*/
'middleware' => [
'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class,
'encrypt_cookies' => Illuminate\Cookie\Middleware\EncryptCookies::class,
'validate_csrf_token' => Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
],
];

View File

@ -18,7 +18,7 @@ return [
| |
*/ */
'driver' => env('SESSION_DRIVER', 'database'), 'driver' => env('SESSION_DRIVER', 'array'),
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------

View File

@ -3,15 +3,25 @@
use App\Http\Controllers\AuthController; use App\Http\Controllers\AuthController;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Http\Controllers\StaticSiteController;
use App\Http\Controllers\PortfolioController;
Route::post('/auth/register', [AuthController::class, 'register']); Route::post('/auth/register', [AuthController::class, 'register']);
Route::post('/auth/login', [AuthController::class, 'login']); Route::post('/auth/login', [AuthController::class, 'login']);
Route::middleware('auth:sanctum')->get('/me', function (Request $request) {
return $request->user();
});
Route::get('/ping', function () {return 'pongpong';}); Route::get('/ping', function () {return 'pongpong';});
Route::get('/pute', function () {return response()->json(['pute' => 'Dimitri']);}); Route::get('/pute', function () {return response()->json(['pute' => 'Dimitri']);});
Route::middleware('auth:api')->group(function () {
Route::get('/user', [AuthController::class, 'user']);
Route::post('/logout', [AuthController::class, 'logout']);
Route::apiResource('portfolios', PortfolioController::class);
Route::post('/portfolios/{portfolio}/deploy', [PortfolioController::class, 'deploy']);
Route::post('/portfolios/{portfolio}/upload', [PortfolioController::class, 'upload']);
Route::post('/deploy', [StaticSiteController::class, 'deploy']);
});