diff --git a/app/Http/Controllers/.idea/.gitignore b/app/Http/Controllers/.idea/.gitignore new file mode 100644 index 00000000..13566b81 --- /dev/null +++ b/app/Http/Controllers/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/app/Http/Controllers/.idea/Controllers.iml b/app/Http/Controllers/.idea/Controllers.iml new file mode 100644 index 00000000..c956989b --- /dev/null +++ b/app/Http/Controllers/.idea/Controllers.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/app/Http/Controllers/.idea/modules.xml b/app/Http/Controllers/.idea/modules.xml new file mode 100644 index 00000000..0315a575 --- /dev/null +++ b/app/Http/Controllers/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/app/Http/Controllers/.idea/php.xml b/app/Http/Controllers/.idea/php.xml new file mode 100644 index 00000000..29059d00 --- /dev/null +++ b/app/Http/Controllers/.idea/php.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/Http/Controllers/.idea/vcs.xml b/app/Http/Controllers/.idea/vcs.xml new file mode 100644 index 00000000..c2365ab1 --- /dev/null +++ b/app/Http/Controllers/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/Http/Controllers/CourseController.php b/app/Http/Controllers/CourseController.php new file mode 100644 index 00000000..bf86b590 --- /dev/null +++ b/app/Http/Controllers/CourseController.php @@ -0,0 +1,101 @@ +filled('skill_level')) { + $query->where('skill_level', $request->skill_level); + } + + $sortBy = $request->get('sort_by', 'id'); + $order = $request->get('order', 'asc'); + $allowedSortBy = ['title', 'created_at', 'id']; + + if (in_array($sortBy, $allowedSortBy)) { + $query->orderBy($sortBy, $order); + } + + $courses = $query->paginate(6); + + return inertia('Courses/Index', [ + 'courses' => $courses, + 'filters' => $request->only('skill_level', 'sort_by', 'order'), + ]); + } + + public function create() + { + return Inertia::render("Courses/Create"); + } + + public function show($id) + { + $course = Course::findOrFail($id); + return Inertia::render("Courses/Show", ["course" => $course]); + } + + public function store(Request $request) + { + $validated = $request->validate([ + "title" => [ + "required", + "string", + "max:255", + Rule::unique('courses', 'title'), + ], + "description" => "required|string", + "language" => "required|string", + "skill_level" => "required|string", + ]); + + $request->user()->courses()->create($validated); + return redirect()->route("courses.index")->with("success", "Course created successfully."); + } + + public function edit(Course $course) + { + return Inertia::render("Courses/Edit", ["course" => $course]); + } + + public function update(Request $request, Course $course) + { + $this->authorize("update", $course); + + $validated = $request->validate([ + "title" => [ + "required", + "string", + "max:255", + Rule::unique('courses', 'title')->ignore($course->id), + ], + "description" => "required|string", + "language" => "required|string", + "skill_level" => "required|string", + ]); + + $course->update($validated); + return redirect()->route("courses.index")->with("success", "Course updated successfully."); + } + + public function destroy(Course $course) + { + $this->authorize("delete", $course); + $course->delete(); + return redirect()->route("courses.index")->with("success", "Course deleted successfully."); + } +} diff --git a/app/Models/Course.php b/app/Models/Course.php new file mode 100644 index 00000000..20d8573a --- /dev/null +++ b/app/Models/Course.php @@ -0,0 +1,20 @@ +belongsTo(User::class, "user_id"); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index 06bb4bd2..3f3c739c 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -34,6 +34,11 @@ class User extends Authenticatable "remember_token", ]; + public function courses() + { + return $this->hasMany(Course::class); + } + protected function casts(): array { return [ diff --git a/app/Policies/CoursePolicy.php b/app/Policies/CoursePolicy.php new file mode 100644 index 00000000..0d729657 --- /dev/null +++ b/app/Policies/CoursePolicy.php @@ -0,0 +1,73 @@ +role === 'teacher' || $user->role === 'admin'; + } + + /** + * Determine whether the user can update the model. + */ + public function update(User $user, Course $course): bool + { + + return $user->id === $course->user_id || $user->role === 'admin'; + } + + /** + * Determine whether the user can delete the model. + */ + public function delete(User $user, Course $course): bool + { + + return $user->id === $course->user_id || $user->role === 'admin'; + } + + /** + * Determine whether the user can restore the model. + */ + public function restore(User $user, Course $course): bool + { + + return $user->role === 'admin' || $user->id === $course->user_id; + } + + /** + * Determine whether the user can permanently delete the model. + */ + public function forceDelete(User $user, Course $course): bool + { + + return $user->role === 'admin'; + } +} diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 2f7cc479..fe0fbc8d 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -5,9 +5,12 @@ namespace Interns2024c\Providers; use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\Gate; use Illuminate\Support\Facades\Vite; use Illuminate\Support\ServiceProvider; use Inertia\Inertia; +use Interns2024c\Models\Course; +use Interns2024c\Policies\CoursePolicy; class AppServiceProvider extends ServiceProvider { @@ -23,7 +26,10 @@ public function register(): void */ public function boot(): void { + // Vite prefetch Vite::prefetch(concurrency: 3); + + // Inertia auth Inertia::share([ "auth" => function () { return [ @@ -31,5 +37,8 @@ public function boot(): void ]; }, ]); + + + Gate::policy(Course::class, CoursePolicy::class); } } diff --git a/bootstrap/cache/.gitignore b/bootstrap/cache/.gitignore old mode 100644 new mode 100755 diff --git a/database/migrations/2024_12_17_124351_create_courses_table.php b/database/migrations/2024_12_17_124351_create_courses_table.php new file mode 100644 index 00000000..26e1fedf --- /dev/null +++ b/database/migrations/2024_12_17_124351_create_courses_table.php @@ -0,0 +1,27 @@ +id(); + $table->string("title"); + $table->text("description"); + $table->string("language"); + $table->string("skill_level"); + $table->foreignId("user_id")->constrained()->onDelete("cascade"); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists("courses"); + } +}; diff --git a/package-lock.json b/package-lock.json index 9a191207..a0468d3f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,8 @@ "@tailwindcss/typography": "^0.5.15", "laravel-vite-plugin": "^1.0.5", "lodash": "^4.17.21", - "vue": "^3.5.10" + "vue": "^3.5.10", + "vue-router": "^4.5.0" }, "devDependencies": { "@blumilksoftware/eslint-config": "^2.0.0", @@ -1518,6 +1519,11 @@ "he": "^1.2.0" } }, + "node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==" + }, "node_modules/@vue/eslint-config-typescript": { "version": "12.0.0", "resolved": "https://registry.npmjs.org/@vue/eslint-config-typescript/-/eslint-config-typescript-12.0.0.tgz", @@ -5942,6 +5948,20 @@ "eslint": ">=6.0.0" } }, + "node_modules/vue-router": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.5.0.tgz", + "integrity": "sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==", + "dependencies": { + "@vue/devtools-api": "^6.6.4" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, "node_modules/vue-tsc": { "version": "2.1.10", "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.1.10.tgz", diff --git a/package.json b/package.json index 159dc51a..fbcfbbac 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "@tailwindcss/typography": "^0.5.15", "laravel-vite-plugin": "^1.0.5", "lodash": "^4.17.21", - "vue": "^3.5.10" + "vue": "^3.5.10", + "vue-router": "^4.5.0" }, "devDependencies": { "@blumilksoftware/eslint-config": "^2.0.0", diff --git a/resources/js/Layouts/AuthenticatedLayout.vue b/resources/js/Layouts/AuthenticatedLayout.vue index 5c5e712c..305ab594 100644 --- a/resources/js/Layouts/AuthenticatedLayout.vue +++ b/resources/js/Layouts/AuthenticatedLayout.vue @@ -3,8 +3,6 @@ import { ref } from 'vue' import ApplicationLogo from '@/Components/ApplicationLogo.vue' import Dropdown from '@/Components/Dropdown.vue' import DropdownLink from '@/Components/DropdownLink.vue' -import NavLink from '@/Components/NavLink.vue' -import ResponsiveNavLink from '@/Components/ResponsiveNavLink.vue' import { Link } from '@inertiajs/vue3' const showingNavigationDropdown = ref(false) @@ -13,186 +11,45 @@ const showingNavigationDropdown = ref(false) + \ No newline at end of file diff --git a/resources/js/Pages/Courses/Create.vue b/resources/js/Pages/Courses/Create.vue new file mode 100644 index 00000000..ce005cd4 --- /dev/null +++ b/resources/js/Pages/Courses/Create.vue @@ -0,0 +1,73 @@ + + + + + diff --git a/resources/js/Pages/Courses/Edit.vue b/resources/js/Pages/Courses/Edit.vue new file mode 100644 index 00000000..a0cfff07 --- /dev/null +++ b/resources/js/Pages/Courses/Edit.vue @@ -0,0 +1,65 @@ +// Edit.vue + + + diff --git a/resources/js/Pages/Courses/Index.vue b/resources/js/Pages/Courses/Index.vue new file mode 100644 index 00000000..0a278ebf --- /dev/null +++ b/resources/js/Pages/Courses/Index.vue @@ -0,0 +1,87 @@ + + + diff --git a/resources/js/Pages/Courses/Show.vue b/resources/js/Pages/Courses/Show.vue new file mode 100644 index 00000000..3a865e0b --- /dev/null +++ b/resources/js/Pages/Courses/Show.vue @@ -0,0 +1,51 @@ + + + + + \ No newline at end of file diff --git a/resources/js/router.ts b/resources/js/router.ts new file mode 100644 index 00000000..adca40d9 --- /dev/null +++ b/resources/js/router.ts @@ -0,0 +1,24 @@ +import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'; + +// Sayfa bileşenlerini import et +import CoursesIndex from './Pages/Courses/Index.vue'; + +const routes: Array = [ + { + path: '/', + name: 'home', + component: CoursesIndex, // Ana sayfa olarak kullanılacak component + }, + { + path: '/courses', + name: 'courses', + component: CoursesIndex, // Örnek başka bir sayfa + } +]; + +const router = createRouter({ + history: createWebHistory(), + routes, +}); + +export default router; diff --git a/resources/js/ziggy.js b/resources/js/ziggy.js new file mode 100644 index 00000000..4eeaaf0f --- /dev/null +++ b/resources/js/ziggy.js @@ -0,0 +1,5 @@ +const Ziggy = {"url":"http:\/\/interns2024c.blumilk.localhost","port":null,"defaults":{},"routes":{"sanctum.csrf-cookie":{"uri":"sanctum\/csrf-cookie","methods":["GET","HEAD"]},"ignition.healthCheck":{"uri":"_ignition\/health-check","methods":["GET","HEAD"]},"ignition.executeSolution":{"uri":"_ignition\/execute-solution","methods":["POST"]},"ignition.updateConfig":{"uri":"_ignition\/update-config","methods":["POST"]},"dashboard":{"uri":"dashboard","methods":["GET","HEAD"]},"profile.edit":{"uri":"profile","methods":["GET","HEAD"]},"profile.update":{"uri":"profile","methods":["PATCH"]},"profile.destroy":{"uri":"profile","methods":["DELETE"]},"register":{"uri":"register","methods":["GET","HEAD"]},"login":{"uri":"login","methods":["GET","HEAD"]},"password.request":{"uri":"forgot-password","methods":["GET","HEAD"]},"password.email":{"uri":"forgot-password","methods":["POST"]},"password.reset":{"uri":"reset-password\/{token}","methods":["GET","HEAD"],"parameters":["token"]},"password.store":{"uri":"reset-password","methods":["POST"]},"verification.notice":{"uri":"verify-email","methods":["GET","HEAD"]},"verification.verify":{"uri":"verify-email\/{id}\/{hash}","methods":["GET","HEAD"],"parameters":["id","hash"]},"verification.send":{"uri":"email\/verification-notification","methods":["POST"]},"password.confirm":{"uri":"confirm-password","methods":["GET","HEAD"]},"password.update":{"uri":"password","methods":["PUT"]},"logout":{"uri":"logout","methods":["POST"]}}}; +if (typeof window !== 'undefined' && typeof window.Ziggy !== 'undefined') { + Object.assign(Ziggy.routes, window.Ziggy.routes); +} +export { Ziggy }; diff --git a/routes/web.php b/routes/web.php index 233de68c..1cd11cf9 100644 --- a/routes/web.php +++ b/routes/web.php @@ -6,7 +6,9 @@ use Illuminate\Support\Facades\Route; use Inertia\Inertia; use Interns2024c\Http\Controllers\Auth\ProfileController; +use Interns2024c\Http\Controllers\CourseController; +// home page Route::get("/", function () { return Inertia::render("Welcome", [ "canLogin" => Route::has("login"), @@ -16,7 +18,11 @@ ]); }); -Route::get("/dashboard", fn() => Inertia::render("Dashboard"))->middleware(["auth", "verified"])->name("dashboard"); +// Dashboard route +Route::get("/dashboard", fn() => Inertia::render("Dashboard")) + ->middleware(["auth", "verified"]) + ->name("dashboard"); + Route::middleware("auth")->group(function (): void { Route::get("/profile", [ProfileController::class, "edit"])->name("profile.edit"); @@ -24,4 +30,13 @@ Route::delete("/profile", [ProfileController::class, "destroy"])->name("profile.destroy"); }); + +Route::middleware(["auth"])->group(function (): void { + // course crud route + Route::resource("courses", CourseController::class) + ->parameters(["courses" => "course"]) + ->whereNumber("course"); +}); + + require __DIR__ . "/auth.php"; diff --git a/storage/app/.gitignore b/storage/app/.gitignore old mode 100644 new mode 100755 diff --git a/storage/app/public/.gitignore b/storage/app/public/.gitignore old mode 100644 new mode 100755 diff --git a/storage/framework/.gitignore b/storage/framework/.gitignore old mode 100644 new mode 100755 diff --git a/storage/framework/cache/.gitignore b/storage/framework/cache/.gitignore old mode 100644 new mode 100755 diff --git a/storage/framework/cache/data/.gitignore b/storage/framework/cache/data/.gitignore old mode 100644 new mode 100755 diff --git a/storage/framework/sessions/.gitignore b/storage/framework/sessions/.gitignore old mode 100644 new mode 100755 diff --git a/storage/framework/testing/.gitignore b/storage/framework/testing/.gitignore old mode 100644 new mode 100755 diff --git a/storage/framework/views/.gitignore b/storage/framework/views/.gitignore old mode 100644 new mode 100755 diff --git a/storage/logs/.gitignore b/storage/logs/.gitignore old mode 100644 new mode 100755