mirror of https://github.com/movim/movim
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
378 lines
10 KiB
378 lines
10 KiB
<?php
|
|
|
|
namespace App;
|
|
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use App\Contact;
|
|
use App\Configuration;
|
|
use App\Session as AppSession;
|
|
use Illuminate\Database\Capsule\Manager as DB;
|
|
|
|
class User extends Model
|
|
{
|
|
protected $fillable = [
|
|
'id',
|
|
'language',
|
|
'nightmode',
|
|
'chatmain',
|
|
'nsfw',
|
|
'nickname',
|
|
'notificationchat',
|
|
'notificationcall',
|
|
'omemoenabled',
|
|
'accentcolor',
|
|
'posts_since'
|
|
];
|
|
public $with = ['session', 'capability'];
|
|
protected $keyType = 'string';
|
|
public $incrementing = false;
|
|
private $unreads = null;
|
|
|
|
private $blockListInitialized = false;
|
|
private $userBlocked = [];
|
|
private $globalBlocked = [];
|
|
|
|
protected $casts = [
|
|
'posts_since' => 'datetime:Y-m-d H:i:s',
|
|
'notifications_since' => 'datetime:Y-m-d H:i:s',
|
|
];
|
|
|
|
public const ACCENT_COLORS = ['red', 'pink', 'purple', 'dpurple', 'indigo', 'blue', 'cyan', 'teal', 'green', 'lgreen', 'orange', 'dorange'];
|
|
|
|
public function session()
|
|
{
|
|
return $this->hasOne(AppSession::class);
|
|
}
|
|
|
|
public function contact()
|
|
{
|
|
return $this->hasOne(Contact::class, 'id');
|
|
}
|
|
|
|
public function capability()
|
|
{
|
|
return $this->hasOne(Info::class, 'server', 'id')->where('node', '');
|
|
}
|
|
|
|
public function messages()
|
|
{
|
|
return $this->hasMany(Message::class);
|
|
}
|
|
|
|
public function getLastMessage(string $to, bool $muc = false): ?Message
|
|
{
|
|
$m = null;
|
|
|
|
if ($muc) {
|
|
// Resolve the current presence
|
|
$presence = $this->session->presences()
|
|
->where('jid', $to)
|
|
->where('muc', true)
|
|
->where('mucjid', $this->id)
|
|
->first();
|
|
|
|
if ($presence) {
|
|
$m = $this->messages()
|
|
->where('type', 'groupchat')
|
|
->where('jidfrom', $to)
|
|
->where('jidto', $this->id)
|
|
->where('resource', $presence->resource)
|
|
->orderBy('published', 'desc')
|
|
->first();
|
|
}
|
|
} else {
|
|
$m = $this->messages()
|
|
->where('jidto', $to)
|
|
->orderBy('published', 'desc')
|
|
->first();
|
|
}
|
|
|
|
return $m;
|
|
}
|
|
|
|
public function stories()
|
|
{
|
|
return Post::myStories($this);
|
|
}
|
|
|
|
public function rosterStories(Roster $roster)
|
|
{
|
|
return $this->stories()->where('server', $roster->jid);
|
|
}
|
|
|
|
public function rosterFirstUnseenStory(Roster $roster): ?Post
|
|
{
|
|
return $this->rosterStories($roster)->whereNotIn('id', function ($query) {
|
|
$query->select('post_id')
|
|
->from('post_user_views')
|
|
->where('user_id', $this->id);
|
|
})->first();
|
|
}
|
|
|
|
public function rosterStoriesAllSeen(Roster $roster): bool
|
|
{
|
|
return !$this->rosterStories($roster)->whereNotIn('id', function ($query) {
|
|
$query->select('post_id')
|
|
->from('post_user_views')
|
|
->where('user_id', $this->id);
|
|
})->exists();
|
|
}
|
|
|
|
public function MAMEarliests()
|
|
{
|
|
return $this->hasMany(MAMEarliest::class);
|
|
}
|
|
|
|
public function openChats()
|
|
{
|
|
return $this->hasMany(OpenChat::class);
|
|
}
|
|
|
|
public function drafts()
|
|
{
|
|
return $this->hasMany(Draft::class);
|
|
}
|
|
|
|
public function pushSubscriptions()
|
|
{
|
|
return $this->hasMany(PushSubscription::class);
|
|
}
|
|
|
|
public function reported()
|
|
{
|
|
return $this->belongsToMany(Reported::class)->withTimestamps();
|
|
}
|
|
|
|
public function postViews()
|
|
{
|
|
return $this->belongsToMany(User::class, 'post_user_views', 'user_id', 'post_id')->withTimestamps();
|
|
}
|
|
|
|
public function emojis()
|
|
{
|
|
return $this->belongsToMany(Emoji::class)->withPivot('alias')->withTimestamps();
|
|
}
|
|
|
|
public function getUsernameAttribute()
|
|
{
|
|
return $this->contact && $this->contact->nickname
|
|
? $this->contact->nickname
|
|
: $this->session->username;
|
|
}
|
|
|
|
public function getResolvedNicknameAttribute()
|
|
{
|
|
return $this->nickname ?? $this->id;
|
|
}
|
|
|
|
public function unreads(?string $jid = null, bool $quoted = false, ?array $space = null, bool $cached = false): int
|
|
{
|
|
if ($this->unreads !== null && $cached) return $this->unreads;
|
|
|
|
$union = DB::table('messages')
|
|
->where('user_id', $this->id)
|
|
->where('seen', false)
|
|
->whereIn('type', ['chat', 'headline', 'invitation', 'space_pending']);
|
|
|
|
$union = ($jid != null)
|
|
? $union->where('jidfrom', $jid)
|
|
: $union->where('jidfrom', '!=', $this->id);
|
|
|
|
$unreads = $this->messages()
|
|
->where('seen', false)
|
|
->where('jidfrom', '!=', $this->id)
|
|
->where(function ($query) use ($quoted, $space) {
|
|
$query->where('type', 'groupchat')
|
|
->whereNull('subject')
|
|
->whereIn('jidfrom', function ($query) use ($space) {
|
|
$query->select('conference')
|
|
->from('conferences')
|
|
->where('session_id', function ($query) {
|
|
$query->select('id')
|
|
->from('sessions')
|
|
->where('user_id', $this->id);
|
|
})
|
|
->where('space_server', $space ? $space[0] : null)
|
|
->where('space_node', $space ? $space[1] : null);
|
|
});
|
|
|
|
if ($quoted) {
|
|
$query->where('quoted', true);
|
|
}
|
|
});
|
|
|
|
if ($space == null) $unreads = $unreads->unionAll($union);
|
|
|
|
$unreads = ($jid != null)
|
|
? $unreads->where('jidfrom', $jid)
|
|
: $unreads->distinct('jidfrom');
|
|
|
|
$unreads = $unreads->count();
|
|
|
|
if ($jid == null) {
|
|
$this->unreads = $unreads;
|
|
}
|
|
|
|
return $unreads;
|
|
}
|
|
|
|
public function encryptedPasswords()
|
|
{
|
|
return $this->hasMany(EncryptedPassword::class);
|
|
}
|
|
|
|
public function subscriptions()
|
|
{
|
|
return $this->hasMany(Subscription::class, 'jid', 'id');
|
|
}
|
|
|
|
public function affiliations()
|
|
{
|
|
return $this->hasMany(Affiliation::class, 'jid', 'id');
|
|
}
|
|
|
|
public function init()
|
|
{
|
|
$contact = Contact::firstOrNew(['id' => $this->id]);
|
|
$contact->save();
|
|
}
|
|
|
|
public function setConfig(array $config)
|
|
{
|
|
if (isset($config['language'])) {
|
|
$this->language = (string)$config['language'];
|
|
}
|
|
|
|
if (isset($config['accentcolor']) && in_array($config['accentcolor'], User::ACCENT_COLORS)) {
|
|
$this->accentcolor = (string)$config['accentcolor'];
|
|
}
|
|
|
|
if (isset($config['nsfw'])) {
|
|
$this->nsfw = (bool)$config['nsfw'];
|
|
}
|
|
|
|
if (isset($config['omemoenabled'])) {
|
|
$this->omemoenabled = (bool)$config['omemoenabled'];
|
|
}
|
|
|
|
if (isset($config['chatmain'])) {
|
|
$this->chatmain = (bool)$config['chatmain'];
|
|
}
|
|
|
|
if (isset($config['nightmode'])) {
|
|
$this->nightmode = (bool)$config['nightmode'];
|
|
}
|
|
|
|
if (isset($config['notificationcall'])) {
|
|
$this->notificationcall = (bool)$config['notificationcall'];
|
|
}
|
|
|
|
if (isset($config['notificationchat'])) {
|
|
$this->notificationchat = (bool)$config['notificationchat'];
|
|
}
|
|
}
|
|
|
|
public function isRestricted(): bool
|
|
{
|
|
return \App\Configuration::get()->restrictsuggestions;
|
|
}
|
|
|
|
public function hasRegister(): bool
|
|
{
|
|
$rootInfo = Info::where('server', explodeJid($this->attributes['id'])['server'])
|
|
->where('node', '')
|
|
->first();
|
|
|
|
if ($rootInfo) {
|
|
return $rootInfo->hasFeature('jabber:iq:register');
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public function hasMAM(): bool
|
|
{
|
|
return ($this->capability && $this->capability->hasFeature('urn:xmpp:mam:2'));
|
|
}
|
|
|
|
public function hasBookmarksConvertion(): bool
|
|
{
|
|
return ($this->capability && $this->capability->hasFeature('urn:xmpp:bookmarks:1#compat'));
|
|
}
|
|
|
|
public function hasOMEMO(): bool
|
|
{
|
|
return (bool)$this->omemoenabled;
|
|
}
|
|
|
|
public function hasPubsub(bool $withChatOnlyDisabled = true)
|
|
{
|
|
$hasPubsub = ($this->capability
|
|
&& $this->capability->hasFeature('http://jabber.org/protocol/pubsub#persistent-items')
|
|
&& ($this->capability->hasFeature('http://jabber.org/protocol/pubsub#multi-items')
|
|
|| ($this->session->serverCapability
|
|
&& $this->session->serverCapability->hasFeature('http://jabber.org/protocol/pubsub#multi-items')
|
|
)
|
|
)
|
|
);
|
|
|
|
if ($withChatOnlyDisabled) {
|
|
return ($hasPubsub && !Configuration::get()->chatonly);
|
|
}
|
|
|
|
return $hasPubsub;
|
|
}
|
|
|
|
public function hasSocialFeatures(): bool
|
|
{
|
|
$configuration = Configuration::get();
|
|
return (!$configuration->chatonly);
|
|
}
|
|
|
|
public function hasUpload(): bool
|
|
{
|
|
return ($this->session && $this->session->getUploadService());
|
|
}
|
|
|
|
public function hasSpaces(): bool
|
|
{
|
|
return ($this->session && $this->session->getSpacesService());
|
|
}
|
|
|
|
public function setPublic()
|
|
{
|
|
$this->attributes['public'] = true;
|
|
$this->save();
|
|
}
|
|
|
|
public function setPrivate()
|
|
{
|
|
$this->attributes['public'] = false;
|
|
$this->save();
|
|
}
|
|
|
|
public function refreshBlocked()
|
|
{
|
|
$this->blockListInitialized = true;
|
|
$this->userBlocked = (array)$this->reported()->get()->pluck('id')->toArray();
|
|
$this->globalBlocked = (array)Reported::where('blocked', true)->get()->pluck('id')->toArray();
|
|
}
|
|
|
|
public function hasBlocked(string $jid, bool $localOnly = false): bool
|
|
{
|
|
if ($this->blockListInitialized == false) {
|
|
$this->refreshBlocked();
|
|
}
|
|
|
|
if ($localOnly) {
|
|
return in_array($jid, $this->userBlocked);
|
|
}
|
|
|
|
return in_array($jid, $this->userBlocked) || in_array($jid, $this->globalBlocked);
|
|
}
|
|
|
|
public function isBlocked(Contact $contact): bool
|
|
{
|
|
return $this->hasBlocked($contact->id, true);
|
|
}
|
|
}
|