Initial commit
This commit is contained in:
37
app/plugins/chat/controllers/admin/chat.php
Normal file
37
app/plugins/chat/controllers/admin/chat.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/chat/controllers/admin/chat.php
|
||||
*
|
||||
* This is the chat admin controller.
|
||||
*
|
||||
* @package TP Chat
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Controllers\Admin;
|
||||
|
||||
use TheTempusProject\Bedrock\Functions\Input;
|
||||
use TheTempusProject\Houdini\Classes\Issues;
|
||||
use TheTempusProject\Houdini\Classes\Views;
|
||||
use TheTempusProject\Houdini\Classes\Navigation;
|
||||
use TheTempusProject\Houdini\Classes\Components;
|
||||
use TheTempusProject\Classes\AdminController;
|
||||
use TheTempusProject\Models\Chat as ChatModel;
|
||||
|
||||
class Chat extends AdminController {
|
||||
protected static $chat;
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
self::$title = 'Admin - Chat';
|
||||
self::$chat = new ChatModel;
|
||||
$view = Navigation::activePageSelect( 'nav.admin', '/admin/chat' );
|
||||
Components::set( 'ADMINNAV', $view );
|
||||
}
|
||||
|
||||
public function index() {
|
||||
// Views::view( 'chat.admin.list', self::$chat->list() );
|
||||
}
|
||||
}
|
45
app/plugins/chat/controllers/api/messages.php
Normal file
45
app/plugins/chat/controllers/api/messages.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/**
|
||||
* app/controllers/api/users.php
|
||||
*
|
||||
* This is the users' api controller.
|
||||
*
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Controllers\Api;
|
||||
|
||||
use TheTempusProject\Models\User;
|
||||
use TheTempusProject\Classes\ApiController;
|
||||
use TheTempusProject\Houdini\Classes\Views;
|
||||
use TheTempusProject\Bedrock\Functions\Input;
|
||||
use TheTempusProject\Classes\Forms;
|
||||
use TheTempusProject\Houdini\Classes\Template;
|
||||
use TheTempusProject\Models\Chat;
|
||||
|
||||
class Messages extends ApiController {
|
||||
public static $chat;
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
self::$chat = new Chat;
|
||||
Template::setTemplate( 'api' );
|
||||
}
|
||||
|
||||
public function sendMessage() {
|
||||
$response = true;
|
||||
if ( ! Forms::check( 'newChatMessage' ) ) {
|
||||
$response = 'Invalid Form';
|
||||
} else {
|
||||
$response = self::$chat->create( Input::post( 'chatMessage' ) );
|
||||
}
|
||||
Views::view( 'api.response', ['response' => json_encode( [ 'data' => $response ], true )]);
|
||||
}
|
||||
|
||||
public function getMessages() {
|
||||
$response = Views::simpleView( 'chat.chat', self::$chat->recent( 50 ) );
|
||||
Views::view( 'api.response', ['response' => json_encode( [ 'data' => $response ], true )]);
|
||||
}
|
||||
}
|
191
app/plugins/chat/controllers/chat.php
Normal file
191
app/plugins/chat/controllers/chat.php
Normal file
@ -0,0 +1,191 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/chat/controllers/chat.php
|
||||
*
|
||||
* This is the public chat controller.
|
||||
*
|
||||
* @package TP Chat
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Controllers;
|
||||
|
||||
use TheTempusProject\Hermes\Functions\Redirect;
|
||||
use TheTempusProject\Bedrock\Functions\Upload;
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Bedrock\Functions\Input;
|
||||
use TheTempusProject\Bedrock\Functions\Session;
|
||||
use TheTempusProject\Houdini\Classes\Issues;
|
||||
use TheTempusProject\Houdini\Classes\Views;
|
||||
use TheTempusProject\Classes\Controller;
|
||||
use TheTempusProject\Classes\Forms;
|
||||
use TheTempusProject\Models\Chat as ChatModel;
|
||||
use TheTempusProject\Models\Upload as UploadModel;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
use TheTempusProject\Houdini\Classes\Components;
|
||||
use TheTempusProject\Houdini\Classes\Template;
|
||||
use TheTempusProject\Canary\Canary as Debug;
|
||||
|
||||
class Chat extends Controller {
|
||||
protected static $chat;
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
self::$chat = new ChatModel;
|
||||
Template::setTemplate( 'chat' );
|
||||
}
|
||||
|
||||
public function index() {
|
||||
if ( !App::$isMember ) {
|
||||
Session::flash( 'error', 'You do not have permission to view this page.' );
|
||||
return Redirect::home();
|
||||
}
|
||||
self::$title = '{SITENAME} Chat';
|
||||
self::$pageDescription = 'One of the privleges of membership is the ability to chat with your fellow members.';
|
||||
|
||||
if ( App::$isLoggedIn ) {
|
||||
Components::set( 'CREATE_MESSAGE', Views::simpleView( 'chat.create' ) );
|
||||
} else {
|
||||
Components::set( 'CREATE_MESSAGE', '' );
|
||||
}
|
||||
|
||||
$upload = '';
|
||||
$sharePlugin = 'TheTempusProject\Plugins\Fileshare';
|
||||
if ( class_exists( $sharePlugin ) ) {
|
||||
$plugin = new $sharePlugin;
|
||||
if ( $plugin->checkEnabled() ) {
|
||||
$upload = Views::simpleView( 'chat.upload' );
|
||||
}
|
||||
}
|
||||
Components::set( 'FILE_UPLOAD', $upload );
|
||||
|
||||
Components::set( 'CHAT', Views::simpleView( 'chat.chat' ) );
|
||||
return Views::view( 'chat.index' );
|
||||
}
|
||||
|
||||
public function sendMessage() {
|
||||
Template::setTemplate( 'api' );
|
||||
$out = [ 'response' => true ];
|
||||
if ( !Forms::check( 'newChatMessage' ) ) {
|
||||
$out = [ 'response' => false ];
|
||||
echo json_encode($out);
|
||||
return;
|
||||
}
|
||||
self::$chat->create(
|
||||
Input::post( 'chatMessage' ),
|
||||
);
|
||||
echo json_encode($out);
|
||||
return;
|
||||
}
|
||||
|
||||
public function uploadFile() {
|
||||
Template::setTemplate( 'api' );
|
||||
$out = [ 'response' => true ];
|
||||
if ( ! Forms::check( 'newFileUpload' ) ) {
|
||||
$out = [ 'response' => false ];
|
||||
echo json_encode($out);
|
||||
return;
|
||||
}
|
||||
|
||||
$sharePlugin = 'TheTempusProject\Plugins\Fileshare';
|
||||
if ( ! class_exists( $sharePlugin ) ) {
|
||||
$out = [ 'error' => 'Fileshare must be installed and enabled for this feature to work1.' ];
|
||||
echo json_encode($out);
|
||||
return;
|
||||
}
|
||||
|
||||
$plugin = new $sharePlugin;
|
||||
|
||||
if ( ! $plugin->checkEnabled() ) {
|
||||
$out = [ 'error' => 'Fileshare must be installed and enabled for this feature to work2.' ];
|
||||
echo json_encode($out);
|
||||
return;
|
||||
}
|
||||
|
||||
$folder = UPLOAD_DIRECTORY . App::$activeUser->username . DIRECTORY_SEPARATOR;
|
||||
if ( ! Upload::image( 'file', $folder ) ) {
|
||||
$out = [ 'error' => 'could not upload image' ];
|
||||
echo json_encode($out);
|
||||
return;
|
||||
}
|
||||
|
||||
$route = str_replace( APP_ROOT_DIRECTORY, '', $folder );
|
||||
$location = $route . Upload::last();
|
||||
$uploads = new UploadModel;
|
||||
$result = $uploads->create( 'Chat Upload', $location );
|
||||
|
||||
if ( ! $result ) {
|
||||
$out = [ 'error' => 'could not add upload to fileshare.' ];
|
||||
echo json_encode( $out );
|
||||
return;
|
||||
}
|
||||
|
||||
self::$chat->create(
|
||||
'Shared a file with the chat: ' .
|
||||
'<a href="/' . $location . '" target="_blank">Upload</a>'
|
||||
);
|
||||
echo json_encode($out);
|
||||
return;
|
||||
}
|
||||
|
||||
public function getMessages() {
|
||||
Template::setTemplate( 'api' );
|
||||
echo Views::simpleView( 'chat.chat', self::$chat->recent( 50 ) );
|
||||
return;
|
||||
}
|
||||
|
||||
public function getMessageEvents() {
|
||||
if ($_SERVER['HTTP_ACCEPT'] !== 'text/event-stream') {
|
||||
Debug::info( 'connection refused, wrong HTTP_ACCEPT' );
|
||||
exit();
|
||||
}
|
||||
|
||||
header("X-Accel-Buffering: no");
|
||||
header('Content-Type: text/event-stream');
|
||||
header('Cache-Control: no-cache');
|
||||
header('Connection: keep-alive');
|
||||
|
||||
// Ensure unlimited script execution time
|
||||
set_time_limit(0);
|
||||
|
||||
// Disable output buffering
|
||||
ini_set('output_buffering', 'off');
|
||||
ini_set('zlib.output_compression', false);
|
||||
|
||||
if (Input::exists('lastId')) {
|
||||
$lastId = Input::get('lastId');
|
||||
} else {
|
||||
$lastId = 0;
|
||||
}
|
||||
|
||||
while ( true ) {
|
||||
echo "id: 0\n";
|
||||
echo "event: ping\n";
|
||||
echo 'data: {"time": "' . time() . '"}';
|
||||
echo "\n\n";
|
||||
if ( connection_aborted() ) {
|
||||
Debug::info( 'getMessageEvents connection aborted' );
|
||||
break;
|
||||
}
|
||||
|
||||
$newMessages = self::$chat->sinceMessage( $lastId );
|
||||
if ( ! empty( $newMessages )) {
|
||||
foreach ( $newMessages as $message ) {
|
||||
$lastId = $message->ID;
|
||||
echo "id: {$message->ID}\n";
|
||||
echo "data: " . json_encode($message) . "\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
// If there were any messages added, flush the output buffer
|
||||
if (ob_get_contents()) {
|
||||
ob_end_flush();
|
||||
}
|
||||
flush();
|
||||
// sessions will block the end-user from sending messages unless we close the session
|
||||
session_write_close();
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
}
|
116
app/plugins/chat/css/chat.css
Normal file
116
app/plugins/chat/css/chat.css
Normal file
@ -0,0 +1,116 @@
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 20px auto;
|
||||
font-family: "Lato";
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
form {
|
||||
padding: 15px 25px;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
form label {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
input {
|
||||
font-family: "Lato";
|
||||
}
|
||||
|
||||
a {
|
||||
color: #0000ff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#chatMessages {
|
||||
text-align: left;
|
||||
margin: 0 auto;
|
||||
padding: 10px;
|
||||
height: 300px;
|
||||
border: 1px solid #a7a7a7;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#usermsg {
|
||||
flex: 1;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ff9800;
|
||||
}
|
||||
|
||||
#name {
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ff9800;
|
||||
padding: 2px 8px;
|
||||
}
|
||||
|
||||
#submitmsg,
|
||||
#enter{
|
||||
background: #ff9800;
|
||||
border: 2px solid #e65100;
|
||||
color: white;
|
||||
padding: 4px 10px;
|
||||
font-weight: bold;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: #ff0000;
|
||||
}
|
||||
|
||||
#menu {
|
||||
padding: 15px 25px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#menu p.welcome {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
a#exit {
|
||||
color: white;
|
||||
background: #c62828;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.msgln {
|
||||
margin: 0 0 5px 0;
|
||||
}
|
||||
|
||||
.span.left-info {
|
||||
color: orangered;
|
||||
}
|
||||
|
||||
span .chat-time {
|
||||
color: #666;
|
||||
font-size: 80%;
|
||||
vertical-align: super;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.msgln b.user-name, .msgln b.user-name-left {
|
||||
font-weight: bold;
|
||||
background: #546e7a;
|
||||
color: white;
|
||||
padding: 2px 4px;
|
||||
font-size: 90%;
|
||||
border-radius: 4px;
|
||||
margin: 0 5px 0 0;
|
||||
}
|
||||
|
||||
.msgln b.user-name-left {
|
||||
background: orangered;
|
||||
}
|
52
app/plugins/chat/forms.php
Normal file
52
app/plugins/chat/forms.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/chat/forms.php
|
||||
*
|
||||
* This houses all of the form checking functions for this plugin.
|
||||
*
|
||||
* @package TP Chat
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Plugins\Chat;
|
||||
|
||||
use TheTempusProject\Bedrock\Functions\Input;
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Classes\Forms;
|
||||
|
||||
class ChatForms extends Forms {
|
||||
/**
|
||||
* Adds these functions to the form list.
|
||||
*/
|
||||
public function __construct() {
|
||||
self::addHandler( 'newChatMessage', __CLASS__, 'newChatMessage' );
|
||||
self::addHandler( 'newFileUpload', __CLASS__, 'newFileUpload' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the new blog post form.
|
||||
*
|
||||
* @return {bool}
|
||||
*/
|
||||
public static function newChatMessage() {
|
||||
if ( !Input::exists( 'chatMessage' ) ) {
|
||||
self::addUserError( 'You must includes a message' );
|
||||
return false;
|
||||
}
|
||||
// if (!self::token()) {
|
||||
// return false;
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
public static function newFileUpload() {
|
||||
if ( !Input::exists( 'file' ) ) {
|
||||
self::addUserError( 'You must includes a file' );
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
new ChatForms;
|
116
app/plugins/chat/js/chat.js
Normal file
116
app/plugins/chat/js/chat.js
Normal file
@ -0,0 +1,116 @@
|
||||
$(document).ready(function() {
|
||||
var chatform = $('#sendChatMessage');
|
||||
var uploadForm = $('#uploadFile');
|
||||
|
||||
chatform.bind('submit', function(event) {
|
||||
event.preventDefault(); // Prevent page reload
|
||||
var msg = $("#chatMessage").val();
|
||||
|
||||
console.log("Submitting message:", msg);
|
||||
|
||||
var ajax_params = {
|
||||
url: '/chat/sendMessage',
|
||||
type: 'POST',
|
||||
data: { chatMessage: msg },
|
||||
success: function(response) {
|
||||
console.log("Message sent successfully:", response);
|
||||
$("#chatMessage").val("");
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
console.error("Error sending message:", error, status, xhr);
|
||||
},
|
||||
complete: function() {
|
||||
console.log("AJAX request complete");
|
||||
}
|
||||
};
|
||||
|
||||
$.ajax(ajax_params);
|
||||
return false;
|
||||
});
|
||||
|
||||
uploadForm.bind('submit', function(event) {
|
||||
event.preventDefault(); // Prevent page reload
|
||||
|
||||
var formData = new FormData(this); // Create FormData object
|
||||
|
||||
$.ajax({
|
||||
url: '/chat/uploadFile',
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
processData: false, // Don't process the files
|
||||
contentType: false, // Set content type to false as jQuery will tell the server its a query string request
|
||||
success: function(response) {
|
||||
console.log("File uploaded successfully:", response);
|
||||
$("#file").val("");
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
console.error("Error uploading file:", error, status, xhr);
|
||||
},
|
||||
complete: function() {
|
||||
console.log("AJAX request complete");
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
const eventSource = new EventSource('/chat/getMessageEvents');
|
||||
eventSource.onmessage = function( event ) {
|
||||
const message = JSON.parse( event.data );
|
||||
|
||||
var userPopup = "<div class='media'>" +
|
||||
"<span class='pull-left'>" +
|
||||
"<img class='media-object avatar-round-40' src='/"+message.avatar+"' alt=''>" +
|
||||
"</span>" +
|
||||
"<div class='media-body'>" +
|
||||
"<h5 class='media-heading'>" +
|
||||
"<strong>"+message.submittedByName+"</strong>" +
|
||||
"</h5>" +
|
||||
"<a href='/home/profile/"+message.submittedByName+"' class='btn btn-sm btn-primary' role='button'><i class='glyphicon glyphicon-open'></i> View Profile</a>" +
|
||||
"</div>" +
|
||||
"</div>";
|
||||
|
||||
$("#chatMessages").append(
|
||||
"<span class='chat-time'>" +
|
||||
new Date(message.submittedAt * 1000).toLocaleString('en-US', { month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric', hour12: true }) +
|
||||
// new Date(message.submittedAt * 1000).toLocaleString() +
|
||||
"</span> " +
|
||||
'<a tabindex="0" role="button" data-toggle="popover" data-html="true" data-trigger="focus" title="'+message.submittedByName+'" data-content="'+userPopup+'">' +
|
||||
message.submittedByName +
|
||||
'</a> ' +
|
||||
message.chatMessage + "<br>"
|
||||
);
|
||||
$("[data-toggle=popover]").popover();
|
||||
$("#chatMessages").scrollTop($("#chatMessages")[0].scrollHeight);
|
||||
};
|
||||
|
||||
eventSource.onerror = function(event) {
|
||||
console.error('EventSource failed:', event);
|
||||
};
|
||||
|
||||
window.addEventListener('beforeunload', function() {
|
||||
eventSource.close();
|
||||
});
|
||||
|
||||
window.addEventListener('unload', function() {
|
||||
eventSource.close();
|
||||
});
|
||||
|
||||
// function getUserProfile( id ) {
|
||||
// var ajax_params = {
|
||||
// url: '/api/users/find/' + id,
|
||||
// type: 'GET',
|
||||
// success: function(response) {
|
||||
// console.log("User retrieved:", response);
|
||||
// $("#chatMessage").val("");
|
||||
// },
|
||||
// error: function(xhr, status, error) {
|
||||
// console.error("Error retrieved user:", error, status, xhr);
|
||||
// },
|
||||
// complete: function() {
|
||||
// console.log("AJAX request complete");
|
||||
// }
|
||||
// };
|
||||
// $.ajax(ajax_params);
|
||||
// }
|
||||
});
|
145
app/plugins/chat/models/chat.php
Normal file
145
app/plugins/chat/models/chat.php
Normal file
@ -0,0 +1,145 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/chat/models/chat.php
|
||||
*
|
||||
* This class is used for the manipulation of the chat database table.
|
||||
*
|
||||
* @todo make this send a confirmation email
|
||||
*
|
||||
* @package TP Chat
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Models;
|
||||
|
||||
use TheTempusProject\Bedrock\Classes\Config;
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Canary\Canary as Debug;
|
||||
use TheTempusProject\Classes\DatabaseModel;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
use TheTempusProject\Houdini\Classes\Filters;
|
||||
|
||||
class Chat extends DatabaseModel {
|
||||
public $tableName = 'chat';
|
||||
public $databaseMatrix = [
|
||||
[ 'submittedAt', 'int', '10' ],
|
||||
[ 'submittedBy', 'int', '11' ],
|
||||
[ 'chatMessage', 'text', '' ],
|
||||
];
|
||||
|
||||
/**
|
||||
* The model constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a chat form to the db.
|
||||
*
|
||||
* @param string $message -contents of the chat form.
|
||||
* @return bool
|
||||
*/
|
||||
public function create( $message ) {
|
||||
$fields = [
|
||||
'submittedBy' => App::$activeUser->ID,
|
||||
'submittedAt' => time(),
|
||||
'chatMessage' => $message,
|
||||
];
|
||||
if ( !self::$db->insert( $this->tableName, $fields ) ) {
|
||||
Debug::info( 'Chat::create - failed to insert to db' );
|
||||
return false;
|
||||
}
|
||||
return self::$db->lastId();
|
||||
}
|
||||
|
||||
public function filter( $data, $params = [] ) {
|
||||
foreach ( $data as $instance ) {
|
||||
if ( !is_object( $instance ) ) {
|
||||
$instance = $data;
|
||||
$end = true;
|
||||
}
|
||||
$instance->chatMessage = Filters::applyOne( 'mentions.0', $instance->chatMessage, true );
|
||||
$instance->chatMessage = Filters::applyOne( 'hashtags.0', $instance->chatMessage, true );
|
||||
$user = self::$user->findById( $instance->submittedBy );
|
||||
if ( ! empty( $user ) ) {
|
||||
$instance->submittedByName = $user->username;
|
||||
$instance->profileUrl = '/home/profile/' . $user->username;
|
||||
} else {
|
||||
$instance->submittedByName = 'Unknown';
|
||||
$instance->profileUrl = '#';
|
||||
}
|
||||
$instance->avatar = self::$user->getAvatar( $instance->submittedBy );
|
||||
$out[] = $instance;
|
||||
if ( !empty( $end ) ) {
|
||||
$out = $out[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to clear chat from the DB.
|
||||
*
|
||||
* @todo is there a way i could check for success here I'm pretty sure this is just a bad idea?
|
||||
* @return bool
|
||||
*/
|
||||
public function clear() {
|
||||
if ( empty( self::$log ) ) {
|
||||
self::$log = new Log;
|
||||
}
|
||||
self::$db->delete( $this->tableName, ['ID', '>=', '0'] );
|
||||
self::$log->admin( 'Cleared Chat' );
|
||||
Debug::info( 'Chat Cleared' );
|
||||
return true;
|
||||
}
|
||||
|
||||
public function recent( $limit = null ) {
|
||||
if ( empty( $limit ) ) {
|
||||
$postData = self::$db->get( $this->tableName, '*' );
|
||||
} else {
|
||||
$postData = self::$db->get( $this->tableName, '*', 'ID', 'ASC', [0, $limit] );
|
||||
}
|
||||
if ( !$postData->count() ) {
|
||||
Debug::info( 'No messages found.' );
|
||||
return false;
|
||||
}
|
||||
return $this->filter( $postData->results() );
|
||||
}
|
||||
|
||||
public function sinceMessage($id = 0) {
|
||||
if (empty($id)) {
|
||||
$postData = self::$db->get($this->tableName, '*', 'ID', 'DESC', [0, 20]);
|
||||
} else {
|
||||
$postData = self::$db->get($this->tableName, ['ID', '>', $id], 'ID', 'ASC', [0, 20]);
|
||||
}
|
||||
if ( ! $postData->count() ) {
|
||||
Debug::debug( 'No messages found.' );
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($id)) {
|
||||
$results = array_reverse($postData->results()); // Reverse the order to get ascending IDs
|
||||
} else {
|
||||
$results = $postData->results();
|
||||
}
|
||||
|
||||
return $this->filter($results);
|
||||
}
|
||||
|
||||
public function sinceMessageSingle( $id = 0 ) {
|
||||
if ( empty( $id ) ) {
|
||||
$postData = self::$db->get( $this->tableName, '*', 'ID', 'ASC', [0, 1] );
|
||||
} else {
|
||||
$postData = self::$db->get( $this->tableName, [ 'ID', '>', $id ], 'ID', 'ASC', [0, 1] );
|
||||
}
|
||||
if ( ! $postData->count() ) {
|
||||
Debug::debug( 'No messages found.' );
|
||||
return false;
|
||||
}
|
||||
return $this->filter( $postData->results() );
|
||||
}
|
||||
}
|
55
app/plugins/chat/plugin.php
Normal file
55
app/plugins/chat/plugin.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/chat/plugin.php
|
||||
*
|
||||
* This houses all of the main plugin info and functionality.
|
||||
*
|
||||
* @package TP Chat
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Plugins;
|
||||
|
||||
use TheTempusProject\Classes\Plugin;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
|
||||
class Chat extends Plugin {
|
||||
public $pluginName = 'TP Chat';
|
||||
public $configName = 'chat';
|
||||
public $pluginAuthor = 'JoeyK';
|
||||
public $pluginWebsite = 'https://TheTempusProject.com';
|
||||
public $modelVersion = '1.0';
|
||||
public $pluginVersion = '3.0';
|
||||
public $pluginDescription = 'A simple plugin which adds a site wide chat system.';
|
||||
public $permissionMatrix = [
|
||||
'chat' => [
|
||||
'pretty' => 'Can use chat',
|
||||
'default' => false,
|
||||
],
|
||||
];
|
||||
public $admin_links = [
|
||||
[
|
||||
'text' => '<i class="fa fa-fw fa-copy"></i> Chat',
|
||||
'url' => '{ROOT_URL}admin/chat',
|
||||
],
|
||||
];
|
||||
public $main_links = [
|
||||
[
|
||||
'text' => 'Chat',
|
||||
'url' => '{ROOT_URL}chat/index',
|
||||
'filter' => 'loggedin',
|
||||
],
|
||||
];
|
||||
public $configMatrix = [
|
||||
'enabled' => [
|
||||
'type' => 'radio',
|
||||
'pretty' => 'Enable Chat.',
|
||||
'default' => true,
|
||||
],
|
||||
];
|
||||
public function __construct( $load = false ) {
|
||||
parent::__construct( $load );
|
||||
}
|
||||
}
|
32
app/plugins/chat/templates/chat.inc.php
Normal file
32
app/plugins/chat/templates/chat.inc.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/blog/templates/blog.inc.php
|
||||
*
|
||||
* This is the loader for the blog template.
|
||||
*
|
||||
* @package TP Blog
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Templates;
|
||||
|
||||
use TheTempusProject\Plugins\Calendar;
|
||||
|
||||
use TheTempusProject\Houdini\Classes\Components;
|
||||
use TheTempusProject\Houdini\Classes\Navigation;
|
||||
use TheTempusProject\Houdini\Classes\Views;
|
||||
use TheTempusProject\Houdini\Classes\Template;
|
||||
use TheTempusProject\Bedrock\Functions\Input;
|
||||
|
||||
class ChatLoader extends DefaultLoader {
|
||||
/**
|
||||
* This is the function used to generate any components that may be
|
||||
* needed by this template.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->addJs( '<script language="JavaScript" crossorigin="anonymous" type="text/javascript" src="{ROOT_URL}app/plugins/chat/js/chat.js"></script>' );
|
||||
parent::__construct();
|
||||
}
|
||||
}
|
88
app/plugins/chat/templates/chat.tpl
Normal file
88
app/plugins/chat/templates/chat.tpl
Normal file
@ -0,0 +1,88 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<!--
|
||||
* app/templates/default/default.tpl
|
||||
*
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
-->
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<meta property="og:url" content="{CURRENT_URL}">
|
||||
<meta name='twitter:card' content='summary_large_image' />
|
||||
<title>{TITLE}</title>
|
||||
<meta itemprop="name" content="{TITLE}">
|
||||
<meta name="twitter:title" content="{TITLE}">
|
||||
<meta property="og:title" content="{TITLE}">
|
||||
<meta name="description" content="{PAGE_DESCRIPTION}">
|
||||
<meta itemprop="description" content="{PAGE_DESCRIPTION}">
|
||||
<meta name="twitter:description" content="{PAGE_DESCRIPTION}">
|
||||
<meta property="og:description" content="{PAGE_DESCRIPTION}">
|
||||
<meta itemprop="image" content="{META_IMAGE}">
|
||||
<meta name="twitter:image" content="{META_IMAGE}">
|
||||
<meta property="og:image" content="{META_IMAGE}">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
{AUTHOR}
|
||||
{ROBOT}
|
||||
<link rel="icon" href="{ROOT_URL}images/favicon.ico">
|
||||
<!-- Required CSS -->
|
||||
<link rel="stylesheet" href="{FONT_AWESOME_URL}font-awesome.min.css" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="{BOOTSTRAP_CDN}css/bootstrap-theme.min.css" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="{BOOTSTRAP_CDN}css/bootstrap.min.css" crossorigin="anonymous">
|
||||
<!-- Custom styles for this template -->
|
||||
{TEMPLATE_CSS_INCLUDES}
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
||||
<!--Brand and toggle should get grouped for better mobile display but I had to account for additional menus-->
|
||||
<div class="navbar-header">
|
||||
<a href="{ROOT_URL}" class="navbar-brand">{SITENAME}</a>
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse" style="">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="container-fluid">
|
||||
<div class="collapse navbar-collapse navbar-ex1-collapse">
|
||||
{topNavLeft}
|
||||
<div class="navbar-right">
|
||||
<ul class="nav navbar-nav">
|
||||
{topNavRight}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container-fluid top-pad foot-pad">
|
||||
{ISSUES}
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
{ERROR}
|
||||
{NOTICE}
|
||||
{SUCCESS}
|
||||
{INFO}
|
||||
</div>
|
||||
</div>
|
||||
{/ISSUES}
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
{CONTENT}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
{FOOT}
|
||||
{COPY}
|
||||
</footer>
|
||||
<!-- Bootstrap core JavaScript and jquery -->
|
||||
<script language="JavaScript" crossorigin="anonymous" type="text/javascript" src="{JQUERY_CDN}jquery.min.js"></script>
|
||||
<script language="JavaScript" crossorigin="anonymous" type="text/javascript" src="{BOOTSTRAP_CDN}js/bootstrap.min.js"></script>
|
||||
<!-- Custom javascript for this template -->
|
||||
{TEMPLATE_JS_INCLUDES}
|
||||
</body>
|
||||
</html>
|
0
app/plugins/chat/views/admin/index.html
Normal file
0
app/plugins/chat/views/admin/index.html
Normal file
10
app/plugins/chat/views/chat.html
Normal file
10
app/plugins/chat/views/chat.html
Normal file
@ -0,0 +1,10 @@
|
||||
{LOOP}
|
||||
<div class='msgln'>
|
||||
<span class='chat-time'>{DTC time}{submittedAt}{/DTC}</span> <b class='user-name'>{submittedByName}</b>: {chatMessage}<br>
|
||||
</div>
|
||||
{/LOOP}
|
||||
{ALT}
|
||||
<div class="msgln">
|
||||
No messages Found.<br>
|
||||
</div>
|
||||
{/ALT}
|
9
app/plugins/chat/views/create.html
Normal file
9
app/plugins/chat/views/create.html
Normal file
@ -0,0 +1,9 @@
|
||||
<form class="form-horizontal" id="sendChatMessage">
|
||||
<input type="hidden" name="token" value="{TOKEN}">
|
||||
<div class="form-group col-lg-10">
|
||||
<input type="text" class="form-control" name="chatMessage" id="chatMessage">
|
||||
</div>
|
||||
<div class="form-group col-lg-2">
|
||||
<button id="submitChatMessage" name="submitChatMessage" value="button" class="btn btn-sm btn-primary center-block ">Send</button>
|
||||
</div>
|
||||
</form>
|
18
app/plugins/chat/views/index.html
Normal file
18
app/plugins/chat/views/index.html
Normal file
@ -0,0 +1,18 @@
|
||||
<link rel="stylesheet" href="{ROOT_URL}app/plugins/chat/css/chat.css" crossorigin="anonymous">
|
||||
<span class="col-lg-12" id="Chat">
|
||||
<div class="panel panel-default" role="tab">
|
||||
<div class="panel-heading">
|
||||
<button type="button" class="btn btn-default btn-sm" data-target="#Collapse${id}" data-toggle="collapse" aria-expanded="true" aria-controls="#Collapse${id}">
|
||||
<i class="glyphicon glyphicon-th-list"></i> {USERNAME}
|
||||
</button>
|
||||
</div>
|
||||
<div id="Collapse${id}" class="panel-collapse collapse in" style="width:100%; position: relative;" role="tabpanel" aria-expanded="true">
|
||||
<div class="panel-body" id="chatMessages">
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
{CREATE_MESSAGE}
|
||||
{FILE_UPLOAD}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
9
app/plugins/chat/views/upload.html
Normal file
9
app/plugins/chat/views/upload.html
Normal file
@ -0,0 +1,9 @@
|
||||
<form action="" method="post" class="form-horizontal" enctype="multipart/form-data" id="uploadFile">
|
||||
<input type="hidden" name="token" value="{TOKEN}">
|
||||
<div class="form-group col-lg-3 col-lg-offset-6">
|
||||
<input type="file" class="form-control" name="file" id="file">
|
||||
</div>
|
||||
<div class="form-group col-lg-3">
|
||||
<button id="submitUpload" name="submit" value="submit" class="btn btn-sm btn-primary center-block">Upload</button>
|
||||
</div>
|
||||
</form>
|
Reference in New Issue
Block a user