Commit 4ad0a7b3 authored by 朱招明's avatar 朱招明

权限相关接口

parent 116df568
...@@ -64,3 +64,5 @@ VITE_PUSHER_PORT="${PUSHER_PORT}" ...@@ -64,3 +64,5 @@ VITE_PUSHER_PORT="${PUSHER_PORT}"
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}" VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
L5_SWAGGER_GENERATE_ALWAYS = true
...@@ -17,3 +17,5 @@ yarn-error.log ...@@ -17,3 +17,5 @@ yarn-error.log
/.fleet /.fleet
/.idea /.idea
/.vscode /.vscode
/storage/api-docs/api-docs.json
/storage/api-docs/*.json
<?php
/**
* @desc
* @author [ZZM]
* @since 2023/10/23
* @copyright
*/
namespace Modules\Admin\ApiDocs;
/**
*
* @OA\OpenApi(
* @OA\Info(
* version="1.0.0",
* title="OA系统接口",
* description="<b>通用状态码</b>:
* 200 成功
* 201 成功创建
* 204 执行成功,没有返回内容
*
* 401 没有登陆
* 403 没有权限
* 404 要操作的资源不存在
* 405 操作方法不允许
* 422 参数验证错误
* 500 程序出现错误
*",
* )
* )
*
*/
class Base
{
}
\ No newline at end of file
<?php <?php
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Migrations\Migration;
...@@ -65,6 +66,24 @@ return new class extends Migration ...@@ -65,6 +66,24 @@ return new class extends Migration
$table->timestamps(); $table->timestamps();
}); });
DB::transaction(function (){
DB::table("admin_users")->insert([
"id" => "1",
"username" => "admin",
"name" => "admin",
"salt" => "4IpZw+?%MD1c",
"password" => password_hash(md5('1234564IpZw+?%MD1c'), PASSWORD_DEFAULT),
]);
DB::table("admin_roles")->insert([
"id" => "1",
"name" => "超级管理员",
"slug" => "超级管理员",
]);
DB::table("admin_role_users")->insert([
"role_id" => "1",
"user_id" => "1",
]);
});
} }
/** /**
......
...@@ -16,25 +16,5 @@ class AdminDatabaseSeeder extends Seeder ...@@ -16,25 +16,5 @@ class AdminDatabaseSeeder extends Seeder
public function run() public function run()
{ {
DB::transaction(function (){
DB::table("admin_users")->insert([
"id" => "1",
"username" => "admin",
"name" => "admin",
"salt" => "4IpZw+?%MD1c",
"password" => password_hash(md5('1234564IpZw+?%MD1c'), PASSWORD_DEFAULT),
]);
DB::table("admin_roles")->insert([
"id" => "1",
"name" => "超级管理员",
"slug" => "超级管理员",
]);
DB::table("admin_role_users")->insert([
"role_id" => "1",
"user_id" => "1",
]);
});
} }
} }
...@@ -10,10 +10,21 @@ namespace Modules\Admin\Entities; ...@@ -10,10 +10,21 @@ namespace Modules\Admin\Entities;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Cache;
use Modules\Admin\Http\Utils\Helper;
class AdminMenu extends Model class AdminMenu extends Model
{ {
protected $fillable = [ protected $fillable = [
'title','uri', 'parent_id', 'icon' 'title','uri', 'parent_id', 'icon'
]; ];
public static function boot()
{
parent::boot();
static::saving(function ($model) {
Helper::getAllMenu(true);
});
}
} }
\ No newline at end of file
...@@ -6,6 +6,7 @@ namespace Modules\Admin\Http\Controllers; ...@@ -6,6 +6,7 @@ namespace Modules\Admin\Http\Controllers;
use Exception; use Exception;
use Dingo\Api\Http\Request; use Dingo\Api\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Modules\Admin\Entities\AdminMenu; use Modules\Admin\Entities\AdminMenu;
use Modules\Admin\Entities\AdminUser; use Modules\Admin\Entities\AdminUser;
...@@ -15,11 +16,41 @@ use Modules\Admin\Http\Utils\Helper; ...@@ -15,11 +16,41 @@ use Modules\Admin\Http\Utils\Helper;
class AuthController extends BaseController class AuthController extends BaseController
{ {
/** /**
* 登录授权 * @OA\Post(
* tags={"基础接口"},
* summary="登录",
* path="api/auth/login",
* @OA\RequestBody(
* @OA\MediaType(
* mediaType="application/x-www-form-urlencoded",
* @OA\Schema(
* type="object",
* required={"username","password"},
* @OA\Property(
* property="username",
* type="string"
* ),
* @OA\Property(
* property="password",
* type="string"
* ),
* )
* )
* ),
* @OA\Response(
* response="201",
* description="登陆成功",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(property="data", type="object", ref="#/components/schemas/Token")
* )
* )
* )
* )
* *
* @param Request $request
*/ */
public function login(Request $request) public function login(Request $request)
{ {
...@@ -44,22 +75,47 @@ class AuthController extends BaseController ...@@ -44,22 +75,47 @@ class AuthController extends BaseController
} }
/** /**
* 刷新token *
* @desc * @OA\Put(
* @author [ZZM] * tags={"基础接口"},
* @since 2023/10/21 * summary="刷新token",
* @modify * path="api/auth/refresh",
* security={
* {"jwt_auth": {}}
* },
* @OA\Response(
* response="201",
* description="刷新成功",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(property="data", type="object", ref="#/components/schemas/Token")
* )
* )
* )
* )
*
*/ */
public function refreshToken(){ public function refreshToken(){
return $this->response->item($this->user, new AccessTokenTransformer(true))->setStatusCode(201); return $this->response->item($this->user, new AccessTokenTransformer(true))->setStatusCode(201);
} }
/** /**
* 登出 *
* @desc * @OA\Put(
* @author [ZZM] * tags={"基础接口"},
* @since 2023/10/21 * summary="登出",
* @modify * path="api/auth/login_out",
* security={
* {"jwt_auth": {}}
* },
* @OA\Response(
* response="204",
* description="登出成功",
* )
* )
*
*/ */
public function loginOut(){ public function loginOut(){
auth('api')->logout(true); auth('api')->logout(true);
...@@ -67,31 +123,34 @@ class AuthController extends BaseController ...@@ -67,31 +123,34 @@ class AuthController extends BaseController
} }
/** /**
* 获取配置
* @desc
* *
* @param Request $request * @OA\Put(
* tags={"基础接口"},
* summary="获取配置",
* path="api/configs",
* security={
* {"jwt_auth": {}}
* },
* @OA\Response(
* response="200",
* description="",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(property="data", type="object", ref="#/components/schemas/Menu")
* )
* )
* )
* )
* *
* @return \Dingo\Api\Http\Response
* @author [ZZM]
* @since 2023/10/21
* @modify
*/ */
public function apiConfig(Request $request) public function apiConfig(Request $request)
{ {
$user = $this->user; $user = $this->user;
#角色
$role = $user->roles()->first(); $role = $user->roles()->first();
if($role->id == 1){
#超级管理员默认获取全部菜单
$menu = AdminMenu::get();
}else{
#菜单
$menu = $role->menu;
}
$menu = $menu->toArray(); $menu = Helper::getRoleMenu($role,true);
$menu = Helper::makeTree($menu); $menu = Helper::makeTree($menu);
$data = [ $data = [
...@@ -100,4 +159,6 @@ class AuthController extends BaseController ...@@ -100,4 +159,6 @@ class AuthController extends BaseController
return $this->response->array(['data'=>$data]); return $this->response->array(['data'=>$data]);
} }
} }
...@@ -9,18 +9,83 @@ ...@@ -9,18 +9,83 @@
namespace Modules\Admin\Http\Controllers; namespace Modules\Admin\Http\Controllers;
use Dingo\Api\Http\Request; use Dingo\Api\Http\Request;
use Illuminate\Support\Facades\DB;
use Modules\Admin\Entities\AdminMenu; use Modules\Admin\Entities\AdminMenu;
use Modules\Admin\Entities\AdminRoleMenu;
use Modules\Admin\Http\Requests\MenuRequest; use Modules\Admin\Http\Requests\MenuRequest;
use Modules\Admin\Http\Transformers\AdminMenuTransformer;
use Modules\Admin\Http\Utils\Helper; use Modules\Admin\Http\Utils\Helper;
class MenuController extends BaseController class MenuController extends BaseController
{ {
/**
* @OA\Get(
* tags={"菜单"},
* summary="列表",
* path="api/menu/list",
* security={
* {"jwt_auth": {}}
* },
* @OA\Response(
* response="200",
* description="",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property="data",
* type="array",
* @OA\Items(ref="#/components/schemas/Menu"),
* description="列表"
* ),
* )
* )
* )
* )
*
*/
public function list(){ public function list(){
$menu = AdminMenu::all()->toArray(); $menu = AdminMenu::all();
$menu = Helper::makeTree($menu); return $this->response->collection($menu,new AdminMenuTransformer());
return $this->response->array(['data'=>$menu]);
} }
/**
* @OA\Post(
* tags={"菜单"},
* summary="添加",
* path="api/menu/add",
* security={
* {"jwt_auth": {}}
* },
* @OA\RequestBody(
* @OA\MediaType(
* mediaType="application/x-www-form-urlencoded",
* @OA\Schema(
* type="object",
* required={"title"},
* @OA\Property(
* property="title",
* type="string"
* ),
* @OA\Property(
* property="uri",
* type="string"
* ),
* @OA\Property(
* property="parent_id",
* type="string"
* ),
* )
* )
* ),
* @OA\Response(
* response="201",
* description="",
* )
* )
*
*/
public function add(MenuRequest $request){ public function add(MenuRequest $request){
$params = $request->all(['title','uri','parent_id']); $params = $request->all(['title','uri','parent_id']);
...@@ -29,16 +94,117 @@ class MenuController extends BaseController ...@@ -29,16 +94,117 @@ class MenuController extends BaseController
return $this->response->noContent()->statusCode(201); return $this->response->noContent()->statusCode(201);
} }
public function detail(){ /**
* @OA\Get(
* tags={"菜单"},
* summary="详情",
* path="api/menu/{id}/detail",
* security={
* {"jwt_auth": {}}
* },
* @OA\Response(
* response="200",
* description="",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(property="data", type="object", ref="#/components/schemas/Menu")
* )
* )
* )
* )
*
*/
public function detail($id){
$menu = AdminMenu::where('id',$id)->first();
if(!$menu){
abort(500,'菜单不存在');
}
return $this->response->item($menu,new AdminMenuTransformer());
} }
public function edit(){ /**
* @OA\Put(
* tags={"菜单"},
* summary="编辑",
* path="api/menu/{id}/edit",
* security={
* {"jwt_auth": {}}
* },
* @OA\RequestBody(
* @OA\MediaType(
* mediaType="application/x-www-form-urlencoded",
* @OA\Schema(
* type="object",
* required={"title"},
* @OA\Property(
* property="title",
* type="string"
* ),
* @OA\Property(
* property="uri",
* type="string"
* ),
* @OA\Property(
* property="parent_id",
* type="string"
* ),
* )
* )
* ),
* @OA\Response(
* response="204",
* description="",
* )
* )
*
*/
public function edit(MenuRequest $request,$id){
$params = $request->all(['title','uri','parent_id']);
$menu = AdminMenu::where('id',$id)->first();
if(!$menu){
abort(500,'菜单不存在');
}
if($params['uri'] && $menu->uri != $params['uri'] && AdminMenu::where('uri',$params['uri'])->first()){
abort(500,'uri重复');
}
$menu->update($params);
return $this->response->noContent()->statusCode(204);
} }
public function delete(){ /**
* @OA\Delete(
* tags={"菜单"},
* summary="删除",
* path="api/menu/{id}/delete",
* security={
* {"jwt_auth": {}}
* },
* @OA\Response(
* response="204",
* description="",
* )
* )
*
*/
public function delete($id){
$menu = AdminMenu::where('id',$id)->first();
if($menu){
DB::transaction(function () use ($menu){
$menu->delete();
AdminRoleMenu::where('menu_id',$menu->id)->delete();
});
}
return $this->response->noContent()->statusCode(204);
} }
} }
\ No newline at end of file
...@@ -13,14 +13,76 @@ use Illuminate\Support\Facades\DB; ...@@ -13,14 +13,76 @@ use Illuminate\Support\Facades\DB;
use Modules\Admin\Entities\AdminMenu; use Modules\Admin\Entities\AdminMenu;
use Modules\Admin\Entities\AdminRole; use Modules\Admin\Entities\AdminRole;
use Modules\Admin\Entities\AdminRoleMenu; use Modules\Admin\Entities\AdminRoleMenu;
use Modules\Admin\Entities\AdminRoleUser;
use Modules\Admin\Http\Requests\RoleRequest; use Modules\Admin\Http\Requests\RoleRequest;
use Modules\Admin\Http\Transformers\AdminRoleTransformer;
class RoleController extends BaseController class RoleController extends BaseController
{ {
/**
* @OA\Get(
* tags={"角色"},
* summary="列表",
* path="api/role/list",
* security={
* {"jwt_auth": {}}
* },
* @OA\Response(
* response="200",
* description="",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property="data",
* type="array",
* @OA\Items(ref="#/components/schemas/Role"),
* description="列表"
* ),
* )
* )
* )
* )
*
*/
public function list(){ public function list(){
$roles = AdminRole::all();
return $this->response->collection($roles,new AdminRoleTransformer());
} }
/**
* @OA\Post(
* tags={"角色"},
* summary="添加",
* path="api/role/add",
* security={
* {"jwt_auth": {}}
* },
* @OA\RequestBody(
* @OA\MediaType(
* mediaType="application/x-www-form-urlencoded",
* @OA\Schema(
* type="object",
* required={"name","slug",},
* @OA\Property(
* property="name",
* type="string"
* ),
* @OA\Property(
* property="slug",
* type="string"
* ),
* )
* )
* ),
* @OA\Response(
* response="201",
* description="",
* )
* )
*
*/
public function add(RoleRequest $request){ public function add(RoleRequest $request){
$params = $request->all(['name','slug']); $params = $request->all(['name','slug']);
...@@ -29,22 +91,79 @@ class RoleController extends BaseController ...@@ -29,22 +91,79 @@ class RoleController extends BaseController
return $this->response->noContent()->statusCode(201); return $this->response->noContent()->statusCode(201);
} }
public function detail(){ /**
* @OA\Get(
} * tags={"角色"},
* summary="详情",
public function edit(){ * path="api/role/{id}/detail",
* security={
* {"jwt_auth": {}}
* },
* @OA\Response(
* response="200",
* description="",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(property="data", type="object", ref="#/components/schemas/Role")
* )
* )
* )
* )
*
*/
public function detail($role_id){
$role = AdminRole::where('id',$role_id)->first();
if(!$role){
abort(500,'角色不存在');
}
return $this->response->item($role,new AdminRoleTransformer(true));
} }
public function delete(){ /**
* @OA\Put(
* tags={"角色"},
* summary="编辑",
* path="api/role/{id}/edit",
* security={
* {"jwt_auth": {}}
* },
* @OA\RequestBody(
* @OA\MediaType(
* mediaType="application/x-www-form-urlencoded",
* @OA\Schema(
* type="object",
* required={"name","slug",},
* @OA\Property(
* property="name",
* type="string"
* ),
* @OA\Property(
* property="slug",
* type="string"
* ),
* )
* )
* ),
* @OA\Response(
* response="204",
* description="",
* )
* )
*
*/
public function edit(RoleRequest $request,$role_id){
$params = $request->all(['name','slug','menus']);
$role = AdminRole::where('id',$role_id)->first();
} if(!$role){
abort(500,'角色不存在');
}
public function setRoleMenu(Request $request,$role_id){
$params = $request->all(['menus']);
if(!is_array($params['menus'])){ if(!is_array($params['menus'])){
abort(422,'格式错误'); abort(422,'菜单格式错误');
} }
if($role_id == 1){ if($role_id == 1){
...@@ -56,7 +175,11 @@ class RoleController extends BaseController ...@@ -56,7 +175,11 @@ class RoleController extends BaseController
abort(500,$error); abort(500,$error);
} }
DB::transaction(function () use ($params,$role_id){ DB::transaction(function () use ($role,$params,$role_id){
$role->name = $params['name'];
$role->slug = $params['slug'];
$role->save();
AdminRoleMenu::where('role_id',$role_id)->delete(); AdminRoleMenu::where('role_id',$role_id)->delete();
$insert = []; $insert = [];
...@@ -70,6 +193,38 @@ class RoleController extends BaseController ...@@ -70,6 +193,38 @@ class RoleController extends BaseController
AdminRoleMenu::insert($insert); AdminRoleMenu::insert($insert);
} }
}); });
return $this->response->noContent()->statusCode(204);
}
/**
* @OA\Delete(
* tags={"角色"},
* summary="删除",
* path="api/role/{id}/delete",
* security={
* {"jwt_auth": {}}
* },
* @OA\Response(
* response="204",
* description="",
* )
* )
*
*/
public function delete($role_id){
$role = AdminRole::where('id',$role_id)->first();
if($role){
if(AdminRoleUser::where('role_id',$role->id)->count() > 0){
abort("此角色还有关联的用户,无法删除");
}
DB::transaction(function () use ($role){
$role->delete();
AdminRoleMenu::where('role_id',$role->id)->delete();
});
}
return $this->response->noContent()->statusCode(204); return $this->response->noContent()->statusCode(204);
} }
......
...@@ -18,11 +18,88 @@ use Modules\Admin\Http\Utils\Helper; ...@@ -18,11 +18,88 @@ use Modules\Admin\Http\Utils\Helper;
class UserController extends BaseController class UserController extends BaseController
{ {
/**
* @OA\Get(
* tags={"用户"},
* summary="列表",
* path="api/user/list",
* security={
* {"jwt_auth": {}}
* },
* @OA\Response(
* response="200",
* description="",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property="data",
* type="array",
* @OA\Items(ref="#/components/schemas/User"),
* description="列表"
* ),
* )
* )
* )
* )
*
*/
public function list(){ public function list(){
$list = AdminUser::all(); $list = AdminUser::all();
return $this->response->collection($list,new AdminUserTransformer()); return $this->response->collection($list,new AdminUserTransformer());
} }
/**
* @OA\Post(
* tags={"用户"},
* summary="添加",
* path="api/user/add",
* security={
* {"jwt_auth": {}}
* },
* @OA\RequestBody(
* @OA\MediaType(
* mediaType="application/x-www-form-urlencoded",
* @OA\Schema(
* type="object",
* required={"username","password","name","avatar","role_id",},
* @OA\Property(
* property="username",
* type="string",
* description="用户名",
* ),
* @OA\Property(
* property="password",
* type="string",
* description="密码",
* ),
* @OA\Property(
* property="name",
* type="string",
* description="名称",
* ),
* @OA\Property(
* property="avatar",
* type="string",
* description="头像",
* ),
* @OA\Property(
* property="role_id",
* type="string",
* description="角色ID",
* ),
*
* )
* )
* ),
* @OA\Response(
* response="201",
* description="",
* )
* )
*
*/
public function add(UserRequest $request){ public function add(UserRequest $request){
$params = $request->all(['username','password','name','avatar','role_id']); $params = $request->all(['username','password','name','avatar','role_id']);
...@@ -34,7 +111,6 @@ class UserController extends BaseController ...@@ -34,7 +111,6 @@ class UserController extends BaseController
$params['salt'] = Helper::generateRandomString(); $params['salt'] = Helper::generateRandomString();
$params['password'] = password_hash(md5($params['password'].$params['salt']), PASSWORD_DEFAULT); $params['password'] = password_hash(md5($params['password'].$params['salt']), PASSWORD_DEFAULT);
$user = DB::transaction(function () use ($params){ $user = DB::transaction(function () use ($params){
$role_id = $params['role_id']; $role_id = $params['role_id'];
unset($params['role_id']); unset($params['role_id']);
...@@ -49,15 +125,146 @@ class UserController extends BaseController ...@@ -49,15 +125,146 @@ class UserController extends BaseController
return $this->response->item($user,new AdminUserTransformer()); return $this->response->item($user,new AdminUserTransformer());
} }
public function detail(){ /**
* @OA\Get(
* tags={"用户"},
* summary="详情",
* path="api/user/{id}/detail",
* security={
* {"jwt_auth": {}}
* },
* @OA\Response(
* response="200",
* description="",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(property="data", type="object", ref="#/components/schemas/User")
* )
* )
* )
* )
*
*/
public function detail($id){
$user = AdminUser::where('id',$id)->first();
if(!$user){
abort(500,'用户不存在');
}
return $this->response->item($user,new AdminUserTransformer());
} }
public function edit(){ /**
* @OA\Put(
* tags={"用户"},
* summary="编辑",
* path="api/user/{id}/edit",
* security={
* {"jwt_auth": {}}
* },
* @OA\RequestBody(
* @OA\MediaType(
* mediaType="application/x-www-form-urlencoded",
* @OA\Schema(
* type="object",
* required={"username","password","name","avatar","role_id",},
* @OA\Property(
* property="username",
* type="string",
* description="用户名",
* ),
* @OA\Property(
* property="password",
* type="string",
* description="密码",
* ),
* @OA\Property(
* property="name",
* type="string",
* description="名称",
* ),
* @OA\Property(
* property="avatar",
* type="string",
* description="头像",
* ),
* @OA\Property(
* property="role_id",
* type="string",
* description="角色ID",
* ),
*
* )
* )
* ),
* @OA\Response(
* response="204",
* description="",
* )
* )
*
*/
public function edit(UserRequest $request,$id){
$params = $request->all(['username','password','name','avatar','role_id']);
$user = AdminUser::where('id',$id)->first();
if(!$user){
abort(500,'用户不存在');
}
if($user->username != $params['username'] && AdminUser::where('username',$params['username'])->first()){
abort(500,'用户名重复');
}
if(!empty($params['password'])){
$params['password'] = password_hash(md5($params['password'].$user->salt), PASSWORD_DEFAULT);
}else{
unset($params['password']);
}
DB::transaction(function () use ($user,$params){
$role_id = $params['role_id'];
unset($params['role_id']);
$user->update($params);
if($role_id && !AdminRoleUser::where(['user_id'=>$user->id,'role_id'=>$role_id])->first()){
AdminRoleUser::where('user_id',$user->id)->delete();
AdminRoleUser::create(['role_id'=>$role_id,'user_id'=>$user->id]);
}
});
return $this->response->noContent()->statusCode(204);
} }
public function delete(){ /**
* @OA\Delete(
* tags={"用户"},
* summary="删除",
* path="api/user/{id}/delete",
* security={
* {"jwt_auth": {}}
* },
* @OA\Response(
* response="204",
* description="",
* )
* )
*
*/
public function delete($id){
$user = AdminUser::where('id',$id)->first();
if($user){
DB::transaction(function () use ($user){
$user->delete();
AdminRoleUser::where('user_id',$user->id)->delete();
});
}
return $this->response->noContent()->statusCode(204);
} }
} }
\ No newline at end of file
<?php
namespace Modules\Admin\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Dingo\Api\Facade\Route;
use Modules\Admin\Http\Utils\Helper;
class RoleMenu
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
$user = auth()->user();
#角色
$role = $user->roles()->first();
$menus = Helper::getRoleMenu($role);
$role_uris = array_filter(array_column($menus,'uri'));
$uris = array_filter(array_column(Helper::getAllMenu(),'uri'));
$route = str_replace(".", "/", Route::currentRouteName());
#验证菜单权限
if(
!Helper::isAdministrator($role->id)
&& in_array($route,$uris)
&& !in_array($route,$role_uris)
){
abort(403,'没有权限');
}
return $next($request);
}
}
...@@ -11,8 +11,37 @@ class MenuRequest extends BaseRequest ...@@ -11,8 +11,37 @@ class MenuRequest extends BaseRequest
*/ */
public function postRules() public function postRules()
{ {
if(empty($this->parent_id)){
$this['parent_id'] = 0;
$parent_id_rule = [];
}else{
$parent_id_rule = ['exists:admin_menus,id'];
}
if(empty($this->uri)){
$uri_rule = [];
}else{
$uri_rule = ['unique:admin_menus,uri'];
}
return [
'parent_id' => $parent_id_rule,
'title' => 'bail|required',
'uri' => $uri_rule,
];
}
public function putRules()
{
if(empty($this->parent_id)){
$this->parent_id = 0;
$parent_id_rule = ['integer'];
}else{
$parent_id_rule = ['integer','exists:admin_menus,id'];
}
return [ return [
'parent_id' => 'integer|exists:admin_menus', 'parent_id' => $parent_id_rule,
'title' => 'bail|required', 'title' => 'bail|required',
]; ];
} }
...@@ -22,6 +51,7 @@ class MenuRequest extends BaseRequest ...@@ -22,6 +51,7 @@ class MenuRequest extends BaseRequest
return [ return [
'title.required' => '菜单名称必须', 'title.required' => '菜单名称必须',
'parent_id.exists' => '父菜单不存在', 'parent_id.exists' => '父菜单不存在',
'uri.unique' => 'uri重复',
]; ];
} }
} }
...@@ -4,11 +4,6 @@ namespace Modules\Admin\Http\Requests; ...@@ -4,11 +4,6 @@ namespace Modules\Admin\Http\Requests;
class RoleRequest extends BaseRequest class RoleRequest extends BaseRequest
{ {
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function postRules() public function postRules()
{ {
return [ return [
...@@ -17,6 +12,14 @@ class RoleRequest extends BaseRequest ...@@ -17,6 +12,14 @@ class RoleRequest extends BaseRequest
]; ];
} }
public function putRules()
{
return [
'name' => 'bail|required',
'slug' => 'bail|required',
];
}
public function messages() public function messages()
{ {
return [ return [
......
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
namespace Modules\Admin\Http\Requests; namespace Modules\Admin\Http\Requests;
use Illuminate\Validation\Rule;
use Modules\Admin\Entities\AdminUser;
class UserRequest extends BaseRequest class UserRequest extends BaseRequest
{ {
/** /**
...@@ -18,6 +21,15 @@ class UserRequest extends BaseRequest ...@@ -18,6 +21,15 @@ class UserRequest extends BaseRequest
]; ];
} }
public function putRules()
{
return [
'username' => ['bail','required'],
'name' => 'bail|required',
'role_id' => 'bail|required|exists:admin_roles,id',
];
}
public function messages() public function messages()
{ {
return [ return [
......
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/6/13
* Time: 11:12
*/
namespace Modules\Admin\Http\Transformers;
use Illuminate\Support\Traits\Macroable;
use Modules\Admin\Entities\AdminMenu;
use Modules\Admin\Entities\AdminRole;
use Modules\Admin\Entities\AdminUser;
use Modules\Admin\Http\Utils\Helper;
class AdminMenuTransformer extends BaseTransformer
{
use Macroable;
public function __construct()
{
parent::__construct();
}
/**
* @OA\Schema(
* description="菜单信息",
* type="object",
* schema="Menu",
* @OA\Property(property="id", type="integer", description="ID"),
* @OA\Property(property="parent_id", type="string", description="上级ID"),
* @OA\Property(property="title", type="string", description="标题"),
* @OA\Property(property="uri", type="string", description="uri"),
* @OA\Property(property="created_at", type="string", description="创建时间"),
* )
*/
public function transform(AdminMenu $menu)
{
$return = ['id','parent_id','title','uri','created_at'];
return Helper::mapAttr($menu,$return);
}
}
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/6/13
* Time: 11:12
*/
namespace Modules\Admin\Http\Transformers;
use Illuminate\Support\Traits\Macroable;
use Modules\Admin\Entities\AdminRole;
use Modules\Admin\Entities\AdminUser;
use Modules\Admin\Http\Utils\Helper;
class AdminRoleTransformer extends BaseTransformer
{
use Macroable;
protected $show_menu;
public function __construct($show_menu = false)
{
$this->show_menu = $show_menu;
parent::__construct();
}
/**
* @OA\Schema(
* description="角色信息",
* type="object",
* schema="Role",
* @OA\Property(property="name", type="integer", description="名称"),
* @OA\Property(property="slug", type="string", description="描述"),
* @OA\Property(property="created_at", type="string", description="创建时间"),
* )
*/
public function transform(AdminRole $role)
{
$return = ['name','slug','created_at'];
$return = Helper::mapAttr($role,$return);
if($this->show_menu){
$return['menu_ids'] = array_column($role->menu->toArray(),'id');
}
return $return;
}
}
...@@ -29,16 +29,16 @@ class AdminUserTransformer extends BaseTransformer ...@@ -29,16 +29,16 @@ class AdminUserTransformer extends BaseTransformer
* type="object", * type="object",
* schema="User", * schema="User",
* @OA\Property(property="id", type="integer", description="用户ID"), * @OA\Property(property="id", type="integer", description="用户ID"),
* @OA\Property(property="name", type="string", description="用户名"), * @OA\Property(property="username", type="string", description="用户名"),
* @OA\Property(property="email", type="string", description="邮箱"), * @OA\Property(property="avatar", type="string", description="头像"),
* @OA\Property(property="phone", type="string", description="手机号"), * @OA\Property(property="name", type="string", description="名称"),
* @OA\Property(property="created_at", type="string", description="注册时间"), * @OA\Property(property="created_at", type="string", description="注册时间"),
* @OA\Property(property="updated_at", type="string", description="更新时间") * @OA\Property(property="updated_at", type="string", description="更新时间")
* ) * )
*/ */
public function transform(AdminUser $user) public function transform(AdminUser $user)
{ {
$return = ['id', 'username', 'avatar', 'name', 'sex', 'created_at', 'updated_at']; $return = ['id', 'username', 'avatar', 'name', 'created_at', 'updated_at'];
return Helper::mapAttr($user,$return); return Helper::mapAttr($user,$return);
} }
......
...@@ -4,8 +4,76 @@ declare(strict_types=1); ...@@ -4,8 +4,76 @@ declare(strict_types=1);
namespace Modules\Admin\Http\Utils; namespace Modules\Admin\Http\Utils;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Support\Facades\Cache;
use Modules\Admin\Entities\AdminMenu;
class Helper { class Helper {
/**
* 获取全部菜单
* @desc
* @return mixed|mixed[]
* @since 2023/10/23
* @modify
* @author [ZZM]
*/
static function getAllMenu($refresh = false){
if(!$refresh && $menu = Cache::get("ALL_MENU")){
return json_decode($menu,true);
}
$menu = AdminMenu::all()->toArray();
if($menu){
Cache::put("ALL_MENU",json_encode($menu));
}
return $menu;
}
/**
* 获取角色菜单
* @desc
*
* @param $role
*
* @return mixed|mixed[]
* @author [ZZM]
* @since 2023/10/23
* @modify
*/
static function getRoleMenu($role,$refresh = false){
if(Helper::isAdministrator($role->id)){
#超级管理员默认获取全部菜单
return self::getAllMenu();
}
if(!$refresh && $menu = Cache::get("ROLE_MENU_{$role->id}")){
return json_decode($menu,true);
}
$menu = $role->menu;
$menu = $menu->toArray();
if($menu){
Cache::put("ROLE_MENU_{$role->id}",json_encode($menu));
}
return $menu;
}
/**
* 是否超级管理员
* @desc
*
* @param $role_id
*
* @return bool
* @author [ZZM]
* @since 2023/10/23
* @modify
*/
static function isAdministrator($role_id){
return $role_id == 1;
}
static function makeTree(array $elements, $parentId = 0) { static function makeTree(array $elements, $parentId = 0) {
$branch = []; $branch = [];
......
...@@ -8,14 +8,14 @@ use Illuminate\Support\Facades\Route; ...@@ -8,14 +8,14 @@ use Illuminate\Support\Facades\Route;
class RouteRegister { class RouteRegister {
public static function registerApi($api,$route, $controller) { public static function registerApi($api,$route, $controller) {
#列表 #列表
$api->get("{$route}/list", "{$controller}@list"); $api->get("{$route}/list", "{$controller}@list")->name("{$route}.list");
#添加 #添加
$api->post("{$route}/add", "{$controller}@add"); $api->post("{$route}/add", "{$controller}@add")->name("{$route}.add");
#详情 #详情
$api->get("{$route}/{id}/show", "{$controller}@detail"); $api->get("{$route}/{id}/detail", "{$controller}@detail")->name("{$route}.detail");
#编辑 #编辑
$api->put("{$route}/{id}/edit", "{$controller}@edit"); $api->put("{$route}/{id}/edit", "{$controller}@edit")->name("{$route}.edit");
#删除 #删除
$api->delete("{$route}/{id}/delete", "{$controller}@delete"); $api->delete("{$route}/{id}/delete", "{$controller}@delete")->name("{$route}.delete");
} }
} }
...@@ -23,23 +23,24 @@ $api->version('v1', [ ...@@ -23,23 +23,24 @@ $api->version('v1', [
$api->post('auth/login', 'AuthController@login'); $api->post('auth/login', 'AuthController@login');
$api->group(['middleware' => 'api.auth'], function ($api) { $api->group(['middleware' => 'api.auth'], function ($api) {
#刷新token #刷新token
$api->get('auth/refresh', 'AuthController@refreshToken'); $api->put('auth/refresh', 'AuthController@refreshToken');
#登出 #登出
$api->put('auth/login_out', 'AuthController@loginOut'); $api->put('auth/login_out', 'AuthController@loginOut');
#配置 #配置
$api->get('configs', 'AuthController@apiConfig'); $api->get('configs', 'AuthController@apiConfig');
#菜单 $api->group(['middleware' => 'role_menu'], function ($api){
\Modules\Admin\Http\Utils\RouteRegister::registerApi($api,'menu','MenuController'); #菜单
\Modules\Admin\Http\Utils\RouteRegister::registerApi($api,'menu','MenuController');
#用户 #用户
\Modules\Admin\Http\Utils\RouteRegister::registerApi($api,'user','UserController'); \Modules\Admin\Http\Utils\RouteRegister::registerApi($api,'user','UserController');
#角色
\Modules\Admin\Http\Utils\RouteRegister::registerApi($api,'role','RoleController');
#角色权限
$api->put('role/{id}/set_menu', 'RoleController@setRoleMenu');
#角色
\Modules\Admin\Http\Utils\RouteRegister::registerApi($api,'role','RoleController');
#角色权限
$api->put('role/{id}/set_menu', 'RoleController@setRoleMenu')->name("role.set_menu");;
});
}); });
}); });
<?php
namespace App\Admin\Controllers;
use Encore\Admin\Controllers\AuthController as BaseAuthController;
class AuthController extends BaseAuthController
{
}
<?php
namespace App\Admin\Controllers;
use Encore\Admin\Controllers\AdminController;
use Encore\Admin\Form;
use Encore\Admin\Grid;
use Encore\Admin\Show;
class ExampleController extends AdminController
{
/**
* Title for current resource.
*
* @var string
*/
protected $title = 'Example controller';
/**
* Make a grid builder.
*
* @return Grid
*/
protected function grid()
{
$grid = new Grid(new ExampleModel);
$grid->column('id', __('ID'))->sortable();
$grid->column('created_at', __('Created at'));
$grid->column('updated_at', __('Updated at'));
return $grid;
}
/**
* Make a show builder.
*
* @param mixed $id
* @return Show
*/
protected function detail($id)
{
$show = new Show(ExampleModel::findOrFail($id));
$show->field('id', __('ID'));
$show->field('created_at', __('Created at'));
$show->field('updated_at', __('Updated at'));
return $show;
}
/**
* Make a form builder.
*
* @return Form
*/
protected function form()
{
$form = new Form(new ExampleModel);
$form->display('id', __('ID'));
$form->display('created_at', __('Created At'));
$form->display('updated_at', __('Updated At'));
return $form;
}
}
<?php
namespace App\Admin\Controllers;
use App\Http\Controllers\Controller;
use Encore\Admin\Controllers\Dashboard;
use Encore\Admin\Layout\Column;
use Encore\Admin\Layout\Content;
use Encore\Admin\Layout\Row;
class HomeController extends Controller
{
public function index(Content $content)
{
return $content
->title('Dashboard')
->description('Description...')
->row(Dashboard::title())
->row(function (Row $row) {
$row->column(4, function (Column $column) {
$column->append(Dashboard::environment());
});
$row->column(4, function (Column $column) {
$column->append(Dashboard::extensions());
});
$row->column(4, function (Column $column) {
$column->append(Dashboard::dependencies());
});
});
}
}
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
namespace App\Http; namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel; use Illuminate\Foundation\Http\Kernel as HttpKernel;
use Modules\Admin\Http\Middleware\RoleMenu;
class Kernel extends HttpKernel class Kernel extends HttpKernel
{ {
...@@ -64,5 +65,6 @@ class Kernel extends HttpKernel ...@@ -64,5 +65,6 @@ class Kernel extends HttpKernel
'signed' => \App\Http\Middleware\ValidateSignature::class, 'signed' => \App\Http\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'role_menu' => RoleMenu::class,
]; ];
} }
<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
<?php
/**
* @OA\Info(title="My First API", version="0.1")
*/
/**
* @OA\SecurityScheme(
* securityScheme="jwt_auth",
* type="http",
* scheme="bearer",
* bearerFormat="JWT",
* )
*
* @OA\Get(
* tags={"基础接口"},
* summary="获取验证码",
* path="/api/captcha",
* @OA\Response(
* response="200",
* description="验证码信息",
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(property="data", type="object", ref="#/components/schemas/Verify")
* )
* )
* )
* )
*
*
* @OA\Get(
* tags={"基础接口"},
* summary="缩略图",
* path="/imagecache/{template}/{image_path}",
* @OA\Parameter(
* name="template",
* in="path",
* description="图片处理模板,默认有 small,medium,large三种",
* required=true,
* @OA\Schema(
* type="string",
* )
* ),
* @OA\Parameter(
* name="image_path",
* in="path",
* description="储存的文件名,程序保存时的路径",
* required=true,
* @OA\Schema(
* type="string",
* )
* ),
* @OA\Response(
* response="200",
* description="处理后的图片",
* @OA\MediaType(
* mediaType="image/png",
* @OA\Schema(
* type="string",
* format="binary",
* )
* ),
* @OA\MediaType(
* mediaType="image/jpg",
* @OA\Schema(
* type="string",
* format="binary",
* )
* ),
* @OA\MediaType(
* mediaType="image/jpeg",
* @OA\Schema(
* type="string",
* format="binary",
* )
* ),
* @OA\MediaType(
* mediaType="image/gif",
* @OA\Schema(
* type="string",
* format="binary",
* )
* )
* )
* )
*
* @OA\Schema(
* description="请求验证错误422",
* type="object",
* schema="error422",
* @OA\Property(property="message", type="string", description="422 Unprocessable Entity"),
* @OA\Property(property="error", type="object", description="错误",
* @OA\Property(property="key", type="array", description="请求键值",
* @OA\Items(type="string", description="具体错误"),
* ),
* ),
* @OA\Property(property="status_code", type="integer", description="状态码422", example=422),
* @OA\Property(property="debug", type="object", description="错误调试信息")
* )
*
*
*
* @OA\Schema(
* description="验证码信息",
* type="object",
* schema="Verify",
* @OA\Property(property="sensitive", type="boolean", description="验证码是否大小写敏感"),
* @OA\Property(property="key", type="string", description="验证码KEY"),
* @OA\Property(property="img", type="string", description="验证码图片(base64图片编码)")
* )
*
* @OA\Schema(
* description="手机号",
* type="string",
* schema="phone",
* minLength=11
* )
*
* @OA\Schema(
* description="密码",
* type="string",
* schema="password",
* minLength=6
* )
*
* @OA\Schema(
* description="手机短信验证码",
* type="string",
* schema="phone_code",
* minLength=4
* )
*
* @OA\Schema(
* description="邮箱",
* type="string",
* schema="email"
* )
*
* @OA\Schema(
* description="1为是,0为否",
* type="integer",
* enum={0,1},
* schema="yesno"
* )
*
* @OA\Schema(
* description="验证码KEY",
* type="string",
* schema="captcha_key"
* )
*
* @OA\Schema(
* description="验证码",
* type="string",
* schema="captcha_code"
* )
*
*/
\ No newline at end of file
...@@ -6,14 +6,16 @@ ...@@ -6,14 +6,16 @@
"license": "MIT", "license": "MIT",
"require": { "require": {
"php": "^8.1", "php": "^8.1",
"api-ecosystem-for-laravel/dingo-api": "^4.1", "api-ecosystem-for-laravel/dingo-api": "4.1.*",
"darkaonline/l5-swagger": "^8.5",
"guzzlehttp/guzzle": "^7.2", "guzzlehttp/guzzle": "^7.2",
"laravel/framework": "10.*", "laravel/framework": "10.*",
"laravel/tinker": "^2.8", "laravel/tinker": "^2.8",
"namshi/jose": "^7.2", "namshi/jose": "^7.2",
"nesbot/carbon": "^2.71", "nesbot/carbon": "^2.71",
"nwidart/laravel-modules": "^10.0", "nwidart/laravel-modules": "^10.0",
"php-open-source-saver/jwt-auth": "^2.1" "php-open-source-saver/jwt-auth": "^2.1",
"zircote/swagger-php": "^4.7"
}, },
"require-dev": { "require-dev": {
"fakerphp/faker": "^1.9.1", "fakerphp/faker": "^1.9.1",
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "befc3d7b06f7f26225cbcbdefe34731f", "content-hash": "c14b94053584d7feae995e94d306c004",
"packages": [ "packages": [
{ {
"name": "api-ecosystem-for-laravel/dingo-api", "name": "api-ecosystem-for-laravel/dingo-api",
...@@ -147,6 +147,85 @@ ...@@ -147,6 +147,85 @@
"time": "2023-01-15T23:15:59+00:00" "time": "2023-01-15T23:15:59+00:00"
}, },
{ {
"name": "darkaonline/l5-swagger",
"version": "8.5.1",
"source": {
"type": "git",
"url": "https://github.com/DarkaOnLine/L5-Swagger.git",
"reference": "02348149f1833c63bf52764838d5659507857394"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/DarkaOnLine/L5-Swagger/zipball/02348149f1833c63bf52764838d5659507857394",
"reference": "02348149f1833c63bf52764838d5659507857394",
"shasum": ""
},
"require": {
"ext-json": "*",
"laravel/framework": "^10.0 || ^9.0 || >=8.40.0 || ^7.0",
"php": "^7.2 || ^8.0",
"swagger-api/swagger-ui": "^3.0 || >=4.1.3",
"symfony/yaml": "^5.0 || ^6.0",
"zircote/swagger-php": "^3.2.0 || ^4.0.0"
},
"require-dev": {
"mockery/mockery": "1.*",
"orchestra/testbench": "^8.0 || 7.* || ^6.15 || 5.*",
"php-coveralls/php-coveralls": "^2.0",
"phpunit/phpunit": "^10.0 || ^9.5"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"L5Swagger\\L5SwaggerServiceProvider"
],
"aliases": {
"L5Swagger": "L5Swagger\\L5SwaggerFacade"
}
}
},
"autoload": {
"files": [
"src/helpers.php"
],
"psr-4": {
"L5Swagger\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Darius Matulionis",
"email": "darius@matulionis.lt"
}
],
"description": "OpenApi or Swagger integration to Laravel",
"keywords": [
"api",
"documentation",
"laravel",
"openapi",
"specification",
"swagger",
"ui"
],
"support": {
"issues": "https://github.com/DarkaOnLine/L5-Swagger/issues",
"source": "https://github.com/DarkaOnLine/L5-Swagger/tree/8.5.1"
},
"funding": [
{
"url": "https://github.com/DarkaOnLine",
"type": "github"
}
],
"time": "2023-06-05T04:21:50+00:00"
},
{
"name": "dflydev/dot-access-data", "name": "dflydev/dot-access-data",
"version": "v3.0.2", "version": "v3.0.2",
"source": { "source": {
...@@ -4022,6 +4101,67 @@ ...@@ -4022,6 +4101,67 @@
"time": "2023-04-15T23:01:58+00:00" "time": "2023-04-15T23:01:58+00:00"
}, },
{ {
"name": "swagger-api/swagger-ui",
"version": "v5.9.0",
"source": {
"type": "git",
"url": "https://github.com/swagger-api/swagger-ui.git",
"reference": "cbfc3e949d3d9e2b71d566fb722cb3970036f593"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/swagger-api/swagger-ui/zipball/cbfc3e949d3d9e2b71d566fb722cb3970036f593",
"reference": "cbfc3e949d3d9e2b71d566fb722cb3970036f593",
"shasum": ""
},
"type": "library",
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Anna Bodnia",
"email": "anna.bodnia@gmail.com"
},
{
"name": "Buu Nguyen",
"email": "buunguyen@gmail.com"
},
{
"name": "Josh Ponelat",
"email": "jponelat@gmail.com"
},
{
"name": "Kyle Shockey",
"email": "kyleshockey1@gmail.com"
},
{
"name": "Robert Barnwell",
"email": "robert@robertismy.name"
},
{
"name": "Sahar Jafari",
"email": "shr.jafari@gmail.com"
}
],
"description": " Swagger UI is a collection of HTML, Javascript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API.",
"homepage": "http://swagger.io",
"keywords": [
"api",
"documentation",
"openapi",
"specification",
"swagger",
"ui"
],
"support": {
"issues": "https://github.com/swagger-api/swagger-ui/issues",
"source": "https://github.com/swagger-api/swagger-ui/tree/v5.9.0"
},
"time": "2023-09-29T12:27:07+00:00"
},
{
"name": "symfony/console", "name": "symfony/console",
"version": "v6.3.4", "version": "v6.3.4",
"source": { "source": {
...@@ -6341,6 +6481,78 @@ ...@@ -6341,6 +6481,78 @@
"time": "2023-09-12T10:11:35+00:00" "time": "2023-09-12T10:11:35+00:00"
}, },
{ {
"name": "symfony/yaml",
"version": "v6.3.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "e23292e8c07c85b971b44c1c4b87af52133e2add"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/e23292e8c07c85b971b44c1c4b87af52133e2add",
"reference": "e23292e8c07c85b971b44c1c4b87af52133e2add",
"shasum": ""
},
"require": {
"php": ">=8.1",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-ctype": "^1.8"
},
"conflict": {
"symfony/console": "<5.4"
},
"require-dev": {
"symfony/console": "^5.4|^6.0"
},
"bin": [
"Resources/bin/yaml-lint"
],
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Yaml\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Loads and dumps YAML files",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/yaml/tree/v6.3.3"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2023-07-31T07:08:24+00:00"
},
{
"name": "tijsverkoyen/css-to-inline-styles", "name": "tijsverkoyen/css-to-inline-styles",
"version": "2.2.6", "version": "2.2.6",
"source": { "source": {
...@@ -6608,6 +6820,84 @@ ...@@ -6608,6 +6820,84 @@
"source": "https://github.com/webmozarts/assert/tree/1.11.0" "source": "https://github.com/webmozarts/assert/tree/1.11.0"
}, },
"time": "2022-06-03T18:03:27+00:00" "time": "2022-06-03T18:03:27+00:00"
},
{
"name": "zircote/swagger-php",
"version": "4.7.15",
"source": {
"type": "git",
"url": "https://github.com/zircote/swagger-php.git",
"reference": "df8de8e484003f68cd2fa68db1e6cfb47a3a92cb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/zircote/swagger-php/zipball/df8de8e484003f68cd2fa68db1e6cfb47a3a92cb",
"reference": "df8de8e484003f68cd2fa68db1e6cfb47a3a92cb",
"shasum": ""
},
"require": {
"doctrine/annotations": "^1.7 || ^2.0",
"ext-json": "*",
"php": ">=7.2",
"psr/log": "^1.1 || ^2.0 || ^3.0",
"symfony/deprecation-contracts": "^2 || ^3",
"symfony/finder": ">=2.2",
"symfony/yaml": ">=3.3"
},
"require-dev": {
"composer/package-versions-deprecated": "^1.11",
"friendsofphp/php-cs-fixer": "^2.17 || ^3.0",
"phpstan/phpstan": "^1.6",
"phpunit/phpunit": ">=8",
"vimeo/psalm": "^4.23"
},
"bin": [
"bin/openapi"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.x-dev"
}
},
"autoload": {
"psr-4": {
"OpenApi\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Robert Allen",
"email": "zircote@gmail.com"
},
{
"name": "Bob Fanger",
"email": "bfanger@gmail.com",
"homepage": "https://bfanger.nl"
},
{
"name": "Martin Rademacher",
"email": "mano@radebatz.net",
"homepage": "https://radebatz.net"
}
],
"description": "swagger-php - Generate interactive documentation for your RESTful API using phpdoc annotations",
"homepage": "https://github.com/zircote/swagger-php/",
"keywords": [
"api",
"json",
"rest",
"service discovery"
],
"support": {
"issues": "https://github.com/zircote/swagger-php/issues",
"source": "https://github.com/zircote/swagger-php/tree/4.7.15"
},
"time": "2023-10-12T20:26:34+00:00"
} }
], ],
"packages-dev": [ "packages-dev": [
...@@ -9056,78 +9346,6 @@ ...@@ -9056,78 +9346,6 @@
"time": "2023-10-09T12:55:26+00:00" "time": "2023-10-09T12:55:26+00:00"
}, },
{ {
"name": "symfony/yaml",
"version": "v6.3.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "e23292e8c07c85b971b44c1c4b87af52133e2add"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/e23292e8c07c85b971b44c1c4b87af52133e2add",
"reference": "e23292e8c07c85b971b44c1c4b87af52133e2add",
"shasum": ""
},
"require": {
"php": ">=8.1",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-ctype": "^1.8"
},
"conflict": {
"symfony/console": "<5.4"
},
"require-dev": {
"symfony/console": "^5.4|^6.0"
},
"bin": [
"Resources/bin/yaml-lint"
],
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Yaml\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Loads and dumps YAML files",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/yaml/tree/v6.3.3"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2023-07-31T07:08:24+00:00"
},
{
"name": "theseer/tokenizer", "name": "theseer/tokenizer",
"version": "1.2.1", "version": "1.2.1",
"source": { "source": {
......
...@@ -70,7 +70,7 @@ return [ ...@@ -70,7 +70,7 @@ return [
| |
*/ */
'timezone' => 'UTC', 'timezone' => 'Asia/Shanghai',
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
......
<?php
return [
'default' => 'default',
'documentations' => [
'default' => [
'api' => [
'title' => 'L5 Swagger UI',
],
'routes' => [
/*
* Route for accessing api documentation interface
*/
'api' => 'api/documentation',
],
'paths' => [
/*
* Edit to include full URL in ui for assets
*/
//'use_absolute_path' => env('L5_SWAGGER_USE_ABSOLUTE_PATH', true),
/*
* File name of the generated json documentation file
*/
'docs_json' => 'api-docs.json',
/*
* File name of the generated YAML documentation file
*/
'docs_yaml' => 'api-docs.yaml',
/*
* Set this to `json` or `yaml` to determine which documentation file to use in UI
*/
'format_to_use_for_docs' => env('L5_FORMAT_TO_USE_FOR_DOCS', 'json'),
/*
* Absolute paths to directory containing the swagger annotations are stored.
*/
'annotations' => [
base_path('Modules'),
],
],
],
],
'defaults' => [
'routes' => [
/*
* Route for accessing parsed swagger annotations.
*/
'docs' => 'docs',
/*
* Route for Oauth2 authentication callback.
*/
'oauth2_callback' => 'api/oauth2-callback',
/*
* Middleware allows to prevent unexpected access to API documentation
*/
'middleware' => [
'api' => [],
'asset' => [],
'docs' => [],
'oauth2_callback' => [],
],
/*
* Route Group options
*/
'group_options' => [],
],
'paths' => [
/*
* Absolute path to location where parsed annotations will be stored
*/
'docs' => storage_path('api-docs'),
/*
* Absolute path to directory where to export views
*/
'views' => base_path('resources/views/vendor/l5-swagger'),
/*
* Edit to set the api's base path
*/
'base' => env('L5_SWAGGER_BASE_PATH', null),
/*
* Edit to set path where swagger ui assets should be stored
*/
'swagger_ui_assets_path' => env('L5_SWAGGER_UI_ASSETS_PATH', 'vendor/swagger-api/swagger-ui/dist/'),
/*
* Absolute path to directories that should be exclude from scanning
* @deprecated Please use `scanOptions.exclude`
* `scanOptions.exclude` overwrites this
*/
'excludes' => [],
],
'scanOptions' => [
/**
* analyser: defaults to \OpenApi\StaticAnalyser .
*
* @see \OpenApi\scan
*/
'analyser' => null,
/**
* analysis: defaults to a new \OpenApi\Analysis .
*
* @see \OpenApi\scan
*/
'analysis' => null,
/**
* Custom query path processors classes.
*
* @link https://github.com/zircote/swagger-php/tree/master/Examples/schema-query-parameter-processor
* @see \OpenApi\scan
*/
'processors' => [
// new \App\SwaggerProcessors\SchemaQueryParameter(),
],
/**
* pattern: string $pattern File pattern(s) to scan (default: *.php) .
*
* @see \OpenApi\scan
*/
'pattern' => null,
/*
* Absolute path to directories that should be excluded from scanning
* @note This option overwrites `paths.excludes`
* @see \OpenApi\scan
*/
'exclude' => [],
/*
* Allows to generate specs either for OpenAPI 3.0.0 or OpenAPI 3.1.0.
* By default the spec will be in version 3.0.0
*/
'open_api_spec_version' => env('L5_SWAGGER_OPEN_API_SPEC_VERSION', \L5Swagger\Generator::OPEN_API_DEFAULT_SPEC_VERSION),
],
/*
* API security definitions. Will be generated into documentation file.
*/
'securityDefinitions' => [
'securitySchemes' => [
/*
* Examples of Security schemes
*/
/*
'api_key_security_example' => [ // Unique name of security
'type' => 'apiKey', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2".
'description' => 'A short description for security scheme',
'name' => 'api_key', // The name of the header or query parameter to be used.
'in' => 'header', // The location of the API key. Valid values are "query" or "header".
],
'oauth2_security_example' => [ // Unique name of security
'type' => 'oauth2', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2".
'description' => 'A short description for oauth2 security scheme.',
'flow' => 'implicit', // The flow used by the OAuth2 security scheme. Valid values are "implicit", "password", "application" or "accessCode".
'authorizationUrl' => 'http://example.com/auth', // The authorization URL to be used for (implicit/accessCode)
//'tokenUrl' => 'http://example.com/auth' // The authorization URL to be used for (password/application/accessCode)
'scopes' => [
'read:projects' => 'read your projects',
'write:projects' => 'modify projects in your account',
]
],
*/
/* Open API 3.0 support
'passport' => [ // Unique name of security
'type' => 'oauth2', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2".
'description' => 'Laravel passport oauth2 security.',
'in' => 'header',
'scheme' => 'https',
'flows' => [
"password" => [
"authorizationUrl" => config('app.url') . '/oauth/authorize',
"tokenUrl" => config('app.url') . '/oauth/token',
"refreshUrl" => config('app.url') . '/token/refresh',
"scopes" => []
],
],
],
'sanctum' => [ // Unique name of security
'type' => 'apiKey', // Valid values are "basic", "apiKey" or "oauth2".
'description' => 'Enter token in format (Bearer <token>)',
'name' => 'Authorization', // The name of the header or query parameter to be used.
'in' => 'header', // The location of the API key. Valid values are "query" or "header".
],
*/
],
'security' => [
/*
* Examples of Securities
*/
[
/*
'oauth2_security_example' => [
'read',
'write'
],
'passport' => []
*/
],
],
],
/*
* Set this to `true` in development mode so that docs would be regenerated on each request
* Set this to `false` to disable swagger generation on production
*/
'generate_always' => env('L5_SWAGGER_GENERATE_ALWAYS', false),
/*
* Set this to `true` to generate a copy of documentation in yaml format
*/
'generate_yaml_copy' => env('L5_SWAGGER_GENERATE_YAML_COPY', false),
/*
* Edit to trust the proxy's ip address - needed for AWS Load Balancer
* string[]
*/
'proxy' => false,
/*
* Configs plugin allows to fetch external configs instead of passing them to SwaggerUIBundle.
* See more at: https://github.com/swagger-api/swagger-ui#configs-plugin
*/
'additional_config_url' => null,
/*
* Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically),
* 'method' (sort by HTTP method).
* Default is the order returned by the server unchanged.
*/
'operations_sort' => env('L5_SWAGGER_OPERATIONS_SORT', null),
/*
* Pass the validatorUrl parameter to SwaggerUi init on the JS side.
* A null value here disables validation.
*/
'validator_url' => null,
/*
* Swagger UI configuration parameters
*/
'ui' => [
'display' => [
/*
* Controls the default expansion setting for the operations and tags. It can be :
* 'list' (expands only the tags),
* 'full' (expands the tags and operations),
* 'none' (expands nothing).
*/
'doc_expansion' => env('L5_SWAGGER_UI_DOC_EXPANSION', 'none'),
/**
* If set, enables filtering. The top bar will show an edit box that
* you can use to filter the tagged operations that are shown. Can be
* Boolean to enable or disable, or a string, in which case filtering
* will be enabled using that string as the filter expression. Filtering
* is case-sensitive matching the filter expression anywhere inside
* the tag.
*/
'filter' => env('L5_SWAGGER_UI_FILTERS', true), // true | false
],
'authorization' => [
/*
* If set to true, it persists authorization data, and it would not be lost on browser close/refresh
*/
'persist_authorization' => env('L5_SWAGGER_UI_PERSIST_AUTHORIZATION', false),
'oauth2' => [
/*
* If set to true, adds PKCE to AuthorizationCodeGrant flow
*/
'use_pkce_with_authorization_code_grant' => false,
],
],
],
/*
* Constants which can be used in annotations
*/
'constants' => [
'L5_SWAGGER_CONST_HOST' => env('L5_SWAGGER_CONST_HOST', 'http://my-default-host.com'),
],
],
];
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{config('l5-swagger.documentations.'.$documentation.'.api.title')}}</title>
<link rel="stylesheet" type="text/css" href="{{ l5_swagger_asset($documentation, 'swagger-ui.css') }}">
<link rel="icon" type="image/png" href="{{ l5_swagger_asset($documentation, 'favicon-32x32.png') }}" sizes="32x32"/>
<link rel="icon" type="image/png" href="{{ l5_swagger_asset($documentation, 'favicon-16x16.png') }}" sizes="16x16"/>
<style>
html
{
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after
{
box-sizing: inherit;
}
body {
margin:0;
background: #fafafa;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="{{ l5_swagger_asset($documentation, 'swagger-ui-bundle.js') }}"></script>
<script src="{{ l5_swagger_asset($documentation, 'swagger-ui-standalone-preset.js') }}"></script>
<script>
window.onload = function() {
// Build a system
const ui = SwaggerUIBundle({
dom_id: '#swagger-ui',
url: "{!! $urlToDocs !!}",
operationsSorter: {!! isset($operationsSorter) ? '"' . $operationsSorter . '"' : 'null' !!},
configUrl: {!! isset($configUrl) ? '"' . $configUrl . '"' : 'null' !!},
validatorUrl: {!! isset($validatorUrl) ? '"' . $validatorUrl . '"' : 'null' !!},
oauth2RedirectUrl: "{{ route('l5-swagger.'.$documentation.'.oauth2_callback', [], $useAbsolutePath) }}",
requestInterceptor: function(request) {
request.headers['X-CSRF-TOKEN'] = '{{ csrf_token() }}';
return request;
},
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout",
docExpansion : "{!! config('l5-swagger.defaults.ui.display.doc_expansion', 'none') !!}",
deepLinking: true,
filter: {!! config('l5-swagger.defaults.ui.display.filter') ? 'true' : 'false' !!},
persistAuthorization: "{!! config('l5-swagger.defaults.ui.authorization.persist_authorization') ? 'true' : 'false' !!}",
})
window.ui = ui
@if(in_array('oauth2', array_column(config('l5-swagger.defaults.securityDefinitions.securitySchemes'), 'type')))
ui.initOAuth({
usePkceWithAuthorizationCodeGrant: "{!! (bool)config('l5-swagger.defaults.ui.authorization.oauth2.use_pkce_with_authorization_code_grant') !!}"
})
@endif
}
</script>
</body>
</html>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment