Uploaded From CV. Swandhana Server
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
|
||||
/vendor
|
||||
composer.lock
|
||||
Vendored
+245
@@ -0,0 +1,245 @@
|
||||
# Change log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## v1.6.3 (2024-03-17)
|
||||
|
||||
### Added
|
||||
|
||||
- Support for a custom routes.
|
||||
|
||||
## v1.6.2 (2023-07-27)
|
||||
|
||||
### Added
|
||||
|
||||
- Support for a custom WS server #291.
|
||||
|
||||
## v1.6.1 (2023-03-03)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Migration files issue (Cannot redeclare class...).
|
||||
|
||||
## v1.6.0 (2023-03-03)
|
||||
|
||||
### Added
|
||||
|
||||
- Emoji's support.
|
||||
- Css variables.
|
||||
- Notification sounds.
|
||||
- Auto-time updates.
|
||||
|
||||
### Changed
|
||||
|
||||
- Using UUIDs instead of random IDs on table primary column #243.
|
||||
- UI/UX changes and enhancements.
|
||||
- Code refactored (part of it).
|
||||
- Messenger primary color fallback.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fetching messages multiple times at once on send/fetch requests.
|
||||
- Migrations duplicate class name.
|
||||
- Prevent chat for invalid user ids #246
|
||||
- Fix responsiveness when going to chat with specific ID #247.
|
||||
- App URL should be changed when click the `back to contacts` button on small screens.
|
||||
- Internet connection UI.
|
||||
- Prevent Users from updating each others statuses #254
|
||||
- Contact list realtime updates issues.
|
||||
- Delete messages issues.
|
||||
- Fix contact list error `Malformed UTF-8 characters, possibly incorrectly encoded`
|
||||
- Search multiple request on typing, debouncing used.
|
||||
|
||||
## v1.5.6 (2023-01-26)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Keyboard overlaping on input issue on mobile #202.
|
||||
- Security issue and code enhancements #240.
|
||||
|
||||
## v1.5.5 (2023-01-21)
|
||||
|
||||
### Fixed
|
||||
|
||||
- message delete event channel #238.
|
||||
|
||||
## v1.5.4 (2022-12-05)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Channels auth secutiy issue #29
|
||||
|
||||
## v1.5.3 (2022-12-04)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Channels Secutiy issue #29
|
||||
|
||||
## v1.5.2 (2022-07-08)
|
||||
|
||||
### Fixed
|
||||
|
||||
- MessageCard & fetchMessage methods@`ChatifyMessenger.php` fallback.
|
||||
|
||||
## v1.5.1 (2022-06-09)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Sync the `sending a message form`'s allowed files/images with the `config` file (Update sendForm.blade.php [#190](https://github.com/munafio/chatify/pull/190))
|
||||
|
||||
## v1.5.0 (2022-06-08)
|
||||
|
||||
### Added
|
||||
|
||||
- Page/Document visibility Support which improves (seen) feature #183
|
||||
|
||||
### Fixed
|
||||
|
||||
- fix: case insensitive file upload extension check #182
|
||||
|
||||
## v1.4.0 (2022-05-02)
|
||||
|
||||
### Added
|
||||
|
||||
- [Gravatar](https:://gravatar.com) support (optional, can be changed at config/chatify.php).
|
||||
- Delete Message by ID.
|
||||
- Laravel's Storage disk now supported and can be changed from the config.
|
||||
|
||||
### Changed
|
||||
|
||||
- File upload (user avatar & attachments) `allowed files` and `max size` now can be changed from one place which is (config/chatify.php).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Bugs and UI/UX design fixes/improvements.
|
||||
|
||||
## v1.3.4 (2022-02-04)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed Installing errors on the migrations step. #163
|
||||
|
||||
## v1.3.3 (2022-01-10)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed file upload size limit error message rephrase #160.
|
||||
|
||||
### Changed
|
||||
|
||||
- Files max upload size changed & added to the config to be customizable.
|
||||
- Changed `Messenger colors` logic to be more flexible and customizable.
|
||||
- Migration files renamed, file date automatically will be changed to the publish/install date.
|
||||
|
||||
## v1.3.2 (2022-01-07)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed CSS issue in FF with the contact list #157.
|
||||
- Correct misspelt of `updateContactItem` method (typo error) #159.
|
||||
|
||||
## v1.3.1 (2021-12-23)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed migration's rollback, (ch\_) prefix added.
|
||||
|
||||
## v1.3.0 (2021-11-30)
|
||||
|
||||
### Fixed
|
||||
|
||||
- UI/Ux fixes & improvements.
|
||||
- Backend fixes & improvements.
|
||||
|
||||
### Added
|
||||
|
||||
- Messages, Contacts, and Search pagination.
|
||||
- API routes.
|
||||
|
||||
## v1.2.5 (2021-08-18)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed a security issue on uploaded file-name, which is vulnerable with XSS.
|
||||
|
||||
## v1.2.4 (2021-07-15)
|
||||
|
||||
### Fixed
|
||||
|
||||
- README updates.
|
||||
- Install Command fixes & improvements.
|
||||
- Contact list visible onLoad.
|
||||
- Settings’ modal responsive design.
|
||||
|
||||
### Added
|
||||
|
||||
- UPGRADE.md added.
|
||||
- Publish command added.
|
||||
- Package.json additions & modifications.
|
||||
|
||||
## v1.2.3 - (2021-06-19)
|
||||
|
||||
### Fixed
|
||||
|
||||
- XSS issue on inputs.
|
||||
- UI/UX fixes & improvements.
|
||||
- Send message fixes (UI & backend).
|
||||
- Update Profile Settings (upload file & error handling ….).
|
||||
- Shared photos not working issue.
|
||||
- Typo error fixes (Your `contatc` list is empty).
|
||||
- Rolling back migrations added.
|
||||
- Get Last message `orderBy` query duplication.
|
||||
|
||||
## v1.2.2 - (2021-06-01)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Migrate to database command removed.
|
||||
- Publishable asset `assets` avatar config issue.
|
||||
- Pusher encryption key option removed.
|
||||
- Settings button on click not working issue.
|
||||
|
||||
## v1.2.1 - (2021-05-30)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Publishable asset `assets`.
|
||||
|
||||
## v1.2.0 - (2021-05-30)
|
||||
|
||||
### FIxed
|
||||
|
||||
- Security issues.
|
||||
- UI/UX issues.
|
||||
- Route [home] not defiend.
|
||||
- `$msg->attachment` issue #9.
|
||||
- Delete conversation issue #89.
|
||||
|
||||
### Added
|
||||
|
||||
- Console commands.
|
||||
- `Models` added to assets to be published.
|
||||
- Laravel 8+ support.
|
||||
|
||||
### Changed
|
||||
|
||||
- Project structure.
|
||||
- composer updated `pusher/pusher-php-server` to v^7.0.
|
||||
- Models & Migrations' tables names changed (added `ch` prefix to avoid duplication) solves issue #68.
|
||||
- Models changed to (`ChMessage`, `ChFavorite`)
|
||||
- Migrations' tables names (`ch_messages`, `ch_favorites`)
|
||||
- Configuration file `config/chatify.php`.
|
||||
|
||||
## v1.0.1 - (2020-09-30)
|
||||
|
||||
### FIxed
|
||||
|
||||
- Security issues.
|
||||
|
||||
### Added
|
||||
|
||||
- Routes' controllers namespace included in the configuration.
|
||||
|
||||
## v1.0.0 - (2019-12-30)
|
||||
|
||||
- First release
|
||||
Vendored
+59
@@ -0,0 +1,59 @@
|
||||
<p style="text-align:center;width:100%;"><img src="/art/preview.png" alt="Chatify Laravel Package"></p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/laravel/telescope/actions"><img src="https://poser.pugx.org/munafio/chatify/v/stable?style=flat-square" alt="Build Status"></a>
|
||||
<a href="https://packagist.org/packages/munafio/chatify"><img src="https://poser.pugx.org/munafio/chatify/downloads?style=flat-square" alt="Total Downloads"></a>
|
||||
<a href="https://packagist.org/packages/munafio/chatify"><img src="https://poser.pugx.org/munafio/chatify/license?style=flat-square" alt="License"></a>
|
||||
</p>
|
||||
|
||||
## Chatify Laravel Package
|
||||
|
||||
Laravel's #1 one-to-one chatting system package, helps you add a complete real-time chatting system to your new/existing Laravel application with only one command.
|
||||
|
||||
## Need a Help? 📣
|
||||
|
||||
I have created a server for **Chatify** on `Discord` to let you **up-to-date** and help you as much as I can .. so now you can chat with me, get a help, showcases, and most importantly to get announcements and updates about **Chatify**.
|
||||
|
||||
So, [join now](https://discord.gg/RaxyKVykYJ) and keep updated.
|
||||
|
||||
## Features
|
||||
|
||||
- One-to-one users chat system.
|
||||
- Real-time contact list updates.
|
||||
- Favorite users system (Like stories style).
|
||||
- Saved Messages to save your messages online like Telegram messenger app.
|
||||
- Search functionality.
|
||||
- Contact item's last message indicator (e.g. You: ....).
|
||||
- Real-time user's active status.
|
||||
- Real-time typing indicator.
|
||||
- Real-time message seen indicator.
|
||||
- Real-time internet connection status.
|
||||
- Upload attachments (Photo/File).
|
||||
- Send Emoji's.
|
||||
- User details panel (Shared photos, delete conversation..).
|
||||
- Responsive design with all devices.
|
||||
- User settings and chat customization : user's profile photo, dark mode and chat color.
|
||||
with simple and wonderful UI design.
|
||||
|
||||
...and much more you have to discover it yourself.
|
||||
|
||||
## Demo
|
||||
|
||||
- Demo app - [Click Here](https://github.com/munafio/chatify-demo).
|
||||
<!-- - Demo video on YouTube - [Click Here](https://youtu.be/gjo74FUJJPI) -->
|
||||
|
||||
## Official Documentation
|
||||
|
||||
The official documentation can be found [here](https://chatify.munafio.com)
|
||||
|
||||
## Change log
|
||||
|
||||
[CHANGELOG.md](https://github.com/munafio/chatify/blob/master/CHANGELOG.md)
|
||||
|
||||
## Author
|
||||
|
||||
- [Munaf A. Mahdi](https://www.munafio.com)
|
||||
|
||||
## License
|
||||
|
||||
Chatify is licensed under the [MIT license](https://choosealicense.com/licenses/mit/)
|
||||
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
# Upgrade Guide
|
||||
|
||||
With every upgrade, make sure to re-publish Chatify's assets:
|
||||
|
||||
## For v1.2.3 and earlier versions
|
||||
|
||||
```
|
||||
php artisan verndor:publish --tag=chatify-views --force
|
||||
php artisan verndor:publish --tag=chatify-assets --force
|
||||
```
|
||||
|
||||
If needed, you can re-publish the other assets the same way above by just replacing the name of the asset (chatify-NAME).
|
||||
|
||||
## For v1.2.4+ and higher vertions
|
||||
|
||||
To re-publish only `views` & `assets`:
|
||||
|
||||
```
|
||||
php artisan chatify:publish
|
||||
```
|
||||
|
||||
To re-publish all the assets (views, assets, config..):
|
||||
|
||||
```
|
||||
php artisan chatify:publish --force
|
||||
```
|
||||
|
||||
> This will overwrite all the assets, so all your changes will be overwritten.
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
Vendored
+44
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "munafio/chatify",
|
||||
"description": "A package for Laravel PHP Framework to add a complete real-time chat system.",
|
||||
"type": "library",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"messenger",
|
||||
"conversations",
|
||||
"chat",
|
||||
"php",
|
||||
"pusher",
|
||||
"realtime",
|
||||
"real-time",
|
||||
"chatify"
|
||||
],
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Munaf A. Mahdi",
|
||||
"email": "[email protected]"
|
||||
}
|
||||
],
|
||||
"homepage": "https://github.com/munafio/chatify",
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"require": {
|
||||
"pusher/pusher-php-server": "^6.0|^7.0|^7.1"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Chatify\\": "src/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Chatify\\ChatifyServiceProvider"
|
||||
],
|
||||
"aliases": {
|
||||
"Chatify": "Chatify\\Facades\\ChatifyMessenger"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+445
@@ -0,0 +1,445 @@
|
||||
<?php
|
||||
|
||||
namespace Chatify;
|
||||
|
||||
use App\Models\ChMessage as Message;
|
||||
use App\Models\ChFavorite as Favorite;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Pusher\Pusher;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Exception;
|
||||
|
||||
class ChatifyMessenger
|
||||
{
|
||||
public $pusher;
|
||||
|
||||
/**
|
||||
* Get max file's upload size in MB.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getMaxUploadSize()
|
||||
{
|
||||
return config('chatify.attachments.max_upload_size') * 1048576;
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->pusher = new Pusher(
|
||||
config('chatify.pusher.key'),
|
||||
config('chatify.pusher.secret'),
|
||||
config('chatify.pusher.app_id'),
|
||||
config('chatify.pusher.options'),
|
||||
);
|
||||
}
|
||||
/**
|
||||
* This method returns the allowed image extensions
|
||||
* to attach with the message.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAllowedImages()
|
||||
{
|
||||
return config('chatify.attachments.allowed_images');
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the allowed file extensions
|
||||
* to attach with the message.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAllowedFiles()
|
||||
{
|
||||
return config('chatify.attachments.allowed_files');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array contains messenger's colors
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getMessengerColors()
|
||||
{
|
||||
return config('chatify.colors');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a fallback primary color.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getFallbackColor()
|
||||
{
|
||||
$colors = $this->getMessengerColors();
|
||||
return count($colors) > 0 ? $colors[0] : '#000000';
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger an event using Pusher
|
||||
*
|
||||
* @param string $channel
|
||||
* @param string $event
|
||||
* @param array $data
|
||||
* @return void
|
||||
*/
|
||||
public function push($channel, $event, $data)
|
||||
{
|
||||
return $this->pusher->trigger($channel, $event, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authentication for pusher
|
||||
*
|
||||
* @param User $requestUser
|
||||
* @param User $authUser
|
||||
* @param string $channelName
|
||||
* @param string $socket_id
|
||||
* @param array $data
|
||||
* @return void
|
||||
*/
|
||||
public function pusherAuth($requestUser, $authUser, $channelName, $socket_id)
|
||||
{
|
||||
// Auth data
|
||||
$authData = json_encode([
|
||||
'user_id' => $authUser->id,
|
||||
'user_info' => [
|
||||
'name' => $authUser->name
|
||||
]
|
||||
]);
|
||||
// check if user authenticated
|
||||
if (Auth::check()) {
|
||||
if($requestUser->id == $authUser->id){
|
||||
return $this->pusher->socket_auth(
|
||||
$channelName,
|
||||
$socket_id,
|
||||
$authData
|
||||
);
|
||||
}
|
||||
// if not authorized
|
||||
return response()->json(['message'=>'Unauthorized'], 401);
|
||||
}
|
||||
// if not authenticated
|
||||
return response()->json(['message'=>'Not authenticated'], 403);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch & parse message and return the message card
|
||||
* view as a response.
|
||||
*
|
||||
* @param Message $prefetchedMessage
|
||||
* @param int $id
|
||||
* @return array
|
||||
*/
|
||||
public function parseMessage($prefetchedMessage = null, $id = null)
|
||||
{
|
||||
$msg = null;
|
||||
$attachment = null;
|
||||
$attachment_type = null;
|
||||
$attachment_title = null;
|
||||
if (!!$prefetchedMessage) {
|
||||
$msg = $prefetchedMessage;
|
||||
} else {
|
||||
$msg = Message::where('id', $id)->first();
|
||||
if(!$msg){
|
||||
return [];
|
||||
}
|
||||
}
|
||||
if (isset($msg->attachment)) {
|
||||
$attachmentOBJ = json_decode($msg->attachment);
|
||||
$attachment = $attachmentOBJ->new_name;
|
||||
$attachment_title = htmlentities(trim($attachmentOBJ->old_name), ENT_QUOTES, 'UTF-8');
|
||||
$ext = pathinfo($attachment, PATHINFO_EXTENSION);
|
||||
$attachment_type = in_array($ext, $this->getAllowedImages()) ? 'image' : 'file';
|
||||
}
|
||||
return [
|
||||
'id' => $msg->id,
|
||||
'from_id' => $msg->from_id,
|
||||
'to_id' => $msg->to_id,
|
||||
'message' => $msg->body,
|
||||
'attachment' => (object) [
|
||||
'file' => $attachment,
|
||||
'title' => $attachment_title,
|
||||
'type' => $attachment_type
|
||||
],
|
||||
'timeAgo' => $msg->created_at->diffForHumans(),
|
||||
'created_at' => $msg->created_at->toIso8601String(),
|
||||
'isSender' => ($msg->from_id == Auth::user()->id),
|
||||
'seen' => $msg->seen,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a message card with the given data.
|
||||
*
|
||||
* @param Message $data
|
||||
* @param boolean $isSender
|
||||
* @return string
|
||||
*/
|
||||
public function messageCard($data, $renderDefaultCard = false)
|
||||
{
|
||||
if (!$data) {
|
||||
return '';
|
||||
}
|
||||
if($renderDefaultCard) {
|
||||
$data['isSender'] = false;
|
||||
}
|
||||
return view('Chatify::layouts.messageCard', $data)->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Default fetch messages query between a Sender and Receiver.
|
||||
*
|
||||
* @param int $user_id
|
||||
* @return Message|\Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function fetchMessagesQuery($user_id)
|
||||
{
|
||||
return Message::where('from_id', Auth::user()->id)->where('to_id', $user_id)
|
||||
->orWhere('from_id', $user_id)->where('to_id', Auth::user()->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* create a new message to database
|
||||
*
|
||||
* @param array $data
|
||||
* @return Message
|
||||
*/
|
||||
public function newMessage($data)
|
||||
{
|
||||
$message = new Message();
|
||||
$message->from_id = $data['from_id'];
|
||||
$message->to_id = $data['to_id'];
|
||||
$message->body = $data['body'];
|
||||
$message->attachment = $data['attachment'];
|
||||
$message->save();
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make messages between the sender [Auth user] and
|
||||
* the receiver [User id] as seen.
|
||||
*
|
||||
* @param int $user_id
|
||||
* @return bool
|
||||
*/
|
||||
public function makeSeen($user_id)
|
||||
{
|
||||
Message::Where('from_id', $user_id)
|
||||
->where('to_id', Auth::user()->id)
|
||||
->where('seen', 0)
|
||||
->update(['seen' => 1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get last message for a specific user
|
||||
*
|
||||
* @param int $user_id
|
||||
* @return Message|Collection|\Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model|object|null
|
||||
*/
|
||||
public function getLastMessageQuery($user_id)
|
||||
{
|
||||
return $this->fetchMessagesQuery($user_id)->latest()->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Count Unseen messages
|
||||
*
|
||||
* @param int $user_id
|
||||
* @return Collection
|
||||
*/
|
||||
public function countUnseenMessages($user_id)
|
||||
{
|
||||
return Message::where('from_id', $user_id)->where('to_id', Auth::user()->id)->where('seen', 0)->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user list's item data [Contact Itme]
|
||||
* (e.g. User data, Last message, Unseen Counter...)
|
||||
*
|
||||
* @param int $messenger_id
|
||||
* @param Collection $user
|
||||
* @return string
|
||||
*/
|
||||
public function getContactItem($user)
|
||||
{
|
||||
try {
|
||||
// get last message
|
||||
$lastMessage = $this->getLastMessageQuery($user->id);
|
||||
// Get Unseen messages counter
|
||||
$unseenCounter = $this->countUnseenMessages($user->id);
|
||||
if ($lastMessage) {
|
||||
$lastMessage->created_at = $lastMessage->created_at->toIso8601String();
|
||||
$lastMessage->timeAgo = $lastMessage->created_at->diffForHumans();
|
||||
}
|
||||
return view('Chatify::layouts.listItem', [
|
||||
'get' => 'users',
|
||||
'user' => $this->getUserWithAvatar($user),
|
||||
'lastMessage' => $lastMessage,
|
||||
'unseenCounter' => $unseenCounter,
|
||||
])->render();
|
||||
} catch (\Throwable $th) {
|
||||
throw new Exception($th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user with avatar (formatted).
|
||||
*
|
||||
* @param Collection $user
|
||||
* @return Collection
|
||||
*/
|
||||
public function getUserWithAvatar($user)
|
||||
{
|
||||
if ($user->avatar == 'avatar.png' && config('chatify.gravatar.enabled')) {
|
||||
$imageSize = config('chatify.gravatar.image_size');
|
||||
$imageset = config('chatify.gravatar.imageset');
|
||||
$user->avatar = 'https://www.gravatar.com/avatar/' . md5(strtolower(trim($user->email))) . '?s=' . $imageSize . '&d=' . $imageset;
|
||||
} else {
|
||||
$user->avatar = self::getUserAvatarUrl($user->avatar);
|
||||
}
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a user in the favorite list
|
||||
*
|
||||
* @param int $user_id
|
||||
* @return boolean
|
||||
*/
|
||||
public function inFavorite($user_id)
|
||||
{
|
||||
return Favorite::where('user_id', Auth::user()->id)
|
||||
->where('favorite_id', $user_id)->count() > 0
|
||||
? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make user in favorite list
|
||||
*
|
||||
* @param int $user_id
|
||||
* @param int $star
|
||||
* @return boolean
|
||||
*/
|
||||
public function makeInFavorite($user_id, $action)
|
||||
{
|
||||
if ($action > 0) {
|
||||
// Star
|
||||
$star = new Favorite();
|
||||
$star->user_id = Auth::user()->id;
|
||||
$star->favorite_id = $user_id;
|
||||
$star->save();
|
||||
return $star ? true : false;
|
||||
} else {
|
||||
// UnStar
|
||||
$star = Favorite::where('user_id', Auth::user()->id)->where('favorite_id', $user_id)->delete();
|
||||
return $star ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get shared photos of the conversation
|
||||
*
|
||||
* @param int $user_id
|
||||
* @return array
|
||||
*/
|
||||
public function getSharedPhotos($user_id)
|
||||
{
|
||||
$images = array(); // Default
|
||||
// Get messages
|
||||
$msgs = $this->fetchMessagesQuery($user_id)->orderBy('created_at', 'DESC');
|
||||
if ($msgs->count() > 0) {
|
||||
foreach ($msgs->get() as $msg) {
|
||||
// If message has attachment
|
||||
if ($msg->attachment) {
|
||||
$attachment = json_decode($msg->attachment);
|
||||
// determine the type of the attachment
|
||||
in_array(pathinfo($attachment->new_name, PATHINFO_EXTENSION), $this->getAllowedImages())
|
||||
? array_push($images, $attachment->new_name) : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
return $images;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete Conversation
|
||||
*
|
||||
* @param int $user_id
|
||||
* @return boolean
|
||||
*/
|
||||
public function deleteConversation($user_id)
|
||||
{
|
||||
try {
|
||||
foreach ($this->fetchMessagesQuery($user_id)->get() as $msg) {
|
||||
// delete file attached if exist
|
||||
if (isset($msg->attachment)) {
|
||||
$path = config('chatify.attachments.folder').'/'.json_decode($msg->attachment)->new_name;
|
||||
if (self::storage()->exists($path)) {
|
||||
self::storage()->delete($path);
|
||||
}
|
||||
}
|
||||
// delete from database
|
||||
$msg->delete();
|
||||
}
|
||||
return 1;
|
||||
} catch (Exception $e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete message by ID
|
||||
*
|
||||
* @param int $id
|
||||
* @return boolean
|
||||
*/
|
||||
public function deleteMessage($id)
|
||||
{
|
||||
try {
|
||||
$msg = Message::where('from_id', auth()->id())->where('id', $id)->firstOrFail();
|
||||
if (isset($msg->attachment)) {
|
||||
$path = config('chatify.attachments.folder') . '/' . json_decode($msg->attachment)->new_name;
|
||||
if (self::storage()->exists($path)) {
|
||||
self::storage()->delete($path);
|
||||
}
|
||||
}
|
||||
$msg->delete();
|
||||
return 1;
|
||||
} catch (Exception $e) {
|
||||
throw new Exception($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a storage instance with disk name specified in the config.
|
||||
*
|
||||
*/
|
||||
public function storage()
|
||||
{
|
||||
return Storage::disk(config('chatify.storage_disk_name'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user avatar url.
|
||||
*
|
||||
* @param string $user_avatar_name
|
||||
* @return string
|
||||
*/
|
||||
public function getUserAvatarUrl($user_avatar_name)
|
||||
{
|
||||
return self::storage()->url(config('chatify.user_avatar.folder') . '/' . $user_avatar_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attachment's url.
|
||||
*
|
||||
* @param string $attachment_name
|
||||
* @return string
|
||||
*/
|
||||
public function getAttachmentUrl($attachment_name)
|
||||
{
|
||||
return self::storage()->url(config('chatify.attachments.folder') . '/' . $attachment_name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
namespace Chatify;
|
||||
|
||||
use Chatify\Console\InstallCommand;
|
||||
use Chatify\Console\PublishCommand;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class ChatifyServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
app()->bind('ChatifyMessenger', function () {
|
||||
return new \Chatify\ChatifyMessenger;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
// Load Views and Routes
|
||||
$this->loadViewsFrom(__DIR__ . '/views', 'Chatify');
|
||||
$this->loadRoutes();
|
||||
|
||||
if ($this->app->runningInConsole()) {
|
||||
$this->commands([
|
||||
InstallCommand::class,
|
||||
PublishCommand::class,
|
||||
]);
|
||||
$this->setPublishes();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Publishing the files that the user may override.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function setPublishes()
|
||||
{
|
||||
// Load user's avatar folder from package's config
|
||||
$userAvatarFolder = json_decode(json_encode(include(__DIR__.'/config/chatify.php')))->user_avatar->folder;
|
||||
|
||||
// Config
|
||||
$this->publishes([
|
||||
__DIR__ . '/config/chatify.php' => config_path('chatify.php')
|
||||
], 'chatify-config');
|
||||
|
||||
// Migrations
|
||||
$this->publishes([
|
||||
__DIR__ . '/database/migrations/2022_01_10_99999_add_active_status_to_users.php' => database_path('migrations/' . date('Y_m_d') . '_999999_add_active_status_to_users.php'),
|
||||
__DIR__ . '/database/migrations/2022_01_10_99999_add_avatar_to_users.php' => database_path('migrations/' . date('Y_m_d') . '_999999_add_avatar_to_users.php'),
|
||||
__DIR__ . '/database/migrations/2022_01_10_99999_add_dark_mode_to_users.php' => database_path('migrations/' . date('Y_m_d') . '_999999_add_dark_mode_to_users.php'),
|
||||
__DIR__ . '/database/migrations/2022_01_10_99999_add_messenger_color_to_users.php' => database_path('migrations/' . date('Y_m_d') . '_999999_add_messenger_color_to_users.php'),
|
||||
__DIR__ . '/database/migrations/2022_01_10_99999_create_chatify_favorites_table.php' => database_path('migrations/' . date('Y_m_d') . '_999999_create_chatify_favorites_table.php'),
|
||||
__DIR__ . '/database/migrations/2022_01_10_99999_create_chatify_messages_table.php' => database_path('migrations/' . date('Y_m_d') . '_999999_create_chatify_messages_table.php'),
|
||||
], 'chatify-migrations');
|
||||
|
||||
// Models
|
||||
$isV8 = explode('.', app()->version())[0] >= 8;
|
||||
$this->publishes([
|
||||
__DIR__ . '/Models' => app_path($isV8 ? 'Models' : '')
|
||||
], 'chatify-models');
|
||||
|
||||
// Controllers
|
||||
$this->publishes([
|
||||
__DIR__ . '/Http/Controllers' => app_path('Http/Controllers/vendor/Chatify')
|
||||
], 'chatify-controllers');
|
||||
|
||||
// Views
|
||||
$this->publishes([
|
||||
__DIR__ . '/views' => resource_path('views/vendor/Chatify')
|
||||
], 'chatify-views');
|
||||
|
||||
// Assets
|
||||
$this->publishes([
|
||||
// CSS
|
||||
__DIR__ . '/assets/css' => public_path('css/chatify'),
|
||||
// JavaScript
|
||||
__DIR__ . '/assets/js' => public_path('js/chatify'),
|
||||
// Images
|
||||
__DIR__ . '/assets/imgs' => storage_path('app/public/' . $userAvatarFolder),
|
||||
// CSS
|
||||
__DIR__ . '/assets/sounds' => public_path('sounds/chatify'),
|
||||
], 'chatify-assets');
|
||||
|
||||
// Routes (API and Web)
|
||||
$this->publishes([
|
||||
__DIR__ . '/routes' => base_path('routes/chatify')
|
||||
], 'chatify-routes');
|
||||
}
|
||||
|
||||
/**
|
||||
* Group the routes and set up configurations to load them.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function loadRoutes()
|
||||
{
|
||||
if (config('chatify.routes.custom')) {
|
||||
Route::group($this->routesConfigurations(), function () {
|
||||
$this->loadRoutesFrom(base_path('routes/chatify/web.php'));
|
||||
});
|
||||
Route::group($this->apiRoutesConfigurations(), function () {
|
||||
$this->loadRoutesFrom(base_path('routes/chatify/api.php'));
|
||||
});
|
||||
} else {
|
||||
Route::group($this->routesConfigurations(), function () {
|
||||
$this->loadRoutesFrom(__DIR__ . '/routes/web.php');
|
||||
});
|
||||
Route::group($this->apiRoutesConfigurations(), function () {
|
||||
$this->loadRoutesFrom(__DIR__ . '/routes/api.php');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Routes configurations.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function routesConfigurations()
|
||||
{
|
||||
return [
|
||||
'prefix' => config('chatify.routes.prefix'),
|
||||
'namespace' => config('chatify.routes.namespace'),
|
||||
'middleware' => config('chatify.routes.middleware'),
|
||||
];
|
||||
}
|
||||
/**
|
||||
* API routes configurations.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function apiRoutesConfigurations()
|
||||
{
|
||||
return [
|
||||
'prefix' => config('chatify.api_routes.prefix'),
|
||||
'namespace' => config('chatify.api_routes.namespace'),
|
||||
'middleware' => config('chatify.api_routes.middleware'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
namespace Chatify\Console;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
class InstallCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'chatify:install';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Install Chatify package';
|
||||
|
||||
/**
|
||||
* Check Laravel version.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $isV8;
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->isV8 = explode('.',app()->version())[0] >= 8;
|
||||
|
||||
$this->info('Installing Chatify...');
|
||||
|
||||
$this->line('----------');
|
||||
$this->line('Configurations...');
|
||||
$this->modifyModelsPath('/../Http/Controllers/MessagesController.php','User');
|
||||
$this->modifyModelsPath('/../Http/Controllers/MessagesController.php','ChFavorite');
|
||||
$this->modifyModelsPath('/../Http/Controllers/MessagesController.php','ChMessage');
|
||||
$this->modifyModelsPath('/../Http/Controllers/Api/MessagesController.php','User');
|
||||
$this->modifyModelsPath('/../Http/Controllers/Api/MessagesController.php','ChFavorite');
|
||||
$this->modifyModelsPath('/../Http/Controllers/Api/MessagesController.php','ChMessage');
|
||||
$this->modifyModelsPath('/../ChatifyMessenger.php','ChFavorite');
|
||||
$this->modifyModelsPath('/../ChatifyMessenger.php','ChMessage');
|
||||
$this->modifyModelsPath('/../Models/ChFavorite.php');
|
||||
$this->modifyModelsPath('/../Models/ChMessage.php');
|
||||
$this->info('[✓] done');
|
||||
|
||||
$assetsToBePublished = [
|
||||
'config' => config_path('chatify.php'),
|
||||
'views' => resource_path('views/vendor/Chatify'),
|
||||
'assets' => public_path('css/chatify'),
|
||||
'models' => app_path(($this->isV8 ? 'Models/' : '').'ChMessage.php'),
|
||||
'migrations' => database_path('migrations/2019_09_22_192348_create_messages_table.php'),
|
||||
'routes' => base_path('routes/chatify'),
|
||||
];
|
||||
|
||||
foreach ($assetsToBePublished as $target => $path) {
|
||||
$this->line('----------');
|
||||
$this->process($target, $path);
|
||||
}
|
||||
|
||||
$this->line('----------');
|
||||
$this->line('Creating storage symlink...');
|
||||
Artisan::call('storage:link');
|
||||
$this->info('[✓] Storage linked.');
|
||||
|
||||
$this->line('----------');
|
||||
$this->info('[✓] Chatify installed successfully');
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify models imports/namespace path according to Laravel version.
|
||||
*
|
||||
* @param string $targetFilePath
|
||||
* @param string $model
|
||||
* @return void
|
||||
*/
|
||||
private function modifyModelsPath($targetFilePath, $model = null){
|
||||
$path = realpath(__DIR__.$targetFilePath);
|
||||
$contents = File::get($path);
|
||||
$model = !empty($model) ? '\\'.$model : ';';
|
||||
$contents = str_replace(
|
||||
(!$this->isV8 ? 'App\Models' : 'App').$model,
|
||||
($this->isV8 ? 'App\Models' : 'App').$model,
|
||||
$contents
|
||||
);
|
||||
File::put($path, $contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check, publish, or overwrite the assets.
|
||||
*
|
||||
* @param string $target
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
private function process($target, $path)
|
||||
{
|
||||
$this->line('Publishing '.$target.'...');
|
||||
if (!File::exists($path)) {
|
||||
$this->publish($target);
|
||||
$this->info('[✓] '.$target.' published.');
|
||||
return;
|
||||
}
|
||||
if ($this->shouldOverwrite($target)) {
|
||||
$this->line('Overwriting '.$target.'...');
|
||||
$this->publish($target,true);
|
||||
$this->info('[✓] '.$target.' published.');
|
||||
return;
|
||||
}
|
||||
$this->line('[-] Ignored, The existing '.$target.' was not overwritten');
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask to overwrite.
|
||||
*
|
||||
* @param string $target
|
||||
* @return void
|
||||
*/
|
||||
private function shouldOverwrite($target)
|
||||
{
|
||||
return $this->confirm(
|
||||
$target.' already exists. Do you want to overwrite it?',
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the publish command.
|
||||
*
|
||||
* @param string $tag
|
||||
* @param bool $forcePublish
|
||||
* @return void
|
||||
*/
|
||||
private function publish($tag, $forcePublish = false)
|
||||
{
|
||||
$this->call('vendor:publish', [
|
||||
'--tag' => 'chatify-'.$tag,
|
||||
'--force' => $forcePublish,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Chatify\Console;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class PublishCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'chatify:publish {--force : Overwrite any existing files}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Publish all of the chatify assets';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
if($this->option('force')){
|
||||
$this->call('vendor:publish', [
|
||||
'--tag' => 'chatify-config',
|
||||
'--force' => true,
|
||||
]);
|
||||
|
||||
$this->call('vendor:publish', [
|
||||
'--tag' => 'chatify-migrations',
|
||||
'--force' => true,
|
||||
]);
|
||||
|
||||
$this->call('vendor:publish', [
|
||||
'--tag' => 'chatify-models',
|
||||
'--force' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
$this->call('vendor:publish', [
|
||||
'--tag' => 'chatify-views',
|
||||
'--force' => true,
|
||||
]);
|
||||
|
||||
$this->call('vendor:publish', [
|
||||
'--tag' => 'chatify-assets',
|
||||
'--force' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Chatify\Facades;
|
||||
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
|
||||
class ChatifyMessenger extends Facade
|
||||
{
|
||||
|
||||
protected static function getFacadeAccessor()
|
||||
{
|
||||
return 'ChatifyMessenger';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,400 @@
|
||||
<?php
|
||||
|
||||
namespace Chatify\Http\Controllers\Api;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
use App\Models\ChMessage as Message;
|
||||
use App\Models\ChFavorite as Favorite;
|
||||
use Chatify\Facades\ChatifyMessenger as Chatify;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
|
||||
class MessagesController extends Controller
|
||||
{
|
||||
protected $perPage = 30;
|
||||
|
||||
/**
|
||||
* Authinticate the connection for pusher
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function pusherAuth(Request $request)
|
||||
{
|
||||
return Chatify::pusherAuth(
|
||||
$request->user(),
|
||||
Auth::user(),
|
||||
$request['channel_name'],
|
||||
$request['socket_id']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch data by id for (user/group)
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function idFetchData(Request $request)
|
||||
{
|
||||
return auth()->user();
|
||||
// Favorite
|
||||
$favorite = Chatify::inFavorite($request['id']);
|
||||
|
||||
// User data
|
||||
if ($request['type'] == 'user') {
|
||||
$fetch = User::where('id', $request['id'])->first();
|
||||
if($fetch){
|
||||
$userAvatar = Chatify::getUserWithAvatar($fetch)->avatar;
|
||||
}
|
||||
}
|
||||
|
||||
// send the response
|
||||
return Response::json([
|
||||
'favorite' => $favorite,
|
||||
'fetch' => $fetch ?? null,
|
||||
'user_avatar' => $userAvatar ?? null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method to make a links for the attachments
|
||||
* to be downloadable.
|
||||
*
|
||||
* @param string $fileName
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function download($fileName)
|
||||
{
|
||||
$path = config('chatify.attachments.folder') . '/' . $fileName;
|
||||
if (Chatify::storage()->exists($path)) {
|
||||
return response()->json([
|
||||
'file_name' => $fileName,
|
||||
'download_path' => Chatify::storage()->url($path)
|
||||
], 200);
|
||||
} else {
|
||||
return response()->json([
|
||||
'message'=>"Sorry, File does not exist in our server or may have been deleted!"
|
||||
], 404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to database
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JSON response
|
||||
*/
|
||||
public function send(Request $request)
|
||||
{
|
||||
// default variables
|
||||
$error = (object)[
|
||||
'status' => 0,
|
||||
'message' => null
|
||||
];
|
||||
$attachment = null;
|
||||
$attachment_title = null;
|
||||
|
||||
// if there is attachment [file]
|
||||
if ($request->hasFile('file')) {
|
||||
// allowed extensions
|
||||
$allowed_images = Chatify::getAllowedImages();
|
||||
$allowed_files = Chatify::getAllowedFiles();
|
||||
$allowed = array_merge($allowed_images, $allowed_files);
|
||||
|
||||
$file = $request->file('file');
|
||||
// check file size
|
||||
if ($file->getSize() < Chatify::getMaxUploadSize()) {
|
||||
if (in_array(strtolower($file->extension()), $allowed)) {
|
||||
// get attachment name
|
||||
$attachment_title = $file->getClientOriginalName();
|
||||
// upload attachment and store the new name
|
||||
$attachment = Str::uuid() . "." . $file->extension();
|
||||
$file->storeAs(config('chatify.attachments.folder'), $attachment, config('chatify.storage_disk_name'));
|
||||
} else {
|
||||
$error->status = 1;
|
||||
$error->message = "File extension not allowed!";
|
||||
}
|
||||
} else {
|
||||
$error->status = 1;
|
||||
$error->message = "File size you are trying to upload is too large!";
|
||||
}
|
||||
}
|
||||
|
||||
if (!$error->status) {
|
||||
// send to database
|
||||
$message = Chatify::newMessage([
|
||||
'type' => $request['type'],
|
||||
'from_id' => Auth::user()->id,
|
||||
'to_id' => $request['id'],
|
||||
'body' => htmlentities(trim($request['message']), ENT_QUOTES, 'UTF-8'),
|
||||
'attachment' => ($attachment) ? json_encode((object)[
|
||||
'new_name' => $attachment,
|
||||
'old_name' => htmlentities(trim($attachment_title), ENT_QUOTES, 'UTF-8'),
|
||||
]) : null,
|
||||
]);
|
||||
|
||||
// fetch message to send it with the response
|
||||
$messageData = Chatify::parseMessage($message);
|
||||
|
||||
// send to user using pusher
|
||||
if (Auth::user()->id != $request['id']) {
|
||||
Chatify::push("private-chatify.".$request['id'], 'messaging', [
|
||||
'from_id' => Auth::user()->id,
|
||||
'to_id' => $request['id'],
|
||||
'message' => $messageData
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// send the response
|
||||
return Response::json([
|
||||
'status' => '200',
|
||||
'error' => $error,
|
||||
'message' => $messageData ?? [],
|
||||
'tempID' => $request['temporaryMsgId'],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* fetch [user/group] messages from database
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JSON response
|
||||
*/
|
||||
public function fetch(Request $request)
|
||||
{
|
||||
$query = Chatify::fetchMessagesQuery($request['id'])->latest();
|
||||
$messages = $query->paginate($request->per_page ?? $this->perPage);
|
||||
$totalMessages = $messages->total();
|
||||
$lastPage = $messages->lastPage();
|
||||
$response = [
|
||||
'total' => $totalMessages,
|
||||
'last_page' => $lastPage,
|
||||
'last_message_id' => collect($messages->items())->last()->id ?? null,
|
||||
'messages' => $messages->items(),
|
||||
];
|
||||
return Response::json($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make messages as seen
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function seen(Request $request)
|
||||
{
|
||||
// make as seen
|
||||
$seen = Chatify::makeSeen($request['id']);
|
||||
// send the response
|
||||
return Response::json([
|
||||
'status' => $seen,
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get contacts list
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse response
|
||||
*/
|
||||
public function getContacts(Request $request)
|
||||
{
|
||||
// get all users that received/sent message from/to [Auth user]
|
||||
$users = Message::join('users', function ($join) {
|
||||
$join->on('ch_messages.from_id', '=', 'users.id')
|
||||
->orOn('ch_messages.to_id', '=', 'users.id');
|
||||
})
|
||||
->where(function ($q) {
|
||||
$q->where('ch_messages.from_id', Auth::user()->id)
|
||||
->orWhere('ch_messages.to_id', Auth::user()->id);
|
||||
})
|
||||
->where('users.id','!=',Auth::user()->id)
|
||||
->select('users.*',DB::raw('MAX(ch_messages.created_at) max_created_at'))
|
||||
->orderBy('max_created_at', 'desc')
|
||||
->groupBy('users.id')
|
||||
->paginate($request->per_page ?? $this->perPage);
|
||||
|
||||
return response()->json([
|
||||
'contacts' => $users->items(),
|
||||
'total' => $users->total() ?? 0,
|
||||
'last_page' => $users->lastPage() ?? 1,
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a user in the favorites list
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function favorite(Request $request)
|
||||
{
|
||||
$userId = $request['user_id'];
|
||||
// check action [star/unstar]
|
||||
$favoriteStatus = Chatify::inFavorite($userId) ? 0 : 1;
|
||||
Chatify::makeInFavorite($userId, $favoriteStatus);
|
||||
|
||||
// send the response
|
||||
return Response::json([
|
||||
'status' => @$favoriteStatus,
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get favorites list
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function getFavorites(Request $request)
|
||||
{
|
||||
$favorites = Favorite::where('user_id', Auth::user()->id)->get();
|
||||
foreach ($favorites as $favorite) {
|
||||
$favorite->user = User::where('id', $favorite->favorite_id)->first();
|
||||
}
|
||||
return Response::json([
|
||||
'total' => count($favorites),
|
||||
'favorites' => $favorites ?? [],
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search in messenger
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function search(Request $request)
|
||||
{
|
||||
$input = trim(filter_var($request['input']));
|
||||
$records = User::where('id','!=',Auth::user()->id)
|
||||
->where('name', 'LIKE', "%{$input}%")
|
||||
->paginate($request->per_page ?? $this->perPage);
|
||||
|
||||
foreach ($records->items() as $index => $record) {
|
||||
$records[$index] += Chatify::getUserWithAvatar($record);
|
||||
}
|
||||
|
||||
return Response::json([
|
||||
'records' => $records->items(),
|
||||
'total' => $records->total(),
|
||||
'last_page' => $records->lastPage()
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get shared photos
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function sharedPhotos(Request $request)
|
||||
{
|
||||
$images = Chatify::getSharedPhotos($request['user_id']);
|
||||
|
||||
foreach ($images as $image) {
|
||||
$image = asset(config('chatify.attachments.folder') . $image);
|
||||
}
|
||||
// send the response
|
||||
return Response::json([
|
||||
'shared' => $images ?? [],
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete conversation
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function deleteConversation(Request $request)
|
||||
{
|
||||
// delete
|
||||
$delete = Chatify::deleteConversation($request['id']);
|
||||
|
||||
// send the response
|
||||
return Response::json([
|
||||
'deleted' => $delete ? 1 : 0,
|
||||
], 200);
|
||||
}
|
||||
|
||||
public function updateSettings(Request $request)
|
||||
{
|
||||
$msg = null;
|
||||
$error = $success = 0;
|
||||
|
||||
// dark mode
|
||||
if ($request['dark_mode']) {
|
||||
$request['dark_mode'] == "dark"
|
||||
? User::where('id', Auth::user()->id)->update(['dark_mode' => 1]) // Make Dark
|
||||
: User::where('id', Auth::user()->id)->update(['dark_mode' => 0]); // Make Light
|
||||
}
|
||||
|
||||
// If messenger color selected
|
||||
if ($request['messengerColor']) {
|
||||
$messenger_color = trim(filter_var($request['messengerColor']));
|
||||
User::where('id', Auth::user()->id)
|
||||
->update(['messenger_color' => $messenger_color]);
|
||||
}
|
||||
// if there is a [file]
|
||||
if ($request->hasFile('avatar')) {
|
||||
// allowed extensions
|
||||
$allowed_images = Chatify::getAllowedImages();
|
||||
|
||||
$file = $request->file('avatar');
|
||||
// check file size
|
||||
if ($file->getSize() < Chatify::getMaxUploadSize()) {
|
||||
if (in_array(strtolower($file->extension()), $allowed_images)) {
|
||||
// delete the older one
|
||||
if (Auth::user()->avatar != config('chatify.user_avatar.default')) {
|
||||
$path = Chatify::getUserAvatarUrl(Auth::user()->avatar);
|
||||
if (Chatify::storage()->exists($path)) {
|
||||
Chatify::storage()->delete($path);
|
||||
}
|
||||
}
|
||||
// upload
|
||||
$avatar = Str::uuid() . "." . $file->extension();
|
||||
$update = User::where('id', Auth::user()->id)->update(['avatar' => $avatar]);
|
||||
$file->storeAs(config('chatify.user_avatar.folder'), $avatar, config('chatify.storage_disk_name'));
|
||||
$success = $update ? 1 : 0;
|
||||
} else {
|
||||
$msg = "File extension not allowed!";
|
||||
$error = 1;
|
||||
}
|
||||
} else {
|
||||
$msg = "File size you are trying to upload is too large!";
|
||||
$error = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// send the response
|
||||
return Response::json([
|
||||
'status' => $success ? 1 : 0,
|
||||
'error' => $error ? 1 : 0,
|
||||
'message' => $error ? $msg : 0,
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set user's active status
|
||||
*
|
||||
* @param Request $request
|
||||
* @return void
|
||||
*/
|
||||
public function setActiveStatus(Request $request)
|
||||
{
|
||||
$activeStatus = $request['status'] > 0 ? 1 : 0;
|
||||
$status = User::where('id', Auth::user()->id)->update(['active_status' => $activeStatus]);
|
||||
return Response::json([
|
||||
'status' => $status,
|
||||
], 200);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,483 @@
|
||||
<?php
|
||||
|
||||
namespace Chatify\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
use App\Models\User;
|
||||
use App\Models\ChMessage as Message;
|
||||
use App\Models\ChFavorite as Favorite;
|
||||
use Chatify\Facades\ChatifyMessenger as Chatify;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Request as FacadesRequest;
|
||||
use Illuminate\Support\Str;
|
||||
class MessagesController extends Controller
|
||||
{
|
||||
protected $perPage = 30;
|
||||
|
||||
/**
|
||||
* Authenticate the connection for pusher
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function pusherAuth(Request $request)
|
||||
{
|
||||
return Chatify::pusherAuth(
|
||||
$request->user(),
|
||||
Auth::user(),
|
||||
$request['channel_name'],
|
||||
$request['socket_id']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returning the view of the app with the required data.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
|
||||
*/
|
||||
public function index( $id = null)
|
||||
{
|
||||
$messenger_color = Auth::user()->messenger_color;
|
||||
return view('Chatify::pages.app', [
|
||||
'id' => $id ?? 0,
|
||||
'messengerColor' => $messenger_color ? $messenger_color : Chatify::getFallbackColor(),
|
||||
'dark_mode' => Auth::user()->dark_mode < 1 ? 'light' : 'dark',
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fetch data (user, favorite.. etc).
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function idFetchData(Request $request)
|
||||
{
|
||||
$favorite = Chatify::inFavorite($request['id']);
|
||||
$fetch = User::where('id', $request['id'])->first();
|
||||
if($fetch){
|
||||
$userAvatar = Chatify::getUserWithAvatar($fetch)->avatar;
|
||||
}
|
||||
return Response::json([
|
||||
'favorite' => $favorite,
|
||||
'fetch' => $fetch ?? null,
|
||||
'user_avatar' => $userAvatar ?? null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method to make a links for the attachments
|
||||
* to be downloadable.
|
||||
*
|
||||
* @param string $fileName
|
||||
* @return \Symfony\Component\HttpFoundation\StreamedResponse|void
|
||||
*/
|
||||
public function download($fileName)
|
||||
{
|
||||
$filePath = config('chatify.attachments.folder') . '/' . $fileName;
|
||||
if (Chatify::storage()->exists($filePath)) {
|
||||
return Chatify::storage()->download($filePath);
|
||||
}
|
||||
return abort(404, "Sorry, File does not exist in our server or may have been deleted!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to database
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function send(Request $request)
|
||||
{
|
||||
// default variables
|
||||
$error = (object)[
|
||||
'status' => 0,
|
||||
'message' => null
|
||||
];
|
||||
$attachment = null;
|
||||
$attachment_title = null;
|
||||
|
||||
// if there is attachment [file]
|
||||
if ($request->hasFile('file')) {
|
||||
// allowed extensions
|
||||
$allowed_images = Chatify::getAllowedImages();
|
||||
$allowed_files = Chatify::getAllowedFiles();
|
||||
$allowed = array_merge($allowed_images, $allowed_files);
|
||||
|
||||
$file = $request->file('file');
|
||||
// check file size
|
||||
if ($file->getSize() < Chatify::getMaxUploadSize()) {
|
||||
if (in_array(strtolower($file->extension()), $allowed)) {
|
||||
// get attachment name
|
||||
$attachment_title = $file->getClientOriginalName();
|
||||
// upload attachment and store the new name
|
||||
$attachment = Str::uuid() . "." . $file->extension();
|
||||
$file->storeAs(config('chatify.attachments.folder'), $attachment, config('chatify.storage_disk_name'));
|
||||
} else {
|
||||
$error->status = 1;
|
||||
$error->message = "File extension not allowed!";
|
||||
}
|
||||
} else {
|
||||
$error->status = 1;
|
||||
$error->message = "File size you are trying to upload is too large!";
|
||||
}
|
||||
}
|
||||
|
||||
if (!$error->status) {
|
||||
$message = Chatify::newMessage([
|
||||
'from_id' => Auth::user()->id,
|
||||
'to_id' => $request['id'],
|
||||
'body' => htmlentities(trim($request['message']), ENT_QUOTES, 'UTF-8'),
|
||||
'attachment' => ($attachment) ? json_encode((object)[
|
||||
'new_name' => $attachment,
|
||||
'old_name' => htmlentities(trim($attachment_title), ENT_QUOTES, 'UTF-8'),
|
||||
]) : null,
|
||||
]);
|
||||
$messageData = Chatify::parseMessage($message);
|
||||
if (Auth::user()->id != $request['id']) {
|
||||
Chatify::push("private-chatify.".$request['id'], 'messaging', [
|
||||
'from_id' => Auth::user()->id,
|
||||
'to_id' => $request['id'],
|
||||
'message' => Chatify::messageCard($messageData, true)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// send the response
|
||||
return Response::json([
|
||||
'status' => '200',
|
||||
'error' => $error,
|
||||
'message' => Chatify::messageCard(@$messageData),
|
||||
'tempID' => $request['temporaryMsgId'],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* fetch [user/group] messages from database
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function fetch(Request $request)
|
||||
{
|
||||
$query = Chatify::fetchMessagesQuery($request['id'])->latest();
|
||||
$messages = $query->paginate($request->per_page ?? $this->perPage);
|
||||
$totalMessages = $messages->total();
|
||||
$lastPage = $messages->lastPage();
|
||||
$response = [
|
||||
'total' => $totalMessages,
|
||||
'last_page' => $lastPage,
|
||||
'last_message_id' => collect($messages->items())->last()->id ?? null,
|
||||
'messages' => '',
|
||||
];
|
||||
|
||||
// if there is no messages yet.
|
||||
if ($totalMessages < 1) {
|
||||
$response['messages'] ='<p class="message-hint center-el"><span>Say \'hi\' and start messaging</span></p>';
|
||||
return Response::json($response);
|
||||
}
|
||||
if (count($messages->items()) < 1) {
|
||||
$response['messages'] = '';
|
||||
return Response::json($response);
|
||||
}
|
||||
$allMessages = null;
|
||||
foreach ($messages->reverse() as $message) {
|
||||
$allMessages .= Chatify::messageCard(
|
||||
Chatify::parseMessage($message)
|
||||
);
|
||||
}
|
||||
$response['messages'] = $allMessages;
|
||||
return Response::json($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make messages as seen
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse|void
|
||||
*/
|
||||
public function seen(Request $request)
|
||||
{
|
||||
// make as seen
|
||||
$seen = Chatify::makeSeen($request['id']);
|
||||
// send the response
|
||||
return Response::json([
|
||||
'status' => $seen,
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get contacts list
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function getContacts(Request $request)
|
||||
{
|
||||
// get all users that received/sent message from/to [Auth user]
|
||||
$users = Message::join('users', function ($join) {
|
||||
$join->on('ch_messages.from_id', '=', 'users.id')
|
||||
->orOn('ch_messages.to_id', '=', 'users.id');
|
||||
})
|
||||
->where(function ($q) {
|
||||
$q->where('ch_messages.from_id', Auth::user()->id)
|
||||
->orWhere('ch_messages.to_id', Auth::user()->id);
|
||||
})
|
||||
->where('users.id','!=',Auth::user()->id)
|
||||
->select('users.*',DB::raw('MAX(ch_messages.created_at) max_created_at'))
|
||||
->orderBy('max_created_at', 'desc')
|
||||
->groupBy('users.id')
|
||||
->paginate($request->per_page ?? $this->perPage);
|
||||
|
||||
$usersList = $users->items();
|
||||
|
||||
if (count($usersList) > 0) {
|
||||
$contacts = '';
|
||||
foreach ($usersList as $user) {
|
||||
$contacts .= Chatify::getContactItem($user);
|
||||
}
|
||||
} else {
|
||||
$contacts = '<p class="message-hint center-el"><span>Your contact list is empty</span></p>';
|
||||
}
|
||||
|
||||
return Response::json([
|
||||
'contacts' => $contacts,
|
||||
'total' => $users->total() ?? 0,
|
||||
'last_page' => $users->lastPage() ?? 1,
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user's list item data
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function updateContactItem(Request $request)
|
||||
{
|
||||
// Get user data
|
||||
$user = User::where('id', $request['user_id'])->first();
|
||||
if(!$user){
|
||||
return Response::json([
|
||||
'message' => 'User not found!',
|
||||
], 401);
|
||||
}
|
||||
$contactItem = Chatify::getContactItem($user);
|
||||
|
||||
// send the response
|
||||
return Response::json([
|
||||
'contactItem' => $contactItem,
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a user in the favorites list
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse|void
|
||||
*/
|
||||
public function favorite(Request $request)
|
||||
{
|
||||
$userId = $request['user_id'];
|
||||
// check action [star/unstar]
|
||||
$favoriteStatus = Chatify::inFavorite($userId) ? 0 : 1;
|
||||
Chatify::makeInFavorite($userId, $favoriteStatus);
|
||||
|
||||
// send the response
|
||||
return Response::json([
|
||||
'status' => @$favoriteStatus,
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get favorites list
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse|void
|
||||
*/
|
||||
public function getFavorites(Request $request)
|
||||
{
|
||||
$favoritesList = null;
|
||||
$favorites = Favorite::where('user_id', Auth::user()->id);
|
||||
foreach ($favorites->get() as $favorite) {
|
||||
// get user data
|
||||
$user = User::where('id', $favorite->favorite_id)->first();
|
||||
$favoritesList .= view('Chatify::layouts.favorite', [
|
||||
'user' => $user,
|
||||
]);
|
||||
}
|
||||
// send the response
|
||||
return Response::json([
|
||||
'count' => $favorites->count(),
|
||||
'favorites' => $favorites->count() > 0
|
||||
? $favoritesList
|
||||
: 0,
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search in messenger
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse|void
|
||||
*/
|
||||
public function search(Request $request)
|
||||
{
|
||||
$getRecords = null;
|
||||
$input = trim(filter_var($request['input']));
|
||||
$records = User::where('id','!=',Auth::user()->id)
|
||||
->where('name', 'LIKE', "%{$input}%")
|
||||
->paginate($request->per_page ?? $this->perPage);
|
||||
foreach ($records->items() as $record) {
|
||||
$getRecords .= view('Chatify::layouts.listItem', [
|
||||
'get' => 'search_item',
|
||||
'user' => Chatify::getUserWithAvatar($record),
|
||||
])->render();
|
||||
}
|
||||
if($records->total() < 1){
|
||||
$getRecords = '<p class="message-hint center-el"><span>Nothing to show.</span></p>';
|
||||
}
|
||||
// send the response
|
||||
return Response::json([
|
||||
'records' => $getRecords,
|
||||
'total' => $records->total(),
|
||||
'last_page' => $records->lastPage()
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get shared photos
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse|void
|
||||
*/
|
||||
public function sharedPhotos(Request $request)
|
||||
{
|
||||
$shared = Chatify::getSharedPhotos($request['user_id']);
|
||||
$sharedPhotos = null;
|
||||
|
||||
// shared with its template
|
||||
for ($i = 0; $i < count($shared); $i++) {
|
||||
$sharedPhotos .= view('Chatify::layouts.listItem', [
|
||||
'get' => 'sharedPhoto',
|
||||
'image' => Chatify::getAttachmentUrl($shared[$i]),
|
||||
])->render();
|
||||
}
|
||||
// send the response
|
||||
return Response::json([
|
||||
'shared' => count($shared) > 0 ? $sharedPhotos : '<p class="message-hint"><span>Nothing shared yet</span></p>',
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete conversation
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function deleteConversation(Request $request)
|
||||
{
|
||||
// delete
|
||||
$delete = Chatify::deleteConversation($request['id']);
|
||||
|
||||
// send the response
|
||||
return Response::json([
|
||||
'deleted' => $delete ? 1 : 0,
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete message
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function deleteMessage(Request $request)
|
||||
{
|
||||
// delete
|
||||
$delete = Chatify::deleteMessage($request['id']);
|
||||
|
||||
// send the response
|
||||
return Response::json([
|
||||
'deleted' => $delete ? 1 : 0,
|
||||
], 200);
|
||||
}
|
||||
|
||||
public function updateSettings(Request $request)
|
||||
{
|
||||
$msg = null;
|
||||
$error = $success = 0;
|
||||
|
||||
// dark mode
|
||||
if ($request['dark_mode']) {
|
||||
$request['dark_mode'] == "dark"
|
||||
? User::where('id', Auth::user()->id)->update(['dark_mode' => 1]) // Make Dark
|
||||
: User::where('id', Auth::user()->id)->update(['dark_mode' => 0]); // Make Light
|
||||
}
|
||||
|
||||
// If messenger color selected
|
||||
if ($request['messengerColor']) {
|
||||
$messenger_color = trim(filter_var($request['messengerColor']));
|
||||
User::where('id', Auth::user()->id)
|
||||
->update(['messenger_color' => $messenger_color]);
|
||||
}
|
||||
// if there is a [file]
|
||||
if ($request->hasFile('avatar')) {
|
||||
// allowed extensions
|
||||
$allowed_images = Chatify::getAllowedImages();
|
||||
|
||||
$file = $request->file('avatar');
|
||||
// check file size
|
||||
if ($file->getSize() < Chatify::getMaxUploadSize()) {
|
||||
if (in_array(strtolower($file->extension()), $allowed_images)) {
|
||||
// delete the older one
|
||||
if (Auth::user()->avatar != config('chatify.user_avatar.default')) {
|
||||
$avatar = Auth::user()->avatar;
|
||||
if (Chatify::storage()->exists($avatar)) {
|
||||
Chatify::storage()->delete($avatar);
|
||||
}
|
||||
}
|
||||
// upload
|
||||
$avatar = Str::uuid() . "." . $file->extension();
|
||||
$update = User::where('id', Auth::user()->id)->update(['avatar' => $avatar]);
|
||||
$file->storeAs(config('chatify.user_avatar.folder'), $avatar, config('chatify.storage_disk_name'));
|
||||
$success = $update ? 1 : 0;
|
||||
} else {
|
||||
$msg = "File extension not allowed!";
|
||||
$error = 1;
|
||||
}
|
||||
} else {
|
||||
$msg = "File size you are trying to upload is too large!";
|
||||
$error = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// send the response
|
||||
return Response::json([
|
||||
'status' => $success ? 1 : 0,
|
||||
'error' => $error ? 1 : 0,
|
||||
'message' => $error ? $msg : 0,
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set user's active status
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function setActiveStatus(Request $request)
|
||||
{
|
||||
$activeStatus = $request['status'] > 0 ? 1 : 0;
|
||||
$status = User::where('id', Auth::user()->id)->update(['active_status' => $activeStatus]);
|
||||
return Response::json([
|
||||
'status' => $status,
|
||||
], 200);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Chatify\Traits\UUID;
|
||||
|
||||
class ChFavorite extends Model
|
||||
{
|
||||
use UUID;
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Chatify\Traits\UUID;
|
||||
|
||||
class ChMessage extends Model
|
||||
{
|
||||
use UUID;
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Chatify\Traits;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
trait UUID
|
||||
{
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
static::creating(function ($model) {
|
||||
$model->{$model->getKeyName()} = (string) Str::uuid();
|
||||
});
|
||||
}
|
||||
|
||||
public function getIncrementing ()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getKeyType ()
|
||||
{
|
||||
return 'string';
|
||||
}
|
||||
}
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
/*app scroll*/
|
||||
.app-scroll::-webkit-scrollbar-thumb,
|
||||
.app-scroll-thin::-webkit-scrollbar-thumb {
|
||||
background: var(--dark-scrollbar-thumb-color);
|
||||
}
|
||||
.app-scroll-thin::-webkit-scrollbar {
|
||||
background: var(--dark-secondary-bg-color);
|
||||
}
|
||||
.app-scroll::-webkit-scrollbar:hover,
|
||||
.app-scroll-thin::-webkit-scrollbar:hover {
|
||||
background: var(--dark-secondary-bg-color);
|
||||
}
|
||||
.messenger {
|
||||
background: var(--dark-primary-bg-color);
|
||||
}
|
||||
.messenger-search[type="text"] {
|
||||
background: var(--dark-secondary-bg-color);
|
||||
color: #fff;
|
||||
}
|
||||
.messenger-search[type="text"]::placeholder {
|
||||
color: #fff;
|
||||
}
|
||||
.messenger-listView {
|
||||
background: var(--dark-primary-bg-color);
|
||||
border: 1px solid var(--dark-border-color);
|
||||
}
|
||||
.messenger-listView-tabs {
|
||||
border-bottom: 1px solid var(--dark-border-color);
|
||||
}
|
||||
.messenger-listView-tabs a:hover,
|
||||
.messenger-listView-tabs a:focus {
|
||||
background-color: var(--dark-secondary-bg-color);
|
||||
}
|
||||
.messenger-favorites div.avatar {
|
||||
border: 2px solid var(--dark-primary-bg-color);
|
||||
}
|
||||
.messenger-list-item:hover {
|
||||
background: var(--dark-secondary-bg-color);
|
||||
}
|
||||
.messenger-messagingView {
|
||||
border-top: 1px solid var(--dark-secondary-bg-color);
|
||||
border-bottom: 1px solid var(--dark-secondary-bg-color);
|
||||
background: var(--dark-messagingView-bg-color);
|
||||
}
|
||||
.m-header-messaging {
|
||||
background: var(--dark-primary-bg-color);
|
||||
}
|
||||
.messenger-infoView {
|
||||
background: var(--dark-primary-bg-color);
|
||||
border: 1px solid var(--dark-border-color);
|
||||
}
|
||||
.messenger-infoView > p {
|
||||
color: #fff;
|
||||
}
|
||||
.divider {
|
||||
border-top: 1px solid var(--dark-border-color);
|
||||
}
|
||||
.messenger-sendCard {
|
||||
background: var(--dark-primary-bg-color);
|
||||
border-top: 1px solid var(--dark-border-color);
|
||||
}
|
||||
.attachment-preview > p {
|
||||
color: #fff;
|
||||
}
|
||||
.m-send {
|
||||
color: #fff;
|
||||
}
|
||||
.m-send::placeholder {
|
||||
color: #fff;
|
||||
}
|
||||
.message-card .message {
|
||||
background: var(--dark-message-card-color);
|
||||
color: #fff;
|
||||
}
|
||||
.m-li-divider {
|
||||
border-bottom: 1px solid var(--dark-border-color);
|
||||
}
|
||||
.m-header a,
|
||||
.m-header a:hover,
|
||||
.m-header a:focus {
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
}
|
||||
.messenger-list-item td p {
|
||||
color: #fff;
|
||||
}
|
||||
.activeStatus {
|
||||
border: 2px solid var(--dark-border-color);
|
||||
}
|
||||
.messenger-list-item:hover .activeStatus {
|
||||
border-color: var(--dark-secondary-bg-color);
|
||||
}
|
||||
.messenger-favorites > div p {
|
||||
color: #ffffff;
|
||||
}
|
||||
.avatar {
|
||||
background-color: var(--dark-secondary-bg-color);
|
||||
border-color: var(--dark-border-color);
|
||||
}
|
||||
.messenger-sendCard svg {
|
||||
color: var(--dark-send-input-icons-color);
|
||||
}
|
||||
.messenger-title {
|
||||
color: #dbdbdb;
|
||||
}
|
||||
.messenger-title > span {
|
||||
background-color: var(--dark-primary-bg-color);
|
||||
}
|
||||
.messenger-title::before {
|
||||
background-color: var(--dark-border-color);
|
||||
}
|
||||
.message-hint span {
|
||||
background: var(--dark-message-hint-bg-color);
|
||||
color: var(--dark-message-hint-color);
|
||||
}
|
||||
.messenger-infoView > nav > p {
|
||||
color: #fff;
|
||||
}
|
||||
/*
|
||||
***********************************************
|
||||
* Placeholder loading
|
||||
***********************************************
|
||||
*/
|
||||
.loadingPlaceholder-body div,
|
||||
.loadingPlaceholder-header tr td div {
|
||||
background: var(--dark-secondary-bg-color);
|
||||
background-image: -webkit-linear-gradient(
|
||||
left,
|
||||
var(--dark-secondary-bg-color) 0%,
|
||||
var(--dark-secondary-bg-color) 20%,
|
||||
var(--dark-secondary-bg-color) 40%,
|
||||
var(--dark-secondary-bg-color) 100%
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
***********************************************
|
||||
* App Modal
|
||||
***********************************************
|
||||
*/
|
||||
|
||||
.app-modal-card {
|
||||
background: var(--dark-modal-bg-color);
|
||||
}
|
||||
.app-modal-header {
|
||||
color: #fff;
|
||||
}
|
||||
.app-modal-body {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.messages .message-time {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.message-card .actions .delete-btn {
|
||||
color: #fff;
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
/*app scroll*/
|
||||
.app-scroll::-webkit-scrollbar-thumb,
|
||||
.app-scroll-thin::-webkit-scrollbar-thumb {
|
||||
background: var(--scrollbar-thumb-color);
|
||||
}
|
||||
.app-scroll-thin::-webkit-scrollbar {
|
||||
background: var(--secondary-bg-color);
|
||||
}
|
||||
.app-scroll::-webkit-scrollbar:hover,
|
||||
.app-scroll-thin::-webkit-scrollbar:hover {
|
||||
background: var(--secondary-bg-color);
|
||||
}
|
||||
|
||||
.messenger {
|
||||
background: var(--primary-bg-color);
|
||||
}
|
||||
.messenger-search[type="text"] {
|
||||
background: var(--secondary-bg-color);
|
||||
color: #333;
|
||||
}
|
||||
.messenger-listView {
|
||||
background: var(--primary-bg-color);
|
||||
border: 1px solid var(--border-color);
|
||||
}
|
||||
.messenger-listView-tabs {
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
.messenger-listView-tabs a:hover,
|
||||
.messenger-listView-tabs a:focus {
|
||||
background-color: var(--secondary-bg-color);
|
||||
}
|
||||
.messenger-favorites div.avatar {
|
||||
border: 2px solid var(--primary-bg-color);
|
||||
}
|
||||
|
||||
.messenger-list-item:hover {
|
||||
background: var(--secondary-bg-color);
|
||||
}
|
||||
.messenger-messagingView {
|
||||
border-top: 1px solid var(--secondary-bg-color);
|
||||
border-bottom: 1px solid var(--secondary-bg-color);
|
||||
background: var(--messagingView-bg-color);
|
||||
}
|
||||
.m-header-messaging {
|
||||
background: var(--primary-bg-color);
|
||||
}
|
||||
.messenger-infoView {
|
||||
background: var(--primary-bg-color);
|
||||
border: 1px solid var(--border-color);
|
||||
}
|
||||
.messenger-infoView > p {
|
||||
color: #000;
|
||||
}
|
||||
.divider {
|
||||
border-top: 1px solid var(--border-color);
|
||||
}
|
||||
.messenger-sendCard {
|
||||
background: var(--primary-bg-color);
|
||||
border-top: 1px solid var(--border-color);
|
||||
}
|
||||
.attachment-preview > p {
|
||||
color: #333;
|
||||
}
|
||||
.m-send {
|
||||
color: #333;
|
||||
}
|
||||
.message-card .message {
|
||||
background: var(--message-card-color);
|
||||
color: #656b75;
|
||||
box-shadow: 0px 6px 11px rgba(18, 67, 105, 0.03);
|
||||
}
|
||||
.m-li-divider {
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
.m-header a,
|
||||
.m-header a:hover,
|
||||
.m-header a:focus {
|
||||
text-decoration: none;
|
||||
color: #202020;
|
||||
}
|
||||
.messenger-list-item td p {
|
||||
color: #3c3c3c;
|
||||
}
|
||||
.messenger-list-item td span {
|
||||
color: #929292;
|
||||
}
|
||||
.activeStatus {
|
||||
border: 2px solid var(--primary-bg-color);
|
||||
}
|
||||
.messenger-list-item:hover .activeStatus {
|
||||
border-color: var(--secondary-bg-color);
|
||||
}
|
||||
.messenger-favorites > div p {
|
||||
color: #4a4a4a;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
background-color: var(--secondary-bg-color);
|
||||
border-color: var(--border-color);
|
||||
}
|
||||
.messenger-sendCard svg {
|
||||
color: var(--send-input-icons-color);
|
||||
}
|
||||
.messenger-title {
|
||||
color: #797979;
|
||||
}
|
||||
.messenger-title > span {
|
||||
background-color: var(--primary-bg-color);
|
||||
}
|
||||
.messenger-title::before {
|
||||
background-color: var(--border-color);
|
||||
}
|
||||
.message-hint span {
|
||||
background: var(--message-hint-bg-color);
|
||||
color: var(--message-hint-color);
|
||||
}
|
||||
/*
|
||||
***********************************************
|
||||
* Placeholder loading
|
||||
***********************************************
|
||||
*/
|
||||
.loadingPlaceholder-body div,
|
||||
.loadingPlaceholder-header tr td div {
|
||||
background: var(--secondary-bg-color);
|
||||
background-image: -webkit-linear-gradient(
|
||||
left,
|
||||
var(--secondary-bg-color) 0%,
|
||||
var(--secondary-bg-color) 20%,
|
||||
var(--secondary-bg-color) 40%,
|
||||
var(--secondary-bg-color) 100%
|
||||
);
|
||||
}
|
||||
.messenger-infoView > nav > p {
|
||||
color: #333;
|
||||
}
|
||||
/*
|
||||
***********************************************
|
||||
* App Modal
|
||||
***********************************************
|
||||
*/
|
||||
|
||||
.app-modal-card {
|
||||
background: var(--modal-bg-color);
|
||||
}
|
||||
.app-modal-header {
|
||||
color: #000;
|
||||
}
|
||||
.app-modal-body {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/*
|
||||
*****************************************
|
||||
* Responsive Design
|
||||
*****************************************
|
||||
*/
|
||||
@media (max-width: 1060px) {
|
||||
.messenger-infoView {
|
||||
box-shadow: 0px 0px 20px rgba(18, 67, 105, 0.06);
|
||||
}
|
||||
}
|
||||
@media (max-width: 980px) {
|
||||
.messenger-listView {
|
||||
box-shadow: 0px 0px 20px rgba(18, 67, 105, 0.06);
|
||||
}
|
||||
}
|
||||
+1184
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
+288
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
****************************************************************************
|
||||
* Text Area auto resize
|
||||
****************************************************************************
|
||||
*/
|
||||
(function (global, factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(['module', 'exports'], factory);
|
||||
} else if (typeof exports !== "undefined") {
|
||||
factory(module, exports);
|
||||
} else {
|
||||
var mod = {
|
||||
exports: {}
|
||||
};
|
||||
factory(mod, mod.exports);
|
||||
global.autosize = mod.exports;
|
||||
}
|
||||
})(this, function (module, exports) {
|
||||
'use strict';
|
||||
|
||||
var map = typeof Map === "function" ? new Map() : function () {
|
||||
var keys = [];
|
||||
var values = [];
|
||||
|
||||
return {
|
||||
has: function has(key) {
|
||||
return keys.indexOf(key) > -1;
|
||||
},
|
||||
get: function get(key) {
|
||||
return values[keys.indexOf(key)];
|
||||
},
|
||||
set: function set(key, value) {
|
||||
if (keys.indexOf(key) === -1) {
|
||||
keys.push(key);
|
||||
values.push(value);
|
||||
}
|
||||
},
|
||||
delete: function _delete(key) {
|
||||
var index = keys.indexOf(key);
|
||||
if (index > -1) {
|
||||
keys.splice(index, 1);
|
||||
values.splice(index, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
}();
|
||||
|
||||
var createEvent = function createEvent(name) {
|
||||
return new Event(name, { bubbles: true });
|
||||
};
|
||||
try {
|
||||
new Event('test');
|
||||
} catch (e) {
|
||||
// IE does not support `new Event()`
|
||||
createEvent = function createEvent(name) {
|
||||
var evt = document.createEvent('Event');
|
||||
evt.initEvent(name, true, false);
|
||||
return evt;
|
||||
};
|
||||
}
|
||||
|
||||
function assign(ta) {
|
||||
if (!ta || !ta.nodeName || ta.nodeName !== 'TEXTAREA' || map.has(ta)) return;
|
||||
|
||||
var heightOffset = null;
|
||||
var clientWidth = null;
|
||||
var cachedHeight = null;
|
||||
|
||||
function init() {
|
||||
var style = window.getComputedStyle(ta, null);
|
||||
|
||||
if (style.resize === 'vertical') {
|
||||
ta.style.resize = 'none';
|
||||
} else if (style.resize === 'both') {
|
||||
ta.style.resize = 'horizontal';
|
||||
}
|
||||
|
||||
if (style.boxSizing === 'content-box') {
|
||||
heightOffset = -(parseFloat(style.paddingTop) + parseFloat(style.paddingBottom));
|
||||
} else {
|
||||
heightOffset = parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth);
|
||||
}
|
||||
// Fix when a textarea is not on document body and heightOffset is Not a Number
|
||||
if (isNaN(heightOffset)) {
|
||||
heightOffset = 0;
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
function changeOverflow(value) {
|
||||
{
|
||||
// Chrome/Safari-specific fix:
|
||||
// When the textarea y-overflow is hidden, Chrome/Safari do not reflow the text to account for the space
|
||||
// made available by removing the scrollbar. The following forces the necessary text reflow.
|
||||
var width = ta.style.width;
|
||||
ta.style.width = '0px';
|
||||
// Force reflow:
|
||||
/* jshint ignore:start */
|
||||
ta.offsetWidth;
|
||||
/* jshint ignore:end */
|
||||
ta.style.width = width;
|
||||
}
|
||||
|
||||
ta.style.overflowY = value;
|
||||
}
|
||||
|
||||
function getParentOverflows(el) {
|
||||
var arr = [];
|
||||
|
||||
while (el && el.parentNode && el.parentNode instanceof Element) {
|
||||
if (el.parentNode.scrollTop) {
|
||||
arr.push({
|
||||
node: el.parentNode,
|
||||
scrollTop: el.parentNode.scrollTop
|
||||
});
|
||||
}
|
||||
el = el.parentNode;
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
function resize() {
|
||||
if (ta.scrollHeight === 0) {
|
||||
// If the scrollHeight is 0, then the element probably has display:none or is detached from the DOM.
|
||||
return;
|
||||
}
|
||||
|
||||
var overflows = getParentOverflows(ta);
|
||||
var docTop = document.documentElement && document.documentElement.scrollTop; // Needed for Mobile IE (ticket #240)
|
||||
|
||||
ta.style.height = '';
|
||||
ta.style.height = ta.scrollHeight + heightOffset + 'px';
|
||||
|
||||
// used to check if an update is actually necessary on window.resize
|
||||
clientWidth = ta.clientWidth;
|
||||
|
||||
// prevents scroll-position jumping
|
||||
overflows.forEach(function (el) {
|
||||
el.node.scrollTop = el.scrollTop;
|
||||
});
|
||||
|
||||
if (docTop) {
|
||||
document.documentElement.scrollTop = docTop;
|
||||
}
|
||||
}
|
||||
|
||||
function update() {
|
||||
resize();
|
||||
|
||||
var styleHeight = Math.round(parseFloat(ta.style.height));
|
||||
var computed = window.getComputedStyle(ta, null);
|
||||
|
||||
// Using offsetHeight as a replacement for computed.height in IE, because IE does not account use of border-box
|
||||
var actualHeight = computed.boxSizing === 'content-box' ? Math.round(parseFloat(computed.height)) : ta.offsetHeight;
|
||||
|
||||
// The actual height not matching the style height (set via the resize method) indicates that
|
||||
// the max-height has been exceeded, in which case the overflow should be allowed.
|
||||
if (actualHeight < styleHeight) {
|
||||
if (computed.overflowY === 'hidden') {
|
||||
changeOverflow('scroll');
|
||||
resize();
|
||||
actualHeight = computed.boxSizing === 'content-box' ? Math.round(parseFloat(window.getComputedStyle(ta, null).height)) : ta.offsetHeight;
|
||||
}
|
||||
} else {
|
||||
// Normally keep overflow set to hidden, to avoid flash of scrollbar as the textarea expands.
|
||||
if (computed.overflowY !== 'hidden') {
|
||||
changeOverflow('hidden');
|
||||
resize();
|
||||
actualHeight = computed.boxSizing === 'content-box' ? Math.round(parseFloat(window.getComputedStyle(ta, null).height)) : ta.offsetHeight;
|
||||
}
|
||||
}
|
||||
|
||||
if (cachedHeight !== actualHeight) {
|
||||
cachedHeight = actualHeight;
|
||||
var evt = createEvent('autosize:resized');
|
||||
try {
|
||||
ta.dispatchEvent(evt);
|
||||
} catch (err) {
|
||||
// Firefox will throw an error on dispatchEvent for a detached element
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=889376
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var pageResize = function pageResize() {
|
||||
if (ta.clientWidth !== clientWidth) {
|
||||
update();
|
||||
}
|
||||
};
|
||||
|
||||
var destroy = function (style) {
|
||||
window.removeEventListener('resize', pageResize, false);
|
||||
ta.removeEventListener('input', update, false);
|
||||
ta.removeEventListener('keyup', update, false);
|
||||
ta.removeEventListener('autosize:destroy', destroy, false);
|
||||
ta.removeEventListener('autosize:update', update, false);
|
||||
|
||||
Object.keys(style).forEach(function (key) {
|
||||
ta.style[key] = style[key];
|
||||
});
|
||||
|
||||
map.delete(ta);
|
||||
}.bind(ta, {
|
||||
height: ta.style.height,
|
||||
resize: ta.style.resize,
|
||||
overflowY: ta.style.overflowY,
|
||||
overflowX: ta.style.overflowX,
|
||||
wordWrap: ta.style.wordWrap
|
||||
});
|
||||
|
||||
ta.addEventListener('autosize:destroy', destroy, false);
|
||||
|
||||
// IE9 does not fire onpropertychange or oninput for deletions,
|
||||
// so binding to onkeyup to catch most of those events.
|
||||
// There is no way that I know of to detect something like 'cut' in IE9.
|
||||
if ('onpropertychange' in ta && 'oninput' in ta) {
|
||||
ta.addEventListener('keyup', update, false);
|
||||
}
|
||||
|
||||
window.addEventListener('resize', pageResize, false);
|
||||
ta.addEventListener('input', update, false);
|
||||
ta.addEventListener('autosize:update', update, false);
|
||||
ta.style.overflowX = 'hidden';
|
||||
ta.style.wordWrap = 'break-word';
|
||||
|
||||
map.set(ta, {
|
||||
destroy: destroy,
|
||||
update: update
|
||||
});
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
function destroy(ta) {
|
||||
var methods = map.get(ta);
|
||||
if (methods) {
|
||||
methods.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
function update(ta) {
|
||||
var methods = map.get(ta);
|
||||
if (methods) {
|
||||
methods.update();
|
||||
}
|
||||
}
|
||||
|
||||
var autosize = null;
|
||||
|
||||
// Do nothing in Node.js environment and IE8 (or lower)
|
||||
if (typeof window === 'undefined' || typeof window.getComputedStyle !== 'function') {
|
||||
autosize = function autosize(el) {
|
||||
return el;
|
||||
};
|
||||
autosize.destroy = function (el) {
|
||||
return el;
|
||||
};
|
||||
autosize.update = function (el) {
|
||||
return el;
|
||||
};
|
||||
} else {
|
||||
autosize = function autosize(el, options) {
|
||||
if (el) {
|
||||
Array.prototype.forEach.call(el.length ? el : [el], function (x) {
|
||||
return assign(x, options);
|
||||
});
|
||||
}
|
||||
return el;
|
||||
};
|
||||
autosize.destroy = function (el) {
|
||||
if (el) {
|
||||
Array.prototype.forEach.call(el.length ? el : [el], destroy);
|
||||
}
|
||||
return el;
|
||||
};
|
||||
autosize.update = function (el) {
|
||||
if (el) {
|
||||
Array.prototype.forEach.call(el.length ? el : [el], update);
|
||||
}
|
||||
return el;
|
||||
};
|
||||
}
|
||||
|
||||
exports.default = autosize;
|
||||
module.exports = exports['default'];
|
||||
});
|
||||
+1711
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
+41
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* changes date string to time ago string.
|
||||
* @param dateString - The date string to convert to a time ago string.
|
||||
* @returns A string that tells the user how long ago the date was.
|
||||
*/
|
||||
function dateStringToTimeAgo(dateString) {
|
||||
const now = new Date();
|
||||
const date = new Date(dateString);
|
||||
const seconds = Math.floor((now - date) / 1000);
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const hours = Math.floor(minutes / 60);
|
||||
const days = Math.floor(hours / 24);
|
||||
const weeks = Math.floor(days / 7);
|
||||
if (seconds < 60) {
|
||||
return "just now";
|
||||
} else if (minutes < 60) {
|
||||
return `${minutes}m ago`;
|
||||
} else if (hours < 24) {
|
||||
return `${hours}h ago`;
|
||||
} else if (days < 7) {
|
||||
return `${days}d ago`;
|
||||
} else {
|
||||
return `${weeks}w ago`;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* It returns a function that, when invoked, will wait for a specified amount of time before executing
|
||||
* the original function.
|
||||
* @param callback - The function to be executed after the delay.
|
||||
* @param delay - The amount of time to wait before calling the callback.
|
||||
* @returns A function that will call the callback function after a delay.
|
||||
*/
|
||||
function debounce(callback, delay) {
|
||||
let timerId;
|
||||
return function (...args) {
|
||||
clearTimeout(timerId);
|
||||
timerId = setTimeout(() => {
|
||||
callback.apply(this, args);
|
||||
}, delay);
|
||||
};
|
||||
}
|
||||
Binary file not shown.
+124
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|-------------------------------------
|
||||
| Messenger display name
|
||||
|-------------------------------------
|
||||
*/
|
||||
'name' => env('CHATIFY_NAME', 'Chatify Messenger'),
|
||||
|
||||
/*
|
||||
|-------------------------------------
|
||||
| The disk on which to store added
|
||||
| files and derived images by default.
|
||||
|-------------------------------------
|
||||
*/
|
||||
'storage_disk_name' => env('CHATIFY_STORAGE_DISK', 'public'),
|
||||
|
||||
/*
|
||||
|-------------------------------------
|
||||
| Routes configurations
|
||||
|-------------------------------------
|
||||
*/
|
||||
'routes' => [
|
||||
'custom' => env('CHATIFY_CUSTOM_ROUTES', false),
|
||||
'prefix' => env('CHATIFY_ROUTES_PREFIX', 'chatify'),
|
||||
'middleware' => env('CHATIFY_ROUTES_MIDDLEWARE', ['web','auth']),
|
||||
'namespace' => env('CHATIFY_ROUTES_NAMESPACE', 'Chatify\Http\Controllers'),
|
||||
],
|
||||
'api_routes' => [
|
||||
'prefix' => env('CHATIFY_API_ROUTES_PREFIX', 'chatify/api'),
|
||||
'middleware' => env('CHATIFY_API_ROUTES_MIDDLEWARE', ['api']),
|
||||
'namespace' => env('CHATIFY_API_ROUTES_NAMESPACE', 'Chatify\Http\Controllers\Api'),
|
||||
],
|
||||
|
||||
/*
|
||||
|-------------------------------------
|
||||
| Pusher API credentials
|
||||
|-------------------------------------
|
||||
*/
|
||||
'pusher' => [
|
||||
'debug' => env('APP_DEBUG', false),
|
||||
'key' => env('PUSHER_APP_KEY'),
|
||||
'secret' => env('PUSHER_APP_SECRET'),
|
||||
'app_id' => env('PUSHER_APP_ID'),
|
||||
'options' => [
|
||||
'cluster' => env('PUSHER_APP_CLUSTER', 'mt1'),
|
||||
'host' => env('PUSHER_HOST') ?: 'api-'.env('PUSHER_APP_CLUSTER', 'mt1').'.pusher.com',
|
||||
'port' => env('PUSHER_PORT', 443),
|
||||
'scheme' => env('PUSHER_SCHEME', 'https'),
|
||||
'encrypted' => true,
|
||||
'useTLS' => env('PUSHER_SCHEME', 'https') === 'https',
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|-------------------------------------
|
||||
| User Avatar
|
||||
|-------------------------------------
|
||||
*/
|
||||
'user_avatar' => [
|
||||
'folder' => 'users-avatar',
|
||||
'default' => 'avatar.png',
|
||||
],
|
||||
|
||||
/*
|
||||
|-------------------------------------
|
||||
| Gravatar
|
||||
|
|
||||
| imageset property options:
|
||||
| [ 404 | mp | identicon (default) | monsterid | wavatar ]
|
||||
|-------------------------------------
|
||||
*/
|
||||
'gravatar' => [
|
||||
'enabled' => true,
|
||||
'image_size' => 200,
|
||||
'imageset' => 'identicon'
|
||||
],
|
||||
|
||||
/*
|
||||
|-------------------------------------
|
||||
| Attachments
|
||||
|-------------------------------------
|
||||
*/
|
||||
'attachments' => [
|
||||
'folder' => 'attachments',
|
||||
'download_route_name' => 'attachments.download',
|
||||
'allowed_images' => (array) ['png','jpg','jpeg','gif'],
|
||||
'allowed_files' => (array) ['zip','rar','txt'],
|
||||
'max_upload_size' => env('CHATIFY_MAX_FILE_SIZE', 150), // MB
|
||||
],
|
||||
|
||||
/*
|
||||
|-------------------------------------
|
||||
| Messenger's colors
|
||||
|-------------------------------------
|
||||
*/
|
||||
'colors' => (array) [
|
||||
'#2180f3',
|
||||
'#2196F3',
|
||||
'#00BCD4',
|
||||
'#3F51B5',
|
||||
'#673AB7',
|
||||
'#4CAF50',
|
||||
'#FFC107',
|
||||
'#FF9800',
|
||||
'#ff2522',
|
||||
'#9C27B0',
|
||||
],
|
||||
/*
|
||||
|-------------------------------------
|
||||
| Sounds
|
||||
| You can enable/disable the sounds and
|
||||
| change sound's name/path placed at
|
||||
| `public/` directory of your app.
|
||||
|
|
||||
|-------------------------------------
|
||||
*/
|
||||
'sounds' => [
|
||||
'enabled' => true,
|
||||
'public_path' => 'sounds/chatify',
|
||||
'new_message' => 'new-message-sound.mp3',
|
||||
]
|
||||
];
|
||||
Vendored
+35
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddActiveStatusToUsers extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
// if not exist, add the new column
|
||||
if (!Schema::hasColumn('users', 'active_status')) {
|
||||
$table->boolean('active_status')->default(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn('active_status');
|
||||
});
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddAvatarToUsers extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
// if not exist, add the new column
|
||||
if (!Schema::hasColumn('users', 'avatar')) {
|
||||
$table->string('avatar')->default(config('chatify.user_avatar.default'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn('avatar');
|
||||
});
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddDarkModeToUsers extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
// if not exist, add the new column
|
||||
if (!Schema::hasColumn('users', 'dark_mode')) {
|
||||
$table->boolean('dark_mode')->default(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn('dark_mode');
|
||||
});
|
||||
}
|
||||
}
|
||||
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddMessengerColorToUsers extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
if (!Schema::hasColumn('users', 'messenger_color')) {
|
||||
$table->string('messenger_color')->nullable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn('messenger_color');
|
||||
});
|
||||
}
|
||||
}
|
||||
Vendored
+33
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateChatifyFavoritesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('ch_favorites', function (Blueprint $table) {
|
||||
$table->uuid('id')->primary();
|
||||
$table->bigInteger('user_id');
|
||||
$table->bigInteger('favorite_id');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('ch_favorites');
|
||||
}
|
||||
}
|
||||
Vendored
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateChatifyMessagesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('ch_messages', function (Blueprint $table) {
|
||||
$table->uuid('id')->primary();
|
||||
$table->bigInteger('from_id');
|
||||
$table->bigInteger('to_id');
|
||||
$table->string('body',5000)->nullable();
|
||||
$table->string('attachment')->nullable();
|
||||
$table->boolean('seen')->default(false);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('ch_messages');
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
/**
|
||||
* Authentication for pusher private channels
|
||||
*/
|
||||
Route::post('/chat/auth', 'MessagesController@pusherAuth')->name('api.pusher.auth');
|
||||
|
||||
/**
|
||||
* Fetch info for specific id [user/group]
|
||||
*/
|
||||
Route::post('/idInfo', 'MessagesController@idFetchData')->name('api.idInfo');
|
||||
|
||||
/**
|
||||
* Send message route
|
||||
*/
|
||||
Route::post('/sendMessage', 'MessagesController@send')->name('api.send.message');
|
||||
|
||||
/**
|
||||
* Fetch messages
|
||||
*/
|
||||
Route::post('/fetchMessages', 'MessagesController@fetch')->name('api.fetch.messages');
|
||||
|
||||
/**
|
||||
* Download attachments route to create a downloadable links
|
||||
*/
|
||||
Route::get('/download/{fileName}', 'MessagesController@download')->name('api.'.config('chatify.attachments.download_route_name'));
|
||||
|
||||
/**
|
||||
* Make messages as seen
|
||||
*/
|
||||
Route::post('/makeSeen', 'MessagesController@seen')->name('api.messages.seen');
|
||||
|
||||
/**
|
||||
* Get contacts
|
||||
*/
|
||||
Route::get('/getContacts', 'MessagesController@getContacts')->name('api.contacts.get');
|
||||
|
||||
/**
|
||||
* Star in favorite list
|
||||
*/
|
||||
Route::post('/star', 'MessagesController@favorite')->name('api.star');
|
||||
|
||||
/**
|
||||
* get favorites list
|
||||
*/
|
||||
Route::post('/favorites', 'MessagesController@getFavorites')->name('api.favorites');
|
||||
|
||||
/**
|
||||
* Search in messenger
|
||||
*/
|
||||
Route::get('/search', 'MessagesController@search')->name('api.search');
|
||||
|
||||
/**
|
||||
* Get shared photos
|
||||
*/
|
||||
Route::post('/shared', 'MessagesController@sharedPhotos')->name('api.shared');
|
||||
|
||||
/**
|
||||
* Delete Conversation
|
||||
*/
|
||||
Route::post('/deleteConversation', 'MessagesController@deleteConversation')->name('api.conversation.delete');
|
||||
|
||||
/**
|
||||
* Delete Conversation
|
||||
*/
|
||||
Route::post('/updateSettings', 'MessagesController@updateSettings')->name('api.avatar.update');
|
||||
|
||||
/**
|
||||
* Set active status
|
||||
*/
|
||||
Route::post('/setActiveStatus', 'MessagesController@setActiveStatus')->name('api.activeStatus.set');
|
||||
|
||||
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
/**
|
||||
* -----------------------------------------------------------------
|
||||
* NOTE : There is two routes has a name (user & group),
|
||||
* any change in these two route's name may cause an issue
|
||||
* if not modified in all places that used in (e.g Chatify class,
|
||||
* Controllers, chatify javascript file...).
|
||||
* -----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
/*
|
||||
* This is the main app route [Chatify Messenger]
|
||||
*/
|
||||
Route::get('/', 'MessagesController@index')->name(config('chatify.routes.prefix'));
|
||||
|
||||
/**
|
||||
* Fetch info for specific id [user/group]
|
||||
*/
|
||||
Route::post('/idInfo', 'MessagesController@idFetchData');
|
||||
|
||||
/**
|
||||
* Send message route
|
||||
*/
|
||||
Route::post('/sendMessage', 'MessagesController@send')->name('send.message');
|
||||
|
||||
/**
|
||||
* Fetch messages
|
||||
*/
|
||||
Route::post('/fetchMessages', 'MessagesController@fetch')->name('fetch.messages');
|
||||
|
||||
/**
|
||||
* Download attachments route to create a downloadable links
|
||||
*/
|
||||
Route::get('/download/{fileName}', 'MessagesController@download')->name(config('chatify.attachments.download_route_name'));
|
||||
|
||||
/**
|
||||
* Authentication for pusher private channels
|
||||
*/
|
||||
Route::post('/chat/auth', 'MessagesController@pusherAuth')->name('pusher.auth');
|
||||
|
||||
/**
|
||||
* Make messages as seen
|
||||
*/
|
||||
Route::post('/makeSeen', 'MessagesController@seen')->name('messages.seen');
|
||||
|
||||
/**
|
||||
* Get contacts
|
||||
*/
|
||||
Route::get('/getContacts', 'MessagesController@getContacts')->name('contacts.get');
|
||||
|
||||
/**
|
||||
* Update contact item data
|
||||
*/
|
||||
Route::post('/updateContacts', 'MessagesController@updateContactItem')->name('contacts.update');
|
||||
|
||||
|
||||
/**
|
||||
* Star in favorite list
|
||||
*/
|
||||
Route::post('/star', 'MessagesController@favorite')->name('star');
|
||||
|
||||
/**
|
||||
* get favorites list
|
||||
*/
|
||||
Route::post('/favorites', 'MessagesController@getFavorites')->name('favorites');
|
||||
|
||||
/**
|
||||
* Search in messenger
|
||||
*/
|
||||
Route::get('/search', 'MessagesController@search')->name('search');
|
||||
|
||||
/**
|
||||
* Get shared photos
|
||||
*/
|
||||
Route::post('/shared', 'MessagesController@sharedPhotos')->name('shared');
|
||||
|
||||
/**
|
||||
* Delete Conversation
|
||||
*/
|
||||
Route::post('/deleteConversation', 'MessagesController@deleteConversation')->name('conversation.delete');
|
||||
|
||||
/**
|
||||
* Delete Message
|
||||
*/
|
||||
Route::post('/deleteMessage', 'MessagesController@deleteMessage')->name('message.delete');
|
||||
|
||||
/**
|
||||
* Update setting
|
||||
*/
|
||||
Route::post('/updateSettings', 'MessagesController@updateSettings')->name('avatar.update');
|
||||
|
||||
/**
|
||||
* Set active status
|
||||
*/
|
||||
Route::post('/setActiveStatus', 'MessagesController@setActiveStatus')->name('activeStatus.set');
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* [Group] view by id
|
||||
*/
|
||||
Route::get('/group/{id}', 'MessagesController@index')->name('group');
|
||||
|
||||
/*
|
||||
* user view by id.
|
||||
* Note : If you added routes after the [User] which is the below one,
|
||||
* it will considered as user id.
|
||||
*
|
||||
* e.g. - The commented routes below :
|
||||
*/
|
||||
// Route::get('/route', function(){ return 'Munaf'; }); // works as a route
|
||||
Route::get('/{id}', 'MessagesController@index')->name('user');
|
||||
// Route::get('/route', function(){ return 'Munaf'; }); // works as a user id
|
||||
@@ -0,0 +1,8 @@
|
||||
<div class="favorite-list-item">
|
||||
@if($user)
|
||||
<div data-id="{{ $user->id }}" data-action="0" class="avatar av-m"
|
||||
style="background-image: url('{{ Chatify::getUserWithAvatar($user)->avatar }}');">
|
||||
</div>
|
||||
<p>{{ strlen($user->name) > 5 ? substr($user->name,0,6).'..' : $user->name }}</p>
|
||||
@endif
|
||||
</div>
|
||||
@@ -0,0 +1,17 @@
|
||||
<script src="https://js.pusher.com/7.2.0/pusher.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@joeattardi/[email protected]/dist/index.min.js"></script>
|
||||
<script >
|
||||
// Gloabl Chatify variables from PHP to JS
|
||||
window.chatify = {
|
||||
name: "{{ config('chatify.name') }}",
|
||||
sounds: {!! json_encode(config('chatify.sounds')) !!},
|
||||
allowedImages: {!! json_encode(config('chatify.attachments.allowed_images')) !!},
|
||||
allowedFiles: {!! json_encode(config('chatify.attachments.allowed_files')) !!},
|
||||
maxUploadSize: {{ Chatify::getMaxUploadSize() }},
|
||||
pusher: {!! json_encode(config('chatify.pusher')) !!},
|
||||
pusherAuthEndpoint: '{{route("pusher.auth")}}'
|
||||
};
|
||||
window.chatify.allAllowedExtensions = chatify.allowedImages.concat(chatify.allowedFiles);
|
||||
</script>
|
||||
<script src="{{ asset('js/chatify/utils.js') }}"></script>
|
||||
<script src="{{ asset('js/chatify/code.js') }}"></script>
|
||||
@@ -0,0 +1,30 @@
|
||||
<title>{{ config('chatify.name') }}</title>
|
||||
|
||||
{{-- Meta tags --}}
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="id" content="{{ $id }}">
|
||||
<meta name="messenger-color" content="{{ $messengerColor }}">
|
||||
<meta name="messenger-theme" content="{{ $dark_mode }}">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
<meta name="url" content="{{ url('').'/'.config('chatify.routes.prefix') }}" data-user="{{ Auth::user()->id }}">
|
||||
|
||||
{{-- scripts --}}
|
||||
<script
|
||||
src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script src="{{ asset('js/chatify/font.awesome.min.js') }}"></script>
|
||||
<script src="{{ asset('js/chatify/autosize.js') }}"></script>
|
||||
<script src="{{ asset('js/app.js') }}"></script>
|
||||
<script src='https://unpkg.com/[email protected]/nprogress.js'></script>
|
||||
|
||||
{{-- styles --}}
|
||||
<link rel='stylesheet' href='https://unpkg.com/[email protected]/nprogress.css'/>
|
||||
<link href="{{ asset('css/chatify/style.css') }}" rel="stylesheet" />
|
||||
<link href="{{ asset('css/chatify/'.$dark_mode.'.mode.css') }}" rel="stylesheet" />
|
||||
<link href="{{ asset('css/app.css') }}" rel="stylesheet" />
|
||||
|
||||
{{-- Setting messenger primary color to css --}}
|
||||
<style>
|
||||
:root {
|
||||
--primary-color: {{ $messengerColor }};
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,11 @@
|
||||
{{-- user info and avatar --}}
|
||||
<div class="avatar av-l chatify-d-flex"></div>
|
||||
<p class="info-name">{{ config('chatify.name') }}</p>
|
||||
<div class="messenger-infoView-btns">
|
||||
<a href="#" class="danger delete-conversation">Delete Conversation</a>
|
||||
</div>
|
||||
{{-- shared photos --}}
|
||||
<div class="messenger-infoView-shared">
|
||||
<p class="messenger-title"><span>Shared Photos</span></p>
|
||||
<div class="shared-photos-list"></div>
|
||||
</div>
|
||||
@@ -0,0 +1,90 @@
|
||||
{{-- -------------------- Saved Messages -------------------- --}}
|
||||
@if($get == 'saved')
|
||||
<table class="messenger-list-item" data-contact="{{ Auth::user()->id }}">
|
||||
<tr data-action="0">
|
||||
{{-- Avatar side --}}
|
||||
<td>
|
||||
<div class="saved-messages avatar av-m">
|
||||
<span class="far fa-bookmark"></span>
|
||||
</div>
|
||||
</td>
|
||||
{{-- center side --}}
|
||||
<td>
|
||||
<p data-id="{{ Auth::user()->id }}" data-type="user">Saved Messages <span>You</span></p>
|
||||
<span>Save messages secretly</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@endif
|
||||
|
||||
{{-- -------------------- Contact list -------------------- --}}
|
||||
@if($get == 'users' && !!$lastMessage)
|
||||
<?php
|
||||
$lastMessageBody = mb_convert_encoding($lastMessage->body, 'UTF-8', 'UTF-8');
|
||||
$lastMessageBody = strlen($lastMessageBody) > 30 ? mb_substr($lastMessageBody, 0, 30, 'UTF-8').'..' : $lastMessageBody;
|
||||
?>
|
||||
<table class="messenger-list-item" data-contact="{{ $user->id }}">
|
||||
<tr data-action="0">
|
||||
{{-- Avatar side --}}
|
||||
<td style="position: relative">
|
||||
@if($user->active_status)
|
||||
<span class="activeStatus"></span>
|
||||
@endif
|
||||
<div class="avatar av-m"
|
||||
style="background-image: url('{{ $user->avatar }}');">
|
||||
</div>
|
||||
</td>
|
||||
{{-- center side --}}
|
||||
<td>
|
||||
<p data-id="{{ $user->id }}" data-type="user">
|
||||
{{ strlen($user->name) > 12 ? trim(substr($user->name,0,12)).'..' : $user->name }}
|
||||
<span class="contact-item-time" data-time="{{$lastMessage->created_at}}">{{ $lastMessage->timeAgo }}</span></p>
|
||||
<span>
|
||||
{{-- Last Message user indicator --}}
|
||||
{!!
|
||||
$lastMessage->from_id == Auth::user()->id
|
||||
? '<span class="lastMessageIndicator">You :</span>'
|
||||
: ''
|
||||
!!}
|
||||
{{-- Last message body --}}
|
||||
@if($lastMessage->attachment == null)
|
||||
{!!
|
||||
$lastMessageBody
|
||||
!!}
|
||||
@else
|
||||
<span class="fas fa-file"></span> Attachment
|
||||
@endif
|
||||
</span>
|
||||
{{-- New messages counter --}}
|
||||
{!! $unseenCounter > 0 ? "<b>".$unseenCounter."</b>" : '' !!}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@endif
|
||||
|
||||
{{-- -------------------- Search Item -------------------- --}}
|
||||
@if($get == 'search_item')
|
||||
<table class="messenger-list-item" data-contact="{{ $user->id }}">
|
||||
<tr data-action="0">
|
||||
{{-- Avatar side --}}
|
||||
<td>
|
||||
<div class="avatar av-m"
|
||||
style="background-image: url('{{ $user->avatar }}');">
|
||||
</div>
|
||||
</td>
|
||||
{{-- center side --}}
|
||||
<td>
|
||||
<p data-id="{{ $user->id }}" data-type="user">
|
||||
{{ strlen($user->name) > 12 ? trim(substr($user->name,0,12)).'..' : $user->name }}
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
</table>
|
||||
@endif
|
||||
|
||||
{{-- -------------------- Shared photos Item -------------------- --}}
|
||||
@if($get == 'sharedPhoto')
|
||||
<div class="shared-photo chat-image" style="background-image: url('{{ $image }}')"></div>
|
||||
@endif
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
$seenIcon = (!!$seen ? 'check-double' : 'check');
|
||||
$timeAndSeen = "<span data-time='$created_at' class='message-time'>
|
||||
".($isSender ? "<span class='fas fa-$seenIcon' seen'></span>" : '' )." <span class='time'>$timeAgo</span>
|
||||
</span>";
|
||||
?>
|
||||
|
||||
<div class="message-card @if($isSender) mc-sender @endif" data-id="{{ $id }}">
|
||||
{{-- Delete Message Button --}}
|
||||
@if ($isSender)
|
||||
<div class="actions">
|
||||
<i class="fas fa-trash delete-btn" data-id="{{ $id }}"></i>
|
||||
</div>
|
||||
@endif
|
||||
{{-- Card --}}
|
||||
<div class="message-card-content">
|
||||
@if (@$attachment->type != 'image' || $message)
|
||||
<div class="message">
|
||||
{!! ($message == null && $attachment != null && @$attachment->type != 'file') ? $attachment->title : nl2br($message) !!}
|
||||
{!! $timeAndSeen !!}
|
||||
{{-- If attachment is a file --}}
|
||||
@if(@$attachment->type == 'file')
|
||||
<a href="{{ route(config('chatify.attachments.download_route_name'), ['fileName'=>$attachment->file]) }}" class="file-download">
|
||||
<span class="fas fa-file"></span> {{$attachment->title}}</a>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
@if(@$attachment->type == 'image')
|
||||
<div class="image-wrapper" style="text-align: {{$isSender ? 'end' : 'start'}}">
|
||||
<div class="image-file chat-image" style="background-image: url('{{ Chatify::getAttachmentUrl($attachment->file) }}')">
|
||||
<div>{{ $attachment->title }}</div>
|
||||
</div>
|
||||
<div style="margin-bottom:5px">
|
||||
{!! $timeAndSeen !!}
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,73 @@
|
||||
{{-- ---------------------- Image modal box ---------------------- --}}
|
||||
<div id="imageModalBox" class="imageModal">
|
||||
<span class="imageModal-close">×</span>
|
||||
<img class="imageModal-content" id="imageModalBoxSrc">
|
||||
</div>
|
||||
|
||||
{{-- ---------------------- Delete Modal ---------------------- --}}
|
||||
<div class="app-modal" data-name="delete">
|
||||
<div class="app-modal-container">
|
||||
<div class="app-modal-card" data-name="delete" data-modal='0'>
|
||||
<div class="app-modal-header">Are you sure you want to delete this?</div>
|
||||
<div class="app-modal-body">You can not undo this action</div>
|
||||
<div class="app-modal-footer">
|
||||
<a href="javascript:void(0)" class="app-btn cancel">Cancel</a>
|
||||
<a href="javascript:void(0)" class="app-btn a-btn-danger delete">Delete</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{-- ---------------------- Alert Modal ---------------------- --}}
|
||||
<div class="app-modal" data-name="alert">
|
||||
<div class="app-modal-container">
|
||||
<div class="app-modal-card" data-name="alert" data-modal='0'>
|
||||
<div class="app-modal-header"></div>
|
||||
<div class="app-modal-body"></div>
|
||||
<div class="app-modal-footer">
|
||||
<a href="javascript:void(0)" class="app-btn cancel">Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{-- ---------------------- Settings Modal ---------------------- --}}
|
||||
<div class="app-modal" data-name="settings">
|
||||
<div class="app-modal-container">
|
||||
<div class="app-modal-card" data-name="settings" data-modal='0'>
|
||||
<form id="update-settings" action="{{ route('avatar.update') }}" enctype="multipart/form-data" method="POST">
|
||||
@csrf
|
||||
{{-- <div class="app-modal-header">Update your profile settings</div> --}}
|
||||
<div class="app-modal-body">
|
||||
{{-- Udate profile avatar --}}
|
||||
<div class="avatar av-l upload-avatar-preview chatify-d-flex"
|
||||
style="background-image: url('{{ Chatify::getUserWithAvatar(Auth::user())->avatar }}');"
|
||||
></div>
|
||||
<p class="upload-avatar-details"></p>
|
||||
<label class="app-btn a-btn-primary update" style="background-color:{{$messengerColor}}">
|
||||
Upload New
|
||||
<input class="upload-avatar chatify-d-none" accept="image/*" name="avatar" type="file" />
|
||||
</label>
|
||||
{{-- Dark/Light Mode --}}
|
||||
<p class="divider"></p>
|
||||
<p class="app-modal-header">Dark Mode <span class="
|
||||
{{ Auth::user()->dark_mode > 0 ? 'fas' : 'far' }} fa-moon dark-mode-switch"
|
||||
data-mode="{{ Auth::user()->dark_mode > 0 ? 1 : 0 }}"></span></p>
|
||||
{{-- change messenger color --}}
|
||||
<p class="divider"></p>
|
||||
{{-- <p class="app-modal-header">Change {{ config('chatify.name') }} Color</p> --}}
|
||||
<div class="update-messengerColor">
|
||||
@foreach (config('chatify.colors') as $color)
|
||||
<span style="background-color: {{ $color}}" data-color="{{$color}}" class="color-btn"></span>
|
||||
@if (($loop->index + 1) % 5 == 0)
|
||||
<br/>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-modal-footer">
|
||||
<a href="javascript:void(0)" class="app-btn cancel">Cancel</a>
|
||||
<input type="submit" class="app-btn a-btn-success update" value="Save Changes" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,9 @@
|
||||
<div class="messenger-sendCard">
|
||||
<form id="message-form" method="POST" action="{{ route('send.message') }}" enctype="multipart/form-data">
|
||||
@csrf
|
||||
<label><span class="fas fa-plus-circle"></span><input disabled='disabled' type="file" class="upload-attachment" name="file" accept=".{{implode(', .',config('chatify.attachments.allowed_images'))}}, .{{implode(', .',config('chatify.attachments.allowed_files'))}}" /></label>
|
||||
<button class="emoji-button"></span><span class="fas fa-smile"></button>
|
||||
<textarea readonly='readonly' name="message" class="m-send app-scroll" placeholder="Type a message.."></textarea>
|
||||
<button disabled='disabled' class="send-button"><span class="fas fa-paper-plane"></span></button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,112 @@
|
||||
@include('Chatify::layouts.headLinks')
|
||||
<div class="messenger">
|
||||
{{-- ----------------------Users/Groups lists side---------------------- --}}
|
||||
<div class="messenger-listView {{ !!$id ? 'conversation-active' : '' }}">
|
||||
{{-- Header and search bar --}}
|
||||
<div class="m-header">
|
||||
<nav>
|
||||
<a href="#"><i class="fas fa-inbox"></i> <span class="messenger-headTitle">MESSAGES</span> </a>
|
||||
{{-- header buttons --}}
|
||||
<nav class="m-header-right">
|
||||
<a href="#"><i class="fas fa-cog settings-btn"></i></a>
|
||||
<a href="#" class="listView-x"><i class="fas fa-times"></i></a>
|
||||
</nav>
|
||||
</nav>
|
||||
{{-- Search input --}}
|
||||
<input type="text" class="messenger-search" placeholder="Search" />
|
||||
{{-- Tabs --}}
|
||||
{{-- <div class="messenger-listView-tabs">
|
||||
<a href="#" class="active-tab" data-view="users">
|
||||
<span class="far fa-user"></span> Contacts</a>
|
||||
</div> --}}
|
||||
</div>
|
||||
{{-- tabs and lists --}}
|
||||
<div class="m-body contacts-container">
|
||||
{{-- Lists [Users/Group] --}}
|
||||
{{-- ---------------- [ User Tab ] ---------------- --}}
|
||||
<div class="show messenger-tab users-tab app-scroll" data-view="users">
|
||||
{{-- Favorites --}}
|
||||
<div class="favorites-section">
|
||||
<p class="messenger-title"><span>Favorites</span></p>
|
||||
<div class="messenger-favorites app-scroll-hidden"></div>
|
||||
</div>
|
||||
{{-- Saved Messages --}}
|
||||
<p class="messenger-title"><span>Your Space</span></p>
|
||||
{!! view('Chatify::layouts.listItem', ['get' => 'saved']) !!}
|
||||
{{-- Contact --}}
|
||||
<p class="messenger-title"><span>All Messages</span></p>
|
||||
<div class="listOfContacts" style="width: 100%;height: calc(100% - 272px);position: relative;"></div>
|
||||
</div>
|
||||
{{-- ---------------- [ Search Tab ] ---------------- --}}
|
||||
<div class="messenger-tab search-tab app-scroll" data-view="search">
|
||||
{{-- items --}}
|
||||
<p class="messenger-title"><span>Search</span></p>
|
||||
<div class="search-records">
|
||||
<p class="message-hint center-el"><span>Type to search..</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- ----------------------Messaging side---------------------- --}}
|
||||
<div class="messenger-messagingView">
|
||||
{{-- header title [conversation name] amd buttons --}}
|
||||
<div class="m-header m-header-messaging">
|
||||
<nav class="chatify-d-flex chatify-justify-content-between chatify-align-items-center">
|
||||
{{-- header back button, avatar and user name --}}
|
||||
<div class="chatify-d-flex chatify-justify-content-between chatify-align-items-center">
|
||||
<a href="#" class="show-listView"><i class="fas fa-arrow-left"></i></a>
|
||||
<div class="avatar av-s header-avatar" style="margin: 0px 10px; margin-top: -5px; margin-bottom: -5px;">
|
||||
</div>
|
||||
<a href="#" class="user-name">{{ config('chatify.name') }}</a>
|
||||
</div>
|
||||
{{-- header buttons --}}
|
||||
<nav class="m-header-right">
|
||||
<a href="#" class="add-to-favorite"><i class="fas fa-star"></i></a>
|
||||
<a href="/"><i class="fas fa-home"></i></a>
|
||||
<a href="#" class="show-infoSide"><i class="fas fa-info-circle"></i></a>
|
||||
</nav>
|
||||
</nav>
|
||||
{{-- Internet connection --}}
|
||||
<div class="internet-connection">
|
||||
<span class="ic-connected">Connected</span>
|
||||
<span class="ic-connecting">Connecting...</span>
|
||||
<span class="ic-noInternet">No internet access</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Messaging area --}}
|
||||
<div class="m-body messages-container app-scroll">
|
||||
<div class="messages">
|
||||
<p class="message-hint center-el"><span>Please select a chat to start messaging</span></p>
|
||||
</div>
|
||||
{{-- Typing indicator --}}
|
||||
<div class="typing-indicator">
|
||||
<div class="message-card typing">
|
||||
<div class="message">
|
||||
<span class="typing-dots">
|
||||
<span class="dot dot-1"></span>
|
||||
<span class="dot dot-2"></span>
|
||||
<span class="dot dot-3"></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{{-- Send Message Form --}}
|
||||
@include('Chatify::layouts.sendForm')
|
||||
</div>
|
||||
{{-- ---------------------- Info side ---------------------- --}}
|
||||
<div class="messenger-infoView app-scroll">
|
||||
{{-- nav actions --}}
|
||||
<nav>
|
||||
<p>User Details</p>
|
||||
<a href="#"><i class="fas fa-times"></i></a>
|
||||
</nav>
|
||||
{!! view('Chatify::layouts.info')->render() !!}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@include('Chatify::layouts.modals')
|
||||
@include('Chatify::layouts.footerLinks')
|
||||
Reference in New Issue
Block a user