620 lines
19 KiB
PHP
620 lines
19 KiB
PHP
<?php
|
|
|
|
namespace Paymenter\Extensions\Others\SocialBase\Http\Controllers;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\User;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\Event;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Illuminate\Support\Facades\Validator;
|
|
use Paymenter\Extensions\Others\SocialBase\Models\UserProfile;
|
|
use Paymenter\Extensions\Others\SocialBase\Models\ProfileComment;
|
|
|
|
class ProfileController extends Controller
|
|
{
|
|
/**
|
|
* Redirect to logged-in user's profile
|
|
*/
|
|
public function redirectToOwnProfile()
|
|
{
|
|
return redirect()->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
|
|
}
|
|
} |