526 lines
19 KiB
PHP
526 lines
19 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\Bank;
|
|
use App\Models\Organization;
|
|
use App\Models\User;
|
|
use App\Traits\ActiveStatesTrait;
|
|
use App\Traits\LocationTrait;
|
|
use App\Traits\ProfilePermissionTrait;
|
|
use Illuminate\Http\Request;
|
|
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
|
|
|
|
class ProfileController extends Controller
|
|
{
|
|
use ActiveStatesTrait;
|
|
use LocationTrait;
|
|
use ProfilePermissionTrait;
|
|
|
|
|
|
|
|
public function show($type, $id)
|
|
{
|
|
if (strtolower($type) === strtolower(__('user'))) {
|
|
return $this->showUser($id);
|
|
}
|
|
if (strtolower($type) === strtolower(__('organization'))) {
|
|
return $this->showOrganization($id);
|
|
}
|
|
if (strtolower($type) === strtolower(__('bank'))) {
|
|
return $this->showBank($id);
|
|
}
|
|
return view('profile.not_found');
|
|
}
|
|
|
|
|
|
public function showActive()
|
|
{
|
|
$profile = getActiveProfile();
|
|
return $this->show(__(class_basename($profile)), $profile->id);
|
|
}
|
|
|
|
|
|
public function showUser($id)
|
|
{
|
|
$user = User::select([
|
|
'id',
|
|
'name',
|
|
'full_name',
|
|
'profile_photo_path',
|
|
'about',
|
|
'about_short',
|
|
'motivation',
|
|
'date_of_birth',
|
|
'website',
|
|
'phone_public',
|
|
'phone',
|
|
'cyclos_skills',
|
|
'lang_preference',
|
|
'email_verified_at',
|
|
'created_at',
|
|
'last_login_at',
|
|
'love_reactant_id',
|
|
'inactive_at',
|
|
'deleted_at'
|
|
])
|
|
->with([
|
|
'organizations:id,name,profile_photo_path',
|
|
'accounts:id,name,accountable_type,accountable_id',
|
|
'languages:id,name,lang_code,flag',
|
|
'tags:tag_id',
|
|
'socials:id,name,icon,urL_structure',
|
|
'locations.district.translations:district_id,name',
|
|
'locations.city.translations:city_id,name',
|
|
'locations.division.translations:division_id,name',
|
|
'locations.country.translations:country_id,name',
|
|
'loveReactant.reactions.reacter.reacterable',
|
|
'loveReactant.reactionCounters',
|
|
])
|
|
->find($id);
|
|
|
|
if (!$user) {
|
|
return view('profile.not_found');
|
|
}
|
|
|
|
$states = $this->getActiveStates($user);
|
|
$canManageProfiles = $this->getCanManageProfiles();
|
|
$canViewIncompleteProfiles = $this->canViewIncompleteProfiles();
|
|
$isViewingOwnProfile = getActiveProfile() &&
|
|
get_class(getActiveProfile()) === User::class &&
|
|
getActiveProfile()->id === $user->id;
|
|
|
|
// For admins/banks: Always show incomplete label if profile is incomplete (ignore config)
|
|
if ($canManageProfiles) {
|
|
$states['hidden'] = false;
|
|
$states['inactiveLabel'] = !$user->isActive();
|
|
$states['inactiveSince'] = $user->inactive_at
|
|
? \Illuminate\Support\Carbon::parse($user->inactive_at)->diffForHumans()
|
|
: '';
|
|
$states['emailUnverifiedLabel'] = !$user->isEmailVerified();
|
|
$states['incompleteLabel'] = $user->hasIncompleteProfile($user);
|
|
}
|
|
|
|
// When viewing own profile, never hide but show all labels
|
|
if ($isViewingOwnProfile) {
|
|
$states['hidden'] = false;
|
|
$states['inactiveLabel'] = !$user->isActive();
|
|
$states['inactiveSince'] = $user->inactive_at
|
|
? \Illuminate\Support\Carbon::parse($user->inactive_at)->diffForHumans()
|
|
: '';
|
|
$states['emailUnverifiedLabel'] = !$user->isEmailVerified();
|
|
$states['incompleteLabel'] = $user->hasIncompleteProfile($user);
|
|
|
|
// Show incomplete warning modal when viewing own profile
|
|
$states['showIncompleteWarning'] = timebank_config('profile_incomplete.show_warning_modal') &&
|
|
$user->hasIncompleteProfile($user);
|
|
}
|
|
|
|
// Check if profile should be hidden
|
|
if ($states['hidden'] && !$canManageProfiles && !$isViewingOwnProfile) {
|
|
// Only allow Admin and Bank profiles to view incomplete-only profiles
|
|
// Inactive profiles should be hidden from everyone except admins/banks
|
|
$isIncompleteOnly = ($states['isIncomplete'] ?? false) &&
|
|
!($states['inactive'] ?? false) &&
|
|
!($states['emailUnverifiedLabel'] ?? false);
|
|
|
|
// Show profile only if it's incomplete-only AND viewer is admin/bank
|
|
if (!($isIncompleteOnly && $canViewIncompleteProfiles)) {
|
|
return view('profile.not_found');
|
|
}
|
|
}
|
|
|
|
$user->reactionCounter = $user->loveReactant->reactionCounters->first() ? (int)$user->loveReactant->reactionCounters->first()->weight : null;
|
|
|
|
$profile = $user;
|
|
$header = __('Personal profile');
|
|
|
|
return $profile != null
|
|
? view('profile.show', array_merge(compact('profile', 'header'), $states))
|
|
: abort(403);
|
|
|
|
}
|
|
|
|
public function showOrganization($id)
|
|
{
|
|
$organization = Organization::select([
|
|
'id',
|
|
'name',
|
|
'profile_photo_path',
|
|
'about',
|
|
'motivation',
|
|
'website',
|
|
'phone_public',
|
|
'phone',
|
|
'cyclos_skills',
|
|
'lang_preference',
|
|
'email_verified_at',
|
|
'created_at',
|
|
'last_login_at',
|
|
'love_reactant_id',
|
|
'inactive_at',
|
|
'deleted_at'
|
|
])
|
|
->with([
|
|
'managers:id,name,profile_photo_path',
|
|
'accounts:id,name,accountable_type,accountable_id',
|
|
'languages:id,name,lang_code,flag',
|
|
'tags:tag_id',
|
|
'socials:id,name,icon,urL_structure',
|
|
'locations.district.translations:district_id,name',
|
|
'locations.city.translations:city_id,name',
|
|
'locations.division.translations:division_id,name',
|
|
'locations.country.translations:country_id,name',
|
|
'loveReactant.reactions.reacter.reacterable',
|
|
// 'loveReactant.reactions.type',
|
|
'loveReactant.reactionCounters',
|
|
// 'loveReactant.reactionTotal',
|
|
])
|
|
->find($id);
|
|
|
|
if (!$organization) {
|
|
return view('profile.not_found');
|
|
}
|
|
|
|
$states = $this->getActiveStates($organization);
|
|
$canManageProfiles = $this->getCanManageProfiles();
|
|
$canViewIncompleteProfiles = $this->canViewIncompleteProfiles();
|
|
$isViewingOwnProfile = getActiveProfile() &&
|
|
get_class(getActiveProfile()) === Organization::class &&
|
|
getActiveProfile()->id === $organization->id;
|
|
|
|
// For admins/banks: Always show incomplete label if profile is incomplete (ignore config)
|
|
if ($canManageProfiles) {
|
|
$states['hidden'] = false;
|
|
$states['inactiveLabel'] = !$organization->isActive();
|
|
$states['inactiveSince'] = $organization->inactive_at
|
|
? \Illuminate\Support\Carbon::parse($organization->inactive_at)->diffForHumans()
|
|
: '';
|
|
$states['emailUnverifiedLabel'] = !$organization->isEmailVerified();
|
|
$states['incompleteLabel'] = $organization->hasIncompleteProfile($organization);
|
|
}
|
|
|
|
// When viewing own profile, never hide but show all labels
|
|
if ($isViewingOwnProfile) {
|
|
$states['hidden'] = false;
|
|
$states['inactiveLabel'] = !$organization->isActive();
|
|
$states['inactiveSince'] = $organization->inactive_at
|
|
? \Illuminate\Support\Carbon::parse($organization->inactive_at)->diffForHumans()
|
|
: '';
|
|
$states['emailUnverifiedLabel'] = !$organization->isEmailVerified();
|
|
$states['incompleteLabel'] = $organization->hasIncompleteProfile($organization);
|
|
|
|
// Show incomplete warning modal when viewing own profile
|
|
$states['showIncompleteWarning'] = timebank_config('profile_incomplete.show_warning_modal') &&
|
|
$organization->hasIncompleteProfile($organization);
|
|
}
|
|
|
|
// Check if profile should be hidden
|
|
if ($states['hidden'] && !$canManageProfiles && !$isViewingOwnProfile) {
|
|
// Only allow Admin and Bank profiles to view incomplete-only profiles
|
|
// Inactive profiles should be hidden from everyone except admins/banks
|
|
$isIncompleteOnly = ($states['isIncomplete'] ?? false) &&
|
|
!($states['inactive'] ?? false) &&
|
|
!($states['emailUnverifiedLabel'] ?? false);
|
|
|
|
// Show profile only if it's incomplete-only AND viewer is admin/bank
|
|
if (!($isIncompleteOnly && $canViewIncompleteProfiles)) {
|
|
return view('profile.not_found');
|
|
}
|
|
}
|
|
|
|
$organization->reactionCounter = $organization->loveReactant->reactionCounters->first() ? (int)$organization->loveReactant->reactionCounters->first()->weight : null;
|
|
|
|
$profile = $organization;
|
|
$header = __('Organization profile');
|
|
|
|
return $profile != null
|
|
? view('profile.show', array_merge(compact('profile', 'header'), $states))
|
|
: abort(403);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function showBank($id)
|
|
{
|
|
$bank = Bank::select([
|
|
'id',
|
|
'name',
|
|
'profile_photo_path',
|
|
'about',
|
|
'motivation',
|
|
'website',
|
|
'phone_public',
|
|
'phone',
|
|
'cyclos_skills',
|
|
'lang_preference',
|
|
'email_verified_at',
|
|
'created_at',
|
|
'last_login_at',
|
|
'love_reactant_id',
|
|
'inactive_at',
|
|
'deleted_at'
|
|
])
|
|
->with([
|
|
'managers:id,name,profile_photo_path',
|
|
'accounts:id,name,accountable_type,accountable_id',
|
|
'languages:id,name,lang_code,flag',
|
|
'tags:tag_id',
|
|
'socials:id,name,icon,urL_structure',
|
|
'locations.district.translations:district_id,name',
|
|
'locations.city.translations:city_id,name',
|
|
'locations.division.translations:division_id,name',
|
|
'locations.country.translations:country_id,name',
|
|
'loveReactant.reactions.reacter.reacterable',
|
|
// 'loveReactant.reactions.type',
|
|
'loveReactant.reactionCounters',
|
|
// 'loveReactant.reactionTotal',
|
|
])
|
|
->find($id);
|
|
|
|
if (!$bank) {
|
|
return view('profile.not_found');
|
|
}
|
|
|
|
$states = $this->getActiveStates($bank);
|
|
$canManageProfiles = $this->getCanManageProfiles();
|
|
$canViewIncompleteProfiles = $this->canViewIncompleteProfiles();
|
|
$isViewingOwnProfile = getActiveProfile() &&
|
|
get_class(getActiveProfile()) === Bank::class &&
|
|
getActiveProfile()->id === $bank->id;
|
|
|
|
// For admins/banks: Always show incomplete label if profile is incomplete (ignore config)
|
|
if ($canManageProfiles) {
|
|
$states['hidden'] = false;
|
|
$states['inactiveLabel'] = !$bank->isActive();
|
|
$states['inactiveSince'] = $bank->inactive_at
|
|
? \Illuminate\Support\Carbon::parse($bank->inactive_at)->diffForHumans()
|
|
: '';
|
|
$states['emailUnverifiedLabel'] = !$bank->isEmailVerified();
|
|
$states['incompleteLabel'] = $bank->hasIncompleteProfile($bank);
|
|
}
|
|
|
|
// When viewing own profile, never hide but show all labels
|
|
if ($isViewingOwnProfile) {
|
|
$states['hidden'] = false;
|
|
$states['inactiveLabel'] = !$bank->isActive();
|
|
$states['inactiveSince'] = $bank->inactive_at
|
|
? \Illuminate\Support\Carbon::parse($bank->inactive_at)->diffForHumans()
|
|
: '';
|
|
$states['emailUnverifiedLabel'] = !$bank->isEmailVerified();
|
|
$states['incompleteLabel'] = $bank->hasIncompleteProfile($bank);
|
|
|
|
// Show incomplete warning modal when viewing own profile
|
|
$states['showIncompleteWarning'] = timebank_config('profile_incomplete.show_warning_modal') &&
|
|
$bank->hasIncompleteProfile($bank);
|
|
}
|
|
|
|
// Check if profile should be hidden
|
|
if ($states['hidden'] && !$canManageProfiles && !$isViewingOwnProfile) {
|
|
// Only allow Admin and Bank profiles to view incomplete-only profiles
|
|
// Inactive profiles should be hidden from everyone except admins/banks
|
|
$isIncompleteOnly = ($states['isIncomplete'] ?? false) &&
|
|
!($states['inactive'] ?? false) &&
|
|
!($states['emailUnverifiedLabel'] ?? false);
|
|
|
|
// Show profile only if it's incomplete-only AND viewer is admin/bank
|
|
if (!($isIncompleteOnly && $canViewIncompleteProfiles)) {
|
|
return view('profile.not_found');
|
|
}
|
|
}
|
|
|
|
$bank->reactionCounter = $bank->loveReactant->reactionCounters->first() ? (int)$bank->loveReactant->reactionCounters->first()->weight : null;
|
|
|
|
$profile = $bank;
|
|
$header = __('Bank profile');
|
|
|
|
return $profile != null
|
|
? view('profile.show', array_merge(compact('profile', 'header'), $states))
|
|
: abort(403);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Show the form for editing the specified resource.
|
|
*
|
|
* @param int $id
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function edit()
|
|
{
|
|
$type = strtolower(class_basename(getActiveProfile()));
|
|
$profile = getActiveProfile();
|
|
|
|
// Check if profile is incomplete - show warning if config allows
|
|
$showIncompleteWarning = false;
|
|
|
|
if (timebank_config('profile_incomplete.show_warning_modal') &&
|
|
method_exists($profile, 'hasIncompleteProfile') &&
|
|
$profile->hasIncompleteProfile($profile)) {
|
|
$showIncompleteWarning = true;
|
|
}
|
|
|
|
return view('profile-' . $type . '.edit', compact('showIncompleteWarning'));
|
|
}
|
|
|
|
|
|
/**
|
|
* Update the specified resource in storage.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @param int $id
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function update(Request $request, $id)
|
|
{
|
|
//
|
|
}
|
|
|
|
|
|
/**
|
|
* Remove the specified resource from storage.
|
|
*
|
|
* @param int $id
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function destroy($id)
|
|
{
|
|
//
|
|
}
|
|
|
|
/**
|
|
* Redirects the authenticated user to their profile settings page with locale-specific routing.
|
|
*
|
|
* This method is used by the route profile.settings.no_locale.
|
|
* The email footer template uses this route because when sending the locale of the
|
|
* recipient is unknown.
|
|
*
|
|
* @return \Illuminate\Http\RedirectResponse Redirects to the localized profile settings page.
|
|
*/
|
|
public function settingsNoLocale()
|
|
{
|
|
$user = auth()->user();
|
|
$locale = $user->lang_preference ?? config('app.fallback_locale');
|
|
|
|
// Load the route translations for the specific locale
|
|
$routeTranslations = include resource_path("lang/{$locale}/routes.php");
|
|
$translatedRoute = $routeTranslations['profile.settings'] ?? 'profile/settings';
|
|
|
|
$localizedUrl = url("/{$locale}/{$translatedRoute}");
|
|
|
|
return redirect($localizedUrl . '#message_settings');
|
|
}
|
|
|
|
|
|
/**
|
|
* Show the user settings screen.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return \Illuminate\View\View
|
|
*/
|
|
public function settings(Request $request)
|
|
{
|
|
|
|
$type = strtolower(class_basename(getActiveProfile()));
|
|
|
|
if ($type === 'user') {
|
|
|
|
return view('profile.settings', [
|
|
'request' => $request,
|
|
'user' => $request->user(),
|
|
]);
|
|
|
|
} else {
|
|
|
|
return view('profile-' . $type . '.settings');
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public function manage()
|
|
{
|
|
return view('profiles.manage');
|
|
}
|
|
|
|
|
|
/**
|
|
* Determines the inactive status flags for a given profile.
|
|
*
|
|
* @param mixed $profile The profile object to check for inactivity.
|
|
* @return array An associative array containing:
|
|
* - 'inactive' (bool): Whether the profile is inactive.
|
|
* - 'hidden' (bool): Whether the profile should be hidden.
|
|
* - 'inactiveLabel' (bool): Whether the profile should be labeled as inactive.
|
|
* - 'inactiveSince' (string): Human-readable duration since the profile became inactive.
|
|
*/
|
|
private function getActiveStates($profile)
|
|
{
|
|
$inactive = false;
|
|
$hidden = false;
|
|
$inactiveLabel = false;
|
|
$inactiveSince = '';
|
|
$emailUnverifiedLabel = false;
|
|
$isIncomplete = false;
|
|
$incompleteLabel = false;
|
|
$noExchangesYetLabel = false;
|
|
$removedSince = '';
|
|
|
|
if (method_exists($profile, 'isActive') && !$profile->isActive()) {
|
|
$inactive = true;
|
|
if (timebank_config('profile_inactive.profile_hidden')) {
|
|
$hidden = true;
|
|
}
|
|
if (timebank_config('profile_inactive.profile_labeled')) {
|
|
$inactiveLabel = true;
|
|
$inactiveSince = $profile->inactive_at
|
|
? \Illuminate\Support\Carbon::parse($profile->inactive_at)->diffForHumans()
|
|
: '';
|
|
}
|
|
}
|
|
|
|
if (method_exists($profile, 'isEmailVerified') && !$profile->isEmailVerified()) {
|
|
$emailUnverifiedLabel = false;
|
|
if (timebank_config('profile_email_unverified.profile_hidden')) {
|
|
$hidden = true;
|
|
}
|
|
if (timebank_config('profile_email_unverified.profile_labeled')) {
|
|
$emailUnverifiedLabel = true;
|
|
}
|
|
}
|
|
|
|
if (method_exists($profile, 'hasIncompleteProfile') && $profile->hasIncompleteProfile($profile)) {
|
|
$isIncomplete = true;
|
|
if (timebank_config('profile_incomplete.profile_hidden')) {
|
|
$hidden = true;
|
|
}
|
|
if (timebank_config('profile_incomplete.profile_labeled')) {
|
|
$incompleteLabel = true;
|
|
}
|
|
}
|
|
|
|
if (
|
|
timebank_config('profile_incomplete.no_exchanges_yet_label') &&
|
|
method_exists($profile, 'hasNeverReceivedTransaction') &&
|
|
$profile->hasNeverReceivedTransaction($profile)
|
|
) {
|
|
$noExchangesYetLabel = true;
|
|
}
|
|
|
|
if (
|
|
(method_exists($profile, 'isRemoved') && $profile->isRemoved()) ||
|
|
(!empty($profile->deleted_at) && \Carbon\Carbon::parse($profile->deleted_at)->isPast())
|
|
) {
|
|
$hidden = true;
|
|
$removedSince = !empty($profile->deleted_at)
|
|
? \Carbon\Carbon::parse($profile->deleted_at)->diffForHumans()
|
|
: '';
|
|
}
|
|
|
|
return compact('inactive', 'hidden', 'inactiveLabel', 'inactiveSince', 'emailUnverifiedLabel', 'isIncomplete', 'incompleteLabel', 'noExchangesYetLabel', 'removedSince');
|
|
}
|
|
}
|