Strimoid/Strimoid

View on GitHub
app/Models/User.php

Summary

Maintainability
B
6 hrs
Test Coverage
<?php

namespace Strimoid\Models;

use Illuminate\Auth\Authenticatable;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Foundation\Auth\Access\Authorizable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Laravel\Passport\HasApiTokens;
use Strimoid\Models\Traits\HasAvatar;

class User extends BaseModel implements AuthenticatableContract, CanResetPasswordContract, AuthorizableContract
{
    use Authenticatable, Authorizable, CanResetPassword, HasApiTokens, HasAvatar, Notifiable;

    protected string $avatarPath = 'avatars/';
    protected $table = 'users';
    protected $fillable = [
        'age', 'description', 'location', 'sex',
    ];
    protected $appends = ['avatar_url'];
    protected $visible = [
        'id', 'age', 'avatar', 'avatar_url', 'created_at',
        'description', 'location', 'sex', 'name',
    ];
    protected $casts = [
        'age' => 'integer',
        'settings' => 'array',
        'last_login' => 'datetime',
    ];

    public function getColoredName(): string
    {
        $type = $this->type ?: 'normal';

        return '<span class="user_' . $type . '">' . $this->name . '</span>';
    }

    public function getAvatarPath(int $width = null, int $height = null)
    {
        $host = config('app.cdn_host');

        // Show default avatar if user is blocked
        if (Auth::check() && Auth::user()->isBlockingUser($this)) {
            return $this->getDefaultAvatarPath();
        }

        if ($this->avatar && $width && $height) {
            return $host . '/' . $width . 'x' . $height . '/avatars/' . $this->avatar;
        }

        if ($this->avatar) {
            return $host . '/avatars/' . $this->avatar;
        }

        return $this->getDefaultAvatarPath();
    }

    public function getDefaultAvatarPath(): string
    {
        return '/i/duck/' . $this->name . '.svg';
    }

    public function getAvatarUrlAttribute(): string
    {
        return $this->getAvatarPath();
    }

    public function getSexClass(): string
    {
        if ($this->sex && in_array($this->sex, ['male', 'female'])) {
            return $this->sex;
        }

        return 'nosex';
    }

    public function setAgeAttribute($value): void
    {
        $this->attributes['age'] = $value ?: null;
    }

    public function setEmailAttribute($value): void
    {
        $lowercase = Str::lower($value);
        $this->attributes['email'] = $lowercase;
    }

    public function setPasswordAttribute($value): void
    {
        $this->attributes['password'] = bcrypt($value);
    }

    public function actions()
    {
        return $this->hasMany(UserAction::class);
    }

    public function contents()
    {
        return $this->hasMany(Content::class);
    }

    public function comments()
    {
        return $this->hasMany(Comment::class);
    }

    public function commentReplies()
    {
        return $this->hasMany(CommentReply::class);
    }

    public function entries()
    {
        return $this->hasMany(Entry::class);
    }

    public function entryReplies()
    {
        return $this->hasMany(EntryReply::class);
    }

    public function folders()
    {
        return $this->hasMany(Folder::class);
    }

    public function notifications()
    {
        return $this->belongsToMany(Notification::class, 'notification_targets')->withPivot('read');
    }

    public function settings()
    {
        return $this->hasMany(UserSetting::class);
    }

    public function bannedGroups()
    {
        return $this->belongsToMany(Group::class, 'group_bans')->withTimestamps();
    }

    public function blockedGroups()
    {
        return $this->belongsToMany(Group::class, 'user_blocked_groups')->withTimestamps();
    }

    public function subscribedGroups()
    {
        return $this->belongsToMany(Group::class, 'user_subscribed_groups')->withTimestamps();
    }

    public function moderatedGroups()
    {
        return $this->belongsToMany(Group::class, 'group_moderators')->withTimestamps()->withPivot('type');
    }

    public function blockedUsers()
    {
        return $this->belongsToMany(self::class, 'user_blocked_users', 'source_id', 'target_id')->withTimestamps();
    }

    public function followedUsers()
    {
        return $this->belongsToMany(self::class, 'user_followed_users', 'source_id', 'target_id')->withTimestamps();
    }

    public function blockedDomains(): object
    {
        return DB::table('user_blocked_domains')->where('user_id', $this->getKey())->pluck('domain');
    }

    public function isBanned(Group $group): bool
    {
        return $this->bannedGroups()->where('group_id', $group->id)->exists();
    }

    public function isSuperAdmin(): bool
    {
        return $this->type === 'admin';
    }

    public function isAdmin($group): bool
    {
        if ($group instanceof Group) {
            $group = $group->getKey();
        }

        return $this->moderatedGroups()
            ->where('group_id', $group)
            ->where('group_moderators.type', 'admin')
            ->exists();
    }

    public function isModerator($group): bool
    {
        if ($group instanceof Group) {
            $group = $group->getKey();
        }

        $cacheTags = ['users.moderated-groups', 'u.' . auth()->id()];
        $moderatedGroupsIds = $this->moderatedGroups()->remember(60)->cacheTags($cacheTags)->pluck('groups.id');

        return $moderatedGroupsIds->contains($group);
    }

    public function isSubscriber($group): bool
    {
        if ($group instanceof Group) {
            $group = $group->getKey();
        }

        $cacheTags = ['users.subscribed-groups', 'u.' . auth()->id()];
        $subscribedGroupsIds = $this->subscribedGroups()->remember(60)->cacheTags($cacheTags)->pluck('id');

        return $subscribedGroupsIds->contains($group);
    }

    public function isBlocking($group): bool
    {
        if ($group instanceof Group) {
            $group = $group->getKey();
        }

        $cacheTags = ['users.blocked-groups', 'u.' . auth()->id()];
        $blockedGroupsIds = $this->blockedGroups()->remember(60)->cacheTags($cacheTags)->pluck('id');

        return $blockedGroupsIds->contains($group);
    }

    public function isObservingUser($user): bool
    {
        return false;
    }

    public function isBlockingUser($user): bool
    {
        if ($user instanceof self) {
            $user = $user->getKey();
        }

        $cacheTags = ['users.blocked-users', 'u.' . auth()->id()];
        $blockedUsersIds = $this->blockedUsers()->remember(60)->cacheTags($cacheTags)->pluck('id');

        return $blockedUsersIds->contains($user);
    }

    public function getRouteKey(): string
    {
        return $this->name;
    }

    public function scopeName($query, $value): void
    {
        $query->where('name', $value);
    }
}