diff --git a/app/Http/Controllers/Admin/CourseController.php b/app/Http/Controllers/Admin/CourseController.php new file mode 100755 index 0000000..d65412c --- /dev/null +++ b/app/Http/Controllers/Admin/CourseController.php @@ -0,0 +1,148 @@ +middleware('auth'); + } + + public function index(Request $request) + { + Gate::authorize('viewAny', Course::class); + + $query = Course::with(['category', 'creator']); + + if ($request->filled('category_id')) { + $query->where('category_id', $request->category_id); + } + + if ($request->filled('type')) { + $query->where('type', $request->type); + } + + if ($request->filled('search')) { + $query->where(function($q) use ($request) { + $q->where('title', 'like', '%' . $request->search . '%') + ->orWhere('description', 'like', '%' . $request->search . '%'); + }); + } + + $courses = $query->orderBy('created_at', 'desc')->paginate(20); + $categories = CourseCategory::pluck('name', 'id'); + + return view('admin.courses.index', compact('courses', 'categories')); + } + + public function create() + { + Gate::authorize('create', Course::class); + + $categories = CourseCategory::pluck('name', 'id'); + + return view('admin.courses.create', compact('categories')); + } + + public function store(Request $request) + { + Gate::authorize('create', Course::class); + + $validated = $request->validate([ + 'title' => 'required|string|max:255', + 'slug' => 'nullable|string|max:255|unique:courses', + 'description' => 'nullable|string', + 'objectives' => 'nullable|string', + 'category_id' => 'nullable|exists:course_categories,id', + 'type' => 'required|in:standard,scorm,h5p', + 'thumbnail' => 'nullable|image|max:2048', + 'duration_minutes' => 'nullable|integer', + 'passing_score' => 'nullable|integer|min:0|max:100', + 'has_certificate' => 'boolean', + 'is_active' => 'boolean', + ]); + + $validated['slug'] = $validated['slug'] ?? Str::slug($validated['title']); + $validated['created_by'] = auth()->id(); + $validated['is_active'] = $request->boolean('is_active'); + $validated['has_certificate'] = $request->boolean('has_certificate'); + + if ($request->hasFile('thumbnail')) { + $validated['thumbnail'] = $request->file('thumbnail')->store('courses/thumbnails', 'public'); + } + + $course = Course::create($validated); + + return redirect()->route('admin.courses.show', $course)->with('success', 'Курс успешно создан.'); + } + + public function show(Course $course) + { + Gate::authorize('view', $course); + + $course->load(['category', 'creator', 'modules', 'tests']); + + return view('admin.courses.show', compact('course')); + } + + public function edit(Course $course) + { + Gate::authorize('update', $course); + + $categories = CourseCategory::pluck('name', 'id'); + + return view('admin.courses.edit', compact('course', 'categories')); + } + + public function update(Request $request, Course $course) + { + Gate::authorize('update', $course); + + $validated = $request->validate([ + 'title' => 'required|string|max:255', + 'slug' => 'nullable|string|max:255|unique:courses,slug,' . $course->id, + 'description' => 'nullable|string', + 'objectives' => 'nullable|string', + 'category_id' => 'nullable|exists:course_categories,id', + 'type' => 'required|in:standard,scorm,h5p', + 'thumbnail' => 'nullable|image|max:2048', + 'duration_minutes' => 'nullable|integer', + 'passing_score' => 'nullable|integer|min:0|max:100', + 'has_certificate' => 'boolean', + 'is_active' => 'boolean', + ]); + + $validated['slug'] = $validated['slug'] ?? Str::slug($validated['title']); + $validated['is_active'] = $request->boolean('is_active'); + $validated['has_certificate'] = $request->boolean('has_certificate'); + + if ($request->hasFile('thumbnail')) { + if ($course->thumbnail) Storage::disk('public')->delete($course->thumbnail); + $validated['thumbnail'] = $request->file('thumbnail')->store('courses/thumbnails', 'public'); + } + + $course->update($validated); + + return redirect()->route('admin.courses.show', $course)->with('success', 'Курс успешно обновлён.'); + } + + public function destroy(Course $course) + { + Gate::authorize('delete', $course); + + if ($course->thumbnail) Storage::disk('public')->delete($course->thumbnail); + + $course->delete(); + + return redirect()->route('admin.courses.index')->with('success', 'Курс успешно удалён.'); + } +} diff --git a/app/Models/Course.php b/app/Models/Course.php index dc1ca33..ac63bfb 100755 --- a/app/Models/Course.php +++ b/app/Models/Course.php @@ -74,4 +74,9 @@ class Course extends Model { return $this->hasMany(CourseRequestItem::class); } + + public function users() + { + return $this->belongsToMany(User::class, 'course_assignments'); + } } diff --git a/app/Policies/CoursePolicy.php b/app/Policies/CoursePolicy.php new file mode 100755 index 0000000..280cac0 --- /dev/null +++ b/app/Policies/CoursePolicy.php @@ -0,0 +1,34 @@ +hasRole(['Administrator', 'Manager', 'Curator']); + } + + public function view(User $user, Course $course): bool + { + return $user->hasRole(['Administrator', 'Manager', 'Curator']); + } + + public function create(User $user): bool + { + return $user->hasRole(['Administrator', 'Manager', 'Curator']); + } + + public function update(User $user, Course $course): bool + { + return $user->hasRole(['Administrator', 'Manager', 'Curator']); + } + + public function delete(User $user, Course $course): bool + { + return $user->hasRole(['Administrator', 'Manager']); + } +} diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index 7edbf4c..6ae86d1 100755 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -21,6 +21,7 @@ class AuthServiceProvider extends ServiceProvider */ protected $policies = [ CourseCategory::class => CourseCategoryPolicy::class, + Course::class => CoursePolicy::class, Organization::class => OrganizationPolicy::class, Group::class => GroupPolicy::class, User::class => UserPolicy::class, diff --git a/resources/views/admin/courses/create.blade.php b/resources/views/admin/courses/create.blade.php new file mode 100644 index 0000000..ea8e05a --- /dev/null +++ b/resources/views/admin/courses/create.blade.php @@ -0,0 +1,89 @@ +@extends('layouts.app') +@section('title', 'Добавить курс') +@section('content') +
{{ Str::limit($course->description, 80) }}
+Курсов пока нет
| Категория: | {{ $course->category?->name ?? '—' }} |
|---|---|
| Тип: | {{ $course->type }} |
| Длительность: | {{ $course->duration_minutes ?? '—' }} мин |
| Проходной балл: | {{ $course->passing_score }}% |
| Сертификат: | @if($course->has_certificate)Да@elseНет@endif |
| Статус: | @if($course->is_active)Активен@elseНе активен@endif |
| Создан: | {{ $course->created_at->format('d.m.Y H:i') }} |
| Автор: | {{ $course->creator?->name ?? '—' }} |