style: 以 pint 格式化 routes、Docs 與 BookingListTest
Run Tests / test (pull_request) Successful in 36s

純格式調整,不改變行為。這四個檔案在 master 上即未通過 pint,
因本次功能變更觸及而一併修正,以符合變更檔案需通過 pint 的審查要求。

- 已驗證 route:list 除角色 middleware 外無差異
- 已驗證 l5-swagger 產出的 JSON 在格式化前後完全相同

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-17 23:57:30 +08:00
parent 16ccb4c18c
commit 90fc8f2d49
4 changed files with 354 additions and 204 deletions
+113 -51
View File
@@ -38,40 +38,48 @@ class MemberApiDoc
* operationId="createBooking", * operationId="createBooking",
* tags={"會員預約"}, * tags={"會員預約"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\RequestBody( * @OA\RequestBody(
* required=true, * required=true,
*
* @OA\JsonContent( * @OA\JsonContent(
* required={"offer_id","schedule_id","participants"}, * required={"offer_id","schedule_id","participants"},
*
* @OA\Property(property="offer_id", type="integer", example=1, description="課程 ID"), * @OA\Property(property="offer_id", type="integer", example=1, description="課程 ID"),
* @OA\Property(property="schedule_id", type="integer", example=2, description="時段 ID"), * @OA\Property(property="schedule_id", type="integer", example=2, description="時段 ID"),
* @OA\Property(property="participants", type="integer", example=2, description="參加人數"), * @OA\Property(property="participants", type="integer", example=2, description="參加人數"),
* @OA\Property(property="note", type="string", nullable=true, example="需要器材租借") * @OA\Property(property="note", type="string", nullable=true, example="需要器材租借")
* ) * )
* ), * ),
*
* @OA\Response( * @OA\Response(
* response=201, * response=201,
* description="預約建立成功", * description="預約建立成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="message", type="string", example="預約成功"), * @OA\Property(property="message", type="string", example="預約成功"),
* @OA\Property(property="data", ref="#/components/schemas/Booking") * @OA\Property(property="data", ref="#/components/schemas/Booking")
* ) * )
* ), * ),
*
* @OA\Response( * @OA\Response(
* response=422, * response=422,
* description="驗證失敗或時段已滿", * description="驗證失敗或時段已滿",
*
* @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse") * @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")
* ), * ),
*
* @OA\Response( * @OA\Response(
* response=403, * response=403,
* description="無權限(非 member 角色)", * description="無權限(非 member 角色)",
*
* @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse") * @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")
* ) * )
* ) * )
*/ */
public function createBooking() public function createBooking() {}
{
}
/** /**
* 取得我的預約列表 * 取得我的預約列表
@@ -83,23 +91,26 @@ class MemberApiDoc
* operationId="listMemberBookings", * operationId="listMemberBookings",
* tags={"會員預約"}, * tags={"會員預約"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="page", in="query", description="頁碼", @OA\Schema(type="integer", default=1)), * @OA\Parameter(name="page", in="query", description="頁碼", @OA\Schema(type="integer", default=1)),
* @OA\Parameter(name="per_page", in="query", description="每頁筆數", @OA\Schema(type="integer", default=15)), * @OA\Parameter(name="per_page", in="query", description="每頁筆數", @OA\Schema(type="integer", default=15)),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="取得成功", * description="取得成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="data", type="array", @OA\Items(ref="#/components/schemas/Booking")), * @OA\Property(property="data", type="array", @OA\Items(ref="#/components/schemas/Booking")),
* @OA\Property(property="meta", ref="#/components/schemas/PaginationMeta") * @OA\Property(property="meta", ref="#/components/schemas/PaginationMeta")
* ) * )
* ), * ),
*
* @OA\Response(response=403, description="非 member 角色", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=403, description="非 member 角色", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function listMemberBookings() public function listMemberBookings() {}
{
}
/** /**
* 取得單一預約 * 取得單一預約
@@ -110,22 +121,25 @@ class MemberApiDoc
* operationId="getMemberBooking", * operationId="getMemberBooking",
* tags={"會員預約"}, * tags={"會員預約"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="id", in="path", required=true, description="預約 ID", @OA\Schema(type="integer")), * @OA\Parameter(name="id", in="path", required=true, description="預約 ID", @OA\Schema(type="integer")),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="取得成功", * description="取得成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="data", ref="#/components/schemas/Booking") * @OA\Property(property="data", ref="#/components/schemas/Booking")
* ) * )
* ), * ),
*
* @OA\Response(response=404, description="預約不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")), * @OA\Response(response=404, description="預約不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")),
* @OA\Response(response=403, description="非 member 角色或非本人預約", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=403, description="非 member 角色或非本人預約", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function getMemberBooking() public function getMemberBooking() {}
{
}
/** /**
* 取消預約 * 取消預約
@@ -137,22 +151,25 @@ class MemberApiDoc
* operationId="cancelBooking", * operationId="cancelBooking",
* tags={"會員預約"}, * tags={"會員預約"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="id", in="path", required=true, description="預約 ID", @OA\Schema(type="integer")), * @OA\Parameter(name="id", in="path", required=true, description="預約 ID", @OA\Schema(type="integer")),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="取消成功", * description="取消成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="message", type="string", example="預約已取消") * @OA\Property(property="message", type="string", example="預約已取消")
* ) * )
* ), * ),
*
* @OA\Response(response=403, description="非 member 角色、非本人預約或狀態不允許取消", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")), * @OA\Response(response=403, description="非 member 角色、非本人預約或狀態不允許取消", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")),
* @OA\Response(response=404, description="預約不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=404, description="預約不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function cancelBooking() public function cancelBooking() {}
{
}
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Member Reviews // Member Reviews
@@ -168,32 +185,37 @@ class MemberApiDoc
* operationId="createReview", * operationId="createReview",
* tags={"會員評價"}, * tags={"會員評價"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\RequestBody( * @OA\RequestBody(
* required=true, * required=true,
*
* @OA\JsonContent( * @OA\JsonContent(
* required={"booking_id","rating"}, * required={"booking_id","rating"},
*
* @OA\Property(property="booking_id", type="integer", example=5), * @OA\Property(property="booking_id", type="integer", example=5),
* @OA\Property(property="rating", type="integer", minimum=1, maximum=5, example=4), * @OA\Property(property="rating", type="integer", minimum=1, maximum=5, example=4),
* @OA\Property(property="comment", type="string", nullable=true, example="課程非常棒!"), * @OA\Property(property="comment", type="string", nullable=true, example="課程非常棒!"),
* @OA\Property(property="is_anonymous", type="boolean", example=false) * @OA\Property(property="is_anonymous", type="boolean", example=false)
* ) * )
* ), * ),
*
* @OA\Response( * @OA\Response(
* response=201, * response=201,
* description="評價建立成功", * description="評價建立成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="message", type="string", example="評價已提交"), * @OA\Property(property="message", type="string", example="評價已提交"),
* @OA\Property(property="data", ref="#/components/schemas/Review") * @OA\Property(property="data", ref="#/components/schemas/Review")
* ) * )
* ), * ),
*
* @OA\Response(response=403, description="非 member 角色、預約未完成或非本人預約", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")), * @OA\Response(response=403, description="非 member 角色、預約未完成或非本人預約", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")),
* @OA\Response(response=422, description="驗證失敗", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=422, description="驗證失敗", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function createReview() public function createReview() {}
{
}
/** /**
* 更新評價 * 更新評價
@@ -204,30 +226,36 @@ class MemberApiDoc
* operationId="updateReview", * operationId="updateReview",
* tags={"會員評價"}, * tags={"會員評價"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="id", in="path", required=true, description="評價 ID", @OA\Schema(type="integer")), * @OA\Parameter(name="id", in="path", required=true, description="評價 ID", @OA\Schema(type="integer")),
*
* @OA\RequestBody( * @OA\RequestBody(
* required=true, * required=true,
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="rating", type="integer", minimum=1, maximum=5, example=5), * @OA\Property(property="rating", type="integer", minimum=1, maximum=5, example=5),
* @OA\Property(property="comment", type="string", nullable=true, example="更新後的評語"), * @OA\Property(property="comment", type="string", nullable=true, example="更新後的評語"),
* @OA\Property(property="is_anonymous", type="boolean", example=true) * @OA\Property(property="is_anonymous", type="boolean", example=true)
* ) * )
* ), * ),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="更新成功", * description="更新成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="data", ref="#/components/schemas/Review") * @OA\Property(property="data", ref="#/components/schemas/Review")
* ) * )
* ), * ),
*
* @OA\Response(response=403, description="非 member 角色或非本人評價", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")), * @OA\Response(response=403, description="非 member 角色或非本人評價", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")),
* @OA\Response(response=404, description="評價不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=404, description="評價不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function updateReview() public function updateReview() {}
{
}
/** /**
* 刪除評價 * 刪除評價
@@ -238,22 +266,25 @@ class MemberApiDoc
* operationId="deleteReview", * operationId="deleteReview",
* tags={"會員評價"}, * tags={"會員評價"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="id", in="path", required=true, description="評價 ID", @OA\Schema(type="integer")), * @OA\Parameter(name="id", in="path", required=true, description="評價 ID", @OA\Schema(type="integer")),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="刪除成功", * description="刪除成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="message", type="string", example="評價已刪除") * @OA\Property(property="message", type="string", example="評價已刪除")
* ) * )
* ), * ),
*
* @OA\Response(response=403, description="非 member 角色或非本人評價", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")), * @OA\Response(response=403, description="非 member 角色或非本人評價", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")),
* @OA\Response(response=404, description="評價不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=404, description="評價不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function deleteReview() public function deleteReview() {}
{
}
/** /**
* 標記評價為有幫助 * 標記評價為有幫助
@@ -265,22 +296,25 @@ class MemberApiDoc
* operationId="markReviewHelpful", * operationId="markReviewHelpful",
* tags={"會員評價"}, * tags={"會員評價"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="id", in="path", required=true, description="評價 ID", @OA\Schema(type="integer")), * @OA\Parameter(name="id", in="path", required=true, description="評價 ID", @OA\Schema(type="integer")),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="操作成功", * description="操作成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="helpful_count", type="integer", example=4), * @OA\Property(property="helpful_count", type="integer", example=4),
* @OA\Property(property="has_voted", type="boolean", example=true) * @OA\Property(property="has_voted", type="boolean", example=true)
* ) * )
* ), * ),
*
* @OA\Response(response=404, description="評價不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=404, description="評價不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function markReviewHelpful() public function markReviewHelpful() {}
{
}
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Booking Messages(即時訊息,Member + Provider 共用) // Booking Messages(即時訊息,Member + Provider 共用)
@@ -296,10 +330,13 @@ class MemberApiDoc
* operationId="getMessageUnreadCounts", * operationId="getMessageUnreadCounts",
* tags={"即時訊息"}, * tags={"即時訊息"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="取得成功", * description="取得成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property( * @OA\Property(
* property="data", * property="data",
@@ -311,9 +348,7 @@ class MemberApiDoc
* ) * )
* ) * )
*/ */
public function getMessageUnreadCounts() public function getMessageUnreadCounts() {}
{
}
/** /**
* 取得預約訊息列表 * 取得預約訊息列表
@@ -325,17 +360,23 @@ class MemberApiDoc
* operationId="listBookingMessages", * operationId="listBookingMessages",
* tags={"即時訊息"}, * tags={"即時訊息"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="booking", in="path", required=true, description="預約 ID", @OA\Schema(type="integer")), * @OA\Parameter(name="booking", in="path", required=true, description="預約 ID", @OA\Schema(type="integer")),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="取得成功", * description="取得成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property( * @OA\Property(
* property="data", * property="data",
* type="array", * type="array",
*
* @OA\Items( * @OA\Items(
* type="object", * type="object",
*
* @OA\Property(property="id", type="integer", example=1), * @OA\Property(property="id", type="integer", example=1),
* @OA\Property(property="booking_id", type="integer", example=12), * @OA\Property(property="booking_id", type="integer", example=12),
* @OA\Property(property="sender_type", type="string", enum={"member","provider"}, example="member"), * @OA\Property(property="sender_type", type="string", enum={"member","provider"}, example="member"),
@@ -347,13 +388,12 @@ class MemberApiDoc
* ) * )
* ) * )
* ), * ),
*
* @OA\Response(response=403, description="非參與方或預約狀態不符", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")), * @OA\Response(response=403, description="非參與方或預約狀態不符", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")),
* @OA\Response(response=404, description="預約不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=404, description="預約不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function listBookingMessages() public function listBookingMessages() {}
{
}
/** /**
* 發送預約訊息 * 發送預約訊息
@@ -365,21 +405,29 @@ class MemberApiDoc
* operationId="sendBookingMessage", * operationId="sendBookingMessage",
* tags={"即時訊息"}, * tags={"即時訊息"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="booking", in="path", required=true, description="預約 ID", @OA\Schema(type="integer")), * @OA\Parameter(name="booking", in="path", required=true, description="預約 ID", @OA\Schema(type="integer")),
*
* @OA\RequestBody( * @OA\RequestBody(
* required=true, * required=true,
*
* @OA\MediaType( * @OA\MediaType(
* mediaType="multipart/form-data", * mediaType="multipart/form-data",
*
* @OA\Schema( * @OA\Schema(
*
* @OA\Property(property="message", type="string", nullable=true, example="請問需要自備潛水裝備嗎?"), * @OA\Property(property="message", type="string", nullable=true, example="請問需要自備潛水裝備嗎?"),
* @OA\Property(property="image", type="string", format="binary", nullable=true, description="圖片(jpg/png,message 與 image 至少擇一)") * @OA\Property(property="image", type="string", format="binary", nullable=true, description="圖片(jpg/png,message 與 image 至少擇一)")
* ) * )
* ) * )
* ), * ),
*
* @OA\Response( * @OA\Response(
* response=201, * response=201,
* description="訊息已送出", * description="訊息已送出",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property( * @OA\Property(
* property="data", * property="data",
@@ -394,13 +442,12 @@ class MemberApiDoc
* ) * )
* ) * )
* ), * ),
*
* @OA\Response(response=403, description="非參與方或預約狀態不符", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")), * @OA\Response(response=403, description="非參與方或預約狀態不符", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")),
* @OA\Response(response=422, description="message 與 image 皆為空", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=422, description="message 與 image 皆為空", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function sendBookingMessage() public function sendBookingMessage() {}
{
}
/** /**
* 標記訊息為已讀 * 標記訊息為已讀
@@ -412,21 +459,24 @@ class MemberApiDoc
* operationId="markMessagesRead", * operationId="markMessagesRead",
* tags={"即時訊息"}, * tags={"即時訊息"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="booking", in="path", required=true, description="預約 ID", @OA\Schema(type="integer")), * @OA\Parameter(name="booking", in="path", required=true, description="預約 ID", @OA\Schema(type="integer")),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="標記成功", * description="標記成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="message", type="string", example="已標記為已讀") * @OA\Property(property="message", type="string", example="已標記為已讀")
* ) * )
* ), * ),
*
* @OA\Response(response=403, description="非參與方", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=403, description="非參與方", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function markMessagesRead() public function markMessagesRead() {}
{
}
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Notifications (Member + Provider 共用) // Notifications (Member + Provider 共用)
@@ -442,18 +492,24 @@ class MemberApiDoc
* operationId="listNotifications", * operationId="listNotifications",
* tags={"通知"}, * tags={"通知"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="page", in="query", description="頁碼", @OA\Schema(type="integer", default=1)), * @OA\Parameter(name="page", in="query", description="頁碼", @OA\Schema(type="integer", default=1)),
* @OA\Parameter(name="per_page", in="query", description="每頁筆數", @OA\Schema(type="integer", default=15)), * @OA\Parameter(name="per_page", in="query", description="每頁筆數", @OA\Schema(type="integer", default=15)),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="取得成功", * description="取得成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property( * @OA\Property(
* property="data", * property="data",
* type="array", * type="array",
*
* @OA\Items( * @OA\Items(
* type="object", * type="object",
*
* @OA\Property(property="id", type="integer", example=1), * @OA\Property(property="id", type="integer", example=1),
* @OA\Property(property="type", type="string", example="booking_confirmed"), * @OA\Property(property="type", type="string", example="booking_confirmed"),
* @OA\Property(property="title", type="string", example="預約已確認"), * @OA\Property(property="title", type="string", example="預約已確認"),
@@ -467,9 +523,7 @@ class MemberApiDoc
* ) * )
* ) * )
*/ */
public function listNotifications() public function listNotifications() {}
{
}
/** /**
* 取得未讀通知數量 * 取得未讀通知數量
@@ -480,19 +534,20 @@ class MemberApiDoc
* operationId="getUnreadNotificationCount", * operationId="getUnreadNotificationCount",
* tags={"通知"}, * tags={"通知"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="取得成功", * description="取得成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="unread_count", type="integer", example=3) * @OA\Property(property="unread_count", type="integer", example=3)
* ) * )
* ) * )
* ) * )
*/ */
public function getUnreadNotificationCount() public function getUnreadNotificationCount() {}
{
}
/** /**
* 標記單一通知為已讀 * 標記單一通知為已讀
@@ -503,21 +558,24 @@ class MemberApiDoc
* operationId="markNotificationRead", * operationId="markNotificationRead",
* tags={"通知"}, * tags={"通知"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="id", in="path", required=true, description="通知 ID", @OA\Schema(type="integer")), * @OA\Parameter(name="id", in="path", required=true, description="通知 ID", @OA\Schema(type="integer")),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="標記成功", * description="標記成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="message", type="string", example="通知已標記為已讀") * @OA\Property(property="message", type="string", example="通知已標記為已讀")
* ) * )
* ), * ),
*
* @OA\Response(response=404, description="通知不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=404, description="通知不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function markNotificationRead() public function markNotificationRead() {}
{
}
/** /**
* 全部通知標記為已讀 * 全部通知標記為已讀
@@ -528,19 +586,20 @@ class MemberApiDoc
* operationId="markAllNotificationsRead", * operationId="markAllNotificationsRead",
* tags={"通知"}, * tags={"通知"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="標記成功", * description="標記成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="message", type="string", example="所有通知已標記為已讀") * @OA\Property(property="message", type="string", example="所有通知已標記為已讀")
* ) * )
* ) * )
* ) * )
*/ */
public function markAllNotificationsRead() public function markAllNotificationsRead() {}
{
}
/** /**
* 刪除通知 * 刪除通知
@@ -551,19 +610,22 @@ class MemberApiDoc
* operationId="deleteNotification", * operationId="deleteNotification",
* tags={"通知"}, * tags={"通知"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="id", in="path", required=true, description="通知 ID", @OA\Schema(type="integer")), * @OA\Parameter(name="id", in="path", required=true, description="通知 ID", @OA\Schema(type="integer")),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="刪除成功", * description="刪除成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="message", type="string", example="通知已刪除") * @OA\Property(property="message", type="string", example="通知已刪除")
* ) * )
* ), * ),
*
* @OA\Response(response=404, description="通知不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=404, description="通知不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function deleteNotification() public function deleteNotification() {}
{
}
} }
+154 -66
View File
@@ -42,10 +42,13 @@ class ProviderApiDoc
* operationId="getProviderVerification", * operationId="getProviderVerification",
* tags={"教練驗證"}, * tags={"教練驗證"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="取得成功", * description="取得成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property( * @OA\Property(
* property="data", * property="data",
@@ -55,8 +58,10 @@ class ProviderApiDoc
* @OA\Property( * @OA\Property(
* property="certifications", * property="certifications",
* type="array", * type="array",
*
* @OA\Items( * @OA\Items(
* type="object", * type="object",
*
* @OA\Property(property="id", type="integer", example=1), * @OA\Property(property="id", type="integer", example=1),
* @OA\Property(property="url", type="string", example="http://localhost:8080/storage/providers/5/certifications/uuid.jpg") * @OA\Property(property="url", type="string", example="http://localhost:8080/storage/providers/5/certifications/uuid.jpg")
* ) * )
@@ -64,12 +69,11 @@ class ProviderApiDoc
* ) * )
* ) * )
* ), * ),
*
* @OA\Response(response=403, description="非 provider 角色", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=403, description="非 provider 角色", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function getProviderVerification() public function getProviderVerification() {}
{
}
/** /**
* 上傳證照圖片 * 上傳證照圖片
@@ -81,20 +85,27 @@ class ProviderApiDoc
* operationId="uploadCertification", * operationId="uploadCertification",
* tags={"教練驗證"}, * tags={"教練驗證"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\RequestBody( * @OA\RequestBody(
* required=true, * required=true,
*
* @OA\MediaType( * @OA\MediaType(
* mediaType="multipart/form-data", * mediaType="multipart/form-data",
*
* @OA\Schema( * @OA\Schema(
* required={"certification"}, * required={"certification"},
*
* @OA\Property(property="certification", type="string", format="binary", description="證照圖片(jpg/png,最大 5MB)") * @OA\Property(property="certification", type="string", format="binary", description="證照圖片(jpg/png,最大 5MB)")
* ) * )
* ) * )
* ), * ),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="上傳成功", * description="上傳成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property( * @OA\Property(
* property="data", * property="data",
@@ -104,13 +115,12 @@ class ProviderApiDoc
* ) * )
* ) * )
* ), * ),
*
* @OA\Response(response=422, description="圖片驗證失敗", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")), * @OA\Response(response=422, description="圖片驗證失敗", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")),
* @OA\Response(response=403, description="非 provider 角色", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=403, description="非 provider 角色", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function uploadCertification() public function uploadCertification() {}
{
}
/** /**
* 刪除證照圖片 * 刪除證照圖片
@@ -122,22 +132,25 @@ class ProviderApiDoc
* operationId="deleteCertification", * operationId="deleteCertification",
* tags={"教練驗證"}, * tags={"教練驗證"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="id", in="path", required=true, description="證照 ID", @OA\Schema(type="integer")), * @OA\Parameter(name="id", in="path", required=true, description="證照 ID", @OA\Schema(type="integer")),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="刪除成功", * description="刪除成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="message", type="string", example="證照已刪除") * @OA\Property(property="message", type="string", example="證照已刪除")
* ) * )
* ), * ),
*
* @OA\Response(response=403, description="非 provider 角色、非本人證照或當前狀態不可刪除", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")), * @OA\Response(response=403, description="非 provider 角色、非本人證照或當前狀態不可刪除", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")),
* @OA\Response(response=404, description="證照不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=404, description="證照不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function deleteCertification() public function deleteCertification() {}
{
}
/** /**
* 送出驗證申請 * 送出驗證申請
@@ -149,21 +162,23 @@ class ProviderApiDoc
* operationId="submitVerification", * operationId="submitVerification",
* tags={"教練驗證"}, * tags={"教練驗證"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="送審成功", * description="送審成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="message", type="string", example="驗證申請已送出") * @OA\Property(property="message", type="string", example="驗證申請已送出")
* ) * )
* ), * ),
*
* @OA\Response(response=422, description="尚未上傳證照或當前狀態不可送審", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")), * @OA\Response(response=422, description="尚未上傳證照或當前狀態不可送審", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")),
* @OA\Response(response=403, description="非 provider 角色", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=403, description="非 provider 角色", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function submitVerification() public function submitVerification() {}
{
}
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Provider Offers CRUD // Provider Offers CRUD
@@ -179,23 +194,26 @@ class ProviderApiDoc
* operationId="listProviderOffers", * operationId="listProviderOffers",
* tags={"教練課程"}, * tags={"教練課程"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="page", in="query", description="頁碼", @OA\Schema(type="integer", default=1)), * @OA\Parameter(name="page", in="query", description="頁碼", @OA\Schema(type="integer", default=1)),
* @OA\Parameter(name="per_page", in="query", description="每頁筆數", @OA\Schema(type="integer", default=15)), * @OA\Parameter(name="per_page", in="query", description="每頁筆數", @OA\Schema(type="integer", default=15)),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="取得成功", * description="取得成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="data", type="array", @OA\Items(ref="#/components/schemas/DivingOffer")), * @OA\Property(property="data", type="array", @OA\Items(ref="#/components/schemas/DivingOffer")),
* @OA\Property(property="meta", ref="#/components/schemas/PaginationMeta") * @OA\Property(property="meta", ref="#/components/schemas/PaginationMeta")
* ) * )
* ), * ),
*
* @OA\Response(response=403, description="非 provider 角色", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=403, description="非 provider 角色", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function listProviderOffers() public function listProviderOffers() {}
{
}
/** /**
* 建立課程 * 建立課程
@@ -207,10 +225,13 @@ class ProviderApiDoc
* operationId="createProviderOffer", * operationId="createProviderOffer",
* tags={"教練課程"}, * tags={"教練課程"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\RequestBody( * @OA\RequestBody(
* required=true, * required=true,
*
* @OA\JsonContent( * @OA\JsonContent(
* required={"title","description","region","price","max_participants"}, * required={"title","description","region","price","max_participants"},
*
* @OA\Property(property="title", type="string", example="基礎開放水域課程"), * @OA\Property(property="title", type="string", example="基礎開放水域課程"),
* @OA\Property(property="description", type="string", example="適合初學者的 OWD 課程"), * @OA\Property(property="description", type="string", example="適合初學者的 OWD 課程"),
* @OA\Property(property="region", type="string", example="墾丁"), * @OA\Property(property="region", type="string", example="墾丁"),
@@ -219,22 +240,24 @@ class ProviderApiDoc
* @OA\Property(property="tags", type="array", @OA\Items(type="string"), example={"初學","OWD"}) * @OA\Property(property="tags", type="array", @OA\Items(type="string"), example={"初學","OWD"})
* ) * )
* ), * ),
*
* @OA\Response( * @OA\Response(
* response=201, * response=201,
* description="課程建立成功", * description="課程建立成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="message", type="string", example="課程建立成功"), * @OA\Property(property="message", type="string", example="課程建立成功"),
* @OA\Property(property="data", ref="#/components/schemas/DivingOffer") * @OA\Property(property="data", ref="#/components/schemas/DivingOffer")
* ) * )
* ), * ),
*
* @OA\Response(response=422, description="驗證失敗", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")), * @OA\Response(response=422, description="驗證失敗", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")),
* @OA\Response(response=403, description="非 provider 角色", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=403, description="非 provider 角色", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function createProviderOffer() public function createProviderOffer() {}
{
}
/** /**
* 取得單一課程(Provider 視角) * 取得單一課程(Provider 視角)
@@ -246,22 +269,25 @@ class ProviderApiDoc
* operationId="getProviderOffer", * operationId="getProviderOffer",
* tags={"教練課程"}, * tags={"教練課程"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="id", in="path", required=true, description="課程 ID", @OA\Schema(type="integer")), * @OA\Parameter(name="id", in="path", required=true, description="課程 ID", @OA\Schema(type="integer")),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="取得成功", * description="取得成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="data", ref="#/components/schemas/DivingOffer") * @OA\Property(property="data", ref="#/components/schemas/DivingOffer")
* ) * )
* ), * ),
*
* @OA\Response(response=403, description="非 provider 角色或非本人課程", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")), * @OA\Response(response=403, description="非 provider 角色或非本人課程", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")),
* @OA\Response(response=404, description="課程不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=404, description="課程不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function getProviderOffer() public function getProviderOffer() {}
{
}
/** /**
* 更新課程 * 更新課程
@@ -272,10 +298,14 @@ class ProviderApiDoc
* operationId="updateProviderOffer", * operationId="updateProviderOffer",
* tags={"教練課程"}, * tags={"教練課程"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="id", in="path", required=true, description="課程 ID", @OA\Schema(type="integer")), * @OA\Parameter(name="id", in="path", required=true, description="課程 ID", @OA\Schema(type="integer")),
*
* @OA\RequestBody( * @OA\RequestBody(
* required=true, * required=true,
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="title", type="string", example="進階開放水域課程"), * @OA\Property(property="title", type="string", example="進階開放水域課程"),
* @OA\Property(property="description", type="string", example="AOWD 課程"), * @OA\Property(property="description", type="string", example="AOWD 課程"),
* @OA\Property(property="region", type="string", example="小琉球"), * @OA\Property(property="region", type="string", example="小琉球"),
@@ -285,21 +315,23 @@ class ProviderApiDoc
* @OA\Property(property="is_active", type="boolean", example=true) * @OA\Property(property="is_active", type="boolean", example=true)
* ) * )
* ), * ),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="更新成功", * description="更新成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="data", ref="#/components/schemas/DivingOffer") * @OA\Property(property="data", ref="#/components/schemas/DivingOffer")
* ) * )
* ), * ),
*
* @OA\Response(response=403, description="非 provider 角色或非本人課程", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")), * @OA\Response(response=403, description="非 provider 角色或非本人課程", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")),
* @OA\Response(response=422, description="驗證失敗", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=422, description="驗證失敗", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function updateProviderOffer() public function updateProviderOffer() {}
{
}
/** /**
* 刪除課程 * 刪除課程
@@ -310,22 +342,25 @@ class ProviderApiDoc
* operationId="deleteProviderOffer", * operationId="deleteProviderOffer",
* tags={"教練課程"}, * tags={"教練課程"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="id", in="path", required=true, description="課程 ID", @OA\Schema(type="integer")), * @OA\Parameter(name="id", in="path", required=true, description="課程 ID", @OA\Schema(type="integer")),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="刪除成功", * description="刪除成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="message", type="string", example="課程已刪除") * @OA\Property(property="message", type="string", example="課程已刪除")
* ) * )
* ), * ),
*
* @OA\Response(response=403, description="非 provider 角色或非本人課程", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")), * @OA\Response(response=403, description="非 provider 角色或非本人課程", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")),
* @OA\Response(response=404, description="課程不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=404, description="課程不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function deleteProviderOffer() public function deleteProviderOffer() {}
{
}
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Provider Offer Images // Provider Offer Images
@@ -341,32 +376,39 @@ class ProviderApiDoc
* operationId="uploadOfferCover", * operationId="uploadOfferCover",
* tags={"教練圖片"}, * tags={"教練圖片"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="id", in="path", required=true, description="課程 ID", @OA\Schema(type="integer")), * @OA\Parameter(name="id", in="path", required=true, description="課程 ID", @OA\Schema(type="integer")),
*
* @OA\RequestBody( * @OA\RequestBody(
* required=true, * required=true,
*
* @OA\MediaType( * @OA\MediaType(
* mediaType="multipart/form-data", * mediaType="multipart/form-data",
*
* @OA\Schema( * @OA\Schema(
* required={"cover_image"}, * required={"cover_image"},
*
* @OA\Property(property="cover_image", type="string", format="binary", description="封面圖片(jpg/png,最大 5MB)") * @OA\Property(property="cover_image", type="string", format="binary", description="封面圖片(jpg/png,最大 5MB)")
* ) * )
* ) * )
* ), * ),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="上傳成功", * description="上傳成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="cover_image_url", type="string", example="https://example.com/covers/1.jpg") * @OA\Property(property="cover_image_url", type="string", example="https://example.com/covers/1.jpg")
* ) * )
* ), * ),
*
* @OA\Response(response=422, description="圖片驗證失敗", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")), * @OA\Response(response=422, description="圖片驗證失敗", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")),
* @OA\Response(response=403, description="非 provider 角色或非本人課程", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=403, description="非 provider 角色或非本人課程", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function uploadOfferCover() public function uploadOfferCover() {}
{
}
/** /**
* 刪除封面圖片 * 刪除封面圖片
@@ -377,21 +419,24 @@ class ProviderApiDoc
* operationId="deleteOfferCover", * operationId="deleteOfferCover",
* tags={"教練圖片"}, * tags={"教練圖片"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="id", in="path", required=true, description="課程 ID", @OA\Schema(type="integer")), * @OA\Parameter(name="id", in="path", required=true, description="課程 ID", @OA\Schema(type="integer")),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="刪除成功", * description="刪除成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="message", type="string", example="封面圖片已刪除") * @OA\Property(property="message", type="string", example="封面圖片已刪除")
* ) * )
* ), * ),
*
* @OA\Response(response=403, description="非 provider 角色或非本人課程", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=403, description="非 provider 角色或非本人課程", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function deleteOfferCover() public function deleteOfferCover() {}
{
}
/** /**
* 上傳相簿圖片 * 上傳相簿圖片
@@ -403,37 +448,45 @@ class ProviderApiDoc
* operationId="uploadOfferImages", * operationId="uploadOfferImages",
* tags={"教練圖片"}, * tags={"教練圖片"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="id", in="path", required=true, description="課程 ID", @OA\Schema(type="integer")), * @OA\Parameter(name="id", in="path", required=true, description="課程 ID", @OA\Schema(type="integer")),
*
* @OA\RequestBody( * @OA\RequestBody(
* required=true, * required=true,
*
* @OA\MediaType( * @OA\MediaType(
* mediaType="multipart/form-data", * mediaType="multipart/form-data",
*
* @OA\Schema( * @OA\Schema(
* required={"images[]"}, * required={"images[]"},
*
* @OA\Property( * @OA\Property(
* property="images[]", * property="images[]",
* type="array", * type="array",
*
* @OA\Items(type="string", format="binary"), * @OA\Items(type="string", format="binary"),
* description="相簿圖片(每張最大 5MB)" * description="相簿圖片(每張最大 5MB)"
* ) * )
* ) * )
* ) * )
* ), * ),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="上傳成功", * description="上傳成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="images", type="array", @OA\Items(type="string"), example={"https://example.com/img/1.jpg"}) * @OA\Property(property="images", type="array", @OA\Items(type="string"), example={"https://example.com/img/1.jpg"})
* ) * )
* ), * ),
*
* @OA\Response(response=422, description="圖片驗證失敗", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")), * @OA\Response(response=422, description="圖片驗證失敗", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")),
* @OA\Response(response=403, description="非 provider 角色或非本人課程", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=403, description="非 provider 角色或非本人課程", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function uploadOfferImages() public function uploadOfferImages() {}
{
}
/** /**
* 刪除相簿圖片 * 刪除相簿圖片
@@ -444,22 +497,25 @@ class ProviderApiDoc
* operationId="deleteOfferImage", * operationId="deleteOfferImage",
* tags={"教練圖片"}, * tags={"教練圖片"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="id", in="path", required=true, description="圖片 ID", @OA\Schema(type="integer")), * @OA\Parameter(name="id", in="path", required=true, description="圖片 ID", @OA\Schema(type="integer")),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="刪除成功", * description="刪除成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="message", type="string", example="圖片已刪除") * @OA\Property(property="message", type="string", example="圖片已刪除")
* ) * )
* ), * ),
*
* @OA\Response(response=403, description="非 provider 角色或非本人圖片", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")), * @OA\Response(response=403, description="非 provider 角色或非本人圖片", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")),
* @OA\Response(response=404, description="圖片不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=404, description="圖片不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function deleteOfferImage() public function deleteOfferImage() {}
{
}
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Provider Schedules // Provider Schedules
@@ -475,21 +531,24 @@ class ProviderApiDoc
* operationId="listProviderSchedules", * operationId="listProviderSchedules",
* tags={"教練時段"}, * tags={"教練時段"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="offer_id", in="query", required=false, description="課程 ID 篩選", @OA\Schema(type="integer")), * @OA\Parameter(name="offer_id", in="query", required=false, description="課程 ID 篩選", @OA\Schema(type="integer")),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="取得成功", * description="取得成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="data", type="array", @OA\Items(ref="#/components/schemas/CourseSchedule")) * @OA\Property(property="data", type="array", @OA\Items(ref="#/components/schemas/CourseSchedule"))
* ) * )
* ), * ),
*
* @OA\Response(response=403, description="非 provider 角色", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=403, description="非 provider 角色", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function listProviderSchedules() public function listProviderSchedules() {}
{
}
/** /**
* 建立時段 * 建立時段
@@ -500,31 +559,36 @@ class ProviderApiDoc
* operationId="createProviderSchedule", * operationId="createProviderSchedule",
* tags={"教練時段"}, * tags={"教練時段"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\RequestBody( * @OA\RequestBody(
* required=true, * required=true,
*
* @OA\JsonContent( * @OA\JsonContent(
* required={"offer_id","start_date","end_date","available_slots"}, * required={"offer_id","start_date","end_date","available_slots"},
*
* @OA\Property(property="offer_id", type="integer", example=1), * @OA\Property(property="offer_id", type="integer", example=1),
* @OA\Property(property="start_date", type="string", format="date", example="2025-07-01"), * @OA\Property(property="start_date", type="string", format="date", example="2025-07-01"),
* @OA\Property(property="end_date", type="string", format="date", example="2025-07-03"), * @OA\Property(property="end_date", type="string", format="date", example="2025-07-03"),
* @OA\Property(property="available_slots", type="integer", example=4) * @OA\Property(property="available_slots", type="integer", example=4)
* ) * )
* ), * ),
*
* @OA\Response( * @OA\Response(
* response=201, * response=201,
* description="時段建立成功", * description="時段建立成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="data", ref="#/components/schemas/CourseSchedule") * @OA\Property(property="data", ref="#/components/schemas/CourseSchedule")
* ) * )
* ), * ),
*
* @OA\Response(response=422, description="驗證失敗", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")), * @OA\Response(response=422, description="驗證失敗", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")),
* @OA\Response(response=403, description="非 provider 角色或非本人課程", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=403, description="非 provider 角色或非本人課程", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function createProviderSchedule() public function createProviderSchedule() {}
{
}
/** /**
* 更新時段 * 更新時段
@@ -535,31 +599,37 @@ class ProviderApiDoc
* operationId="updateProviderSchedule", * operationId="updateProviderSchedule",
* tags={"教練時段"}, * tags={"教練時段"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="id", in="path", required=true, description="時段 ID", @OA\Schema(type="integer")), * @OA\Parameter(name="id", in="path", required=true, description="時段 ID", @OA\Schema(type="integer")),
*
* @OA\RequestBody( * @OA\RequestBody(
* required=true, * required=true,
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="start_date", type="string", format="date", example="2025-07-05"), * @OA\Property(property="start_date", type="string", format="date", example="2025-07-05"),
* @OA\Property(property="end_date", type="string", format="date", example="2025-07-07"), * @OA\Property(property="end_date", type="string", format="date", example="2025-07-07"),
* @OA\Property(property="available_slots", type="integer", example=6), * @OA\Property(property="available_slots", type="integer", example=6),
* @OA\Property(property="is_active", type="boolean", example=true) * @OA\Property(property="is_active", type="boolean", example=true)
* ) * )
* ), * ),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="更新成功", * description="更新成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="data", ref="#/components/schemas/CourseSchedule") * @OA\Property(property="data", ref="#/components/schemas/CourseSchedule")
* ) * )
* ), * ),
*
* @OA\Response(response=403, description="非 provider 角色或非本人時段", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")), * @OA\Response(response=403, description="非 provider 角色或非本人時段", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")),
* @OA\Response(response=404, description="時段不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=404, description="時段不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function updateProviderSchedule() public function updateProviderSchedule() {}
{
}
/** /**
* 刪除時段 * 刪除時段
@@ -570,22 +640,25 @@ class ProviderApiDoc
* operationId="deleteProviderSchedule", * operationId="deleteProviderSchedule",
* tags={"教練時段"}, * tags={"教練時段"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="id", in="path", required=true, description="時段 ID", @OA\Schema(type="integer")), * @OA\Parameter(name="id", in="path", required=true, description="時段 ID", @OA\Schema(type="integer")),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="刪除成功", * description="刪除成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="message", type="string", example="時段已刪除") * @OA\Property(property="message", type="string", example="時段已刪除")
* ) * )
* ), * ),
*
* @OA\Response(response=403, description="非 provider 角色或非本人時段", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")), * @OA\Response(response=403, description="非 provider 角色或非本人時段", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")),
* @OA\Response(response=404, description="時段不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=404, description="時段不存在", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function deleteProviderSchedule() public function deleteProviderSchedule() {}
{
}
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Provider Bookings Management // Provider Bookings Management
@@ -601,23 +674,26 @@ class ProviderApiDoc
* operationId="listProviderBookings", * operationId="listProviderBookings",
* tags={"教練預約"}, * tags={"教練預約"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="page", in="query", description="頁碼", @OA\Schema(type="integer", default=1)), * @OA\Parameter(name="page", in="query", description="頁碼", @OA\Schema(type="integer", default=1)),
* @OA\Parameter(name="per_page", in="query", description="每頁筆數", @OA\Schema(type="integer", default=15)), * @OA\Parameter(name="per_page", in="query", description="每頁筆數", @OA\Schema(type="integer", default=15)),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="取得成功", * description="取得成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="data", type="array", @OA\Items(ref="#/components/schemas/Booking")), * @OA\Property(property="data", type="array", @OA\Items(ref="#/components/schemas/Booking")),
* @OA\Property(property="meta", ref="#/components/schemas/PaginationMeta") * @OA\Property(property="meta", ref="#/components/schemas/PaginationMeta")
* ) * )
* ), * ),
*
* @OA\Response(response=403, description="非 provider 角色", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=403, description="非 provider 角色", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function listProviderBookings() public function listProviderBookings() {}
{
}
/** /**
* 確認預約 * 確認預約
@@ -628,23 +704,26 @@ class ProviderApiDoc
* operationId="confirmBooking", * operationId="confirmBooking",
* tags={"教練預約"}, * tags={"教練預約"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="id", in="path", required=true, description="預約 ID", @OA\Schema(type="integer")), * @OA\Parameter(name="id", in="path", required=true, description="預約 ID", @OA\Schema(type="integer")),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="確認成功", * description="確認成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="message", type="string", example="預約已確認"), * @OA\Property(property="message", type="string", example="預約已確認"),
* @OA\Property(property="data", ref="#/components/schemas/Booking") * @OA\Property(property="data", ref="#/components/schemas/Booking")
* ) * )
* ), * ),
*
* @OA\Response(response=403, description="非 provider 角色或非本人課程的預約", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")), * @OA\Response(response=403, description="非 provider 角色或非本人課程的預約", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")),
* @OA\Response(response=422, description="狀態不允許確認", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=422, description="狀態不允許確認", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function confirmBooking() public function confirmBooking() {}
{
}
/** /**
* 拒絕預約 * 拒絕預約
@@ -655,23 +734,26 @@ class ProviderApiDoc
* operationId="rejectBooking", * operationId="rejectBooking",
* tags={"教練預約"}, * tags={"教練預約"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="id", in="path", required=true, description="預約 ID", @OA\Schema(type="integer")), * @OA\Parameter(name="id", in="path", required=true, description="預約 ID", @OA\Schema(type="integer")),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="拒絕成功", * description="拒絕成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="message", type="string", example="預約已拒絕"), * @OA\Property(property="message", type="string", example="預約已拒絕"),
* @OA\Property(property="data", ref="#/components/schemas/Booking") * @OA\Property(property="data", ref="#/components/schemas/Booking")
* ) * )
* ), * ),
*
* @OA\Response(response=403, description="非 provider 角色或非本人課程的預約", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")), * @OA\Response(response=403, description="非 provider 角色或非本人課程的預約", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")),
* @OA\Response(response=422, description="狀態不允許拒絕", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=422, description="狀態不允許拒絕", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function rejectBooking() public function rejectBooking() {}
{
}
/** /**
* 標記預約完成 * 標記預約完成
@@ -682,23 +764,26 @@ class ProviderApiDoc
* operationId="completeBookingByProvider", * operationId="completeBookingByProvider",
* tags={"教練預約"}, * tags={"教練預約"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="id", in="path", required=true, description="預約 ID", @OA\Schema(type="integer")), * @OA\Parameter(name="id", in="path", required=true, description="預約 ID", @OA\Schema(type="integer")),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="標記成功", * description="標記成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="message", type="string", example="預約已完成"), * @OA\Property(property="message", type="string", example="預約已完成"),
* @OA\Property(property="data", ref="#/components/schemas/Booking") * @OA\Property(property="data", ref="#/components/schemas/Booking")
* ) * )
* ), * ),
*
* @OA\Response(response=403, description="非 provider 角色或非本人課程的預約", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")), * @OA\Response(response=403, description="非 provider 角色或非本人課程的預約", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")),
* @OA\Response(response=422, description="狀態不允許完成", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=422, description="狀態不允許完成", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function completeBookingByProvider() public function completeBookingByProvider() {}
{
}
/** /**
* 取消預約(Provider) * 取消預約(Provider)
@@ -709,21 +794,24 @@ class ProviderApiDoc
* operationId="cancelBookingByProvider", * operationId="cancelBookingByProvider",
* tags={"教練預約"}, * tags={"教練預約"},
* security={{"bearerAuth": {}}}, * security={{"bearerAuth": {}}},
*
* @OA\Parameter(name="id", in="path", required=true, description="預約 ID", @OA\Schema(type="integer")), * @OA\Parameter(name="id", in="path", required=true, description="預約 ID", @OA\Schema(type="integer")),
*
* @OA\Response( * @OA\Response(
* response=200, * response=200,
* description="取消成功", * description="取消成功",
*
* @OA\JsonContent( * @OA\JsonContent(
*
* @OA\Property(property="status", type="boolean", example=true), * @OA\Property(property="status", type="boolean", example=true),
* @OA\Property(property="message", type="string", example="預約已取消"), * @OA\Property(property="message", type="string", example="預約已取消"),
* @OA\Property(property="data", ref="#/components/schemas/Booking") * @OA\Property(property="data", ref="#/components/schemas/Booking")
* ) * )
* ), * ),
*
* @OA\Response(response=403, description="非 provider 角色或非本人課程的預約", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")), * @OA\Response(response=403, description="非 provider 角色或非本人課程的預約", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")),
* @OA\Response(response=422, description="狀態不允許取消", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse")) * @OA\Response(response=422, description="狀態不允許取消", @OA\JsonContent(ref="#/components/schemas/ApiErrorResponse"))
* ) * )
*/ */
public function cancelBookingByProvider() public function cancelBookingByProvider() {}
{
}
} }
+64 -64
View File
@@ -1,22 +1,22 @@
<?php <?php
use Illuminate\Support\Facades\Broadcast;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\API\AuthController;
use App\Http\Controllers\API\DivingOfferController;
use App\Http\Controllers\API\ProviderOfferController;
use App\Http\Controllers\API\ScheduleController;
use App\Http\Controllers\API\ProviderBookingController;
use App\Http\Controllers\API\MemberBookingController;
use App\Http\Controllers\API\ReviewController;
use App\Http\Controllers\API\AdminReviewController;
use App\Http\Controllers\API\AdminBookingController; use App\Http\Controllers\API\AdminBookingController;
use App\Http\Controllers\API\CourseImageController; use App\Http\Controllers\API\AdminOfferController;
use App\Http\Controllers\API\AdminReviewController;
use App\Http\Controllers\API\AdminStatsController; use App\Http\Controllers\API\AdminStatsController;
use App\Http\Controllers\API\AdminUserController; use App\Http\Controllers\API\AdminUserController;
use App\Http\Controllers\API\AdminOfferController; use App\Http\Controllers\API\AuthController;
use App\Http\Controllers\API\BookingMessageController; use App\Http\Controllers\API\BookingMessageController;
use App\Http\Controllers\API\CourseImageController;
use App\Http\Controllers\API\DivingOfferController;
use App\Http\Controllers\API\MemberBookingController;
use App\Http\Controllers\API\NotificationController; use App\Http\Controllers\API\NotificationController;
use App\Http\Controllers\API\ProviderBookingController;
use App\Http\Controllers\API\ProviderOfferController;
use App\Http\Controllers\API\ReviewController;
use App\Http\Controllers\API\ScheduleController;
use Illuminate\Support\Facades\Broadcast;
use Illuminate\Support\Facades\Route;
Broadcast::routes(['middleware' => ['auth:sanctum']]); Broadcast::routes(['middleware' => ['auth:sanctum']]);
@@ -24,7 +24,7 @@ Broadcast::routes(['middleware' => ['auth:sanctum']]);
Route::get('/diving-offers', [DivingOfferController::class, 'index']); Route::get('/diving-offers', [DivingOfferController::class, 'index']);
Route::get('/diving-offers/{id}', [DivingOfferController::class, 'show']); Route::get('/diving-offers/{id}', [DivingOfferController::class, 'show']);
Route::get('/diving-offers/{id}/schedules', [ScheduleController::class, 'publicList']); Route::get('/diving-offers/{id}/schedules', [ScheduleController::class, 'publicList']);
Route::get('/diving-offers/{id}/reviews', [ReviewController::class, 'publicList']); Route::get('/diving-offers/{id}/reviews', [ReviewController::class, 'publicList']);
// 會員註冊/登入 // 會員註冊/登入
Route::post('/member/register', [AuthController::class, 'registerMember']); Route::post('/member/register', [AuthController::class, 'registerMember']);
@@ -49,14 +49,14 @@ Route::middleware(['auth:sanctum', 'member'])->prefix('member')->group(function
// 修改密碼 // 修改密碼
Route::put('/change-password', [AuthController::class, 'changeMemberPassword']); Route::put('/change-password', [AuthController::class, 'changeMemberPassword']);
// 預約 // 預約
Route::get('/bookings', [MemberBookingController::class, 'index']); Route::get('/bookings', [MemberBookingController::class, 'index']);
Route::post('/bookings', [MemberBookingController::class, 'store']); Route::post('/bookings', [MemberBookingController::class, 'store']);
Route::get('/bookings/{id}', [MemberBookingController::class, 'show']); Route::get('/bookings/{id}', [MemberBookingController::class, 'show']);
Route::delete('/bookings/{id}', [MemberBookingController::class, 'destroy']); Route::delete('/bookings/{id}', [MemberBookingController::class, 'destroy']);
// 評價 // 評價
Route::post('/reviews', [ReviewController::class, 'store']); Route::post('/reviews', [ReviewController::class, 'store']);
Route::put('/reviews/{id}', [ReviewController::class, 'update']); Route::put('/reviews/{id}', [ReviewController::class, 'update']);
Route::delete('/reviews/{id}',[ReviewController::class, 'destroy']); Route::delete('/reviews/{id}', [ReviewController::class, 'destroy']);
}); });
// 有幫助投票(需登入,但不限 member prefix) // 有幫助投票(需登入,但不限 member prefix)
@@ -79,32 +79,32 @@ Route::middleware(['auth:sanctum', 'provider'])->prefix('provider')->group(funct
// 修改密碼 // 修改密碼
Route::put('/change-password', [AuthController::class, 'changeProviderPassword']); Route::put('/change-password', [AuthController::class, 'changeProviderPassword']);
// 教練課程管理 // 教練課程管理
Route::get('/offers', [ProviderOfferController::class, 'index']); Route::get('/offers', [ProviderOfferController::class, 'index']);
Route::post('/offers', [ProviderOfferController::class, 'store']); Route::post('/offers', [ProviderOfferController::class, 'store']);
Route::get('/offers/{id}', [ProviderOfferController::class, 'show']); Route::get('/offers/{id}', [ProviderOfferController::class, 'show']);
Route::put('/offers/{id}', [ProviderOfferController::class, 'update']); Route::put('/offers/{id}', [ProviderOfferController::class, 'update']);
Route::delete('/offers/{id}', [ProviderOfferController::class, 'destroy']); Route::delete('/offers/{id}', [ProviderOfferController::class, 'destroy']);
// 驗證申請(證照送審) // 驗證申請(證照送審)
Route::get('/verification', [\App\Http\Controllers\API\ProviderVerificationController::class, 'show']); Route::get('/verification', [\App\Http\Controllers\API\ProviderVerificationController::class, 'show']);
Route::post('/verification/certifications', [\App\Http\Controllers\API\ProviderVerificationController::class, 'uploadCertification']); Route::post('/verification/certifications', [\App\Http\Controllers\API\ProviderVerificationController::class, 'uploadCertification']);
Route::delete('/verification/certifications/{id}', [\App\Http\Controllers\API\ProviderVerificationController::class, 'deleteCertification']); Route::delete('/verification/certifications/{id}', [\App\Http\Controllers\API\ProviderVerificationController::class, 'deleteCertification']);
Route::post('/verification/submit', [\App\Http\Controllers\API\ProviderVerificationController::class, 'submit']); Route::post('/verification/submit', [\App\Http\Controllers\API\ProviderVerificationController::class, 'submit']);
// 課程圖片 // 課程圖片
Route::post('/offers/{id}/cover', [CourseImageController::class, 'uploadCover']); Route::post('/offers/{id}/cover', [CourseImageController::class, 'uploadCover']);
Route::delete('/offers/{id}/cover', [CourseImageController::class, 'deleteCover']); Route::delete('/offers/{id}/cover', [CourseImageController::class, 'deleteCover']);
Route::post('/offers/{id}/images', [CourseImageController::class, 'uploadImage']); Route::post('/offers/{id}/images', [CourseImageController::class, 'uploadImage']);
Route::delete('/images/{id}', [CourseImageController::class, 'deleteImage']); Route::delete('/images/{id}', [CourseImageController::class, 'deleteImage']);
// 時段管理 // 時段管理
Route::get('/schedules', [ScheduleController::class, 'index']); Route::get('/schedules', [ScheduleController::class, 'index']);
Route::post('/schedules', [ScheduleController::class, 'store']); Route::post('/schedules', [ScheduleController::class, 'store']);
Route::put('/schedules/{id}', [ScheduleController::class, 'update']); Route::put('/schedules/{id}', [ScheduleController::class, 'update']);
Route::delete('/schedules/{id}', [ScheduleController::class, 'destroy']); Route::delete('/schedules/{id}', [ScheduleController::class, 'destroy']);
// 預約管理 // 預約管理
Route::get('/bookings', [ProviderBookingController::class, 'index']); Route::get('/bookings', [ProviderBookingController::class, 'index']);
Route::put('/bookings/{id}/confirm', [ProviderBookingController::class, 'confirm']); Route::put('/bookings/{id}/confirm', [ProviderBookingController::class, 'confirm']);
Route::put('/bookings/{id}/reject', [ProviderBookingController::class, 'reject']); Route::put('/bookings/{id}/reject', [ProviderBookingController::class, 'reject']);
Route::put('/bookings/{id}/cancel', [ProviderBookingController::class, 'cancel']); Route::put('/bookings/{id}/cancel', [ProviderBookingController::class, 'cancel']);
Route::put('/bookings/{id}/complete', [ProviderBookingController::class, 'complete']); Route::put('/bookings/{id}/complete', [ProviderBookingController::class, 'complete']);
}); });
// 管理員登入(帳號建立僅限主機端 php artisan app:create-admin,不提供公開註冊) // 管理員登入(帳號建立僅限主機端 php artisan app:create-admin,不提供公開註冊)
@@ -129,42 +129,42 @@ Route::middleware(['auth:sanctum', 'admin'])->prefix('admin')->group(function ()
// 統計數據 // 統計數據
Route::get('/stats', [AdminStatsController::class, 'index']); Route::get('/stats', [AdminStatsController::class, 'index']);
// 用戶管理 // 用戶管理
Route::get('/members', [AdminUserController::class, 'members']); Route::get('/members', [AdminUserController::class, 'members']);
Route::get('/members/{id}', [AdminUserController::class, 'member']); Route::get('/members/{id}', [AdminUserController::class, 'member']);
Route::put('/members/{id}/toggle-active', [AdminUserController::class, 'toggleMemberActive']); Route::put('/members/{id}/toggle-active', [AdminUserController::class, 'toggleMemberActive']);
Route::get('/providers', [AdminUserController::class, 'providers']); Route::get('/providers', [AdminUserController::class, 'providers']);
Route::get('/providers/{id}', [AdminUserController::class, 'provider']); Route::get('/providers/{id}', [AdminUserController::class, 'provider']);
Route::put('/providers/{id}/toggle-active', [AdminUserController::class, 'toggleProviderActive']); Route::put('/providers/{id}/toggle-active', [AdminUserController::class, 'toggleProviderActive']);
// 教練審核(toggle-verified 已由審核狀態機取代) // 教練審核(toggle-verified 已由審核狀態機取代)
Route::get('/verifications', [\App\Http\Controllers\API\AdminVerificationController::class, 'index']); Route::get('/verifications', [\App\Http\Controllers\API\AdminVerificationController::class, 'index']);
Route::put('/verifications/{userId}/approve', [\App\Http\Controllers\API\AdminVerificationController::class, 'approve']); Route::put('/verifications/{userId}/approve', [\App\Http\Controllers\API\AdminVerificationController::class, 'approve']);
Route::put('/verifications/{userId}/reject', [\App\Http\Controllers\API\AdminVerificationController::class, 'reject']); Route::put('/verifications/{userId}/reject', [\App\Http\Controllers\API\AdminVerificationController::class, 'reject']);
// 課程管理 // 課程管理
Route::get('/offers', [AdminOfferController::class, 'index']); Route::get('/offers', [AdminOfferController::class, 'index']);
Route::delete('/offers/{id}', [AdminOfferController::class, 'destroy']); Route::delete('/offers/{id}', [AdminOfferController::class, 'destroy']);
// 預約管理 // 預約管理
Route::get('/bookings', [AdminBookingController::class, 'index']); Route::get('/bookings', [AdminBookingController::class, 'index']);
Route::put('/bookings/{id}/complete', [AdminBookingController::class, 'complete']); Route::put('/bookings/{id}/complete', [AdminBookingController::class, 'complete']);
// 評價管理 // 評價管理
Route::get('/reviews', [AdminReviewController::class, 'index']); Route::get('/reviews', [AdminReviewController::class, 'index']);
Route::delete('/reviews/{id}', [AdminReviewController::class, 'destroy']); Route::delete('/reviews/{id}', [AdminReviewController::class, 'destroy']);
}); });
// 通知(Member + Provider 共用) // 通知(Member + Provider 共用)
Route::middleware('auth:sanctum')->prefix('notifications')->group(function () { Route::middleware('auth:sanctum')->prefix('notifications')->group(function () {
Route::get('/', [NotificationController::class, 'index']); Route::get('/', [NotificationController::class, 'index']);
Route::get('/unread-count', [NotificationController::class, 'unreadCount']); Route::get('/unread-count', [NotificationController::class, 'unreadCount']);
Route::patch('/read-all', [NotificationController::class, 'markAllRead']); Route::patch('/read-all', [NotificationController::class, 'markAllRead']);
Route::patch('/{id}/read', [NotificationController::class, 'markRead']); Route::patch('/{id}/read', [NotificationController::class, 'markRead']);
Route::delete('/{id}', [NotificationController::class, 'destroy']); Route::delete('/{id}', [NotificationController::class, 'destroy']);
}); });
// 即時訊息(Member + Provider 共用,依 booking 參與方驗證) // 即時訊息(Member + Provider 共用,依 booking 參與方驗證)
Route::middleware('auth:sanctum')->group(function () { Route::middleware('auth:sanctum')->group(function () {
// unread-counts 必須在 {booking} 之前,否則會被 route model binding 吃掉 // unread-counts 必須在 {booking} 之前,否則會被 route model binding 吃掉
Route::get('/bookings/messages/unread-counts', [BookingMessageController::class, 'unreadCounts']); Route::get('/bookings/messages/unread-counts', [BookingMessageController::class, 'unreadCounts']);
Route::get('/bookings/{booking}/messages', [BookingMessageController::class, 'index']); Route::get('/bookings/{booking}/messages', [BookingMessageController::class, 'index']);
Route::post('/bookings/{booking}/messages', [BookingMessageController::class, 'store']); Route::post('/bookings/{booking}/messages', [BookingMessageController::class, 'store']);
Route::post('/bookings/{booking}/messages/read', [BookingMessageController::class, 'markRead']); Route::post('/bookings/{booking}/messages/read', [BookingMessageController::class, 'markRead']);
}); });
+22 -22
View File
@@ -34,22 +34,22 @@ class BookingListTest extends TestCase
$offer = DivingOffer::create([ $offer = DivingOffer::create([
'provider_id' => $provider->id, 'provider_id' => $provider->id,
'title' => 'Dive Course', 'title' => 'Dive Course',
'location' => 'Kenting', 'location' => 'Kenting',
'price' => 3000, 'price' => 3000,
'region' => '南部', 'region' => '南部',
'rating' => 0, 'rating' => 0,
'reviews' => 0, 'reviews' => 0,
]); ]);
$schedule = CourseSchedule::create([ $schedule = CourseSchedule::create([
'diving_offer_id' => $offer->id, 'diving_offer_id' => $offer->id,
'provider_id' => $provider->id, 'provider_id' => $provider->id,
'scheduled_date' => now()->addDays(30)->toDateString(), 'scheduled_date' => now()->addDays(30)->toDateString(),
'start_time' => '09:00', 'start_time' => '09:00',
'max_participants' => 10, 'max_participants' => 10,
'current_participants' => 0, 'current_participants' => 0,
'status' => ScheduleStatus::Open, 'status' => ScheduleStatus::Open,
]); ]);
return [$provider, $schedule]; return [$provider, $schedule];
@@ -58,11 +58,11 @@ class BookingListTest extends TestCase
private function makePendingBooking(User $member, CourseSchedule $schedule): Booking private function makePendingBooking(User $member, CourseSchedule $schedule): Booking
{ {
return Booking::create([ return Booking::create([
'schedule_id' => $schedule->id, 'schedule_id' => $schedule->id,
'member_id' => $member->id, 'member_id' => $member->id,
'participants' => 1, 'participants' => 1,
'total_price' => 3000, 'total_price' => 3000,
'status' => BookingStatus::Pending, 'status' => BookingStatus::Pending,
]); ]);
} }
@@ -71,8 +71,8 @@ class BookingListTest extends TestCase
public function test_member_sees_only_own_bookings(): void public function test_member_sees_only_own_bookings(): void
{ {
[$provider, $schedule] = $this->makeProviderWithSchedule(); [$provider, $schedule] = $this->makeProviderWithSchedule();
$memberA = User::factory()->create(['role' => 'member']); $memberA = User::factory()->create(['role' => 'member']);
$memberB = User::factory()->create(['role' => 'member']); $memberB = User::factory()->create(['role' => 'member']);
$bookingA = $this->makePendingBooking($memberA, $schedule); $bookingA = $this->makePendingBooking($memberA, $schedule);
$bookingB = $this->makePendingBooking($memberB, $schedule); $bookingB = $this->makePendingBooking($memberB, $schedule);
@@ -90,7 +90,7 @@ class BookingListTest extends TestCase
{ {
[$providerA, $scheduleA] = $this->makeProviderWithSchedule(); [$providerA, $scheduleA] = $this->makeProviderWithSchedule();
[$providerB, $scheduleB] = $this->makeProviderWithSchedule(); [$providerB, $scheduleB] = $this->makeProviderWithSchedule();
$member = User::factory()->create(['role' => 'member']); $member = User::factory()->create(['role' => 'member']);
$bookingA = $this->makePendingBooking($member, $scheduleA); $bookingA = $this->makePendingBooking($member, $scheduleA);
$bookingB = $this->makePendingBooking($member, $scheduleB); $bookingB = $this->makePendingBooking($member, $scheduleB);
@@ -106,11 +106,11 @@ class BookingListTest extends TestCase
public function test_admin_sees_all_bookings(): void public function test_admin_sees_all_bookings(): void
{ {
$admin = User::factory()->create(['role' => 'admin']); $admin = User::factory()->create(['role' => 'admin']);
[$providerA, $scheduleA] = $this->makeProviderWithSchedule(); [$providerA, $scheduleA] = $this->makeProviderWithSchedule();
[$providerB, $scheduleB] = $this->makeProviderWithSchedule(); [$providerB, $scheduleB] = $this->makeProviderWithSchedule();
$memberA = User::factory()->create(['role' => 'member']); $memberA = User::factory()->create(['role' => 'member']);
$memberB = User::factory()->create(['role' => 'member']); $memberB = User::factory()->create(['role' => 'member']);
$bookingA = $this->makePendingBooking($memberA, $scheduleA); $bookingA = $this->makePendingBooking($memberA, $scheduleA);
$bookingB = $this->makePendingBooking($memberB, $scheduleB); $bookingB = $this->makePendingBooking($memberB, $scheduleB);