323 lines
9.5 KiB
PHP
323 lines
9.5 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use App\Models\Locations\Location;
|
|
use App\Models\User;
|
|
use App\Notifications\NonUserPasswordResetNotification;
|
|
use App\Notifications\VerifyProfileEmail;
|
|
use App\Traits\ActiveStatesTrait;
|
|
use App\Traits\HasPresence;
|
|
use App\Traits\LocationTrait;
|
|
use App\Traits\TaggableWithLocale;
|
|
use Illuminate\Auth\MustVerifyEmail as AuthMustVerifyEmail;
|
|
use Illuminate\Auth\Passwords\CanResetPassword;
|
|
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
|
|
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
|
use Illuminate\Database\Eloquent\Collection;
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
|
use Illuminate\Notifications\Notifiable;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Laravel\Jetstream\HasProfilePhoto;
|
|
use Namu\WireChat\Traits\Chatable;
|
|
use Spatie\Activitylog\LogOptions;
|
|
use Spatie\Activitylog\Traits\LogsActivity;
|
|
use Spatie\Permission\Traits\HasRoles;
|
|
|
|
class Admin extends Authenticatable implements MustVerifyEmail, CanResetPasswordContract
|
|
{
|
|
use HasFactory;
|
|
use AuthMustVerifyEmail;
|
|
use Notifiable;
|
|
use HasRoles;
|
|
use LogsActivity; // Spatie Activity Log
|
|
use HasProfilePhoto;
|
|
use TaggableWithLocale;
|
|
use LocationTrait;
|
|
use CanResetPassword; // Trait
|
|
use Chatable;
|
|
use ActiveStatesTrait;
|
|
use HasPresence;
|
|
|
|
/**
|
|
* The attributes that should be hidden for serialization.
|
|
* BEWARE: API's CAN POTENTIALLY EXPOSE ALL VISIBLE FIELDS
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $hidden = [
|
|
'email',
|
|
'email_verified_at',
|
|
'full_name',
|
|
'password',
|
|
'remember_token',
|
|
'phone',
|
|
'cyclos_id',
|
|
'cyclos_salt',
|
|
'two_factor_confirmed_at',
|
|
'two_factor_recovery_codes',
|
|
'two_factor_secret',
|
|
'limit_min',
|
|
'limit_max',
|
|
'lang_preference',
|
|
'created_at',
|
|
'updated_at',
|
|
'last_login_at',
|
|
'inactive_at',
|
|
'deleted_at',
|
|
];
|
|
|
|
/**
|
|
* The attributes that are mass assignable.
|
|
*
|
|
* @var string[]
|
|
*/
|
|
protected $fillable = [
|
|
'name',
|
|
'full_name',
|
|
'email',
|
|
'profile_photo_path',
|
|
'about',
|
|
'about_short',
|
|
'motivation',
|
|
'website',
|
|
'phone',
|
|
'phone_public',
|
|
'password',
|
|
'limit_min',
|
|
'limit_max',
|
|
'lang_preference',
|
|
'last_login_at',
|
|
'last_login_ip'
|
|
];
|
|
|
|
|
|
/**
|
|
* The attributes that should be cast.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $casts = [
|
|
'phone_public' => 'boolean',
|
|
'email_verified_at' => 'datetime',
|
|
'inactive_at' => 'datetime',
|
|
'deleted_at' => 'datetime',
|
|
];
|
|
|
|
|
|
/**
|
|
* Get the admin's user(s) that can manage admin profiles.
|
|
* Many-to-many.
|
|
*/
|
|
public function users()
|
|
{
|
|
return $this->belongsToMany(User::class);
|
|
}
|
|
|
|
|
|
/**
|
|
* Get all related languages of the admin.
|
|
* Many-to-many polymorphic.
|
|
*/
|
|
public function languages()
|
|
{
|
|
return $this->morphToMany(Language::class, 'languagable')->withPivot('competence');
|
|
}
|
|
|
|
|
|
/**
|
|
* Get all related the locations of the admin.
|
|
* One-to-many polymorph.
|
|
*/
|
|
public function locations()
|
|
{
|
|
return $this->morphMany(Location::class, 'locatable');
|
|
}
|
|
|
|
|
|
/**
|
|
* Get all related accounts of the user.
|
|
* One-to-many polymorphic.
|
|
* NOTE: At the moment admins do not use accounts, but to keep methods consistent
|
|
* with the other profile models, we keep this method.
|
|
* Removing this method will break generic methods that will are used on all profile models!
|
|
*/
|
|
public function accounts()
|
|
{
|
|
return $this->morphMany(Account::class, 'accountable');
|
|
}
|
|
|
|
/**
|
|
* Get all of the admin's message settings.
|
|
*/
|
|
public function message_settings()
|
|
{
|
|
return $this->morphMany(MessageSetting::class, 'message_settingable');
|
|
}
|
|
|
|
|
|
public function sendEmailVerificationNotification()
|
|
{
|
|
\Mail::to($this->email)->send(new \App\Mail\VerifyProfileEmailMailable($this));
|
|
}
|
|
|
|
/**
|
|
* Send the password reset notification.
|
|
*
|
|
* @param string $token
|
|
* @return void
|
|
*/
|
|
public function sendPasswordResetNotification($token)
|
|
{
|
|
// Construct the full reset URL using the named route
|
|
// The route 'non-user.password.reset' expects 'profileType' and 'token' parameters.
|
|
// It's also good practice to include the email in the query string for the reset form.
|
|
$resetUrl = route('non-user.password.reset', [
|
|
'profileType' => 'admin', // Hardcode 'admin' for the Admin model
|
|
'token' => $token,
|
|
'email' => $this->getEmailForPasswordReset(), // Method from CanResetPassword trait
|
|
]);
|
|
|
|
// Pass the fully constructed URL to your notification
|
|
$this->notify(new NonUserPasswordResetNotification($resetUrl, $this));
|
|
}
|
|
|
|
|
|
/**
|
|
* Configure the activity log options for the User model.
|
|
*
|
|
* This method sets up the logging to:
|
|
* - Only log changes to the 'name', 'password', and 'last_login_ip' attributes.
|
|
* - Log only when these attributes have been modified (dirty).
|
|
* - Prevent submission of empty logs.
|
|
* - Use 'user' as the log name.
|
|
*
|
|
* @return \Spatie\Activitylog\LogOptions
|
|
*/
|
|
public function getActivitylogOptions(): LogOptions
|
|
{
|
|
return LogOptions::defaults()
|
|
->logOnly([
|
|
'name',
|
|
'last_login_ip',
|
|
'inactive_at',
|
|
'deleted_at',
|
|
])
|
|
->logOnlyDirty() // Only log attributes that have been changed
|
|
->dontSubmitEmptyLogs()
|
|
->useLogName('Admin');
|
|
}
|
|
|
|
|
|
/**
|
|
* Wirechat: Returns the URL for the user's cover image (avatar).
|
|
* Adjust the 'avatar_url' field to your database setup.
|
|
*/
|
|
public function getCoverUrlAttribute(): ?string
|
|
{
|
|
return Storage::url($this->profile_photo_path) ?? null;
|
|
}
|
|
|
|
|
|
/**
|
|
* Wirechat:Returns the URL for the user's profile page.
|
|
* Adjust the 'profile' route as needed for your setup.
|
|
*/
|
|
public function getProfileUrlAttribute(): ?string
|
|
{
|
|
return route('profile.show_by_type_and_id', ['type' => __('admin'), 'id' => $this->id]);
|
|
}
|
|
|
|
|
|
/**
|
|
* Wirechat: Returns the display name for the user.
|
|
* Modify this to use your preferred name field.
|
|
*/
|
|
public function getDisplayNameAttribute(): ?string
|
|
{
|
|
if ($this->full_name !== $this->name) {
|
|
return $this->full_name . ' (' . $this->name . ')';
|
|
} elseif ($this->name) {
|
|
return $this->name;
|
|
} else {
|
|
return __('Admin');
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Wirechat: Search for users when creating a new chat or adding members to a group.
|
|
* Customize the search logic to limit results, such as restricting to friends or eligible users only.
|
|
*/
|
|
public function searchChatables(string $query): ?\Illuminate\Support\Collection
|
|
{
|
|
$searchableFields = ['name', 'full_name'];
|
|
|
|
// Search across all profile types
|
|
$users = \App\Models\User::where(function ($queryBuilder) use ($searchableFields, $query) {
|
|
foreach ($searchableFields as $field) {
|
|
$queryBuilder->orWhere($field, 'LIKE', '%'.$query.'%');
|
|
}
|
|
})->limit(6)->get();
|
|
|
|
$organizations = \App\Models\Organization::where(function ($queryBuilder) use ($searchableFields, $query) {
|
|
foreach ($searchableFields as $field) {
|
|
$queryBuilder->orWhere($field, 'LIKE', '%'.$query.'%');
|
|
}
|
|
})->limit(6)->get();
|
|
|
|
$banks = \App\Models\Bank::where(function ($queryBuilder) use ($searchableFields, $query) {
|
|
foreach ($searchableFields as $field) {
|
|
$queryBuilder->orWhere($field, 'LIKE', '%'.$query.'%');
|
|
}
|
|
})->limit(6)->get();
|
|
|
|
$admins = Admin::where(function ($queryBuilder) use ($searchableFields, $query) {
|
|
foreach ($searchableFields as $field) {
|
|
$queryBuilder->orWhere($field, 'LIKE', '%'.$query.'%');
|
|
}
|
|
})->limit(6)->get();
|
|
|
|
// Combine all results into a base Collection to avoid serialization issues
|
|
$results = collect()
|
|
->merge($users->all())
|
|
->merge($organizations->all())
|
|
->merge($banks->all())
|
|
->merge($admins->all());
|
|
|
|
// Filter out profiles based on configuration
|
|
return $results->filter(function ($profile) {
|
|
// Check inactive profiles
|
|
if (timebank_config('profile_inactive.messenger_hidden') && !$profile->isActive()) {
|
|
return false;
|
|
}
|
|
|
|
// Check email unverified profiles
|
|
if (timebank_config('profile_email_unverified.messenger_hidden') && !$profile->isEmailVerified()) {
|
|
return false;
|
|
}
|
|
|
|
// Check incomplete profiles
|
|
if (
|
|
timebank_config('profile_incomplete.messenger_hidden')
|
|
&& method_exists($profile, 'hasIncompleteProfile')
|
|
&& $profile->hasIncompleteProfile($profile)
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
})->take(6)->values();
|
|
}
|
|
|
|
|
|
/**
|
|
* Wirechat: Determine if the user can create new groups.
|
|
*/
|
|
public function canCreateGroups(): bool
|
|
{
|
|
return timebank_config('profiles.bank.messenger_can_create_groups');
|
|
}
|
|
}
|