Files
back-meditation/routes/api.php
T
2026-06-13 17:20:42 +03:30

328 lines
17 KiB
PHP

<?php
use App\Http\Controllers\UserController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Laravel\Socialite\Facades\Socialite;
use App\Http\Controllers\BreathingExerciseController;
use App\Http\Controllers\PackageNameController;
use App\Http\Controllers\ProductController;
use App\Http\Controllers\BreathingTemplate;
use App\Http\Controllers\MoodController;
use App\Http\Controllers\WorryController;
use Illuminate\Support\Facades\Hash;
use App\Http\Controllers\QuestionController;
use App\Http\Controllers\SurveyQuestionController;
use App\Http\Controllers\ChatTopicController;
use App\Http\Controllers\AppFeedbackController;
use App\Http\Controllers\SliderController;
use App\Http\Controllers\SceneController;
use App\Http\Controllers\BellSoundController;
use App\Http\Controllers\BackgroundSoundController;
use App\Http\Controllers\TimerPresetController;
use App\Http\Controllers\ImageController;
use App\Http\Controllers\MusicController;
use App\Http\Controllers\MediaController;
use App\Http\Controllers\CategoryController;
use App\Http\Controllers\SubCategoryController;
use App\Http\Controllers\MusicCategoryController;
use App\Http\Controllers\MusicPlaylistController;
use App\Http\Controllers\RatingController;
use App\Http\Controllers\CommentController;
use App\Http\Controllers\MusicSubcategoryController;
use App\Http\Controllers\SaveController;
use App\Http\Controllers\LikeController;
use App\Http\Controllers\InteractionController;
Route::get('/test-hash', function() {
$plain = 'amnk1380';
$hash = Hash::make($plain);
return [
'plain' => $plain,
'hash' => $hash,
'check' => Hash::check($plain, $hash), // should be true
];
});
Route::get('package-names/{name}/products', [ProductController::class, 'index']);
Route::prefix('auth')->controller(UserController::class)->group(function () {
Route::post('login-with-approo-v2', [UserController::class, 'loginV2']);
Route::middleware(['throttle:3,1'])->post('login-otp', 'loginOTP');
Route::post('check-otp', 'checkOTP');
Route::post('verify-email-code','verifyEmailCode');
Route::post('login', 'login');
Route::post('register', 'register');
Route::post('resend-email-verification', [UserController::class, 'resendEmailVerification']);
Route::post('/login-google', 'googleLogin');
Route::get('/oauth/callback', 'oauthCallback');
Route::middleware('auth:sanctum')->group(function () {
Route::put('logout', 'logout');
});
});
Route::middleware('auth:sanctum')->group(function () {
Route::apiResource('reminders', ReminderController::class);
Route::get('status', [UserController::class, 'status']);
Route::prefix('package-names')->controller(PackageNameController::class)->group(function () {
Route::get('/', 'index');
Route::middleware('abilities:admin')->post('/', 'store');
Route::middleware('abilities:admin')->post('/{name}', 'update');
Route::put('/{name}/try', [UserController::class, 'try']);
Route::middleware('abilities:admin')->post('/{name}/products', [ProductController::class, 'store']);
Route::middleware('abilities:admin')->patch('/{name}/products/{id}', [ProductController::class, 'update']);
Route::middleware('abilities:admin')->delete('/{name}/products/{id}', [ProductController::class, 'delete']);
Route::put('/{name}/products/{id}/subscribe', [ProductController::class, 'subscribe']);
});
// --------- user profile
Route::post('/profile', [UserController::class, 'updateProfile']);
Route::get('/profile', [UserController::class, 'profile']);
////-- leader board
Route::get('/leader-board', [UserController::class, 'leaderBoard']);
////-- referral (دعوت دوستان)
Route::get('/referral', [UserController::class, 'referral']);
///-- mood routes
Route::post('/moods/today', [MoodController::class, 'storeUserMood']);
Route::get('/moods/history', [MoodController::class, 'getUserMoods']);
// --------- get moods
Route::get('/moods', [MoodController::class, 'getAllMoods']);
// Route::post('breathing-exercises', [BreathingExerciseController::class, 'store']);
// Route::get('profile', [BreathingExerciseController::class, 'profile']);
// ------------------------------------------------
Route::post('breathing-templates', [BreathingExerciseController::class, 'createTemplate']);
Route::get('breathing-templates', [BreathingExerciseController::class, 'getTemplates']);
Route::post('breathing-complete', [BreathingExerciseController::class, 'completeSession']);
// Route::get('profile', [BreathingExerciseController::class, 'profile']);
Route::put('breathing-templates/{id}', [BreathingExerciseController::class, 'updateTemplate']);
Route::delete('breathing-templates/{id}', [BreathingExerciseController::class, 'deleteTemplate']);
Route::get('user-templates', [BreathingExerciseController::class, 'getUserTemplates']);
Route::get('breathing-sessions', [BreathingExerciseController::class, 'getSessions']);
/// worry box feature
Route::prefix('worries')->controller(WorryController::class)->group(function () {
Route::post('/', 'store'); // Create worry + note
Route::get('/', 'index'); // Get all worries
Route::put('/{id}', 'update'); // Edit worry & note
Route::patch('/{id}/toggle', 'toggleSolved'); // Mark solved / unsolved
Route::delete('/{id}', 'destroy'); // Delete worry
});
/// questions feature
Route::get('/questions', [QuestionController::class, 'index']);
Route::post('/questions', [QuestionController::class, 'store']);
Route::get('/questions/{question}', [QuestionController::class, 'show']);
Route::put('/questions/{question}', [QuestionController::class, 'update']);
Route::delete('/questions/{question}', [QuestionController::class, 'destroy']);
/// advisor chat — suggested topics (موضوعات پیشنهادی)
Route::apiResource('chat-topics', ChatTopicController::class);
/// app feedback — ideas & reviews (نظرات و ایده‌ها)
Route::get('/app-feedback', [AppFeedbackController::class, 'mine']);
Route::post('/app-feedback', [AppFeedbackController::class, 'store']);
Route::middleware('abilities:admin')->group(function () {
Route::get('/admin/app-feedback', [AppFeedbackController::class, 'adminIndex']);
Route::delete('/admin/app-feedback/{id}', [AppFeedbackController::class, 'adminDestroy']);
});
/// survey questions feature (question + description + single/multi options, answered by users)
// Admin: see all users' answers (must be registered before the resource so it isn't caught by {survey_question}).
Route::middleware('abilities:admin')->group(function () {
// Aggregated analytics — register before the {id} routes so "analytics" isn't read as an id.
Route::get('/admin/survey-questions/analytics', [SurveyQuestionController::class, 'adminAnalytics']);
Route::get('/admin/survey-questions/{id}/analytics', [SurveyQuestionController::class, 'adminAnalytics']);
Route::get('/admin/survey-questions', [SurveyQuestionController::class, 'adminIndex']);
Route::get('/admin/survey-questions/{id}', [SurveyQuestionController::class, 'adminShow']);
});
// User: answer + read questions with their own answers only.
Route::get('/survey-questions/suggested-media', [SurveyQuestionController::class, 'suggestedMedia']);
Route::post('/survey-questions/answers', [SurveyQuestionController::class, 'bulkAnswer']);
Route::post('/survey-questions/{id}/answer', [SurveyQuestionController::class, 'answer']);
Route::apiResource('survey-questions', SurveyQuestionController::class);
/// slider feature
// Route::get('/slider', [SliderController::class, 'index']);
/// images
Route::post('/images', [ImageController::class, 'store']);
Route::get('/images/private', [ImageController::class, 'userImages']);
Route::get('/images/all', [ImageController::class, 'allImages']);
Route::get('/images/public', [ImageController::class, 'publicImages']);
Route::put('/images/{id}', [ImageController::class, 'update']); // ✅ update
Route::delete('/images/{id}', [ImageController::class, 'destroy']); // ✅ delete
/// music
// Route::post('/music', [MusicController::class, 'store']);
// Route::get('/music/all', [MusicController::class, 'all']);
// Route::put('/music/{id}', [MusicController::class, 'update']);
// Route::delete('/music/{id}', [MusicController::class, 'destroy']);
Route::get('/slider', [SliderController::class, 'index']); // list all sliders
Route::post('/slider', [SliderController::class, 'store']); // create slider
Route::get('/slider/{id}', [SliderController::class, 'show']); // get single slider
Route::put('/slider/{id}', [SliderController::class, 'update']); // update slider
Route::delete('/slider/{id}', [SliderController::class, 'destroy']); // delete slider
/// scenes (تنظیمات صحنه) — each scene has an image, optional video, and sound
// Consolidated settings screen (all scenes + current user's preferences) in one call.
Route::get('/scene-settings', [SceneController::class, 'settings']);
Route::put('/scene-settings', [SceneController::class, 'updateSettings']);
Route::get('/scenes', [SceneController::class, 'index']);
Route::post('/scenes', [SceneController::class, 'store']); // multipart: image, video, sound
Route::get('/scenes/{id}', [SceneController::class, 'show']);
Route::post('/scenes/{id}', [SceneController::class, 'update']); // multipart update
Route::delete('/scenes/{id}', [SceneController::class, 'destroy']);
/// insight timer (زمان‌سنج)
// Builder catalogs (bells / background sounds / background images) in one call.
Route::get('/timer/options', [TimerPresetController::class, 'options']);
// Saved timers per user (ذخیره‌شده‌های من).
Route::get('/timer-presets', [TimerPresetController::class, 'index']);
Route::post('/timer-presets', [TimerPresetController::class, 'store']);
Route::get('/timer-presets/{id}', [TimerPresetController::class, 'show']);
Route::put('/timer-presets/{id}', [TimerPresetController::class, 'update']);
Route::delete('/timer-presets/{id}', [TimerPresetController::class, 'destroy']);
// Timer sound/image catalogs (POST update for multipart uploads).
Route::get('/bell-sounds', [BellSoundController::class, 'index']);
Route::post('/bell-sounds', [BellSoundController::class, 'store']);
Route::get('/bell-sounds/{id}', [BellSoundController::class, 'show']);
Route::post('/bell-sounds/{id}', [BellSoundController::class, 'update']);
Route::delete('/bell-sounds/{id}', [BellSoundController::class, 'destroy']);
Route::get('/background-sounds', [BackgroundSoundController::class, 'index']);
Route::post('/background-sounds', [BackgroundSoundController::class, 'store']);
Route::get('/background-sounds/{id}', [BackgroundSoundController::class, 'show']);
Route::post('/background-sounds/{id}', [BackgroundSoundController::class, 'update']);
Route::delete('/background-sounds/{id}', [BackgroundSoundController::class, 'destroy']);
// Background images for timers reuse the shared images catalog (see /images routes).
///media
Route::get('/media/filters', [MediaController::class, 'filters']);
Route::get('/media/popular', [MediaController::class, 'popular']);
Route::get('/media/newest', [MediaController::class, 'newest']);
Route::get('/media/recently-played', [MediaController::class, 'recentlyPlayed']);
Route::post('/media', [MediaController::class, 'store']);
Route::get('/media', [MediaController::class, 'index']);
Route::post('/media/{id}', [MediaController::class, 'update']);
Route::get('/media/saved', [MediaController::class, 'saved']);
Route::delete('/media/{id}', [MediaController::class, 'destroy']);
Route::get('/media/{id}', [MediaController::class, 'show']);
Route::post('/media/{id}/play', [MediaController::class, 'recordPlay']);
Route::post('/media/{id}/save', [MediaController::class, 'toggleSaveMedia']);
Route::post('/media/{id}/rate', [MediaController::class, 'rate']);
Route::post('/media/{id}/comment', [MediaController::class, 'storeComment']);
Route::get('/media/{id}/comments', [MediaController::class, 'getComments']);
Route::post('/media/{id}/feedback', [MediaController::class, 'submitFeedback']);
//add note to media
Route::post('/media/{id}/note', [MediaController::class, 'storeNote']);
// Media categories
// Category with its sub-categories, each carrying its medias.
Route::get('categories/{id}/grouped', [CategoryController::class, 'grouped']);
// Explicit POST update so an icon image can be uploaded (multipart can't ride a PUT).
Route::post('categories/{id}', [CategoryController::class, 'update']);
Route::apiResource('categories', CategoryController::class);
// Media sub categories
Route::get('sub-categories/by-category/{categoryId}', [SubCategoryController::class, 'index']);
Route::apiResource('sub-categories', SubCategoryController::class);
// Music Categories
// Category with its sub-categories, each carrying its playlists.
Route::get('music-categories/{id}/grouped', [MusicCategoryController::class, 'grouped']);
Route::apiResource('music-categories', MusicCategoryController::class);
Route::get('public/music-categories', [MusicCategoryController::class, 'index']);
// Music Playlists
// Explicit POST update so a playlist image can be uploaded (multipart can't ride a PUT).
Route::post('music-playlists/{music_playlist}', [MusicPlaylistController::class, 'update']);
Route::apiResource('music-playlists', MusicPlaylistController::class);
Route::get('playlists/by-category/{categoryId}', [MusicPlaylistController::class, 'index']);
// Subcategory routes
Route::apiResource('music-subcategories', MusicSubcategoryController::class);
Route::get('subcategories/by-category/{categoryId}', [MusicSubcategoryController::class, 'index']);
// Music Routes - Add this line before your other routes
Route::get('music/all', [MusicController::class, 'getAllMusic']); // For old app compatibility
// Music
Route::get('music/playlist/{playlistId}', [MusicController::class, 'getMusicByPlaylist']);
Route::post('music/{musicId}/add-to-playlist', [MusicController::class, 'addToPlaylist']);
Route::delete('music/{musicId}/remove-from-playlist', [MusicController::class, 'removeFromPlaylist']);
Route::post('music/update-order', [MusicController::class, 'updateOrder']);
Route::apiResource('music', MusicController::class);
// Generic Rating Routes (works for both music and media)
Route::prefix('ratings')->group(function () {
Route::post('{type}/{id}', [RatingController::class, 'rate']);
Route::get('{type}/{id}/user', [RatingController::class, 'getUserRating']);
Route::delete('{type}/{id}', [RatingController::class, 'deleteRating']);
Route::get('{type}/{id}', [RatingController::class, 'getRatings']);
Route::get('top/{type}', [RatingController::class, 'topRated']);
});
// Generic Comment Routes (works for both music and media)
Route::prefix('comments')->group(function () {
Route::post('{type}/{id}', [CommentController::class, 'addComment']);
Route::get('{type}/{id}', [CommentController::class, 'getComments']);
Route::put('{type}/{id}/{commentId}', [CommentController::class, 'updateComment']);
Route::delete('{type}/{id}/{commentId}', [CommentController::class, 'deleteComment']);
Route::get('most/{type}', [CommentController::class, 'mostCommented']);
});
// Save routes (works for all models)
Route::prefix('saves')->group(function () {
Route::post('/save', [SaveController::class, 'save']);
Route::post('/unsave', [SaveController::class, 'unsave']);
Route::post('/toggle', [SaveController::class, 'toggleSave']);
Route::get('/my-saved', [SaveController::class, 'mySavedItems']);
Route::post('/check', [SaveController::class, 'checkSaved']);
});
// Combined comment + like in one request (music / media / playlist)
Route::post('interactions/{type}/{id}', [InteractionController::class, 'store']);
// Like routes (only for music and media)
Route::prefix('likes')->group(function () {
Route::post('/like', [LikeController::class, 'like']);
Route::post('/unlike', [LikeController::class, 'unlike']);
Route::post('/toggle', [LikeController::class, 'toggleLike']);
Route::get('/my-liked', [LikeController::class, 'myLikedItems']);
Route::post('/check', [LikeController::class, 'checkLiked']);
Route::get('/top-liked', [LikeController::class, 'topLiked']);
});
});