Merge branch 'develop'
# Conflicts: # public/js/10.js # public/js/11.js # public/js/13.js # public/js/14.js # public/js/2.js # public/js/20.js # public/js/21.js # public/js/22.js # public/js/23.js # public/js/3.js # public/js/8.js # public/js/9.js # public/js/app.js
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
APP_NAME=Laravel
|
||||
APP_ENV=local
|
||||
APP_ENV=production
|
||||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
APP_DEBUG=false
|
||||
APP_URL=http://localhost
|
||||
APP_DEMO=false
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ class SettingController extends Controller
|
||||
'documentation' => setting('documentation'),
|
||||
'allow_registration' => setting('allow_registration'),
|
||||
'default_package' => setting('default_package'),
|
||||
'enable_api' => setting('enable_api'),
|
||||
'api_token' => setting('api_token') ? decrypt(setting('api_token')) : null,
|
||||
];
|
||||
|
||||
$packages = Package::pluck('name', 'id');
|
||||
@@ -37,8 +39,14 @@ class SettingController extends Controller
|
||||
'support_emails',
|
||||
'allow_registration',
|
||||
'documentation',
|
||||
'default_package'
|
||||
'default_package',
|
||||
'enable_api',
|
||||
'api_token',
|
||||
]) as $key => $value) {
|
||||
if ($key === 'api_token') {
|
||||
$value = encrypt($value);
|
||||
}
|
||||
|
||||
setting([$key => $value]);
|
||||
}
|
||||
|
||||
|
||||
29
app/Http/Controllers/Api/UserController.php
Normal file
29
app/Http/Controllers/Api/UserController.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Api\UserRequest;
|
||||
use App\Http\Resources\Api\UserResource;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return UserResource::collection(User::latest()->paginate());
|
||||
}
|
||||
|
||||
public function store(UserRequest $request)
|
||||
{
|
||||
$user = User::create($request->validated());
|
||||
|
||||
return new UserResource($user);
|
||||
}
|
||||
|
||||
public function show($id)
|
||||
{
|
||||
return new UserResource(User::findOrFail($id));
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,11 @@ class Kernel extends HttpKernel
|
||||
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
||||
];
|
||||
|
||||
protected $middlewarePriority = [
|
||||
\Inertia\Middleware::class,
|
||||
\App\Http\Middleware\Demo::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* The application's route middleware groups.
|
||||
*
|
||||
@@ -63,6 +68,7 @@ class Kernel extends HttpKernel
|
||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||
'can' => \Illuminate\Auth\Middleware\Authorize::class,
|
||||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||
'global.api.authenticated' => \App\Http\Middleware\GlobalApiAuthenticated::class,
|
||||
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
|
||||
'role' => \App\Http\Middleware\RoleMiddleware::class,
|
||||
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
|
||||
|
||||
35
app/Http/Middleware/GlobalApiAuthenticated.php
Normal file
35
app/Http/Middleware/GlobalApiAuthenticated.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Services\Ploi\Exceptions\Http\Unauthenticated;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class GlobalApiAuthenticated
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if (!$this->isAuthenticated($request)) {
|
||||
throw new Unauthenticated('Unauthenticated for global access.');
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
protected function isAuthenticated(Request $request)
|
||||
{
|
||||
return
|
||||
setting('enable_api') &&
|
||||
setting('api_token') &&
|
||||
$request->bearerToken() &&
|
||||
$request->bearerToken() === decrypt(setting('api_token'));
|
||||
}
|
||||
}
|
||||
41
app/Http/Requests/Api/UserRequest.php
Normal file
41
app/Http/Requests/Api/UserRequest.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\Api;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class UserRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return $this->bearerToken() && $this->bearerToken() === setting('api_token');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'name' => [
|
||||
'required',
|
||||
'string',
|
||||
'max:255'
|
||||
],
|
||||
'email' => [
|
||||
'required',
|
||||
'string',
|
||||
'email',
|
||||
'max:255',
|
||||
'unique:users'
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
25
app/Http/Resources/Api/UserResource.php
Normal file
25
app/Http/Resources/Api/UserResource.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources\Api;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class UserResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'avatar' => $this->avatar,
|
||||
'name' => $this->name,
|
||||
'email' => $this->email,
|
||||
'created_at' => $this->created_at,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -29,17 +29,11 @@ class AppServiceProvider extends ServiceProvider
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
$this->registerInertia();
|
||||
$this->registerLengthAwarePaginator();
|
||||
if (!$this->app->request->is('api*')) {
|
||||
$this->registerInertia();
|
||||
$this->registerLengthAwarePaginator();
|
||||
}
|
||||
}
|
||||
|
||||
public function registerInertia()
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Cache\RateLimiting\Limit;
|
||||
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\RateLimiter;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
class RouteServiceProvider extends ServiceProvider
|
||||
{
|
||||
@@ -30,35 +33,37 @@ class RouteServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
//
|
||||
$this->configureRateLimiting();
|
||||
|
||||
parent::boot();
|
||||
$this->routes(function () {
|
||||
if (setting('enable_api')) {
|
||||
Route::prefix('api')
|
||||
->middleware('api')
|
||||
->namespace($this->namespace . '\Api')
|
||||
->group(base_path('routes/api.php'));
|
||||
}
|
||||
|
||||
Route::middleware('web')
|
||||
->namespace($this->namespace)
|
||||
->group(base_path('routes/web.php'));
|
||||
|
||||
Route::middleware(['web', 'auth', 'role:admin'])
|
||||
->prefix('admin')
|
||||
->as('admin.')
|
||||
->namespace($this->namespace . '\\Admin')
|
||||
->group(base_path('routes/admin.php'));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the routes for the application.
|
||||
* Configure the rate limiters for the application.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function map()
|
||||
protected function configureRateLimiting()
|
||||
{
|
||||
$this->mapWebRoutes();
|
||||
$this->mapAdminRoutes();
|
||||
}
|
||||
|
||||
protected function mapWebRoutes()
|
||||
{
|
||||
Route::middleware('web')
|
||||
->namespace($this->namespace)
|
||||
->group(base_path('routes/web.php'));
|
||||
}
|
||||
|
||||
protected function mapAdminRoutes()
|
||||
{
|
||||
Route::middleware(['web', 'auth', 'role:admin'])
|
||||
->prefix('admin')
|
||||
->as('admin.')
|
||||
->namespace($this->namespace .'\\Admin')
|
||||
->group(base_path('routes/admin.php'));
|
||||
RateLimiter::for('api', function (Request $request) {
|
||||
return Limit::perMinute(60);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
1854
public/js/10.js
vendored
1854
public/js/10.js
vendored
File diff suppressed because one or more lines are too long
1686
public/js/11.js
vendored
1686
public/js/11.js
vendored
File diff suppressed because one or more lines are too long
1632
public/js/13.js
vendored
1632
public/js/13.js
vendored
File diff suppressed because one or more lines are too long
2076
public/js/14.js
vendored
2076
public/js/14.js
vendored
File diff suppressed because one or more lines are too long
885
public/js/2.js
vendored
885
public/js/2.js
vendored
File diff suppressed because one or more lines are too long
1524
public/js/20.js
vendored
1524
public/js/20.js
vendored
File diff suppressed because one or more lines are too long
1149
public/js/21.js
vendored
1149
public/js/21.js
vendored
File diff suppressed because one or more lines are too long
1345
public/js/22.js
vendored
1345
public/js/22.js
vendored
File diff suppressed because one or more lines are too long
1165
public/js/23.js
vendored
1165
public/js/23.js
vendored
File diff suppressed because one or more lines are too long
816
public/js/3.js
vendored
816
public/js/3.js
vendored
File diff suppressed because one or more lines are too long
1844
public/js/8.js
vendored
1844
public/js/8.js
vendored
File diff suppressed because one or more lines are too long
1912
public/js/9.js
vendored
1912
public/js/9.js
vendored
File diff suppressed because one or more lines are too long
21946
public/js/app.js
vendored
21946
public/js/app.js
vendored
File diff suppressed because one or more lines are too long
@@ -63,6 +63,18 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input id="enable_api" class="form-checkbox" type="checkbox"
|
||||
v-model="form.enable_api">
|
||||
<label for="enable_api" class="ml-2 text-sm">{{ __('Enable API') }}</label>
|
||||
<p class="text-small mt-1 text-medium-emphasis">
|
||||
{{ __('This will allow you to interact with your system via the API.') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<FormInput v-if="form.enable_api" allow-random-string :label="__('API token')" :errors="$page.errors.api_token"
|
||||
v-model="form.api_token"/>
|
||||
|
||||
<FormActions>
|
||||
<Button>{{ __('Save changes') }}</Button>
|
||||
</FormActions>
|
||||
@@ -140,6 +152,8 @@
|
||||
email: this.company_settings.email,
|
||||
support_emails: this.company_settings.support_emails,
|
||||
support: this.company_settings.support,
|
||||
enable_api: this.company_settings.enable_api,
|
||||
api_token: this.company_settings.api_token,
|
||||
documentation: this.company_settings.documentation,
|
||||
allow_registration: this.company_settings.allow_registration,
|
||||
default_package: this.company_settings.default_package,
|
||||
@@ -158,7 +172,9 @@
|
||||
submit() {
|
||||
this.sending = true
|
||||
|
||||
this.$inertia.patch(this.route('admin.settings.update'), this.form)
|
||||
this.$inertia.patch(this.route('admin.settings.update'), this.form, {
|
||||
preserveScroll: true
|
||||
})
|
||||
.then(() => {
|
||||
this.sending = false;
|
||||
})
|
||||
|
||||
@@ -18,9 +18,6 @@
|
||||
<template #segments>
|
||||
<SettingsSegment>
|
||||
<template #title>{{ __('Edit') }}</template>
|
||||
<template #subtitle>
|
||||
Form
|
||||
</template>
|
||||
<template #form>
|
||||
<form class="space-y-4" @submit.prevent="submit">
|
||||
<FormInput :label="__('Name')" :errors="$page.errors.name" v-model="form.name" />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<FormGroup class="relative">
|
||||
<FormGroup class="relative max-w-lg">
|
||||
<Label :errors="errors" :forId="id">{{ label }}</Label>
|
||||
|
||||
<button type="button" @click="copy" v-if="allowCopy" class="flex items-center right-0 absolute text-xs text-medium-emphasis">
|
||||
@@ -7,6 +7,11 @@
|
||||
{{ copyText }}
|
||||
</button>
|
||||
|
||||
<button type="button" @click="generateString" v-if="allowRandomString" class="flex items-center right-0 absolute text-xs text-medium-emphasis">
|
||||
<IconKey class="mr-2" />
|
||||
{{ __('Generate') }}
|
||||
</button>
|
||||
|
||||
<input :id="id"
|
||||
:class="[defaultClasses]"
|
||||
:type="type"
|
||||
@@ -16,6 +21,7 @@
|
||||
:placeholder="placeholder" />
|
||||
<ErrorText v-if="errors">{{ errors[0] }}</ErrorText>
|
||||
<HelperText v-if="helperText && !errors">{{ helperText }}</HelperText>
|
||||
|
||||
</FormGroup>
|
||||
</template>
|
||||
|
||||
@@ -25,9 +31,10 @@ import Label from '@/components/Label'
|
||||
import ErrorText from '@/components/ErrorText'
|
||||
import HelperText from '@/components/HelperText'
|
||||
import IconClipboard from '@/components/icons/IconClipboard'
|
||||
import IconKey from '@/components/icons/IconKey'
|
||||
|
||||
const defaultClasses =
|
||||
'w-full border-medium-emphasis text-body h-10 max-w-lg px-2 border rounded bg-surface-1 focus:outline-none focus:border-primary'
|
||||
'w-full border-medium-emphasis text-body h-10 px-2 border rounded bg-surface-1 focus:outline-none focus:border-primary'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
@@ -64,6 +71,11 @@ export default {
|
||||
required: false,
|
||||
default: false,
|
||||
type: Boolean
|
||||
},
|
||||
allowRandomString: {
|
||||
required: false,
|
||||
default: false,
|
||||
type: Boolean
|
||||
}
|
||||
},
|
||||
|
||||
@@ -73,6 +85,7 @@ export default {
|
||||
ErrorText,
|
||||
HelperText,
|
||||
IconClipboard,
|
||||
IconKey,
|
||||
},
|
||||
|
||||
data() {
|
||||
@@ -103,6 +116,9 @@ export default {
|
||||
|
||||
this.$copyText(this.value);
|
||||
},
|
||||
generateString() {
|
||||
this.$emit('input', this.randomString());
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
|
||||
6
resources/js/components/icons/IconKey.vue
Normal file
6
resources/js/components/icons/IconKey.vue
Normal file
@@ -0,0 +1,6 @@
|
||||
<template>
|
||||
<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-key" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" d="M0 8a4 4 0 0 1 7.465-2H14a.5.5 0 0 1 .354.146l1.5 1.5a.5.5 0 0 1 0 .708l-1.5 1.5a.5.5 0 0 1-.708 0L13 9.207l-.646.647a.5.5 0 0 1-.708 0L11 9.207l-.646.647a.5.5 0 0 1-.708 0L9 9.207l-.646.647A.5.5 0 0 1 8 10h-.535A4 4 0 0 1 0 8zm4-3a3 3 0 1 0 2.712 4.285A.5.5 0 0 1 7.163 9h.63l.853-.854a.5.5 0 0 1 .708 0l.646.647.646-.647a.5.5 0 0 1 .708 0l.646.647.646-.647a.5.5 0 0 1 .708 0l.646.647.793-.793-1-1h-6.63a.5.5 0 0 1-.451-.285A3 3 0 0 0 4 5z"/>
|
||||
<path d="M4 8a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"/>
|
||||
</svg>
|
||||
</template>
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div class="grid grid-cols-4 gap-16">
|
||||
<aside class="col-span-1">
|
||||
<aside class="col-span-4 md:col-span-1">
|
||||
<slot name="nav" />
|
||||
</aside>
|
||||
<section class="col-span-3">
|
||||
<section class="col-span-4 md:col-span-3">
|
||||
<div class="space-y-16">
|
||||
<slot name="segments"></slot>
|
||||
</div>
|
||||
|
||||
9
resources/js/mixins.js
vendored
9
resources/js/mixins.js
vendored
@@ -24,5 +24,14 @@ module.exports = {
|
||||
|
||||
return splitted[0];
|
||||
},
|
||||
|
||||
randomString() {
|
||||
let m = m || 20;
|
||||
let s = '', r = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
for (let i = 0; i < m; i++) {
|
||||
s += r.charAt(Math.floor(Math.random() * r.length));
|
||||
}
|
||||
return s;
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
22
routes/api.php
Normal file
22
routes/api.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| API Routes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you can register API routes for your application. These
|
||||
| routes are loaded by the RouteServiceProvider within a group which
|
||||
| is assigned the "api" middleware group. Enjoy building your API!
|
||||
|
|
||||
*/
|
||||
|
||||
Route::group(['middleware' => 'global.api.authenticated'], function () {
|
||||
Route::group(['prefix' => 'users'], function () {
|
||||
Route::get('/', 'UserController@index');
|
||||
Route::post('/', 'UserController@store');
|
||||
Route::get('{user}', 'UserController@show');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user