Compare commits

...

60 Commits

Author SHA1 Message Date
d7d8fc4b5e Carousel fix + fiixes 2024-12-02 21:18:36 -05:00
b1b0da0c08 wip 2024-12-02 18:56:52 -05:00
3eec88c228 Carousel fix 2024-12-02 18:04:44 -05:00
113499254b Merge remote-tracking branch 'origin/update_PHP_deps_20240821121538' 2024-08-21 08:16:05 -04:00
3b6d7f3a2c Update PHP dependencies [20240821121538] 2024-08-21 12:15:43 +00:00
09f96c369a fixes to support composer 2024-08-21 08:15:27 -04:00
afb9624971 Merge remote-tracking branch 'origin/update_PHP_deps_20240821101926' 2024-08-21 06:20:22 -04:00
8d3dee2ac2 Update PHP dependencies [20240821101926] 2024-08-21 10:19:29 +00:00
355e509e68 composer bump 2024-08-21 06:19:13 -04:00
c3f46cf6c3 Merge remote-tracking branch 'origin/update_PHP_deps_20240821101740' 2024-08-21 06:19:00 -04:00
4a521afa88 Update PHP dependencies [20240821101740] 2024-08-21 10:17:43 +00:00
0fa83b0ae6 composer bump 2024-08-21 06:17:29 -04:00
5c7a320c2a bugfixes for pagination and installation 2024-08-21 06:14:54 -04:00
551f6654f6 composer version bumps 2024-08-20 06:42:29 -04:00
80048ad1dd various bugfixes 2024-08-20 06:37:38 -04:00
80b8226218 Readme updates 2024-08-20 06:32:38 -04:00
cc9e57888f more fixes 2024-08-16 22:17:41 -04:00
ec317e6426 cleanup 2024-08-16 22:14:43 -04:00
910c9646b8 Readme updates 2024-08-15 13:50:59 -04:00
44dcb29060 remove non-standard plugins 2024-08-15 12:49:34 -04:00
431b1214fa lock down composer versions for final testing 2024-08-15 12:40:31 -04:00
9972f6a654 Readme Updates 2024-08-15 12:30:57 -04:00
b658614ce8 Readme Updates 2024-08-15 12:30:52 -04:00
55a725cd9e readme and license updates 2024-08-15 12:30:45 -04:00
a8b972acf5 Readme Updates 2024-08-15 12:30:45 -04:00
fd8d37d67a Readme Updates 2024-08-15 12:30:36 -04:00
c8eed20814 Readme Updates 2024-08-15 12:30:10 -04:00
b6767ae846 Docker updates 2024-08-15 12:30:10 -04:00
156f19ee97 Bookmark plugin renaming continued 2024-08-15 12:30:10 -04:00
0a9a5a433f Bookmark plugin renaming 2024-08-15 12:30:09 -04:00
b8c75a128a Merge remote-tracking branch 'origin/update_PHP_deps_20240813063608' 2024-08-13 02:36:31 -04:00
e4e72905fc Update PHP dependencies [20240813063608] 2024-08-13 06:36:12 +00:00
74e9af4539 bookmark bugfix 2024-08-13 02:35:55 -04:00
46c0376dfc Merge remote-tracking branch 'origin/update_PHP_deps_20240813062630' 2024-08-13 02:27:10 -04:00
90ba704a69 Update PHP dependencies [20240813062630] 2024-08-13 06:26:32 +00:00
fb92682eed install improvements 2024-08-13 02:26:19 -04:00
54e1a6a817 Merge remote-tracking branch 'origin/update_PHP_deps_20240813051915' 2024-08-13 01:20:00 -04:00
9eacdcdc37 Update PHP dependencies [20240813051915] 2024-08-13 05:19:20 +00:00
4388a4baa8 various bugfixes 2024-08-13 01:19:05 -04:00
ed43b2f2df amend gitignore 2024-08-13 00:26:38 -04:00
e88c8486a1 Merge remote-tracking branch 'origin/update_PHP_deps_20240813032443' 2024-08-12 23:25:49 -04:00
16dbc6c4e2 Update PHP dependencies [20240813032443] 2024-08-13 03:24:45 +00:00
14f8f134bc to prevent runaway job creation 2024-08-12 23:24:33 -04:00
ea30628ef8 final fix 2024-08-12 23:19:41 -04:00
e1d7c7fcc7 dsfsdv 2024-08-12 23:09:09 -04:00
ee5bcd23fa fix 2024-08-12 23:07:42 -04:00
b6add64d14 bugfix 2024-08-12 23:06:37 -04:00
19e34583d1 pipeline fix 2024-08-12 23:05:10 -04:00
7e296b2468 Merge remote-tracking branch 'origin/update_PHP_deps_20240813022109' 2024-08-12 22:22:08 -04:00
e9988d4a14 Update PHP dependencies [20240813022109] 2024-08-13 02:21:11 +00:00
4ccbd17607 pipeline update 2024-08-12 22:20:54 -04:00
7eb1ad9f7d fix 2024-08-12 22:10:38 -04:00
14bc0c1e64 bugfixes 2024-08-12 22:08:54 -04:00
4d1e8d6753 Update .gitlab-ci.yml file 2024-08-13 02:06:26 +00:00
468d48cc00 Update .gitlab-ci.yml file 2024-08-12 22:28:05 +00:00
778a9882b8 remove unused plugins 2024-08-10 14:14:54 -04:00
60985c8c09 fixes for ci/cd 2024-08-10 02:36:52 -04:00
e2d32ab0a0 add CD 2024-08-10 02:18:31 -04:00
136e85dd14 install bugfix 2024-08-09 18:00:56 -04:00
2fc3338d0f poll bugfix 2024-08-09 17:58:30 -04:00
453 changed files with 2109 additions and 44807 deletions

4
.gitignore vendored
View File

@ -54,11 +54,11 @@ Temporary Items
# TheTempusProject Specific
.htaccess
app/config/*
!app/config/constants.php
uploads/images/*
logs/*
.vscode/
mail.log
vendor/canary/logs/*
docker/.env
.env
components/*

74
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,74 @@
stages:
- prepare
- build
- test
- update
- deploy
variables:
TIMEZONE: "America/New_York" # For the system in general
DATE_TIMEZONE: ${TIMEZONE} # For PHP
GIT_DEPTH: 1
GITLAB_API_URL: ${CI_API_V4_URL}
TARGET_BRANCH: ${CI_COMMIT_REF_NAME} # This is the branch chosen in the `Pipeline Schedule`
TARGET_REMOTE: "https://${GITLAB_USERNAME}:${GITLAB_ACCESS_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}.git"
# These could/should be overridden in an extending job:
UPDATE_BRANCH_PREFIX: "update_PHP_deps_" # Used for the update branch name, it will be followed by the datetime
GIT_USER: "DependBot" # Used for the update commit
GIT_EMAIL: "webmaster@thetempusproject.com" # Used for the update commit
GITLAB_USERNAME: "root" # Used for pushing the new branch and opening the MR
GITLAB_ACCESS_TOKEN: "glpat-PKEmivGtBfbz4DVPdhzk" # Used for pushing the new branch and opening the MR
MERGE_IF_SUCCESSFUL: "true" # Set to true, to merge automatically if the pipeline succeeds
SECONDS_BETWEEN_POOLING: 10 # Nbr of seconds between checking if the MR pipeline is successful, so then it will merge
JOB_GIT_FLAGS: ""
JOB_CURL_FLAGS: ""
JOB_COMPOSER_FLAGS: ""
composer_update:
stage: update
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
image: composer:latest
interruptible: true # allows to stop the job if a newer pipeline starts, saving resources and allowing new jobs to start because job concurrency is limited
script:
- git ${JOB_GIT_FLAGS} fetch origin ${TARGET_BRANCH}
- git ${JOB_GIT_FLAGS} checkout ${TARGET_BRANCH}
- git reset --hard origin/main
- git pull --allow-unrelated-histories
- export DATE_TIME="$(date '+%Y%m%d%H%M%S')"
- export MR_BRANCH="${UPDATE_BRANCH_PREFIX}${DATE_TIME}"
- git ${JOB_GIT_FLAGS} checkout -b "${MR_BRANCH}"
- composer update ${JOB_COMPOSER_FLAGS}
- if [ "$(git diff)" == "" ]; then echo "No updates needed!"; exit 0; fi
- export TITLE="Update PHP dependencies [${DATE_TIME}]"
- git ${JOB_GIT_FLAGS} commit -a -m "${TITLE}"
- git ${JOB_GIT_FLAGS} push "${TARGET_REMOTE}" "${MR_BRANCH}"
artifacts:
paths:
- vendor/
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- vendor/
prepare:
stage: prepare
script:
- echo "Preparing environment..."
build:
stage: build
script:
- echo "Building the project..."
test:
stage: test
script:
- echo "Running tests..."
deploy:
stage: deploy
script:
- echo "Deploying the project..."

View File

@ -1,6 +1,10 @@
MIT License
Copyright (c) 2024-present Joey Kimsey
Copyright (c) 2024 Joey Kimsey
Portions of this software are licensed as follows:
* All content residing under the "app/" directory of this repository, excluding "app/plugins/"; is licensed under "Creative Commons: CC BY-SA 4.0 license".
* All third party components incorporated into The Tempus Project Software including plugins are licensed under the original license provided by the owner of the applicable component.
* Content outside of the above mentioned directories or restrictions above is available under the "MIT Expat" license as defined below.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,39 +1,41 @@
# The Tempus Project
need to make a vs battle for dnd. someone makes a truly broken character, we take the base character and hand it to two people and give them some time to figure out how they would break it
need to track points once a week
a huge table tracks points day to day then we add and erase the old data, or move it to historical...
## Rapid Prototyping Framework
## Developer(s): Joey Kimsey
### Developer(s): Joey Kimsey
The aim of this project is to provide a simple and stable platform from which to easily add functionality. The goal being the ability to quickly build and test new projects with a lightweight ecosystem to help.
**Notice: This code is in _still_ not production ready. This framework is provided as is, use at your own risk.**
I am working very hard to ensure the system is safe and reliable enough for me to endorse its widespread use. Unfortunately, it still needs a lot of QA and improvements.
Currently I am in the process of testing all the systems in preparation for the first production ready release. The beta is still on-going. If you would like to participate or stay up to date with the latest, you can find more information at: https://TheTempusProject.com/beta
## Features
- A Plugin system that allows plug-and-play functionality
- A User management system
- groups
- permissions
- preferences
- registration and recovery
(All Controlled dynamically via our plugin interface)
- Compatibility with both Apache and NGINX
- Built with Bootstrap with a focus on mobile compatibility
- Incredibly easy to set-up, deploy, and develop
A User management system with groups, permissions, preferences, registration, and recovery. (All Controlled dynamically via our plugin interface)
A Plugin system that allows plug-and-play functionality for a huge number of features.
Compatibility with both Apache and NGINX.
Built with Bootstrap with a focus on mobile compatibility.
Incredibly easy to set-up, deploy, and develop with.
## Installation
Preferred method for installation is using composer. Special attention has been given to use without composer and more information is included below.
Preferred method for installation is using composer.
### Manually
### Docker
### Composer
The simplest method to start a new project is to use composer to create a new project and automatically clone all the necessary files:
```
composer create-project thetempusproject/thetempusproject test-app
```
1. Clone the directory to wherever you want to install the framework.
2. Open your terminal to the directory you previously cloned the repository.
3. Install using composer:
@ -41,12 +43,6 @@ composer create-project thetempusproject/thetempusproject test-app
4. Open your browser and navigate to install.php (it will be in the root directory of your installation)
5. When prompted, complete the forms and complete the process.
### Manually
### Docker
#### Apache
#### NGINX
@ -376,3 +372,9 @@ What is my goal here?
I would like to play Dungeons and Dragons once a week with my friends. In an ideal world, I would DM this game and spend all week building tools for us to use that I then put on a website which sells memberships to other players so they can use the tools too.
i need to be able to name models in camel case, this shit is getting crazy. Find whatever prevents this and fix it

View File

@ -1,8 +1,8 @@
<?php
/**
* app/classes/admin_controller.php
* app/classes/api_controller.php
*
* This is the base admin controller. Every other admin controller should
* This is the base api controller. Every other api controller should
* extend this class.
*
* @version 3.0

View File

@ -1,12 +1,12 @@
<?php
/**
* classes/config.php
* app/classes/config.php
*
* This class handles all the hard-coded configurations.
*
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com/Core
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Classes;

View File

@ -16,11 +16,19 @@ namespace TheTempusProject\Classes;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Canary\Bin\Canary as Debug;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\Models\User;
use TheTempusProject\Classes\Forms;
use TheTempusProject\Bedrock\Classes\Database;
class Forms extends Check {
private static $formHandlers = [];
private static $initialized = false;
public static function check( $formName ) {
if ( self::$initialized !== true ) {
self::initHandlers();
}
if ( empty( self::$formHandlers[ $formName ] ) ) {
Debug::error( "Form not found: $formName" );
return false;
@ -74,4 +82,530 @@ class Forms extends Check {
}
return true;
}
/**
* Adds these functions to the form list.
*/
public function __construct() {
if ( self::$initialized === true ) {
return;
}
self::initHandlers();
}
private static function initHandlers() {
self::addHandler( 'passwordResetCode', __CLASS__, 'passwordResetCode' );
self::addHandler( 'createRoute', __CLASS__, 'createRoute' );
self::addHandler( 'editRoute', __CLASS__, 'editRoute' );
self::addHandler( 'register', __CLASS__, 'register' );
self::addHandler( 'createUser', __CLASS__, 'createUser' );
self::addHandler( 'editUser', __CLASS__, 'editUser' );
self::addHandler( 'login', __CLASS__, 'login' );
self::addHandler( 'changeEmail', __CLASS__, 'changeEmail' );
self::addHandler( 'changePassword', __CLASS__, 'changePassword' );
self::addHandler( 'passwordReset', __CLASS__, 'passwordReset' );
self::addHandler( 'emailConfirmation', __CLASS__, 'emailConfirmation' );
self::addHandler( 'confirmationResend', __CLASS__, 'confirmationResend' );
self::addHandler( 'replyMessage', __CLASS__, 'replyMessage' );
self::addHandler( 'newMessage', __CLASS__, 'newMessage' );
self::addHandler( 'userPrefs', __CLASS__, 'userPrefs' );
self::addHandler( 'newGroup', __CLASS__, 'newGroup' );
self::addHandler( 'editGroup', __CLASS__, 'editGroup' );
self::addHandler( 'install', __CLASS__, 'install' );
self::addHandler( 'installStart', __CLASS__, 'install', [ 'start' ] );
self::addHandler( 'installAgreement', __CLASS__, 'install', [ 'agreement' ] );
self::addHandler( 'installCheck', __CLASS__, 'install', [ 'check' ] );
self::addHandler( 'installConfigure', __CLASS__, 'install', [ 'configure' ] );
self::addHandler( 'installRouting', __CLASS__, 'install', [ 'routing' ] );
self::addHandler( 'installModels', __CLASS__, 'install', [ 'models' ] );
self::addHandler( 'installPlugins', __CLASS__, 'install', [ 'plugins' ] );
self::addHandler( 'installResources', __CLASS__, 'install', [ 'resources' ] );
self::addHandler( 'installAdminUser', __CLASS__, 'install', [ 'adminUser' ] );
self::$initialized = true;
}
/**
* Validates the installer forms.
*
* @return {bool}
*/
public static function install( $page = '' ) {
// if ( !self::token() ) {
// return false;
// }
switch ( $page ) {
case 'configure':
if ( ! Input::exists( 'submit' ) ) {
return false;
}
if ( !Database::check( Input::post( 'dbHost' ), Input::post( 'dbName' ), Input::post( 'dbUsername' ), Input::post( 'dbPassword' ) ) ) {
self::addUserError( 'DB connection error.' );
return false;
}
return true;
case 'adminUser':
if ( !self::checkUsername( Input::post( 'newUsername' ) ) ) {
self::addUserError( 'Invalid username.' );
return false;
}
if ( !self::password( Input::post( 'userPassword' ) ) ) {
self::addUserError( 'Invalid password.' );
return false;
}
if ( Input::post( 'userPassword' ) !== Input::post( 'userPassword2' ) ) {
self::addUserError( 'Passwords do not match.' );
return false;
}
if ( Input::post( 'userEmail' ) !== Input::post( 'userEmail2' ) ) {
self::addUserError( 'Emails do not match.' );
return false;
}
return true;
case 'check':
if ( !self::uploads() ) {
self::addUserError( 'Uploads are disabled.' );
return false;
}
if ( !self::php() ) {
self::addUserError( 'PHP version is too old.' );
return false;
}
if ( !self::phpExtensions() ) {
self::addUserError( 'PHP extensions are missing.' );
return false;
}
if ( !self::sessions() ) {
self::addUserError( 'There is an error with Sessions.' );
return false;
}
if ( !self::mail() ) {
self::addUserError( 'PHP mail is not enabled.' );
return false;
}
if ( !self::safe() ) {
self::addUserError( 'Safe mode is enabled.' );
return false;
}
if ( ! Input::exists( 'submit' ) ) {
return false;
}
return true;
case 'start':
case 'agreement':
case 'routing':
case 'models':
case 'plugins':
case 'resources':
if ( ! Input::exists( 'submit' ) ) {
return false;
}
return true;
default:
return false;
}
return false;
}
/**
* Validates the password re-send form.
*
* @return {bool}
*/
public static function passwordResetCode() {
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the route creation form.
*
* @return {bool}
*/
public static function createRoute() {
if ( !Input::exists( 'redirect_type' ) ) {
return false;
}
if ( 'external' == Input::post( 'redirect_type' ) && !self::url( Input::post( 'forwarded_url' ) ) ) {
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the route edit form.
*
* @return {bool}
*/
public static function editRoute() {
if ( !Input::exists( 'redirect_type' ) ) {
return false;
}
if ( 'external' == Input::post( 'redirect_type' ) && !self::url( Input::post( 'forwarded_url' ) ) ) {
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the user creation form.
*
* @return {bool}
*/
public static function createUser() {
$user = new User;
if ( !$user->checkUsername( Input::post( 'username' ) ) ) {
self::addUserError( 'Invalid username.' );
return false;
}
if ( !self::password( Input::post( 'password' ) ) ) {
self::addUserError( 'Invalid password.' );
return false;
}
if ( !self::email( Input::post( 'email' ) ) ) {
self::addUserError( 'Invalid Email.' );
return false;
}
if ( !$user->noEmailExists( Input::post( 'email' ) ) ) {
self::addUserError( 'A user with that email is already registered.' );
return false;
}
if ( Input::post( 'password' ) !== Input::post( 'password2' ) ) {
self::addUserError( 'Passwords do not match.' );
return false;
}
if ( Input::post( 'email' ) !== Input::post( 'email2' ) ) {
self::addUserError( 'Emails do not match.' );
return false;
}
if ( !Input::post( 'groupSelect' ) ) {
self::addUserError( 'You must select a group for the new user.' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the user edit form.
*
* @return {bool}
*/
public static function editUser() {
$user = new User;
if ( !$user->checkUsername( Input::post( 'username' ) ) ) {
self::addUserError( 'Invalid username.' );
return false;
}
if ( Input::exists( 'password' ) ) {
if ( !self::password( Input::post( 'password' ) ) ) {
self::addUserError( 'Invalid password.' );
return false;
}
if ( Input::post( 'password' ) !== Input::post( 'password2' ) ) {
self::addUserError( 'Passwords do not match.' );
return false;
}
}
if ( !self::email( Input::post( 'email' ) ) ) {
self::addUserError( 'Invalid Email.' );
return false;
}
if ( !Input::post( 'groupSelect' ) ) {
self::addUserError( 'You must select a group for the new user.' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the user registration form.
*
* @return {bool}
*/
public static function register() {
$user = new User;
if ( !self::checkUsername( Input::post( 'username' ) ) ) {
self::addUserError( 'Invalid username.' );
return false;
}
if ( !self::password( Input::post( 'password' ) ) ) {
self::addUserError( 'Invalid password.' );
return false;
}
if ( !self::email( Input::post( 'email' ) ) ) {
self::addUserError( 'Invalid Email.' );
return false;
}
if ( !$user->noEmailExists( Input::post( 'email' ) ) ) {
self::addUserError( 'A user with that email is already registered.' );
return false;
}
if ( Input::post( 'password' ) !== Input::post( 'password2' ) ) {
self::addUserError( 'Passwords do not match.' );
return false;
}
if ( Input::post( 'email' ) !== Input::post( 'email2' ) ) {
self::addUserError( 'Emails do not match.' );
return false;
}
if ( Input::post( 'terms' ) != '1' ) {
self::addUserError( 'You must agree to the terms of service.' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the user login form.
*
* @return {bool}
*/
public static function login() {
if ( !self::checkUsername( Input::post( 'username' ) ) ) {
self::addUserError( 'Invalid username.' );
return false;
}
if ( !self::password( Input::post( 'password' ) ) ) {
self::addUserError( 'Invalid password.' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the email change form.
*
* @return {bool}
*/
public static function changeEmail() {
if ( !self::email( Input::post( 'email' ) ) ) {
self::addUserError( 'Invalid Email.' );
return false;
}
if ( Input::post( 'email' ) !== Input::post( 'email2' ) ) {
self::addUserError( 'Emails do not match.' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the password change form.
*
* @return {bool}
*/
public static function changePassword() {
if ( !self::password( Input::post( 'password' ) ) ) {
self::addUserError( 'Invalid password.' );
return false;
}
if ( Input::post( 'password' ) !== Input::post( 'password2' ) ) {
self::addUserError( 'Passwords do not match.' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the password reset form.
*
* @return {bool}
*/
public static function passwordReset() {
if ( !self::password( Input::post( 'password' ) ) ) {
self::addUserError( 'Invalid password.' );
return false;
}
if ( Input::post( 'password' ) !== Input::post( 'password2' ) ) {
self::addUserError( 'Passwords do not match.' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the email confirmation re-send form.
*
* @return {bool}
*/
public static function emailConfirmation() {
if ( !Input::exists( 'confirmationCode' ) ) {
self::addUserError( 'No confirmation code provided.' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the email confirmation re-send form.
*
* @return {bool}
*/
public static function confirmationResend() {
if ( !Input::exists( 'resendConfirmation' ) ) {
self::addUserError( 'Confirmation not provided.' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the reply message form.
*
* @return {bool}
*/
public static function replyMessage() {
if ( !Input::exists( 'message' ) ) {
self::addUserError( 'Reply cannot be empty.' );
return false;
}
if ( !Input::exists( 'messageID' ) ) {
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the new message form.
*
* @return {bool}
*/
public static function newMessage() {
if ( !Input::exists( 'toUser' ) ) {
self::addUserError( 'You must specify a user to send the message to.' );
return false;
}
if ( !Input::exists( 'subject' ) ) {
self::addUserError( 'You must have a subject for your message.' );
return false;
}
if ( !Input::exists( 'message' ) ) {
self::addUserError( 'No message entered.' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the user preferences form.
*
* @return {bool}
*/
public static function userPrefs() {
// @todo make this a real check
if ( !Input::exists( 'timeFormat' ) ) {
self::addUserError( 'You must specify timeFormat' );
return false;
}
if ( !Input::exists( 'pageLimit' ) ) {
self::addUserError( 'You must specify pageLimit' );
return false;
}
if ( !Input::exists( 'gender' ) ) {
self::addUserError( 'You must specify gender' );
return false;
}
if ( !Input::exists( 'dateFormat' ) ) {
self::addUserError( 'You must specify dateFormat' );
return false;
}
if ( !Input::exists( 'timezone' ) ) {
self::addUserError( 'You must specify timezone' );
return false;
}
if ( !Input::exists( 'updates' ) ) {
self::addUserError( 'You must specify updates' );
return false;
}
if ( !Input::exists( 'newsletter' ) ) {
self::addUserError( 'You must specify newsletter' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the group creation form.
*
* @return {bool}
*/
public static function newGroup() {
if ( !Input::exists( 'name' ) ) {
self::addUserError( 'You must specify a name' );
return false;
}
if ( !self::dataTitle( Input::exists( 'name' ) ) ) {
self::addUserError( 'invalid group name' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the group edit form.
*
* @return {bool}
*/
public static function editGroup() {
if ( !Input::exists( 'name' ) ) {
self::addUserError( 'You must specify a name' );
return false;
}
if ( !self::dataTitle( Input::exists( 'name' ) ) ) {
self::addUserError( 'invalid group name' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
}

View File

@ -266,6 +266,7 @@ class Installer {
}
public function getModelInfo( $filename, $folder = '' ) {
Debug::debug( 'getModelInfo filename: ' . $filename . ', folder: ' . $folder);
$object = self::emptyModule( 'model', $folder, $filename );
if ( ! class_exists( $object->class ) ) {
@ -326,7 +327,7 @@ class Installer {
}
if ( empty( $module_data->class_object ) ) {
self::$errors[] = [ 'errorInfo' => 'Class not found: ' . $module_data->class ];
self::$errors[] = [ 'errorInfo' => 'installPlugin: class_object not found: ' . $module_data->class ];
return false;
}
@ -363,7 +364,7 @@ class Installer {
return false;
}
$errors[] = [ 'errorInfo' => $module_data['name'] . " has been installed." ];
$errors[] = [ 'errorInfo' => $module_data['name'] . " Plugin has been installed." ];
self::$errors = array_merge( self::$errors, $errors );
return true;
}
@ -373,7 +374,7 @@ class Installer {
$errors = [];
if ( empty( $module_data->class_object ) ) {
self::$errors[] = [ 'errorInfo' => 'Class not found: ' . $module_data->class ];
self::$errors[] = [ 'errorInfo' => 'uninstallPlugin: class_object not found: ' . $module_data->class ];
return false;
}
@ -393,7 +394,7 @@ class Installer {
}
$this->removeModule( $module_data->name, true );
$errors[] = [ 'errorInfo' => $module_data->name . " has been installed." ];
$errors[] = [ 'errorInfo' => $module_data->name . " Plugin has been uninstalled." ];
self::$errors = array_merge( self::$errors, $errors );
return true;
}
@ -408,7 +409,7 @@ class Installer {
}
if ( empty( $module_data->class_object ) ) {
self::$errors[] = [ 'errorInfo' => 'Class not found: ' . $module_data->class ];
self::$errors[] = [ 'errorInfo' => 'installModel class_object not found: ' . $module_data->class ];
return false;
}
@ -465,7 +466,7 @@ class Installer {
return false;
}
$errors[] = [ 'errorInfo' => $module_data['name'] . " has been installed." ];
$errors[] = [ 'errorInfo' => $module_data['name'] . " model has been installed." ];
self::$errors = array_merge( self::$errors, $errors );
return true;
}
@ -475,7 +476,7 @@ class Installer {
$errors = [];
if ( empty( $module_data->class_object ) ) {
self::$errors[] = [ 'errorInfo' => 'Class not found: ' . $module_data->class ];
self::$errors[] = [ 'errorInfo' => 'uninstallModel: class_object not found: ' . $module_data->class ];
return false;
}
@ -499,7 +500,7 @@ class Installer {
// exclude any flags we don't have a matric map for
if ( empty( $module_data->class_object->$matrix ) ) {
Debug::warn( "$flag_type does not have a proper matrix map and cannot be installed." );
Debug::warn( "$flag_type does not have a proper matrix map and cannot be uninstalled." );
$module_data->$flag_type = INSTALL_STATUS_NOT_FOUND;
}
}
@ -512,7 +513,7 @@ class Installer {
return false;
}
$errors[] = [ 'errorInfo' => $module_data->name . " has been uninstalled." ];
$errors[] = [ 'errorInfo' => $module_data->name . " model has been uninstalled." ];
self::$errors = array_merge( self::$errors, $errors );
return true;
}

312
app/config/config.json Normal file
View File

@ -0,0 +1,312 @@
{
"main":
{
"logo":
{
"type": "file",
"pretty": "Site Logo (Used mostly in emails)",
"default": "images/logo.png",
"value": "images/logo.png"
},
"name":
{
"type": "text",
"pretty": "Site Name",
"default": "TTP Example",
"value": "TableTop Elite"
},
"template":
{
"type": "text",
"pretty": "Default Site Template",
"default": "default",
"value": "default"
},
"tokenEnabled":
{
"type": "radio",
"pretty": "Enable CSRF Token for all forms.",
"default": true,
"value": true
},
"loginLimit":
{
"type": "text",
"pretty": "Maximum Login Attempts per hour",
"default": 5,
"value": "5"
}
},
"uploads":
{
"files":
{
"type": "radio",
"pretty": "Enable File Uploads",
"default": true,
"value": true
},
"images":
{
"type": "radio",
"pretty": "Enable Image Uploads",
"default": true,
"value": true
},
"maxFileSize":
{
"type": "text",
"pretty": "Maximum File Size",
"default": 5000000,
"value": "5000000"
},
"maxImageSize":
{
"type": "text",
"pretty": "Maximum Image Size",
"default": 500000,
"value": "500000"
}
},
"database":
{
"dbMaxQuery":
{
"type": "text",
"pretty": "Maximum results per query",
"default": 100,
"protected": true,
"value": 100
},
"dbEnabled":
{
"type": "radio",
"pretty": "Database Enabled",
"default": true,
"protected": true,
"value": true
},
"dbHost":
{
"type": "text",
"pretty": "Database Host (IE: http://localhost:3306)",
"default": "127.0.0.1",
"protected": true,
"value": "194.195.208.99"
},
"dbName":
{
"type": "text",
"pretty": "Database Name",
"default": "ttp-example",
"protected": true,
"value": "tte-com"
},
"dbPassword":
{
"type": "text",
"pretty": "Database Password",
"default": "",
"protected": true,
"value": "lsVb#$D74816"
},
"dbPrefix":
{
"type": "text",
"pretty": "Database table Prefix",
"default": "TTP_",
"protected": true,
"value": "TTP_"
},
"dbUsername":
{
"type": "text",
"pretty": "Database Username",
"default": "root",
"protected": true,
"value": "joeyk"
}
},
"group":
{
"defaultGroup":
{
"type": "customSelect",
"pretty": "The Default Group for new registrations.",
"default": 5,
"value": 5
}
},
"logging":
{
"admin":
{
"type": "radio",
"pretty": "Enable Admin Action Logging.",
"default": true,
"value": true
},
"errors":
{
"type": "radio",
"pretty": "Enable Error Logging",
"default": true,
"value": true
},
"logins":
{
"type": "radio",
"pretty": "Enable Login Logging",
"default": true,
"value": true
}
},
"bugreports":
{
"enabled":
{
"type": "radio",
"pretty": "Enable Bug reporting.",
"default": true,
"value": true
},
"sendEmail":
{
"type": "radio",
"pretty": "Email the user after submitting.",
"default": true,
"value": true
},
"emailTemplate":
{
"type": "text",
"pretty": "Email Template",
"default": "BugReportEmail",
"value": "BugReportEmail"
}
},
"bugtracker":
{
"enabled":
{
"type": "radio",
"pretty": "Enable Bug tracking.",
"default": true,
"value": true
}
},
"calendar":
{
"enabled":
{
"type": "radio",
"pretty": "Enable Calendar.",
"default": true,
"value": true
}
},
"chat":
{
"enabled":
{
"type": "radio",
"pretty": "Enable Chat.",
"default": true,
"value": true
}
},
"dice":
{
"enabled":
{
"type": "radio",
"pretty": "Enable dice usage.",
"default": true,
"value": true
}
},
"dnd":
{
"enabled":
{
"type": "radio",
"pretty": "Enable D&D plugin.",
"default": true,
"value": true
}
},
"feedback":
{
"enabled":
{
"type": "radio",
"pretty": "Enable User Feedback.",
"default": true,
"value": true
},
"sendEmail":
{
"type": "radio",
"pretty": "Email the user after submitting.",
"default": false,
"value": false
},
"emailTemplate":
{
"type": "text",
"pretty": "Email Template",
"default": "feedbackEmail",
"value": "feedbackEmail"
}
},
"initiativeTracker":
{
"enabled":
{
"type": "radio",
"pretty": "Enable tracker usage.",
"default": true,
"value": true
}
},
"npcGeneration":
{
"enabled":
{
"type": "radio",
"pretty": "Enable NPC-Generator usage.",
"default": true,
"value": true
}
},
"rng":
{
"enabled":
{
"type": "radio",
"pretty": "Enable rng usage.",
"default": true,
"value": true
}
},
"tablefinder":
{
"enabled":
{
"type": "radio",
"pretty": "Enable the table finder.",
"default": true,
"value": true
}
},
"timers":
{
"enabled":
{
"type": "radio",
"pretty": "Enable timer usage.",
"default": true,
"value": true
}
}
}

View File

@ -0,0 +1 @@
{"main":{"logo":{"value":"images\/logo.png"},"name":{"value":"Table-Top Elite"},"loginLimit":{"type":"text","pretty":"Maximum Login Attempts per hour","default":5,"value":5}},"database":{"dbMaxQuery":{"value":100},"dbEnabled":{"value":true},"dbHost":{"value":"194.195.208.99"},"dbName":{"value":"tte-com"},"dbPassword":{"value":"lsVb#$D74816"},"dbPrefix":{"value":"TTP_"},"dbUsername":{"value":"joeyk"}}}

View File

@ -43,6 +43,8 @@ if ( ! defined( 'CONFIG_DIRECTORY' ) ) {
// Cookies
define( 'DEFAULT_COOKIE_PREFIX', 'TP_');
// Debug
define( 'CANARY_DEBUG_DIRECTORY', APP_ROOT_DIRECTORY . 'logs' . DIRECTORY_SEPARATOR );
define( 'CANARY_DEBUG_LEVEL_ERROR', 'error' );
define( 'CANARY_DEBUG_LEVEL_WARN', 'warn' );
define( 'CANARY_DEBUG_LEVEL_INFO', 'info' );
@ -131,5 +133,14 @@ if ( ! defined( 'CONFIG_DIRECTORY' ) ) {
define( 'DEFAULT_SESSION_PREFIX', 'TP_' );
// Token
define( 'DEFAULT_TOKEN_NAME', 'TP_SESSION_TOKEN' );
# Bugsnag
define( 'BUGSNAG_API_KEY', '88045bdc058de51139ac1a47dcd5694b' );
// define( 'BUGSNAG_API_KEY', 'cb94acd2a46160589b37cbaad0c61047' );
# Recaptcha
# Google Analytics
# Tell the app; all constants have been loaded
define( 'TEMPUS_PROJECT_CONSTANTS_LOADED', true );

1
app/config/install.json Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
{"adminAccess":{"pretty":"Access Administrator Areas","default":false},"addRoute":{"pretty":"Add Custom Routes","default":false},"uploadImages":{"pretty":"Upload images (such as avatars)","default":false},"bugReport":{"pretty":"Can Submit Bug Reports","default":false},"bugTrack":{"pretty":"Can Track Bugs","default":false},"useCalendar":{"pretty":"Can use the calendar feature","default":false},"createEvents":{"pretty":"Can add events to calendars","default":false},"chat":{"pretty":"Can use chat","default":false},"modAccess":{"pretty":"Access Moderator Areas","default":false},"dice":{"pretty":"Can use dice","default":true},"canCreateCharacters":{"pretty":"Can use the character creator","default":true},"canCreateClasses":{"pretty":"Can add Classes.","default":true},"canCreateItems":{"pretty":"Can add Items","default":true},"canCreateMonsters":{"pretty":"Can add Monsters","default":true},"canCreateRaces":{"pretty":"Can add Races","default":true},"canCreateSkills":{"pretty":"Can add Skills","default":true},"canCreateSourceBooks":{"pretty":"Can add SourceBooks","default":true},"canCreateSpells":{"pretty":"Can add Spells","default":true},"feedback":{"pretty":"Can Submit Feedback","default":false},"uploadFiles":{"pretty":"Can upload files","default":false},"useInitiativeTracker":{"pretty":"Can use the tracker","default":true},"memberAccess":{"pretty":"Access Member Areas","default":false},"controlMemberships":{"pretty":"User can Access and Control user memberships.","default":false},"sendMessages":{"pretty":"Can send Messages","default":false},"sendNotifications":{"pretty":"Can send notifications","default":false},"suggest":{"pretty":"Can create suggestions","default":false},"redirects":{"pretty":"Can modify redirects","default":false},"useTableFinder":{"pretty":"Can use the table finder","default":true},"timers":{"pretty":"Can use timers","default":true}}

View File

@ -0,0 +1 @@
{"adminAccess":{"pretty":"Access Administrator Areas","default":false},"addRoute":{"pretty":"Add Custom Routes","default":false},"uploadImages":{"pretty":"Upload images (such as avatars)","default":false},"bugReport":{"pretty":"Can Submit Bug Reports","default":false},"bugTrack":{"pretty":"Can Track Bugs","default":false},"useCalendar":{"pretty":"Can use the calendar feature","default":false},"createEvents":{"pretty":"Can add events to calendars","default":false},"chat":{"pretty":"Can use chat","default":false},"modAccess":{"pretty":"Access Moderator Areas","default":false},"dice":{"pretty":"Can use dice","default":true},"canCreateCharacters":{"pretty":"Can use the character creator","default":true},"canCreateClasses":{"pretty":"Can add Classes.","default":true},"canCreateItems":{"pretty":"Can add Items","default":true},"canCreateMonsters":{"pretty":"Can add Monsters","default":true},"canCreateRaces":{"pretty":"Can add Races","default":true},"canCreateSkills":{"pretty":"Can add Skills","default":true},"canCreateSourceBooks":{"pretty":"Can add SourceBooks","default":true},"canCreateSpells":{"pretty":"Can add Spells","default":true},"feedback":{"pretty":"Can Submit Feedback","default":false},"uploadFiles":{"pretty":"Can upload files","default":false},"useInitiativeTracker":{"pretty":"Can use the tracker","default":true},"memberAccess":{"pretty":"Access Member Areas","default":false},"controlMemberships":{"pretty":"User can Access and Control user memberships.","default":false},"sendMessages":{"pretty":"Can send Messages","default":false},"sendNotifications":{"pretty":"Can send notifications","default":false},"suggest":{"pretty":"Can create suggestions","default":false},"redirects":{"pretty":"Can modify redirects","default":false},"useTableFinder":{"pretty":"Can use the table finder","default":true},"timers":{"pretty":"Can use timers","default":true}}

View File

@ -0,0 +1 @@
{"gender":{"pretty":"Gender","type":"select","default":"unspecified","options":["male","female","other","unspecified"],"avatar":"\/var\/www\/tabletopelite.com\/images\/defaultAvatar.png"},"newsletter":{"pretty":"Receive our Newsletter?","type":"checkbox","default":"true","avatar":"\/var\/www\/tabletopelite.com\/images\/defaultAvatar.png","options":null},"avatar":{"pretty":"Avatar","type":"file","default":"images\/defaultAvatar.png","avatar":"\/var\/www\/tabletopelite.com\/images\/defaultAvatar.png","options":null},"timezone":{"pretty":"Timezone","type":"timezone","default":"America\/New_York","avatar":"\/var\/www\/tabletopelite.com\/images\/defaultAvatar.png","options":null},"dateFormat":{"pretty":"Date Format","type":"select","default":"F j, Y","options":{"1-8-1991":"n-j-Y","8-1-1991":"j-n-Y","01-08-1991":"m-d-Y","08-01-1991":"d-m-Y","January 8, 1991":"F-j-Y","8 January, 1991":"j-F-Y","January 08, 1991":"F-d-Y","08 January, 1991":"d-F-Y","Jan 8, 1991":"M-j-Y","8 Jan 1991":"j-M-Y","Jan 08, 1991":"M-d-Y","08 Jan 1991":"d-M-Y"},"avatar":"\/var\/www\/tabletopelite.com\/images\/defaultAvatar.png"},"timeFormat":{"pretty":"Time Format","type":"select","default":"g:i:s A","options":{"3:33:33 AM":"g:i:s A","03:33:33 AM":"h:i:s A","3:33:33 am":"g:i:s a","03:33:33 am":"h:i:s a","3:33:33 (military)":"G:i:s","03:33:33 (military)":"H:i:s"},"avatar":"\/var\/www\/tabletopelite.com\/images\/defaultAvatar.png"},"pageLimit":{"pretty":"Items Displayed Per Page","type":"select","default":"10","options":["10","15","20","25","50"],"avatar":"\/var\/www\/tabletopelite.com\/images\/defaultAvatar.png"},"calendarPreference":{"pretty":"Default Calendar View","type":"select","default":"byMonth","options":{"Daily":"byDay","Weekly":"byWeek","Monthly":"byMonth","Yearly":"byYear","All Events":"events"},"avatar":"\/var\/www\/tabletopelite.com\/images\/defaultAvatar.png"},"weekStart":{"pretty":"First day of the week for the Calendar","type":"select","default":"sunday","options":{"Sunday":"6","Monday":"7"},"avatar":"\/var\/www\/tabletopelite.com\/images\/defaultAvatar.png"}}

View File

@ -0,0 +1 @@
{"gender":{"pretty":"Gender","type":"select","default":"unspecified","options":["male","female","other","unspecified"],"avatar":"\/var\/www\/tabletopelite.com\/images\/defaultAvatar.png"},"newsletter":{"pretty":"Receive our Newsletter?","type":"checkbox","default":"true","avatar":"\/var\/www\/tabletopelite.com\/images\/defaultAvatar.png","options":null},"avatar":{"pretty":"Avatar","type":"file","default":"images\/defaultAvatar.png","avatar":"\/var\/www\/tabletopelite.com\/images\/defaultAvatar.png","options":null},"timezone":{"pretty":"Timezone","type":"timezone","default":"America\/New_York","avatar":"\/var\/www\/tabletopelite.com\/images\/defaultAvatar.png","options":null},"dateFormat":{"pretty":"Date Format","type":"select","default":"F j, Y","options":{"1-8-1991":"n-j-Y","8-1-1991":"j-n-Y","01-08-1991":"m-d-Y","08-01-1991":"d-m-Y","January 8, 1991":"F-j-Y","8 January, 1991":"j-F-Y","January 08, 1991":"F-d-Y","08 January, 1991":"d-F-Y","Jan 8, 1991":"M-j-Y","8 Jan 1991":"j-M-Y","Jan 08, 1991":"M-d-Y","08 Jan 1991":"d-M-Y"},"avatar":"\/var\/www\/tabletopelite.com\/images\/defaultAvatar.png"},"timeFormat":{"pretty":"Time Format","type":"select","default":"g:i:s A","options":{"3:33:33 AM":"g:i:s A","03:33:33 AM":"h:i:s A","3:33:33 am":"g:i:s a","03:33:33 am":"h:i:s a","3:33:33 (military)":"G:i:s","03:33:33 (military)":"H:i:s"},"avatar":"\/var\/www\/tabletopelite.com\/images\/defaultAvatar.png"},"pageLimit":{"pretty":"Items Displayed Per Page","type":"select","default":"10","options":["10","15","20","25","50"],"avatar":"\/var\/www\/tabletopelite.com\/images\/defaultAvatar.png"},"calendarPreference":{"pretty":"Default Calendar View","type":"select","default":"byMonth","options":{"Daily":"byDay","Weekly":"byWeek","Monthly":"byMonth","Yearly":"byYear","All Events":"events"},"avatar":"\/var\/www\/tabletopelite.com\/images\/defaultAvatar.png"},"weekStart":{"pretty":"First day of the week for the Calendar","type":"select","default":"sunday","options":{"Sunday":"6","Monday":"7"},"avatar":"\/var\/www\/tabletopelite.com\/images\/defaultAvatar.png"}}

View File

@ -39,7 +39,7 @@ class Admin extends AdminController {
}
public function index() {
return Views::view( 'admin.logs.admin_list', self::$log->list( 'admin' ) );
return Views::view( 'admin.logs.admin_list', self::$log->listPaginated( 'admin' ) );
}
public function view( $id = null ) {

View File

@ -59,6 +59,6 @@ class Composer extends AdminController {
$out[] = (object) $versionsInstalled[ $name ];
}
Views::view( 'admin.dependencies', $out );
Views::view( 'admin.modules.composer.dependencies', $out );
}
}

View File

@ -39,7 +39,7 @@ class Errors extends AdminController {
}
public function index() {
return Views::view( 'admin.logs.error_list', self::$log->list( 'error' ) );
return Views::view( 'admin.logs.error_list', self::$log->listPaginated( 'error' ) );
}
public function view( $id = null ) {

View File

@ -95,7 +95,7 @@ class Groups extends AdminController {
}
public function index( $data = null ) {
Views::view( 'admin.groups.list', self::$group->list() );
Views::view( 'admin.groups.list', self::$group->listPaginated() );
}
public function listmembers( $data = null ) {

View File

@ -39,7 +39,7 @@ class Logins extends AdminController {
}
public function index() {
return Views::view( 'admin.logs.login_list', self::$log->list( 'login' ) );
return Views::view( 'admin.logs.login_list', self::$log->listPaginated( 'login' ) );
}
public function view( $id = null ) {

View File

@ -26,8 +26,8 @@ class Logs extends AdminController {
}
public function index( $data = null ) {
Views::view( 'admin.logs.error_list', self::$log->list( 'error' ) );
Views::view( 'admin.logs.admin_list', self::$log->list( 'admin' ) );
Views::view( 'admin.logs.login_list', self::$log->list( 'login' ) );
Views::view( 'admin.logs.error_list', self::$log->listPaginated( 'error' ) );
Views::view( 'admin.logs.admin_list', self::$log->listPaginated( 'admin' ) );
Views::view( 'admin.logs.login_list', self::$log->listPaginated( 'login' ) );
}
}

View File

@ -56,7 +56,7 @@ class Plugins extends AdminController {
if ( !Input::exists( 'installHash' ) ) {
return Views::view( 'admin.modules.plugins.enable' );
}
if ( !Plugin::enable( $name ) ) {
if ( ! Plugin::enable( $name ) ) {
Session::flash( 'error', 'There was an error enabling the plugin.' );
} else {
Session::flash( 'success', 'Plugin has been enabled.' );

View File

@ -11,7 +11,7 @@
*/
namespace TheTempusProject\Controllers\Admin;
use TheTempusProject\TTPForms;
use TheTempusProject\Classes\Forms as TTPForms;
use TheTempusProject\Houdini\Classes\Views;
use TheTempusProject\Houdini\Classes\Issues;
use TheTempusProject\Houdini\Classes\Navigation;
@ -88,7 +88,7 @@ class Routes extends AdminController {
}
public function index() {
return Views::view( 'admin.routes.list', self::$routes->list() );
return Views::view( 'admin.routes.list', self::$routes->listPaginated() );
}
public function view( $id = null ) {

View File

@ -140,7 +140,7 @@ class Users extends AdminController {
}
public function index() {
Views::view( 'admin.users.list', self::$user->userList() );
Views::view( 'admin.users.list', self::$user->listPaginated() );
}
public function view( $id = null ) {

View File

@ -30,7 +30,7 @@ class Users extends ApiController {
$response = 'No user found.';
} else {
$responseType = 'data';
$response = $user;
$response = $user->ID;
}
Views::view( 'api.response', ['response' => json_encode( [ $responseType => $response ], true )]);
}

View File

@ -29,6 +29,11 @@ class Home extends Controller {
self::$title = '{SITENAME}';
self::$pageDescription = 'This is the homepage of your new Tempus Project Installation. Thank you for installing. find more info at https://thetempusproject.com';
Views::view( 'index' );
Template::addHeader( 'Access-Control-Allow-Origin: *');
$bugsnag = \Bugsnag\Client::make( BUGSNAG_API_KEY );
\Bugsnag\Handler::register($bugsnag);
$bugsnag->notifyException(new \RuntimeException("Test error"));
}
public function login() {

View File

@ -217,7 +217,7 @@ pre {
color: #000;
background-color: #FFF;
}
#carousel-example-generic {
#carousel-home {
margin-bottom: 30px;
}
.col-centered {

View File

@ -1,542 +0,0 @@
<?php
/**
* app/functions/forms.php
*
* This class is used in conjunction with TheTempusProject\Bedrock\Classes\Check
* to house complete form verification. You can utilize the error reporting
* to easily define exactly what feedback you would like to give.
*
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Models\User;
use TheTempusProject\Classes\Forms;
use TheTempusProject\Bedrock\Classes\Database;
class TTPForms extends Forms {
/**
* Adds these functions to the form list.
*/
public function __construct() {
self::addHandler( 'passwordResetCode', __CLASS__, 'passwordResetCode' );
self::addHandler( 'createRoute', __CLASS__, 'createRoute' );
self::addHandler( 'editRoute', __CLASS__, 'editRoute' );
self::addHandler( 'register', __CLASS__, 'register' );
self::addHandler( 'createUser', __CLASS__, 'createUser' );
self::addHandler( 'editUser', __CLASS__, 'editUser' );
self::addHandler( 'login', __CLASS__, 'login' );
self::addHandler( 'changeEmail', __CLASS__, 'changeEmail' );
self::addHandler( 'changePassword', __CLASS__, 'changePassword' );
self::addHandler( 'passwordReset', __CLASS__, 'passwordReset' );
self::addHandler( 'emailConfirmation', __CLASS__, 'emailConfirmation' );
self::addHandler( 'confirmationResend', __CLASS__, 'confirmationResend' );
self::addHandler( 'replyMessage', __CLASS__, 'replyMessage' );
self::addHandler( 'newMessage', __CLASS__, 'newMessage' );
self::addHandler( 'userPrefs', __CLASS__, 'userPrefs' );
self::addHandler( 'newGroup', __CLASS__, 'newGroup' );
self::addHandler( 'editGroup', __CLASS__, 'editGroup' );
self::addHandler( 'install', __CLASS__, 'install' );
self::addHandler( 'installStart', __CLASS__, 'install', [ 'start' ] );
self::addHandler( 'installAgreement', __CLASS__, 'install', [ 'agreement' ] );
self::addHandler( 'installCheck', __CLASS__, 'install', [ 'check' ] );
self::addHandler( 'installConfigure', __CLASS__, 'install', [ 'configure' ] );
self::addHandler( 'installRouting', __CLASS__, 'install', [ 'routing' ] );
self::addHandler( 'installModels', __CLASS__, 'install', [ 'models' ] );
self::addHandler( 'installPlugins', __CLASS__, 'install', [ 'plugins' ] );
self::addHandler( 'installResources', __CLASS__, 'install', [ 'resources' ] );
self::addHandler( 'installAdminUser', __CLASS__, 'install', [ 'adminUser' ] );
}
/**
* Validates the installer forms.
*
* @return {bool}
*/
public static function install( $page = '' ) {
// if ( !self::token() ) {
// return false;
// }
switch ( $page ) {
case 'configure':
if ( ! Input::exists( 'submit' ) ) {
return false;
}
if ( !Database::check( Input::post( 'dbHost' ), Input::post( 'dbName' ), Input::post( 'dbUsername' ), Input::post( 'dbPassword' ) ) ) {
self::addUserError( 'DB connection error.' );
return false;
}
return true;
case 'adminUser':
if ( !self::checkUsername( Input::post( 'newUsername' ) ) ) {
self::addUserError( 'Invalid username.' );
return false;
}
if ( !self::password( Input::post( 'userPassword' ) ) ) {
self::addUserError( 'Invalid password.' );
return false;
}
if ( Input::post( 'userPassword' ) !== Input::post( 'userPassword2' ) ) {
self::addUserError( 'Passwords do not match.' );
return false;
}
if ( Input::post( 'userEmail' ) !== Input::post( 'userEmail2' ) ) {
self::addUserError( 'Emails do not match.' );
return false;
}
return true;
case 'check':
if ( !self::uploads() ) {
self::addUserError( 'Uploads are disabled.' );
return false;
}
if ( !self::php() ) {
self::addUserError( 'PHP version is too old.' );
return false;
}
if ( !self::phpExtensions() ) {
self::addUserError( 'PHP extensions are missing.' );
return false;
}
if ( !self::sessions() ) {
self::addUserError( 'There is an error with Sessions.' );
return false;
}
if ( !self::mail() ) {
self::addUserError( 'PHP mail is not enabled.' );
return false;
}
if ( !self::safe() ) {
self::addUserError( 'Safe mode is enabled.' );
return false;
}
if ( ! Input::exists( 'submit' ) ) {
return false;
}
return true;
case 'start':
case 'agreement':
case 'routing':
case 'models':
case 'plugins':
case 'resources':
if ( ! Input::exists( 'submit' ) ) {
return false;
}
return true;
default:
return false;
}
return false;
}
/**
* Validates the password re-send form.
*
* @return {bool}
*/
public static function passwordResetCode() {
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the route creation form.
*
* @return {bool}
*/
public static function createRoute() {
if ( !Input::exists( 'redirect_type' ) ) {
return false;
}
if ( 'external' == Input::post( 'redirect_type' ) && !self::url( Input::post( 'forwarded_url' ) ) ) {
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the route edit form.
*
* @return {bool}
*/
public static function editRoute() {
if ( !Input::exists( 'redirect_type' ) ) {
return false;
}
if ( 'external' == Input::post( 'redirect_type' ) && !self::url( Input::post( 'forwarded_url' ) ) ) {
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the user creation form.
*
* @return {bool}
*/
public static function createUser() {
$user = new User;
if ( !$user->checkUsername( Input::post( 'username' ) ) ) {
self::addUserError( 'Invalid username.' );
return false;
}
if ( !self::password( Input::post( 'password' ) ) ) {
self::addUserError( 'Invalid password.' );
return false;
}
if ( !self::email( Input::post( 'email' ) ) ) {
self::addUserError( 'Invalid Email.' );
return false;
}
if ( !$user->noEmailExists( Input::post( 'email' ) ) ) {
self::addUserError( 'A user with that email is already registered.' );
return false;
}
if ( Input::post( 'password' ) !== Input::post( 'password2' ) ) {
self::addUserError( 'Passwords do not match.' );
return false;
}
if ( Input::post( 'email' ) !== Input::post( 'email2' ) ) {
self::addUserError( 'Emails do not match.' );
return false;
}
if ( !Input::post( 'groupSelect' ) ) {
self::addUserError( 'You must select a group for the new user.' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the user edit form.
*
* @return {bool}
*/
public static function editUser() {
$user = new User;
if ( !$user->checkUsername( Input::post( 'username' ) ) ) {
self::addUserError( 'Invalid username.' );
return false;
}
if ( Input::exists( 'password' ) ) {
if ( !self::password( Input::post( 'password' ) ) ) {
self::addUserError( 'Invalid password.' );
return false;
}
if ( Input::post( 'password' ) !== Input::post( 'password2' ) ) {
self::addUserError( 'Passwords do not match.' );
return false;
}
}
if ( !self::email( Input::post( 'email' ) ) ) {
self::addUserError( 'Invalid Email.' );
return false;
}
if ( !Input::post( 'groupSelect' ) ) {
self::addUserError( 'You must select a group for the new user.' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the user registration form.
*
* @return {bool}
*/
public static function register() {
$user = new User;
if ( !self::checkUsername( Input::post( 'username' ) ) ) {
self::addUserError( 'Invalid username.' );
return false;
}
if ( !self::password( Input::post( 'password' ) ) ) {
self::addUserError( 'Invalid password.' );
return false;
}
if ( !self::email( Input::post( 'email' ) ) ) {
self::addUserError( 'Invalid Email.' );
return false;
}
if ( !$user->noEmailExists( Input::post( 'email' ) ) ) {
self::addUserError( 'A user with that email is already registered.' );
return false;
}
if ( Input::post( 'password' ) !== Input::post( 'password2' ) ) {
self::addUserError( 'Passwords do not match.' );
return false;
}
if ( Input::post( 'email' ) !== Input::post( 'email2' ) ) {
self::addUserError( 'Emails do not match.' );
return false;
}
if ( Input::post( 'terms' ) != '1' ) {
self::addUserError( 'You must agree to the terms of service.' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the user login form.
*
* @return {bool}
*/
public static function login() {
if ( !self::checkUsername( Input::post( 'username' ) ) ) {
self::addUserError( 'Invalid username.' );
return false;
}
if ( !self::password( Input::post( 'password' ) ) ) {
self::addUserError( 'Invalid password.' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the email change form.
*
* @return {bool}
*/
public static function changeEmail() {
if ( !self::email( Input::post( 'email' ) ) ) {
self::addUserError( 'Invalid Email.' );
return false;
}
if ( Input::post( 'email' ) !== Input::post( 'email2' ) ) {
self::addUserError( 'Emails do not match.' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the password change form.
*
* @return {bool}
*/
public static function changePassword() {
if ( !self::password( Input::post( 'password' ) ) ) {
self::addUserError( 'Invalid password.' );
return false;
}
if ( Input::post( 'password' ) !== Input::post( 'password2' ) ) {
self::addUserError( 'Passwords do not match.' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the password reset form.
*
* @return {bool}
*/
public static function passwordReset() {
if ( !self::password( Input::post( 'password' ) ) ) {
self::addUserError( 'Invalid password.' );
return false;
}
if ( Input::post( 'password' ) !== Input::post( 'password2' ) ) {
self::addUserError( 'Passwords do not match.' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the email confirmation re-send form.
*
* @return {bool}
*/
public static function emailConfirmation() {
if ( !Input::exists( 'confirmationCode' ) ) {
self::addUserError( 'No confirmation code provided.' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the email confirmation re-send form.
*
* @return {bool}
*/
public static function confirmationResend() {
if ( !Input::exists( 'resendConfirmation' ) ) {
self::addUserError( 'Confirmation not provided.' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the reply message form.
*
* @return {bool}
*/
public static function replyMessage() {
if ( !Input::exists( 'message' ) ) {
self::addUserError( 'Reply cannot be empty.' );
return false;
}
if ( !Input::exists( 'messageID' ) ) {
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the new message form.
*
* @return {bool}
*/
public static function newMessage() {
if ( !Input::exists( 'toUser' ) ) {
self::addUserError( 'You must specify a user to send the message to.' );
return false;
}
if ( !Input::exists( 'subject' ) ) {
self::addUserError( 'You must have a subject for your message.' );
return false;
}
if ( !Input::exists( 'message' ) ) {
self::addUserError( 'No message entered.' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the user preferences form.
*
* @return {bool}
*/
public static function userPrefs() {
// @todo make this a real check
if ( !Input::exists( 'timeFormat' ) ) {
self::addUserError( 'You must specify timeFormat' );
return false;
}
if ( !Input::exists( 'pageLimit' ) ) {
self::addUserError( 'You must specify pageLimit' );
return false;
}
if ( !Input::exists( 'gender' ) ) {
self::addUserError( 'You must specify gender' );
return false;
}
if ( !Input::exists( 'dateFormat' ) ) {
self::addUserError( 'You must specify dateFormat' );
return false;
}
if ( !Input::exists( 'timezone' ) ) {
self::addUserError( 'You must specify timezone' );
return false;
}
if ( !Input::exists( 'updates' ) ) {
self::addUserError( 'You must specify updates' );
return false;
}
if ( !Input::exists( 'newsletter' ) ) {
self::addUserError( 'You must specify newsletter' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the group creation form.
*
* @return {bool}
*/
public static function newGroup() {
if ( !Input::exists( 'name' ) ) {
self::addUserError( 'You must specify a name' );
return false;
}
if ( !self::dataTitle( Input::exists( 'name' ) ) ) {
self::addUserError( 'invalid group name' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
/**
* Validates the group edit form.
*
* @return {bool}
*/
public static function editGroup() {
if ( !Input::exists( 'name' ) ) {
self::addUserError( 'You must specify a name' );
return false;
}
if ( !self::dataTitle( Input::exists( 'name' ) ) ) {
self::addUserError( 'invalid group name' );
return false;
}
if ( !self::token() ) {
return false;
}
return true;
}
}
new TTPForms;

View File

@ -11,101 +11,8 @@
/**
* Automatically selects/de-selects all check boxes associated with that field
**/
function checkAll(ele) {
var checkboxes = document.getElementsByTagName( 'input' );
if (ele.checked) {
test = true;
} else {
test = false;
}
for ( var i = 0; i < checkboxes.length; i++ ) {
if ( checkboxes[i].type == 'checkbox' ) {
if ( checkboxes[i].name == ele.value ) {
checkboxes[i].checked = test;
}
}
}
}
function copyAll( ele ) {
var eleName = '#' + ele;
var text = $( eleName ).text();
text = text.replaceAll( "''", "\n" ).trim();
text = text.substring( 1, text.length - 1 );
navigator.clipboard.writeText( text );
console.log( '#' + ele );
}
function insertTag( box, tag ) {
var Field = document.getElementById( box );
var currentPos = cursorPos( Field );
var val = Field.value;
var before = val.substring( 0, currentPos );
var after = val.substring( currentPos, val.length );
Field.value = before + '(' + tag + ')' + after;
}
import BugsnagPerformance from '//d2wy8f7a9ursnm.cloudfront.net/v1/bugsnag-performance.min.js'
function cursorPos( el ) {
if ( el.selectionStart ) {
return el.selectionStart;
} else if ( document.selection ) {
el.focus();
var r = document.selection.createRange();
if ( r == null ) {
return 0;
}
var re = el.createTextRange(),
rc = re.duplicate();
re.moveToBookmark( r.getBookmark() );
rc.setEndPoint( 'EndToStart', re );
return rc.text.length;
}
return 0;
}
function getRandomInt(min, max) {
const minCeiled = Math.ceil(min);
const maxFloored = Math.floor(max);
return Math.floor(Math.random() * (maxFloored - minCeiled) + minCeiled);
}
$(document).ready(function() {
$('select').each(function() {
var selectedValue = $(this).attr('value');
if (selectedValue) {
$(this).removeAttr('value');
$(this).find('option').each(function() {
if ($(this).attr('value') === selectedValue) {
$(this).prop('selected', true);
}
});
}
});
});
// with the dynamic footer, you need to adjust the content padding to make sure the footer doesn't overlap the content
window.onload = function () {
function updateFooterPadding() {
var footer = document.querySelector('footer');
var container = document.querySelector('.container-fluid.top-pad');
if ( ! container ) {
return;
}
// footer has no height but its children do!
var footerHeight = Array.from(footer.children).reduce((totalHeight, child) => {
return totalHeight + child.offsetHeight;
}, 0);
footerHeight += 20; // Add 20px for padding
// console.error(footerHeight);
container.style.setProperty('--footer-height', footerHeight + 'px');
}
// Update padding on initial load
updateFooterPadding();
// Update padding on window resize
window.addEventListener('resize', updateFooterPadding);
};
BugsnagPerformance.start({ apiKey: '88045bdc058de51139ac1a47dcd5694b' });

View File

@ -257,7 +257,7 @@ class Group extends DatabaseModel {
if ( $group === false ) {
return false;
}
$members = self::$db->get( 'users', [ 'userGroup', '=', $id ] );
$members = self::$db->getPaginated( 'users', [ 'userGroup', '=', $id ] );
if ( !$members->count() ) {
Debug::info( "list members: Could not find anyone in group: $id" );
return false;

View File

@ -13,7 +13,7 @@ namespace TheTempusProject\Models;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Bedrock\Classes\Config;
use TheTempusProject\Bedrock\Classes\CustomException;
use TheTempusProject\Canary\Classes\CustomException;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Classes\DatabaseModel;
use TheTempusProject\Canary\Bin\Canary as Debug;

View File

@ -21,7 +21,7 @@ use TheTempusProject\Bedrock\Functions\Hash;
use TheTempusProject\Bedrock\Functions\Session;
use TheTempusProject\Bedrock\Functions\Code;
use TheTempusProject\Bedrock\Classes\Config;
use TheTempusProject\Bedrock\Classes\CustomException;
use TheTempusProject\Canary\Classes\CustomException;
use TheTempusProject\Classes\Email;
use TheTempusProject\Classes\DatabaseModel;
use TheTempusProject\Classes\Preferences;

View File

@ -17,11 +17,14 @@ use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Bedrock\Functions\Sanitize;
use TheTempusProject\Classes\DatabaseModel;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Bedrock\Classes\CustomException;
use TheTempusProject\Canary\Classes\CustomException;
use TheTempusProject\Houdini\Classes\Filters;
use TheTempusProject\Plugins\Comments as CommentPlugin;
use TheTempusProject\Models\Comments;
class Posts extends DatabaseModel {
public $tableName = 'posts';
public static $comments = false;
public $databaseMatrix = [
[ 'author', 'int', '11' ],
@ -32,19 +35,14 @@ class Posts extends DatabaseModel {
[ 'content', 'text', '' ],
];
public $resourceMatrix = [
[
'title' => 'Welcome',
'content' => '<p>This is just a simple message to say thank you for installing The Tempus Project. If you have any questions you can find everything through our website <a href="https://TheTempusProject.com">here</a>.</p>',
'author' => 1,
'created' => '{time}',
'edited' => '{time}',
'draft' => 0,
],
];
public function __construct() {
parent::__construct();
if ( class_exists( 'TheTempusProject\Plugins\Comments' ) ) {
$comments = new CommentPlugin;
if ( $comments->checkEnabled() ) {
self::$comments = new Comments;
}
}
}
public function newPost( $title, $post, $draft ) {
@ -161,6 +159,9 @@ class Posts extends DatabaseModel {
if ( isset( $params['stripHtml'] ) && $params['stripHtml'] === true ) {
$instance->contentSummary = strip_tags( $instance->content );
}
if ( self::$comments !== false ) {
$instance->commentCount = self::$comments->count( 'blog', $instance->ID );
}
$instance->content = Filters::applyOne( 'mentions.0', $instance->content, true );
$instance->content = Filters::applyOne( 'hashtags.0', $instance->content, true );
$out[] = $instance;

View File

@ -38,6 +38,18 @@ class Blog extends Plugin {
'url' => '{ROOT_URL}blog/index',
],
];
public $resourceMatrix = [
'posts' => [
[
'title' => 'Welcome',
'content' => '<p>This is just a simple message to say thank you for installing The Tempus Project. If you have any questions you can find everything through our website <a href="https://TheTempusProject.com">here</a>.</p>',
'author' => 1,
'created' => '{time}',
'edited' => '{time}',
'draft' => 0,
],
],
];
public $posts;
public function __construct( $load = false ) {

View File

@ -1,402 +0,0 @@
<?php
/**
* app/plugins/bugreport/controllers/bugreport.php
*
* This is the bug reports controller.
*
* @package TP BugReports
* @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\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\Bookmarks as Bookmark;
use TheTempusProject\Models\Folders;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Houdini\Classes\Components;
use TheTempusProject\Houdini\Classes\Forms as HoudiniForms;
use TheTempusProject\Houdini\Classes\Navigation;
class Bookmarks extends Controller {
protected static $bookmarks;
protected static $folders;
public function __construct() {
parent::__construct();
if ( !App::$isLoggedIn ) {
Session::flash( 'notice', 'You must be logged in to create or manage bookmarks.' );
return Redirect::home();
}
self::$bookmarks = new Bookmark;
self::$folders = new Folders;
self::$title = 'Bookmarks - {SITENAME}';
self::$pageDescription = 'Add and save url bookmarks here.';
$folderTabs = Views::simpleView( 'bookmarks.nav.folderTabs' );
if ( stripos( Input::get('url'), 'bookmarks/bookmarks' ) !== false ) {
$tabsView = Navigation::activePageSelect( $folderTabs, '/bookmarks/folders/', false, true );
$userFolderTabs = Views::simpleView('bookmarks.nav.userFolderTabs', self::$folders->simpleObjectByUser(true) );
$userFolderTabsView = Navigation::activePageSelect( $userFolderTabs, Input::get( 'url' ), false, true );
} else {
$tabsView = Navigation::activePageSelect( $folderTabs, Input::get( 'url' ), false, true );
$userFolderTabsView = '';
}
Components::set( 'userFolderTabs', $userFolderTabsView );
Views::raw( $tabsView );
}
public function index() {
$bookmarks = self::$bookmarks->noFolder();
$folders = self::$folders->byUser();
$panelArray = [];
if ( !empty( $folders ) ) {
foreach ( $folders as $folder ) {
$panel = new \stdClass();
$folderObject = new \stdClass();
$folderObject->bookmarks = self::$bookmarks->byFolder( $folder->ID );
$folderObject->ID = $folder->ID;
$folderObject->title = $folder->title;
$folderObject->color = $folder->color;
$folderObject->bookmarkListRows = Views::simpleView( 'bookmarks.components.bookmarkListRows', $folderObject->bookmarks );
$panel->panel = Views::simpleView( 'bookmarks.components.bookmarkListPanel', [$folderObject] );
$panelArray[] = $panel;
}
}
Components::set( 'foldersList', Views::simpleView( 'bookmarks.folders.list', $folders ) );
Components::set( 'folderPanels', Views::simpleView( 'bookmarks.components.folderPanelList', $panelArray ) );
Components::set( 'bookmarksList', Views::simpleView( 'bookmarks.bookmarks.list', $bookmarks ) );
return Views::view( 'bookmarks.dash' );
}
/**
* Bookmarks
*/
public function bookmark( $id = 0 ) {
$bookmark = self::$bookmarks->findById( $id );
if ( $bookmark == false ) {
Session::flash( 'error', 'Bookmark not found.' );
return Redirect::to( 'bookmarks/index' );
}
if ( $bookmark->createdBy != App::$activeUser->ID ) {
Session::flash( 'error', 'You do not have permission to modify this bookmark.' );
return Redirect::to( 'bookmarks/index' );
}
Navigation::setCrumbComponent( 'BookmarkBreadCrumbs', 'bookmarks/bookmark/' . $id );
return Views::view( 'bookmarks.bookmarks.view', $bookmark );
}
public function bookmarks( $id = null ) {
$folder = self::$folders->findById( $id );
if ( $folder == false ) {
Session::flash( 'error', 'Folder not found.' );
return Redirect::to( 'bookmarks/index' );
}
if ( $folder->createdBy != App::$activeUser->ID ) {
Session::flash( 'error', 'You do not have permission to view this folder.' );
return Redirect::to( 'bookmarks/index' );
}
Navigation::setCrumbComponent( 'BookmarkBreadCrumbs', 'bookmarks/bookmarks/' . $id );
$bookmarks = self::$bookmarks->noFolder();
$panelArray = [];
$panel = new \stdClass();
$folderObject = new \stdClass();
$folderObject->bookmarks = self::$bookmarks->byFolder( $folder->ID );
$folderObject->ID = $folder->ID;
$folderObject->title = $folder->title;
$folderObject->color = $folder->color;
$folderObject->bookmarkListRows = Views::simpleView( 'bookmarks.components.bookmarkListRows', $folderObject->bookmarks );
$panel->panel = Views::simpleView( 'bookmarks.components.bookmarkListPanel', [$folderObject] );
$panelArray[] = $panel;
return Views::view( 'bookmarks.components.folderPanelList', $panelArray );
}
public function createBookmark( $id = null ) {
$folderID = Input::get('folder_id') ? Input::get('folder_id') : $id;
$folderID = Input::post('folder_id') ? Input::post('folder_id') : $id;
$folderSelect = HoudiniForms::getFormFieldHtml( 'folder_id', 'Folder', 'select', $folderID, self::$folders->simpleByUser() );
Components::set( 'folderSelect', $folderSelect );
if ( ! Input::exists() ) {
return Views::view( 'bookmarks.bookmarks.create' );
}
if ( ! Forms::check( 'createBookmark' ) ) {
Issues::add( 'error', [ 'There was an error with your form.' => Check::userErrors() ] );
return Views::view( 'bookmarks.bookmarks.create' );
}
$result = self::$bookmarks->create(
Input::post('title'),
Input::post('url'),
$folderID,
Input::post('description'),
Input::post('color'),
Input::post('privacy'),
);
if ( ! $result ) {
Issues::add( 'error', [ 'There was an error creating your bookmark.' => Check::userErrors() ] );
return Views::view( 'bookmarks.bookmarks.create' );
}
self::$bookmarks->refreshInfo( $result );
Session::flash( 'success', 'Your Bookmark has been created.' );
Redirect::to( 'bookmarks/bookmarks/'. $folderID );
}
public function editBookmark( $id = null ) {
$folderID = Input::exists('folder_id') ? Input::post('folder_id') : '';
$bookmark = self::$bookmarks->findById( $id );
if ( $bookmark == false ) {
Issues::add( 'error', 'Bookmark not found.' );
return Redirect::to( 'bookmarks/index' );
}
if ( $bookmark->createdBy != App::$activeUser->ID ) {
Issues::add( 'error', 'You do not have permission to modify this bookmark.' );
return Redirect::to( 'bookmarks/index' );
}
if ( empty( $folderID ) ) {
$folderID = $bookmark->folderID;
}
$folderSelect = HoudiniForms::getFormFieldHtml( 'folder_id', 'Folder', 'select', $folderID, self::$folders->simpleByUser() );
Components::set( 'folderSelect', $folderSelect );
Components::set( 'color', $bookmark->color );
if ( ! Input::exists( 'submit' ) ) {
return Views::view( 'bookmarks.bookmarks.edit', $bookmark );
}
if ( ! Forms::check( 'editBookmark' ) ) {
Issues::add( 'error', [ 'There was an error updating your bookmark.' => Check::userErrors() ] );
return Views::view( 'bookmarks.bookmarks.edit', $bookmark );
}
$result = self::$bookmarks->update(
$id,
Input::post('title'),
Input::post('url'),
$folderID,
Input::post('description'),
Input::post('color'),
Input::post('privacy'),
);
if ( ! $result ) {
Issues::add( 'error', [ 'There was an error updating your bookmark.' => Check::userErrors() ] );
return Views::view( 'bookmarks.bookmarks.edit', $bookmark );
}
Session::flash( 'success', 'Your Bookmark has been updated.' );
Redirect::to( 'bookmarks/folders/'. $bookmark->folderID );
}
public function deleteBookmark( $id = null ) {
$bookmark = self::$bookmarks->findById( $id );
if ( $bookmark == false ) {
Issues::add( 'error', 'Bookmark not found.' );
return $this->index();
}
if ( $bookmark->createdBy != App::$activeUser->ID ) {
Issues::add( 'error', 'You do not have permission to modify this bookmark.' );
return $this->index();
}
$result = self::$bookmarks->delete( $id );
if ( !$result ) {
Session::flash( 'error', 'There was an error deleting the bookmark(s)' );
} else {
Session::flash( 'success', 'Bookmark deleted' );
}
Redirect::to( 'bookmarks/folders/'. $bookmark->folderID );
}
/**
* Folders
*/
public function folders( $id = null) {
$folder = self::$folders->findById( $id );
if ( $folder == false ) {
$folders = self::$folders->byUser();
return Views::view( 'bookmarks.folders.list', $folders );
}
if ( $folder->createdBy != App::$activeUser->ID ) {
Session::flash( 'error', 'You do not have permission to view this folder.' );
return Redirect::to( 'bookmarks/index' );
}
Navigation::setCrumbComponent( 'BookmarkBreadCrumbs', 'bookmarks/folders/' . $id );
return Views::view( 'bookmarks.folders.view', $folder );
}
public function createFolder( $id = 0 ) {
$folderID = Input::exists('folder_id') ? Input::post('folder_id') : $id;
$folders = self::$folders->simpleByUser();
if ( ! empty( $folders ) ) {
$folderSelect = HoudiniForms::getFormFieldHtml( 'folder_id', 'Folder', 'select', $folderID, $folders );
} else {
$folderSelect = '';
}
Components::set( 'folderSelect', $folderSelect );
if ( ! Input::exists() ) {
return Views::view( 'bookmarks.folders.create' );
}
if ( ! Forms::check( 'createFolder' ) ) {
Issues::add( 'error', [ 'There was an error creating your folder.' => Check::userErrors() ] );
return Views::view( 'bookmarks.folders.create' );
}
$folder = self::$folders->create( Input::post('title'), $folderID, Input::post('description'), Input::post('color'), Input::post('privacy') );
if ( ! $folder ) {
return Views::view( 'bookmarks.folders.create' );
}
Session::flash( 'success', 'Your Folder has been created.' );
Redirect::to( 'bookmarks/folders' );
}
public function editFolder( $id = null ) {
$folder = self::$folders->findById( $id );
if ( $folder == false ) {
Issues::add( 'error', 'Folder not found.' );
return $this->index();
}
if ( $folder->createdBy != App::$activeUser->ID ) {
Issues::add( 'error', 'You do not have permission to modify this folder.' );
return $this->index();
}
$folderID = ( false === Input::exists('folder_id') ) ? $folder->ID : Input::post('folder_id');
$folderSelect = HoudiniForms::getFormFieldHtml( 'folder_id', 'Folder', 'select', $folderID, self::$folders->simpleByUser() );
Components::set( 'folderSelect', $folderSelect );
Components::set( 'color', $folder->color );
if ( ! Input::exists( 'submit' ) ) {
return Views::view( 'bookmarks.folders.edit', $folder );
}
if ( !Forms::check( 'editFolder' ) ) {
Issues::add( 'error', [ 'There was an error editing your folder.' => Check::userErrors() ] );
return Views::view( 'bookmarks.folders.edit', $folder );
}
$result = self::$folders->update( $id, Input::post('title'), $folderID, Input::post('description'), Input::post('color'), Input::post('privacy') );
if ( !$result ) {
Issues::add( 'error', [ 'There was an error updating your folder.' => Check::userErrors() ] );
return Views::view( 'bookmarks.folders.edit', $folder );
}
Session::flash( 'success', 'Your Folder has been updated.' );
Redirect::to( 'bookmarks/folders/'. $folder->ID );
}
public function deleteFolder( $id = null ) {
$folder = self::$folders->findById( $id );
if ( $folder == false ) {
Issues::add( 'error', 'Folder not found.' );
return $this->index();
}
if ( $folder->createdBy != App::$activeUser->ID ) {
Issues::add( 'error', 'You do not have permission to modify this folder.' );
return $this->index();
}
$results = self::$bookmarks->deleteByFolder( $id );
$result = self::$folders->delete( $id );
if ( !$result ) {
Session::flash( 'error', 'There was an error deleting the folder(s)' );
} else {
Session::flash( 'success', 'Folder deleted' );
}
Redirect::to( 'bookmarks/folders' );
}
/**
* Functionality
*/
public function hideBookmark( $id = null ) {
$bookmark = self::$bookmarks->findById( $id );
if ( $bookmark == false ) {
Session::flash( 'error', 'Bookmark not found.' );
return Redirect::to( 'bookmarks/index' );
}
if ( $bookmark->createdBy != App::$activeUser->ID ) {
Session::flash( 'error', 'You do not have permission to modify this bookmark.' );
return Redirect::to( 'bookmarks/index' );
}
self::$bookmarks->hide( $id );
Session::flash( 'success', 'Bookmark hidden.' );
return Redirect::to( 'bookmarks/index' );
}
public function archiveBookmark( $id = null ) {
$bookmark = self::$bookmarks->findById( $id );
if ( $bookmark == false ) {
Session::flash( 'error', 'Bookmark not found.' );
return Redirect::to( 'bookmarks/index' );
}
if ( $bookmark->createdBy != App::$activeUser->ID ) {
Session::flash( 'error', 'You do not have permission to modify this bookmark.' );
return Redirect::to( 'bookmarks/index' );
}
self::$bookmarks->archive( $id );
Session::flash( 'success', 'Bookmark archived.' );
return Redirect::to( 'bookmarks/index' );
}
public function showBookmark( $id = null ) {
$bookmark = self::$bookmarks->findById( $id );
if ( $bookmark == false ) {
Session::flash( 'error', 'Bookmark not found.' );
return Redirect::to( 'bookmarks/index' );
}
if ( $bookmark->createdBy != App::$activeUser->ID ) {
Session::flash( 'error', 'You do not have permission to modify this bookmark.' );
return Redirect::to( 'bookmarks/index' );
}
self::$bookmarks->show( $id );
Session::flash( 'success', 'Bookmark shown.' );
return Redirect::to( 'bookmarks/index' );
}
public function unarchiveBookmark( $id = null ) {
$bookmark = self::$bookmarks->findById( $id );
if ( $bookmark == false ) {
Session::flash( 'error', 'Bookmark not found.' );
return Redirect::to( 'bookmarks/index' );
}
if ( $bookmark->createdBy != App::$activeUser->ID ) {
Session::flash( 'error', 'You do not have permission to modify this bookmark.' );
return Redirect::to( 'bookmarks/index' );
}
self::$bookmarks->unarchive( $id );
Session::flash( 'success', 'Bookmark un-archived.' );
return Redirect::to( 'bookmarks/index' );
}
public function refreshBookmark( $id = null ) {
$bookmark = self::$bookmarks->findById( $id );
if ( $bookmark == false ) {
Session::flash( 'error', 'Bookmark not found.' );
return Redirect::to( 'bookmarks/index' );
}
if ( $bookmark->createdBy != App::$activeUser->ID ) {
Session::flash( 'error', 'You do not have permission to modify this bookmark.' );
return Redirect::to( 'bookmarks/index' );
}
$info = self::$bookmarks->refreshInfo( $id );
if ( false == $info ) {
Session::flash( 'error', 'Issue refreshing your bookmark.' );
return Redirect::to( 'bookmarks/bookmark/' . $bookmark->ID );
}
Session::flash( 'success', 'Bookmark data refreshed.' );
return Redirect::to( 'bookmarks/bookmark/' . $bookmark->ID );
}
}

View File

@ -1,122 +0,0 @@
<?php
/**
* app/plugins/bookmarks/forms.php
*
* This houses all of the form checking functions for this plugin.
*
* @package TP Bookmarks
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Plugins\Bookmarks;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Classes\Forms;
class BookmarksForms extends Forms {
/**
* Adds these functions to the form list.
*/
public function __construct() {
self::addHandler( 'createBookmark', __CLASS__, 'createBookmark' );
self::addHandler( 'createFolder', __CLASS__, 'createFolder' );
self::addHandler( 'editBookmark', __CLASS__, 'editBookmark' );
self::addHandler( 'editFolder', __CLASS__, 'editFolder' );
}
public static function createBookmark() {
// if ( ! Input::exists( 'title' ) ) {
// Check::addUserError( 'You must include a title.' );
// return false;
// }
if ( ! Input::exists( 'url' ) ) {
Check::addUserError( 'You must include a url.' );
return false;
}
// if ( ! Input::exists( 'color' ) ) {
// Check::addUserError( 'You must include a color.' );
// return false;
// }
// if ( ! Input::exists( 'privacy' ) ) {
// Check::addUserError( 'You must include a privacy.' );
// return false;
// }
// if ( !self::token() ) {
// Check::addUserError( 'token - comment out later.' );
// return false;
// }
return true;
}
public static function createFolder() {
if ( ! Input::exists( 'title' ) ) {
Check::addUserError( 'You must include a title.' );
return false;
}
// if ( ! Input::exists( 'color' ) ) {
// Check::addUserError( 'You must include a color.' );
// return false;
// }
// if ( ! Input::exists( 'privacy' ) ) {
// Check::addUserError( 'You must include a privacy.' );
// return false;
// }
// if ( ! self::token() ) {
// Check::addUserError( 'token - comment out later.' );
// return false;
// }
return true;
}
public static function editBookmark() {
// if ( ! Input::exists( 'title' ) ) {
// Check::addUserError( 'You must include a title.' );
// return false;
// }
if ( ! Input::exists( 'url' ) ) {
Check::addUserError( 'You must include a url.' );
return false;
}
// if ( ! Input::exists( 'color' ) ) {
// Check::addUserError( 'You must include a color.' );
// return false;
// }
// if ( ! Input::exists( 'privacy' ) ) {
// Check::addUserError( 'You must include a privacy.' );
// return false;
// }
// if ( !self::token() ) {
// Check::addUserError( 'token - comment out later.' );
// return false;
// }
return true;
}
public static function editFolder() {
if ( ! Input::exists( 'submit' ) ) {
return false;
}
if ( ! Input::exists( 'title' ) ) {
Check::addUserError( 'You must include a title.' );
return false;
}
// if ( ! Input::exists( 'color' ) ) {
// Check::addUserError( 'You must include a color.' );
// return false;
// }
// if ( ! Input::exists( 'privacy' ) ) {
// Check::addUserError( 'You must include a privacy.' );
// return false;
// }
// if ( !self::token() ) {
// Check::addUserError( 'token - comment out later.' );
// return false;
// }
return true;
}
}
new BookmarksForms;

View File

@ -1,149 +0,0 @@
<?php
/**
* app/plugins/bookmarks/models/bookmarkViews.php
*
* This class is used for the manipulation of the bookmark_views database table.
*
* @package TP Bookmarks
* @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\Bin\Canary as Debug;
use TheTempusProject\Classes\DatabaseModel;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Houdini\Classes\Filters;
use TheTempusProject\Bedrock\Classes\CustomException;
class BookmarkViews extends DatabaseModel {
public $tableName = 'bookmark_views';
public $databaseMatrix = [
[ 'title', 'varchar', '256' ],
[ 'description', 'text', '' ],
[ 'privacy', 'varchar', '48' ],
[ 'createdBy', 'int', '11' ],
[ 'createdAt', 'int', '11' ],
[ 'updatedAt', 'int', '11' ],
];
/**
* The model constructor.
*/
public function __construct() {
parent::__construct();
}
public function create( $title, $description = '', $privacy = 'private' ) {
if ( ! Check::dataTitle( $title ) ) {
Debug::info( 'Views: illegal title.' );
return false;
}
$fields = [
'title' => $title,
'description' => $description,
'privacy' => $privacy,
'createdBy' => App::$activeUser->ID,
'createdAt' => time(),
];
if ( ! self::$db->insert( $this->tableName, $fields ) ) {
new CustomException( 'viewCreate' );
Debug::error( "Views: not created " . var_export($fields,true) );
return false;
}
return self::$db->lastId();
}
public function update( $id, $title, $description = '', $privacy = 'private' ) {
if ( !Check::id( $id ) ) {
Debug::info( 'Views: illegal ID.' );
return false;
}
if ( !Check::dataTitle( $title ) ) {
Debug::info( 'Views: illegal title.' );
return false;
}
$fields = [
'title' => $title,
'description' => $description,
'privacy' => $privacy,
];
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
new CustomException( 'viewUpdate' );
Debug::error( "Views: $id not updated: $fields" );
return false;
}
return true;
}
public function byUser( $limit = null ) {
$whereClause = ['createdBy', '=', App::$activeUser->ID];
if ( empty( $limit ) ) {
$views = self::$db->get( $this->tableName, $whereClause );
} else {
$views = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
}
if ( !$views->count() ) {
Debug::info( 'No Views found.' );
return false;
}
return $this->filter( $views->results() );
}
public function getName( $id ) {
$views = self::findById( $id );
if (false == $views) {
return 'unknown';
}
return $views->title;
}
public function simpleByUser() {
$whereClause = ['createdBy', '=', App::$activeUser->ID];
$views = self::$db->get( $this->tableName, $whereClause );
if ( !$views->count() ) {
Debug::warn( 'Could not find any Views' );
return false;
}
$views = $views->results();
$out = [];
foreach ( $views as $view ) {
$out[ $view->title ] = $view->ID;
}
return $out;
}
public function simpleObjectByUser() {
$whereClause = ['createdBy', '=', App::$activeUser->ID];
$views = self::$db->get( $this->tableName, $whereClause );
if ( !$views->count() ) {
Debug::warn( 'Could not find any Views' );
return false;
}
$views = $views->results();
$out = [];
foreach ( $views as $view ) {
$obj = new \stdClass();
$obj->title = $view->title;
$obj->ID = $view->ID;
$out[] = $obj;
}
return $out;
}
}

View File

@ -1,705 +0,0 @@
<?php
/**
* app/plugins/bookmarks/models/bookmarks.php
*
* This class is used for the manipulation of the bookmarks database table.
*
* @package TP Bookmarks
* @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\Bin\Canary as Debug;
use TheTempusProject\Classes\DatabaseModel;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Houdini\Classes\Filters;
use TheTempusProject\Bedrock\Classes\CustomException;
class Bookmarks extends DatabaseModel {
public $tableName = 'bookmarks';
public $linkTypes = [
'Open in New Tab' => 'external',
'Open in Same Tab' => 'internal',
];
public $databaseMatrix = [
[ 'title', 'varchar', '256' ],
[ 'url', 'text', '' ],
[ 'color', 'varchar', '48' ],
[ 'privacy', 'varchar', '48' ],
[ 'folderID', 'int', '11' ],
[ 'description', 'text', '' ],
[ 'createdBy', 'int', '11' ],
[ 'createdAt', 'int', '11' ],
[ 'meta', 'text', '' ],
[ 'icon', 'text', '' ],
[ 'archivedAt', 'int', '11' ],
[ 'refreshedAt', 'int', '11' ],
[ 'hiddenAt', 'int', '11' ],
[ 'order', 'int', '11' ],
[ 'linkType', 'varchar', '32' ],
];
/**
* The model constructor.
*/
public function __construct() {
parent::__construct();
}
public function create( $title, $url, $folderID = 0, $description = '', $color = 'default', $privacy = 'private', $type = 'external' ) {
$fields = [
'title' => $title,
'url' => $url,
'description' => $description,
'color' => $color,
'privacy' => $privacy,
'createdBy' => App::$activeUser->ID,
'createdAt' => time(),
];
if ( !empty( $folderID ) ) {
$fields['folderID'] = $folderID;
} else {
$fields['folderID'] = null;
}
if ( ! self::$db->insert( $this->tableName, $fields ) ) {
new CustomException( 'bookmarkCreate' );
Debug::error( "Bookmarks: not created " . var_export($fields,true) );
return false;
}
return self::$db->lastId();
}
public function update( $id, $title, $url, $folderID = 0, $description = '', $color = 'default', $privacy = 'private', $type = 'external', $order = 0 ) {
if ( !Check::id( $id ) ) {
Debug::info( 'Bookmarks: illegal ID.' );
return false;
}
$fields = [
'title' => $title,
'url' => $url,
'description' => $description,
'color' => $color,
'privacy' => $privacy,
// 'linkType' => $type,
// 'order' => $order,
];
if ( !empty( $folderID ) ) {
$fields['folderID'] = $folderID;
}
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
new CustomException( 'bookmarkUpdate' );
Debug::error( "Bookmarks: $id not updated" );
return false;
}
return true;
}
public function byUser( $limit = null ) {
$whereClause = ['createdBy', '=', App::$activeUser->ID];
if ( empty( $limit ) ) {
$bookmarks = self::$db->get( $this->tableName, $whereClause );
} else {
$bookmarks = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
}
if ( !$bookmarks->count() ) {
Debug::info( 'No Bookmarks found.' );
return false;
}
return $this->filter( $bookmarks->results() );
}
public function byFolder( $id, $limit = null ) {
$whereClause = ['createdBy', '=', App::$activeUser->ID, 'AND'];
$whereClause = array_merge( $whereClause, [ 'folderID', '=', $id ] );
if ( empty( $limit ) ) {
$bookmarks = self::$db->get( $this->tableName, $whereClause );
} else {
$bookmarks = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
}
if ( !$bookmarks->count() ) {
Debug::info( 'No Bookmarks found.' );
return false;
}
return $this->filter( $bookmarks->results() );
}
public function noFolder( $id = 0, $limit = 10 ) {
$whereClause = ['createdBy', '=', App::$activeUser->ID, 'AND'];
if ( !empty( $id ) ) {
$whereClause = array_merge( $whereClause, ['folderID', '!=', $id] );
} else {
$whereClause = array_merge( $whereClause, [ 'folderID', 'IS', null] );
}
if ( empty( $limit ) ) {
$bookmarks = self::$db->get( $this->tableName, $whereClause );
} else {
$bookmarks = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [ 0, $limit ] );
}
if ( !$bookmarks->count() ) {
Debug::info( 'No Bookmarks found.' );
return false;
}
return $this->filter( $bookmarks->results() );
}
public function getName( $id ) {
$bookmarks = self::findById( $id );
if (false == $bookmarks) {
return 'unknown';
}
return $bookmarks->title;
}
public function getColor( $id ) {
$bookmarks = self::findById( $id );
if (false == $bookmarks) {
return 'default';
}
return $bookmarks->color;
}
public function simpleByUser() {
$whereClause = ['createdBy', '=', App::$activeUser->ID];
$bookmarks = self::$db->get( $this->tableName, $whereClause );
if ( !$bookmarks->count() ) {
Debug::warn( 'Could not find any bookmarks' );
return false;
}
$bookmarks = $bookmarks->results();
$out = [];
foreach ( $bookmarks as $bookmarks ) {
$out[ $bookmarks->title ] = $bookmarks->ID;
}
return $out;
}
public function simpleObjectByUser() {
$whereClause = ['createdBy', '=', App::$activeUser->ID];
$bookmarks = self::$db->get( $this->tableName, $whereClause );
if ( !$bookmarks->count() ) {
Debug::warn( 'Could not find any bookmarks' );
return false;
}
$bookmarks = $bookmarks->results();
$out = [];
foreach ( $bookmarks as $bookmarks ) {
$obj = new \stdClass();
$obj->title = $bookmarks->title;
$obj->ID = $bookmarks->ID;
$out[] = $obj;
}
return $out;
}
public function deleteByFolder( $folderID ) {
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
$whereClause = array_merge( $whereClause, [ 'folderID', '=', $folderID ] );
$bookmarks = self::$db->get( $this->tableName, $whereClause );
if ( ! $bookmarks->count() ) {
Debug::info( 'No ' . $this->tableName . ' data found.' );
return [];
}
foreach( $bookmarks->results() as $bookmark ) {
$this->delete( $bookmark->ID );
}
return true;
}
private function resolveShortenedUrl( $url ) {
$ch = curl_init($url);
// Set curl options
curl_setopt($ch, CURLOPT_NOBODY, true); // We don't need the body
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // Follow redirects
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // Return the response
curl_setopt($ch, CURLOPT_TIMEOUT, 30); // Set a timeout
// curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); // Maybe sketchy?
// Maybe sketchy?
// curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // Disable SSL host verification
// curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // Disable SSL peer verification
// curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
// added to support the regex site
// curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
// =
// curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, 'AES256+EECDH:AES256+EDH' );
// Execute curl
$response = curl_exec( $ch );
// Check if there was an error
if ( curl_errno( $ch ) ) {
// Get error details
$errorCode = curl_errno($ch);
$errorMessage = curl_error($ch);
// Log or display the error details
dv('cURL Error: ' . $errorMessage . ' (Error Code: ' . $errorCode . ')');
curl_close($ch);
// return $url; // Return the original URL if there was an error
$url = rtrim( $url, '/' );
$ch2 = curl_init($url);
curl_setopt($ch2, CURLOPT_NOBODY, true); // We don't need the body
curl_setopt($ch2, CURLOPT_FOLLOWLOCATION, true); // Follow redirects
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true); // Return the response
curl_setopt($ch2, CURLOPT_TIMEOUT, 5); // Set a timeout
curl_exec($ch2);
if ( curl_errno( $ch2 ) ) {
}
curl_close( $ch );
return $url;
}
// Get the effective URL (the final destination after redirects)
$finalUrl = curl_getinfo( $ch, CURLINFO_EFFECTIVE_URL );
curl_close( $ch );
return $finalUrl;
// $headers = get_headers( $url, 1 );
$headers = @get_headers($url, 1);
if ( $headers === false ) {
}
if ( isset( $headers['Location'] ) ) {
if (is_array($headers['Location'])) {
return end($headers['Location']);
} else {
return $headers['Location'];
}
} else {
return $url;
}
}
public function filter( $data, $params = [] ) {
foreach ( $data as $instance ) {
if ( !is_object( $instance ) ) {
$instance = $data;
$end = true;
}
$base_url = $this->getBaseUrl( $instance->url );
if ( empty( $instance->icon ) ) {
$instance->iconHtml = '<i class="glyphicon glyphicon-link"></i>';
} else {
if (strpos($instance->icon, 'http') !== false) {
$instance->iconHtml = '<img src="' . $instance->icon .'" />';
} else {
$instance->iconHtml = '<img src="' . $base_url . ltrim( $instance->icon, '/' ) .'" />';
}
}
if ( empty( $instance->hiddenAt ) ) {
$instance->hideBtn = '
<a href="{ROOT_URL}bookmarks/hideBookmark/'.$instance->ID.'" class="btn btn-sm btn-warning" role="button">
<i class="glyphicon glyphicon-eye-open"></i>
</a>';
} else {
$instance->hideBtn = '
<a href="{ROOT_URL}bookmarks/showBookmark/'.$instance->ID.'" class="btn btn-sm btn-default" role="button">
<i class="glyphicon glyphicon-eye-open"></i>
</a>';
}
if ( empty( $instance->archivedAt ) ) {
$instance->archiveBtn = '
<a href="{ROOT_URL}bookmarks/archiveBookmark/'.$instance->ID.'" class="btn btn-sm btn-info" role="button">
<i class="glyphicon glyphicon-briefcase"></i>
</a>';
} else {
$instance->archiveBtn = '
<a href="{ROOT_URL}bookmarks/unarchiveBookmark/'.$instance->ID.'" class="btn btn-sm btn-default" role="button">
<i class="glyphicon glyphicon-briefcase"></i>
</a>';
}
if ( ! empty( $instance->refreshedAt ) && time() < ( $instance->refreshedAt + ( 60 * 10 ) ) ) {
$instance->refreshBtn = '
<a href="{ROOT_URL}bookmarks/refreshBookmark/'.$instance->ID.'" class="btn btn-sm btn-danger" role="button">
<i class="glyphicon glyphicon-refresh"></i>
</a>';
} else {
$instance->refreshBtn = '
<a href="{ROOT_URL}bookmarks/refreshBookmark/'.$instance->ID.'" class="btn btn-sm btn-success" role="button">
<i class="glyphicon glyphicon-refresh"></i>
</a>';
}
$out[] = $instance;
if ( !empty( $end ) ) {
$out = $out[0];
break;
}
}
return $out;
}
public function hide( $id ) {
if ( !Check::id( $id ) ) {
Debug::info( 'Bookmarks: illegal ID.' );
return false;
}
$fields = [
'hiddenAt' => time(),
];
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
new CustomException( 'bookmarkUpdate' );
Debug::error( "Bookmarks: $id not updated" );
return false;
}
return true;
}
public function show( $id ) {
if ( !Check::id( $id ) ) {
Debug::info( 'Bookmarks: illegal ID.' );
return false;
}
$fields = [
'hiddenAt' => 0,
];
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
new CustomException( 'bookmarkUpdate' );
Debug::error( "Bookmarks: $id not updated" );
return false;
}
return true;
}
public function archive( $id ) {
if ( !Check::id( $id ) ) {
Debug::info( 'Bookmarks: illegal ID.' );
return false;
}
$fields = [
'archivedAt' => time(),
];
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
new CustomException( 'bookmarkUpdate' );
Debug::error( "Bookmarks: $id not updated" );
return false;
}
return true;
}
public function unarchive( $id ) {
if ( !Check::id( $id ) ) {
Debug::info( 'Bookmarks: illegal ID.' );
return false;
}
$fields = [
'archivedAt' => 0,
];
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
new CustomException( 'bookmarkUpdate' );
Debug::error( "Bookmarks: $id not updated" );
return false;
}
return true;
}
public function extractMetaTags($htmlContent) {
$doc = new \DOMDocument();
@$doc->loadHTML($htmlContent);
$metaTags = [];
foreach ($doc->getElementsByTagName('meta') as $meta) {
$name = $meta->getAttribute('name') ?: $meta->getAttribute('property');
$content = $meta->getAttribute('content');
if ($name && $content) {
$metaTags[$name] = $content;
}
}
return $metaTags;
}
public function fetchUrlData($url) {
$ch = curl_init();
// Set cURL options
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true); // Include headers in the output
curl_setopt($ch, CURLOPT_NOBODY, false); // Include the body in the output
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // Follow redirects
curl_setopt($ch, CURLOPT_TIMEOUT, 30); // Set a timeout
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // Disable SSL host verification for testing
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // Disable SSL peer verification for testing
// Execute cURL request
$response = curl_exec($ch);
// Check if there was an error
if (curl_errno($ch)) {
$errorMessage = curl_error($ch);
curl_close($ch);
throw new \Exception('cURL Error: ' . $errorMessage);
}
// Get HTTP status code
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
// Separate headers and body
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$headers = substr($response, 0, $headerSize);
$body = substr($response, $headerSize);
curl_close($ch);
// Parse headers into an associative array
$headerLines = explode("\r\n", trim($headers));
$headerArray = [];
foreach ($headerLines as $line) {
$parts = explode(': ', $line, 2);
if (count($parts) == 2) {
$headerArray[$parts[0]] = $parts[1];
}
}
return [
'http_code' => $httpCode,
'headers' => $headerArray,
'body' => $body,
];
}
private function getMetaTagsAndFavicon( $url ) {
try {
// $url = 'https://runescape.wiki';
$data = $this->fetchUrlData($url);
// iv($data);
// Get headers
$headers = $data['headers'];
iv($headers);
// Get meta tags
$metaTags = $this->extractMetaTags($data['body']);
} catch (Exception $e) {
dv( 'Error: ' . $e->getMessage());
}
$metaInfo = [
'url' => $url,
'title' => null,
'description' => null,
'image' => null,
'favicon' => null
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$html = curl_exec($ch);
curl_close($ch);
if ($html === false) {
return null;
}
$meta = @get_meta_tags( $url );
$dom = new \DOMDocument('1.0', 'utf-8');
$dom->strictErrorChecking = false;
$dom->loadHTML($html, LIBXML_NOERROR);
$xml = simplexml_import_dom($dom);
$arr = $xml->xpath('//link[@rel="shortcut icon"]');
// Get the title of the page
$titles = $dom->getElementsByTagName('title');
if ($titles->length > 0) {
$metaInfo['title'] = $titles->item(0)->nodeValue;
}
// Get the meta tags
$metaTags = $dom->getElementsByTagName('meta');
$metadata = [];
foreach ($metaTags as $meta) {
$metadata[] = [
'name' => $meta->getAttribute('name'),
'property' => $meta->getAttribute('property'),
'content' => $meta->getAttribute('content')
];
if ($meta->getAttribute('name') === 'description') {
$metaInfo['description'] = $meta->getAttribute('content');
}
if ($meta->getAttribute('itemprop') === 'image') {
$metaInfo['google_image'] = $meta->getAttribute('content');
}
if ($meta->getAttribute('property') === 'og:image') {
$metaInfo['image'] = $meta->getAttribute('content');
}
}
// Get the link tags to find the favicon
$linkTags = $dom->getElementsByTagName('link');
$metadata['links'] = [];
foreach ($linkTags as $link) {
$metadata['links'][] = [ $link->getAttribute('rel') => $link->getAttribute('href') ];
if ( $link->getAttribute('rel') === 'icon' || $link->getAttribute('rel') === 'shortcut icon') {
$metaInfo['favicon'] = $link->getAttribute('href');
break;
}
}
$metaInfo['metadata'] = $metadata;
return $metaInfo;
}
public function retrieveInfo( $url ) {
$finalDestination = $this->resolveShortenedUrl( $url );
$info = $this->getMetaTagsAndFavicon( $finalDestination );
$base_url = $this->getBaseUrl( $finalDestination );
if ( ! empty( $info['favicon'] ) ) {
echo 'favicon exists' . PHP_EOL;
if ( stripos( $info['favicon'], 'http' ) !== false) {
echo 'favicon is full url' . PHP_EOL;
$imageUrl = $info['favicon'];
} else {
echo 'favicon is not full url' . PHP_EOL;
$imageUrl = trim( $base_url, '/' ) . '/' . ltrim( $info['favicon'], '/' );
}
if ( $this->isValidImageUrl( $imageUrl ) ) {
echo 'image is valid' . PHP_EOL;
$info['favicon'] = $imageUrl;
} else {
echo 'image is not valid' . PHP_EOL;
$base_info = $this->getMetaTagsAndFavicon( $base_url );
if ( ! empty( $base_info['favicon'] ) ) {
echo 'parent favicon exists!';
if ( stripos( $base_info['favicon'], 'http' ) !== false) {
echo 'parent favicon is full url' . PHP_EOL;
$imageUrl = $base_info['favicon'];
} else {
echo 'parent favicon is not full url' . PHP_EOL;
$imageUrl = trim( $base_url, '/' ) . '/' . ltrim( $base_info['favicon'], '/' );
}
if ( $this->isValidImageUrl( $imageUrl ) ) {
echo 'parent favicon image is valid' . PHP_EOL;
$info['favicon'] = $imageUrl;
} else {
echo 'parent favicon image is not valid' . PHP_EOL;
}
}
}
} else {
echo 'favicon does not exist' . PHP_EOL;
$base_info = $this->getMetaTagsAndFavicon( $base_url );
if ( ! empty( $base_info['favicon'] ) ) {
echo 'parent favicon exists!' . PHP_EOL;
if ( stripos( $base_info['favicon'], 'http' ) !== false) {
echo 'parent favicon is full url' . PHP_EOL;
$imageUrl = $base_info['favicon'];
} else {
echo 'parent favicon is not full url' . PHP_EOL;
$imageUrl = trim( $base_url, '/' ) . '/' . ltrim( $base_info['favicon'], '/' );
}
if ( $this->isValidImageUrl( $imageUrl ) ) {
echo 'parent favicon image is valid' . PHP_EOL;
$info['favicon'] = $imageUrl;
} else {
echo 'parent favicon image is not valid' . PHP_EOL;
}
}
}
return $info;
}
public function refreshInfo( $id ) {
if ( !Check::id( $id ) ) {
Debug::info( 'Bookmarks: illegal ID.' );
return false;
}
$bookmark = self::findById( $id );
if ( $bookmark == false ) {
Debug::info( 'Bookmarks not found.' );
return false;
}
if ( $bookmark->createdBy != App::$activeUser->ID ) {
Debug::info( 'You do not have permission to modify this bookmark.' );
return false;
}
if ( time() < ( $bookmark->refreshedAt + ( 60 * 10 ) ) ) {
Debug::info( 'You may only fetch bookmarks once every 10 minutes.' );
return false;
}
$info = $this->retrieveInfo( $bookmark->url );
$fields = [
// 'refreshedAt' => time(),
];
if ( empty( $bookmark->title ) && ! empty( $info['title'] ) ) {
$fields['title'] = $info['title'];
}
if ( empty( $bookmark->description ) && ! empty( $info['description'] ) ) {
$fields['description'] = $info['description'];
}
if ( ( empty( $bookmark->icon ) || ! $this->isValidImageUrl( $bookmark->icon ) ) && ! empty( $info['favicon'] ) ) {
$fields['icon'] = $info['favicon'];
}
$fields['meta'] = json_encode( $info['metadata'] );
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
new CustomException( 'bookmarkUpdate' );
Debug::error( "Bookmarks: $id not updated" );
return false;
}
return true;
}
private function getBaseUrl ($url ) {
$parsedUrl = parse_url($url);
if (isset($parsedUrl['scheme']) && isset($parsedUrl['host'])) {
return $parsedUrl['scheme'] . '://' . $parsedUrl['host'] . '/';
} else {
return null; // URL is not valid or cannot be parsed
}
}
function isValidImageUrl($url) {
$headers = @get_headers($url);
if ($headers && strpos($headers[0], '200') !== false) {
return true;
// Further check to ensure it's an image
foreach ($headers as $header) {
if (strpos(strtolower($header), 'content-type:') !== false) {
if (strpos(strtolower($header), 'image/') !== false) {
return true;
}
}
}
}
return false;
}
}

View File

@ -1,157 +0,0 @@
<?php
/**
* app/plugins/bookmarks/models/folders.php
*
* This class is used for the manipulation of the folders database table.
*
* @package TP Bookmarks
* @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\Bin\Canary as Debug;
use TheTempusProject\Classes\DatabaseModel;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Houdini\Classes\Filters;
use TheTempusProject\Bedrock\Classes\CustomException;
class Folders extends DatabaseModel {
public $tableName = 'folders';
public $databaseMatrix = [
[ 'title', 'varchar', '256' ],
[ 'color', 'varchar', '48' ],
[ 'privacy', 'varchar', '48' ],
[ 'description', 'text', '' ],
[ 'folderID', 'int', '11' ],
[ 'createdBy', 'int', '11' ],
[ 'createdAt', 'int', '11' ],
];
/**
* The model constructor.
*/
public function __construct() {
parent::__construct();
}
public function create( $title, $folderID = 0, $description = '', $color = 'default', $privacy = 'private' ) {
if ( ! Check::dataTitle( $title ) ) {
Debug::info( 'Folders: illegal title.' );
return false;
}
$fields = [
'title' => $title,
'description' => $description,
'color' => $color,
'privacy' => $privacy,
'createdBy' => App::$activeUser->ID,
'createdAt' => time(),
];
if ( !empty( $folderID ) ) {
$fields['folderID'] = $folderID;
}
if ( ! self::$db->insert( $this->tableName, $fields ) ) {
new CustomException( 'folderCreate' );
Debug::error( "Folders: not created " . var_export($fields,true) );
return false;
}
return self::$db->lastId();
}
public function update( $id, $title, $folderID = 0, $description = '', $color = 'default', $privacy = 'private' ) {
if ( !Check::id( $id ) ) {
Debug::info( 'Folders: illegal ID.' );
return false;
}
if ( !Check::dataTitle( $title ) ) {
Debug::info( 'Folders: illegal title.' );
return false;
}
$fields = [
'title' => $title,
'description' => $description,
'color' => $color,
'privacy' => $privacy,
];
if ( !empty( $folderID ) ) {
$fields['folderID'] = $folderID;
}
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
new CustomException( 'folderUpdate' );
Debug::error( "Folders: $id not updated: $fields" );
return false;
}
return true;
}
public function byUser( $limit = null ) {
$whereClause = ['createdBy', '=', App::$activeUser->ID];
if ( empty( $limit ) ) {
$folders = self::$db->get( $this->tableName, $whereClause );
} else {
$folders = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
}
if ( !$folders->count() ) {
Debug::info( 'No Folders found.' );
return false;
}
return $this->filter( $folders->results() );
}
public function getName( $id ) {
$folder = self::findById( $id );
if (false == $folder) {
return 'unknown';
}
return $folder->title;
}
public function getColor( $id ) {
$folder = self::findById( $id );
if (false == $folder) {
return 'default';
}
return $folder->color;
}
public function simpleByUser() {
$whereClause = ['createdBy', '=', App::$activeUser->ID];
$folders = self::$db->get( $this->tableName, $whereClause );
if ( !$folders->count() ) {
Debug::warn( 'Could not find any folders' );
return false;
}
$folders = $folders->results();
$out = [];
$out[ 'No Folder' ] = 0;
foreach ( $folders as $folder ) {
$out[ $folder->title ] = $folder->ID;
}
return $out;
}
public function simpleObjectByUser() {
$whereClause = ['createdBy', '=', App::$activeUser->ID];
$folders = self::$db->get( $this->tableName, $whereClause );
if ( !$folders->count() ) {
Debug::warn( 'Could not find any folders' );
return false;
}
$folders = $folders->results();
$out = [];
foreach ( $folders as $folder ) {
$obj = new \stdClass();
$obj->title = $folder->title;
$obj->ID = $folder->ID;
$out[] = $obj;
}
return $out;
}
}

View File

@ -1,62 +0,0 @@
<?php
/**
* app/plugins/bookmarks/plugin.php
*
* This houses all of the main plugin info and functionality.
*
* @package TP Bookmarks
* @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\Models\Events;
use TheTempusProject\Models\Bookmarks as Bookmark;
use TheTempusProject\Models\Folders;
use TheTempusProject\Houdini\Classes\Components;
use TheTempusProject\Houdini\Classes\Template;
class Bookmarks extends Plugin {
public $pluginName = 'TP Bookmarks';
public $configName = 'bookmarks';
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 bookmark system.';
public $permissionMatrix = [
'useBookmarks' => [
'pretty' => 'Can use the bookmarks feature',
'default' => false,
],
'createEvents' => [
'pretty' => 'Can add events to bookmarks',
'default' => false,
],
];
public $main_links = [
[
'text' => 'Bookmarks',
'url' => '{ROOT_URL}bookmarks/index',
'filter' => 'loggedin',
],
];
public $configMatrix = [
'enabled' => [
'type' => 'radio',
'pretty' => 'Enable Bookmarks.',
'default' => true,
],
];
public $bookmarks;
public $folders;
public function __construct( $load = false ) {
$this->bookmarks = new Bookmark;
$this->folders = new Folders;
parent::__construct( $load );
}
}

View File

@ -1,45 +0,0 @@
<legend>Create Bookmark</legend>
{BookmarkBreadCrumbs}
<form action="" method="post" class="form-horizontal">
<input type="hidden" name="token" value="{TOKEN}">
<div class="form-group">
<label for="title" class="col-lg-3 control-label">Title</label>
<div class="col-lg-3">
<input type="text" class="form-control" name="title" id="title">
</div>
</div>
<div class="form-group">
<label for="url" class="col-lg-3 control-label">URL:</label>
<div class="col-lg-3">
<input type="text" class="form-control" name="url" id="url">
</div>
</div>
<div class="form-group">
<label for="description" class="col-lg-3 control-label">Description:</label>
<div class="col-lg-3">
<textarea class="form-control" name="description" maxlength="2000" rows="10" cols="50" id="description"></textarea>
</div>
</div>
{folderSelect}
<div class="form-group">
<label for="privacy" class="col-lg-3 control-label">Privacy</label>
<div class="col-lg-3 select-container" id="colorContainer">
<select id="privacy" name="privacy" class="form-control custom-select">
<option value="private">Private</option>
<option value="public">Public</option>
</select>
</div>
</div>
<div class="form-group">
<label for="color" class="col-lg-3 control-label">Color</label>
<div class="col-lg-3 select-container" id="colorContainer">
{colorSelect}
</div>
</div>
<div class="form-group">
<label for="submit" class="col-lg-3 control-label"></label>
<div class="col-lg-3">
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block ">Submit</button>
</div>
</div>
</form>

View File

@ -1,45 +0,0 @@
<legend>Edit Bookmark</legend>
{BookmarkBreadCrumbs}
<form action="" method="post" class="form-horizontal">
<input type="hidden" name="token" value="{TOKEN}">
<div class="form-group">
<label for="title" class="col-lg-3 control-label">Title</label>
<div class="col-lg-3">
<input type="text" class="form-control" name="title" id="title" value="{title}">
</div>
</div>
<div class="form-group">
<label for="url" class="col-lg-3 control-label">URL:</label>
<div class="col-lg-3">
<input type="text" class="form-control" name="url" id="url" value="{url}">
</div>
</div>
<div class="form-group">
<label for="description" class="col-lg-3 control-label">Description:</label>
<div class="col-lg-3">
<textarea class="form-control" name="description" maxlength="2000" rows="10" cols="50" id="description">{description}</textarea>
</div>
</div>
{folderSelect}
<div class="form-group">
<label for="privacy" class="col-lg-3 control-label">Privacy</label>
<div class="col-lg-3 select-container" id="colorContainer">
<select id="privacy" name="privacy" class="form-control custom-select" value="{privacy}">
<option value="private">Private</option>
<option value="public">Public</option>
</select>
</div>
</div>
<div class="form-group">
<label for="color" class="col-lg-3 control-label">Color</label>
<div class="col-lg-3 select-container" id="colorContainer">
{colorSelect}
</div>
</div>
<div class="form-group">
<label for="submit" class="col-lg-3 control-label"></label>
<div class="col-lg-3">
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block ">Submit</button>
</div>
</div>
</form>

View File

@ -1,37 +0,0 @@
{BookmarkBreadCrumbs}
<table class="table table-striped">
<thead>
<tr>
<th style="width: 75%">Bookmark</th>
<th style="width: 10%"></th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td style="text-align: center;">
<a href="{url}" role="button">
{title}
</a>
</td>
<td style="text-align: center;">
{privacy}
</td>
<td><a href="{ROOT_URL}bookmarks/bookmarks/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-open"></i></a></td>
<td><a href="{ROOT_URL}bookmarks/editBookmark/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
<td><a href="{ROOT_URL}bookmarks/deleteBookmark/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
</tr>
{/LOOP}
{ALT}
<tr>
<td style="text-align: center;" colspan="6">
No results to show.
</td>
</tr>
{/ALT}
</tbody>
</table>
<a href="{ROOT_URL}bookmarks/createBookmark" class="btn btn-sm btn-primary" role="button">Create</a>

View File

@ -1,84 +0,0 @@
{BookmarkBreadCrumbs}<br />
<div class="container col-md-4 col-lg-4">
<div class="row">
<div class="panel panel-{color}">
<div class="panel-heading">
<h3 class="panel-title">Bookmark</h3>
</div>
<div class="panel-body">
<div class="row">
<div class="">
<table class="table table-user-primary">
<tbody>
<tr>
<td align="left" width="200"><b>Title</b></td>
<td align="right">{title}</td>
</tr>
<tr>
<td align="left" width="200"><b>URL</b></td>
<td align="right">{url}</td>
</tr>
<tr>
<td align="left" width="200"><b>Type</b></td>
<td align="right">{linkType}</td>
</tr>
<tr>
<td align="left" width="200"><b>Privacy</b></td>
<td align="right">{privacy}</td>
</tr>
<tr>
<td align="left" width="200"><b>Color</b></td>
<td align="right">{color}</td>
</tr>
<tr>
<td align="center" colspan="2"><b>Description</b></td>
</tr>
<tr>
<td colspan="2">{description}</td>
</tr>
<tr>
<td align="center" colspan="2"><b>Icon</b></td>
</tr>
<tr>
<td colspan="2">{iconHtml}</td>
</tr>
<tr>
<td colspan="2">{icon}</td>
</tr>
<tr>
<td align="center" colspan="2"><b>Meta</b></td>
</tr>
<tr>
<td colspan="2">{meta}</td>
</tr>
<tr>
<td><b>Created</b></td>
<td align="right">{DTC}{createdAt}{/DTC}</td>
</tr>
<tr>
<td><b>Archived</b></td>
<td align="right">{DTC}{archivedAt}{/DTC}</td>
</tr>
<tr>
<td><b>Hidden</b></td>
<td align="right">{DTC}{hiddenAt}{/DTC}</td>
</tr>
<tr>
<td><b>Last Refreshed</b></td>
<td align="right">{DTC}{refreshedAt}{/DTC}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="panel-footer">
{refreshBtn}
{hideBtn}
{archiveBtn}
<a href="{ROOT_URL}bookmarks/editBookmark/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a>
<a href="{ROOT_URL}bookmarks/deleteBookmark/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a>
</div>
</div>
</div>
</div>

View File

@ -1,21 +0,0 @@
<div class="panel panel-{color}">
<div class="panel-heading" data-target="#Collapse{ID}" data-toggle="collapse" aria-expanded="true" aria-controls="#Collapse{ID}">
{title}
</div>
<div id="Collapse{ID}" class="panel-collapse collapse in" style="width:100%; position: relative;" role="tabpanel" aria-expanded="true">
<div class="panel-body">
<ul class="list-group">
{bookmarkListRows}
</ul>
</div>
<div class="panel-footer">
<a href="{ROOT_URL}bookmarks/createBookmark/{ID}" class="btn btn-sm btn-success" role="button"><i class="glyphicon glyphicon-plus-sign"></i></a></td>
<span class="pull-right">
<a href="{ROOT_URL}bookmarks/bookmarks/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-th-list"></i></a>
<a href="{ROOT_URL}bookmarks/folders/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-info-sign"></i></a></td>
<a href="{ROOT_URL}bookmarks/editFolder/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
<a href="{ROOT_URL}bookmarks/deleteFolder/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
</span>
</div>
</div>
</div>

View File

@ -1,18 +0,0 @@
{LOOP}
<li class="list-group-item list-group-item-{color}">
<a href="{ROOT_URL}bookmarks/bookmarks/{ID}" class="btn btn-sm" role="button">{iconHtml}</a>
<a href="{url}" class="list-group"> {title}</a>
<span class="pull-right">
{hideBtn}
{archiveBtn}
<a href="{ROOT_URL}bookmarks/editBookmark/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a>
<a href="{ROOT_URL}bookmarks/deleteBookmark/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a>
</span>
</li>
{/LOOP}
{ALT}
<li class="list-group-item">
<a href="#" class="list-group">No Bookmarks</a>
</li>
{/ALT}

View File

@ -1,10 +0,0 @@
{LOOP}
<div class="col-xlg-6 col-lg-6 col-md-6 col-sm-6 col-xs-6">
{panel}
</div>
{/LOOP}
{ALT}
<div class="col-xlg-6 col-lg-6 col-md-6 col-sm-6 col-xs-6">
<p>no folders</p>
</div>
{/ALT}

View File

@ -1,16 +0,0 @@
{BookmarkBreadCrumbs}
<div class="row">
<div class="col-xlg-6 col-lg-6 col-md-6 col-sm-6 col-xs-6">
<legend>Unsorted Bookmarks</legend>
{bookmarksList}
</div>
<div class="col-xlg-6 col-lg-6 col-md-6 col-sm-6 col-xs-6">
<legend>Folders List</legend>
{foldersList}
</div>
</div>
<legend>Folders</legend>
<div class="row">
{folderPanels}
</div>

View File

@ -1,39 +0,0 @@
<legend>Create Folder</legend>
{BookmarkBreadCrumbs}
<form action="" method="post" class="form-horizontal">
<input type="hidden" name="token" value="{TOKEN}">
<div class="form-group">
<label for="title" class="col-lg-3 control-label">Title</label>
<div class="col-lg-3">
<input type="text" class="form-control" name="title" id="title">
</div>
</div>
<div class="form-group">
<label for="description" class="col-lg-3 control-label">Description:</label>
<div class="col-lg-3">
<textarea class="form-control" name="description" maxlength="2000" rows="10" cols="50" id="description"></textarea>
</div>
</div>
{folderSelect}
<div class="form-group">
<label for="privacy" class="col-lg-3 control-label">Privacy</label>
<div class="col-lg-3 select-container" id="colorContainer">
<select id="privacy" name="privacy" class="form-control custom-select">
<option value="private">Private</option>
<option value="public">Public</option>
</select>
</div>
</div>
<div class="form-group">
<label for="color" class="col-lg-3 control-label">Color</label>
<div class="col-lg-3 select-container" id="colorContainer">
{colorSelect}
</div>
</div>
<div class="form-group">
<label for="submit" class="col-lg-3 control-label"></label>
<div class="col-lg-3">
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block ">Submit</button>
</div>
</div>
</form>

View File

@ -1,39 +0,0 @@
<legend>Edit Folder</legend>
{BookmarkBreadCrumbs}
<form action="" method="post" class="form-horizontal">
<input type="hidden" name="token" value="{TOKEN}">
<div class="form-group">
<label for="title" class="col-lg-3 control-label">Title</label>
<div class="col-lg-3">
<input type="text" class="form-control" name="title" id="title" value="{title}">
</div>
</div>
<div class="form-group">
<label for="description" class="col-lg-3 control-label">Description:</label>
<div class="col-lg-3">
<textarea class="form-control" name="description" maxlength="2000" rows="10" cols="50" id="description">{description}</textarea>
</div>
</div>
{folderSelect}
<div class="form-group">
<label for="privacy" class="col-lg-3 control-label">Privacy</label>
<div class="col-lg-3 select-container" id="colorContainer">
<select id="privacy" name="privacy" class="form-control custom-select" value="{privacy}">
<option value="private">Private</option>
<option value="public">Public</option>
</select>
</div>
</div>
<div class="form-group">
<label for="color" class="col-lg-3 control-label">Color</label>
<div class="col-lg-3 select-container" id="colorContainer">
{colorSelect}
</div>
</div>
<div class="form-group">
<label for="submit" class="col-lg-3 control-label"></label>
<div class="col-lg-3">
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block ">Submit</button>
</div>
</div>
</form>

View File

@ -1,33 +0,0 @@
{BookmarkBreadCrumbs}
<table class="table table-striped">
<thead>
<tr>
<th style="width: 35%">Title</th>
<th style="width: 20%">Privacy</th>
<th style="width: 30%">Description</th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td align="center">{title}</td>
<td align="center">{privacy}</td>
<td>{description}</td>
<td><a href="{ROOT_URL}bookmarks/folders/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-info-sign"></i></a></td>
<td><a href="{ROOT_URL}bookmarks/editFolder/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
<td><a href="{ROOT_URL}bookmarks/deleteFolder/{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="7">
No results to show.
</td>
</tr>
{/ALT}
</tbody>
</table>
<a href="{ROOT_URL}bookmarks/createFolder" class="btn btn-sm btn-primary" role="button">Create</a>

View File

@ -1,47 +0,0 @@
{BookmarkBreadCrumbs}<br />
<div class="container col-md-4 col-lg-4">
<div class="row">
<div class="panel panel-{color}">
<div class="panel-heading">
<h3 class="panel-title">Bookmark Folder</h3>
</div>
<div class="panel-body">
<div class="row">
<div class="">
<table class="table table-user-primary">
<tbody>
<tr>
<td align="left" width="200"><b>Title</b></td>
<td align="right">{title}</td>
</tr>
<tr>
<td align="left" width="200"><b>Privacy</b></td>
<td align="right">{privacy}</td>
</tr>
<tr>
<td align="left" width="200"><b>Color</b></td>
<td align="right">{color}</td>
</tr>
<tr>
<td align="center" colspan="2"><b>Description</b></td>
</tr>
<tr>
<td colspan="2">{description}</td>
</tr>
<tr>
<td><b>Created</b></td>
<td align="right">{DTC}{createdAt}{/DTC}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="panel-footer">
<a href="{ROOT_URL}bookmarks/bookmarks/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-th-list"></i></a>
<a href="{ROOT_URL}bookmarks/editFolder/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a>
<a href="{ROOT_URL}bookmarks/deleteFolder/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a>
</div>
</div>
</div>
</div>

View File

@ -1,5 +0,0 @@
<ul class="nav nav-tabs">
<li><a href="{ROOT_URL}bookmarks/index/">Dashboard</a></li>
<li><a href="{ROOT_URL}bookmarks/folders/">Folders</a></li>
</ul>
{userFolderTabs}

View File

@ -1,9 +0,0 @@
<ul class="nav nav-tabs">
<li><a href="{ROOT_URL}bookmarks/folders/">All</a></li>
{LOOP}
<li><a href="{ROOT_URL}bookmarks/bookmarks/{ID}">{title}</a></li>
{/LOOP}
{ALT}
<li></li>
{/ALT}
</ul>

View File

@ -15,7 +15,7 @@ namespace TheTempusProject\Models;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Bedrock\Classes\Config;
use TheTempusProject\Canary\Bin\Canary as Debug;
use TheTempusProject\Bedrock\Classes\CustomException;
use TheTempusProject\Canary\Classes\CustomException;
use TheTempusProject\Classes\DatabaseModel;
use TheTempusProject\Plugins\Bugreport as Plugin;
use TheTempusProject\TheTempusProject as App;

View File

@ -1,7 +0,0 @@
<?php
# bugTracker
define( 'TRACKER_STATUS_IN_PROGRESS', 'In Progress' );
define( 'TRACKER_STATUS_TESTING', 'Needs Testing' );
define( 'TRACKER_STATUS_NEW', 'New' );
define( 'TRACKER_STATUS_FIXED', 'Fixed' );
define( 'TRACKER_STATUS_CLOSED', 'Closed' );

View File

@ -1,206 +0,0 @@
<?php
/**
* app/plugins/bugtracker/controllers/admin/bugtracker.php
*
* This is the Bug-Tracker admin controller.
*
* @package TP BugTracker
* @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\Check;
use TheTempusProject\Bedrock\Functions\Upload;
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\Houdini\Classes\Forms as FormGen;
use TheTempusProject\Classes\AdminController;
use TheTempusProject\Classes\Forms;
use TheTempusProject\Models\Bugtracker as BugtrackerModel;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Models\Comments;
class Bugtracker extends AdminController {
protected static $tracker;
protected static $comments;
public function __construct() {
parent::__construct();
self::$tracker = new BugtrackerModel;
self::$title = 'Admin - Bug-Tracker';
$view = Navigation::activePageSelect( 'nav.admin', '/admin/bugtracker' );
Components::set( 'ADMINNAV', $view );
}
public function index( $data = null ) {
Views::view( 'bugtracker.admin.list', self::$tracker->list() );
}
public function create( $data = null ) {
$form = '';
$form .= FormGen::getFormFieldHtml( 'title', 'Title', 'text', Input::post('title') );
$form .= FormGen::getFormFieldHtml( 'description', 'Description', 'block', Input::post('description') );
$form .= FormGen::getFormFieldHtml( 'bugImage', 'Screenshot', 'file', '' );
$form .= FormGen::getFormFieldHtml( 'url', 'URL (if possible)', 'text', '' );
$form .= FormGen::getFormFieldHtml( 'repeat', 'Has this happened more than once', 'radio' );
Components::set( 'TRACKER_FORM', $form );
if ( !Input::exists( 'submit' ) ) {
return Views::view( 'bugtracker.admin.create' );
}
if ( !Forms::check( 'newBugTracker' ) ) {
Issues::add( 'error', [ 'There was an error with your request.' => Check::userErrors() ] );
return Views::view( 'bugtracker.admin.create' );
}
$image = '';
if ( Input::exists( 'bugImage' ) ) {
$folder = IMAGE_UPLOAD_DIRECTORY . App::$activeUser->username . DIRECTORY_SEPARATOR;
if ( !Upload::image( 'bugImage', $folder ) ) {
Issues::add( 'error', [ 'There was an error with your upload.' => Check::systemErrors() ] );
} else {
$route = str_replace( APP_ROOT_DIRECTORY, '', $folder );
$image = $route . Upload::last();
}
}
$result = self::$tracker->create(
App::$activeUser->ID,
Input::post( 'url' ),
$image,
Input::post( 'repeat' ),
Input::post( 'description' ),
Input::post( 'title' ),
);
if ( $result ) {
Issues::add( 'success', 'Your tracker has been created.' );
return $this->index();
} else {
Issues::add( 'error', [ 'There was an unknown error submitting your data.' => Check::userErrors() ] );
return $this->index();
}
}
public function edit( $data = null ) {
if ( !Input::exists( 'submit' ) ) {
$bug = self::$tracker->findById( $data );
$statusList = [
TRACKER_STATUS_IN_PROGRESS => TRACKER_STATUS_IN_PROGRESS,
TRACKER_STATUS_TESTING => TRACKER_STATUS_TESTING,
TRACKER_STATUS_NEW => TRACKER_STATUS_NEW,
TRACKER_STATUS_FIXED => TRACKER_STATUS_FIXED,
TRACKER_STATUS_CLOSED => TRACKER_STATUS_CLOSED,
];
$form = '';
$form .= FormGen::getFormFieldHtml( 'title', 'Title', 'text', $bug->title );
$form .= FormGen::getFormFieldHtml( 'description', 'Description', 'block', $bug->description );
$form .= FormGen::getFormFieldHtml( 'bugImage', 'Screenshot', 'file', $bug->image );
$form .= FormGen::getFormFieldHtml( 'url', 'Page you were on', 'text', $bug->url );
$form .= FormGen::getFormFieldHtml( 'repeat', 'Has this happened more than once', 'radio', $bug->repeatable );
$form .= FormGen::getFormFieldHtml( 'status', 'Status', 'customSelect', $bug->status, $statusList );
Components::set( 'TRACKER_FORM', $form );
return Views::view( 'bugtracker.admin.edit', $bug );
}
if ( !Forms::check( 'editBugTracker' ) ) {
Issues::add( 'error', [ 'There was an error with your form.' => Check::userErrors() ] );
return $this->index();
}
$image = '';
if ( Input::exists( 'bugImage' ) ) {
$folder = IMAGE_UPLOAD_DIRECTORY . App::$activeUser->username . DIRECTORY_SEPARATOR;
if ( !Upload::image( 'bugImage', $folder ) ) {
Issues::add( 'error', [ 'There was an error with your upload.' => Check::systemErrors() ] );
} else {
$image = $folder . Upload::last();
}
}
$tracker = self::$tracker->updateTracker(
$data,
Input::post( 'url' ),
$image,
Input::post( 'repeat' ),
Input::post( 'description' ),
Input::post( 'title' ),
Input::post( 'status' )
);
if ( true === $tracker ) {
Issues::add( 'success', 'Tracker Updated.' );
return $this->index();
}
Issues::add( 'error', 'There was an error with your request.' );
$this->index();
}
public function view( $id = null ) {
if ( empty( self::$comments ) ) {
self::$comments = new Comments;
}
$data = self::$tracker->findById( $id );
if ( $data === false ) {
Issues::add( 'error', 'Tracker not found.' );
return $this->index();
}
if ( Input::exists( 'contentId' ) ) {
$this->comments( 'post', Input::post( 'contentId' ) );
}
if ( empty( self::$comments ) ) {
self::$comments = new Comments;
}
Components::set( 'CONTENT_ID', $id );
Components::set( 'COMMENT_TYPE', 'admin/bugtracker' );
Components::set( 'count', self::$comments->count( 'tracker', $id ) );
Components::set( 'NEWCOMMENT', Views::simpleView( 'comments.create' ) );
Components::set( 'COMMENTS', Views::simpleView( 'comments.list', self::$comments->display( 10, 'tracker', $id ) ) );
Views::view( 'bugtracker.admin.view', $data );
}
public function delete( $data = null ) {
if ( $data == null ) {
if ( Input::exists( 'T_' ) ) {
$data = Input::post( 'T_' );
}
}
if ( !self::$tracker->delete( $data ) ) {
Issues::add( 'error', 'There was an error with your request.' );
} else {
Issues::add( 'success', 'Tracker has been deleted' );
}
$this->index();
}
public function comments( $sub = null, $data = null ) {
if ( empty( self::$comments ) ) {
self::$comments = new Comments;
}
if ( empty( $sub ) || empty( $data ) ) {
Session::flash( 'error', 'Whoops, try again.' );
Redirect::to( 'admin/bugtracker' );
}
switch ( $sub ) {
case 'post':
$content = self::$tracker->findById( $data );
if ( empty( $content ) ) {
Session::flash( 'error', 'Unknown Post.' );
Redirect::to( 'admin/bugtracker' );
}
return self::$comments->formPost( 'tracker', $content, 'admin/bugtracker/view/' );
case 'edit':
$content = self::$comments->findById( $data );
if ( empty( $content ) ) {
Session::flash( 'error', 'Unknown Comment.' );
Redirect::to( 'admin/bugtracker' );
}
return self::$comments->formEdit( 'tracker', $content, 'admin/bugtracker/view/' );
case 'delete':
$content = self::$comments->findById( $data );
if ( empty( $content ) ) {
Session::flash( 'error', 'Unknown Comment.' );
Redirect::to( 'admin/bugtracker' );
}
return self::$comments->formDelete( 'tracker', $content, 'admin/bugtracker/view/' );
}
}
}

View File

@ -1,92 +0,0 @@
<?php
/**
* app/plugins/bugtracker/forms.php
*
* This houses all of the form checking functions for this plugin.
*
* @package TP BugTracker
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Plugins\Bugreport;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\Classes\Forms;
class BugTrackerForms extends Forms {
/**
* Adds these functions to the form list.
*/
public function __construct() {
self::addHandler( 'newBugTracker', __CLASS__, 'newBugTracker' );
self::addHandler( 'editBugTracker', __CLASS__, 'editBugTracker' );
}
/**
* Validates the bug tracker create form.
*
* @return {bool}
*/
public static function newBugTracker() {
if ( !empty(Input::post( 'url' )) && !self::url( Input::post( 'url' ) ) ) {
self::addUserError( 'Invalid url: <code>' . Input::post( 'url' ) . '</code>' );
return false;
}
if ( !self::tf( Input::post( 'repeat' ) ) ) {
self::addUserError( 'Invalid repeat value: ' . Input::post( 'repeat' ) );
return false;
}
if ( !Input::exists( 'title' ) ) {
self::addUserError( 'You must specify title' );
return false;
}
if ( !self::dataTitle( Input::post( 'title' ) ) ) {
self::addUserError( 'Invalid title' );
return false;
}
if ( !Input::exists( 'description' ) ) {
self::addUserError( 'You must specify a description' );
return false;
}
// if ( !self::token() ) {
// return false;
// }
return true;
}
/**
* Validates the bug tracker create form.
*
* @return {bool}
*/
public static function editBugTracker() {
if ( !empty(Input::post( 'url' )) && !self::url( Input::post( 'url' ) ) ) {
self::addUserError( 'Invalid url.' . Input::post( 'url' ) );
return false;
}
if ( !self::tf( Input::post( 'repeat' ) ) ) {
self::addUserError( 'Invalid repeat value.' );
return false;
}
if ( !Input::exists( 'title' ) ) {
self::addUserError( 'You must specify title' );
return false;
}
if ( !self::dataTitle( Input::post( 'title' ) ) ) {
self::addUserError( 'Invalid title' );
return false;
}
if ( !Input::exists( 'description' ) ) {
self::addUserError( 'You must specify a description' );
return false;
}
// if ( !self::token() ) {
// return false;
// }
return true;
}
}
new BugTrackerForms;

View File

@ -1,142 +0,0 @@
<?php
/**
* app/plugins/bugtracker/models/bugtracker.php
*
* This class is used for the manipulation of the bugs database table.
*
* @package TP BugTracker
* @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\Bedrock\Classes\Config;
use TheTempusProject\Canary\Bin\Canary as Debug;
use TheTempusProject\Bedrock\Classes\CustomException;
use TheTempusProject\Classes\DatabaseModel;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Plugins\Bugtracker as Plugin;
class Bugtracker extends DatabaseModel {
public $tableName = 'bugs';
public $databaseMatrix = [
[ 'userID', 'int', '11' ],
[ 'time', 'int', '10' ],
[ 'title', 'varchar', '128' ],
[ 'status', 'varchar', '64' ],
[ 'description', 'text', '' ],
[ 'image', 'varchar', '256' ],
[ 'repeatable', 'varchar', '5' ],
[ 'url', 'varchar', '256' ],
];
public $plugin;
/**
* The model constructor.
*/
public function __construct() {
parent::__construct();
$this->plugin = new Plugin;
}
/**
* This function parses the bug reports description and
* separates it into separate keys in the array.
*
* @param array $data - The data being parsed.
*
* @return array
*/
public function filter( $data, $params = [] ) {
foreach ( $data as $instance ) {
if ( !is_object( $instance ) ) {
$instance = $data;
$end = true;
}
$instance->submittedBy = self::$user->getUsername( $instance->userID );
$instance->repeatText = ( 'false' == $instance->repeatable ? 'no' : 'yes' );
$out[] = $instance;
if ( !empty( $end ) ) {
$out = $out[0];
break;
}
}
return $out;
}
/**
* Logs a Bug Report form.
*
* @param int $ID the user ID submitting the form
* @param string $url the url
* @param string $o_url the original url
* @param int $repeat is repeatable?
* @param string $description_ description of the event.
*
* @return null
*/
public function create( $ID, $url, $image, $repeat, $description, $title ) {
if ( !$this->plugin->checkEnabled() ) {
Debug::info( 'Bug Tracking is disabled in the config.' );
return false;
}
if ( !Check::dataTitle( $title ) ) {
Debug::info( 'bugTracker: illegal title.' );
return false;
}
$fields = [
'userID' => App::$activeUser->ID,
'time' => time(),
'title' => $title,
'status' => TRACKER_STATUS_NEW,
'description' => $description,
'image' => $image,
'repeatable' => $repeat,
'url' => $url,
];
if ( !self::$db->insert( $this->tableName, $fields ) ) {
new CustomException( $this->tableName );
return false;
}
return self::$db->lastId();
}
public function updateTracker( $ID, $url, $image, $repeat, $description, $title, $status ) {
if ( !$this->plugin->checkEnabled() ) {
Debug::info( 'Bug Tracking is disabled in the config.' );
return false;
}
if ( empty( self::$log ) ) {
self::$log = new Log;
}
if ( !Check::id( $ID ) ) {
Debug::info( 'bugTracker: illegal ID.' );
return false;
}
if ( !Check::dataTitle( $title ) ) {
Debug::info( 'bugTracker: illegal title.' );
return false;
}
$fields = [
'url' => $url,
'description' => $description,
'repeatable' => $repeat,
'title' => $title,
'status' => $status,
];
if ( !empty( $image ) ) {
$fields['image'] = $image;
}
if ( !self::$db->update( $this->tableName, $ID, $fields ) ) {
new CustomException( $this->tableName );
Debug::error( "Tracker Post: $ID not updated: $fields" );
return false;
}
self::$log->admin( "Updated Tracker Post: $ID" );
return true;
}
}

View File

@ -1,48 +0,0 @@
<?php
/**
* app/plugins/bugtracker/plugin.php
*
* This houses all of the main plugin info and functionality.
*
* @package TP BugTracker
* @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\Classes\Installer;
use TheTempusProject\Houdini\Classes\Navigation;
use TheTempusProject\Classes\Plugin;
use TheTempusProject\TheTempusProject as App;
class Bugtracker extends Plugin {
public $pluginName = 'TP BugTracker';
public $pluginAuthor = 'JoeyK';
public $pluginWebsite = 'https://TheTempusProject.com';
public $modelVersion = '1.0';
public $pluginVersion = '3.0';
public $pluginDescription = '';
public $configName = 'bugtracker';
public $configMatrix = [
'enabled' => [
'type' => 'radio',
'pretty' => 'Enable Bug tracking.',
'default' => true,
],
];
public $permissionMatrix = [
'bugTrack' => [
'pretty' => 'Can Track Bugs',
'default' => false,
],
];
public $admin_links = [
[
'text' => '<i class="fa fa-fw fa-bug"></i> Bug Tracker',
'url' => '{ROOT_URL}admin/bugtracker',
],
];
}

View File

@ -1,6 +0,0 @@
<form action="" method="post" class="form-horizontal" enctype="multipart/form-data">
<legend>Create Bug Tracker</legend>
{TRACKER_FORM}
<input type="hidden" name="token" value="{TOKEN}">
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Save</button><br>
</form>

View File

@ -1,30 +0,0 @@
<legend>New Bugs</legend>
<table class="table table-striped">
<thead>
<tr>
<th style="width: 20%"></th>
<th style="width: 65%"></th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td>{title}</td>
<td>{description}</td>
<td><a href="{ROOT_URL}admin/bugtracker/view/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-open"></i></a></td>
<td><a href="{ROOT_URL}admin/bugtracker/edit/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
<td width="30px"><a href="{ROOT_URL}admin/bugtracker/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="5">
No results to show.
</td>
</tr>
{/ALT}
</tbody>
</table>

View File

@ -1,6 +0,0 @@
<form action="" method="post" class="form-horizontal" enctype="multipart/form-data">
<legend>Edit Bug Tracker</legend>
{TRACKER_FORM}
<input type="hidden" name="token" value="{TOKEN}">
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Save</button><br>
</form>

View File

@ -1,45 +0,0 @@
<legend>Bug Trackers</legend>
{PAGINATION}
<form action="{ROOT_URL}admin/bugtracker/delete" method="post">
<table class="table table-striped">
<thead>
<tr>
<th style="width: 30%">Title</th>
<th style="width: 40%">Description</th>
<th style="width: 10%">Status</th>
<th style="width: 5%">Time Submitted</th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
<th style="width: 5%">
<INPUT type="checkbox" onchange="checkAll(this)" name="check.br" value="T_[]"/>
</th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td><a href="{ROOT_URL}admin/bugtracker/view/{ID}">{title}</a></td>
<td>{description}</td>
<td>{status}</td>
<td align="center">{DTC}{time}{/DTC}</td>
<td><a href="{ROOT_URL}admin/bugtracker/edit/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
<td><a href="{ROOT_URL}admin/bugtracker/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="T_[]">
</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>
<a href="{ROOT_URL}admin/bugtracker/create" class="btn btn-sm btn-primary" role="button">Create</a>
</form>
<br />
<a href="{ROOT_URL}admin/bugtracker/clear">clear all</a>

View File

@ -1,74 +0,0 @@
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-6 col-lg-6 col-xs-offset-0 col-sm-offset-0 col-md-offset-3 col-lg-offset-3 top-pad" >
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Bug Tracker</h3>
</div>
<div class="panel-body">
<div class="row">
<div class=" col-md-12 col-lg-12 ">
<table class="table table-user-primary">
<tbody>
<tr>
<td align="center" colspan="2">Title</td>
</tr>
<tr>
<td colspan="2">{title}</td>
</tr>
<tr>
<td align="center" colspan="2">Description</td>
</tr>
<tr>
<td colspan="2">{description}</td>
</tr>
</tr>
<tr>
<td colspan="2">
<div align="center">
<a href="{ROOT_URL}{image}"><img alt="Screenshot" src="{ROOT_URL}{image}" class="img-responsive"></a>
</div>
</td>
</tr>
<tr>
<td align="left" width="200">Status</td>
<td align="right">{status}</td>
</tr>
<tr>
<td align="left" width="200">ID</td>
<td align="right">{ID}</td>
</tr>
<tr>
<td>Time submitted</td>
<td align="right">{DTC}{time}{/DTC}</td>
</tr>
<tr>
<td>Submitted by</td>
<td align="right"><a href="{ROOT_URL}admin/users/view/{userID}">{submittedBy}</a></td>
</tr>
<tr>
<td>URL:</td>
<td align="right">{URL}</td>
</tr>
<tr>
<td>Multiple occurrences?</td>
<td align="right">{repeatText}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="panel-footer">
{ADMIN}
<a href="{ROOT_URL}admin/bugtracker/delete/{ID}" class="btn btn-md btn-danger" role="button">Delete</a>
<a href="{ROOT_URL}admin/bugtracker/edit/{ID}" class="btn btn-md btn-warning" role="button">Edit</a>
<a href="{ROOT_URL}admin/comments/tracker/{ID}" class="btn btn-md btn-primary" role="button">View Comments</a>
{/ADMIN}
</div>
</div>
{COMMENTS}
{NEWCOMMENT}
</div>
</div>
</div>

View File

@ -1,593 +0,0 @@
<?php
/**
* app/plugins/calendar/controllers/calendar.php
*
* This is the calendar controller.
*
* @package TP Calendar
* @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\Bedrock\Functions\Check;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\Bedrock\Functions\Session;
use TheTempusProject\Bedrock\Functions\Date;
use TheTempusProject\Classes\Controller;
use TheTempusProject\Houdini\Classes\Forms as HoudiniForms;
use TheTempusProject\Classes\Forms;
use TheTempusProject\Houdini\Classes\Issues;
use TheTempusProject\Houdini\Classes\Views;
use TheTempusProject\Houdini\Classes\Template;
use TheTempusProject\Houdini\Classes\Components;
use TheTempusProject\Hermes\Functions\Redirect;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Models\Events;
use TheTempusProject\Models\Calendars;
use TheTempusProject\Houdini\Classes\Navigation;
class Calendar extends Controller {
protected static $events;
protected static $calendars;
protected static $defaultView;
protected static $defaultCalendar;
protected static $selectedDate;
public function __construct() {
if ( !App::$isLoggedIn ) {
Session::flash( 'notice', 'You must be logged in to create or manage calendars.' );
return Redirect::home();
}
parent::__construct();
self::$title = 'Calendar - {SITENAME}';
self::$pageDescription = 'The {SITENAME} calendar is where you can find various features for creating and managing events and schedules.';
self::$events = new Events;
self::$calendars = new Calendars;
$prefs = App::$activePrefs;
if ( ! empty( $prefs['calendarPreference'] ) ) {
$view = $prefs['calendarPreference'];
} else {
Session::flash( 'info', 'You can select a default view for this page in your user settings in the top right.' );
$view = 'byMonth';
}
self::$defaultView = $view;
self::$selectedDate = intval( strtotime( Date::determineDateInput() ) );
Template::setTemplate( 'calendar' );
// Date Dropdown
$dateDropdownView = Views::simpleView('calendar.nav.dateDropdown', Date::getDateBreakdown( self::$selectedDate ) );
Components::set( 'dateDropdown', $dateDropdownView );
// Calendar Top Tabs
$calendarTabs = Views::simpleView('calendar.nav.topTabs');
$tabsView = Navigation::activePageSelect( $calendarTabs, Input::get( 'url' ), false, true );
// must be done after top-nav gets selected
$calendarDropdown = Views::simpleView('calendar.nav.calendarDropdown', self::$calendars->simpleObjectByUser() );
$calendarDropdownView = Navigation::activePageSelect( $calendarDropdown, Input::get( 'url' ), false, true ); // add notebookID as second param
Components::set( 'calendarDropdown', $calendarDropdownView);
// must be done after dropdown gets added
Components::set( 'CalendarNav', Template::parse( $calendarTabs ) );
}
public function index() {
if ( method_exists( $this, self::$defaultView ) ) {
Redirect::to( 'calendar/'.self::$defaultView.'/' );
} else {
Redirect::to( 'calendar/byMonth/' );
}
}
/**
* Events
*/
public function event( $id = null ) {
$event = $this->findEventOrFail( $id );
Views::view( 'calendar.events.view', $event );
}
public function createEvent() {
// get the url calendar input
$newCalendar = Input::get('calendar_id') ? Input::get('calendar_id') : '';// for loading the form
$calendarSelect = HoudiniForms::getFormFieldHtml( 'calendar_id', 'Calendar', 'select', $newCalendar, self::$calendars->simpleByUser() );
Components::set( 'calendarSelect', $calendarSelect );
$repeatSelect = HoudiniForms::getFormFieldHtml( 'repeats', 'Frequency', 'select', 'none', self::$events->repeatOptions );
Components::set( 'repeatSelect', $repeatSelect );
$dateSelect = Views::simpleView( 'calendar.dateSelect', $this->getEventBreakdown( self::$selectedDate ) );
Components::set( 'dateSelect', $dateSelect );
if ( ! Input::exists() ) {
return Views::view( 'calendar.events.create' );
}
/** Attempt to save the form data somewhat */
// get the form calendar input
$calendarID = Input::post('calendar_id') ? Input::post('calendar_id') : ''; // for submitting the form
$calendarSelect = HoudiniForms::getFormFieldHtml( 'calendar_id', 'Calendar', 'select', $calendarID, self::$calendars->simpleByUser() );
Components::set( 'calendarSelect', $calendarSelect );
$repeatSelect = HoudiniForms::getFormFieldHtml( 'repeats', 'Frequency', 'select', Input::post('repeats'), self::$events->repeatOptions );
Components::set( 'repeatSelect', $repeatSelect );
if ( ! Forms::check( 'createEvent' ) ) {
Issues::add( 'error', [ 'There was an error with your form.' => Check::userErrors() ] );
return Views::view( 'calendar.events.create' );
}
$event_id = self::$events->create(
$calendarID,
Input::post('title'),
Date::applyUtcToDate( Date::determineDateInput() ),
Input::post('description'),
Input::post('location'),
Input::post('repeats'),
Input::post('color'),
0,
);
if ( ! $event_id ) {
Issues::add( 'error', [ 'There was an error creating your event.' => Check::userErrors() ] );
return Views::view( 'calendar.events.create' );
}
if ( Input::post('repeats') != 'none' ) {
$childrens = self::$events->generateChildEvents( $event_id, true, true );
}
Session::flash( 'success', 'Your Event has been created.' );
Redirect::to( 'calendar/'.self::$defaultView.'/'. $calendarID );
}
public function editEvent( $id = null ) {
$calendar = Input::exists('calendar_id') ? Input::post('calendar_id') : '';
$event = self::$events->findById( $id );
$readableDate = date('Y-m-d H:i:s', $event->event_time);
if ( $event == false ) {
Session::flash( 'error', 'Event not found.' );
return Redirect::to( 'calendar/'.self::$defaultView.'/' );
}
if ( $event->createdBy != App::$activeUser->ID ) {
Session::flash( 'error', 'You do not have permission to modify this event.' );
return Redirect::to( 'calendar/'.self::$defaultView.'/' );
}
$repeatSelect = HoudiniForms::getFormFieldHtml( 'repeats', 'Frequency', 'select', $event->repeats, self::$events->repeatOptions );
Components::set( 'repeatSelect', $repeatSelect );
// there should be a way to do this natively
$event_at = Date::getDateBreakdown( $event->event_time, true );
// $readableDate = date('Y-m-d H:i:s', $readableDate);
$dateSelect = Views::simpleView( 'calendar.dateSelect', $event_at );
Components::set( 'dateSelect', $dateSelect );
Components::set( 'color', $event->color );
if ( ! Input::exists( 'submit' ) ) {
return Views::view( 'calendar.events.edit', $event );
}
if ( ! Forms::check( 'editEvent' ) ) {
Issues::add( 'error', [ 'There was an error updating your event.' => Check::userErrors() ] );
return Views::view( 'calendar.events.edit', $event );
}
$result = self::$events->update(
$id,
Input::post('title'),
Date::applyUtcToDate( Date::determineDateInput() ),
Input::post('description'),
Input::post('location'),
Input::post('repeats'),
Input::post('color'),
);
if ( Input::post('repeats') != 'none' && $event->parent_id == 0 ) {
$childrens = self::$events->generateChildEvents( $event->ID, true, true );
}
if ( ! $result ) {
Issues::add( 'error', [ 'There was an error updating your event.' => Check::userErrors() ] );
return Views::view( 'calendar.events.edit', $event->ID );
}
Session::flash( 'success', 'Your Event has been updated.' );
Redirect::to( 'calendar/'.self::$defaultView.'/'. $event->calendar_id );
}
public function deleteEvent( $id = null ) {
$event = self::$events->findById( $id );
if ( $event == false ) {
Issues::add( 'error', 'Event not found.' );
return $this->index();
}
if ( $event->createdBy != App::$activeUser->ID ) {
Issues::add( 'error', 'You do not have permission to modify this event.' );
return $this->index();
}
$result = self::$events->delete( $id );
if ( !$result ) {
Session::flash( 'error', 'There was an error deleting the event(s)' );
} else {
Session::flash( 'success', 'Event deleted' );
}
return $this->index();
}
/**
* Calendars
*/
public function calendar( $id = null ) {
$calendar = $this->findCalendarOrFail( $id );
Views::view( 'calendar.calendar.view', $calendar );
}
public function createCalendar() {
$timezoneSelect = HoudiniForms::getTimezoneHtml( Date::getTimezone() );
Components::set( 'timezoneSelect', $timezoneSelect );
if ( ! Input::exists() ) {
return Views::view( 'calendar.calendar.create' );
}
if ( ! Forms::check( 'createCalendar' ) ) {
Issues::add( 'error', [ 'There was an error creating your calendar111.' => Check::userErrors() ] );
return Views::view( 'calendar.calendar.create' );
}
$calendar = self::$calendars->create( Input::post('title'), Input::post('description'), Input::post('timezone'), Input::post('color') );
if ( ! $calendar ) {
return Views::view( 'calendar.calendar.create' );
}
Session::flash( 'success', 'Your Calendar has been created.' );
Redirect::to( 'calendar/'.self::$defaultView.'/');
}
public function editCalendar( $id = null ) {
$calendar = $this->findCalendarOrFail( $id );
$timezoneSelect = HoudiniForms::getTimezoneHtml( Date::getTimezone() );
Components::set( 'timezoneSelect', $timezoneSelect );
Components::set( 'color', $calendar->color );
if ( ! Input::exists( 'submit' ) ) {
return Views::view( 'calendar.calendar.edit', $calendar );
}
if ( !Forms::check( 'editCalendar' ) ) {
Issues::add( 'error', [ 'There was an error editing your calendar.' => Check::userErrors() ] );
return Views::view( 'calendar.calendar.edit', $calendar );
}
$result = self::$calendars->update( $id, Input::post('title'), Input::post('description'), Input::post('timezone'), Input::post('color') );
if ( !$result ) {
Issues::add( 'error', [ 'There was an error updating your calendar.' => Check::userErrors() ] );
return Views::view( 'calendar.calendar.edit', $calendar );
}
Session::flash( 'success', 'Your Calendar has been updated.' );
Redirect::to( 'calendar/'.self::$defaultView.'/'. $calendar->ID );
}
public function deleteCalendar( $id = null ) {
$calendar = self::$calendars->findById( $id );
if ( $calendar == false ) {
Issues::add( 'error', 'Calendar not found.' );
return $this->index();
}
if ( $calendar->createdBy != App::$activeUser->ID ) {
Issues::add( 'error', 'You do not have permission to modify this calendar.' );
return $this->index();
}
$results = self::$events->deleteByCalendar( $id );
$result = self::$calendars->delete( $id );
if ( !$result ) {
Session::flash( 'error', 'There was an error deleting the calendar(s)' );
} else {
Session::flash( 'success', 'Calendar deleted' );
}
Redirect::to( 'calendar/'.self::$defaultView.'/' );
}
/**
* Views
*/
public function byDay( $id = 0 ) {
// Set base components
Components::set( 'currentView', __FUNCTION__ );
Components::set( 'calendarID', $id );
// Set components for next / back arrows
$nextDayMonth = date( 'M', strtotime( 'tomorrow', self::$selectedDate ) );
$nextDay = date( 'd', strtotime( 'tomorrow', self::$selectedDate ) );
$lastDayMonth = date( 'M', strtotime( 'yesterday', self::$selectedDate ) );
$lastDay = date( 'd', strtotime( 'yesterday', self::$selectedDate ) );
Components::set( 'nextDayMonth', $nextDayMonth );
Components::set( 'nextDay', $nextDay );
Components::set( 'lastDayMonth', $lastDayMonth );
Components::set( 'lastDay', $lastDay );
// Get the data
$dayArray = self::$events->dayArray( $id, self::$selectedDate );
// build the results
$selectedHour = Date::getCurrentHour();
$day = date( 'd', self::$selectedDate );
$month = date( 'M', self::$selectedDate );
$year = date( 'Y', self::$selectedDate );
$fullDay = [];
foreach ( $dayArray as $hour => $events ) {
Components::set( 'hour', $hour );
$hourCell = new \stdClass();
$hourCell->hour = $hour;
if ( $hour == $selectedHour ) {
$hourCell->hourSelected = ' hour-active';
} else {
$hourCell->hourSelected = '';
}
$hourCell->day = $day;
$hourCell->month = $month;
$hourCell->year = $year;
$hourCell->EventCells = Views::simpleView( 'calendar.nav.row', $events );
$fullDay[] = $hourCell;
}
// Calendar Top Tabs
Components::unset( 'calendarDropdown');
$calendarTabs = Views::simpleView('calendar.nav.topTabs');
$tabsView = Navigation::activePageSelect( $calendarTabs, '/calendar/byDay/', false, true );
// must be done after top-nav gets selected
$calendarDropdown = Views::simpleView('calendar.nav.calendarDropdown', self::$calendars->simpleObjectByUser() );
$calendarDropdownView = Navigation::activePageSelect( $calendarDropdown, Input::get( 'url' ), false, true ); // add notebookID as second param
Components::set( 'calendarDropdown', $calendarDropdownView);
Components::set( 'CalendarNav', Template::parse( $tabsView ) );
Components::set( 'activeDate', date( 'F d, Y', self::$selectedDate ) );
Views::view( 'calendar.byDay', $fullDay );
}
public function byWeek( $id = 0 ) {
// Set base components
Components::set( 'currentView', __FUNCTION__ );
Components::set( 'calendarID', $id );
// Set components for next / back arrows
$lastWeekMonth = date( 'M', strtotime( '-7 days', self::$selectedDate) );
$lastWeekDay = date( 'd', strtotime( '-7 days', self::$selectedDate) );
$lastWeekYear = date( 'Y', strtotime( '-7 days', self::$selectedDate) );
$nextWeekMonth = date( 'M', strtotime( '+7 days', self::$selectedDate) );
$nextWeekDay = date( 'd', strtotime( '+7 days', self::$selectedDate) );
$nextWeekYear = date( 'Y', strtotime( '+7 days', self::$selectedDate) );
Components::set( 'lastWeekMonth', $lastWeekMonth );
Components::set( 'lastWeek', $lastWeekDay );
Components::set( 'lastYear', $lastWeekYear );
Components::set( 'nextWeekMonth', $nextWeekMonth );
Components::set( 'nextWeek', $nextWeekDay );
Components::set( 'nextYear', $nextWeekYear );
// Get the data
$weekArray = self::$events->weekArray( $id, self::$selectedDate );
// build the results
$presentMonth = date( 'F', self::$selectedDate );
$presentDay = date( 'd', self::$selectedDate );
foreach ( $weekArray as $week => $days ) {
$weekFormat = [];
foreach ( $days as $day => $events ) {
if ( empty( $first ) ) {
$first = true;
if ( intval( $presentDay ) >= $day ) {
$month = date( 'F', self::$selectedDate );
} else {
$month = date( 'F', strtotime( '-7 days', self::$selectedDate ) );
}
}
if ( $day == '01' ) {
$month = date( 'F', strtotime( '+7 days', self::$selectedDate ) );
}
Components::set( 'currentMonth', $month );
Components::set( 'currentDay', $day );
$dayCell = new \stdClass();
if ( $presentDay == $day && $presentMonth == $month ) {
$dayCell->highlightedDate = ' today';
} else {
$dayCell->highlightedDate = '';
}
$dayCell->day = $day;
$dayCell->dayEventList = Views::simpleView( 'calendar.nav.cell', $events );
$weekFormat[] = $dayCell;
}
$weekView = Views::simpleView( 'calendar.nav.week', $weekFormat );
Components::set( $week . 'Element', $weekView );
}
// Calendar Top Tabs
Components::unset( 'calendarDropdown');
$calendarTabs = Views::simpleView('calendar.nav.topTabs');
$tabsView = Navigation::activePageSelect( $calendarTabs, '/calendar/byWeek/', false, true );
// must be done after top-nav gets selected
$calendarDropdown = Views::simpleView('calendar.nav.calendarDropdown', self::$calendars->simpleObjectByUser() );
$calendarDropdownView = Navigation::activePageSelect( $calendarDropdown, Input::get( 'url' ), false, true ); // add notebookID as second param
Components::set( 'calendarDropdown', $calendarDropdownView);
Components::set( 'CalendarNav', Template::parse( $tabsView ) );
Components::set( 'dateWeek', 'Week of ' . date( 'F d, Y', self::$selectedDate ) );
Views::view( 'calendar.byWeek' );
}
public function byMonth( $id = 0 ) {
// Set base components
Components::set( 'currentView', __FUNCTION__ );
Components::set( 'calendarID', $id );
// Set components for next / back arrows
$month = date( 'F', strtotime( 'first day of last month', self::$selectedDate ) );
$lastMonthYear = date( 'Y', strtotime( 'first day of last month', self::$selectedDate ) );
$nextMonth = date( 'F', strtotime( 'first day of next month', self::$selectedDate ) );
$nextMonthYear = date( 'Y', strtotime( 'first day of next month', self::$selectedDate ) );
Components::set( 'lastMonth', $month );
Components::set( 'lastMonthYear', $lastMonthYear );
Components::set( 'nextMonth', $nextMonth );
Components::set( 'nextMonthYear', $nextMonthYear );
// Get the data
$monthArray = self::$events->monthArray( $id, self::$selectedDate );
// build the results
$lastMonth = strtotime( 'last month', self::$selectedDate );
$presentMonth = date( 'F', self::$selectedDate );
$presentDay = date( 'd', self::$selectedDate );
foreach ( $monthArray as $week => $days ) {
$weekFormat = [];
foreach ( $days as $day => $events ) {
if ( $day == '01' ) {
$month = date( 'F', strtotime( '+1 month', $lastMonth ) );
$lastMonth = strtotime( '+1 month', $lastMonth) ;
}
Components::set( 'currentMonth', $month );
Components::set( 'currentDay', $day );
$dayCell = new \stdClass();
if ( $presentDay == $day && $presentMonth == $month ) {
$dayCell->highlightedDate = ' today';
} else {
$dayCell->highlightedDate = '';
}
$dayCell->day = $day;
// prevent duplicated entries for previous/next month
if ( $lastMonth < strtotime( 'this month',self::$selectedDate ) || $lastMonth == strtotime( 'next month',self::$selectedDate )) {
$events = [];
}
$dayCell->dayEventList = Views::simpleView( 'calendar.nav.cell', $events );
$weekFormat[] = $dayCell;
}
$weekView = Views::simpleView( 'calendar.nav.week', $weekFormat );
Components::set( $week . 'Element', $weekView );
}
// Calendar Top Tabs
Components::unset( 'calendarDropdown');
$calendarTabs = Views::simpleView('calendar.nav.topTabs');
$tabsView = Navigation::activePageSelect( $calendarTabs, '/calendar/byMonth/', false, true );
// must be done after top-nav gets selected
$calendarDropdown = Views::simpleView('calendar.nav.calendarDropdown', self::$calendars->simpleObjectByUser() );
$calendarDropdownView = Navigation::activePageSelect( $calendarDropdown, Input::get( 'url' ), false, true ); // add notebookID as second param
Components::set( 'calendarDropdown', $calendarDropdownView);
Components::set( 'CalendarNav', Template::parse( $tabsView ) );
Components::set( 'dateMonth', date( 'F Y', self::$selectedDate ) );
Views::view( 'calendar.byMonth' );
}
public function byYear( $id = 0 ) {
// Set base components
Components::set( 'calendarID', $id );
Components::set( 'currentView', __FUNCTION__ );
// Set components for next / back arrows
$nextYear = date( 'Y', strtotime( 'next year', self::$selectedDate ) );
$lastYear = date( 'Y', strtotime( 'last year', self::$selectedDate ) );
Components::set( 'lastYear', $lastYear );
Components::set( 'nextYear', $nextYear );
// Get the data
$eventList = self::$events->yearArray( $id, self::$selectedDate );
// Calendar Top Tabs
Components::unset( 'calendarDropdown');
$calendarTabs = Views::simpleView('calendar.nav.topTabs');
$tabsView = Navigation::activePageSelect( $calendarTabs, '/calendar/byYear/', false, true );
// must be done after top-nav gets selected
$calendarDropdown = Views::simpleView('calendar.nav.calendarDropdown', self::$calendars->simpleObjectByUser() );
$calendarDropdownView = Navigation::activePageSelect( $calendarDropdown, Input::get( 'url' ), false, true ); // add notebookID as second param
Components::set( 'calendarDropdown', $calendarDropdownView);
Components::set( 'CalendarNav', Template::parse( $tabsView ) );
Components::set( 'dateYear', date( 'Y', self::$selectedDate ) );
Views::view( 'calendar.byYear', $eventList );
}
public function events( $id = 0 ) {
Components::set( 'currentView', __FUNCTION__ );
Components::set( 'calendarID', $id );
if ( ! empty( $id ) ) {
$calendar = self::$calendars->findById( $id );
if ( $calendar == false ) {
Issues::add( 'error', 'Calendar not found.' );
return $this->index();
}
if ( $calendar->createdBy != App::$activeUser->ID ) {
Issues::add( 'error', 'You do not have permission to view this calendar.' );
return $this->index();
}
Components::set( 'calendarName', $calendar->title );
$eventList = self::$events->findByCalendar( $id );
} else {
$eventList = self::$events->userEvents( 5 );
}
// Calendar Top Tabs
Components::unset( 'calendarDropdown');
$calendarTabs = Views::simpleView('calendar.nav.topTabs');
$tabsView = Navigation::activePageSelect( $calendarTabs, '/calendar/events/', false, true );
// must be done after top-nav gets selected
$calendarDropdown = Views::simpleView('calendar.nav.calendarDropdown', self::$calendars->simpleObjectByUser() );
$calendarDropdownView = Navigation::activePageSelect( $calendarDropdown, Input::get( 'url' ), false, true ); // add notebookID as second param
Components::set( 'calendarDropdown', $calendarDropdownView);
Components::set( 'CalendarNav', Template::parse( $tabsView ) );
Views::view( 'calendar.events.list', $eventList );
}
/**
* Support Functions
*/
private function findCalendarOrFail( $id = null ) {
$calendar = self::$calendars->findById( $id );
if ( $calendar == false ) {
Session::flash( 'error', 'Calendar not found.' );
Redirect::to( 'calendar/'.self::$defaultView.'/' );
}
if ( $calendar->createdBy != App::$activeUser->ID ) {
Session::flash( 'error', 'Permissions Error.' );
Redirect::to( 'calendar/'.self::$defaultView.'/' );
}
return $calendar;
}
private function findEventOrFail( $id = null ) {
$event = self::$events->findById( $id );
if ( $event == false ) {
Session::flash( 'error', 'Event not found.' );
Redirect::to( 'calendar/'.self::$defaultView.'/' );
}
if ( $event->createdBy != App::$activeUser->ID ) {
Session::flash( 'error', 'Permissions Error.' );
Redirect::to( 'calendar/'.self::$defaultView.'/' );
}
return $event;
}
private function getEventBreakdown( $start_timestamp = 0, $end_timestamp = 0, $with_timezone = false ) {
$out = new \stdClass();
if ( empty( $end_timestamp ) ) {
$out->allDay = 'true';
// $out->date = ;
// $out->time = ;
$out->endDate = $out->date;
$out->endTime = $out->time;
} else {
$out->allDay = 'false';
// $out->date = ;
// $out->time = ;
$out->endDate = $out->date;
$out->endTime = $out->time;
}
$timestamp = intval( $timestamp );
$init = date('Y-m-d H:i:s', $timestamp);
if ( true === $with_timezone ) {
$readableDate = self::applyTimezoneToTimestamp( $timestamp );
} else {
$readableDate = date('Y-m-d H:i:s', $timestamp);
}
$date = date( 'Y-m-d', strtotime( $readableDate ) );
$time = date( 'H:i', strtotime( $readableDate ) );
return [
'time' => $time,
'date' => $date,
];
}
}

View File

@ -1,153 +0,0 @@
.calendar-container {
margin-left: 20px;
margin-right: 20px;
}
.calendar-row {
display: flex;
justify-content: space-between;
width: 100%;
}
.calendar-cell {
flex: 1;
border: 1px solid #ddd;
text-align: center;
padding: 10px 0;
margin: 0 5px;
}
.calendar-cell h4 {
margin: 0;
padding: 5px;
border-radius: 4px;
background-color: #f8f8f8;
}
.hour-row {
display: flex;
justify-content: space-between;
width: 100%;
}
.hour-body {
display: flex; /* Add this line to use flexbox */
flex-direction: row; /* Ensure the direction is row */
flex: 4;
border: 1px solid #ddd;
text-align: center;
padding: 10px 0;
margin-left: 5px;
margin-right: 5px;
align-items: center;
}
.hour-cell {
flex: 1;
border: 1px solid #ddd;
text-align: center;
padding: 10px 0;
margin-left: 5px;
margin-right: 5px;
align-items: center;
max-width: 250px;
}
.today {
background-color: #5cb85c !important;
}
.hour-header, .hour-footer {
flex: 0 0 10%;
background-color: #f8f8f8;
text-align: center;
padding: 10px 0;
margin: 0 5px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
/* Adjusting the first and last cell margins to align with the container edges */
.calendar-cell:first-child {
margin-left: 0;
}
.calendar-cell:last-child {
margin-right: 0;
}
.select-container {
color: white;
}
.custom-select {
/* color: red; */
color: #000;
}
.custom-select .white {
background-color: #ffffff;
}
.custom-select .primary {
background-color: #337ab7;
}
.custom-select .success {
background-color: #5cb85c;
}
.custom-select .info {
background-color: #5bc0de;
}
.custom-select .warning {
background-color: #f0ad4e;
}
.custom-select .danger {
background-color: #d9534f;
}
.select-container .primary {
background-color: #337ab7;
}
.select-container .white {
background-color: #ffffff;
}
.select-container .success {
background-color: #5cb85c;
}
.select-container .info {
background-color: #5bc0de;
}
.select-container .warning {
background-color: #f0ad4e;
}
.select-container .danger {
background-color: #d9534f;
}
.dateDayContainer {
width: 250px;
display: inline-block;
text-align: center;
}
.dateWeekContainer {
width: 450px;
display: inline-block;
text-align: center;
}
.dateMonthContainer {
width: 250px;
display: inline-block;
text-align: center;
}
.dateYearContainer {
width: 150px;
display: inline-block;
text-align: center;
}
.hour-active {
background-color: #217025 !important;
/* color: #00ff0d !important; */
background-image:none;
}

View File

@ -1,136 +0,0 @@
<?php
/**
* app/plugins/calendar/forms.php
*
* This houses all of the form checking functions for this plugin.
*
* @package TP Calendar
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Plugins\Calendar;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Classes\Forms;
class CalendarForms extends Forms {
/**
* Adds these functions to the form list.
*/
public function __construct() {
self::addHandler( 'calendarSelect', __CLASS__, 'calendarSelect' );
self::addHandler( 'createEvent', __CLASS__, 'createEvent' );
self::addHandler( 'createCalendar', __CLASS__, 'createCalendar' );
self::addHandler( 'editEvent', __CLASS__, 'editEvent' );
self::addHandler( 'editCalendar', __CLASS__, 'editCalendar' );
}
/**
* Validates the password re-send form.
*
* @return {bool}
*/
public static function calendarSelect() {
if ( ! Input::exists( 'calendar_id' ) ) {
Check::addUserError( 'You must include a title.' );
return false;
}
// if ( !self::token() ) {
// Check::addUserError( 'token - comment out later.' );
// return false;
// }
return true;
}
public static function createEvent() {
if ( ! Input::exists( 'title' ) ) {
Check::addUserError( 'You must include a title.' );
return false;
}
if ( ! Input::exists( 'date' ) ) {
Check::addUserError( 'You must include a date.' );
return false;
}
if ( ! Input::exists( 'time' ) ) {
Check::addUserError( 'You must include a time.' );
return false;
}
if ( ! Input::exists( 'repeats' ) ) {
Check::addUserError( 'You must include a frequency.' );
return false;
}
if ( ! Input::exists( 'calendar_id' ) ) {
Check::addUserError( 'You must select a calendar.' );
return false;
}
// if ( !self::token() ) {
// Check::addUserError( 'token - comment out later.' );
// return false;
// }
return true;
}
public static function createCalendar() {
if ( ! Input::exists( 'title' ) ) {
Check::addUserError( 'You must include a title.' );
return false;
}
if ( ! Input::exists( 'timezone' ) ) {
Check::addUserError( 'You must include a timezone.' );
return false;
}
// if ( ! self::token() ) {
// Check::addUserError( 'token - comment out later.' );
// return false;
// }
return true;
}
public static function editEvent() {
if ( ! Input::exists( 'title' ) ) {
Check::addUserError( 'You must include a title.' );
return false;
}
if ( ! Input::exists( 'date' ) ) {
Check::addUserError( 'You must include a date.' );
return false;
}
if ( ! Input::exists( 'time' ) ) {
Check::addUserError( 'You must include a time.' );
return false;
}
if ( ! Input::exists( 'repeats' ) ) {
Check::addUserError( 'You must include a frequency.' );
return false;
}
// if ( !self::token() ) {
// Check::addUserError( 'token - comment out later.' );
// return false;
// }
return true;
}
public static function editCalendar() {
if ( ! Input::exists( 'submit' ) ) {
return false;
}
if ( ! Input::exists( 'title' ) ) {
Check::addUserError( 'You must include a title.' );
return false;
}
if ( ! Input::exists( 'timezone' ) ) {
Check::addUserError( 'You must include a timezone.' );
return false;
}
// if ( !self::token() ) {
// Check::addUserError( 'token - comment out later.' );
// return false;
// }
return true;
}
}
new CalendarForms;

View File

@ -1,157 +0,0 @@
<?php
/**
* app/plugins/calendar/models/events.php
*
* This class is used for the manipulation of the calendars database table.
*
* @package TP Calendar
* @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\Bedrock\Functions\Date;
use TheTempusProject\Canary\Bin\Canary as Debug;
use TheTempusProject\Classes\DatabaseModel;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Houdini\Classes\Filters;
use TheTempusProject\Bedrock\Classes\CustomException;
class Calendars extends DatabaseModel {
public $tableName = 'calendars';
public $databaseMatrix = [
[ 'title', 'varchar', '256' ],
[ 'color', 'varchar', '48' ],
[ 'privacy', 'varchar', '48' ],
[ 'description', 'text', '' ],
[ 'createdBy', 'int', '11' ],
[ 'createdAt', 'int', '11' ],
[ 'timezone', 'varchar', '256' ],
];
/**
* The model constructor.
*/
public function __construct() {
parent::__construct();
}
public function create( $title, $description = '', $timezone = '', $color = 'default' ) {
if ( ! Check::dataTitle( $title ) ) {
Debug::info( 'Calendars: illegal title.' );
return false;
}
if ( empty( $timezone ) ) {
$timezone = Date::getTimezone();
}
$fields = [
'title' => $title,
'description' => $description,
'timezone' => $timezone,
'color' => $color,
'createdBy' => App::$activeUser->ID,
'createdAt' => time(),
];
if ( ! self::$db->insert( $this->tableName, $fields ) ) {
new CustomException( 'calendarCreate' );
Debug::error( "Calendar: not created " . var_export($fields,true) );
return false;
}
return self::$db->lastId();
}
public function update( $id, $title, $description = '', $timezone = '', $color = 'default' ) {
if ( empty( $timezone ) ) {
$timezone = Date::getTimezone();
}
if ( !Check::id( $id ) ) {
Debug::info( 'Calendars: illegal ID.' );
return false;
}
if ( !Check::dataTitle( $title ) ) {
Debug::info( 'Calendars: illegal title.' );
return false;
}
$fields = [
'title' => $title,
'description' => $description,
'timezone' => $timezone,
'color' => $color,
];
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
new CustomException( 'calendarUpdate' );
Debug::error( "Calendar: $id not updated: $fields" );
return false;
}
return true;
}
public function byUser( $limit = null ) {
$whereClause = ['createdBy', '=', App::$activeUser->ID];
if ( empty( $limit ) ) {
$calendars = self::$db->get( $this->tableName, $whereClause );
} else {
$calendars = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
}
if ( !$calendars->count() ) {
Debug::info( 'No Calendars found.' );
return false;
}
return $this->filter( $calendars->results() );
}
public function getName( $id ) {
$calendar = self::findById( $id );
if (false == $calendar) {
return 'unknown';
}
return $calendar->title;
}
public function getColor( $id ) {
$calendar = self::findById( $id );
if (false == $calendar) {
return 'default';
}
return $calendar->color;
}
public function simpleByUser() {
$whereClause = ['createdBy', '=', App::$activeUser->ID];
$calendars = self::$db->get( $this->tableName, $whereClause );
if ( !$calendars->count() ) {
Debug::warn( 'Could not find any calendars' );
return false;
}
$calendars = $calendars->results();
$out = [];
foreach ( $calendars as &$calendar ) {
$out[ $calendar->title ] = $calendar->ID;
}
return $out;
}
public function simpleObjectByUser() {
$whereClause = ['createdBy', '=', App::$activeUser->ID];
$calendars = self::$db->get( $this->tableName, $whereClause );
if ( !$calendars->count() ) {
Debug::warn( 'Could not find any calendars' );
return false;
}
$calendars = $calendars->results();
$out = [];
foreach ( $calendars as &$calendar ) {
$obj = new \stdClass();
$obj->title = $calendar->title;
$obj->ID = $calendar->ID;
$out[] = $obj;
}
return $out;
}
}

View File

@ -1,509 +0,0 @@
<?php
/**
* app/plugins/calendar/models/events.php
*
* This class is used for the manipulation of the events database table.
*
* @package TP Calendar
* @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\Bin\Canary as Debug;
use TheTempusProject\Classes\DatabaseModel;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Houdini\Classes\Filters;
use TheTempusProject\Models\Calendars;
use TheTempusProject\Bedrock\Classes\CustomException;
use TheTempusProject\Bedrock\Functions\Date;
use TheTempusProject\Bedrock\Classes\Pagination;
class Events extends DatabaseModel {
public $tableName = 'events';
public $repeatOptions = [
'Does Not Repeat' => 'none',
'Every Day' => 'daily',
'Every Week' => 'weekly',
'Every Month' => 'monthly',
'Every Year' => 'yearly',
];
public $databaseMatrix = [
[ 'calendar_id', 'int', '11' ],
[ 'title', 'varchar', '256' ],
[ 'event_time', 'int', '11' ],
[ 'event_ends', 'int', '11' ],
[ 'description', 'text', '' ],
[ 'location', 'varchar', '256' ],
[ 'repeats', 'varchar', '48' ],
[ 'color', 'varchar', '48' ],
[ 'parent_id', 'int', '11' ],
[ 'createdBy', 'int', '11' ],
[ 'createdAt', 'int', '11' ],
];
protected static $calendars;
/**
* The model constructor.
*/
public function __construct() {
parent::__construct();
self::$calendars = new Calendars;
}
/**
* Saves a chat form to the db.
*
* @param string $message -contents of the chat form.
* @return bool
*/
public function create( $calendar_id, $title, $event_time, $description = '', $location = '', $repeats = 'none', $color = 'default', $parent_id = 0 ) {
if ( ! Check::id( $calendar_id ) ) {
Debug::info( 'calendar event: illegal calendar ID.' );
return false;
}
$fields = [
'calendar_id' => $calendar_id,
'title' => $title,
'event_time' => $event_time,
'description' => $description,
'location' => $location,
'repeats' => $repeats,
'color' => $color,
'parent_id' => $parent_id,
'createdBy' => App::$activeUser->ID,
'createdAt' => time(),
];
if ( !self::$db->insert( $this->tableName, $fields ) ) {
Debug::info( 'Events::create - failed to insert to db' );
return false;
}
return self::$db->lastId();
}
public function update( $id, $title, $event_time, $description = '', $location ='', $repeats = 'none', $color = 'default', $parent_id = 0, $calendar_id = '' ) {
if ( ! Check::id( $id ) ) {
Debug::info( 'calendar event: illegal ID.' );
return false;
}
$fields = [
'title' => $title,
'event_time' => $event_time,
'description' => $description,
'location' => $location,
'repeats' => $repeats,
'color' => $color,
'parent_id' => $parent_id,
];
if ( ! self::$db->update( $this->tableName, $id, $fields ) ) {
new CustomException( 'calendarEventUpdate' );
Debug::error( "Event: $id not updated: $fields" );
return false;
}
return true;
}
public function dayArray( $calendar_id = 0, $date = 0 ) {
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
if ( ! empty( $calendar_id ) ) {
$whereClause = array_merge( $whereClause, [ 'calendar_id', '=', $calendar_id, 'AND' ] );
}
$whereClause = array_merge( $whereClause, [
'event_time', '>=', Date::getDayStartTimestamp( $date, true ), 'AND',
'event_time', '<=', Date::getDayEndTimestamp( $date, true ),
] );
$events = self::$db->get( $this->tableName, $whereClause );
if ( ! $events->count() ) {
$results = [];
} else {
$results = $events->results();
}
$events = $this->sortByEventTimeHour(
$this->filter(
$results
)
);
// Generate day array
$currentDay = [];
$currentHour = Date::getDayStartTimestamp( $date );
$lastHour = Date::getDayEndTimestamp( $date );
while ( $currentHour <= $lastHour ) {
$hour = date( 'H', $currentHour );
if ( ! empty( $events[ $hour ] ) ) {
$dailyEvents = $events[ $hour ];
} else {
$dailyEvents = [];
}
$currentDay[ $hour ] = $dailyEvents;
$currentHour = strtotime('+1 hour', $currentHour);
}
return $currentDay;
}
public function weekArray( $calendar_id = 0, $date = null ) {
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
if ( ! empty( $calendar_id ) ) {
$whereClause = array_merge( $whereClause, [ 'calendar_id', '=', $calendar_id, 'AND' ] );
}
$whereClause = array_merge( $whereClause, [
'event_time', '>=', Date::getWeekStartTimestamp( $date, true ), 'AND',
'event_time', '<=', Date::getWeekEndTimestamp( $date, true ),
] );
$events = self::$db->get( $this->tableName, $whereClause );
if ( ! $events->count() ) {
$results = [];
} else {
$results = $events->results();
}
$events = $this->sortByEventTime(
$this->filter(
$results
),
);
// Generate weeks array
$output = [];
$currentWeek = [];
$currentDay = Date::getWeekStartTimestamp( $date );
$weekCounter = 1;
$dayCounter = 1;
// Re-index the array using the date derived from event_time as the key
while ( $currentDay <= Date::getWeekEndTimestamp( $date ) ) {
$month = date( 'F', $currentDay );
$dayOfMonth = date( 'd', $currentDay );
if ( ! empty( $events[ $month ][ $dayOfMonth ] ) ) {
$dailyEvents = $events[ $month ][ $dayOfMonth ];
} else {
$dailyEvents = [];
}
$currentWeek[ $dayOfMonth ] = $dailyEvents;
$currentDay = strtotime('+1 day', $currentDay);
}
// Handle any remaining days in the last week
if ( ! empty( $currentWeek ) ) {
$output["week$weekCounter"] = $currentWeek;
}
return $output;
}
public function monthArray( $calendar_id = 0, $date = null ) {
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
if ( ! empty( $calendar_id ) ) {
$whereClause = array_merge( $whereClause, [ 'calendar_id', '=', $calendar_id, 'AND' ] );
}
$whereClause = array_merge( $whereClause, [
'event_time', '>=', Date::getMonthStartTimestamp( $date, true ), 'AND',
'event_time', '<=', Date::getMonthEndTimestamp( $date, true ),
] );
$events = self::$db->get( $this->tableName, $whereClause );
if ( ! $events->count() ) {
$results = [];
} else {
$results = $events->results();
}
$events = $this->sortByEventTime(
$this->filter(
$results
),
);
// Generate weeks array
$output = [];
$currentWeek = [];
$currentDay = Date::getMonthStartTimestamp( $date );
$weekCounter = 1;
$dayCounter = 1;
// Re-index the array using the date derived from event_time as the key
while ( $currentDay <= Date::getMonthEndTimestamp( $date ) ) {
$month = date( 'F', $currentDay );
$dayOfMonth = date( 'd', $currentDay );
if ( ! empty( $events[ $month ][ $dayOfMonth ] ) ) {
$dailyEvents = $events[ $month ][ $dayOfMonth ];
} else {
$dailyEvents = [];
}
$currentWeek[$dayOfMonth] = $dailyEvents;
if (count($currentWeek) == 7) {
$output["week$weekCounter"] = $currentWeek;
$currentWeek = [];
$weekCounter++;
}
$currentDay = strtotime('+1 day', $currentDay);
}
// Handle any remaining days in the last week
if ( ! empty( $currentWeek ) ) {
$output["week$weekCounter"] = $currentWeek;
}
while ( $weekCounter < 7 ) {
$output["week$weekCounter"] = [];
$weekCounter++;
}
return $output;
}
public function yearArray( $calendar_id = 0, $date = null ) {
if ( empty( $date ) ) {
$date = time();
}
$year = date( 'Y', $date );
$firstDayUnix = date( 'U', strtotime( "Jan 1, $year" ) );
$lastDayUnix = date( 'U', strtotime( "December 31, $year" ) );
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
if ( ! empty( $calendar_id ) ) {
$whereClause = array_merge( $whereClause, [ 'calendar_id', '=', $calendar_id, 'AND' ] );
}
$whereClause = array_merge( $whereClause, [
'event_time', '<=', $lastDayUnix, 'AND',
'event_time', '>=', $firstDayUnix,
] );
$events = self::$db->get( $this->tableName, $whereClause );
if ( ! $events->count() ) {
Debug::info( 'No ' . $this->tableName . ' data found.' );
return [];
}
return $this->filter( $events->results() );
}
public function compareEventTime($a, $b) {
return $a->event_time - $b->event_time;
}
public function sortByEventTimeHour( $results ) {
usort( $results, [ $this,'compareEventTime' ] );
$sortedResults = array();
foreach ( $results as $result ) {
$date = new \DateTime();
$date->setTimestamp( $result->event_time );
$timezone = new \DateTimeZone( Date::getTimezone() );
$date->setTimezone( $timezone );
$dateKey = $date->format('H');
$sortedResults[ $dateKey ][] = $result;
}
return $sortedResults;
}
public function sortByEventTime( $results ) {
usort( $results, [ $this,'compareEventTime' ] );
$sortedResults = array();
foreach ( $results as $result ) {
$date = new \DateTime();
$date->setTimestamp( $result->event_time );
$timezone = new \DateTimeZone( Date::getTimezone() );
$date->setTimezone( $timezone );
$month = $date->format('F');
$dateKey = $date->format('d');
if ( ! isset( $sortedResults[ $month ] ) ) {
$sortedResults[ $month ] = [];
}
if ( ! isset( $sortedResults[ $month ][ $dateKey ] ) ) {
$sortedResults[ $month ][ $dateKey ] = [];
}
$sortedResults[ $month ][ $dateKey ][] = $result;
}
return $sortedResults;
}
public function findByCalendar( $id ) {
$calendar = $this->verifyCalendar( $id );
if ( empty( $calendar ) ) {
return [];
}
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
$whereClause = array_merge( $whereClause, [ 'calendar_id', '=', $id ] );
$events = self::$db->getPaginated( $this->tableName, $whereClause );
if ( ! $events->count() ) {
Debug::info( 'No ' . $this->tableName . ' data found.' );
return [];
}
return $this->filter( $events->results() );
}
public function userEvents( $limit = 0 ) {
$whereClause = [ 'createdBy', '=', App::$activeUser->ID ];
$events = self::$db->getPaginated( $this->tableName, $whereClause );
if ( ! $events->count() ) {
Debug::info( 'No ' . $this->tableName . ' data found.' );
return [];
}
return $this->filter( $events->results() );
}
public function filter( $data, $params = [] ) {
$out = [];
foreach ( $data as $instance ) {
if ( !is_object( $instance ) ) {
$instance = $data;
$end = true;
}
$instance->repeatsText = array_search('none', $this->repeatOptions);
$instance->calendarName = self::$calendars->getName( $instance->calendar_id );
if ( empty( $instance->color ) || $instance->color == 'default' || $instance->color == 'none') {
$instance->displayColor = self::$calendars->getColor( $instance->calendar_id );
} else {
$instance->displayColor = $instance->color;
}
$out[] = $instance;
if ( !empty( $end ) ) {
$out = $out[0];
break;
}
}
return $out;
}
public function today( $limit = 0 ) {
$date = time();
$day = date('d', $date);
$month = date('M', $date);
$year = date( 'Y', $date );
$firstDayUnix = date( 'U', strtotime( "00:00:00 $day $month $year" ) );
$lastDayUnix = date( 'U', strtotime( "23:59:59 $day $month $year" ) );
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
$whereClause = array_merge( $whereClause, [
'event_time', '<=', $lastDayUnix, 'AND',
'event_time', '>=', $firstDayUnix,
] );
if ( empty( $limit ) ) {
$events = self::$db->get( $this->tableName, $whereClause );
} else {
$events = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
}
if ( ! $events->count() ) {
Debug::info( 'No ' . $this->tableName . ' data found.' );
return [];
}
return $this->filter( $events->results() );
}
private function verifyCalendar( $calendar_id ) {
if ( ! Check::id( $calendar_id ) ) {
Debug::info( 'Invalid Calendar ID' );
return false;
}
$calendar = self::$calendars->findById( $calendar_id );
if ( $calendar == false ) {
Debug::info( 'Calendar not found' );
return false;
}
if ( $calendar->createdBy != App::$activeUser->ID ) {
Debug::info( 'You do not have permission to view this calendar' );
return false;
}
return $calendar;
}
public function deleteByCalendar( $calendar_id ) {
$calendar = $this->verifyCalendar( $calendar_id );
if ( empty( $calendar ) ) {
return [];
}
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
$whereClause = array_merge( $whereClause, [ 'calendar_id', '=', $calendar_id ] );
$events = self::$db->get( $this->tableName, $whereClause );
if ( ! $events->count() ) {
Debug::info( 'No ' . $this->tableName . ' data found.' );
return [];
}
foreach( $events->results() as $event ) {
$this->deleteByParent( $event->ID );
}
return true;
}
public function deleteByParent( $event_id ) {
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
$whereClause = array_merge( $whereClause, [ 'parent_id', '=', $event_id ] );
$events = self::$db->get( $this->tableName, $whereClause );
if ( ! $events->count() ) {
Debug::info( 'No ' . $this->tableName . ' data found.' );
return [];
}
foreach( $events->results() as $event ) {
$this->delete( $event->ID );
}
// need to delete all child events accordingly
return true;
}
public function delete( $idArray ) {
if ( !is_array( $idArray ) ) {
$idArray = [ $idArray ];
}
return parent::delete( $idArray );
}
public function generateChildEvents( $event_id, $remove_existing_children = true, $remove_history = false ) {
$event = self::findById( $event_id );
if (empty($event)) {
return false;
}
if ($event->parent_id != 0) {
return false;
}
if (!in_array($event->repeats, $this->repeatOptions)) {
return false;
}
$startDate = time();
$whereClause = [
'parent_id', '=', $event_id,
];
if ( $remove_history && ! $remove_existing_children) {
$whereClause = array_merge( $whereClause, [ 'AND', 'event_time', '<=', $startDate ] );
} elseif ( $remove_existing_children && ! $remove_history ) {
$whereClause = array_merge( $whereClause, [ 'AND', 'event_time', '>=', $startDate ] );
} elseif ( !$remove_existing_children && !$remove_history ) {
return false;
}
self::$db->delete($this->tableName, $whereClause);
switch ($event->repeats) {
case 'daily':
return $this->generateEvents( $event, 'P90D' );
case 'weekly':
return $this->generateEvents( $event, 'P1W' );
case 'monthly':
return $this->generateEvents( $event, 'P1M' );
case 'yearly':
return $this->generateEvents( $event, 'P1Y' );
default:
return false;
}
}
private function generateEvents( $event, $interval, $years = 2 ) {
$endDate = strtotime('+'.$years.' years');
$interval = new \DateInterval( $interval );
$period = new \DatePeriod(new \DateTime('@' . $event->event_time), $interval, new \DateTime('@' . $endDate));
foreach ($period as $date) {
if ( $date->getTimestamp() <= time() ) {
continue;
}
$result = $this->create(
$event->calendar_id,
$event->title,
$date->getTimestamp(),
$event->description,
$event->location,
$event->repeats,
$event->color,
$event->ID,
);
}
}
}

View File

@ -1,84 +0,0 @@
<?php
/**
* app/plugins/calendar/plugin.php
*
* This houses all of the main plugin info and functionality.
*
* @package TP Calendar
* @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\Models\Events;
use TheTempusProject\Models\Calendars;
use TheTempusProject\Houdini\Classes\Components;
use TheTempusProject\Houdini\Classes\Template;
class Calendar extends Plugin {
public $pluginName = 'TP Calendar';
public $configName = 'calendar';
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 calendar system.';
public $permissionMatrix = [
'useCalendar' => [
'pretty' => 'Can use the calendar feature',
'default' => false,
],
'createEvents' => [
'pretty' => 'Can add events to calendars',
'default' => false,
],
];
public $main_links = [
[
'text' => 'Calendar',
'url' => '{ROOT_URL}calendar/index',
'filter' => 'loggedin',
],
];
public $configMatrix = [
'enabled' => [
'type' => 'radio',
'pretty' => 'Enable Calendar.',
'default' => true,
],
];
public $preferenceMatrix = [
'calendarPreference' => [
'pretty' => 'Default Calendar View',
'type' => 'select',
'default' => 'byMonth',
'options' => [
'Daily' => 'byDay',
'Weekly' => 'byWeek',
'Monthly' => 'byMonth',
'Yearly' => 'byYear',
'All Events' => 'events',
],
],
'weekStart' => [
'pretty' => 'First day of the week for the Calendar',
'type' => 'select',
'default' => 'sunday',
'options' => [
'Sunday' => '6',
'Monday' => '7',
],
],
];
public $events;
public $calendars;
public function __construct( $load = false ) {
$this->events = new Events;
$this->calendars = new Calendars;
parent::__construct( $load );
}
}

View File

@ -1,41 +0,0 @@
<?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;
use TheTempusProject\Models\Events;
use TheTempusProject\Models\Calendars;
class CalendarLoader extends DefaultLoader {
/**
* This is the function used to generate any components that may be
* needed by this template.
*/
public function __construct() {
$events = new Events;
$calendars = new Calendars;
Navigation::setCrumbComponent( 'CALENDAR_BREADCRUMBS', Input::get( 'url' ) );
Components::set( 'todaysDate', date( 'F d, Y', time()) );
Components::set( 'currentDay', date( 'F d, Y', time()) );
Components::set( 'weekOf', 'Week of ' . date( 'F d, Y', strtotime( 'this week' ) ) );
Components::set( 'year', date( 'Y', time() ));
Components::set( 'month', date( 'F', time() ));
parent::__construct();
}
}

View File

@ -1,96 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<!--
* app/plugins/calendar/templates/calendar.tpl
*
* @package TP Calendar
* @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' />
<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">
<meta name="author" content="The Tempus Project">
{ROBOT}
<link rel="alternate" hreflang="en-us" href="alternateURL">
<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">
<!-- RSS -->
<link rel="alternate" href="{ROOT_URL}blog/rss" title="{TITLE} Feed" type="application/rss+xml" />
<!-- Custom styles for this template -->
{TEMPLATE_CSS_INCLUDES}
<link rel="stylesheet" href="{ROOT_URL}app/plugins/calendar/css/calendar.css" />
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<!--Brand and toggle should get grouped for better mobile display -->
<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">
<div class="foot-pad">
{ISSUES}
<div class="row">
<div class="container">
{ERROR}
{NOTICE}
{SUCCESS}
</div>
</div>
{/ISSUES}
<div class="row">
<div class="container-fluid calendar-container">
<div class="row">
{CalendarNav}
{CONTENT}
</div>
</div>
</div>
</div>
</div>
<footer>
{COPY}
</footer>
<!-- Bootstrap core JavaScript and jquery -->
<script src="{JQUERY_CDN}jquery.min.js" crossorigin="anonymous"></script>
<script src="{BOOTSTRAP_CDN}js/bootstrap.min.js" crossorigin="anonymous"></script>
<!-- Custom javascript for this template -->
{TEMPLATE_JS_INCLUDES}
</body>
</html>

View File

@ -1,25 +0,0 @@
<h2 class="pull-left">
<a href="{ROOT_URL}calendar/byDay/{calendarID}?day={lastDay}&month={lastDayMonth}" role="button" class="btn btn-primary">
<i class="glyphicon glyphicon-chevron-left"></i>
</a>
<span class="dateDayContainer">{activeDate}</span>
<a href="{ROOT_URL}calendar/byDay/{calendarID}?day={nextDay}&month={nextDayMonth}" role="button" class="btn btn-primary">
<i class="glyphicon glyphicon-chevron-right"></i>
</a>
</h2>
{dateDropdown}
<div class="container-fluid">
{LOOP}
<div class="hour-row{hourSelected}">
<h2 class="hour-header">{hour}:00</h2>
{EventCells}
<span class="hour-footer">
<a href="{ROOT_URL}calendar/createEvent?calendar_id={calendarID}&hour={hour}&day={day}" class="btn btn-sm btn-success" role="button"><i class="glyphicon glyphicon-plus"></i></a>
</span>
</div>
{/LOOP}
{ALT}
<div class="hour-row{hourSelected}">
</div>
{/ALT}
</div>

View File

@ -1,34 +0,0 @@
<h2 class="pull-left">
<a href="{ROOT_URL}calendar/byMonth/{calendarID}?month={lastMonth}&year={lastMonthYear}" role="button" class="btn btn-primary">
<i class="glyphicon glyphicon-chevron-left"></i>
</a>
<span class="dateMonthContainer">{dateMonth}</span>
<a href="{ROOT_URL}calendar/byMonth/{calendarID}?month={nextMonth}&year={nextMonthYear}" role="button" class="btn btn-primary">
<i class="glyphicon glyphicon-chevron-right"></i>
</a>
</h2>
{dateDropdown}
<div class="container-fluid">
<!-- Header -->
<div class="row calendar-row">
<div class="col-xs-1 calendar-cell"><h4>Sunday</h4></div>
<div class="col-xs-1 calendar-cell"><h4>Monday</h4></div>
<div class="col-xs-1 calendar-cell"><h4>Tuesday</h4></div>
<div class="col-xs-1 calendar-cell"><h4>Wednesday</h4></div>
<div class="col-xs-1 calendar-cell"><h4>Thursday</h4></div>
<div class="col-xs-1 calendar-cell"><h4>Friday</h4></div>
<div class="col-xs-1 calendar-cell"><h4>Saturday</h4></div>
</div>
<!-- Week 1 -->
{week1Element}
<!-- Week 2 -->
{week2Element}
<!-- Week 3 -->
{week3Element}
<!-- Week 4 -->
{week4Element}
<!-- Week 5 -->
{week5Element}
<!-- Week 6 -->
{week6Element}
</div>

View File

@ -1,25 +0,0 @@
<h2 class="pull-left">
<a href="{ROOT_URL}calendar/byWeek/{calendarID}?month={lastWeekMonth}&day={lastWeek}&year={lastYear}" role="button" class="btn btn-primary">
<i class="glyphicon glyphicon-chevron-left"></i>
</a>
<span class="dateWeekContainer">{dateWeek}</span>
<a href="{ROOT_URL}calendar/byWeek/{calendarID}?month={nextWeekMonth}&day={nextWeek}&year={nextYear}" role="button" class="btn btn-primary">
<i class="glyphicon glyphicon-chevron-right"></i>
</a>
</h2>
{dateDropdown}
<div class="container-fluid">
<!-- Header -->
<div class="row calendar-row">
<div class="col-xs-1 calendar-cell"><h4>Sunday</h4></div>
<div class="col-xs-1 calendar-cell"><h4>Monday</h4></div>
<div class="col-xs-1 calendar-cell"><h4>Tuesday</h4></div>
<div class="col-xs-1 calendar-cell"><h4>Wednesday</h4></div>
<div class="col-xs-1 calendar-cell"><h4>Thursday</h4></div>
<div class="col-xs-1 calendar-cell"><h4>Friday</h4></div>
<div class="col-xs-1 calendar-cell"><h4>Saturday</h4></div>
</div>
<!-- Week 1 -->
{week1Element}
</div>

View File

@ -1,42 +0,0 @@
<h2 class="pull-left">
<a href="{ROOT_URL}calendar/byYear/{calendarID}?year={lastYear}" role="button" class="btn btn-primary">
<i class="glyphicon glyphicon-chevron-left"></i>
</a>
<span class="dateYearContainer">{dateYear}</span>
<a href="{ROOT_URL}calendar/byYear/{calendarID}?year={nextYear}" role="button" class="btn btn-primary">
<i class="glyphicon glyphicon-chevron-right"></i>
</a>
</h2>
{dateDropdown}
<table class="table table-striped">
<thead>
<tr>
<th style="width: 10%">ID</th>
<th style="width: 20%">Time</th>
<th style="width: 40%">Title</th>
<th style="width: 10%"></th>
<th style="width: 10%"></th>
<th style="width: 10%"></th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td style="text-align: center;">{ID}</td>
<td style="text-align: center;">{DTC}{event_time}{/DTC}</td>
<td style="text-align: center;">{title}</td>
<td><a href="{ROOT_URL}calendar/event/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-open"></i></a></td>
<td><a href="{ROOT_URL}calendar/editEvent/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
<td><a href="{ROOT_URL}calendar/deleteEvent/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
</tr>
{/LOOP}
{ALT}
<tr>
<td style="text-align: center;" colspan="6">
No results to show.
</td>
</tr>
{/ALT}
</tbody>
</table>
<a href="{ROOT_URL}calendar/createEvent" class="btn btn-sm btn-primary" role="button">Create</a>

View File

@ -1,34 +0,0 @@
<legend>Create Calendar</legend>
<form action="" method="post" class="form-horizontal">
<input type="hidden" name="token" value="{TOKEN}">
<div class="form-group">
<label for="title" class="col-lg-3 control-label">Title</label>
<div class="col-lg-3">
<input type="text" class="form-control" name="title" id="title">
</div>
</div>
<div class="form-group">
<label for="description" class="col-lg-3 control-label">Description</label>
<div class="col-lg-3">
<textarea class="form-control" name="description" maxlength="2000" rows="10" cols="50" id="description"></textarea>
</div>
</div>
<div class="form-group">
<label for="description" class="col-lg-3 control-label">Timezone</label>
<div class="col-lg-3">
{timezoneSelect}
</div>
</div>
<div class="form-group">
<label for="color" class="col-lg-3 control-label">Calendar Color</label>
<div class="col-lg-3 select-container" id="colorContainer">
{colorSelect}
</div>
</div>
<div class="form-group">
<label for="submit" class="col-lg-3 control-label"></label>
<div class="col-lg-3">
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block ">Submit</button>
</div>
</div>
</form>

View File

@ -1,29 +0,0 @@
<legend>Edit Calendar</legend>
<form action="" method="post" class="form-horizontal">
<div class="form-group">
<label for="title" class="col-lg-3 control-label">Title</label>
<div class="col-lg-3">
<input type="text" class="form-check-input form-control" name="title" id="title" value="{title}">
</div>
</div>
<div class="form-group">
<label for="description" class="col-lg-3 control-label">Description</label>
<div class="col-lg-6">
<textarea class="form-control" name="description" maxlength="2000" rows="10" cols="50" id="description">{description}</textarea>
</div>
</div>
<div class="form-group">
<label for="description" class="col-lg-3 control-label">Timezone</label>
<div class="col-lg-3">
{timezoneSelect}
</div>
</div>
<div class="form-group">
<label for="color" class="col-lg-3 control-label">Calendar Color</label>
<div class="col-lg-3 select-container" id="colorContainer">
{colorSelect}
</div>
</div>
<input type="hidden" name="token" value="{TOKEN}">
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Submit</button>
</form>

View File

@ -1,45 +0,0 @@
<legend>Calendars</legend>
<form action="{ROOT_URL}calendar/deleteCalendar" method="post">
<table class="table table-striped">
<thead>
<tr>
<th style="width: 5%">ID</th>
<th style="width: 20%">Title</th>
<th style="width: 50%">Description</th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
<th style="width: 5%">
<input type="checkbox" onchange="checkAll(this)" name="check.br" value="CAL_[]"/>
</th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td align="center">{ID}</td>
<td align="center">{title}</td>
<td>{description}</td>
<td><a href="{ROOT_URL}calendar/byMonth/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-share-alt"></i></a></td>
<td><a href="{ROOT_URL}calendar/calendar/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-info-sign"></i></a></td>
<td><a href="{ROOT_URL}calendar/editCalendar/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
<td><a href="{ROOT_URL}calendar/deleteCalendar/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
<td>
<input type="checkbox" value="{ID}" name="CAL_[]">
</td>
</tr>
{/LOOP}
{ALT}
<tr>
<td align="center" colspan="7">
No results to show.
</td>
</tr>
{/ALT}
</tbody>
</table>
<a href="{ROOT_URL}calendar/createCalendar" class="btn btn-sm btn-primary" role="button">Create</a>
<button name="submit" value="submit" type="submit" class="btn btn-sm btn-danger">Delete</button>
</form>
<br />

View File

@ -1,42 +0,0 @@
<div class="container col-md-4 col-lg-4">
<div class="row">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Calendar</h3>
</div>
<div class="panel-body">
<div class="row">
<div class="">
<table class="table table-user-primary">
<tbody>
<tr>
<td align="left" width="200"><b>Title</b></td>
<td align="right">{title}</td>
</tr>
<tr>
<td><b>Created</b></td>
<td align="right">{DTC}{createdAt}{/DTC}</td>
</tr>
<tr>
<td align="center" colspan="2"><b>Description</b></td>
</tr>
<tr>
<td colspan="2">{description}</td>
</tr>
<tr>
<td><b>TimeZone</b></td>
<td align="right">{timezone}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="panel-footer">
<a href="{ROOT_URL}calendar/deleteCalendar/{ID}" class="btn btn-md btn-danger" role="button">Delete</a>
<a href="{ROOT_URL}calendar/editCalendar/{ID}" class="btn btn-md btn-warning" role="button">Edit</a>
<a href="{ROOT_URL}calendar/byMonth/{ID}" class="btn btn-md btn-primary" role="button">View Events</a>
</div>
</div>
</div>
</div>

View File

@ -1,20 +0,0 @@
<div class="form-group">
<label for="day" class="col-lg-3 control-label">All-Day Event</label>
<div class="col-lg-3">
<input class="" type="checkbox" name="allDay" id="allDay" value="true" {CHECKED:allDay=true}>
</div>
</div>
<div class="form-group">
<label for="month" class="col-lg-3 control-label">Event Start</label>
<div class="col-lg-3">
<input type="date" name="date" id="date" class="form-control" value="{date}" />
<input type="time" name="time" id="time" class="form-control" value="{time}" />
</div>
</div>
<div class="form-group">
<label for="month" class="col-lg-3 control-label">Event End</label>
<div class="col-lg-3">
<input type="date" name="endDate" id="endDate" class="form-control" value="{endDate}" />
<input type="time" name="endTime" id="endTime" class="form-control" value="{endTime}" />
</div>
</div>

View File

@ -1,37 +0,0 @@
<legend>Create Event</legend>
<form action="" method="post" class="form-horizontal">
<input type="hidden" name="token" value="{TOKEN}">
{calendarSelect}
<div class="form-group">
<label for="title" class="col-lg-3 control-label">Title</label>
<div class="col-lg-3">
<input type="text" class="form-control" name="title" id="title">
</div>
</div>
<div class="form-group">
<label for="description" class="col-lg-3 control-label">Description</label>
<div class="col-lg-3">
<textarea class="form-control" name="description" maxlength="2000" rows="6" cols="30" id="description"></textarea>
</div>
</div>
<div class="form-group">
<label for="location" class="col-lg-3 control-label">Location</label>
<div class="col-lg-3">
<input type="text" class="form-control" name="location" id="location">
</div>
</div>
<div class="form-group">
<label for="color" class="col-lg-3 control-label">Event Color</label>
<div class="col-lg-3 select-container" id="colorContainer">
{colorSelect}
</div>
</div>
{dateSelect}
{repeatSelect}
<div class="form-group">
<label for="submit" class="col-lg-3 control-label"></label>
<div class="col-lg-3">
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Submit</button>
</div>
</div>
</form>

View File

@ -1,31 +0,0 @@
<legend>Edit Event</legend>
<form action="" method="post" class="form-horizontal">
<div class="form-group">
<label for="title" class="col-lg-3 control-label">Title</label>
<div class="col-lg-3">
<input type="text" class="form-control" name="title" id="title" value="{title}">
</div>
</div>
<div class="form-group">
<label for="description" class="col-lg-3 control-label">Description</label>
<div class="col-lg-6">
<textarea class="form-control" name="description" maxlength="2000" rows="10" cols="50" id="description">{description}</textarea>
</div>
</div>
<div class="form-group">
<label for="location" class="col-lg-3 control-label">Location</label>
<div class="col-lg-6">
<input type="text" class="form-control" name="location" id="location" value="{location}">
</div>
</div>
<div class="form-group">
<label for="color" class="col-lg-3 control-label">Event Color</label>
<div class="col-lg-3 select-container" id="colorContainer">
{colorSelect}
</div>
</div>
{dateSelect}
{repeatSelect}
<input type="hidden" name="token" value="{TOKEN}">
<button name="submit" value="submit" type="submit" class="btn btn-lg btn-primary center-block">Submit</button>
</form>

View File

@ -1,34 +0,0 @@
{PAGINATION}
<table class="table table-striped">
<thead>
<tr>
<th style="width: 10%">ID</th>
<th style="width: 20%">Time</th>
<th style="width: 40%">Title</th>
<th style="width: 10%"></th>
<th style="width: 10%"></th>
<th style="width: 10%"></th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td style="text-align: center;">{ID}</td>
<td style="text-align: center;">{DTC}{event_time}{/DTC}</td>
<td style="text-align: center;">{title}</td>
<td><a href="{ROOT_URL}calendar/event/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-open"></i></a></td>
<td><a href="{ROOT_URL}calendar/editEvent/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
<td><a href="{ROOT_URL}calendar/deleteEvent/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
</tr>
{/LOOP}
{ALT}
<tr>
<td style="text-align: center;" colspan="6">
No results to show.
</td>
</tr>
{/ALT}
</tbody>
</table>
{PAGINATION}
<a href="{ROOT_URL}calendar/createEvent" class="btn btn-sm btn-primary" role="button">Create</a>

View File

@ -1,52 +0,0 @@
<div class="container col-md-4 col-lg-4">
<div class="row">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Event</h3>
</div>
<div class="panel-body">
<div class="row">
<table class="table table-user-primary">
<tbody>
<tr>
<td style="text-align: left;" width="200"><b>Title</b></td>
<td style="text-align: right;">{title}</td>
</tr>
<tr>
<td><b>Created</b></td>
<td style="text-align: right;">{DTC}{createdAt}{/DTC}</td>
</tr>
<tr>
<td><b>Event Time</b></td>
<td style="text-align: right;">{DTC}{event_time}{/DTC}</td>
</tr>
<tr>
<td style="text-align: center;" colspan="2"><b>Description</b></td>
</tr>
<tr>
<td colspan="2">{description}</td>
</tr>
<tr>
<td><b>Location</b></td>
<td style="text-align: right;">{location}</td>
</tr>
<tr>
<td><b>Frequency</b></td>
<td style="text-align: right;">{repeatsText}</td>
</tr>
<tr>
<td><b>Calendar</b></td>
<td style="text-align: right;">{calendarName}</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="panel-footer">
<a href="{ROOT_URL}calendar/deleteEvent/{ID}" class="btn btn-md btn-danger" role="button">Delete</a>
<a href="{ROOT_URL}calendar/editEvent/{ID}" class="btn btn-md btn-warning" role="button">Edit</a>
<a href="{ROOT_URL}calendar/byMonth/{calendar_id}" class="btn btn-md btn-primary" role="button">View Events</a>
</div>
</div>
</div>
</div>

View File

@ -1,16 +0,0 @@
<li class="pull-right dropdown">
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Calendars <span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="{ROOT_URL}calendar/{currentView}/">All</a></li>
<li role="separator" class="divider"></li>
{LOOP}
<li><a href="{ROOT_URL}calendar/{currentView}/{ID}">{title}</a></li>
{/LOOP}
<li role="separator" class="divider"></li>
<li><a href="{ROOT_URL}calendar/createCalendar">Create Calendar</a></li>
<li><a href="{ROOT_URL}calendar/editCalendar/{calendarID}">Edit Calendar</a></li>
<li><a href="{ROOT_URL}calendar/deleteCalendar/{calendarID}">Delete Calendar</a></li>
</ul>
</li>

View File

@ -1,23 +0,0 @@
<ul class="list-group">
{LOOP}
<li class="list-group-item btn-{displayColor}">
<p style="text-align: center;">{title}</p>
<p style="text-align: center;">{DTC}{event_time}{/DTC}</p>
<p>
<a href="{ROOT_URL}calendar/event/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-open"></i></a>
<a href="{ROOT_URL}calendar/editEvent/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a>
<a href="{ROOT_URL}calendar/deleteEvent/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a>
</p>
</li>
{/LOOP}
{ALT}
<li class="list-group-item">
<br />
<br />
<br />
<br />
<br />
</li>
{/ALT}
<a href="{ROOT_URL}calendar/createEvent?calendar_id={calendarID}&month={currentMonth}&day={currentDay}" class="list-group-item list-group-item-success"><i class="glyphicon glyphicon-plus"></i></a>
</ul>

View File

@ -1,18 +0,0 @@
<ul class="nav nav-pills">
<li class="dropdown pull-right">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Switch Date <span class="caret"></span>
</button>
<ul class="dropdown-menu">
<form action="" method="post" class="form-horizontal">
<li><input type="date" name="date" id="date" class="form-control" value="{date}" /></li>
<li role="separator" class="divider"></li>
<li>
<button name="submit" value="submit" type="submit" class="btn btn-primary center-block">
Select Date
</button>
</li>
</form>
</ul>
</li>
</ul>

View File

@ -1,12 +0,0 @@
<span class="hour-body">
{LOOP}
<div class="hour-cell btn-{displayColor}">
<p class="event-title">{title}</p>
<a href="{ROOT_URL}calendar/event/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-open"></i></a>
<a href="{ROOT_URL}calendar/editEvent/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a>
<a href="{ROOT_URL}calendar/deleteEvent/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a>
</div>
{/LOOP}
{ALT}
{/ALT}
</span>

View File

@ -1,8 +0,0 @@
<ul class="nav nav-tabs">
<li><a href="{ROOT_URL}calendar/byDay/{calendarID}">Daily</a></li>
<li><a href="{ROOT_URL}calendar/byWeek/{calendarID}">Weekly</a></li>
<li><a href="{ROOT_URL}calendar/byMonth/{calendarID}">Monthly</a></li>
<li><a href="{ROOT_URL}calendar/byYear/{calendarID}">Yearly</a></li>
<li><a href="{ROOT_URL}calendar/events/{calendarID}">Events</a></li>
{calendarDropdown}
</ul>

View File

@ -1,9 +0,0 @@
<div class="row calendar-row">
{LOOP}
<div class="col-xs-1 calendar-cell">
<h4 class="{highlightedDate}">{day}</h4>{dayEventList}
</div>
{/LOOP}
{ALT}
{/ALT}
</div>

View File

@ -1,37 +0,0 @@
<?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() );
}
}

View File

@ -1,45 +0,0 @@
<?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 )]);
}
}

View File

@ -1,191 +0,0 @@
<?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\Bin\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);
}
}
}

View File

@ -1,116 +0,0 @@
* {
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;
}

View File

@ -1,52 +0,0 @@
<?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;

View File

@ -1,116 +0,0 @@
$(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);
// }
});

View File

@ -1,145 +0,0 @@
<?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\Bin\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() );
}
}

Some files were not shown because too many files have changed in this diff Show More