Add sports-match type, device tracking, profile visits, and share refactor
- New SportsMatch model/controller and sports UI components/modal - Move share-modal to a reusable x-share-modal/x-share-button component - Add VideoSharedWithUser notification and share-to-members flow - Device/user-agent tracking on views, downloads, share accesses - ProfileVisit model + migration; subscription source tracking - Email thumbnail support; remove stale TODO files
This commit is contained in:
1 parent
6aae6f86b6
commit
73527f3781
61 files changed
+4014
-636
No files matched your search
@@ -4,6 +4,7 @@ use App\Http\Controllers\CommentController;
|
||||
use App\Http\Controllers\ImageUploadController;
|
||||
use App\Http\Controllers\MatchEventController;
|
||||
use App\Http\Controllers\MediaController;
|
||||
use App\Http\Controllers\SportsMatchController;
|
||||
use App\Http\Controllers\PostController;
|
||||
use App\Http\Controllers\SuperAdminController;
|
||||
use App\Http\Controllers\UserController;
|
||||
@@ -16,6 +17,7 @@ Route::get('/media/thumbnails/{filename}', [MediaController::class, 'thumbnail
|
||||
Route::get('/media/avatars/{filename}', [MediaController::class, 'avatar'])->name('media.avatar')->where('filename', '.+');
|
||||
Route::get('/media/banners/{filename}', [MediaController::class, 'banner'])->name('media.banner')->where('filename', '.+');
|
||||
Route::get('/media/post-images/{filename}', [MediaController::class, 'postImage'])->name('media.post-image')->where('filename', '.+');
|
||||
Route::get('/media/sports/{filename}', [MediaController::class, 'sportsImage'])->name('media.sports-image')->where('filename', '.+');
|
||||
|
||||
// Root route - show videos
|
||||
Route::get('/', [VideoController::class, 'index'])->name('home');
|
||||
@@ -49,12 +51,16 @@ Route::get('/videos/{video}/recommendations', [VideoController::class, 'recommen
|
||||
Route::get('/videos/{video}/player-data', [VideoController::class, 'playerData'])->name('videos.playerData');
|
||||
Route::post('/videos/{video}/share', [VideoController::class, 'recordShare'])->name('videos.recordShare');
|
||||
Route::post('/videos/{video}/share/email', [VideoController::class, 'shareByEmail'])->name('videos.shareEmail')->middleware(['auth', 'throttle:10,1']);
|
||||
Route::post('/videos/{video}/share/members', [VideoController::class, 'shareWithMembers'])->name('videos.shareMembers')->middleware(['auth', 'throttle:20,1']);
|
||||
Route::get('/videos/{video}/og-image', [VideoController::class, 'ogImage'])->name('videos.ogImage');
|
||||
Route::get('/s/{token}', [VideoController::class, 'accessShare'])->name('share.access');
|
||||
Route::get('/videos/{video}/insights', [VideoController::class, 'insights'])->name('videos.insights')->middleware('auth');
|
||||
Route::get('/videos/{video}/insights/country/{country}', [VideoController::class, 'insightsCountry'])->name('videos.insights.country')->middleware('auth');
|
||||
Route::get('/videos/{video}/insights/day/{date}', [VideoController::class, 'insightsDay'])->name('videos.insights.day')->middleware('auth');
|
||||
Route::get('/videos/{video}/insights/downloader/{userId}', [VideoController::class, 'insightsDownloaderHistory'])->name('videos.insights.downloader')->middleware('auth');
|
||||
Route::get('/videos/{video}/insights/viewer/{who}', [VideoController::class, 'insightsViewer'])->where('who', '[ug]:[A-Za-z0-9\.:_-]+')->name('videos.insights.viewer')->middleware('auth');
|
||||
Route::get('/videos/{video}/insights/share/{token}', [VideoController::class, 'insightsShare'])->where('token', '[A-Za-z0-9]+')->name('videos.insights.share')->middleware('auth');
|
||||
Route::post('/videos/{video}/identify', [VideoController::class, 'identify'])->name('videos.identify');
|
||||
|
||||
// Video routes - auth + verified required
|
||||
Route::middleware(['auth', 'verified'])->group(function () {
|
||||
@@ -79,8 +85,13 @@ Route::middleware(['auth'])->group(function () {
|
||||
Route::get('/notifications/fetch', [UserController::class, 'fetchNotifications'])->name('notifications.fetch');
|
||||
Route::post('/notifications/{id}/read', [UserController::class, 'markNotificationRead'])->name('notifications.read');
|
||||
Route::post('/notifications/read-all', [UserController::class, 'markAllNotificationsRead'])->name('notifications.read-all');
|
||||
Route::get('/users/search', [UserController::class, 'searchUsers'])->name('users.search');
|
||||
});
|
||||
|
||||
// View progress + profile-visit tracking — accept both guests and authed users
|
||||
Route::post('/videos/{video}/view-progress', [VideoController::class, 'trackProgress'])->name('videos.viewProgress');
|
||||
Route::post('/profile-visits/{user}', [UserController::class, 'recordProfileVisit'])->name('profile.visit');
|
||||
|
||||
// Comment routes
|
||||
Route::get('/videos/{video}/comments', [CommentController::class, 'index'])->name('comments.index');
|
||||
Route::middleware(['auth', 'verified'])->group(function () {
|
||||
@@ -134,6 +145,7 @@ Route::get('/user/playlists', [PlaylistController::class, 'userPlaylists'])->nam
|
||||
// Public playlist routes
|
||||
Route::get('/playlists', [PlaylistController::class, 'index'])->name('playlists.index');
|
||||
Route::get('/playlists/share/{token}', [PlaylistController::class, 'showByToken'])->name('playlists.showByToken');
|
||||
Route::get('/playlists/{playlist}/og-image', [PlaylistController::class, 'ogImage'])->name('playlists.ogImage');
|
||||
Route::get('/playlists/{playlist}', [PlaylistController::class, 'show'])->name('playlists.show');
|
||||
Route::post('/playlists/{playlist}/share', [PlaylistController::class, 'recordShare'])->name('playlists.recordShare');
|
||||
Route::get('/ps/{token}', [PlaylistController::class, 'accessShare'])->name('playlists.accessShare');
|
||||
@@ -168,6 +180,13 @@ Route::middleware(['auth'])->group(function () {
|
||||
Route::post('/2fa/enable', [TwoFactorController::class, 'enable'])->name('2fa.enable');
|
||||
Route::post('/2fa/disable', [TwoFactorController::class, 'disable'])->name('2fa.disable');
|
||||
});
|
||||
|
||||
// Sports match records (progressive-disclosure creation flow)
|
||||
Route::middleware(['auth'])->group(function () {
|
||||
Route::post('/sports-matches', [SportsMatchController::class, 'store'])->name('sports-matches.store');
|
||||
Route::get('/sports-matches/{sportsMatch}/edit', [SportsMatchController::class, 'edit'])->name('sports-matches.edit');
|
||||
Route::put('/sports-matches/{sportsMatch}', [SportsMatchController::class, 'update'])->name('sports-matches.update');
|
||||
});
|
||||
// Signed confirmation link — no auth required (user may click from a different device/browser)
|
||||
Route::get('/2fa/disable/confirm', [TwoFactorController::class, 'confirmDisable'])->name('2fa.disable.confirm');
|
||||
|
||||
|
||||
Reference in new issue
Block a user