Files
wticreatorstudio/Modules/Chat/Repositories/UserRepository.php
T
2024-02-12 22:54:20 -05:00

587 lines
21 KiB
PHP

<?php
namespace Modules\Chat\Repositories;
use App;
use App\Events\UpdatesEvent;
use App\Exceptions\ApiOperationFailedException;
use Modules\Chat\Entities\ArchivedUser;
use Modules\Chat\Entities\BlockedUser;
use Modules\Chat\Entities\ChatRequestModel;
use Modules\Chat\Entities\Conversation;
use Modules\Chat\Entities\Group;
use Modules\Chat\Entities\GroupMessageRecipient;
use Modules\Chat\Entities\GroupUser;
use Modules\Chat\Entities\LastConversation;
use Modules\Chat\Entities\MessageAction;
use Modules\Chat\Entities\Notification;
use Modules\Chat\Entities\ReportedUser;
use Modules\Chat\Entities\Role;
use Modules\Chat\Entities\SocialAccount;
use Modules\Chat\Entities\User;
use Modules\Chat\Entities\UserStatus;
use App\Traits\ImageTrait;
use Auth;
use Carbon\Carbon;
use DB;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Query\JoinClause;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
class UserRepository extends BaseRepository
{
/**
* @var array
*/
protected $fieldSearchable = [
'name', 'email', 'phone', 'last_seen', 'about', 'photo', 'is_online',
];
/**
* Return searchable fields.
*
* @return array
*/
public function getFieldsSearchable()
{
return $this->fieldSearchable;
}
/**
* Configure the Model.
**/
public function model()
{
return User::class;
}
/**
* @param array $input
*
* @return User
*/
public function store($input)
{
/** @var AccountRepository $accountRepo */
$accountRepo = App::make(AccountRepository::class);
try {
$input['email_verified_at'] = Carbon::now();
/** @var User $user */
$user = User::create($input);
$this->assignRoles($user, $input);
$this->updateProfilePhoto($user, $input);
$activateCode = $accountRepo->generateUserActivationToken($user->id);
if (! $user->is_active) {
$accountRepo->sendConfirmEmail($user->name, $user->email, $activateCode);
}
return $user;
} catch (Exception $e) {
throw new UnprocessableEntityHttpException($e->getMessage());
}
}
/**
* @param array $input
* @param int $id
*
* @return User
*/
public function update($input, $id)
{
/** @var User $user */
$user = User::findOrFail($id);
try {
$user->update($input);
$this->assignRoles($user, $input);
$this->updateProfilePhoto($user, $input);
return $user;
} catch (Exception $e) {
throw new UnprocessableEntityHttpException($e->getMessage());
}
}
/**
* @param int $id
* @param array $input
*
* @return array
*/
public function getConversation($id, $input)
{
$orderBy = 'desc';
$user = $firstUnreadMessage = $lastUnreadMsg = null;
$group = $lastConversation = null;
$isGroup = (isset($input['is_group'])) ? $input['is_group'] : 0;
$authUser = getLoggedInUser();
$limit = 30;
$chatRequest = null;
$authId = getLoggedInUserId();
if ($isGroup) {
// TODO : will use this later to load only unread messages
$unreadCount = GroupMessageRecipient::whereNull('read_at')
->orderBy('conversation_id', 'asc')
->where('group_id', $id)
->where('user_id', Auth::id())
->count();
$firstUnreadMessage = GroupMessageRecipient::whereNull('read_at')
->orderBy('conversation_id', 'asc')
->where('group_id', $id)
->where('user_id', Auth::id())
->first(['conversation_id', 'id']);
$limit = ($unreadCount == 0) ? 100 : $limit;
if ($unreadCount != 0 && $unreadCount < 20) {
// load last 50 unread messages
$firstUnreadMessage = GroupMessageRecipient::where('conversation_id', '<=',
$firstUnreadMessage->conversation_id)
->orderBy('conversation_id', 'desc')
->where('group_id', $id)
->where('user_id', Auth::id())
->limit(50)
->offset(20)
->first(['conversation_id']);
}
/** @var Group $group */
$group = Group::with([
'users.userStatus', 'users.roles', 'usersWithTrashed', 'lastConversations', 'createdByUser',
])->find($id);
$group->append('group_created_by');
$group->users;
if (empty($group)) {
throw new BadRequestHttpException('Group not found.');
}
if ($group->removed_from_group) {
$id = $group->id;
$lastConversation = $group->lastConversations->keyBy('user_id');
if (isset($lastConversation[getLoggedInUserId()])) {
$lastConversation = $lastConversation[getLoggedInUserId()];
$group = $lastConversation->group_details;
}
}
} else {
/** @var User $user */
$user = User::with(['roles', 'userStatus', 'reportedUser'])->find($id);
if (empty($user)) {
throw new BadRequestHttpException('User not found.');
}
$isPrivateAccount = ($user->privacy == 0) ? true : false;
$isSuperAdmin = $user->hasRole(Role::ADMIN_ROLE_NAME);
$isMyContact = $this->checkIsMyContact($id);
$isReqSendReceive = ($isMyContact) ? false : true;
if (! $isMyContact) {
$chatRequest = $this->checkIsRequestSendOrReceive($id);
$isReqSendReceive = ! empty($chatRequest) ? true : false;
}
$commonGroups = Group::with(['users' => function ($q) use ($authUser) {
$q->select(['users.name', 'users.id']);
}])->whereHas('users', function ($q) use ($id, $authUser) {
return $q->whereIn('users.id', [$id, $authUser->id]);
}, '>=', 2)
->get()->toArray();
$user = $user->toArray();
/** @var BlockedUser $isBlocked */
$blockedUser = BlockedUser::whereBlockedBy($authUser->id)->whereBlockedTo($user['id'])
->orWhere(function (Builder $query) use ($user, $authUser) {
$query->where('blocked_by', $user['id'])->where('blocked_to', $authUser->id);
})->get()->keyBy('blocked_by');
$isBlockedByAuthUser = false;
if (! empty($blockedUser) && isset($blockedUser[Auth::id()])) {
$isBlockedByAuthUser = true;
}
$user['is_blocked_by_auth_user'] = $isBlockedByAuthUser;
$user['is_blocked'] = (! $blockedUser->isEmpty()) ? true : false;
$user['is_super_admin'] = $isSuperAdmin;
$user['is_my_contact'] = $isMyContact;
$user['is_req_send_receive'] = $isReqSendReceive;
$user['is_private_account'] = $isPrivateAccount;
$user['common_groups'] = $commonGroups;
}
$allMedia = [];
if (isset($input['before']) && empty($input['before'])) {
return ['user' => $user, 'group' => $group, 'conversations' => [], 'media' => $allMedia];
}
if (isset($input['after']) && empty($input['after'])) {
return ['user' => $user, 'group' => $group, 'conversations' => [], 'media' => $allMedia];
}
$query = Conversation::with(['replyMessage.sender']);
$query->whereDoesntHave('messageAction');
if ($isGroup) {
$query->leftJoin('group_message_recipients as gmr', function (JoinClause $join) use ($authId) {
$join->on('gmr.user_id', '=', DB::raw("$authId"));
$join->on('gmr.conversation_id', '=', 'conversations.id');
})
->leftJoin('users as u', 'u.id', '=', 'conversations.from_id')
->whereNull('u.deleted_at')
->withCount('readByAll')
->selectRaw(
"conversations.*, CASE WHEN gmr.read_at IS NULL and gmr.user_id = $authId THEN 0 ELSE 1 END as status");
$query->where('conversations.to_type', '=', Group::class)
->where('to_id', '=', $id);
if (! empty($lastConversation)) {
$query->where('conversations.id', '<=', $lastConversation->conversation_id);
}
$query->with(['sender', 'receiver', 'readBy']);
} else {
$query->where(function (Builder $q) use ($authUser, $id) {
$q->where(function (Builder $q) use ($authUser, $id) {
$q->where('from_id', '=', $authUser->id)->where('to_id', '=', $id);
})->orWhere(function (Builder $q) use ($authUser, $id) {
$q->where('from_id', '=', $id)->where('to_id', '=', $authUser->id);
});
});
$query->where('conversations.to_type', '=', Conversation::class);
$query->with(['sender', 'receiver']);
}
$mediaQuery = clone $query;
$countQuery = clone $query;
$unreadCount = $countQuery->where('conversations.status', '=', 0)->where('to_id', '=', getLoggedInUserId())->count();
if (! isset($input['before']) && ! isset($input['after'])) {
$allMedia = $mediaQuery->whereIn('message_type', Conversation::MEDIA_MESSAGE_TYPES
)->get(['conversations.*']);
}
$needToReverse = false;
if (isset($input['before']) && ! empty($input['before'])) {
$query->where('conversations.id', '<', $input['before']);
} elseif (isset($input['after']) && ! empty($input['after'])) {
$query->where('conversations.id', '>', $input['after']);
$orderBy = 'ASC';
} elseif ($unreadCount > $limit) {
$query->where('status', '=', 0);
$orderBy = 'ASC';
$needToReverse = true;
}
if (! empty($firstUnreadMessage) && ! isset($input['before']) && ! isset($input['after'])) {
$orderBy = 'ASC';
$needToReverse = true;
$query->where('conversations.id', '>=', $firstUnreadMessage->conversation_id);
}
$query->limit($limit);
$query->orderBy('conversations.id', $orderBy);
$messages = $query->get(['conversations.*'])->toArray();
$messages = ($needToReverse) ? array_reverse($messages) : $messages;
/** @var NotificationRepository $notificationRepo */
$notificationRepo = app(NotificationRepository::class);
$notificationRepo->readNotificationWhenOpenChatWindow($id);
return [
'user' => $user, 'group' => $group, 'conversations' => $messages, 'media' => $allMedia,
'chat_request' => $chatRequest,
];
}
/**
* @param array $input
*
* @throws ApiOperationFailedException
*
* @return bool|void
*/
public function updateProfile($input)
{
/** @var User $user */
$user = Auth::user();
if (empty($user)) {
throw new BadRequestHttpException('User not found.');
}
$this->updateProfilePhoto($user, $input);
return true;
}
public function updateProfilePhoto(User $user, $input)
{
try {
$options = ['height' => User::HEIGHT, 'width' => User::WIDTH];
if (! empty($input['photo'])) {
$input['photo'] = ImageTrait::makeImage($input['photo'], User::$PATH, $options);
$oldImageName = $user->photo;
if (! empty($oldImageName)) {
$user->deleteImage();
}
}
$input['is_subscribed'] = isset($input['is_subscribed']) ? 1 : 0;
$user->update($input);
$broadcastData['type'] = User::PROFILE_UPDATES;
$broadcastData['user'] = $user->fresh()->toArray();
broadcast(new UpdatesEvent($broadcastData))->toOthers();
} catch (Exception $e) {
throw new ApiOperationFailedException($e->getMessage());
}
}
/**
* @param $user
* @param $input
*
* @return bool
*/
public function assignRoles($user, $input)
{
$roles = ! empty($input['role_id']) ? $input['role_id'] : [];
/** @var User $user */
$user->roles()->sync($roles);
return true;
}
/**
* @param int $id
*
* @return User
*/
public function activeDeActiveUser($id)
{
/** @var User $user */
$user = User::findOrFail($id);
$user->update(['is_active' => !$user->is_active]);
return $user;
}
/**
* @param array $input
*
* @return bool
*/
public function storeAndUpdateNotification($input)
{
/** @var User $user */
$user = Auth::user();
$user->update($input);
return true;
}
/**
* @param $input
*
* @return UserStatus|Builder|Model|object|null
*/
public function setUserCustomStatus($input)
{
$input['user_id'] = getLoggedInUserId();
$input['emoji'] = str_replace($input['emoji_short_name'], '', $input['emoji']);
$userStatus = UserStatus::where('user_id', '=', getLoggedInUserId())->first();
if (! empty($userStatus)) {
$userStatus->update($input);
} else {
$userStatus = UserStatus::create($input);
}
$broadcastData['type'] = User::STATUS_UPDATE;
$broadcastData['user_status'] = [
'user_id' => $userStatus->user_id,
'emoji' => $userStatus->emoji,
'status' => $userStatus->status,
];
broadcast(new UpdatesEvent($broadcastData))->toOthers();
return $userStatus;
}
/**
* @throws Exception
*/
public function clearUserCustomStatus()
{
UserStatus::whereUserId(getLoggedInUserId())->delete();
$broadcastData['type'] = User::STATUS_CLEAR;
$broadcastData['user_id'] = getLoggedInUserId();
broadcast(new UpdatesEvent($broadcastData))->toOthers();
}
/**
* @return array
*/
public function myContactIds()
{
$authId = getLoggedInUserId();
$records = ChatRequestModel::whereOwnerType(User::class)
->where(function (Builder $query) use ($authId) {
$query->where('from_id', '=', $authId)
->orWhere('owner_id', '=', $authId);
})
->get(DB::raw("IF(from_id=$authId, owner_id, from_id) as my_contact_id, status"))
->groupBy('status');
$myContactIds = (isset($records[ChatRequestModel::STATUS_ACCEPTED])) ?
$records[ChatRequestModel::STATUS_ACCEPTED]->pluck('my_contact_id')->toArray() :
[];
$declinedIds = (isset($records[ChatRequestModel::STATUS_DECLINE])) ?
$records[ChatRequestModel::STATUS_DECLINE]->pluck('my_contact_id')->toArray() :
[];
$pendingIds = (isset($records[ChatRequestModel::STATUS_PENDING])) ?
$records[ChatRequestModel::STATUS_PENDING]->pluck('my_contact_id')->toArray() :
[];
$myPendingRequestIds = array_merge($declinedIds, $pendingIds);
$conversationUserIds = Conversation::whereToType(Conversation::class)
->where(function (Builder $query) use ($authId) {
$query->where('from_id', '=', $authId)
->orWhere('to_id', '=', $authId);
})
->toBase()
->get(DB::raw("IF(from_id=$authId, to_id, from_id) as my_contact_id"))
->pluck('my_contact_id')
->toArray();
$conversationUserIds = array_unique($conversationUserIds);
$myContactIds = array_unique(array_merge($myContactIds, $conversationUserIds));
$myContactIds = array_diff($myContactIds, $myPendingRequestIds);
return array_unique($myContactIds);
}
/**
* @return array
*/
public function myPendingRequest()
{
$authId = getLoggedInUserId();
$myContactIds = ChatRequestModel::whereIn('status',
[ChatRequestModel::STATUS_PENDING, ChatRequestModel::STATUS_DECLINE])
->whereOwnerType(User::class)
->where(function (Builder $query) use ($authId) {
$query->where('from_id', '=', $authId)
->orWhere('owner_id', '=', $authId);
})
->get(DB::raw("IF(from_id=$authId, owner_id, from_id) as my_contact_id"))
->pluck('my_contact_id')
->toArray();
return array_unique($myContactIds);
}
/**
* @param int $userId
*
* @return bool
*/
public function checkIsMyContact($userId)
{
$myContactIds = $this->myContactIds();
return in_array($userId, $myContactIds) ? true : false;
}
/**
* @param $userId
*
* @return ChatRequestModel|Builder|Model|\Illuminate\Database\Query\Builder|object|null
*/
public function checkIsRequestSendOrReceive($userId)
{
$authId = getLoggedInUserId();
return ChatRequestModel::whereOwnerType(User::class)
->whereIn('status', [ChatRequestModel::STATUS_PENDING, ChatRequestModel::STATUS_DECLINE])
->where(function (Builder $query) use ($authId, $userId) {
$query->where(function (Builder $q) use ($authId, $userId) {
$q->where('from_id', '=', $authId)
->where('owner_id', '=', $userId);
})->orWhere(function (Builder $q) use ($authId, $userId) {
$q->where('owner_id', '=', $authId)
->where('from_id', '=', $userId);
});
})->first();
}
/**
* @param int $userId
*
* @throws Exception
*/
public function deleteUser($userId)
{
try {
DB::beginTransaction();
ArchivedUser::whereArchivedBy($userId)->orWhere(function (Builder $q) use ($userId) {
$q->where('owner_id', '=', $userId)
->where('owner_type', '=', User::class);
})->delete();
BlockedUser::whereBlockedBy($userId)->orWhere('blocked_to', '=', $userId)->delete();
ChatRequestModel::whereFromId($userId)->orWhere(function (Builder $q) use ($userId) {
$q->where('owner_id', '=', $userId)
->where('owner_type', '=', User::class);
})->delete();
Conversation::whereFromId($userId)->orWhere('to_id', '=', $userId)->delete();
MessageAction::whereDeletedBy($userId)->delete();
Notification::whereOwnerId($userId)->whereOwnerType(User::class)->forceDelete();
GroupUser::whereUserId($userId)->forceDelete();
GroupMessageRecipient::whereUserId($userId)->delete();
LastConversation::whereUserId($userId)->delete();
ReportedUser::whereReportedTo($userId)->orWhere('reported_by', '=', $userId)->delete();
UserStatus::whereUserId($userId)->delete();
SocialAccount::whereUserId($userId)->delete();
User::withTrashed()->whereId($userId)->first()->forceDelete();
DB::commit();
} catch (Exception $exception) {
DB::rollBack();
throw new Exception($exception->getMessage(), $exception->getCode());
}
}
/**
* @param int $userId
*/
public function restore($userId)
{
$user = User::withTrashed()->whereId($userId)->first();
if ($user->is_system) {
throw new UnprocessableEntityHttpException('You can not update system generated user.');
}
$user->restore();
}
/**
* @param int $userId
*
* @return bool
*/
public function checkUserItSelf($userId)
{
if ($userId == getLoggedInUserId()) {
throw new UnprocessableEntityHttpException('You can not update yourself');
}
return false;
}
}