hfkfhkfhgjkuhgfkjfghkj

This commit is contained in:
Local Dev
2025-02-03 12:03:51 -05:00
commit fd36f0f4bf
302 changed files with 22625 additions and 0 deletions

View File

@ -0,0 +1,85 @@
<?php
/**
* app/plugins/notifications/controllers/admin/notifications.php
*
* This is the notifications admin controller.
*
* @package TP Notifications
* @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\Notification as NotificationsModel;
use TheTempusProject\Models\Group;
use TheTempusProject\Models\User;
use TheTempusProject\Houdini\Classes\Forms;
use TheTempusProject\Classes\Forms as FormChecker;
class Notifications extends AdminController {
protected static $notifications;
public static $user;
public static $group;
public function __construct() {
parent::__construct();
self::$title = 'Admin - Notifications';
self::$notifications = new NotificationsModel;
self::$user = new User;
self::$group = new Group;
$view = Navigation::activePageSelect( 'nav.admin', '/admin/Notifications' );
Components::set( 'ADMINNAV', $view );
}
public function index( $data = null ) {
// this is just a simple form to allow admins to send notifications
return $this->create();
}
public function create() {
$select = Forms::getSelectHtml(
'groupSelect',
self::$group->listGroupsSimple( true )
);
Components::set( 'groupSelect', $select );
if ( ! Input::exists( 'submit' ) ) {
return Views::view( 'notifications.admin.send' );
}
if ( ! FormChecker::check( 'createNotification' ) ) {
Issues::add( 'error', [ 'There was an error with your request.' => Check::userErrors() ] );
return Views::view( 'notifications.admin.send' );
}
if ( Input::exists( 'expires' ) ) {
$expiresAt = time() + intval( Input::post( 'expires' ) );
} else {
$expiresAt = 0;
}
if ( Input::exists( 'groupSelect' ) && Input::post( 'groupSelect' ) != 0 && Input::post( 'groupSelect' ) != 'all' ) {
$list = self::$group->listMembers( Input::post( 'groupSelect' ) );
} else {
$list = self::$user->userList();
}
$results = [];
foreach ( $list as $recipient ) {
$results[] = self::$notifications->create( Input::post( 'notification' ), 'Admin Issued', $recipient->ID, $expiresAt );
}
// $result = self::$notifications->create( Input::post( 'notification' ), 'Admin Issued', XXXXXXX_user_idsXXXXXX, $expiresAt );
if ( ! empty( $results ) ) {
Issues::add( 'success', 'Your notification has been sent.' );
} else {
Issues::add( 'error', [ 'There was an unknown error submitting your data.' => Check::userErrors() ] );
}
Views::view( 'notifications.admin.send' );
}
}

View File

@ -0,0 +1,79 @@
<?php
/**
* app/plugins/notifications/controllers/notifications.php
*
* This is the home controller for the notifications plugin.
*
* @package TP Notifications
* @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\Houdini\Classes\Views;
use TheTempusProject\Houdini\Classes\Issues;
use TheTempusProject\Classes\Controller;
use TheTempusProject\Models\Notification as NotificationsModel;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Hermes\Functions\Redirect;
use TheTempusProject\Bedrock\Functions\Session;
class Notifications extends Controller {
protected static $notifications;
public function __construct() {
parent::__construct();
self::$notifications = new NotificationsModel;
self::$title = 'Notifications - {SITENAME}';
self::$pageDescription = 'Your recent notifications';
if ( ! App::$isLoggedIn ) {
Session::flash( 'error', 'You do not have permission to access this page.' );
return Redirect::home();
}
}
public function index() {
$notifications = self::$notifications->getByUser( 10 );
Views::view( 'notifications.list', $notifications );
}
public function markRead( $id = null ) {
$notification = self::$notifications->findById( $id );
if ( $notification == false ) {
Issues::add( 'error', 'Notification not found.' );
return $this->index();
}
if ( $notification->userID != App::$activeUser->ID ) {
Issues::add( 'error', 'You do not have permission to modify this notification.' );
return $this->index();
}
$result = self::$notifications->markSeen( $id );
if ( $result == true ) {
Issues::add( 'success', 'Notification marked as read.' );
} else {
Issues::add( 'notice', 'There was an problem updating your notification.' );
}
return $this->index();
}
public function delete( $id = null ) {
$notification = self::$notifications->findById( $id );
if ( $notification == false ) {
Issues::add( 'error', 'Notification not found.' );
return $this->index();
}
if ( $notification->userID != App::$activeUser->ID ) {
Issues::add( 'error', 'You do not have permission to modify this notification.' );
return $this->index();
}
$result = self::$notifications->delete( $id );
if ( $result == true ) {
Issues::add( 'success', 'Notification deleted.' );
} else {
Issues::add( 'notice', 'There was an problem deleting your notification.' );
}
return $this->index();
}
}

View File

@ -0,0 +1,41 @@
<?php
/**
* app/plugins/notifications/forms.php
*
* This houses all of the form checking functions for this plugin.
*
* @package TP Notifications
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Plugins\Notifications;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Classes\Forms;
class NotificationForms extends Forms {
/**
* Adds these functions to the form list.
*/
public function __construct() {
self::addHandler( 'createNotification', __CLASS__, 'createNotification' );
}
/**
* Validates the createNotification form.
*
* @return {bool}
*/
public static function createNotification() {
if ( ! Input::exists( 'notification' ) ) {
Check::addUserError( 'You must provide a notification.' );
return false;
}
return true;
}
}
new NotificationForms;

View File

@ -0,0 +1,146 @@
<?php
/**
* app/plugins/notifications/models/notification.php
*
* This class is used for the manipulation of the notifications database table.
*
* @package TP Notifications
* @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\Functions\Check;
use TheTempusProject\Canary\Bin\Canary as Debug;
use TheTempusProject\Classes\DatabaseModel;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Houdini\Classes\Views;
use TheTempusProject\Canary\Classes\CustomException;
class Notification extends DatabaseModel {
public $tableName = 'notifications';
public $databaseMatrix = [
[ 'notification', 'text', '' ],
[ 'origin', 'varchar', '128' ],
[ 'userID', 'int', '11' ],
[ 'createdAt', 'int', '11' ],
[ 'expiresAt', 'int', '11' ],
[ 'deletedAt', 'int', '11' ],
[ 'seenAt', 'int', '11' ],
];
public function getUnreadCount( $userID ) {
$result = self::$db->get(
$this->tableName,
[
'userID', '=', $userID,
'AND',
'deletedAt', '=', '0',
'AND',
'seenAt', '=', '0',
'AND',
'expiresAt', '<', time(),
]
);
return $result->count();
}
public function create( $notification, $origin, $userID, $expiresAt = '0', $deletedAt = '0', $seenAt = '0' ) {
$fields = [
'notification' => $notification,
'origin' => $origin,
'userID' => $userID,
'createdAt' => time(),
'expiresAt' => $expiresAt,
'deletedAt' => $deletedAt,
'seenAt' => $seenAt,
];
if ( !self::$db->insert( $this->tableName, $fields ) ) {
Debug::info( 'Events::create - failed to insert to db' );
return false;
}
return self::$db->lastId();
}
public function getByUser( $limit = 0 ) {
$whereClause = [
'userID', '=', App::$activeUser->ID,
'AND',
'deletedAt', '=', '0',
'AND',
'expiresAt', '<', time(),
];
if ( empty( $limit ) ) {
$notifications = self::$db->get( $this->tableName, $whereClause );
} else {
$notifications = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
}
if ( !$notifications->count() ) {
Debug::info( 'Notification:getByUser No Notifications found' );
return false;
}
return $this->filter( $notifications->results() );
}
public function markSeen( $id ) {
if ( !Check::id( $id ) ) {
Debug::info( 'Notifications: illegal ID.' );
return false;
}
$fields = [
'seenAt' => time(),
];
$notification = self::findById( $id );
if ( ! $notification ) {
Debug::error( "Notifications: $id not updated" );
return false;
}
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
new CustomException( 'notificationUpdate' );
Debug::error( "Notifications: $id not updated" );
return false;
}
return true;
}
public function delete( $id ) {
if ( !Check::id( $id ) ) {
Debug::info( 'Notifications: illegal ID.' );
return false;
}
$fields = [
'deletedAt' => time(),
];
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
new CustomException( 'notificationDelete' );
Debug::error( "Notifications: $id not updated" );
return false;
}
return true;
}
public function filter( $messageArray, $filters = [] ) {
$out = [];
foreach ( $messageArray as $message ) {
if ( !is_object( $message ) ) {
$message = $messageArray;
$end = true;
}
if ( $message->seenAt == 0 ) {
$message->unseenBadge = Views::simpleView( 'notifications.unseenBadge' );
$message->markReadLink = '<a href="{ROOT_URL}notifications/markRead/'.$message->ID.'" class="btn btn-sm btn-primary"><i class="fa-solid fa-fw fa-envelope-open"></i></a>';
} else {
$message->unseenBadge = '';
$message->markReadLink = '';
}
$out[] = (object) $message;
if ( !empty( $end ) ) {
$out = $out[0];
break;
}
}
return $out;
}
}

View File

@ -0,0 +1,64 @@
<?php
/**
* app/plugins/notifications/plugin.php
*
* This houses all of the main plugin info and functionality.
*
* @package TP Notifications
* @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\TheTempusProject as App;
use TheTempusProject\Classes\Plugin;
use TheTempusProject\Models\Notification;
use TheTempusProject\Houdini\Classes\Components;
use TheTempusProject\Houdini\Classes\Views;
class Notifications extends Plugin {
public $pluginName = 'TP Notifications';
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 notification system.';
public $permissionMatrix = [
'sendNotifications' => [
'pretty' => 'Can send notifications',
'default' => false,
],
];
public $admin_links = [
[
'text' => '<i class="fa fa-fw fa-bell"></i> Notify',
'url' => '{ROOT_URL}admin/notifications',
],
];
private static $loaded = false;
public function __construct( $load = false ) {
parent::__construct( $load );
if ( $this->checkEnabled() && App::$isLoggedIn ) {
$notifications = new Notification;
Components::set( 'notificationCount', $notifications->getUnreadCount( App::$activeUser->ID ) );
if ( $notifications->getUnreadCount( App::$activeUser->ID ) > 0 ) {
$messageBadge = Views::simpleView( 'notifications.badge' );
} else {
$messageBadge = '';
}
Components::set( 'NBADGE', $messageBadge );
if ( ! self::$loaded ) {
if ( App::$isLoggedIn ) {
Components::set( 'recentNotifications', Views::simpleView( 'notifications.nav.recentNotificationsDropdown', $notifications->getByUser( 10 ) ) );
} else {
Components::set( 'recentNotifications', '' );
}
App::$topNavRight .= '{recentNotifications}';
App::$topNavRightDropdown .= '<li><a href="{ROOT_URL}notifications" class="dropdown-item"><i class="fa fa-fw fa-bell"></i> Notifications {NBADGE}</a></li>';
self::$loaded = true;
}
}
}
}

View File

@ -0,0 +1,61 @@
<div class="context-main-bg context-main p-3">
<legend class="text-center">Send Notification</legend>
<hr>
{ADMIN_BREADCRUMBS}
<form method="post" enctype="multipart/form-data">
<fieldset>
<!-- Group -->
<div class="mb-3 row">
<label for="groupSelect" class="col-lg-3 col-form-label text-end">Group:</label>
<div class="col-lg-6">
{groupSelect}
</div>
</div>
<!-- Recipients -->
<div class="mb-3 row">
<label for="expiration" class="col-lg-3 col-form-label text-end">Expiration:</label>
<div class="col-lg-6">
<select class="form-control" name="expiration" id="expiration">
<option value="0">forever</option>
<option value="1800">30 Minutes</option>
<option value="3600">60 Minutes</option>
<option value="14400">4 hours</option>
<option value="28800">8 hours</option>
<option value="43200">12 hours</option>
<option value="86400">24 hours</option>
<option value="172800">2 days</option>
<option value="259200">3 days</option>
<option value="432000">5 days</option>
<option value="604800">7 days</option>
<option value="1209600">2 weeks</option>
<option value="1814400">3 weeks</option>
<option value="2419200">4 weeks</option>
<option value="2592000">1 month</option>
<option value="5184000">2 months</option>
<option value="7776000">3 months</option>
<option value="15552000">6 months</option>
<option value="31536000">12 months</option>
</select>
</div>
</div>
<!-- Notification -->
<div class="mb-3 row">
<label for="notification" class="col-lg-3 col-form-label text-end">Notification:</label>
<div class="col-lg-6">
<textarea class="form-control" name="notification" id="notification" rows="6" maxlength="2000" required></textarea>
<small class="form-text text-muted">Max: 2000 characters</small>
</div>
</div>
<!-- Hidden Token -->
<input type="hidden" name="token" value="{TOKEN}">
</fieldset>
<!-- Submit Button -->
<div class="text-center">
<button type="submit" name="submit" value="submit" class="btn btn-primary btn-lg center-block">Send</button>
</div>
</form>
</div>

View File

@ -0,0 +1 @@
<span class="badge bg-danger rounded-pill">{notificationCount}</span>

View File

@ -0,0 +1,41 @@
<div class="m-2 m-lg-4">
<div class="col-12 mx-5 col-sm-10 col-lg-8 mx-auto p-4 rounded shadow-sm context-main-bg">
<div class="row justify-content-center">
<div class="col-md-8">
<legend class="text-center">Notifications</legend>
<table class="table">
<thead>
<tr>
<th style="width: 90%"></th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
</tr>
</thead>
<tbody>
{LOOP}
<tr {unseenBadge}>
<td class=" context-main">{notification}</td>
<td>
{markReadLink}
</td>
<td>
<a href="{ROOT_URL}notifications/delete/{ID}" class="btn btn-sm btn-danger">
<i class="fa fa-fw fa-trash"></i>
</a>
</td>
</tr>
{/LOOP}
{ALT}
<tr>
<td colspan="3" class="text-center context-main">
No Notifications
</td>
</tr>
{/ALT}
</tbody>
</table>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,41 @@
<!-- Notifications Dropdown -->
<div class="dropdown nav-item mx-2 my-2 my-lg-0">
<a
href="#"
class="d-flex align-items-center text-white text-decoration-none dropdown-toggle"
id="notificationsDropdown"
data-bs-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false">
<i class="fa fa-fw fa-bell"></i><span class="">{NBADGE}</span>
</a>
<ul class="dropdown-menu dropdown-menu-dark dropdown-menu-end text-small shadow" aria-labelledby="notificationsDropdown">
{LOOP}
<!-- Notification Item -->
<li>
<a href="{ROOT_URL}notifications" class="dropdown-item">
<div class="media">
<div class="media-body">
<p class="small text-muted mb-1"><i class="fa fa-clock-o me-1"></i> {DTC}{createdAt}{/DTC}</p>
<span>{notification}</span>
</div>
</div>
</a>
</li>
{/LOOP}
{ALT}
<li class="px-3 text-center">
<strong>No Notifications</strong>
</li>
{/ALT}
<!-- Footer -->
<li>
<hr class="dropdown-divider">
</li>
<li>
<a href="/notifications" class="dropdown-item text-center">
See All Notifications
</a>
</li>
</ul>
</div>

View File

@ -0,0 +1 @@
class="bg-info"