route('socialbase.profile.show', ['user' => Auth::id()]); } /** * Show user profile */ public function show(User $user) { $profile = UserProfile::getForUser($user->id); // If no profile exists, show a message if (!$profile) { return view('socialbase::profile.no-profile', [ 'user' => $user, ]); } // Check if profile is viewable if (!$profile->isViewableBy(Auth::user())) { abort(403, 'This profile is private.'); } return view('socialbase::profile.show', [ 'user' => $user, 'profile' => $profile, 'isOwner' => Auth::check() && Auth::id() === $user->id, 'canComment' => Auth::check() && $profile->allowsComments() && Auth::id() !== $user->id, 'title' => $profile->display_name . '\'s Profile', ]); } /** * Show profile edit form */ public function edit() { $user = Auth::user(); $profile = UserProfile::getForUser($user->id); // If no profile exists, create one for editing if (!$profile) { $profile = UserProfile::createForUser($user->id); } return view('socialbase::profile.edit', [ 'user' => $user, 'profile' => $profile, 'title' => 'Edit Profile', ]); } /** * Show profile settings */ public function settings() { $user = Auth::user(); $profile = UserProfile::getForUser($user->id); // If no profile exists, create one for settings if (!$profile) { $profile = UserProfile::createForUser($user->id); } return view('socialbase::profile.settings', [ 'user' => $user, 'profile' => $profile, ]); } /** * Update profile */ public function update(Request $request) { $validator = Validator::make($request->all(), [ 'display_name' => 'nullable|string|max:255', 'bio' => 'nullable|string|max:1000', 'location' => 'nullable|string|max:255', 'website' => 'nullable|url|max:255', 'is_public' => 'boolean', 'show_email' => 'boolean', 'show_joined_date' => 'boolean', 'allow_comments' => 'boolean', ]); if ($validator->fails()) { return back()->withErrors($validator)->withInput(); } $user = Auth::user(); $profile = UserProfile::createForUser($user->id, true); $profile->update([ 'display_name' => $request->display_name, 'bio' => $request->bio, 'location' => $request->location, 'website' => $request->website, 'is_public' => $request->boolean('is_public'), 'show_email' => $request->boolean('show_email'), 'show_joined_date' => $request->boolean('show_joined_date'), 'allow_comments' => $request->boolean('allow_comments'), ]); // Fire profile updated event Event::dispatch('socialbase.profile.updated', [$user, $profile]); return redirect()->route('socialbase.profile.show', ['user' => $user->id]) ->with('success', 'Profile updated successfully!'); } /** * Upload avatar */ public function uploadAvatar(Request $request) { $validator = Validator::make($request->all(), [ 'avatar' => [ 'required', 'image', 'max:' . ($this->getMaxAvatarSize() * 1024), // Convert MB to KB 'mimes:' . $this->getAllowedImageTypes(), ], ]); if ($validator->fails()) { return response()->json([ 'success' => false, 'message' => $validator->errors()->first(), ], 422); } $user = Auth::user(); $profile = UserProfile::createForUser($user->id, true); // Delete old avatar if ($profile->avatar_path) { Storage::delete($profile->avatar_path); } // Store new avatar $path = $request->file('avatar')->store('socialbase/avatars', 'public'); $profile->update(['avatar_path' => $path]); return response()->json([ 'success' => true, 'message' => 'Avatar uploaded successfully!', 'avatar_url' => $profile->avatar_url, ]); } /** * Upload banner */ public function uploadBanner(Request $request) { $validator = Validator::make($request->all(), [ 'banner' => [ 'required', 'image', 'max:' . ($this->getMaxBannerSize() * 1024), // Convert MB to KB 'mimes:' . $this->getAllowedImageTypes(), ], ]); if ($validator->fails()) { return response()->json([ 'success' => false, 'message' => $validator->errors()->first(), ], 422); } $user = Auth::user(); $profile = UserProfile::createForUser($user->id, true); // Delete old banner if ($profile->banner_path) { Storage::delete($profile->banner_path); } // Store new banner $path = $request->file('banner')->store('socialbase/banners', 'public'); $profile->update(['banner_path' => $path]); return response()->json([ 'success' => true, 'message' => 'Banner uploaded successfully!', 'banner_url' => $profile->banner_url, ]); } /** * Remove avatar */ public function removeAvatar() { $user = Auth::user(); $profile = UserProfile::where('user_id', $user->id)->first(); if ($profile && $profile->avatar_path) { Storage::delete($profile->avatar_path); $profile->update(['avatar_path' => null]); } return response()->json([ 'success' => true, 'message' => 'Avatar removed successfully!', 'avatar_url' => $profile ? $profile->avatar_url : null, ]); } /** * Remove banner */ public function removeBanner() { $user = Auth::user(); $profile = UserProfile::where('user_id', $user->id)->first(); if ($profile && $profile->banner_path) { Storage::delete($profile->banner_path); $profile->update(['banner_path' => null]); } return response()->json([ 'success' => true, 'message' => 'Banner removed successfully!', ]); } /** * Store a comment on profile */ public function storeComment(Request $request, User $user) { $profile = UserProfile::where('user_id', $user->id)->first(); if (!$profile || !$profile->allowsComments()) { abort(403, 'Comments are not allowed on this profile.'); } $validator = Validator::make($request->all(), [ 'content' => 'required|string|min:3|max:1000', 'parent_id' => 'nullable|exists:ext_social_profile_comments,id', ]); if ($validator->fails()) { return response()->json([ 'success' => false, 'message' => $validator->errors()->first(), ], 422); } // Check auto-approval setting $autoApprove = $this->getAutoApproveComments(); $comment = ProfileComment::create([ 'user_profile_id' => $profile->id, 'user_id' => Auth::id(), 'parent_id' => $request->input('parent_id'), 'content' => $request->input('content'), 'approved' => $autoApprove, 'metadata' => [ 'ip_address' => $request->ip(), 'user_agent' => $request->userAgent(), ], ]); // Dispatch event for comment creation if ($autoApprove) { event('socialbase.comment.approved', $comment); } else { event('socialbase.comment.created', $comment); } $message = $autoApprove ? 'Comment posted successfully!' : 'Comment submitted for approval.'; return response()->json([ 'success' => true, 'message' => $message, 'comment' => $comment->load('user'), 'approved' => $autoApprove, ]); } /** * Update a comment */ public function updateComment(Request $request, ProfileComment $comment) { if (!$comment->canBeEditedBy(Auth::user())) { abort(403, 'You cannot edit this comment.'); } $validator = Validator::make($request->all(), [ 'content' => 'required|string|min:3|max:1000', ]); if ($validator->fails()) { return response()->json([ 'success' => false, 'message' => $validator->errors()->first(), ], 422); } $comment->update(['content' => $request->input('content')]); return response()->json([ 'success' => true, 'message' => 'Comment updated successfully!', 'comment' => $comment, ]); } /** * Delete a comment */ public function deleteComment(ProfileComment $comment) { if (!$comment->canBeDeletedBy(Auth::user())) { abort(403, 'You cannot delete this comment.'); } $comment->delete(); return response()->json([ 'success' => true, 'message' => 'Comment deleted successfully!', ]); } /** * Get profile statistics */ public function getStats(User $user) { $profile = UserProfile::where('user_id', $user->id)->first(); if (!$profile || !$profile->isViewableBy(Auth::user())) { abort(403, 'Profile not accessible.'); } return response()->json($profile->stats); } /** * Get profile tabs from extensions */ public function getTabs(User $user) { $profile = UserProfile::where('user_id', $user->id)->first(); if (!$profile || !$profile->isViewableBy(Auth::user())) { abort(403, 'Profile not accessible.'); } // Get tabs from other extensions $tabs = Event::dispatch('socialbase.profile.tabs', [$user]); $tabs = collect($tabs)->flatten(1)->filter(); return response()->json($tabs); } /** * Get tab content from extensions */ public function getTabContent(User $user, string $tab) { $profile = UserProfile::where('user_id', $user->id)->first(); if (!$profile || !$profile->isViewableBy(Auth::user())) { abort(403, 'Profile not accessible.'); } // Get content from extensions $content = Event::dispatch('socialbase.profile.content', [$user, $tab]); $content = collect($content)->first(); return response()->json(['content' => $content]); } /** * Get max avatar size from extension settings */ private function getMaxAvatarSize(): int { try { $extension = \App\Models\Extension::where('extension', 'SocialBase')->first(); if ($extension && $extension->settings) { $setting = $extension->settings->where('key', 'max_avatar_size')->first(); return $setting ? (int) $setting->value : 5; } } catch (\Exception $e) { // Fall back to default } return 5; // Default 5MB } /** * Get max banner size from extension settings */ private function getMaxBannerSize(): int { try { $extension = \App\Models\Extension::where('extension', 'SocialBase')->first(); if ($extension && $extension->settings) { $setting = $extension->settings->where('key', 'max_banner_size')->first(); return $setting ? (int) $setting->value : 10; } } catch (\Exception $e) { // Fall back to default } return 10; // Default 10MB } /** * Get allowed image types */ private function getAllowedImageTypes(): string { try { $extension = \App\Models\Extension::where('extension', 'SocialBase')->first(); if ($extension && $extension->settings) { $setting = $extension->settings->where('key', 'allowed_image_types')->first(); return $setting ? $setting->value : 'jpg,jpeg,png,gif,webp'; } } catch (\Exception $e) { // Fall back to default } return 'jpg,jpeg,png,gif,webp'; } /** * Get auto-approve comments setting */ /** * Add or toggle a reaction to a comment */ public function toggleReaction(Request $request, ProfileComment $comment) { if (!Auth::check()) { return response()->json([ 'success' => false, 'message' => 'You must be logged in to react to comments.', ], 401); } // Get available reaction types for social context $availableTypes = \Paymenter\Extensions\Others\SocialBase\Models\Reaction::getAvailableTypes('social'); $validator = Validator::make($request->all(), [ 'type' => 'required|in:' . implode(',', array_keys($availableTypes)), ]); if ($validator->fails()) { return response()->json([ 'success' => false, 'message' => $validator->errors()->first(), ], 422); } $user = Auth::user(); $reactionType = $request->input('type'); // Use the generic reaction system $action = $comment->toggleReaction($user, $reactionType); // Get updated reaction counts $reactionCounts = $comment->fresh()->reaction_counts; return response()->json([ 'success' => true, 'message' => 'Reaction ' . $action . ' successfully!', 'action' => $action, 'reaction_counts' => $reactionCounts, 'user_reaction' => $comment->getUserReaction($user)?->type, ]); } /** * Get reactions for a comment */ public function getCommentReactions(ProfileComment $comment) { return response()->json([ 'reaction_counts' => $comment->reaction_counts, 'user_reaction' => Auth::check() ? $comment->getUserReaction(Auth::user())?->type : null, 'reactions_with_users' => $comment->reactions_with_users, 'total_reactions' => $comment->total_reactions, ]); } /** * Add or toggle a reaction to a profile */ public function toggleProfileReaction(Request $request, User $user) { if (!Auth::check()) { return response()->json([ 'success' => false, 'message' => 'You must be logged in to react to profiles.', ], 401); } $profile = UserProfile::createForUser($user->id, true); // Check if profile is viewable if (!$profile->isViewableBy(Auth::user())) { return response()->json([ 'success' => false, 'message' => 'You cannot react to this profile.', ], 403); } // Don't allow users to react to their own profile if (Auth::id() === $user->id) { return response()->json([ 'success' => false, 'message' => 'You cannot react to your own profile.', ], 422); } // Get available reaction types for social context $availableTypes = \Paymenter\Extensions\Others\SocialBase\Models\Reaction::getAvailableTypes('social'); $validator = Validator::make($request->all(), [ 'type' => 'required|in:' . implode(',', array_keys($availableTypes)), ]); if ($validator->fails()) { return response()->json([ 'success' => false, 'message' => $validator->errors()->first(), ], 422); } $authUser = Auth::user(); $reactionType = $request->input('type'); // Use the generic reaction system $action = $profile->toggleReaction($authUser, $reactionType); // Get updated reaction counts $reactionCounts = $profile->fresh()->reaction_counts; return response()->json([ 'success' => true, 'message' => 'Profile reaction ' . $action . ' successfully!', 'action' => $action, 'reaction_counts' => $reactionCounts, 'user_reaction' => $profile->getUserReaction($authUser)?->type, ]); } /** * Get reactions for a profile */ public function getProfileReactions(User $user) { $profile = UserProfile::createForUser($user->id, true); // Check if profile is viewable if (!$profile->isViewableBy(Auth::user())) { return response()->json([ 'success' => false, 'message' => 'You cannot view reactions for this profile.', ], 403); } return response()->json([ 'reaction_counts' => $profile->reaction_counts, 'user_reaction' => Auth::check() ? $profile->getUserReaction(Auth::user())?->type : null, 'reactions_with_users' => $profile->reactions_with_users, 'total_reactions' => $profile->total_reactions, ]); } private function getAutoApproveComments(): bool { try { $extension = \App\Models\Extension::where('extension', 'SocialBase')->first(); if ($extension && $extension->settings) { $setting = $extension->settings->where('key', 'require_approval_comments')->first(); return $setting ? !(bool) $setting->value : true; // Invert because setting is "require approval" } } catch (\Exception $e) { // Fall back to default } return true; // Default to auto-approve } }