Initial commit

This commit is contained in:
Joey Kimsey
2024-08-04 21:15:59 -04:00
parent c9d1fb983f
commit 0d469501ee
695 changed files with 70184 additions and 71 deletions

View File

@ -0,0 +1,79 @@
<?php
/**
* app/plugins/comments/controllers/admin/comments.php
*
* This is the comments admin controller.
*
* @package TP Comments
* @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\Houdini\Classes\Navigation;
use TheTempusProject\Houdini\Classes\Issues;
use TheTempusProject\Houdini\Classes\Views;
use TheTempusProject\Houdini\Classes\Components;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Classes\Forms;
use TheTempusProject\Classes\AdminController;
use TheTempusProject\Models\Comments as CommentsModel;
class Comments extends AdminController {
protected static $comments;
public function __construct() {
parent::__construct();
self::$title = 'Admin - Comments';
self::$comments = new CommentsModel;
$view = Navigation::activePageSelect( 'nav.admin', '/admin/comments' );
Components::set( 'ADMINNAV', $view );
}
public function edit( $data = null ) {
if ( !Input::exists( 'submit' ) ) {
return Views::view( 'comments.admin.edit', self::$comments->findById( $data ) );
}
if ( !Forms::check( 'editComment' ) ) {
Issues::add( 'error', [ 'There was an error with your request.' => Check::userErrors() ] );
return Views::view( 'comments.admin.edit', self::$comments->findById( $data ) );
}
if ( self::$comments->update( $data, Input::post( 'comment' ) ) ) {
Issues::add( 'success', 'Comment updated' );
} else {
return Views::view( 'comments.admin.edit', self::$comments->findById( $data ) );
}
$this->index();
}
public function viewComment( $data = null ) {
$commentData = self::$comments->findById( $data );
if ( $commentData !== false ) {
return Views::view( 'comments.list', $commentData );
}
Issues::add( 'error', 'Comment not found.' );
$this->index();
}
public function delete( $data = null ) {
if ( $data == null ) {
if ( !Input::exists( 'C_' ) ) {
return $this->index();
}
$data = Input::post( 'C_' );
}
if ( !self::$comments->delete( $data ) ) {
Issues::add( 'error', 'There was an error with your request.' );
} else {
Issues::add( 'success', 'Comment has been deleted' );
}
$this->index();
}
public function index() {
Views::view( 'comments.admin.list', self::$comments->recent() );
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* app/plugins/comments/controllers/moderator.php
*
* This is the Moderator 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;
use TheTempusProject\Houdini\Classes\Template;
use TheTempusProject\Houdini\Classes\Views;
use TheTempusProject\Houdini\Classes\Issues;
use TheTempusProject\Classes\Controller;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Hermes\Functions\Redirect;
use TheTempusProject\Bedrock\Functions\Session;
class Moderator extends Controller {
public function __construct() {
parent::__construct();
Template::noIndex();
if ( !App::$isMod ) {
Session::flash( 'error', 'You do not have permission to view this page.' );
return Redirect::home();
}
}
public function index() {
self::$title = 'Moderator\'s Area';
Views::view( 'comments.moderator' );
}
}

View File

@ -0,0 +1,6 @@
/**
* Comments
*/
.comments {
margin-top: 120px;
}

View File

@ -0,0 +1,69 @@
<?php
/**
* app/plugins/comments/forms.php
*
* This houses all of the form checking functions for this plugin.
*
* @package TP Comments
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Plugins\Feedback;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Classes\Forms;
class CommentsForms extends Forms {
/**
* Adds these functions to the form list.
*/
public function __construct() {
self::addHandler( 'newComment', __CLASS__, 'newComment' );
self::addHandler( 'editComment', __CLASS__, 'editComment' );
}
/**
* Validates the new comment form.
*
* @return {bool}
*/
public static function newComment() {
if ( !Input::exists( 'comment' ) ) {
Check::addUserError( 'You cannot post a blank comment.' );
return false;
}
if ( !Input::exists( 'contentId' ) ) {
Check::addUserError( 'Content ID was missing.' );
return false;
}
// these are disabled because i need to figure out a solution for pages where images are wrong
// a missing image loads a new token and messes this up
// if ( !Check::token() ) {
// return false;
// }
return true;
}
/**
* Validates the edit comment form.
*
* @return {bool}
*/
public static function editComment() {
if ( !Input::exists( 'comment' ) ) {
Check::addUserError( 'You cannot post a blank comment.' );
return false;
}
// these are disabled because i need to figure out a solution for pages where images are wrong
// a missing image loads a new token and messes this up
// if ( !Check::token() ) {
// return false;
// }
return true;
}
}
new CommentsForms;

View File

@ -0,0 +1,184 @@
<?php
/**
* app/plugins/comments/models/comment.php
*
* This class is used for the creation, retrieval, and manipulation
* of the comments table.
*
* @package TP Comments
* @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\Canary as Debug;
use TheTempusProject\Houdini\Classes\Views;
use TheTempusProject\Classes\DatabaseModel;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Bedrock\Classes\CustomException;
use TheTempusProject\Houdini\Classes\Filters;
class Comments extends DatabaseModel {
public $tableName = 'comments';
public $databaseMatrix = [
[ 'author', 'int', '11' ],
[ 'contentID', 'int', '11' ],
[ 'created', 'int', '10' ],
[ 'edited', 'int', '10' ],
[ 'approved', 'int', '1' ],
[ 'contentType', 'varchar', '32' ],
[ 'content', 'text', '' ],
];
public function count( $contentType, $contentID ) {
if ( !Check::id( $contentID ) ) {
Debug::info( 'Comments: illegal ID.' );
return false;
}
if ( !Check::dataTitle( $contentType ) ) {
Debug::info( 'Comments: illegal Type.' );
return false;
}
$where = ['contentType', '=', $contentType, 'AND', 'contentID', '=', $contentID];
$data = self::$db->get( $this->tableName, $where );
if ( !$data->count() ) {
Debug::info( 'No comments found.' );
return 0;
}
return $data->count();
}
public function display( $displayCount, $contentType, $contentID ) {
if ( !Check::id( $contentID ) ) {
Debug::info( 'Comments: illegal ID.' );
return false;
}
if ( !Check::dataTitle( $contentType ) ) {
Debug::info( 'Comments: illegal Type.' );
return false;
}
$where = ['contentType', '=', $contentType, 'AND', 'contentID', '=', $contentID];
$commentData = self::$db->get( $this->tableName, $where, 'created', 'DESC', [0, $displayCount] );
if ( !$commentData->count() ) {
Debug::info( 'No comments found.' );
return false;
}
return $this->filter( $commentData->results() );
}
public function update( $id, $comment ) {
if ( empty( self::$log ) ) {
self::$log = new Log;
}
if ( !Check::id( $id ) ) {
Debug::info( 'Comments: illegal ID.' );
return false;
}
$fields = [
'edited' => time(),
'content' => $comment,
'approved' => 1,
];
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
new CustomException( 'commentUpdate' );
Debug::error( "Post: $id not updated: $fields" );
return false;
}
self::$log->admin( "Updated Comment: $id" );
return true;
}
public function create( $contentType, $contentID, $comment ) {
if ( !Check::id( $contentID ) ) {
Debug::info( 'Comments: illegal ID.' );
return false;
}
if ( !Check::dataTitle( $contentType ) ) {
Debug::info( 'Comments: illegal Type.' );
return false;
}
$fields = [
'author' => App::$activeUser->ID,
'edited' => time(),
'created' => time(),
'content' => $comment,
'contentType' => $contentType,
'contentID' => $contentID,
'approved' => 0,
];
if ( !self::$db->insert( $this->tableName, $fields ) ) {
new CustomException( 'commentCreate' );
Debug::error( "Comments: $data not created: $fields" );
return false;
}
return self::$db->lastId();
}
public function filter( $data, $params = [] ) {
foreach ( $data as $instance ) {
if ( !is_object( $instance ) ) {
$instance = $data;
$end = true;
}
if ( App::$isAdmin || ( App::$isLoggedIn && $instance->author == App::$activeUser->ID ) ) {
$instance->commentControl = Views::simpleView( 'comments.control', ['ID' => $instance->ID] );
} else {
$instance->commentControl = '';
}
$data = self::$db->get( $instance->contentType, ['ID', '=', $instance->contentID] )->results();
if ( empty( $data ) ) {
$title = 'Unknown';
} elseif ( empty( $data[0]->title ) ) {
$title = 'Unknown';
} else {
$title = $data[0]->title;
}
$authorName = self::$user->getUsername( $instance->author );
$authorAvatar = self::$user->getAvatar( $instance->author );
$instance->avatar = $authorAvatar;
$instance->authorName = $authorName;
$instance->contentTitle = $title;
$instance->content = Filters::applyOne( 'mentions.0', $instance->content, true );
$instance->content = Filters::applyOne( 'hashtags.0', $instance->content, true );
$out[] = $instance;
if ( !empty( $end ) ) {
$out = $out[0];
break;
}
}
return $out;
}
public function recent( $contentType = 'all', $limit = null ) {
if ( $contentType === 'all' ) {
$where = ['ID', '>', '0'];
} else {
$where = ['contentType', '=', $contentType];
}
if ( empty( $limit ) ) {
$commentData = self::$db->getPaginated( $this->tableName, $where, 'created', 'DESC' );
} else {
$commentData = self::$db->get( $this->tableName, $where, 'created', 'DESC', [0, $limit] );
}
if ( !$commentData->count() ) {
Debug::info( 'No comments found.' );
return false;
}
return $this->filter( $commentData->results() );
}
}

View File

@ -0,0 +1,146 @@
<?php
/**
* app/plugins/comments/plugin.php
*
* This houses all of the main plugin info and functionality.
*
* @package TP Comments
* @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 ReflectionClass;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Classes\Installer;
use TheTempusProject\Houdini\Classes\Navigation;
use TheTempusProject\Classes\Plugin;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\Houdini\Classes\Components;
use TheTempusProject\Houdini\Classes\Issues;
use TheTempusProject\Houdini\Classes\Views;
use TheTempusProject\Classes\Forms;
use TheTempusProject\Hermes\Functions\Redirect;
use TheTempusProject\Bedrock\Functions\Session;
use TheTempusProject\Models\Comments as CommentModel;
class Comments extends Plugin {
public $pluginName = 'TP Comments';
public $pluginAuthor = 'JoeyK';
public $pluginWebsite = 'https://TheTempusProject.com';
public $modelVersion = '1.0';
public $pluginVersion = '3.0';
public $pluginDescription = 'A simple plugin to add user comments for other plugins.';
public $admin_links = [
[
'text' => '<i class="fa fa-fw fa-comment"></i> Comments',
'url' => '{ROOT_URL}admin/comments',
],
];
public $main_links = [
[
'text' => 'Moderator',
'url' => '{ROOT_URL}moderator/index',
'filter' => 'mod',
]
];
public $permissionMatrix = [
'modAccess' => [
'pretty' => 'Access Moderator Areas',
'default' => false,
],
];
public $resourceMatrix = [
'group' => [
[
'name' => 'Moderator',
'permissions' => '{"adminAccess":false}',
]
],
];
public $comments;
public function __construct( $load = false ) {
if ( !empty(App::$activePerms) ) {
App::$isMod = !empty(App::$activePerms['modAccess']);
} else {
App::$isMod = false;
}
$this->filters[] = [
'name' => 'mod',
'find' => '#{MOD}(.*?){/MOD}#is',
'replace' => ( App::$isMod ? '$1' : '' ),
'enabled' => true,
];
$this->getModel();
parent::__construct( $load );
}
public function formPost( $type, $content, $redirect ) {
if ( !App::$isLoggedIn ) {
Session::flash( 'notice', 'You must be logged in to post comments.' );
return Redirect::to( $redirect . $content->ID );
}
if ( !Forms::check( 'newComment' ) ) {
Session::flash( 'error', [ 'There was a problem with your comment form.' => Check::userErrors() ] );
return Redirect::to( $redirect . $content->ID );
}
if ( !$this->comments->create( $type, $content->ID, Input::post( 'comment' ) ) ) {
Session::flash( 'error', [ 'There was a problem posting your comment.' => Check::userErrors() ] );
} else {
Session::flash( 'success', 'Comment posted' );
}
return Redirect::to( $redirect . $content->ID );
}
public function formEdit( $type, $content, $redirect ) {
if ( !App::$isLoggedIn ) {
Session::flash( 'notice', 'You must be logged in to do that.' );
return Redirect::to( $type );
}
if ( !App::$isAdmin && $content->author != App::$activeUser->ID ) {
Session::flash( 'error', 'You do not have permission to edit this comment' );
return Redirect::to( $type );
}
if ( !Input::exists( 'submit' ) ) {
return Views::view( 'comments.admin.edit', $content );
}
if ( !Forms::check( 'editComment' ) ) {
Issues::add( 'error', [ 'There was a problem editing your comment.' => Check::userErrors() ] );
return Views::view( 'comments.admin.edit', $content );
}
if ( !$this->comments->update( $content->ID, Input::post( 'comment' ) ) ) {
Issues::add( 'error', [ 'There was a problem editing your comment.' => Check::userErrors() ] );
return Views::view( 'comments.admin.edit', $content );
}
Session::flash( 'success', 'Comment updated' );
return Redirect::to( $redirect . $content->contentID );
}
public function formDelete( $type, $content, $redirect ) {
if ( !App::$isLoggedIn ) {
Session::flash( 'notice', 'You must be logged in to do that.' );
return Redirect::to( $type );
}
if ( !App::$isAdmin && $content->author != App::$activeUser->ID ) {
Session::flash( 'error', 'You do not have permission to edit this comment' );
return Redirect::to( $type );
}
if ( !$this->comments->delete( (array) $content->ID ) ) {
Session::flash( 'error', 'There was an error with your request.' );
} else {
Session::flash( 'success', 'Comment has been deleted' );
}
return Redirect::to( $redirect . $content->contentID );
}
public function getModel() {
if ( empty($this->comments) ) {
$this->comments = new CommentModel;
}
return $this->comments;
}
}

View File

@ -0,0 +1,28 @@
<legend>New Comments</legend>
<table class="table table-striped">
<thead>
<tr>
<th style="width: 20%"></th>
<th style="width: 70%"></th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td>{authorName}</td>
<td>{content}</td>
<td><a href="{ROOT_URL}admin/comments/edit/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
<td><a href="{ROOT_URL}admin/comments/delete/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
</tr>
{/LOOP}
{ALT}
<tr>
<td align="center" colspan="4">
No results to show.
</td>
</tr>
{/ALT}
</tbody>
</table>

View File

@ -0,0 +1,9 @@
<form action="" method="post" class="form-horizontal">
<div class="form-group center-block">
<div class="col-lg-4 col-lg-offset-4">
<textarea class="form-control" name="comment" maxlength="2000" rows="10" cols="50" id="comment">{content}</textarea>
</div>
</div>
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Comment</button>
<input type="hidden" name="token" value="{TOKEN}">
</form>

View File

@ -0,0 +1,43 @@
<legend>Recent Comments</legend>
{PAGINATION}
<form action="{ROOT_URL}admin/comments/delete" method="post">
<table class="table table-striped">
<thead>
<tr>
<th style="width: 20%">Author</th>
<th style="width: 20%">Subject</th>
<th style="width: 35%">Comment</th>
<th style="width: 10%">Time</th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
<th style="width: 5%">
<INPUT type="checkbox" onchange="checkAll(this)" name="check.c" value="C_[]"/>
</th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td><a href="{ROOT_URL}admin/users/view/{author}">{authorName}</a></td>
<td><a href="{ROOT_URL}admin/blog/view/{contentID}">{contentTitle}</a></td>
<td>{content}</td>
<td>{DTC}{created}{/DTC}</td>
<td><a href="{ROOT_URL}admin/comments/edit/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
<td><a href="{ROOT_URL}admin/comments/delete/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
<td>
<input type="checkbox" value="{ID}" name="C_[]">
</td>
</tr>
{/LOOP}
{ALT}
<tr>
<td align="center" colspan="7">
No results to show.
</td>
</tr>
{/ALT}
</tbody>
</table>
<button name="submit" value="submit" type="submit" class="btn btn-sm btn-danger">Delete</button>
</form>
<br />

View File

@ -0,0 +1,8 @@
<div class="action">
<a href="{ROOT_URL}{COMMENT_TYPE}/comments/edit/{ID}" class="btn btn-warning btn-xs" role="button">
<span class="glyphicon glyphicon-pencil"></span>
</a>
<a href="{ROOT_URL}{COMMENT_TYPE}/comments/delete/{ID}" class="btn btn-danger btn-xs" role="button">
<span class="glyphicon glyphicon-trash"></span>
</a>
</div>

View File

@ -0,0 +1,10 @@
<form action="" method="post" class="form-horizontal">
<div class="form-group center-block">
<div class="col-lg-8 col-lg-offset-2">
<textarea class="form-control" name="comment" maxlength="2000" rows="4" cols="50" id="comment"></textarea>
</div>
</div>
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Comment</button>
<input type="hidden" name="token" value="{TOKEN}">
<input type="hidden" name="contentId" value="{CONTENT_ID}">
</form>

View File

@ -0,0 +1,42 @@
<div class="panel panel-info widget comments">
<div class="panel-heading">
<span class="glyphicon glyphicon-comment"></span>
<h3 class="panel-title">Comments</h3>
<span class="label label-primary">{count}</span>
</div>
<div class="panel-body">
<ul class="list-group">
{LOOP}
<li class="list-group-item">
<div class="row">
<div class="col-xs-2 col-md-1">
<img src="{ROOT_URL}{avatar}" class="img-circle img-responsive" alt="" />
</div>
<div class="col-xs-10 col-md-11">
<div>
<div class="mic-info">
By: <a href="{ROOT_URL}home/profile/{author}">{authorName}</a> on {DTC date}{created}{/DTC}
</div>
</div>
<div class="comment-text">
{content}
</div>
{commentControl}
</div>
</div>
</li>
{/LOOP}
{ALT}
<li class="list-group-item">
<div class="row">
<div class="col-xs-10 col-md-11">
<div class="comment-text">
<p class="text-center">Be the first to comment.</p>
</div>
</div>
</div>
</li>
{/ALT}
</ul>
</div>
</div>

View File

@ -0,0 +1,7 @@
<h1>Moderator' Area</h1>
<div class="jumbotron">
<h1>Welcome!</h1>
<p>This is the moderator section. You can give some groups permission to access this area. The menu is hidden for normal users and if they get a link to a moderator's area, the authentication system will stop them from accessing any content protected this way.</p>
<p>You can even use this feature in-line with your views, hiding certain components from non-moderators</p>
<p>The idea behind this role is for them to help you in policing comments as needed.</p>
</div>