Initial commit

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

View File

@ -0,0 +1,62 @@
<?php
/**
* app/plugins/todo/controllers/tasts.php
*
* This is the task lists' API controller.
*
* @package TP ToDo
* @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\Tasklists as ListModel;
use TheTempusProject\Classes\ApiController;
use TheTempusProject\Houdini\Classes\Views;
class Lists extends ApiController {
protected static $lists;
public function __construct() {
parent::__construct();
self::$lists = new ListModel;
}
public function hide( $id = null ) {
$list = self::$lists->get( $id );
if ( ! $list ) {
$responseType = 'error';
$response = 'No list found.';
} else {
$responseType = 'data';
$response = self::$lists->hide( $id );
}
Views::view( 'api.response', ['response' => json_encode( [ $responseType => $response ], true )]);
}
public function delete( $id = null ) {
$list = self::$lists->get( $id );
if ( ! $list ) {
$responseType = 'error';
$response = 'No list found.';
} else {
$responseType = 'data';
$response = self::$lists->delete( $id );
}
Views::view( 'api.response', ['response' => json_encode( [ $responseType => $response ], true )]);
}
public function home( $id = null ) {
$list = self::$lists->get( $id );
if ( ! $list ) {
$responseType = 'error';
$response = 'No list found.';
} else {
$responseType = 'data';
$response = $list;
}
Views::view( 'api.response', ['response' => json_encode( [ $responseType => $response ], true )]);
}
}

View File

@ -0,0 +1,62 @@
<?php
/**
* app/plugins/todo/controllers/tasts.php
*
* This is the tasks' API controller.
*
* @package TP ToDo
* @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\Tasks as TaskModel;
use TheTempusProject\Classes\ApiController;
use TheTempusProject\Houdini\Classes\Views;
class Tasks extends ApiController {
protected static $tasks;
public function __construct() {
parent::__construct();
self::$tasks = new TaskModel;
}
public function complete( $id = null ) {
$task = self::$tasks->get( $id );
if ( ! $task ) {
$responseType = 'error';
$response = 'No task found.';
} else {
$responseType = 'data';
$response = self::$tasks->complete( $id );
}
Views::view( 'api.response', ['response' => json_encode( [ $responseType => $response ], true )]);
}
public function delete( $id = null ) {
$task = self::$tasks->get( $id );
if ( ! $task ) {
$responseType = 'error';
$response = 'No task found.';
} else {
$responseType = 'data';
$response = self::$tasks->delete( $id );
}
Views::view( 'api.response', ['response' => json_encode( [ $responseType => $response ], true )]);
}
public function home( $id = null ) {
$task = self::$tasks->get( $id );
if ( ! $task ) {
$responseType = 'error';
$response = 'No task found.';
} else {
$responseType = 'data';
$response = $task;
}
Views::view( 'api.response', ['response' => json_encode( [ $responseType => $response ], true )]);
}
}

View File

@ -0,0 +1,371 @@
<?php
/**
* app/plugins/todo/controllers/todo.php
*
* This is the todo controller.
*
* @package TP ToDo
* @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\Hermes\Functions\Redirect;
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\Houdini\Classes\Forms as FormBuilder;
use TheTempusProject\Models\Tasks;
use TheTempusProject\Models\Tasklists;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Houdini\Classes\Components;
use TheTempusProject\Classes\Config;
use TheTempusProject\Houdini\Classes\Navigation;
use TheTempusProject\Houdini\Classes\Template;
class Todo extends Controller {
protected static $tasks;
protected static $lists;
protected static $showHidden;
protected static $listView;
public function __construct() {
parent::__construct();
if ( !App::$isLoggedIn ) {
Session::flash( 'notice', 'You must be logged in to use this feature.' );
return Redirect::home();
}
self::$tasks = new Tasks;
self::$lists = new Tasklists;
self::$title = 'To-Do - {SITENAME}';
self::$pageDescription = 'On this page you can create and manage tasks and lists.';
if ( Input::exists('includeCompleted') && 'true' == Input::get('includeCompleted') ) {
self::$showHidden = true;
Components::set( 'completedToggleText', 'Hide' );
Components::set( 'completedToggle', 'false' );
} else {
self::$showHidden = false;
Components::set( 'completedToggleText', 'Show' );
Components::set( 'completedToggle', 'true' );
}
$taskTabs = Views::simpleView( 'todo.nav.listTabs' );
if ( stripos( Input::get('url'), 'todo/list' ) !== false ) {
$tabsView = Navigation::activePageSelect( $taskTabs, '/todo/list/', false, true );
$userListTabs = Views::simpleView('todo.nav.userListTabs', self::$lists->simpleObjectByUser(true) );
$userListTabsView = Navigation::activePageSelect( $userListTabs, Input::get( 'url' ), false, true );
} else {
$tabsView = Navigation::activePageSelect( $taskTabs, Input::get( 'url' ), false, true );
$userListTabsView = '';
}
Components::set( 'userListTabs', $userListTabsView );
Views::raw( $tabsView );
}
public function index() {
Components::set( 'listName', 'All' );
Components::set( 'listID', '' );
$recentlyCompleted = Views::simpleView( 'todo.tasks.list', self::$tasks->recentlyCompleted( 10 ) );
Components::set( 'recentlyCompleted', $recentlyCompleted );
$dailyTasks = Views::simpleView( 'todo.tasks.daily', self::$tasks->dailyTasks( 10 ) );
Components::set( 'dailyTasks', $dailyTasks );
$weeklyTasks = Views::simpleView( 'todo.tasks.weekly', self::$tasks->weeklyTasks( 10 ) );
Components::set( 'weeklyTasks', $weeklyTasks );
$monthlyTasks = Views::simpleView( 'todo.tasks.monthly', self::$tasks->monthlyTasks( 10 ) );
Components::set( 'monthlyTasks', $monthlyTasks );
$yearlyTasks = Views::simpleView( 'todo.tasks.yearly', self::$tasks->yearlyTasks( 10 ) );
Components::set( 'yearlyTasks', $yearlyTasks );
$tasks = Views::simpleView( 'todo.tasks.list', self::$tasks->recent( 10 ) );
Components::set( 'taskList', $tasks );
$lists = Views::simpleView( 'todo.lists.list', self::$lists->recent() );
Components::set( 'listList', $lists );
Views::view( 'todo.dashboard' );
}
public function daily() {
Views::view( 'todo.tasks.daily', self::$tasks->dailyTasks( 10, self::$showHidden ) );
}
public function weekly() {
Views::view( 'todo.tasks.weekly', self::$tasks->weeklyTasks( 10, self::$showHidden ) );
}
public function monthly() {
Views::view( 'todo.tasks.monthly', self::$tasks->monthlyTasks( 10, self::$showHidden ) );
}
public function yearly() {
Views::view( 'todo.tasks.yearly', self::$tasks->yearlyTasks( 10, self::$showHidden ) );
}
/**
* Lists
*/
public function list( $id = 0 ) {
$list = self::$lists->findById( $id );
if ( $list == false ) {
$lists = self::$lists->recent();
return Views::view( 'todo.lists.list', $lists );
}
Components::set( 'listID', $id );
if ( Input::exists('includeCompleted') && 'true' == Input::get('includeCompleted') ) {
$include_completed = true;
} else {
$include_completed = false;
}
$tasks = self::$tasks->findByListId( $id, $include_completed );
Components::set( 'listName', $list->title );
Components::set( 'CONTENT_ID', $id );
Components::set( 'COMMENT_TYPE', 'tasklist' );
Views::view( 'todo.tasks.list', $tasks );
}
public function createList() {
if ( !Input::exists() ) {
return Views::view( 'todo.lists.create' );
}
if ( !Forms::check( 'createTaskList' ) ) {
Issues::add( 'error', [ 'There was an error creating your task list.' => Check::userErrors() ] );
return Views::view( 'todo.lists.create' );
}
if ( !self::$lists->create( Input::post( 'listName' )) ) {
Issues::add( 'error', [ 'There was an error creating your task list.' => Check::userErrors() ] );
return Views::view( 'todo.lists.create' );
}
Session::flash( 'success', 'Your Task List has been created.' );
Redirect::to( 'todo/index' );
}
public function editList( $id = null ) {
$list = self::$lists->findById( $id );
if ( $list == false ) {
Issues::add( 'error', 'TaskList not found.' );
return $this->index();
}
if ( !Input::exists() ) {
return Views::view( 'todo.lists.edit', $list );
}
if ( !Forms::check( 'editTaskList' ) ) {
Issues::add( 'error', [ 'There was an error with your todo task.' => Check::userErrors() ] );
return Views::view( 'todo.lists.edit', $list );
}
if ( !self::$lists->update( $id, Input::post( 'listName' ) ) ) {
Issues::add( 'error', [ 'There was an error with your todo task.' => Check::userErrors() ] );
return Views::view( 'todo.lists.edit', $list );
}
Session::flash( 'success', 'Your Task List has been saved.' );
Redirect::to( 'todo/list/' . $id );
}
public function deleteList( $id = null ) {
$list = self::$lists->findById( $id );
if ( $list == false ) {
Issues::add( 'error', 'TaskList not found.' );
return $this->index();
}
if ( $list->createdBy != App::$activeUser->ID ) {
Issues::add( 'error', 'You do not have permission to modify this calendar.' );
return $this->index();
}
$result = self::$lists->delete( $id );
if ( !$result ) {
Issues::add( 'error', 'There was an error deleting the list(s)' );
} else {
Issues::add( 'success', 'List deleted' );
}
return $this->index();
}
/**
* Tasks
*/
public function task( $id = null ) {
$task = self::$tasks->findById( $id );
if ( $task == false ) {
$tasks = self::$tasks->recent();
return Views::view( 'todo.tasks.list', $tasks );
}
Components::set( 'CONTENT_ID', $id );
Components::set( 'COMMENT_TYPE', 'task' );
Views::view( 'todo.tasks.view', $task );
}
public function createTask( $id = null ) {
if ( in_array( $id, self::$tasks->repeatOptions ) ) {
$repeat = $id;
$id = 'non';
} else {
$repeat = 'none';
$id = $id;
}
// @todo need to make this change if it 'id' is actually a repeats value
$select = FormBuilder::getFormFieldHtml(
'listID',
'Task List',
'select',
$id,
self::$lists->getSimpleList(true),
);
Components::set( 'listSelect', $select );
$repeatSelect = FormBuilder::getFormFieldHtml( 'repeats', 'Frequency', 'select', $repeat, self::$tasks->repeatOptions );
Components::set( 'repeatSelect', $repeatSelect );
if ( !Input::exists() ) {
return Views::view( 'todo.tasks.create' );
}
if ( !Forms::check( 'createTask' ) ) {
Issues::add( 'error', [ 'There was an error with your form.' => Check::userErrors() ] );
return Views::view( 'todo.tasks.create' );
}
if ( !self::$tasks->create( Input::post( 'task' ), 'false', Input::post( 'dueDate' ), Input::post( 'listID' ), Input::post( 'repeats' ) ) ) {
Issues::add( 'error', [ 'There was an error with your todo task.' => Check::userErrors() ] );
return Views::view( 'todo.tasks.create' );
}
Session::flash( 'success', 'Your Task has been created.' );
if ( Input::exists( 'listID' ) ) {
Redirect::to( 'todo/list/' . Input::post( 'listID' ) );
} else {
Redirect::to( 'todo/index' );
}
}
public function editTask( $id = null ) {
$task = self::$tasks->findById( $id );
if ( $task == false ) {
Issues::add( 'error', 'Task not found.' );
return $this->index();
}
if ( $task->createdBy != App::$activeUser->ID ) {
Issues::add( 'error', 'You do not have permission to modify this task.' );
return $this->index();
}
$select = FormBuilder::getFormFieldHtml(
'listID',
'Task List',
'select',
$task->listID,
self::$lists->getSimpleList(true),
);
Components::set( 'listSelect', $select );
$repeatSelect = FormBuilder::getFormFieldHtml( 'repeats', 'Frequency', 'select', $task->repeats, self::$tasks->repeatOptions );
Components::set( 'repeatSelect', $repeatSelect );
if ( !Input::exists( 'submit' ) ) {
return Views::view( 'todo.tasks.edit', $task );
}
if ( !Forms::check( 'editTask' ) ) {
Issues::add( 'error', [ 'There was an error with your request.' => Check::userErrors() ] );
return Views::view( 'todo.tasks.edit', $task );
}
if ( self::$tasks->update( $id, Input::post( 'task' ), $task->completed, Input::post( 'dueDate' ), Input::post( 'listID' ), Input::post( 'repeats' ) ) ) {
Session::flash( 'success', 'Task updated' );
} else {
return Views::view( 'todo.tasks.edit', self::$tasks->findById( $data ) );
}
if ( !empty( $task->listID ) ) {
Redirect::to( 'todo/list/' . $task->listID );
} else {
Redirect::to( 'todo/index' );
}
}
public function deleteTask( $id = null ) {
$task = self::$tasks->findById( $id );
if ( $task == false ) {
Issues::add( 'error', 'Task not found.' );
return $this->index();
}
if ( $task->createdBy != App::$activeUser->ID ) {
Issues::add( 'error', 'You do not have permission to modify this task.' );
return $this->index();
}
$result = self::$tasks->delete( $id );
if ( !$result ) {
Session::flash( 'error', 'There was an error deleting the task(s)' );
} else {
Session::flash( 'success', 'Task deleted' );
}
if ( !empty( $task->listID ) ) {
Redirect::to( 'todo/list/' . $task->listID );
} else {
Redirect::to( 'todo/index' );
}
}
public function duplicateTask( $id = null ) {
$task = self::$tasks->findById( $id );
if ( $task == false ) {
Issues::add( 'error', 'Task not found.' );
return $this->index();
}
if ( $task->createdBy != App::$activeUser->ID ) {
Issues::add( 'error', 'You do not have permission to modify this task.' );
return $this->index();
}
if ( $task->repeats != 'none' ) {
Issues::add( 'error', 'You cannot duplicate a repeating task.' );
return $this->index();
}
if ( ! self::$tasks->duplicate( $id ) ) {
Session::flash( 'error', [ 'There was an error duplicating your todo task.'] );
} else {
Session::flash( 'success', 'Your Task has been duplicated.' );
}
if ( !empty( $task->listID ) ) {
Redirect::to( 'todo/list/' . $task->listID );
} else {
Redirect::to( 'todo/index' );
}
}
public function completeTask( $id = null ) {
$task = self::$tasks->findById( $id );
if ( $task == false ) {
Issues::add( 'error', 'Task not found.' );
return $this->index();
}
if ( $task->createdBy != App::$activeUser->ID ) {
Issues::add( 'error', 'You do not have permission to modify this task.' );
return $this->index();
}
$result = self::$tasks->complete( $id );
if ( !$result ) {
Session::flash( 'error', 'There was an error completing the task(s)' );
} else {
Session::flash( 'success', 'Task completed' );
}
if ( !empty( $task->listID ) ) {
Redirect::to( 'todo/list/' . $task->listID );
} else {
Redirect::to( 'todo/index' );
}
}
public function incompleteTask( $id = null ) {
$task = self::$tasks->findById( $id );
if ( $task == false ) {
Issues::add( 'error', 'Task not found.' );
return $this->index();
}
if ( $task->createdBy != App::$activeUser->ID ) {
Issues::add( 'error', 'You do not have permission to modify this task.' );
return $this->index();
}
$result = self::$tasks->incomplete( $id );
if ( ! $result ) {
Session::flash( 'error', 'There was an error un-completing the task(s)' );
} else {
Session::flash( 'success', 'Task un-completed' );
}
if ( !empty( $task->listID ) ) {
Redirect::to( 'todo/list/' . $task->listID );
} else {
Redirect::to( 'todo/index' );
}
}
}

View File

@ -0,0 +1,96 @@
<?php
/**
* app/plugins/bugtracker/forms.php
*
* This houses all of the form checking functions for this plugin.
*
* @package TP ToDo
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Plugins\Todo;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\Classes\Forms;
class TodoForms extends Forms {
/**
* Adds these functions to the form list.
*/
public function __construct() {
self::addHandler( 'createTask', __CLASS__, 'createTask' );
self::addHandler( 'editTask', __CLASS__, 'editTask' );
self::addHandler( 'createTaskList', __CLASS__, 'createTaskList' );
self::addHandler( 'editTaskList', __CLASS__, 'editTaskList' );
}
/**
* Validates the bug tracker create form.
*
* @return {bool}
*/
public static function createTask() {
if ( ! empty(Input::post( 'dueDate' )) && !self::date( Input::post( 'dueDate' ) ) ) {
self::addUserError( 'Invalid Date.' . Input::post( 'dueDate' ) );
return false;
}
if ( ! empty( Input::post( 'listID' ) ) && !self::id( Input::post( 'listID' ) ) ) {
self::addUserError( 'Invalid Date.' . Input::post( 'dueDate' ) );
return false;
}
if ( !Input::exists( 'task' ) ) {
self::addUserError( 'You must specify a task' );
return false;
}
// if ( !self::token() ) {
// return false;
// }
return true;
}
public static function createTaskList() {
if ( !Input::exists( 'listName' ) ) {
self::addUserError( 'You must specify a title' );
return false;
}
// if ( !self::token() ) {
// return false;
// }
return true;
}
public static function editTaskList() {
if ( !Input::exists( 'listName' ) ) {
self::addUserError( 'You must specify a title' );
return false;
}
// if ( !self::token() ) {
// return false;
// }
return true;
}
/**
* Validates the bug tracker create form.
*
* @return {bool}
*/
public static function editTask() {
if ( !empty(Input::post( 'dueDate' )) && !self::date( Input::post( 'dueDate' ) ) ) {
self::addUserError( 'Invalid Date.' . Input::post( 'dueDate' ) );
return false;
}
if ( !Input::exists( 'task' ) ) {
self::addUserError( 'You must specify a task' );
return false;
}
// if ( !self::token() ) {
// return false;
// }
return true;
}
}
new TodoForms;

View File

@ -0,0 +1,199 @@
<?php
/**
* app/plugins/todo/models/todo.php
*
* This class is used for the manipulation of the tasks database table.
*
* @package TP ToDo
* @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\Canary as Debug;
use TheTempusProject\Bedrock\Classes\CustomException;
use TheTempusProject\Classes\DatabaseModel;
use TheTempusProject\Plugins\Bugreport as Plugin;
use TheTempusProject\TheTempusProject as App;
class Tasklists extends DatabaseModel {
public $tableName = 'tasklists';
public $databaseMatrix = [
[ 'title', 'varchar', '128' ],
[ 'active', 'varchar', '5' ],
[ 'createdAt', 'int', '10' ],
[ 'color', 'varchar', '48' ],
[ 'createdBy', 'int', '11' ],
];
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->createdBy );
$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( $title, $active = 'true' ) {
if ( !$this->plugin->checkEnabled() ) {
Debug::info( 'ToDo Plugin is disabled in the config.' );
return false;
}
$fields = [
'createdBy' => App::$activeUser->ID,
'createdAt' => time(),
'title' => $title,
'active' => $active,
];
if ( !self::$db->insert( $this->tableName, $fields ) ) {
new CustomException( $this->tableName );
return false;
}
return self::$db->lastId();
}
public function update( $ID, $title, $active = 'true' ) {
if ( !$this->plugin->checkEnabled() ) {
Debug::info( 'ToDo Plugin is disabled in the config.' );
return false;
}
if ( !Check::id( $ID ) ) {
Debug::info( 'ToDo List: illegal ID.' );
return false;
}
$data = $this->findById( $ID );
if ( $data == false ) {
Debug::info( 'ToDo List: not found.' );
return false;
}
$fields = [
'title' => $title,
'active' => $active,
];
if ( !self::$db->update( $this->tableName, $ID, $fields ) ) {
new CustomException( $this->tableName );
Debug::error( "ToDo List: $ID not updated: $fields" );
return false;
}
return true;
}
public function activate( $ID ) {
if ( !Check::id( $ID ) ) {
Debug::info( 'TaskList: illegal ID.' );
return false;
}
$fields = [
'active' => 'true',
];
if ( !self::$db->update( $this->tableName, $ID, $fields ) ) {
new CustomException( $this->tableName );
Debug::error( "TaskList: $ID not activated: $fields" );
return false;
}
return true;
}
public function hide( $ID ) {
if ( !Check::id( $ID ) ) {
Debug::info( 'TaskList: illegal ID.' );
return false;
}
$fields = [
'active' => 'false',
];
if ( !self::$db->update( $this->tableName, $ID, $fields ) ) {
new CustomException( $this->tableName );
Debug::error( "TaskList: $ID not Hidden: $fields" );
return false;
}
return true;
}
public function recent( $limit = null ) {
$where = ['createdBy', '=', App::$activeUser->ID];
$data = self::$db->get( $this->tableName, $where, 'createdAt', 'DESC', [0, $limit] );
if ( !$data->count() ) {
Debug::info( 'No tasks found.' );
return [];
}
return $this->filter( $data->results() );
}
public function getSimpleList( $includeDefault = false ) {
$out = [];
if ( $includeDefault === true ) {
$out[ 'No List' ] = 0;
}
$lists = self::$db->get( $this->tableName, [ 'createdBy', '=', App::$activeUser->ID ] );
if ( !$lists->count() ) {
Debug::warn( 'Could not find any ' . $this->tableName );
return $out;
}
$taskLists = $lists->results();
foreach ( $taskLists as &$list ) {
$out[ $list->title ] = $list->ID;
}
return $out;
}
public function simpleObjectByUser() {
$whereClause = ['createdBy', '=', App::$activeUser->ID];
$lists = self::$db->get( $this->tableName, $whereClause );
if ( !$lists->count() ) {
Debug::warn( 'Could not find any tasklists' );
return false;
}
$taskLists = $lists->results();
$out = [];
foreach ( $taskLists as &$list ) {
$obj = new \stdClass();
$obj->title = $list->title;
$obj->ID = $list->ID;
$out[] = $obj;
}
return $out;
}
}

View File

@ -0,0 +1,392 @@
<?php
/**
* app/plugins/todo/models/todo.php
*
* This class is used for the manipulation of the tasks database table.
*
* @package TP ToDo
* @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\Canary as Debug;
use TheTempusProject\Bedrock\Classes\CustomException;
use TheTempusProject\Classes\DatabaseModel;
use TheTempusProject\Plugins\Bugreport as Plugin;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Bedrock\Functions\Date;
use TheTempusProject\Houdini\Classes\Template;
class Tasks extends DatabaseModel {
public $tableName = 'tasks';
public $databaseMatrix = [
[ 'task', 'varchar', '128' ],
[ 'completed', 'varchar', '5' ],
[ 'completedAt', 'int', '10' ],
[ 'completedBy', 'int', '10' ],
[ 'dueDate', 'int', '10' ],
[ 'createdAt', 'int', '10' ],
[ 'createdBy', 'int', '11' ],
[ 'listID', 'int', '11' ],
[ 'color', 'varchar', '48' ],
[ 'parentID', 'int', '11' ],
[ 'repeats', 'varchar', '48' ],
];
public $plugin;
public $repeatOptions = [
'Does Not Repeat' => 'none',
'Every Day' => 'daily',
'Every Week' => 'weekly',
'Every Month' => 'monthly',
'Every Year' => 'yearly',
];
public function __construct() {
parent::__construct();
$this->plugin = new Plugin;
}
public function filter( $data, $params = [] ) {
foreach ( $data as $instance ) {
if ( !is_object( $instance ) ) {
$instance = $data;
$end = true;
}
if ( 'true' == $instance->completed ) {
$url = Template::parse(
'<a href="{ROOT_URL}todo/incompleteTask/'.$instance->ID.'" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-remove"></i></a>'
);
$instance->completedUrl = $url;
} else {
$url = Template::parse(
'<a href="{ROOT_URL}todo/completeTask/'.$instance->ID.'" class="btn btn-sm btn-success" role="button"><i class="glyphicon glyphicon-ok"></i></a>'
);
$instance->completedUrl = $url;
}
$out[] = $instance;
if ( !empty( $end ) ) {
$out = $out[0];
break;
}
}
return $out;
}
public function create( $task, $completed = 'false', $dueDate = null, $list = 0, $repeats = 'none') {
if ( !$this->plugin->checkEnabled() ) {
Debug::info( 'ToDo Plugin is disabled in the config.' );
return false;
}
$fields = [
'task' => $task,
'completed' => $completed,
'listID' => intval($list),
'repeats' => $repeats,
'createdBy' => App::$activeUser->ID,
'createdAt' => time(),
];
if ( !empty( $dueDate ) ) {
$fields['dueDate'] = strtotime($dueDate);
}
if ( 'false' !== $completed ) {
$fields['completedBy'] = App::$activeUser->ID;
$fields['completedAt'] = time();
} else {
$fields['completedAt'] = '0';
}
if ( !self::$db->insert( $this->tableName, $fields ) ) {
new CustomException( $this->tableName );
return false;
}
return self::$db->lastId();
}
public function update( $ID, $task, $completed = "false", $dueDate = null, $list = 0, $repeats = 'none' ) {
if ( !Check::id( $ID ) ) {
Debug::info( 'ToDo Task: illegal ID.' );
return false;
}
$data = $this->findById( $ID );
if ( $data == false ) {
Debug::info( 'ToDo Task: not found.' );
return false;
}
$fields = [
'task' => $task,
'completed' => $completed,
'listID' => intval($list),
'repeats' => $repeats,
];
if ( !empty( $dueDate ) ) {
$fields['dueDate'] = strtotime($dueDate);
}
if ( 'false' !== $completed && 'false' === $data->completed ) {
$fields['completedBy'] = App::$activeUser->ID;
$fields['completedAt'] = time();
}
if ( !self::$db->update( $this->tableName, $ID, $fields ) ) {
new CustomException( $this->tableName );
Debug::error( "ToDo: $ID not updated: $fields" );
return false;
}
return true;
}
public function setActive( $ID ) {
if ( !Check::id( $ID ) ) {
Debug::info( 'ToDo Task: illegal ID.' );
return false;
}
$fields = [
'completed' => 'false',
'completedAt' => '0',
'completedBy' => null,
];
if ( !self::$db->update( $this->tableName, $ID, $fields ) ) {
new CustomException( $this->tableName );
Debug::error( "Task: $ID not Activated: $fields" );
return false;
}
return true;
}
public function recent( $limit = null, $include_completed = false ) {
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND', 'ID', '>', '0'];
if ( false == $include_completed ) {
$whereClause = array_merge( $whereClause, [
'AND', 'completed', '!=', 'true'
] );
}
if ( empty( $limit ) ) {
$data = self::$db->getPaginated( $this->tableName, $whereClause, 'createdAt', 'DESC' );
} else {
$data = self::$db->get( $this->tableName, $whereClause, 'createdAt', 'DESC', [0, $limit] );
}
if ( !$data->count() ) {
Debug::info( 'No tasks found.' );
return false;
}
return $this->filter( $data->results() );
}
public function recentlyCompleted( $limit = null ) {
$whereClause = ['createdBy', '=', App::$activeUser->ID, 'AND', 'completed', '=', 'true'];
if ( empty( $limit ) ) {
$data = self::$db->getPaginated( $this->tableName, $whereClause, 'completedAt', 'DESC' );
} else {
$data = self::$db->get( $this->tableName, $whereClause, 'completedAt', 'DESC', [0, $limit] );
}
if ( !$data->count() ) {
Debug::info( 'No tasks found.' );
return false;
}
return $this->filter( $data->results() );
}
public function dailyTasks( $limit = null, $include_completed = false ) {
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND', 'repeats', '=', 'daily' ];
if ( false == $include_completed ) {
$whereClause = array_merge( $whereClause, [
// 'AND', 'completedAt', '<', Date::getDayStartTimestamp( '1735736400000', true ),
'AND', 'completedAt', '<', Date::getDayStartTimestamp( time(), true ),
] );
}
if ( empty( $limit ) ) {
$data = self::$db->getPaginated( $this->tableName, $whereClause, 'createdAt', 'DESC' );
} else {
$data = self::$db->get( $this->tableName, $whereClause, 'createdAt', 'DESC', [0, $limit] );
}
if ( !$data->count() ) {
Debug::info( 'No tasks found.' );
return false;
}
return $this->filter( $data->results() );
}
public function weeklyTasks( $limit = null, $include_completed = false ) {
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND', 'repeats', '=', 'weekly' ];
if ( false == $include_completed ) {
$whereClause = array_merge( $whereClause, [
'AND', 'completedAt', '<', Date::getWeekStartTimestamp( time(), true ),
] );
}
if ( empty( $limit ) ) {
$data = self::$db->getPaginated( $this->tableName, $whereClause, 'createdAt', 'DESC' );
} else {
$data = self::$db->get( $this->tableName, $whereClause, 'createdAt', 'DESC', [0, $limit] );
}
if ( !$data->count() ) {
Debug::info( 'No tasks found.' );
return false;
}
return $this->filter( $data->results() );
}
public function monthlyTasks( $limit = null, $include_completed = false ) {
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND', 'repeats', '=', 'monthly' ];
if ( false == $include_completed ) {
$whereClause = array_merge( $whereClause, [
'AND', 'completedAt', '<', Date::getMonthStartTimestamp( time(), true ),
] );
}
if ( empty( $limit ) ) {
$data = self::$db->getPaginated( $this->tableName, $whereClause, 'createdAt', 'DESC' );
} else {
$data = self::$db->get( $this->tableName, $whereClause, 'createdAt', 'DESC', [0, $limit] );
}
if ( !$data->count() ) {
Debug::info( 'No tasks found.' );
return false;
}
return $this->filter( $data->results() );
}
public function yearlyTasks( $limit = null, $include_completed = false ) {
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND', 'repeats', '=', 'yearly' ];
if ( false == $include_completed ) {
$whereClause = array_merge( $whereClause, [
'AND', 'completedAt', '<', Date::getYearStartTimestamp( time(), true ),
] );
}
if ( empty( $limit ) ) {
$data = self::$db->getPaginated( $this->tableName, $whereClause, 'createdAt', 'DESC' );
} else {
$data = self::$db->get( $this->tableName, $whereClause, 'createdAt', 'DESC', [ 0, $limit ] );
}
if ( !$data->count() ) {
Debug::info( 'No tasks found.' );
return false;
}
return $this->filter( $data->results() );
}
public function findByListId( $id, $include_completed = false ) {
$data = [];
if ( !Check::id( $id ) ) {
Debug::warn( "$this->tableName findByListId: illegal ID: $id" );
return $data;
}
$whereClause = [ 'createdBy', '=', App::$activeUser->ID, 'AND' ];
$whereClause = array_merge( $whereClause, [
'listID', '=', $id,
] );
if ( false == $include_completed ) {
$whereClause = array_merge( $whereClause, [
'AND', 'completed', '!=', 'true'
] );
}
$tasks = self::$db->get( $this->tableName, $whereClause );
if ( ! $tasks->count() ) {
Debug::info( 'No ' . $this->tableName . ' data found.' );
return [];
}
return $this->filter( $tasks->results() );
}
public function duplicate( $ID, $completed = 'false' ) {
if ( ! Check::id( $ID ) ) {
Debug::info( 'ToDo Task: illegal ID.' );
return false;
}
$task = $this->findById( $ID );
if ( $task == false ) {
Debug::info( 'ToDo Task: not found.' );
return false;
}
return $this->create( $task->task, $completed, $task->dueDate, $task->listID );
}
public function complete( $ID ) {
if ( !Check::id( $ID ) ) {
Debug::info( 'ToDo Task: illegal ID.' );
return false;
}
$data = $this->findById( $ID );
if ( $data == false ) {
Debug::info( 'ToDo Task: not found.' );
return false;
}
if ( 'none' == $data->repeats ) {
$completed = 'true';
$completedBy = App::$activeUser->ID;
} else {
$completed = 'false';
$completedBy = $data->completedBy;
$this->duplicate( $data->ID, 'true' );
}
$fields = [
'completed' => $completed,
'completedAt' => time(),
'completedBy' => $completedBy,
];
if ( !self::$db->update( $this->tableName, $ID, $fields ) ) {
new CustomException( $this->tableName );
Debug::error( "Task: $ID not Completed: $fields" );
return false;
}
return true;
}
public function incomplete( $ID ) {
if ( !Check::id( $ID ) ) {
Debug::info( 'ToDo Task: illegal ID.' );
return false;
}
$data = $this->findById( $ID );
if ( $data == false ) {
Debug::info( 'ToDo Task: not found.' );
return false;
}
if ( 'none' != $data->repeats ) {
// this should not be possible as completing a repeating task duplicates it as a completed normal task
Debug::info( 'There was an error with your request' );
return false;
}
$fields = [
'completed' => 'false',
'completedAt' => '0',
'completedBy' => null,
];
if ( !self::$db->update( $this->tableName, $ID, $fields ) ) {
new CustomException( $this->tableName );
Debug::error( "Task: $ID not Completed: $fields" );
return false;
}
return true;
}
private function isTaskCompleted( $repeats, $completedAt ) {
if ( ! intval( $completedAt ) > 0 ) {
return false;
}
switch ($repeats) {
case 'none':
return true;
case 'daily':
$start = Date::getDayStartTimestamp( time(), true );
if ( $completedAt > $start ) {
return true;
}
return false;
case 'weekly':
$start = Date::getWeekStartTimestamp( time(), true );
if ( $completedAt > $start ) {
return true;
}
return false;
case 'monthly':
$start = Date::getMonthStartTimestamp( time(), true );
if ( $completedAt > $start ) {
return true;
}
return false;
case 'yearly':
$start = Date::getYearStartTimestamp( time(), true );
if ( $completedAt > $start ) {
return true;
}
return false;
default:
return true;
}
return false;
}
}

View File

@ -0,0 +1,41 @@
<?php
/**
* app/plugins/todo/plugin.php
*
* This houses all of the main plugin info and functionality.
*
* @package TP ToDo
* @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;
class Todo extends Plugin {
public $pluginName = 'TP ToDo';
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 to-do list.';
public $permissionMatrix = [
'createTas' => [
'pretty' => 'Can create todo items',
'default' => false,
],
'createList' => [
'pretty' => 'Can create todo lists',
'default' => false,
],
];
public $main_links = [
[
'text' => 'To-Do',
'url' => '{ROOT_URL}todo/index/',
'filter' => 'loggedin',
],
];
}

View File

@ -0,0 +1,36 @@
<button id="hideLists" class="btn btn-primary">Show/Hide Lists</button>
<button id="reorder" class="btn btn-primary">Reorder</button>
<div class="row">
<div class="col-xlg-6 col-lg-6 col-md-6 col-sm-6 col-xs-6">
<h3>Recently Completed</h3>
{recentlyCompleted}
</div>
<div class="col-xlg-6 col-lg-6 col-md-6 col-sm-6 col-xs-6">
<h3>Daily Tasks</h3>
{dailyTasks}
</div>
<div class="col-xlg-6 col-lg-6 col-md-6 col-sm-6 col-xs-6">
<h3>Weekly Tasks</h3>
{weeklyTasks}
</div>
</div>
<div class="row">
<div class="col-xlg-6 col-lg-6 col-md-6 col-sm-6 col-xs-6">
<h3>Monthly Tasks</h3>
{monthlyTasks}
</div>
<div class="col-xlg-6 col-lg-6 col-md-6 col-sm-6 col-xs-6">
<h3>Yearly Tasks</h3>
{yearlyTasks}
</div>
</div>
<div class="row">
<h3>Task Lists</h3>
<div class="col-xlg-6 col-lg-6 col-md-6 col-sm-6 col-xs-6">
{listList}
</div>
<h3>Recently Created Tasks</h3>
<div class="col-xlg-6 col-lg-6 col-md-6 col-sm-6 col-xs-6">
{taskList}
</div>
</div>

View File

@ -0,0 +1,19 @@
<legend>New Task List</legend>
{BREADCRUMB}
<form action="" method="post" class="form-horizontal">
<input type="hidden" name="token" value="{TOKEN}">
<fieldset>
<div class="form-group">
<label for="listName" class="col-lg-3 control-label">List Name:</label>
<div class="col-lg-3">
<input class="form-control" type="text" name="listName" id="listName">
</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">Create</button><br>
</div>
</div>
</fieldset>
</form>

View File

@ -0,0 +1,14 @@
<form action="" method="post" class="form-horizontal">
<legend>Edit Task List</legend>
{BREADCRUMB}
<fieldset>
<div class="form-group">
<label for="listName" class="col-lg-6 control-label">List Name:</label>
<div class="col-lg-2">
<input class="form-control" type="text" name="listName" id="listName" value="{title}">
</div>
</div>
</fieldset>
<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

@ -0,0 +1,32 @@
<div class="row" style="margin-top: 30px; margin-bottom: 50px;">
<form action="" method="post">
<table class="table table-striped">
<thead>
<tr>
<th style="width: 95%">List Name</th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td><a href='{ROOT_URL}todo/list/{ID}'>{title}</a></td>
<td><a href="{ROOT_URL}todo/list/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-open"></i></a></td>
<td><a href="{ROOT_URL}todo/editlist/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
<td><a href="{ROOT_URL}todo/deleteList/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
</tr>
{/LOOP}
{ALT}
<tr>
<td colspan="7">
No Task Lists
</td>
</tr>
{/ALT}
</tbody>
</table>
<a href="{ROOT_URL}todo/createlist" class="btn btn-sm btn-primary" role="button">New List</a>
</form>
</div>

View File

@ -0,0 +1,9 @@
<ul class="nav nav-tabs">
<li><a href="{ROOT_URL}todo/index/">Dashboard</a></li>
<li><a href="{ROOT_URL}todo/list/">Lists</a></li>
<li><a href="{ROOT_URL}todo/daily/">Daily</a></li>
<li><a href="{ROOT_URL}todo/weekly/">Weekly</a></li>
<li><a href="{ROOT_URL}todo/monthly/">Monthly</a></li>
<li><a href="{ROOT_URL}todo/yearly/">Yearly</a></li>
</ul>
{userListTabs}

View File

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

View File

@ -0,0 +1,25 @@
<legend>New Task</legend>
{BREADCRUMB}
<form action="" method="post" class="form-horizontal">
<input type="hidden" name="token" value="{TOKEN}">
{listSelect}
<div class="form-group">
<label for="task" class="col-lg-3 control-label">Task:</label>
<div class="col-lg-3">
<input class="form-control" type="text" name="task" id="task">
</div>
</div>
{repeatSelect}
<div class="form-group">
<label for="dueDate" class="col-lg-3 control-label">Due Date:</label>
<div class="col-lg-3">
<input class="form-control" type="date" name="dueDate" id="dueDate">
</div>
</div>
<div class="form-group">
<label for="dueDate" 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">Create</button>
</div>
</div>
</form>

View File

@ -0,0 +1,35 @@
<div class="row" style="margin-top: 30px; margin-bottom: 50px;">
<form action="" method="post">
<table class="table table-striped">
<thead>
<tr>
<th style="width: 60%">Task</th>
<th style="width: 20%">Due</th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td>{task}</td>
<td>{DTC}{dueDate}{/DTC}</td>
<td>{completedUrl}</td>
<td><a href="{ROOT_URL}todo/edittask/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
<td><a href="{ROOT_URL}todo/deleteTask/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
</tr>
{/LOOP}
{ALT}
<tr>
<td colspan="7">
No Tasks
</td>
</tr>
{/ALT}
</tbody>
</table>
<a href="{ROOT_URL}todo/createtask/daily" class="btn btn-sm btn-primary" role="button">New Task</a>
<a href="{ROOT_URL}todo/daily/?includeCompleted={completedToggle}" class="btn btn-sm btn-info" role="button">{completedToggleText} Completed</a>
</form>
</div>

View File

@ -0,0 +1,20 @@
<legend>Edit Task</legend>
{BREADCRUMB}
<form action="" method="post" class="form-horizontal">
{listSelect}
<div class="form-group">
<label for="task" class="col-lg-3 control-label">Task:</label>
<div class="col-lg-2">
<input class="form-control" type="text" name="task" id="task" value="{task}">
</div>
</div>
{repeatSelect}
<div class="form-group">
<label for="dueDate" class="col-lg-3 control-label">Due Date:</label>
<div class="col-lg-2">
<input class="form-control" type="date" name="dueDate" id="dueDate" value="{task}">
</div>
</div>
<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

@ -0,0 +1,37 @@
<div class="row" style="margin-top: 30px; margin-bottom: 50px;">
<form action="" method="post">
<table class="table table-striped">
<thead>
<tr>
<th style="width: 60%">Task</th>
<th style="width: 20%">Due</th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td>{task}</td>
<td>{DTC}{dueDate}{/DTC}</td>
<td>{completedUrl}</td>
<td><a href="{ROOT_URL}todo/duplicateTask/{ID}" class="btn btn-sm btn-primary" role="button"><i class="glyphicon glyphicon-copy"></i></a></td>
<td><a href="{ROOT_URL}todo/edittask/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
<td><a href="{ROOT_URL}todo/deleteTask/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
</tr>
{/LOOP}
{ALT}
<tr>
<td colspan="7">
No Tasks
</td>
</tr>
{/ALT}
</tbody>
</table>
<a href="{ROOT_URL}todo/createtask/{listID}" class="btn btn-sm btn-primary" role="button">New Task</a>
<a href="{ROOT_URL}todo/list/{listID}?includeCompleted={completedToggle}" class="btn btn-sm btn-info" role="button">{completedToggleText} Completed</a>
</form>
</div>

View File

@ -0,0 +1,35 @@
<div class="row" style="margin-top: 30px; margin-bottom: 50px;">
<form action="" method="post">
<table class="table table-striped">
<thead>
<tr>
<th style="width: 60%">Task</th>
<th style="width: 20%">Due</th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td>{task}</td>
<td>{DTC}{dueDate}{/DTC}</td>
<td><a href="{ROOT_URL}todo/completeTask/{ID}" class="btn btn-sm btn-success" role="button"><i class="glyphicon glyphicon-ok"></i></a></td>
<td><a href="{ROOT_URL}todo/edittask/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
<td><a href="{ROOT_URL}todo/deleteTask/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
</tr>
{/LOOP}
{ALT}
<tr>
<td colspan="7">
No Tasks
</td>
</tr>
{/ALT}
</tbody>
</table>
<a href="{ROOT_URL}todo/createtask/monthly" class="btn btn-sm btn-primary" role="button">New Task</a>
<a href="{ROOT_URL}todo/monthly/?includeCompleted={completedToggle}" class="btn btn-sm btn-info" role="button">{completedToggleText} Completed</a>
</form>
</div>

View File

@ -0,0 +1 @@
i don't think this file should ever really be reached normally

View File

@ -0,0 +1,35 @@
<div class="row" style="margin-top: 30px; margin-bottom: 50px;">
<form action="" method="post">
<table class="table table-striped">
<thead>
<tr>
<th style="width: 60%">Task</th>
<th style="width: 20%">Due</th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td>{task}</td>
<td>{DTC}{dueDate}{/DTC}</td>
<td><a href="{ROOT_URL}todo/completeTask/{ID}" class="btn btn-sm btn-success" role="button"><i class="glyphicon glyphicon-ok"></i></a></td>
<td><a href="{ROOT_URL}todo/edittask/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
<td><a href="{ROOT_URL}todo/deleteTask/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
</tr>
{/LOOP}
{ALT}
<tr>
<td colspan="7">
No Tasks
</td>
</tr>
{/ALT}
</tbody>
</table>
<a href="{ROOT_URL}todo/createtask/weekly" class="btn btn-sm btn-primary" role="button">New Task</a>
<a href="{ROOT_URL}todo/weekly/?includeCompleted={completedToggle}" class="btn btn-sm btn-info" role="button">{completedToggleText} Completed</a>
</form>
</div>

View File

@ -0,0 +1,35 @@
<div class="row" style="margin-top: 30px; margin-bottom: 50px;">
<form action="" method="post">
<table class="table table-striped">
<thead>
<tr>
<th style="width: 60%">Task</th>
<th style="width: 20%">Due</th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
<th style="width: 5%"></th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td>{task}</td>
<td>{DTC}{dueDate}{/DTC}</td>
<td><a href="{ROOT_URL}todo/completeTask/{ID}" class="btn btn-sm btn-success" role="button"><i class="glyphicon glyphicon-ok"></i></a></td>
<td><a href="{ROOT_URL}todo/edittask/{ID}" class="btn btn-sm btn-warning" role="button"><i class="glyphicon glyphicon-edit"></i></a></td>
<td><a href="{ROOT_URL}todo/deleteTask/{ID}" class="btn btn-sm btn-danger" role="button"><i class="glyphicon glyphicon-trash"></i></a></td>
</tr>
{/LOOP}
{ALT}
<tr>
<td colspan="7">
No Tasks
</td>
</tr>
{/ALT}
</tbody>
</table>
<a href="{ROOT_URL}todo/createtask/yearly" class="btn btn-sm btn-primary" role="button">New Task</a>
<a href="{ROOT_URL}todo/yearly/?includeCompleted={completedToggle}" class="btn btn-sm btn-info" role="button">{completedToggleText} Completed</a>
</form>
</div>