middleware('can:view_announcements')->only(['index', 'show']); $this->middleware('can:create_announcements')->only(['create', 'store']); $this->middleware('can:edit_announcements')->only(['edit', 'update']); $this->middleware('can:delete_announcements')->only(['destroy']); $this->middleware('can:publish_announcements')->only(['publish', 'archive']); } /** * Display a listing of announcements */ public function index(Request $request) { $query = Announcement::with(['creator', 'lastUpdatedBy']) ->orderByDesc('is_pinned') ->orderByDesc('created_at'); // Filter by status if ($request->filled('status')) { $query->where('status', $request->status); } // Filter by access level if ($request->filled('access_level')) { $query->where('access_level', $request->access_level); } // Filter by pinned if ($request->filled('pinned')) { $query->where('is_pinned', $request->pinned === 'yes'); } // Search if ($request->filled('search')) { $search = $request->search; $query->where(function($q) use ($search) { $q->where('title', 'like', "%{$search}%") ->orWhere('content', 'like', "%{$search}%"); }); } $announcements = $query->paginate(20); // Statistics $stats = [ 'total' => Announcement::count(), 'draft' => Announcement::draft()->count(), 'published' => Announcement::published()->count(), 'archived' => Announcement::archived()->count(), 'pinned' => Announcement::pinned()->count(), ]; return view('admin.announcements.index', compact('announcements', 'stats')); } /** * Show the form for creating a new announcement */ public function create() { return view('admin.announcements.create'); } /** * Store a newly created announcement */ public function store(Request $request) { $validated = $request->validate([ 'title' => 'required|string|max:255', 'content' => 'required|string', 'access_level' => 'required|in:public,members,board,admin', 'published_at' => 'nullable|date', 'expires_at' => 'nullable|date|after:published_at', 'is_pinned' => 'boolean', 'display_order' => 'nullable|integer', 'save_action' => 'required|in:draft,publish', ]); $announcement = Announcement::create([ 'title' => $validated['title'], 'content' => $validated['content'], 'access_level' => $validated['access_level'], 'status' => $validated['save_action'] === 'publish' ? Announcement::STATUS_PUBLISHED : Announcement::STATUS_DRAFT, 'published_at' => $validated['save_action'] === 'publish' ? ($validated['published_at'] ?? now()) : null, 'expires_at' => $validated['expires_at'] ?? null, 'is_pinned' => $validated['is_pinned'] ?? false, 'display_order' => $validated['display_order'] ?? 0, 'created_by_user_id' => auth()->id(), 'last_updated_by_user_id' => auth()->id(), ]); // Audit log AuditLog::create([ 'user_id' => auth()->id(), 'action' => 'announcement.created', 'description' => "建立公告:{$announcement->title} (狀態:{$announcement->getStatusLabel()})", 'ip_address' => request()->ip(), ]); $message = $validated['save_action'] === 'publish' ? '公告已成功發布' : '公告已儲存為草稿'; return redirect() ->route('admin.announcements.show', $announcement) ->with('status', $message); } /** * Display the specified announcement */ public function show(Announcement $announcement) { // Check if user can view this announcement if (!$announcement->canBeViewedBy(auth()->user())) { abort(403, '您沒有權限查看此公告'); } $announcement->load(['creator', 'lastUpdatedBy']); // Increment view count if viewing published announcement if ($announcement->isPublished()) { $announcement->incrementViewCount(); } return view('admin.announcements.show', compact('announcement')); } /** * Show the form for editing the specified announcement */ public function edit(Announcement $announcement) { // Check if user can edit this announcement if (!$announcement->canBeEditedBy(auth()->user())) { abort(403, '您沒有權限編輯此公告'); } return view('admin.announcements.edit', compact('announcement')); } /** * Update the specified announcement */ public function update(Request $request, Announcement $announcement) { // Check if user can edit this announcement if (!$announcement->canBeEditedBy(auth()->user())) { abort(403, '您沒有權限編輯此公告'); } $validated = $request->validate([ 'title' => 'required|string|max:255', 'content' => 'required|string', 'access_level' => 'required|in:public,members,board,admin', 'published_at' => 'nullable|date', 'expires_at' => 'nullable|date|after:published_at', 'is_pinned' => 'boolean', 'display_order' => 'nullable|integer', ]); $announcement->update([ 'title' => $validated['title'], 'content' => $validated['content'], 'access_level' => $validated['access_level'], 'published_at' => $validated['published_at'], 'expires_at' => $validated['expires_at'] ?? null, 'is_pinned' => $validated['is_pinned'] ?? false, 'display_order' => $validated['display_order'] ?? 0, 'last_updated_by_user_id' => auth()->id(), ]); // Audit log AuditLog::create([ 'user_id' => auth()->id(), 'action' => 'announcement.updated', 'description' => "更新公告:{$announcement->title}", 'ip_address' => request()->ip(), ]); return redirect() ->route('admin.announcements.show', $announcement) ->with('status', '公告已成功更新'); } /** * Remove the specified announcement (soft delete) */ public function destroy(Announcement $announcement) { // Check if user can delete this announcement if (!$announcement->canBeEditedBy(auth()->user())) { abort(403, '您沒有權限刪除此公告'); } $title = $announcement->title; $announcement->delete(); // Audit log AuditLog::create([ 'user_id' => auth()->id(), 'action' => 'announcement.deleted', 'description' => "刪除公告:{$title}", 'ip_address' => request()->ip(), ]); return redirect() ->route('admin.announcements.index') ->with('status', '公告已成功刪除'); } /** * Publish a draft announcement */ public function publish(Announcement $announcement) { // Check permission if (!auth()->user()->can('publish_announcements')) { abort(403, '您沒有權限發布公告'); } // Check if user can edit this announcement if (!$announcement->canBeEditedBy(auth()->user())) { abort(403, '您沒有權限發布此公告'); } if ($announcement->isPublished()) { return back()->with('error', '此公告已經發布'); } $announcement->publish(auth()->user()); // Audit log AuditLog::create([ 'user_id' => auth()->id(), 'action' => 'announcement.published', 'description' => "發布公告:{$announcement->title}", 'ip_address' => request()->ip(), ]); return back()->with('status', '公告已成功發布'); } /** * Archive an announcement */ public function archive(Announcement $announcement) { // Check permission if (!auth()->user()->can('publish_announcements')) { abort(403, '您沒有權限歸檔公告'); } // Check if user can edit this announcement if (!$announcement->canBeEditedBy(auth()->user())) { abort(403, '您沒有權限歸檔此公告'); } if ($announcement->isArchived()) { return back()->with('error', '此公告已經歸檔'); } $announcement->archive(auth()->user()); // Audit log AuditLog::create([ 'user_id' => auth()->id(), 'action' => 'announcement.archived', 'description' => "歸檔公告:{$announcement->title}", 'ip_address' => request()->ip(), ]); return back()->with('status', '公告已成功歸檔'); } /** * Pin an announcement */ public function pin(Request $request, Announcement $announcement) { // Check permission if (!auth()->user()->can('edit_announcements')) { abort(403, '您沒有權限置頂公告'); } // Check if user can edit this announcement if (!$announcement->canBeEditedBy(auth()->user())) { abort(403, '您沒有權限置頂此公告'); } $validated = $request->validate([ 'display_order' => 'nullable|integer', ]); $announcement->pin($validated['display_order'] ?? 0, auth()->user()); // Audit log AuditLog::create([ 'user_id' => auth()->id(), 'action' => 'announcement.pinned', 'description' => "置頂公告:{$announcement->title}", 'ip_address' => request()->ip(), ]); return back()->with('status', '公告已成功置頂'); } /** * Unpin an announcement */ public function unpin(Announcement $announcement) { // Check permission if (!auth()->user()->can('edit_announcements')) { abort(403, '您沒有權限取消置頂公告'); } // Check if user can edit this announcement if (!$announcement->canBeEditedBy(auth()->user())) { abort(403, '您沒有權限取消置頂此公告'); } $announcement->unpin(auth()->user()); // Audit log AuditLog::create([ 'user_id' => auth()->id(), 'action' => 'announcement.unpinned', 'description' => "取消置頂公告:{$announcement->title}", 'ip_address' => request()->ip(), ]); return back()->with('status', '公告已取消置頂'); } }