mirror of
https://github.com/HtetPhone/MangaDex.git
synced 2025-02-20 11:23:19 +08:00
Comment and Reply System
This commit is contained in:
parent
27cd37bcfe
commit
c844ef2ff5
@ -49,8 +49,14 @@ class ChapterController extends Controller
|
||||
} else {
|
||||
//chapter number
|
||||
$manga = Manga::where('id', $request->manga_id)->first();
|
||||
$latestChap = $manga->chapters()->orderBy('chapter_no', 'desc')->first()->chapter_no;
|
||||
$formData['chapter_no'] = $latestChap + 1;
|
||||
|
||||
$totalChap = $manga->chapters()->count();
|
||||
if($totalChap == 0 ) {
|
||||
$formData['chapter_no'] = $totalChap + 1;
|
||||
}else {
|
||||
$latestChap = $manga->chapters()->orderBy('chapter_no', 'desc')->first()->chapter_no;
|
||||
$formData['chapter_no'] = $latestChap + 1;
|
||||
}
|
||||
}
|
||||
|
||||
Chapter::create($formData);
|
||||
|
73
app/Http/Controllers/CommentController.php
Normal file
73
app/Http/Controllers/CommentController.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\StoreCommentRequest;
|
||||
use App\Http\Requests\UpdateCommentRequest;
|
||||
use App\Models\Comment;
|
||||
|
||||
class CommentController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(StoreCommentRequest $request)
|
||||
{
|
||||
// dd($request);
|
||||
$request->user()->comments()->create($request->only('comment', 'chapter_id'));
|
||||
return back()->with(['message' => 'Successfully posted a comment']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(Comment $comment)
|
||||
{
|
||||
return abort('403');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(Comment $comment)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(UpdateCommentRequest $request, Comment $comment)
|
||||
{
|
||||
// dd($request);
|
||||
$this->authorize('update', $comment);
|
||||
$comment->update(['comment' => $request->comment_edit]);
|
||||
return back()->with(['message' => 'Comment has been updated!']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(Comment $comment)
|
||||
{
|
||||
$this->authorize('delete', $comment);
|
||||
$comment->delete();
|
||||
return back()->with(['message' => 'Comment has been deleted!!']);
|
||||
}
|
||||
}
|
10
app/Http/Controllers/GenreController.php
Normal file
10
app/Http/Controllers/GenreController.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class GenreController extends Controller
|
||||
{
|
||||
//
|
||||
}
|
@ -12,26 +12,33 @@ class PageController extends Controller
|
||||
public function index()
|
||||
{
|
||||
// Storage::disk('local')->put('example.txt', 'Contents');
|
||||
$mangas = Manga::when(request()->has('search'), function($q) {
|
||||
$mangas = Manga::with(['chapters'])
|
||||
->when(request()->has('search'), function($q) {
|
||||
$keyword = request()->search;
|
||||
$q->where('title', 'like', '%'.$keyword.'%');
|
||||
})
|
||||
->latest('id')
|
||||
->paginate(8)
|
||||
->withQueryString();
|
||||
|
||||
return view('index', ['mangas' => $mangas]);
|
||||
->paginate(8)->withQueryString();
|
||||
$hotMangas = Manga::with(['chapters'])
|
||||
->latest('id')->limit('3')->get();
|
||||
return view('index', ['mangas' => $mangas, 'hotMangas' => $hotMangas]);
|
||||
}
|
||||
|
||||
public function manga($slug)
|
||||
public function manga(Manga $manga)
|
||||
{
|
||||
$manga = Manga::where('slug', $slug)->first();
|
||||
$chapters = $manga->chapters()->orderBy('chapter_no', 'desc')->paginate(10);
|
||||
$firstChapter = $manga->chapters()->orderBy('chapter_no', 'asc')->first();
|
||||
$lastChapter = $manga->chapters()->latest('chapter_no')->first();
|
||||
// dd($firstChapter);
|
||||
$chapters = $manga->chapters()
|
||||
->latest('chapter_no')
|
||||
->paginate(10);
|
||||
$firstChapter = $manga->chapters()
|
||||
->orderBy('chapter_no', 'asc')->first();
|
||||
$lastChapter = $manga->chapters()
|
||||
->latest('chapter_no')
|
||||
->first();
|
||||
$hotMangas = Manga::with(['chapters'])
|
||||
->latest('id')->limit('3')->get();
|
||||
return view('manga',[
|
||||
'manga' => $manga,
|
||||
'hotMangas' => $hotMangas,
|
||||
'chapters' => $chapters,
|
||||
'firstChapter' => $firstChapter,
|
||||
'lastChapter' => $lastChapter
|
||||
@ -40,11 +47,15 @@ class PageController extends Controller
|
||||
|
||||
public function chapter(Manga $manga,Chapter $chapter)
|
||||
{
|
||||
$firstChapter = $manga->chapters()->orderBy('chapter_no', 'asc')->first();
|
||||
$lastChapter = $manga->chapters()->latest('chapter_no')->first();
|
||||
$firstChapter = $manga->chapters()
|
||||
->orderBy('chapter_no', 'asc')
|
||||
->first();
|
||||
$lastChapter = $manga->chapters()
|
||||
->latest('chapter_no')
|
||||
->first();
|
||||
return view('chapter_page', [
|
||||
'manga' => $manga,
|
||||
'chapter' => $chapter,
|
||||
'manga' => $manga,
|
||||
'firstChapter' => $firstChapter,
|
||||
'lastChapter' => $lastChapter
|
||||
]);
|
||||
@ -52,7 +63,6 @@ class PageController extends Controller
|
||||
|
||||
public function select(Manga $manga, Request $request)
|
||||
{
|
||||
// dd($request);
|
||||
return redirect()->route('page.chapter', [$manga, $request->chapter_no]);
|
||||
}
|
||||
}
|
||||
|
73
app/Http/Controllers/ReplyController.php
Normal file
73
app/Http/Controllers/ReplyController.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\StoreReplyRequest;
|
||||
use App\Http\Requests\UpdateReplyRequest;
|
||||
use App\Models\Reply;
|
||||
|
||||
class ReplyController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(StoreReplyRequest $request)
|
||||
{
|
||||
// dd($request->user()->replies());
|
||||
$request->user()->replies()->create($request->only('reply', 'comment_id'));
|
||||
return back()->with(['message' => 'Successfully made a reply!!']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(Reply $reply)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(Reply $reply)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(UpdateReplyRequest $request, Reply $reply)
|
||||
{
|
||||
$this->authorize('update', $reply);
|
||||
|
||||
$reply->update(['reply' => $request->reply_edit]);
|
||||
return back()->with(['message' => 'Reply has been updated!!']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(Reply $reply)
|
||||
{
|
||||
$this->authorize('delete', $reply);
|
||||
$reply->delete();
|
||||
return back()->with(['message' => "Your reply has been deleted"]);
|
||||
}
|
||||
}
|
29
app/Http/Requests/StoreCommentRequest.php
Normal file
29
app/Http/Requests/StoreCommentRequest.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StoreCommentRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'comment' => 'required|min:1|max:255',
|
||||
'chapter_id' => 'required|exists:chapters,id'
|
||||
];
|
||||
}
|
||||
}
|
29
app/Http/Requests/StoreReplyRequest.php
Normal file
29
app/Http/Requests/StoreReplyRequest.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class StoreReplyRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'reply' => 'required|min:1|max:255',
|
||||
'comment_id' => 'required|exists:comments,id'
|
||||
];
|
||||
}
|
||||
}
|
28
app/Http/Requests/UpdateCommentRequest.php
Normal file
28
app/Http/Requests/UpdateCommentRequest.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class UpdateCommentRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'comment_edit' => 'required|min:1|max:255',
|
||||
];
|
||||
}
|
||||
}
|
28
app/Http/Requests/UpdateReplyRequest.php
Normal file
28
app/Http/Requests/UpdateReplyRequest.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class UpdateReplyRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'reply_edit' => 'required|min:1|max:255'
|
||||
];
|
||||
}
|
||||
}
|
@ -18,4 +18,8 @@ class Chapter extends Model
|
||||
{
|
||||
return $this->belongsTo(Manga::class, 'manga_id');
|
||||
}
|
||||
|
||||
public function comments() {
|
||||
return $this->hasMany(Comment::class, 'chapter_id');
|
||||
}
|
||||
}
|
||||
|
23
app/Models/Comment.php
Normal file
23
app/Models/Comment.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Comment extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = ['comment', 'user_id', 'chapter_id'];
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function replies()
|
||||
{
|
||||
return $this->hasMany(Reply::class, 'comment_id');
|
||||
}
|
||||
}
|
11
app/Models/Genre.php
Normal file
11
app/Models/Genre.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Genre extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
}
|
23
app/Models/Reply.php
Normal file
23
app/Models/Reply.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Reply extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = ['reply', 'user_id', 'comment_id'];
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function comment()
|
||||
{
|
||||
return $this->belongsTo(Comment::class, 'comment_id');
|
||||
}
|
||||
}
|
@ -47,4 +47,14 @@ class User extends Authenticatable
|
||||
{
|
||||
return $this->hasMany(Manga::class, 'author_id');
|
||||
}
|
||||
|
||||
public function comments()
|
||||
{
|
||||
return $this->hasMany(Comment::class);
|
||||
}
|
||||
|
||||
public function replies()
|
||||
{
|
||||
return $this->hasMany(Reply::class);
|
||||
}
|
||||
}
|
||||
|
76
app/Policies/CommentPolicy.php
Normal file
76
app/Policies/CommentPolicy.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\Comment;
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\Response;
|
||||
|
||||
class CommentPolicy
|
||||
{
|
||||
/**
|
||||
* access all to admin
|
||||
*/
|
||||
// public function before(User $user)
|
||||
// {
|
||||
// if($user->role === 'admin') {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Determine whether the user can view any models.
|
||||
*/
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*/
|
||||
public function view(User $user, Comment $comment): bool
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can create models.
|
||||
*/
|
||||
public function create(User $user): bool
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the model.
|
||||
*/
|
||||
public function update(User $user, Comment $comment): bool
|
||||
{
|
||||
return $comment->user_id === $user->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the model.
|
||||
*/
|
||||
public function delete(User $user, Comment $comment): bool
|
||||
{
|
||||
return $comment->user_id === $user->id || $user->role === 'admin';
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore the model.
|
||||
*/
|
||||
public function restore(User $user, Comment $comment): bool
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently delete the model.
|
||||
*/
|
||||
public function forceDelete(User $user, Comment $comment): bool
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
66
app/Policies/ReplyPolicy.php
Normal file
66
app/Policies/ReplyPolicy.php
Normal file
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\Reply;
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\Response;
|
||||
|
||||
class ReplyPolicy
|
||||
{
|
||||
/**
|
||||
* Determine whether the user can view any models.
|
||||
*/
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*/
|
||||
public function view(User $user, Reply $reply): bool
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can create models.
|
||||
*/
|
||||
public function create(User $user): bool
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the model.
|
||||
*/
|
||||
public function update(User $user, Reply $reply): bool
|
||||
{
|
||||
return $user->id === $reply->user_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the model.
|
||||
*/
|
||||
public function delete(User $user, Reply $reply): bool
|
||||
{
|
||||
return $user->id === $reply->user_id || $user->role === 'admin';
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore the model.
|
||||
*/
|
||||
public function restore(User $user, Reply $reply): bool
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently delete the model.
|
||||
*/
|
||||
public function forceDelete(User $user, Reply $reply): bool
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
@ -6,9 +6,12 @@ namespace App\Providers;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Manga;
|
||||
use App\Models\Reply;
|
||||
use App\Models\Chapter;
|
||||
use App\Policies\MangaPolicy;
|
||||
use App\Policies\ReplyPolicy;
|
||||
use App\Policies\ChapterPolicy;
|
||||
use App\Policies\CommentPolicy;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
|
||||
|
||||
@ -21,7 +24,9 @@ class AuthServiceProvider extends ServiceProvider
|
||||
*/
|
||||
protected $policies = [
|
||||
Manga::class => MangaPolicy::class,
|
||||
Chapter::class => ChapterPolicy::class
|
||||
Chapter::class => ChapterPolicy::class,
|
||||
Comment::class => CommentPolicy::class,
|
||||
Reply::class => ReplyPolicy::class
|
||||
];
|
||||
|
||||
/**
|
||||
|
23
database/factories/CommentFactory.php
Normal file
23
database/factories/CommentFactory.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Comment>
|
||||
*/
|
||||
class CommentFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
23
database/factories/ReplyFactory.php
Normal file
23
database/factories/ReplyFactory.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Reply>
|
||||
*/
|
||||
class ReplyFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('comments', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->longText('comment');
|
||||
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||||
$table->foreignId('chapter_id')->constrained()->cascadeOnDelete();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('comments');
|
||||
}
|
||||
};
|
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('replies', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('reply');
|
||||
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||||
$table->foreignId('comment_id')->constrained()->cascadeOnDelete();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('replies');
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('genres', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('genres');
|
||||
}
|
||||
};
|
17
database/seeders/CommentSeeder.php
Normal file
17
database/seeders/CommentSeeder.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class CommentSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
17
database/seeders/ReplySeeder.php
Normal file
17
database/seeders/ReplySeeder.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class ReplySeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
@ -4,3 +4,7 @@ import './bootstrap';
|
||||
// selectChapter.addEventListener('change', function() {
|
||||
// this.submit();
|
||||
// });
|
||||
|
||||
|
||||
import "./edit-box";
|
||||
import "./reply-box";
|
||||
|
41
resources/js/edit-box.js
Normal file
41
resources/js/edit-box.js
Normal file
@ -0,0 +1,41 @@
|
||||
let editBtn = document.querySelectorAll('.edit-btn');
|
||||
let editBox =document.querySelectorAll('.edit-box');
|
||||
|
||||
editBtn.forEach( btn => {
|
||||
btn.addEventListener('click', function() {
|
||||
// console.log('click');
|
||||
editBox.forEach( box => {
|
||||
if(btn.id == box.id) {
|
||||
box.classList.toggle('d-none');
|
||||
// console.log(box.classList.contains('d-none'));
|
||||
if(box.classList.contains('d-none')) {
|
||||
btn.innerHTML = 'Edit';
|
||||
}else {
|
||||
btn.innerHTML = 'Cancle';
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
//reply edit box
|
||||
let replyEditBtn = document.querySelectorAll('.reply-edit-btn');
|
||||
let replyEditBox =document.querySelectorAll('.reply-edit-box');
|
||||
|
||||
replyEditBtn.forEach( btn => {
|
||||
btn.addEventListener('click', function() {
|
||||
// console.log('click');
|
||||
replyEditBox.forEach( box => {
|
||||
if(btn.id == box.id) {
|
||||
box.classList.toggle('d-none');
|
||||
// console.log(box.classList.contains('d-none'));
|
||||
if(box.classList.contains('d-none')) {
|
||||
btn.innerHTML = "<i class='bi bi-pencil-square'></i>";
|
||||
}else {
|
||||
btn.innerHTML = "<i class='bi bi-x-circle'></i>";
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
17
resources/js/reply-box.js
Normal file
17
resources/js/reply-box.js
Normal file
@ -0,0 +1,17 @@
|
||||
let replyBtn = document.querySelectorAll(".reply-btn") ;
|
||||
let replyBox = document.querySelectorAll(".reply-box") ;
|
||||
|
||||
replyBtn.forEach( btn => {
|
||||
btn.addEventListener('click', function() {
|
||||
replyBox.forEach(box => {
|
||||
if(box.id == btn.id) {
|
||||
box.classList.toggle('d-none');
|
||||
if(box.classList.contains('d-none')) {
|
||||
btn.innerHTML = 'Reply';
|
||||
}else {
|
||||
btn.innerHTML = 'Cancle';
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
11
resources/js/scroll-to-top.js
Normal file
11
resources/js/scroll-to-top.js
Normal file
@ -0,0 +1,11 @@
|
||||
//scroll to top
|
||||
const sttBtn = document.querySelector('#sttBtn');
|
||||
window.onscroll = () => {
|
||||
if(document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
|
||||
sttBtn.classList.remove('d-none');
|
||||
console.log("gt20");
|
||||
}else {
|
||||
sttBtn.classList.add('d-none');
|
||||
console.log('lt20');
|
||||
}
|
||||
};
|
@ -24,6 +24,16 @@
|
||||
@include('partials.chapter-select-box')
|
||||
@include('partials.chapter-paginate')
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<!-- comment and reply here -->
|
||||
<div class="my-4 mb-5 text-start py-5">
|
||||
@include('partials.discussion')
|
||||
</div>
|
||||
</div>
|
||||
@include('partials.scroll-to-top')
|
||||
@vite(['resources/js/scroll-to-top.js'])
|
||||
@endsection
|
||||
|
||||
@section('footer')
|
||||
<x-footer/>
|
||||
@endsection
|
||||
|
@ -1,3 +1,3 @@
|
||||
<div class="bg-dark py-4 mt-5">
|
||||
<div class="bg-dark py-5 mt-5">
|
||||
<p class="text-center fw-bold text-white">Copyright All Served @MangaDex</p>
|
||||
</div>
|
||||
|
@ -9,7 +9,7 @@
|
||||
<a title="clear search" href="{{ route('page.index') }}" class="btn btn-danger ms-4 p-0 px-1 border-1 border-dark"> <i class="bi bi-x-lg"></i> </a>
|
||||
</div>
|
||||
@endif
|
||||
<div class="col-12 col-md-9 mb-4">
|
||||
<div class="col-12 col-lg-9 mb-4">
|
||||
<div class="row flex-wrap">
|
||||
@forelse ($mangas as $manga)
|
||||
<x-outter-manga-frame :manga="$manga" />
|
||||
@ -24,7 +24,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<hr class="d-block d-md-none w-75 mx-auto text-primary">
|
||||
<div class="col-12 col-md-3 mb-4">
|
||||
<div class="col-12 col-lg-3 my-4 my-lg-0">
|
||||
@include('partials.hot-manga')
|
||||
</div>
|
||||
<div class="col-12 mt-5">
|
||||
|
14
resources/views/partials/comment-edit-box.blade.php
Normal file
14
resources/views/partials/comment-edit-box.blade.php
Normal file
@ -0,0 +1,14 @@
|
||||
<div class="my-3 w-75 d-none edit-box" id="edit{{ $comment->id }}">
|
||||
<form method="POST" action="{{ route('comments.update', $comment->id) }}">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
<div class="input-group">
|
||||
<input name="comment_edit" type="text" class="form-control rounded-start-pill px-3 py-1 border border-dark small"
|
||||
name="content" value="{{ old('comment_edit', $comment->comment) }}">
|
||||
<button class="btn btn-dark rounded-end-pill"> Save </button>
|
||||
</div>
|
||||
@error('comment_edit')
|
||||
<p class="text-danger small"> {{$message}} </p>
|
||||
@enderror
|
||||
</form>
|
||||
</div>
|
80
resources/views/partials/discussion.blade.php
Normal file
80
resources/views/partials/discussion.blade.php
Normal file
@ -0,0 +1,80 @@
|
||||
<h5 class="fw-semibold">Comments From Chapter - {{ $chapter->chapter_no }}</h5>
|
||||
<h5 class="my-4 mt-5"> <i class="bi bi-star bg-primary text-white px-2 py-1 rounded-1"></i> Discussion </h5>
|
||||
|
||||
@guest
|
||||
<p class="text-black-50">You must <a href="{{ route('register') }}" class="text-decoration-none">Register</a> or <a
|
||||
href="{{ route('login') }}" class="text-decoration-none">Login</a> to post a Comment. </p>
|
||||
@endguest
|
||||
|
||||
@auth
|
||||
<div class="d-flex justify-content-between w-75">
|
||||
<p class="text-black-50"> {{ $chapter->comments->count() }} {{ Str::plural('comment', $chapter->comments->count()) }}
|
||||
</p>
|
||||
<p>
|
||||
<i class="bi bi-chat-fill"></i> {{ auth()->user()->name }}
|
||||
</p>
|
||||
</div>
|
||||
<form action="{{ route('comments.store') }}" method="POST" class="mb-5">
|
||||
@csrf
|
||||
<div class="input-group w-75">
|
||||
<input type="hidden" name="chapter_id" value="{{ $chapter->id }}">
|
||||
<input type="text" class="form-control rounded-start-pill px-4 py-2 border border-dark" name="comment"
|
||||
placeholder="Join the discussion ...">
|
||||
<button type="submit" class="btn btn-dark rounded-end-pill"> Comment </button>
|
||||
</div>
|
||||
@error('comment')
|
||||
<p class="text-danger small"> {{ $message }} </p>
|
||||
@enderror
|
||||
</form>
|
||||
@endauth
|
||||
<hr>
|
||||
|
||||
<!-- comment outputs here -->
|
||||
<div class="p-2">
|
||||
@forelse ($chapter->comments()->latest()->get() as $comment)
|
||||
<div class="mb-4 border-bottom">
|
||||
<p class="mb-1">
|
||||
<span class="fw-bold text-primary"> <i class="bi bi-person-fill"></i> {{ $comment->user->name }}</span>
|
||||
<span class="small text-black-50 fw-light ms-2"> {{ $comment->created_at->diffForHumans() }} </span>
|
||||
</p>
|
||||
<p class="small mb-0"> {{ $comment->comment }} </p>
|
||||
<!-- comment edit box here -->
|
||||
@include('partials.comment-edit-box')
|
||||
|
||||
<!-- reply box here -->
|
||||
@include('partials.reply-box')
|
||||
|
||||
<!-- comment edit | delete | reply -->
|
||||
<p class="d-flex align-items-center">
|
||||
@can('update', $comment)
|
||||
<button class="btn btn-sm text-info edit-btn" id="edit{{ $comment->id }}">
|
||||
Edit
|
||||
</button>
|
||||
<span class="mx-2"> <i class="bi bi-cone-striped text-danger"></i> </span>
|
||||
@endcan
|
||||
@can('delete', $comment)
|
||||
<button form="deleteCommentForm{{ $comment->id }}" class="btn btn-sm text-danger">Delete</button>
|
||||
<span class="mx-2"> <i class="bi bi-cone-striped text-danger"></i> </span>
|
||||
@endcan
|
||||
|
||||
@auth
|
||||
<button id="reply{{ $comment->id }}" class="btn btn-sm text-info reply-btn">Reply</button>
|
||||
@endauth
|
||||
|
||||
<!-- replies here -->
|
||||
@include('partials.replies')
|
||||
|
||||
</p>
|
||||
<form id="deleteCommentForm{{ $comment->id }}" class=""
|
||||
action="{{ route('comments.destroy', $comment->id) }}" method="POST">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
</form>
|
||||
|
||||
|
||||
<!-- comment edit | delete | reply -->
|
||||
</div>
|
||||
@empty
|
||||
<p class="text-black-50">There are no comments yet!</p>
|
||||
@endforelse
|
||||
</div>
|
@ -1,28 +1,24 @@
|
||||
<h5 class="fw-semibold text-primary"> <i class="bi bi-award-fill"></i> Manga Hot</h5>
|
||||
<div class="row">
|
||||
@forelse (App\Models\Manga::latest('id')->limit(3)->get() as $hotManga)
|
||||
<div class="col-12 mt-3">
|
||||
<div class="row border-0 flex-wrap">
|
||||
<div class="overflow-hidden col-4">
|
||||
<a href="{{ route('page.manga', $hotManga->slug) }}">
|
||||
<img src="{{ asset( 'storage/'.$hotManga->cover) }}"
|
||||
alt="img" class="cover-img img-fluid">
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-8">
|
||||
<a href="{{ route('page.manga', $hotManga->slug) }}" class="text-decoration-none">
|
||||
<p class="fw-semibold mb-1"> {{ $hotManga->title }} </p>
|
||||
</a>
|
||||
@forelse ($hotMangas as $hotManga)
|
||||
<div class="row border-0 flex-wrap my-3 mb-4">
|
||||
<div class="overflow-hidden col-3 col-lg-4">
|
||||
<a href="{{ route('page.manga', $hotManga->slug) }}">
|
||||
<img src="{{ asset('storage/' . $hotManga->cover) }}" alt="img" class="cover-img img-fluid">
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-5 col-lg-8">
|
||||
<a href="{{ route('page.manga', $hotManga->slug) }}" class="text-decoration-none">
|
||||
<p class="fw-semibold mb-1"> {{ $hotManga->title }} </p>
|
||||
</a>
|
||||
|
||||
@foreach ($hotManga->chapters()->latest('id')->limit(2)->get() as $hotChap)
|
||||
<x-latest-chapter :manga="$hotManga" :chapter="$hotChap" />
|
||||
@endforeach
|
||||
@foreach ($hotManga->chapters()->latest('id')->limit(2)->get() as $hotChap)
|
||||
<x-latest-chapter :manga="$hotManga" :chapter="$hotChap" />
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@empty
|
||||
<p class="text-danger small">No Hot Manga Yet</p>
|
||||
<p class="text-danger small">No Hot Manga Yet</p>
|
||||
@endforelse
|
||||
</div>
|
||||
|
52
resources/views/partials/replies.blade.php
Normal file
52
resources/views/partials/replies.blade.php
Normal file
@ -0,0 +1,52 @@
|
||||
@if ($comment->replies->count())
|
||||
<a class="btn btn-sm btn-link" data-bs-toggle="collapse" href="#collapseReplies{{$comment->id}}" role="button" aria-expanded="false"
|
||||
aria-controls="collapseReplies{{$comment->id}}">
|
||||
See the other replies ...
|
||||
</a>
|
||||
<div class="collapse" id="collapseReplies{{$comment->id}}">
|
||||
@foreach ($comment->replies()->latest()->get() as $reply)
|
||||
<div class="ms-5">
|
||||
<div class="d-flex align-items-center mb-0">
|
||||
<div>
|
||||
<span class="text-primary">
|
||||
{{ $reply->user->name }}
|
||||
</span>
|
||||
|
||||
<i class="bi bi-reply-fill d-inline-block" style="transform: rotate(150deg) skewY(-1deg);"></i>
|
||||
|
||||
<span class="text-primary">
|
||||
{{ $comment->user->name }}
|
||||
</span>
|
||||
|
||||
<span class="small text-black-50 fw-light ms-2">
|
||||
{{ $reply->created_at->diffForHumans() }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- edit and delete -->
|
||||
<div class="small d-flex flex-nowrap">
|
||||
@can('update', $reply)
|
||||
<button id="editReply{{ $reply->id }}" class="btn btn-sm text-success reply-edit-btn">
|
||||
<i class="bi bi-pencil-square"></i>
|
||||
</button>
|
||||
@endcan
|
||||
|
||||
@can('delete', $reply)
|
||||
<form action="{{ route('replies.destroy', $reply->id) }}" method="POST" class="">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button class="btn btn-sm text-danger">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</form>
|
||||
@endcan
|
||||
</div>
|
||||
</div>
|
||||
<p class="small">
|
||||
{{ $reply->reply }}
|
||||
</p>
|
||||
|
||||
@include('partials.reply-edit-box')
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
18
resources/views/partials/reply-box.blade.php
Normal file
18
resources/views/partials/reply-box.blade.php
Normal file
@ -0,0 +1,18 @@
|
||||
@auth
|
||||
<div class="my-3 mb-0 ms-3 w-75 reply-box d-none" id="reply{{ $comment->id}}">
|
||||
<p class="small text-black-50 mb-1"> <i class="bi bi-reply-all-fill"></i> Relying to <span class="text-primary">{{ $comment->user->name }}</span> </p>
|
||||
<form method="POST" action="{{route('replies.store')}}">
|
||||
@csrf
|
||||
<div class="input-group">
|
||||
<input type="hidden" name="comment_id" value="{{$comment->id}}">
|
||||
<input name="reply" type="text"
|
||||
class="form-control focus-ring focus-ring-light rounded-start-pill px-3 py-1 border border-dark small" name="content"
|
||||
value="{{ old('reply') }}">
|
||||
<button class="btn btn-dark rounded-end-pill"> <i class="bi bi-send-fill"></i> </button>
|
||||
</div>
|
||||
@error('reply')
|
||||
<p class="text-danger small"> {{ $message }} </p>
|
||||
@enderror
|
||||
</form>
|
||||
</div>
|
||||
@endauth
|
14
resources/views/partials/reply-edit-box.blade.php
Normal file
14
resources/views/partials/reply-edit-box.blade.php
Normal file
@ -0,0 +1,14 @@
|
||||
<div class="my-3 w-75 d-none reply-edit-box" id="editReply{{ $reply->id }}">
|
||||
<form method="POST" action="{{ route('replies.update', $reply->id) }}">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
<div class="input-group">
|
||||
<input name="reply_edit" type="text" class="form-control rounded-start-pill px-3 py-1 border border-dark small"
|
||||
name="content" value="{{ old('reply_edit', $reply->reply) }}">
|
||||
<button class="btn btn-dark rounded-end-pill"> Save </button>
|
||||
</div>
|
||||
@error('reply_edit')
|
||||
<p class="text-danger small"> {{$message}} </p>
|
||||
@enderror
|
||||
</form>
|
||||
</div>
|
9
resources/views/partials/scroll-to-top.blade.php
Normal file
9
resources/views/partials/scroll-to-top.blade.php
Normal file
@ -0,0 +1,9 @@
|
||||
<button
|
||||
id="sttBtn"
|
||||
onclick="() =>
|
||||
document.body.scrollTop = 0;
|
||||
document.documentElement.scrollTop = 0;
|
||||
"
|
||||
class="btn btn-warning position-fixed d-none z-3" style="bottom:10%;right:10%;">
|
||||
<i class="bi bi-arrow-up"></i>
|
||||
</button>
|
@ -1,13 +1,15 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\ChapterController;
|
||||
use App\Http\Controllers\HomeController;
|
||||
use App\Http\Controllers\MangaController;
|
||||
use App\Http\Controllers\PageController;
|
||||
use App\Http\Controllers\UserController;
|
||||
use App\Models\Chapter;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use App\Http\Controllers\HomeController;
|
||||
use App\Http\Controllers\PageController;
|
||||
use App\Http\Controllers\UserController;
|
||||
use App\Http\Controllers\MangaController;
|
||||
use App\Http\Controllers\ReplyController;
|
||||
use App\Http\Controllers\ChapterController;
|
||||
use App\Http\Controllers\CommentController;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@ -22,21 +24,28 @@ use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::controller(PageController::class)->group(function () {
|
||||
Route::get('/', 'index')->name('page.index');
|
||||
Route::get('/MangaDex/manga/{slug}', 'manga')->name('page.manga');
|
||||
Route::get('/manga/{manga:slug}/chapter/{chapter:chapter_no?}', 'chapter')->name('page.chapter');
|
||||
Route::post('/manga/{manga:slug}/select', 'select')->name('select.chapter');
|
||||
Route::get('/MangaDex/manga/{manga:slug}', 'manga')->name('page.manga');
|
||||
Route::get('/manga/{manga:slug}/chapter-{chapter:chapter_no?}', 'chapter')
|
||||
->name('page.chapter');
|
||||
Route::post('/{manga:slug}/chapter', 'select')->name('select.chapter');
|
||||
});
|
||||
|
||||
Route::resource('comments', CommentController::class)->middleware('auth');
|
||||
Route::resource('replies', ReplyController::class)->middleware('auth');
|
||||
|
||||
Auth::routes();
|
||||
|
||||
Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');
|
||||
Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])
|
||||
->name('home');
|
||||
|
||||
Route::middleware(['auth', 'admin.access'])->group(function () {
|
||||
Route::resource('manga', MangaController::class);
|
||||
|
||||
Route::resource('chapter', ChapterController::class);
|
||||
|
||||
Route::get('/chapters/manage/{manga:slug}', [ChapterController::class, 'manage'])->name('chapters.manage');
|
||||
Route::get('/chapters/manage/{manga:slug}', [ChapterController::class, 'manage'])
|
||||
->name('chapters.manage');
|
||||
|
||||
Route::get('/users-list', [UserController::class, 'index'])->name('users.list')->middleware('can:admin-only');
|
||||
});
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user