Token Crud on console + Mail on create and destroy
This commit is contained in:
parent
28f95934ed
commit
7166d9a097
14 changed files with 717 additions and 4 deletions
137
app/Console/Commands/Api/TokenCrud.php
Normal file
137
app/Console/Commands/Api/TokenCrud.php
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands\Api;
|
||||
|
||||
use App\Mail\Api\ApiTokenCreated;
|
||||
use App\Mail\Api\ApiTokenRemoved;
|
||||
use App\Models\Api\ApiToken;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class TokenCrud extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'api:token
|
||||
{action? : Can be list, add, remove, default is list}
|
||||
{api_token? : Only if action is remove, pass the ID to remove}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Manage api tokens';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return inteager
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
switch ($this->argument('action')) {
|
||||
case null:
|
||||
case 'list':
|
||||
$this->table(['id', 'name', 'token_date'], ApiToken::all()->map(function (ApiToken $apiToken) {
|
||||
return [
|
||||
'id' => $apiToken->id,
|
||||
'name' => $apiToken->name,
|
||||
'token_date' => $apiToken->token_date,
|
||||
];
|
||||
}));
|
||||
return 0;
|
||||
case 'add':
|
||||
return $this->createApiToken();
|
||||
case 'remove':
|
||||
return $this->removeApiToken();
|
||||
default:
|
||||
$this->error(\sprintf(
|
||||
'action \'%s\' is not availaible, use --help to see usage.',
|
||||
$this->argument('action')
|
||||
));
|
||||
return -1;
|
||||
} //end switch
|
||||
}
|
||||
|
||||
/**
|
||||
* Create api Token
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
private function createApiToken(): int
|
||||
{
|
||||
return DB::transaction(function () {
|
||||
$apiToken = new ApiToken();
|
||||
do {
|
||||
if (!($apiToken->name = $this->ask('Give your token a name'))) {
|
||||
$this->warn('Please provide a valid name.');
|
||||
}
|
||||
} while (!$apiToken->name);
|
||||
$publicToken = $apiToken->generatePublicToken();
|
||||
$privateToken = $apiToken->generatePrivateToken();
|
||||
if (
|
||||
!$this->confirm(
|
||||
"Are you should you want to create the following '{$apiToken->name}'"
|
||||
)
|
||||
) {
|
||||
$this->info('Nothing was created.');
|
||||
return 0;
|
||||
}
|
||||
$apiToken->saveOrFail();
|
||||
|
||||
Mail::send(new ApiTokenCreated($apiToken));
|
||||
|
||||
$this->alert("
|
||||
Your new api Token for '{$apiToken->id}' named '{$apiToken->name}'
|
||||
public: {$publicToken}
|
||||
private: {$privateToken}
|
||||
|
||||
Please take note as it wont be available to display anymore !
|
||||
");
|
||||
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove Api token
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
private function removeApiToken(): int
|
||||
{
|
||||
return DB::transaction(function () {
|
||||
if (!\is_numeric($apiTokenId = $this->argument('api_token'))) {
|
||||
$this->error('remove command needs an id, use `list` to see all.');
|
||||
return -1;
|
||||
}
|
||||
/** @var \App\Models\Api\ApiToken|null */
|
||||
if (!($apiToken = ApiToken::where('id', $apiTokenId)->first())) {
|
||||
$this->error("api_token '{$apiTokenId}' was not found");
|
||||
return -1;
|
||||
}
|
||||
if (
|
||||
!$this->confirm(
|
||||
"Are you sur you want to remove apiToken '{$apiToken->id}' '{$apiToken->name}' ?"
|
||||
)
|
||||
) {
|
||||
$this->info('Nothing was deleted.');
|
||||
return 0;
|
||||
}
|
||||
if (!$apiToken->deleteOrFail()) {
|
||||
$this->error('removing apiToken failed');
|
||||
}
|
||||
|
||||
Mail::send(new ApiTokenRemoved($apiToken));
|
||||
|
||||
$this->alert("apiToken '{$apiToken->id}' '{$apiToken->name}' has been removed !");
|
||||
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
10
app/Exceptions/Api/DamException.php
Normal file
10
app/Exceptions/Api/DamException.php
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace App\Exceptions\Api;
|
||||
|
||||
/**
|
||||
* Unhandled error that occus within DAM.
|
||||
*/
|
||||
class DamException extends \RuntimeException
|
||||
{
|
||||
}
|
||||
165
app/Lib/Helper.php
Normal file
165
app/Lib/Helper.php
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
<?php
|
||||
|
||||
namespace App\Lib;
|
||||
|
||||
use App\Exceptions\Api\DamException;
|
||||
use Illuminate\Contracts\Encryption\DecryptException;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* Helper Class
|
||||
*/
|
||||
class Helper
|
||||
{
|
||||
/**
|
||||
* Package infos
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $packageInfos;
|
||||
|
||||
/**
|
||||
* Tells if the request is within api routes
|
||||
*
|
||||
* @param Request $request
|
||||
* @return boolean
|
||||
*/
|
||||
public static function isRequestForApi(Request $request): bool
|
||||
{
|
||||
// * Small hack to ensure to know if route is From APIv1.
|
||||
$routePrefix = (strpos(static::getRoutePrefix($request), 'api/') ? 'api/' : null) ??
|
||||
(strpos($request->path(), 'api/') === 0 ? 'api/' : null) ?? 'none';
|
||||
return strpos($routePrefix, 'api/') === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to get current route name
|
||||
*
|
||||
* @param Request $request
|
||||
* @return string|null
|
||||
*/
|
||||
public static function getRouteName(Request $request)
|
||||
{
|
||||
return Route::currentRouteName() ?? ($request->route() ? $request->route()->getName() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bearer token from request
|
||||
*
|
||||
* @param Request $request
|
||||
* @return string|null
|
||||
*/
|
||||
public static function getBearerTokenFromRequest(Request $request): ?string
|
||||
{
|
||||
$header = $request->header('Authorization', '');
|
||||
|
||||
if (Str::contains($header, 'Bearer ')) {
|
||||
$auths = \explode(',', $header);
|
||||
foreach ($auths as $auth) {
|
||||
if (Str::contains($auth, 'Bearer ')) {
|
||||
return Str::substr($auth, 7);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to get current route prefix
|
||||
*
|
||||
* @param Request $request
|
||||
* @return string|null
|
||||
*/
|
||||
public static function getRoutePrefix(Request $request)
|
||||
{
|
||||
return (Route::getCurrentRoute() ? Route::getCurrentRoute()->getPrefix() : null) ??
|
||||
($request->route() ? $request->route()->getPrefix() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to get route from request
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Routing\Route|null
|
||||
*/
|
||||
public static function getRoute(Request $request)
|
||||
{
|
||||
return Route::getRoutes()->getByName(static::getRouteName($request));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get composer.json infos
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getPackageInfo(): array
|
||||
{
|
||||
if (!static::$packageInfos) {
|
||||
static::$packageInfos = \json_decode(\file_get_contents(__DIR__ . '/../../composer.json'), true);
|
||||
}
|
||||
return static::$packageInfos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the request signature
|
||||
*
|
||||
* @param string $secret
|
||||
* @param string $uri
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
* @return string request signature
|
||||
* @throws \App\Exceptions\Api\DamException If an error occurs.
|
||||
*/
|
||||
public static function signRequest(string $secret, string $uri, string $method, array $parameters): string
|
||||
{
|
||||
try {
|
||||
$uri = collect(\parse_url($uri));
|
||||
$method = \strtolower($method);
|
||||
|
||||
// * Remove signature from parameters to calculate the hashmac.
|
||||
$signature = collect([
|
||||
'uri' => sprintf(
|
||||
'%s://%s%s',
|
||||
$uri->get('scheme'),
|
||||
$uri->get('host'),
|
||||
$uri->get('path')
|
||||
),
|
||||
'method' => $method
|
||||
]);
|
||||
|
||||
$parameters = collect(Arr::flatten($parameters));
|
||||
|
||||
// * Remove signature from parameters.
|
||||
$parameters->pull('signature');
|
||||
|
||||
// * Natural sort all parameters.
|
||||
$parameters = $parameters->sortKeys(\SORT_NATURAL)
|
||||
->map(function ($value, $key) {
|
||||
return sprintf('%s=%s', \rawurlencode($key), \rawurlencode($value));
|
||||
});
|
||||
|
||||
$signature->push($parameters->implode('&'));
|
||||
|
||||
$calculatedHash = base64_encode(hash_hmac(
|
||||
'sha256',
|
||||
$signature->implode('\n'),
|
||||
Crypt::decryptString($secret),
|
||||
true
|
||||
));
|
||||
|
||||
if (!$calculatedHash) {
|
||||
throw new DamException('Failed to calculate requests hash');
|
||||
}
|
||||
|
||||
return $calculatedHash;
|
||||
} catch (DecryptException $e) {
|
||||
throw new DamException('Failed to decrypt service credentials', 0, $e);
|
||||
} catch (\Exception $e) {
|
||||
throw new DamException('An error occured when authenticating service', 0, $e);
|
||||
} //end try
|
||||
}
|
||||
}
|
||||
42
app/Mail/Api/ApiTokenCreated.php
Normal file
42
app/Mail/Api/ApiTokenCreated.php
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace App\Mail\Api;
|
||||
|
||||
use App\Models\Api\ApiToken;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ApiTokenCreated extends Mailable
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var \App\Models\Api\ApiToken
|
||||
*/
|
||||
private $apiToken = null;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @param \App\Models\Api\ApiToken $apiToken
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(ApiToken $apiToken)
|
||||
{
|
||||
$this->apiToken = $apiToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the message.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
return $this->markdown('emails.apiTokens.created', [
|
||||
'apiToken' => $this->apiToken
|
||||
])->subject(trans('!!! :appname a new Api Token has been added !!!', ['appname' => config('app.name')]))
|
||||
->to(config('mail.contactsList.serviceweb'));
|
||||
}
|
||||
}
|
||||
42
app/Mail/Api/ApiTokenRemoved.php
Normal file
42
app/Mail/Api/ApiTokenRemoved.php
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace App\Mail\Api;
|
||||
|
||||
use App\Models\Api\ApiToken;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ApiTokenRemoved extends Mailable
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var \App\Models\Api\ApiToken
|
||||
*/
|
||||
private $apiToken = null;
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
*
|
||||
* @param \App\Models\Api\ApiToken $apiToken
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(ApiToken $apiToken)
|
||||
{
|
||||
$this->apiToken = $apiToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the message.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
return $this->markdown('emails.apiTokens.removed', [
|
||||
'apiToken' => $this->apiToken
|
||||
])->subject(trans('!!! :appname an Api Token has been removed !!!', ['appname' => config('app.name')]))
|
||||
->to(config('mail.contactsList.serviceweb'));
|
||||
}
|
||||
}
|
||||
139
app/Models/Api/ApiToken.php
Normal file
139
app/Models/Api/ApiToken.php
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models\Api;
|
||||
|
||||
use App\Lib\Helper;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Str;
|
||||
use Rennokki\QueryCache\Traits\QueryCacheable;
|
||||
|
||||
class ApiToken extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use QueryCacheable;
|
||||
|
||||
// TODO: Ajouter aussi stats.
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'token_date' => 'datetime'
|
||||
];
|
||||
|
||||
/**
|
||||
* Perform any actions required after the model boots.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function booted()
|
||||
{
|
||||
static::creating(function (self $model) {
|
||||
if (!$model->public_token) {
|
||||
$model->generatePublicToken();
|
||||
}
|
||||
if (!$model->private_token) {
|
||||
$model->generatePrivateToken();
|
||||
}
|
||||
});
|
||||
static::created(function () {
|
||||
// * Flush Eloquent cache.
|
||||
self::flushQueryCache();
|
||||
});
|
||||
static::updated(function () {
|
||||
// * Flush Eloquent cache.
|
||||
self::flushQueryCache();
|
||||
});
|
||||
static::deleted(function () {
|
||||
// * Flush Eloquent cache.
|
||||
self::flushQueryCache();
|
||||
});
|
||||
}
|
||||
|
||||
// * METHODS
|
||||
|
||||
/**
|
||||
* Generates new public token
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function generatePublicToken(): string
|
||||
{
|
||||
$this->public_token = hash('ripemd160', Str::uuid());
|
||||
$this->token_date = now();
|
||||
return $this->public_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates new private token
|
||||
* It store the crypted private token in model
|
||||
* and returns the plain private token
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function generatePrivateToken(): string
|
||||
{
|
||||
$pwd = hash('sha256', Str::uuid());
|
||||
$this->private_token = Crypt::encryptString($pwd);
|
||||
$this->token_date = now();
|
||||
return $pwd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate the request for this service
|
||||
*
|
||||
* This will check hash-mac and that the request is wellformed
|
||||
*
|
||||
* The request should have the minimum following parameters
|
||||
* - timestamp using format Y-m-d H:i:s, and must be UTC (Greenwich Mean Time)
|
||||
* - bearerToken the public token generated by the crm
|
||||
* - signature the hashmac signature of the request
|
||||
*
|
||||
* ! Signature must be calculated with every parameter urlencode once only
|
||||
* ! All parameters to calculate the signature must be sorted (natural sort asc)
|
||||
*
|
||||
* ! Signature should look like
|
||||
* * httpVerb\n
|
||||
* * uri\n
|
||||
* * queryString
|
||||
*
|
||||
* ! httpVerb as well as uri must be lower case
|
||||
* ! uri should include scheme, host and path and nothing else, if path is empty a trailing slash should be added
|
||||
* ! eg: https://ldc-crm.fr/customer/1 or https://ldc-crm.fr/
|
||||
* ! The query string shall be separated with '&', eg param1=value1¶m2=value2
|
||||
* ! Key names and values of the query string must be url encoded using RFC 3986
|
||||
* ! http://www.faqs.org/rfcs/rfc3986.html
|
||||
* ! Signature must be hmac sha256 using the private key generatedby the crm
|
||||
*
|
||||
* * ! They should then be concat in a string separated by \n
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return boolean
|
||||
* @throws \App\Exceptions\Api\V2\CrmException If an error occurs.
|
||||
*/
|
||||
public function authenticateApi(Request $request): bool
|
||||
{
|
||||
// ! Hack to prevent Laravel to cast empty strings to null or the opposite.
|
||||
// ! If cannot decode json user legacy all() method.
|
||||
$data = \json_decode($request->getContent(), true);
|
||||
$data = (\is_array($data) and \json_last_error() === \JSON_ERROR_NONE) ?
|
||||
array_replace_recursive($request->all(), $data) : $request->all();
|
||||
|
||||
$calculatedHash = Helper::signRequest(
|
||||
$this->private_token,
|
||||
$request->getUri(),
|
||||
$request->getMethod(),
|
||||
$data
|
||||
);
|
||||
|
||||
// ! Très important hash_equals https://fr.wikipedia.org/wiki/Attaque_temporelle
|
||||
return \hash_equals($calculatedHash, $request->signature);
|
||||
}
|
||||
}
|
||||
|
|
@ -24,7 +24,8 @@
|
|||
"laravelcollective/html": "^6.3",
|
||||
"ldc/web-status-checker-laravel": "^1.0",
|
||||
"mews/purifier": "^3.3",
|
||||
"pion/laravel-chunk-upload": "^1.5"
|
||||
"pion/laravel-chunk-upload": "^1.5",
|
||||
"rennokki/laravel-eloquent-query-cache": "^3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"fakerphp/faker": "^1.9.1",
|
||||
|
|
|
|||
69
composer.lock
generated
69
composer.lock
generated
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "aa7eb721113c779f78e7abc7a0318ee8",
|
||||
"content-hash": "77f343483e87b0d4403a8b8209b33bd9",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adldap2/adldap2",
|
||||
|
|
@ -4251,6 +4251,73 @@
|
|||
],
|
||||
"time": "2022-02-11T10:27:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "rennokki/laravel-eloquent-query-cache",
|
||||
"version": "3.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/renoki-co/laravel-eloquent-query-cache.git",
|
||||
"reference": "00e73a7050bedca315c71bf433d0c283f8a73fbc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/renoki-co/laravel-eloquent-query-cache/zipball/00e73a7050bedca315c71bf433d0c283f8a73fbc",
|
||||
"reference": "00e73a7050bedca315c71bf433d0c283f8a73fbc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/database": "^8.83|^9.0.1",
|
||||
"illuminate/support": "^8.83|^9.0.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"chelout/laravel-relationship-events": "^1.5",
|
||||
"laravel/legacy-factories": "^1.3",
|
||||
"mockery/mockery": "^1.5",
|
||||
"orchestra/database": "^6.28|^7.0",
|
||||
"orchestra/testbench": "^6.28|^7.0",
|
||||
"orchestra/testbench-core": "^6.28|^7.0",
|
||||
"phpunit/phpunit": "^9.5.13"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Rennokki\\QueryCache\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"Apache-2.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Alex Renoki",
|
||||
"email": "alex@renoki.org",
|
||||
"homepage": "https://github.com/rennokki",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Adding cache on your Laravel Eloquent queries' results is now a breeze.",
|
||||
"homepage": "https://github.com/renoki-co/laravel-eloquent-query-cache",
|
||||
"keywords": [
|
||||
"caching",
|
||||
"eloquent",
|
||||
"laravel",
|
||||
"query",
|
||||
"remember",
|
||||
"sql"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/renoki-co/laravel-eloquent-query-cache/issues",
|
||||
"source": "https://github.com/renoki-co/laravel-eloquent-query-cache/tree/3.3.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/rennokki",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2022-02-12T19:37:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v6.1.2",
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ return [
|
|||
|
||||
// * Contacts List
|
||||
'contactsList' => [
|
||||
'invalidXml' => env('MAIL_LIST_SERVICEWEB', 'equipe.web@ldc.fr'),
|
||||
'serviceweb' => env('MAIL_LIST_SERVICEWEB', 'equipe.web@ldc.fr')
|
||||
'invalidXml' => preg_split('/(\s*,*\s*)*,+(\s*,*\s*)*/', env('MAIL_LIST_SERVICEWEB', 'equipe.web@ldc.fr')),
|
||||
'serviceweb' => preg_split('/(\s*,*\s*)*,+(\s*,*\s*)*/', env('MAIL_LIST_SERVICEWEB', 'equipe.web@ldc.fr'))
|
||||
]
|
||||
];
|
||||
|
|
|
|||
23
database/factories/Api/ApiTokenFactory.php
Normal file
23
database/factories/Api/ApiTokenFactory.php
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Factories\Api;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\ApiTokenFactory>
|
||||
*/
|
||||
class ApiTokenFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition()
|
||||
{
|
||||
return [
|
||||
'name' => $this->faker->name() . ' Token',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('api_tokens', function (Blueprint $table) {
|
||||
$table->id();
|
||||
|
||||
$table->string('name')->comment('Token name');
|
||||
|
||||
$table->string('public_token', 40)
|
||||
->comment('The public token encrypted');
|
||||
$table->string('private_token', 312)
|
||||
->comment('The private token encrypted');
|
||||
|
||||
$table->timestamp('token_date')->useCurrent()
|
||||
->comment('The token generation date');
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('api_tokens');
|
||||
}
|
||||
};
|
||||
21
database/seeders/ApiTokenSeeder.php
Normal file
21
database/seeders/ApiTokenSeeder.php
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Api\ApiToken;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class ApiTokenSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
DB::table('api_tokens')->truncate();
|
||||
ApiToken::factory(10)->create();
|
||||
}
|
||||
}
|
||||
10
resources/views/emails/apiTokens/created.blade.php
Normal file
10
resources/views/emails/apiTokens/created.blade.php
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
@component('mail::message')
|
||||
# !! {{ __('A new Api Token has been created') }} !!
|
||||
|
||||
{{ now() }}<br>
|
||||
{{ __('Token name \':name\'', ['name' => $apiToken->name]) }}
|
||||
|
||||
|
||||
{{ __('Thanks') }},<br>
|
||||
{{ config('app.name') }}
|
||||
@endcomponent
|
||||
14
resources/views/emails/apiTokens/removed.blade.php
Normal file
14
resources/views/emails/apiTokens/removed.blade.php
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
@component('mail::message')
|
||||
# !! {{ __('An Api Token has been removed') }} !!
|
||||
|
||||
{{ __('The concerned service wont have acces to :appname anymore.', [
|
||||
'appname' => config('app.name')
|
||||
]) }}
|
||||
|
||||
{{ now() }}<br>
|
||||
{{ __('Token name \':name\'', ['name' => $apiToken->name]) }}
|
||||
|
||||
|
||||
{{ __('Thanks') }},<br>
|
||||
{{ config('app.name') }}
|
||||
@endcomponent
|
||||
Loading…
Add table
Reference in a new issue