Compare commits
1 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
a3da1bed63 |
|
|
@ -1,17 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Enums;
|
|
||||||
|
|
||||||
enum PriorityStatus: string
|
|
||||||
{
|
|
||||||
case LOW = 'low';
|
|
||||||
case MEDIUM = 'medium';
|
|
||||||
case HIGH = "high";
|
|
||||||
case CRITICAL = "critical";
|
|
||||||
|
|
||||||
public static function values(): array
|
|
||||||
{
|
|
||||||
return array_column(self::cases(), 'value');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Enums;
|
|
||||||
|
|
||||||
enum TodoProgress: string
|
|
||||||
{
|
|
||||||
case COMPLETED = 'completed';
|
|
||||||
case IN_PROGRESS = 'in_progress';
|
|
||||||
case TO_DO = "to_do";
|
|
||||||
|
|
||||||
public static function values(): array
|
|
||||||
{
|
|
||||||
return array_column(self::cases(), 'value');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Events;
|
|
||||||
|
|
||||||
use App\Http\Resources\Messaging\MessageResource;
|
|
||||||
use App\Models\Message;
|
|
||||||
use Illuminate\Broadcasting\Channel;
|
|
||||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
|
||||||
use Illuminate\Broadcasting\PrivateChannel;
|
|
||||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
|
||||||
use Illuminate\Foundation\Events\Dispatchable;
|
|
||||||
use Illuminate\Queue\SerializesModels;
|
|
||||||
|
|
||||||
class MessageSent implements ShouldBroadcast
|
|
||||||
{
|
|
||||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
|
||||||
|
|
||||||
public $message;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new event instance.
|
|
||||||
*/
|
|
||||||
public function __construct(Message $message)
|
|
||||||
{
|
|
||||||
$this->message = $message;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the channels the event should broadcast on.
|
|
||||||
*
|
|
||||||
* @return array<int, \Illuminate\Broadcasting\Channel>
|
|
||||||
*/
|
|
||||||
public function broadcastOn(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
new PrivateChannel('conversation.' . $this->message->conversation_id),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Data to broadcast.
|
|
||||||
*/
|
|
||||||
public function broadcastWith(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'message' => new MessageResource($this->message->load('user')),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Filament\Resources\Todos\Pages;
|
|
||||||
|
|
||||||
use App\Filament\Resources\Todos\TodoResource;
|
|
||||||
use Filament\Resources\Pages\CreateRecord;
|
|
||||||
|
|
||||||
class CreateTodo extends CreateRecord
|
|
||||||
{
|
|
||||||
protected static string $resource = TodoResource::class;
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Filament\Resources\Todos\Pages;
|
|
||||||
|
|
||||||
use App\Filament\Resources\Todos\TodoResource;
|
|
||||||
use Filament\Actions\DeleteAction;
|
|
||||||
use Filament\Actions\ViewAction;
|
|
||||||
use Filament\Resources\Pages\EditRecord;
|
|
||||||
|
|
||||||
class EditTodo extends EditRecord
|
|
||||||
{
|
|
||||||
protected static string $resource = TodoResource::class;
|
|
||||||
|
|
||||||
protected function getHeaderActions(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
ViewAction::make(),
|
|
||||||
DeleteAction::make(),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Filament\Resources\Todos\Pages;
|
|
||||||
|
|
||||||
use App\Filament\Resources\Todos\TodoResource;
|
|
||||||
use Filament\Actions\CreateAction;
|
|
||||||
use Filament\Resources\Pages\ListRecords;
|
|
||||||
|
|
||||||
class ListTodos extends ListRecords
|
|
||||||
{
|
|
||||||
protected static string $resource = TodoResource::class;
|
|
||||||
|
|
||||||
protected function getHeaderActions(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
CreateAction::make(),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Filament\Resources\Todos\Pages;
|
|
||||||
|
|
||||||
use App\Filament\Resources\Todos\TodoResource;
|
|
||||||
use Filament\Actions\EditAction;
|
|
||||||
use Filament\Resources\Pages\ViewRecord;
|
|
||||||
|
|
||||||
class ViewTodo extends ViewRecord
|
|
||||||
{
|
|
||||||
protected static string $resource = TodoResource::class;
|
|
||||||
|
|
||||||
protected function getHeaderActions(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
EditAction::make(),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Filament\Resources\Todos\Schemas;
|
|
||||||
|
|
||||||
use App\Enums\TodoProgress;
|
|
||||||
use Filament\Forms\Components\FileUpload;
|
|
||||||
use Filament\Forms\Components\Select;
|
|
||||||
use Filament\Forms\Components\TextInput;
|
|
||||||
use Filament\Forms\Components\Textarea;
|
|
||||||
use Filament\Schemas\Schema;
|
|
||||||
|
|
||||||
class TodoForm
|
|
||||||
{
|
|
||||||
public static function configure(Schema $schema): Schema
|
|
||||||
{
|
|
||||||
return $schema
|
|
||||||
->components([
|
|
||||||
TextInput::make('name')
|
|
||||||
->required(),
|
|
||||||
Select::make('user_id')
|
|
||||||
->relationship('user', 'name')
|
|
||||||
->required(),
|
|
||||||
FileUpload::make('image_url')
|
|
||||||
->image(),
|
|
||||||
Select::make('status')
|
|
||||||
->options(TodoProgress::class)
|
|
||||||
->default('to_do')
|
|
||||||
->required(),
|
|
||||||
Textarea::make('description')
|
|
||||||
->columnSpanFull(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Filament\Resources\Todos\Schemas;
|
|
||||||
|
|
||||||
use Filament\Infolists\Components\ImageEntry;
|
|
||||||
use Filament\Infolists\Components\TextEntry;
|
|
||||||
use Filament\Schemas\Schema;
|
|
||||||
|
|
||||||
class TodoInfolist
|
|
||||||
{
|
|
||||||
public static function configure(Schema $schema): Schema
|
|
||||||
{
|
|
||||||
return $schema
|
|
||||||
->components([
|
|
||||||
TextEntry::make('name'),
|
|
||||||
TextEntry::make('user.name')
|
|
||||||
->label('User'),
|
|
||||||
TextEntry::make('created_at')
|
|
||||||
->dateTime()
|
|
||||||
->placeholder('-'),
|
|
||||||
TextEntry::make('updated_at')
|
|
||||||
->dateTime()
|
|
||||||
->placeholder('-'),
|
|
||||||
ImageEntry::make('image_url')
|
|
||||||
->placeholder('-'),
|
|
||||||
TextEntry::make('status')
|
|
||||||
->badge(),
|
|
||||||
TextEntry::make('description')
|
|
||||||
->placeholder('-')
|
|
||||||
->columnSpanFull(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Filament\Resources\Todos\Tables;
|
|
||||||
|
|
||||||
use Filament\Actions\BulkActionGroup;
|
|
||||||
use Filament\Actions\DeleteBulkAction;
|
|
||||||
use Filament\Actions\EditAction;
|
|
||||||
use Filament\Actions\ViewAction;
|
|
||||||
use Filament\Tables\Columns\ImageColumn;
|
|
||||||
use Filament\Tables\Columns\TextColumn;
|
|
||||||
use Filament\Tables\Table;
|
|
||||||
|
|
||||||
class TodosTable
|
|
||||||
{
|
|
||||||
public static function configure(Table $table): Table
|
|
||||||
{
|
|
||||||
return $table
|
|
||||||
->columns([
|
|
||||||
TextColumn::make('name')
|
|
||||||
->searchable(),
|
|
||||||
TextColumn::make('user.name')
|
|
||||||
->searchable(),
|
|
||||||
TextColumn::make('created_at')
|
|
||||||
->dateTime()
|
|
||||||
->sortable()
|
|
||||||
->toggleable(isToggledHiddenByDefault: true),
|
|
||||||
TextColumn::make('updated_at')
|
|
||||||
->dateTime()
|
|
||||||
->sortable()
|
|
||||||
->toggleable(isToggledHiddenByDefault: true),
|
|
||||||
ImageColumn::make('image_url'),
|
|
||||||
TextColumn::make('status')
|
|
||||||
->badge()
|
|
||||||
->searchable(),
|
|
||||||
])
|
|
||||||
->filters([
|
|
||||||
//
|
|
||||||
])
|
|
||||||
->recordActions([
|
|
||||||
ViewAction::make(),
|
|
||||||
EditAction::make(),
|
|
||||||
])
|
|
||||||
->toolbarActions([
|
|
||||||
BulkActionGroup::make([
|
|
||||||
DeleteBulkAction::make(),
|
|
||||||
]),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Filament\Resources\Todos;
|
|
||||||
|
|
||||||
use App\Filament\Resources\Todos\Pages\CreateTodo;
|
|
||||||
use App\Filament\Resources\Todos\Pages\EditTodo;
|
|
||||||
use App\Filament\Resources\Todos\Pages\ListTodos;
|
|
||||||
use App\Filament\Resources\Todos\Pages\ViewTodo;
|
|
||||||
use App\Filament\Resources\Todos\Schemas\TodoForm;
|
|
||||||
use App\Filament\Resources\Todos\Schemas\TodoInfolist;
|
|
||||||
use App\Filament\Resources\Todos\Tables\TodosTable;
|
|
||||||
use App\Models\Todo;
|
|
||||||
use BackedEnum;
|
|
||||||
use Filament\Resources\Resource;
|
|
||||||
use Filament\Schemas\Schema;
|
|
||||||
use Filament\Support\Icons\Heroicon;
|
|
||||||
use Filament\Tables\Table;
|
|
||||||
|
|
||||||
class TodoResource extends Resource
|
|
||||||
{
|
|
||||||
protected static ?string $model = Todo::class;
|
|
||||||
|
|
||||||
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack;
|
|
||||||
|
|
||||||
public static function form(Schema $schema): Schema
|
|
||||||
{
|
|
||||||
return TodoForm::configure($schema);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function infolist(Schema $schema): Schema
|
|
||||||
{
|
|
||||||
return TodoInfolist::configure($schema);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function table(Table $table): Table
|
|
||||||
{
|
|
||||||
return TodosTable::configure($table);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getRelations(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
//
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getPages(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'index' => ListTodos::route('/'),
|
|
||||||
'create' => CreateTodo::route('/create'),
|
|
||||||
'view' => ViewTodo::route('/{record}'),
|
|
||||||
'edit' => EditTodo::route('/{record}/edit'),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Http\Requests\Auth\LoginRequest;
|
use App\Http\Requests\LoginRequest;
|
||||||
use App\Http\Requests\Auth\RegisterRequest;
|
use App\Http\Requests\RegisterRequest;
|
||||||
use App\Http\Requests\UpdateUserRequest;
|
use App\Http\Requests\UpdateUserRequest;
|
||||||
use App\Http\Resources\UserResource;
|
use App\Http\Resources\UserResource;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
|
@ -29,11 +29,10 @@ class AuthController extends Controller
|
||||||
'avatar_url' => $avatarPath,
|
'avatar_url' => $avatarPath,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$token = $user->createToken('todos', ['user'])->plainTextToken;
|
$token = $user->createToken('api', ['user'])->plainTextToken;
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'user' => new UserResource($user),
|
'user' => new UserResource($user),
|
||||||
'token' => $token,
|
|
||||||
], 201)->cookie('token', $token, 60 * 24 * 30);
|
], 201)->cookie('token', $token, 60 * 24 * 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,11 +48,10 @@ class AuthController extends Controller
|
||||||
], 401);
|
], 401);
|
||||||
}
|
}
|
||||||
|
|
||||||
$token = $user->createToken('todos')->plainTextToken;
|
$token = $user->createToken('api')->plainTextToken;
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'user' => new UserResource($user),
|
'user' => new UserResource($user),
|
||||||
'token' => $token,
|
|
||||||
])->cookie('token', $token, 60 * 24 * 30);
|
])->cookie('token', $token, 60 * 24 * 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,97 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
|
||||||
|
|
||||||
use App\Http\Requests\Messaging\ConversationRequest;
|
|
||||||
use App\Http\Resources\Messaging\ConversationResource;
|
|
||||||
use App\Models\Conversation;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
|
||||||
|
|
||||||
class ConversationController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Display a listing of the resource.
|
|
||||||
*/
|
|
||||||
public function index(Request $request): AnonymousResourceCollection
|
|
||||||
{
|
|
||||||
$conversations = $request->user()->conversations()
|
|
||||||
->with(['users', 'latestMessage'])
|
|
||||||
->latest()
|
|
||||||
->get();
|
|
||||||
|
|
||||||
return ConversationResource::collection($conversations);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store a newly created resource in storage.
|
|
||||||
*/
|
|
||||||
public function store(ConversationRequest $request): ConversationResource
|
|
||||||
{
|
|
||||||
$validated = $request->validated();
|
|
||||||
|
|
||||||
$conversation = Conversation::create([
|
|
||||||
'label' => $validated['label'] ?? null,
|
|
||||||
'is_group' => $validated['is_group'] ?? false,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$participants = $validated['participants'];
|
|
||||||
if (!in_array($request->user()->id, $participants)) {
|
|
||||||
$participants[] = $request->user()->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
$conversation->users()->sync($participants);
|
|
||||||
|
|
||||||
return new ConversationResource($conversation->load('users'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display the specified resource.
|
|
||||||
*/
|
|
||||||
public function show(Request $request, Conversation $conversation): ConversationResource
|
|
||||||
{
|
|
||||||
// Check if user is participant
|
|
||||||
if (!$conversation->participants()->where('user_id', $request->user()->id)->exists()) {
|
|
||||||
abort(403);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ConversationResource($conversation->load(['users', 'latestMessage']));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the specified resource in storage.
|
|
||||||
*/
|
|
||||||
public function update(ConversationRequest $request, Conversation $conversation): ConversationResource
|
|
||||||
{
|
|
||||||
if (!$conversation->participants()->where('user_id', $request->user()->id)->exists()) {
|
|
||||||
abort(403);
|
|
||||||
}
|
|
||||||
|
|
||||||
$validated = $request->validated();
|
|
||||||
|
|
||||||
$conversation->update([
|
|
||||||
'label' => $validated['label'] ?? $conversation->label,
|
|
||||||
'is_group' => $validated['is_group'] ?? $conversation->is_group,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (isset($validated['participants'])) {
|
|
||||||
$conversation->users()->sync($validated['participants']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ConversationResource($conversation->load('users'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the specified resource from storage.
|
|
||||||
*/
|
|
||||||
public function destroy(Request $request, Conversation $conversation)
|
|
||||||
{
|
|
||||||
if (!$conversation->participants()->where('user_id', $request->user()->id)->exists()) {
|
|
||||||
abort(403);
|
|
||||||
}
|
|
||||||
|
|
||||||
$conversation->delete();
|
|
||||||
|
|
||||||
return response()->noContent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,95 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
|
||||||
|
|
||||||
use App\Http\Requests\Messaging\MessageRequest;
|
|
||||||
use App\Http\Resources\Messaging\MessageResource;
|
|
||||||
use App\Models\Conversation;
|
|
||||||
use App\Models\Message;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
|
||||||
|
|
||||||
class MessageController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Display a listing of the resource for a conversation.
|
|
||||||
*/
|
|
||||||
public function index(Request $request, Conversation $conversation): AnonymousResourceCollection
|
|
||||||
{
|
|
||||||
if (!$conversation->participants()->where('user_id', $request->user()->id)->exists()) {
|
|
||||||
abort(403);
|
|
||||||
}
|
|
||||||
|
|
||||||
$messages = $conversation->messages()
|
|
||||||
->with('user')
|
|
||||||
->oldest()
|
|
||||||
->get();
|
|
||||||
|
|
||||||
return MessageResource::collection($messages);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store a newly created resource in storage.
|
|
||||||
*/
|
|
||||||
public function store(MessageRequest $request, Conversation $conversation): MessageResource
|
|
||||||
{
|
|
||||||
if (!$conversation->participants()->where('user_id', $request->user()->id)->exists()) {
|
|
||||||
abort(403);
|
|
||||||
}
|
|
||||||
|
|
||||||
$validated = $request->validated();
|
|
||||||
|
|
||||||
$user = $request->user();
|
|
||||||
|
|
||||||
$imageUrl = null;
|
|
||||||
if ($request->hasFile('image')) {
|
|
||||||
$imageUrl = $request->file('image')->store('messages/images', 'public');
|
|
||||||
}
|
|
||||||
|
|
||||||
$message = $conversation->messages()->create([
|
|
||||||
'user_id' => $user->id,
|
|
||||||
'sender_name' => $user->name,
|
|
||||||
'sender_avatar_url' => $user->avatar_url,
|
|
||||||
'body' => $validated['body'] ?? null,
|
|
||||||
'image_url' => $imageUrl,
|
|
||||||
]);
|
|
||||||
|
|
||||||
broadcast(new \App\Events\MessageSent($message))->toOthers();
|
|
||||||
|
|
||||||
return new MessageResource($message->load('user'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the specified resource from storage.
|
|
||||||
*/
|
|
||||||
public function destroy(Request $request, Message $message)
|
|
||||||
{
|
|
||||||
if ($message->user_id !== $request->user()->id) {
|
|
||||||
abort(403);
|
|
||||||
}
|
|
||||||
|
|
||||||
$message->delete();
|
|
||||||
|
|
||||||
return response()->noContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mark a message as read.
|
|
||||||
*/
|
|
||||||
public function markAsRead(Request $request, Message $message)
|
|
||||||
{
|
|
||||||
$conversation = $message->conversation;
|
|
||||||
if (!$conversation->participants()->where('user_id', $request->user()->id)->exists()) {
|
|
||||||
abort(403);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($message->user_id === $request->user()->id) {
|
|
||||||
// Can't mark your own message as read by you (well you could but it's redundant)
|
|
||||||
// But let's say anyone in the conversation can mark any message as read.
|
|
||||||
}
|
|
||||||
|
|
||||||
$message->update(['read_at' => now()]);
|
|
||||||
|
|
||||||
return new MessageResource($message->load('user'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
|
||||||
|
|
||||||
use App\Models\Participant;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
|
|
||||||
class ParticipantController 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(Request $request)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display the specified resource.
|
|
||||||
*/
|
|
||||||
public function show(Participant $participant)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the form for editing the specified resource.
|
|
||||||
*/
|
|
||||||
public function edit(Participant $participant)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the specified resource in storage.
|
|
||||||
*/
|
|
||||||
public function update(Request $request, Participant $participant)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the specified resource from storage.
|
|
||||||
*/
|
|
||||||
public function destroy(Participant $participant)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
|
||||||
|
|
||||||
use App\Models\User;
|
|
||||||
use App\Http\Resources\UserResource;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
|
||||||
|
|
||||||
class UserController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Display a listing of all users except the authenticated one.
|
|
||||||
*/
|
|
||||||
public function index(Request $request): AnonymousResourceCollection
|
|
||||||
{
|
|
||||||
// On retourne tous les utilisateurs sauf soi-même pour faciliter la création de conversations
|
|
||||||
$users = User::all();
|
|
||||||
|
|
||||||
return UserResource::collection($users);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,101 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
|
||||||
|
|
||||||
use App\Http\Requests\TodoRequest;
|
|
||||||
use App\Http\Resources\todoResource;
|
|
||||||
use App\Models\Todo;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\Gate;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
|
||||||
|
|
||||||
class todoController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Liste des todos de l'utilisateur connecté.
|
|
||||||
*/
|
|
||||||
public function index(Request $request)
|
|
||||||
{
|
|
||||||
$perPage = (int) $request->query('per_page', 15);
|
|
||||||
$perPage = max(1, min($perPage, 100));
|
|
||||||
|
|
||||||
$todos = $request->user()
|
|
||||||
->todos()
|
|
||||||
->latest()
|
|
||||||
->paginate($perPage)
|
|
||||||
->withQueryString();
|
|
||||||
|
|
||||||
return todoResource::collection($todos);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Création d'un nouveau todo avec image optionnelle.
|
|
||||||
*/
|
|
||||||
public function store(TodoRequest $request)
|
|
||||||
{
|
|
||||||
$data = $request->validated();
|
|
||||||
|
|
||||||
if ($request->hasFile('image')) {
|
|
||||||
// On stocke dans le dossier 'todos' du disque 'public'
|
|
||||||
// $path contiendra par ex: "todos/nom_du_fichier.jpg"
|
|
||||||
$path = $request->file('image')->store('todos', 'public');
|
|
||||||
$data['image_url'] = $path;
|
|
||||||
}
|
|
||||||
|
|
||||||
$todo = $request->user()->todos()->create($data);
|
|
||||||
|
|
||||||
return new todoResource($todo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mise à jour du todo (texte, statut ou image).
|
|
||||||
*/
|
|
||||||
public function update(TodoRequest $request, Todo $todo)
|
|
||||||
{
|
|
||||||
Gate::authorize('update', $todo);
|
|
||||||
|
|
||||||
$data = $request->validated();
|
|
||||||
|
|
||||||
if ($request->hasFile('image')) {
|
|
||||||
// 1. Supprimer l'ancienne image si elle existe
|
|
||||||
if ($todo->image_url) {
|
|
||||||
Storage::disk('public')->delete($todo->image_url);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Stocker la nouvelle image
|
|
||||||
$path = $request->file('image')->store('todos', 'public');
|
|
||||||
$data['image_url'] = $path;
|
|
||||||
}
|
|
||||||
|
|
||||||
$todo->update($data);
|
|
||||||
|
|
||||||
return new todoResource($todo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Affichage d'un todo précis.
|
|
||||||
*/
|
|
||||||
public function show(Todo $todo)
|
|
||||||
{
|
|
||||||
Gate::authorize('view', $todo);
|
|
||||||
|
|
||||||
return new todoResource($todo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Suppression d'un todo et de son image associée.
|
|
||||||
*/
|
|
||||||
public function destroy(Todo $todo)
|
|
||||||
{
|
|
||||||
Gate::authorize('delete', $todo);
|
|
||||||
|
|
||||||
// Nettoyage : supprimer l'image du serveur avant de supprimer le record
|
|
||||||
if ($todo->image_url) {
|
|
||||||
Storage::disk('public')->delete($todo->image_url);
|
|
||||||
}
|
|
||||||
|
|
||||||
$todo->delete();
|
|
||||||
|
|
||||||
return response()->json(['message' => 'Todo supprimé avec succès']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Http\Requests\Auth;
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Requests\Messaging;
|
|
||||||
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
|
||||||
|
|
||||||
class ConversationRequest 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<mixed>|string>
|
|
||||||
*/
|
|
||||||
public function rules(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'label' => 'nullable|string|max:255',
|
|
||||||
'is_group' => 'boolean',
|
|
||||||
'participants' => 'required|array|min:1',
|
|
||||||
'participants.*' => 'exists:users,id',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Requests\Messaging;
|
|
||||||
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
|
||||||
|
|
||||||
class MessageRequest 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<mixed>|string>
|
|
||||||
*/
|
|
||||||
public function rules(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'body' => 'nullable|string|required_without:image',
|
|
||||||
'image' => 'nullable|image|max:5120', // Max 5MB
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Http\Requests\Auth;
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Requests;
|
|
||||||
|
|
||||||
use App\Enums\PriorityStatus;
|
|
||||||
use App\Enums\TodoProgress;
|
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
|
||||||
use Illuminate\Validation\Rule;
|
|
||||||
|
|
||||||
class TodoRequest extends FormRequest
|
|
||||||
{
|
|
||||||
public function rules(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'name' => [$this->isMethod('post') ? 'required' : 'sometimes', 'string', 'max:255'],
|
|
||||||
'status' => ['sometimes','required', Rule::enum(TodoProgress::class)],
|
|
||||||
'description'=> ['sometimes','nullable', 'string'],
|
|
||||||
'image' => ['sometimes', 'nullable', 'image', 'max:2048'],
|
|
||||||
'due_date' => ['sometimes', 'nullable', 'date'],
|
|
||||||
'priority' => ['sometimes', 'required', Rule::enum(PriorityStatus::class)],
|
|
||||||
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function messages(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'image.max' => "L'image ne doit pas dépasser 2 Mo.",
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function authorize(): bool
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Resources\Messaging;
|
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Http\Resources\Json\JsonResource;
|
|
||||||
use App\Http\Resources\UserResource;
|
|
||||||
|
|
||||||
class ConversationResource extends JsonResource
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Transform the resource into an array.
|
|
||||||
*
|
|
||||||
* @return array<string, mixed>
|
|
||||||
*/
|
|
||||||
public function toArray(Request $request): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'id' => $this->id,
|
|
||||||
'label' => $this->label,
|
|
||||||
'isGroup' => $this->is_group,
|
|
||||||
'participants' => UserResource::collection($this->whenLoaded('users')),
|
|
||||||
'lastMessage' => new MessageResource($this->whenLoaded('latestMessage')),
|
|
||||||
'createdAt' => $this->created_at,
|
|
||||||
'updatedAt' => $this->updated_at,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Resources\Messaging;
|
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Http\Resources\Json\JsonResource;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
|
||||||
|
|
||||||
class MessageResource extends JsonResource
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Transform the resource into an array.
|
|
||||||
*
|
|
||||||
* @return array<string, mixed>
|
|
||||||
*/
|
|
||||||
public function toArray(Request $request): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'id' => $this->id,
|
|
||||||
'senderId' => $this->user_id,
|
|
||||||
'senderName' => $this->sender_name,
|
|
||||||
'senderAvatarUrl' => $this->sender_avatar_url,
|
|
||||||
'body' => $this->body,
|
|
||||||
'imageUrl' => $this->image_url ? asset(Storage::url($this->image_url)) : null,
|
|
||||||
'readAt' => $this->read_at,
|
|
||||||
'createdAt' => $this->created_at,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -16,10 +16,9 @@ class UserResource extends JsonResource
|
||||||
public function toArray(Request $request): array
|
public function toArray(Request $request): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'id' => $this->id,
|
|
||||||
'name' => $this->name,
|
'name' => $this->name,
|
||||||
'email' => $this->email,
|
'email' => $this->email,
|
||||||
'avatarUrl' => $this->avatar_url ? asset(Storage::url($this->avatar_url)) : null,
|
'avatar_url' => $this->avatar_url ? asset(Storage::url($this->avatar_url)) : null,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Resources;
|
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Http\Resources\Json\JsonResource;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
|
||||||
|
|
||||||
class todoResource extends JsonResource
|
|
||||||
{
|
|
||||||
public function toArray(Request $request): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'id' => $this->id,
|
|
||||||
'name' => $this->name,
|
|
||||||
'status' => $this->status,
|
|
||||||
'description' => $this->description,
|
|
||||||
'imageUrl' => $this->image_url ? asset(Storage::url($this->image_url)): null,
|
|
||||||
'dueDate' => $this->due_date,
|
|
||||||
'priority' => $this->priority,
|
|
||||||
'created_at' => $this->created_at,
|
|
||||||
'updated_at' => $this->updated_at,
|
|
||||||
'user_id' => $this->user_id,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Concerns\HasUlids;
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
|
||||||
|
|
||||||
class Conversation extends Model
|
|
||||||
{
|
|
||||||
use HasFactory, HasUlids, SoftDeletes;
|
|
||||||
|
|
||||||
protected $fillable = [
|
|
||||||
'label',
|
|
||||||
'is_group',
|
|
||||||
];
|
|
||||||
|
|
||||||
protected function casts(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'is_group' => 'boolean',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function participants(): HasMany
|
|
||||||
{
|
|
||||||
return $this->hasMany(Participant::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function messages(): HasMany
|
|
||||||
{
|
|
||||||
return $this->hasMany(Message::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function latestMessage(): \Illuminate\Database\Eloquent\Relations\HasOne
|
|
||||||
{
|
|
||||||
return $this->hasOne(Message::class)->latestOfMany();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function users(): BelongsToMany
|
|
||||||
{
|
|
||||||
return $this->belongsToMany(User::class, 'participants')
|
|
||||||
->withTimestamps()
|
|
||||||
->using(Participant::class); // Optional, but links the pivot back to Participant model if needed.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Concerns\HasUlids;
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
|
||||||
|
|
||||||
class Message extends Model
|
|
||||||
{
|
|
||||||
use HasFactory, HasUlids, SoftDeletes;
|
|
||||||
|
|
||||||
protected $fillable = [
|
|
||||||
'user_id',
|
|
||||||
'sender_name',
|
|
||||||
'sender_avatar_url',
|
|
||||||
'conversation_id',
|
|
||||||
'body',
|
|
||||||
'image_url',
|
|
||||||
'read_at',
|
|
||||||
];
|
|
||||||
|
|
||||||
protected function casts(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'read_at' => 'datetime',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function conversation(): BelongsTo
|
|
||||||
{
|
|
||||||
return $this->belongsTo(Conversation::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function user(): BelongsTo
|
|
||||||
{
|
|
||||||
return $this->belongsTo(User::class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Concerns\HasUlids;
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
||||||
use Illuminate\Database\Eloquent\Relations\Pivot;
|
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
||||||
|
|
||||||
class Participant extends Pivot
|
|
||||||
{
|
|
||||||
use HasFactory, HasUlids;
|
|
||||||
|
|
||||||
protected $table = 'participants';
|
|
||||||
|
|
||||||
public $incrementing = false;
|
|
||||||
|
|
||||||
protected $fillable = [
|
|
||||||
'conversation_id',
|
|
||||||
'user_id',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function conversation(): BelongsTo
|
|
||||||
{
|
|
||||||
return $this->belongsTo(Conversation::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function user(): BelongsTo
|
|
||||||
{
|
|
||||||
return $this->belongsTo(User::class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use App\Enums\PriorityStatus;
|
|
||||||
use App\Enums\TodoProgress;
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
||||||
use Laravel\Scout\Searchable;
|
|
||||||
|
|
||||||
class Todo extends Model
|
|
||||||
{
|
|
||||||
use HasFactory, Searchable;
|
|
||||||
|
|
||||||
protected $table = 'todo';
|
|
||||||
|
|
||||||
protected $fillable = [
|
|
||||||
'name',
|
|
||||||
'status',
|
|
||||||
'description',
|
|
||||||
'image_url',
|
|
||||||
'due_date',
|
|
||||||
'priority',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function user(): BelongsTo
|
|
||||||
{
|
|
||||||
return $this->belongsTo(User::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function casts(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'status' => TodoProgress::class,
|
|
||||||
'due_date' => 'date',
|
|
||||||
'priority' => PriorityStatus::class,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the indexable data array for the model.
|
|
||||||
*
|
|
||||||
* @return array<string, mixed>
|
|
||||||
*/
|
|
||||||
public function toSearchableArray(): array
|
|
||||||
{
|
|
||||||
$array = $this->toArray();
|
|
||||||
|
|
||||||
// Customize the data array...
|
|
||||||
|
|
||||||
return $array;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -7,7 +7,6 @@ use Filament\Models\Contracts\FilamentUser;
|
||||||
use Filament\Panel;
|
use Filament\Panel;
|
||||||
use Illuminate\Database\Eloquent\Concerns\HasUlids;
|
use Illuminate\Database\Eloquent\Concerns\HasUlids;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
use Laravel\Sanctum\HasApiTokens;
|
use Laravel\Sanctum\HasApiTokens;
|
||||||
|
|
@ -52,22 +51,6 @@ class User extends Authenticatable implements FilamentUser
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function todos(): HasMany
|
|
||||||
{
|
|
||||||
return $this->hasMany(Todo::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function conversations(): \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
|
||||||
{
|
|
||||||
return $this->belongsToMany(Conversation::class, 'participants')
|
|
||||||
->withTimestamps()
|
|
||||||
->using(Participant::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function messages(): HasMany
|
|
||||||
{
|
|
||||||
return $this->hasMany(Message::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isAdmin()
|
public function isAdmin()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Policies;
|
|
||||||
|
|
||||||
use App\Models\User;
|
|
||||||
use App\Models\Todo;
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
|
|
||||||
class TodoPolicy
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Determine whether the user can view any models.
|
|
||||||
*/
|
|
||||||
public function viewAny(User $user): bool
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can view the model.
|
|
||||||
*/
|
|
||||||
public function view(User $user, Todo $todo): bool
|
|
||||||
{
|
|
||||||
return $user->id === $todo->user_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can create models.
|
|
||||||
*/
|
|
||||||
public function create(User $user): bool
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can update the model.
|
|
||||||
*/
|
|
||||||
public function update(User $user, Todo $todo): bool
|
|
||||||
{
|
|
||||||
return $user->id === $todo->user_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the user can delete the model.
|
|
||||||
*/
|
|
||||||
public function delete(User $user, Todo $todo): bool
|
|
||||||
{
|
|
||||||
return $user->id === $todo->user_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -9,7 +9,6 @@ return Application::configure(basePath: dirname(__DIR__))
|
||||||
web: __DIR__.'/../routes/web.php',
|
web: __DIR__.'/../routes/web.php',
|
||||||
api: __DIR__.'/../routes/api.php',
|
api: __DIR__.'/../routes/api.php',
|
||||||
commands: __DIR__.'/../routes/console.php',
|
commands: __DIR__.'/../routes/console.php',
|
||||||
channels: __DIR__.'/../routes/channels.php',
|
|
||||||
health: '/up',
|
health: '/up',
|
||||||
)
|
)
|
||||||
->withMiddleware(function (Middleware $middleware): void {
|
->withMiddleware(function (Middleware $middleware): void {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ services:
|
||||||
- 'host.docker.internal:host-gateway'
|
- 'host.docker.internal:host-gateway'
|
||||||
ports:
|
ports:
|
||||||
- '${APP_PORT:-8003}:80'
|
- '${APP_PORT:-8003}:80'
|
||||||
- '8080:8080'
|
|
||||||
environment:
|
environment:
|
||||||
WWWUSER: '${WWWUSER}'
|
WWWUSER: '${WWWUSER}'
|
||||||
LARAVEL_SAIL: 1
|
LARAVEL_SAIL: 1
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
"http-interop/http-factory-guzzle": "^1.2",
|
"http-interop/http-factory-guzzle": "^1.2",
|
||||||
"laravel/framework": "^12.0",
|
"laravel/framework": "^12.0",
|
||||||
"laravel/horizon": "^5.45",
|
"laravel/horizon": "^5.45",
|
||||||
"laravel/reverb": "^1.0",
|
|
||||||
"laravel/sanctum": "^4.0",
|
"laravel/sanctum": "^4.0",
|
||||||
"laravel/scout": "^11.0",
|
"laravel/scout": "^11.0",
|
||||||
"laravel/tinker": "^2.10.1",
|
"laravel/tinker": "^2.10.1",
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,82 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
return [
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Default Broadcaster
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| This option controls the default broadcaster that will be used by the
|
|
||||||
| framework when an event needs to be broadcast. You may set this to
|
|
||||||
| any of the connections defined in the "connections" array below.
|
|
||||||
|
|
|
||||||
| Supported: "reverb", "pusher", "ably", "redis", "log", "null"
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
'default' => env('BROADCAST_CONNECTION', 'null'),
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Broadcast Connections
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Here you may define all of the broadcast connections that will be used
|
|
||||||
| to broadcast events to other systems or over WebSockets. Samples of
|
|
||||||
| each available type of connection are provided inside this array.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
'connections' => [
|
|
||||||
|
|
||||||
'reverb' => [
|
|
||||||
'driver' => 'reverb',
|
|
||||||
'key' => env('REVERB_APP_KEY'),
|
|
||||||
'secret' => env('REVERB_APP_SECRET'),
|
|
||||||
'app_id' => env('REVERB_APP_ID'),
|
|
||||||
'options' => [
|
|
||||||
'host' => env('REVERB_HOST'),
|
|
||||||
'port' => env('REVERB_PORT', 443),
|
|
||||||
'scheme' => env('REVERB_SCHEME', 'https'),
|
|
||||||
'useTLS' => env('REVERB_SCHEME', 'https') === 'https',
|
|
||||||
],
|
|
||||||
'client_options' => [
|
|
||||||
// Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html
|
|
||||||
],
|
|
||||||
],
|
|
||||||
|
|
||||||
'pusher' => [
|
|
||||||
'driver' => 'pusher',
|
|
||||||
'key' => env('PUSHER_APP_KEY'),
|
|
||||||
'secret' => env('PUSHER_APP_SECRET'),
|
|
||||||
'app_id' => env('PUSHER_APP_ID'),
|
|
||||||
'options' => [
|
|
||||||
'cluster' => env('PUSHER_APP_CLUSTER'),
|
|
||||||
'host' => env('PUSHER_HOST') ?: 'api-'.env('PUSHER_APP_CLUSTER', 'mt1').'.pusher.com',
|
|
||||||
'port' => env('PUSHER_PORT', 443),
|
|
||||||
'scheme' => env('PUSHER_SCHEME', 'https'),
|
|
||||||
'encrypted' => true,
|
|
||||||
'useTLS' => env('PUSHER_SCHEME', 'https') === 'https',
|
|
||||||
],
|
|
||||||
'client_options' => [
|
|
||||||
// Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html
|
|
||||||
],
|
|
||||||
],
|
|
||||||
|
|
||||||
'ably' => [
|
|
||||||
'driver' => 'ably',
|
|
||||||
'key' => env('ABLY_KEY'),
|
|
||||||
],
|
|
||||||
|
|
||||||
'log' => [
|
|
||||||
'driver' => 'log',
|
|
||||||
],
|
|
||||||
|
|
||||||
'null' => [
|
|
||||||
'driver' => 'null',
|
|
||||||
],
|
|
||||||
|
|
||||||
],
|
|
||||||
|
|
||||||
];
|
|
||||||
|
|
@ -1,102 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
return [
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Default Reverb Server
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| This option controls the default server used by Reverb to handle
|
|
||||||
| incoming messages as well as broadcasting message to all your
|
|
||||||
| connected clients. At this time only "reverb" is supported.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
'default' => env('REVERB_SERVER', 'reverb'),
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Reverb Servers
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Here you may define details for each of the supported Reverb servers.
|
|
||||||
| Each server has its own configuration options that are defined in
|
|
||||||
| the array below. You should ensure all the options are present.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
'servers' => [
|
|
||||||
|
|
||||||
'reverb' => [
|
|
||||||
'host' => env('REVERB_SERVER_HOST', '0.0.0.0'),
|
|
||||||
'port' => env('REVERB_SERVER_PORT', 8080),
|
|
||||||
'path' => env('REVERB_SERVER_PATH', ''),
|
|
||||||
'hostname' => env('REVERB_HOST'),
|
|
||||||
'options' => [
|
|
||||||
'tls' => [],
|
|
||||||
],
|
|
||||||
'max_request_size' => env('REVERB_MAX_REQUEST_SIZE', 10_000),
|
|
||||||
'scaling' => [
|
|
||||||
'enabled' => env('REVERB_SCALING_ENABLED', false),
|
|
||||||
'channel' => env('REVERB_SCALING_CHANNEL', 'reverb'),
|
|
||||||
'server' => [
|
|
||||||
'url' => env('REDIS_URL'),
|
|
||||||
'host' => env('REDIS_HOST', '127.0.0.1'),
|
|
||||||
'port' => env('REDIS_PORT', '6379'),
|
|
||||||
'username' => env('REDIS_USERNAME'),
|
|
||||||
'password' => env('REDIS_PASSWORD'),
|
|
||||||
'database' => env('REDIS_DB', '0'),
|
|
||||||
'timeout' => env('REDIS_TIMEOUT', 60),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'pulse_ingest_interval' => env('REVERB_PULSE_INGEST_INTERVAL', 15),
|
|
||||||
'telescope_ingest_interval' => env('REVERB_TELESCOPE_INGEST_INTERVAL', 15),
|
|
||||||
],
|
|
||||||
|
|
||||||
],
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Reverb Applications
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Here you may define how Reverb applications are managed. If you choose
|
|
||||||
| to use the "config" provider, you may define an array of apps which
|
|
||||||
| your server will support, including their connection credentials.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
|
|
||||||
'apps' => [
|
|
||||||
|
|
||||||
'provider' => 'config',
|
|
||||||
|
|
||||||
'apps' => [
|
|
||||||
[
|
|
||||||
'key' => env('REVERB_APP_KEY'),
|
|
||||||
'secret' => env('REVERB_APP_SECRET'),
|
|
||||||
'app_id' => env('REVERB_APP_ID'),
|
|
||||||
'options' => [
|
|
||||||
'host' => env('REVERB_HOST'),
|
|
||||||
'port' => env('REVERB_PORT', 443),
|
|
||||||
'scheme' => env('REVERB_SCHEME', 'https'),
|
|
||||||
'useTLS' => env('REVERB_SCHEME', 'https') === 'https',
|
|
||||||
],
|
|
||||||
'allowed_origins' => ['*'],
|
|
||||||
'ping_interval' => env('REVERB_APP_PING_INTERVAL', 60),
|
|
||||||
'activity_timeout' => env('REVERB_APP_ACTIVITY_TIMEOUT', 30),
|
|
||||||
'max_connections' => env('REVERB_APP_MAX_CONNECTIONS'),
|
|
||||||
'max_message_size' => env('REVERB_APP_MAX_MESSAGE_SIZE', 10_000),
|
|
||||||
'accept_client_events_from' => env('REVERB_APP_ACCEPT_CLIENT_EVENTS_FROM', 'members'),
|
|
||||||
'rate_limiting' => [
|
|
||||||
'enabled' => env('REVERB_APP_RATE_LIMITING_ENABLED', false),
|
|
||||||
'max_attempts' => env('REVERB_APP_RATE_LIMIT_MAX_ATTEMPTS', 60),
|
|
||||||
'decay_seconds' => env('REVERB_APP_RATE_LIMIT_DECAY_SECONDS', 60),
|
|
||||||
'terminate_on_limit' => env('REVERB_APP_RATE_LIMIT_TERMINATE', false),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
|
|
||||||
],
|
|
||||||
|
|
||||||
];
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Database\Factories;
|
|
||||||
|
|
||||||
use App\Models\Todo;
|
|
||||||
use App\Models\User;
|
|
||||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
|
||||||
use Illuminate\Support\Carbon;
|
|
||||||
|
|
||||||
class todoFactory extends Factory
|
|
||||||
{
|
|
||||||
protected $model = Todo::class;
|
|
||||||
|
|
||||||
public function definition(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'name' => $this->faker->name(),
|
|
||||||
'is_done' => $this->faker->boolean(),
|
|
||||||
'image_url' => null,
|
|
||||||
'created_at' => Carbon::now(),
|
|
||||||
'updated_at' => Carbon::now(),
|
|
||||||
|
|
||||||
'user_id' => User::factory(),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -17,6 +17,8 @@ return new class extends Migration
|
||||||
$table->string('email')->unique();
|
$table->string('email')->unique();
|
||||||
$table->timestamp('email_verified_at')->nullable();
|
$table->timestamp('email_verified_at')->nullable();
|
||||||
$table->string('password');
|
$table->string('password');
|
||||||
|
$table->string('avatar_url', 2048)->nullable();
|
||||||
|
|
||||||
$table->rememberToken();
|
$table->rememberToken();
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
use Illuminate\Database\Migrations\Migration;
|
|
||||||
use Illuminate\Database\Schema\Blueprint;
|
|
||||||
use Illuminate\Support\Facades\Schema;
|
|
||||||
|
|
||||||
return new class extends Migration {
|
|
||||||
public function up(): void
|
|
||||||
{
|
|
||||||
Schema::create('todo', function (Blueprint $table) {
|
|
||||||
$table->id();
|
|
||||||
$table->string('name');
|
|
||||||
$table->boolean('is_done')->default(false);
|
|
||||||
$table->foreignUlid('user_id')->constrained('users');
|
|
||||||
$table->timestamps();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function down(): void
|
|
||||||
{
|
|
||||||
Schema::dropIfExists('todo');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
use Illuminate\Database\Migrations\Migration;
|
|
||||||
use Illuminate\Database\Schema\Blueprint;
|
|
||||||
use Illuminate\Support\Facades\Schema;
|
|
||||||
|
|
||||||
return new class extends Migration
|
|
||||||
{
|
|
||||||
public function up(): void
|
|
||||||
{
|
|
||||||
Schema::table('todo', function (Blueprint $table) {
|
|
||||||
$table->string('image_url')->nullable()->after('is_done');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function down(): void
|
|
||||||
{
|
|
||||||
Schema::table('todo', function (Blueprint $table) {
|
|
||||||
$table->dropColumn('image_url');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
<?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::table('todo', function (Blueprint $table) {
|
|
||||||
$table->string('status')->default('to_do');
|
|
||||||
$table->dropColumn('is_done');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reverse the migrations.
|
|
||||||
*/
|
|
||||||
public function down(): void
|
|
||||||
{
|
|
||||||
Schema::table('todo', function (Blueprint $table) {
|
|
||||||
$table->dropColumn('status');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
<?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::table('todo', function (Blueprint $table) {
|
|
||||||
$table->text("description")->nullable();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reverse the migrations.
|
|
||||||
*/
|
|
||||||
public function down(): void
|
|
||||||
{
|
|
||||||
Schema::table('todo', function (Blueprint $table) {
|
|
||||||
$table->dropColumn('description');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
<?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::table('users', function (Blueprint $table) {
|
|
||||||
$table->string('avatar_url', 2048)->nullable()->after('password');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reverse the migrations.
|
|
||||||
*/
|
|
||||||
public function down(): void
|
|
||||||
{
|
|
||||||
Schema::table('users', function (Blueprint $table) {
|
|
||||||
$table->dropColumn('avatar_url');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
<?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::table('todo', function (Blueprint $table) {
|
|
||||||
$table->string('priority')->default('low');
|
|
||||||
$table->date('due_date')->nullable();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reverse the migrations.
|
|
||||||
*/
|
|
||||||
public function down(): void
|
|
||||||
{
|
|
||||||
Schema::table('todo', function (Blueprint $table) {
|
|
||||||
$table->dropColumn('priority');
|
|
||||||
$table->dropColumn('due_date');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
<?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('conversations', function (Blueprint $table) {
|
|
||||||
$table->ulid('id')->primary();
|
|
||||||
$table->string('label')->nullable();
|
|
||||||
$table->boolean('is_group')->default(false);
|
|
||||||
$table->softDeletesTz();
|
|
||||||
$table->timestampsTz();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reverse the migrations.
|
|
||||||
*/
|
|
||||||
public function down(): void
|
|
||||||
{
|
|
||||||
Schema::dropIfExists('conversations');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
<?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('messages', function (Blueprint $table) {
|
|
||||||
$table->ulid('id')->primary();
|
|
||||||
$table->foreignUlid('user_id')->constrained('users')->nullOnDelete();
|
|
||||||
$table->string('sender_name');
|
|
||||||
$table->string('sender_avatar_url')->nullable();
|
|
||||||
$table->foreignUlid('conversation_id')->constrained('conversations')->cascadeOnDelete();
|
|
||||||
$table->text('body')->nullable();
|
|
||||||
$table->timestampTz('read_at')->nullable();
|
|
||||||
$table->softDeletesTz();
|
|
||||||
$table->timestampsTz();
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reverse the migrations.
|
|
||||||
*/
|
|
||||||
public function down(): void
|
|
||||||
{
|
|
||||||
Schema::dropIfExists('messages');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
<?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('participants', function (Blueprint $table) {
|
|
||||||
$table->ulid('id')->primary();
|
|
||||||
$table->foreignUlid('conversation_id')->constrained('conversations')->cascadeOnDelete();
|
|
||||||
$table->foreignUlid('user_id')->constrained('users')->cascadeOnDelete();
|
|
||||||
$table->timestampsTz();
|
|
||||||
|
|
||||||
$table->unique(['conversation_id', 'user_id']);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reverse the migrations.
|
|
||||||
*/
|
|
||||||
public function down(): void
|
|
||||||
{
|
|
||||||
Schema::dropIfExists('participants');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
<?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::table('messages', function (Blueprint $table) {
|
|
||||||
$table->string('image_url')->nullable()->after('body');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reverse the migrations.
|
|
||||||
*/
|
|
||||||
public function down(): void
|
|
||||||
{
|
|
||||||
Schema::table('messages', function (Blueprint $table) {
|
|
||||||
$table->dropColumn('image_url');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -2,11 +2,3 @@ import axios from 'axios';
|
||||||
window.axios = axios;
|
window.axios = axios;
|
||||||
|
|
||||||
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||||
|
|
||||||
/**
|
|
||||||
* Echo exposes an expressive API for subscribing to channels and listening
|
|
||||||
* for events that are broadcast by Laravel. Echo and event broadcasting
|
|
||||||
* allow your team to quickly build robust real-time web applications.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import './echo';
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
import Echo from 'laravel-echo';
|
|
||||||
|
|
||||||
import Pusher from 'pusher-js';
|
|
||||||
window.Pusher = Pusher;
|
|
||||||
|
|
||||||
window.Echo = new Echo({
|
|
||||||
broadcaster: 'reverb',
|
|
||||||
key: import.meta.env.VITE_REVERB_APP_KEY,
|
|
||||||
wsHost: import.meta.env.VITE_REVERB_HOST,
|
|
||||||
wsPort: import.meta.env.VITE_REVERB_PORT ?? 80,
|
|
||||||
wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
|
|
||||||
forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
|
|
||||||
enabledTransports: ['ws', 'wss'],
|
|
||||||
});
|
|
||||||
|
|
@ -2,9 +2,7 @@
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
use Illuminate\Support\Facades\Broadcast;
|
|
||||||
use App\Http\Controllers\AuthController;
|
use App\Http\Controllers\AuthController;
|
||||||
use App\Http\Controllers\todoController;
|
|
||||||
Route::prefix('auth')->group(function (): void {
|
Route::prefix('auth')->group(function (): void {
|
||||||
Route::post('register', [AuthController::class, 'register']);
|
Route::post('register', [AuthController::class, 'register']);
|
||||||
Route::post('login', [AuthController::class, 'login']);
|
Route::post('login', [AuthController::class, 'login']);
|
||||||
|
|
@ -15,22 +13,3 @@ Route::prefix('auth')->group(function (): void {
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
Route::middleware('auth:sanctum')->prefix('todos')->group(function (): void {
|
|
||||||
Route::get('/', [todoController::class, 'index']);
|
|
||||||
Route::post('/', [todoController::class, 'store']);
|
|
||||||
Route::get('/{todo}', [todoController::class, 'show']);
|
|
||||||
Route::patch('/{todo}', [todoController::class, 'update']);
|
|
||||||
Route::delete('/{todo}', [todoController::class, 'destroy']);
|
|
||||||
});
|
|
||||||
|
|
||||||
Route::middleware('auth:sanctum')->group(function (): void {
|
|
||||||
Broadcast::routes();
|
|
||||||
Route::get('users', [\App\Http\Controllers\UserController::class, 'index']);
|
|
||||||
Route::apiResource('conversations', \App\Http\Controllers\ConversationController::class);
|
|
||||||
|
|
||||||
Route::get('conversations/{conversation}/messages', [\App\Http\Controllers\MessageController::class, 'index']);
|
|
||||||
Route::post('conversations/{conversation}/messages', [\App\Http\Controllers\MessageController::class, 'store']);
|
|
||||||
|
|
||||||
Route::delete('messages/{message}', [\App\Http\Controllers\MessageController::class, 'destroy']);
|
|
||||||
Route::patch('messages/{message}/read', [\App\Http\Controllers\MessageController::class, 'markAsRead']);
|
|
||||||
});
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Broadcast;
|
|
||||||
|
|
||||||
Broadcast::channel('App.Models.User.{id}', function ($user, $id) {
|
|
||||||
return (string) $user->id === (string) $id;
|
|
||||||
});
|
|
||||||
|
|
||||||
Broadcast::channel('conversation.{conversationId}', function ($user, $conversationId) {
|
|
||||||
return \App\Models\Conversation::find($conversationId)
|
|
||||||
?->participants()
|
|
||||||
->where('user_id', $user->id)
|
|
||||||
->exists();
|
|
||||||
});
|
|
||||||
Loading…
Reference in New Issue