partially implemented todo tracker

This commit is contained in:
2025-04-20 17:05:41 -06:00
parent 9e47110758
commit ab30859446
29 changed files with 546 additions and 157 deletions
+2 -2
View File
@@ -9,8 +9,8 @@ foreach (glob('components/admin/*.php') as $file)
include_once 'components/head.php'; include_once 'components/head.php';
if (!isset($_SESSION['role_id'])) if (!isset($_SESSION['role_id']))
header('Location: user.php'); header('Location: user.php?view=login');
else if ($_SESSION['role_id'] >= 3) else if ($_SESSION['role_id'] >= contributor)
header('Location: user.php?action=view&user_id=' . $_SESSION['user_id']); header('Location: user.php?action=view&user_id=' . $_SESSION['user_id']);
include_once 'functions/admin_functions.php'; include_once 'functions/admin_functions.php';
+1 -1
View File
@@ -76,7 +76,7 @@ switch ($view) {
break; break;
} }
if (($view == 'list' || $view == 'sort') && (isset($_SESSION['role_id']) && $_SESSION['role_id'] <= 3)) { if (($view == 'list' || $view == 'sort') && (isset($_SESSION['role_id']) && $_SESSION['role_id'] <= contributor)) {
echo ' echo '
<div id="floating_compose"> <div id="floating_compose">
<a href="articles.php?view=compose"><i class="nf nf-md-note_plus"></i></a> <a href="articles.php?view=compose"><i class="nf nf-md-note_plus"></i></a>
+2 -2
View File
@@ -3,14 +3,14 @@ function admin_article_view()
{ {
$display = ' $display = '
<div class="view_card"> <div class="view_card">
<div class="row"> <div class="row_space_between">
<h3>Articles</h3> <h3>Articles</h3>
<a href="admin.php?view=users">View Users</a> <a href="admin.php?view=users">View Users</a>
</div> </div>
<div class="line"></div> <div class="line"></div>
<form method="post"> <form method="post">
<input type="hidden" name="form_id" value="articles"> <input type="hidden" name="form_id" value="articles">
<div class="row"> <div class="row_space_between">
<label for="delete" class="form_checkbox_container">Delete <label for="delete" class="form_checkbox_container">Delete
<input type="radio" class="button" name="action" id="delete" value="delete"> <input type="radio" class="button" name="action" id="delete" value="delete">
<span class="checkmark"></span> <span class="checkmark"></span>
+2 -2
View File
@@ -3,14 +3,14 @@ function admin_user_view()
{ {
$display = ' $display = '
<div class="view_card"> <div class="view_card">
<div class="row"> <div class="row_space_between">
<h3>Users</h3> <h3>Users</h3>
<a href="admin.php?view=articles">View Articles</a> <a href="admin.php?view=articles">View Articles</a>
</div> </div>
<div class="line"></div> <div class="line"></div>
<form method="post" enctype="multipart/form-data"> <form method="post" enctype="multipart/form-data">
<input type="hidden" name="form_id" value="users"> <input type="hidden" name="form_id" value="users">
<div class="row"> <div class="row_space_between">
<label for="delete" class="form_checkbox_container">Delete <label for="delete" class="form_checkbox_container">Delete
<input type="radio" class="button" name="action" id="delete" value="delete"> <input type="radio" class="button" name="action" id="delete" value="delete">
<span class="checkmark"></span> <span class="checkmark"></span>
+3 -3
View File
@@ -17,12 +17,12 @@ function article_page_from_markdown($article_id)
$html = ' $html = '
<div class="article"> <div class="article">
<div class="row"> <div class="row_space_between">
<h1>' . $article['title'] . '</h1> <h1>' . $article['title'] . '</h1>
' . (isset($_SESSION['user_id']) && $_SESSION['user_id'] == $article['author_id'] ? '<a href="articles.php?view=compose&article_id=' . $article_id . '"><i class="nf nf-fa-edit"></i></a>' : '') . ' ' . (isset($_SESSION['user_id']) && $_SESSION['user_id'] == $article['author_id'] ? '<a href="articles.php?view=compose&article_id=' . $article_id . '"><i class="nf nf-fa-edit"></i></a>' : '') . '
</div> </div>
<div class="row"> <div class="row_space_between">
<div class="row"> <div class="row_space_between">
<div class="col_right"> <div class="col_right">
<h5>Written by <a href="user.php?view=display&user_id=' . $author['user_id'] . '">' . $author['username'] . '</a></h5> <h5>Written by <a href="user.php?view=display&user_id=' . $author['user_id'] . '">' . $author['username'] . '</a></h5>
<p>Published on ' . $article['published_at'] . '<br> <p>Published on ' . $article['published_at'] . '<br>
+2 -2
View File
@@ -23,7 +23,7 @@ function article_card($article_id)
$card = ' $card = '
<div class="article_card"> <div class="article_card">
<div class="row"> <div class="row_space_between">
<h4>' . $article['title'] . '</h4> <h4>' . $article['title'] . '</h4>
<div class="card_info_box"> <div class="card_info_box">
<div class="col-right"> <div class="col-right">
@@ -38,7 +38,7 @@ function article_card($article_id)
</div> </div>
<div class="line"></div> <div class="line"></div>
<p>' . $article['excerpt'] . '</p> <p>' . $article['excerpt'] . '</p>
<div class="row"> <div class="row_space_between">
<a href="/articles.php?view=read&article_id=' . $article['article_id'] . '" class="button">Read More</a> <a href="/articles.php?view=read&article_id=' . $article['article_id'] . '" class="button">Read More</a>
<div class="tag_box">' . $tags_html . '</div> <div class="tag_box">' . $tags_html . '</div>
</div> </div>
+1 -1
View File
@@ -5,7 +5,7 @@ function article_list($list = null)
$filters = ' $filters = '
<form method="get" action="articles.php"> <form method="get" action="articles.php">
<input type="hidden" name="view" value="sort"> <input type="hidden" name="view" value="sort">
<div class="row_no_margin"> <div class="row_space_between no_margin">
'; ';
if (!isset($_GET['sort']) || $_GET['sort'] == 'newest') { if (!isset($_GET['sort']) || $_GET['sort'] == 'newest') {
+2
View File
@@ -57,6 +57,8 @@
'; ';
} }
} }
} else if ($_SERVER['SCRIPT_NAME'] == '/todo.php') {
echo '<script src="js/todo.js"></script>';
} }
echo ' echo '
+1
View File
@@ -3,6 +3,7 @@
<head> <head>
<link href="css/base.css" rel="stylesheet" type="text/css"> <link href="css/base.css" rel="stylesheet" type="text/css">
<link href="css/rewrite.css" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="https://nerdfonts.com/assets/css/webfont.css"> <link rel="stylesheet" href="https://nerdfonts.com/assets/css/webfont.css">
<link rel="icon" type="image/x-icon" href="data/vintagecoding-favicon.png" </link> <link rel="icon" type="image/x-icon" href="data/vintagecoding-favicon.png" </link>
<?php <?php
+3 -2
View File
@@ -2,14 +2,14 @@
$current_page = $_SERVER['SCRIPT_NAME']; $current_page = $_SERVER['SCRIPT_NAME'];
$nav = ' $nav = '
<nav> <nav>
<div class="row_no_margin"> <div class="row_space_between no_margin">
<div class="site_navigation"> <div class="site_navigation">
<ul> <ul>
<li><a href="/index.php"' . ($current_page == '/index.php' ? ' class="underline"' : '') . '>Home</a></li> <li><a href="/index.php"' . ($current_page == '/index.php' ? ' class="underline"' : '') . '>Home</a></li>
<li><a href="/articles.php?view=sort&sort=newest"' . ($current_page == '/articles.php' ? ' class="underline"' : '') . '>Articles</a></li> <li><a href="/articles.php?view=sort&sort=newest"' . ($current_page == '/articles.php' ? ' class="underline"' : '') . '>Articles</a></li>
'; ';
if (isset($_SESSION['role_id']) && $_SESSION['role_id'] <= 2) { if (isset($_SESSION['role_id']) && $_SESSION['role_id'] <= admin) {
$nav .= ' $nav .= '
<li><a href="/admin.php?view=users"' . ($current_page == '/admin.php' ? ' class="underline"' : '') . '>Admin</a></li> <li><a href="/admin.php?view=users"' . ($current_page == '/admin.php' ? ' class="underline"' : '') . '>Admin</a></li>
'; ';
@@ -18,6 +18,7 @@ if (isset($_SESSION['role_id']) && $_SESSION['role_id'] <= 2) {
if (isset($_SESSION['user_id'])) { if (isset($_SESSION['user_id'])) {
$nav .= ' $nav .= '
<li><a href="/user.php?view=display&user_id=' . $_SESSION['user_id'] . '"' . ($current_page == '/user.php' ? ' class="underline"' : '') . '>Account</a></li> <li><a href="/user.php?view=display&user_id=' . $_SESSION['user_id'] . '"' . ($current_page == '/user.php' ? ' class="underline"' : '') . '>Account</a></li>
<li><a href="/todo.php?view=display"' . ($current_page == '/todo.php' ? ' class="underline"' : '') . '>Todos</a></li>
'; ';
} }
+20
View File
@@ -0,0 +1,20 @@
<?php
function todo_actions()
{
$actions = '
<div class="todo_actions">
<form method="post">
<button name="action" value="new">New</button>
<button name="action" value="new">New</button>
<button name="action" value="new">New</button>
<button name="action" value="new">New</button>
<button name="action" value="new">New</button>
<button name="action" value="new">New</button>
<button name="action" value="new">New</button>
</form>
</div>
';
return $actions;
}
+13
View File
@@ -0,0 +1,13 @@
<?php
function todo_category($category, $todos)
{
$category = '
<div class="todo_category med_border padding">
<h4 class="padding">' . ucwords($category) . '</h4>
<div class="line bottom_margin"></div>
' . todo_list($todos) . '
</div>
';
return $category;
}
+66
View File
@@ -0,0 +1,66 @@
<?php
function sort_by_completion($a, $b)
{
// Ensure $a and $b are arrays before proceeding
if (!is_array($a) || !is_array($b)) {
// Handle the case where one or both are not arrays.
// This shouldn't ideally happen with uasort on your $categories array,
// but adding a safeguard is good practice.
return 0; // Maintain original order if not arrays
}
$a_completed = true;
foreach ($a as $todo) {
if (isset($todo['status']) && $todo['status'] !== 'completed') {
$a_completed = false;
break;
}
}
$b_completed = true;
foreach ($b as $todo) {
if (isset($todo['status']) && $todo['status'] !== 'completed') {
$b_completed = false;
break;
}
}
if ($a_completed && $b_completed) {
return 0;
} elseif ($a_completed && !$b_completed) {
return 1;
} elseif (!$a_completed && $b_completed) {
return -1;
} else {
return 0;
}
}
function todo_display($todos)
{
$categories = [];
while ($row = $todos->fetch_assoc())
$categories[$row['category']][] = $row;
foreach ($categories as $c)
uasort($c, 'sort_by_completion');
$display = '
<div class="todo_display">
' . todo_actions() . '
<div class="todo_category_window">
';
foreach ($categories as $c)
$c = array_reverse($c);
foreach (array_keys($categories) as $key)
$display .= todo_category($key, $categories[$key]);
$display .= '
</div>
</div>
';
return $display;
}
+28
View File
@@ -0,0 +1,28 @@
<?php
function todo_item($todo)
{
$item = '
<div class="todo_item bottom_margin top_padding bottom_padding sm_border">
<div class="row left_margin">
<div class="column center">
<label class="form_checkbox_container no_margin">
<input type="hidden" name="todo_id" value="' . $todo['todo_id'] . '">
<input type="checkbox"' . ($todo['status'] == 'completed' ? ' checked' : '') . '>
<span class="checkmark no_margin"></span>
</label>
</div>
<div class="column center">
<small>' . $todo['task'] . '</small>
</div>
</div>
</div>
<div class="todo_item_details" style="display: none;">
</div>
';
return $item;
}
+17
View File
@@ -0,0 +1,17 @@
<?php
function todo_list($todos)
{
$list = '
<div class="todo_list">
';
foreach ($todos as $todo)
$list .= todo_item($todo);
$list .= '
</div>
';
return $list;
}
+2
View File
@@ -0,0 +1,2 @@
<?php
function modal() {}
+5 -5
View File
@@ -12,12 +12,12 @@ function user_view($user_id)
$view = ' $view = '
<div class="user_view"> <div class="user_view">
<div class="row"> <div class="row_space_between">
<div class="row"> <div class="row_space_between">
<h1>' . $user['username'] . '</h1> <h1>' . $user['username'] . '</h1>
'; ';
if ($_SESSION['user_id'] != $user_id && !$following) { if ($_SESSION['user_id'] != $user_id && isset($following) && !$following) {
$view .= ' $view .= '
<div class="dropdown"> <div class="dropdown">
<span>Follow</span> <span>Follow</span>
@@ -31,7 +31,7 @@ function user_view($user_id)
</div> </div>
</div> </div>
'; ';
} else if ($following) { } else if (isset($following) && $following) {
$view .= ' $view .= '
<div class="margin_right"> <div class="margin_right">
<form method="post"> <form method="post">
@@ -55,7 +55,7 @@ function user_view($user_id)
// TODO: Allow user to update profile picture. // TODO: Allow user to update profile picture.
// <button id="update_profile_picture_form_button" class="modal_button underline">Update Profile Picture</button> // <button id="update_profile_picture_form_button" class="modal_button underline">Update Profile Picture</button>
// <div id="update_profile_picture_form" class="modal_form">' . update_profile_picture_form() . '</div> // <div id="update_profile_picture_form" class="modal_form">' . update_profile_picture_form() . '</div>
if ((isset($_SESSION['user_id']) && $_SESSION['user_id'] == $user_id) || (isset($_SESSION['role_id']) && $_SESSION['role_id'] <= 2)) { if ((isset($_SESSION['user_id']) && $_SESSION['user_id'] == $user_id) || (isset($_SESSION['role_id']) && $_SESSION['role_id'] <= admin)) {
$view .= ' $view .= '
<h3>User Actions</h3> <h3>User Actions</h3>
<div class="user_actions"> <div class="user_actions">
+70 -20
View File
@@ -19,6 +19,7 @@ h2,
h3, h3,
h4, h4,
h5, h5,
h6,
p, p,
small, small,
label, label,
@@ -61,6 +62,11 @@ h5 a {
font-size: 1.5vw; font-size: 1.5vw;
} }
h6,
h6 a {
font-size: 1.25vw;
}
p, p,
a, a,
label, label,
@@ -167,32 +173,17 @@ code {
margin-bottom: 5px; margin-bottom: 5px;
} }
.row_no_margin {
display: flex;
justify-content: space-between;
width: 100%;
margin: 0;
}
.row {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
margin: 15px 0px 15px 0px;
}
.center-h { .center-h {
margin: 0 auto; margin: 0 auto;
} }
.article_filters form .row_no_margin { .article_filters form .row_space_between {
display: flex; display: flex;
align-items: center; align-items: center;
margin-top: 25px; margin-top: 25px;
} }
.article_filters form .row_no_margin p { .article_filters form .row_space_between p {
margin-bottom: 0; margin-bottom: 0;
padding-bottom: 0; padding-bottom: 0;
} }
@@ -755,8 +746,62 @@ hr {
margin-bottom: 5px; margin-bottom: 5px;
} }
.margin_right { .todo_display {
margin-right: 15px; margin: 0 auto;
margin-top: 25px;
width: 80%;
height: 80vh;
display: flex;
flex-direction: column;
align-items: center;
}
.todo_actions {
padding: 15px;
border: 2px solid white;
border-radius: 8px;
width: 100%;
box-sizing: border-box;
margin-bottom: 25px;
}
.todo_actions form {
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-evenly;
}
.todo_category_window {
display: flex;
flex-direction: row;
width: 100%;
height: 100%;
overflow-x: scroll;
overflow-y: none;
}
.todo_category {
display: block;
min-width: 400px;
margin-right: 50px;
overflow-y: scroll;
overflow-x: none;
}
.todo_category h4 {
text-align: center;
position: relative;
}
.todo_list {
display: flex;
flex-direction: column;
align-items: center;
}
.todo_item {
width: 100%;
} }
@media screen and (max-width: 992px) { @media screen and (max-width: 992px) {
@@ -788,6 +833,11 @@ hr {
font-size: 3vw; font-size: 3vw;
} }
h6,
h6 a {
font-size: 2.5vw;
}
p, p,
a, a,
label, label,
@@ -827,7 +877,7 @@ hr {
flex-direction: row-reverse; flex-direction: row-reverse;
} }
nav .row_no_margin { nav .row_space_between .no_margin {
flex-direction: row-reverse; flex-direction: row-reverse;
} }
+95
View File
@@ -0,0 +1,95 @@
/********** Borders & Outlines **********/
.std_border,
.med_border,
.sm_border {
border-radius: 9px;
}
.std_border {
border: 3px solid white;
}
.med_border {
border: 2px solid white;
}
.sm_border {
border: 1px solid white;
}
.debug {
border: 1px solid red;
}
/********** Rows & Columns **********/
.row {
display: flex;
flex-direction: row;
}
.row_space_between {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
margin: 15px 0px 15px 0px;
}
.column {
display: flex;
flex-direction: column;
}
.center {
align-items: center;
justify-content: center;
}
/********** Margins & Padding **********/
.margin {
margin: 15px;
}
.no_margin {
margin: 0;
}
.top_margin {
margin-top: 15px;
}
.right_margin {
margin-right: 15px;
}
.bottom_margin {
margin-bottom: 15px;
}
.left_margin {
margin-left: 15px;
}
.padding {
padding: 15px;
}
.no_padding {
padding: 0;
}
.top_padding {
padding-top: 15px;
}
.right_padding {
padding-right: 15px;
}
.bottom_padding {
padding-bottom: 15px;
}
.left_padding {
padding-left: 15px;
}
+29
View File
@@ -0,0 +1,29 @@
<?php
include 'functions/functions.php';
if (isset($_POST['ajax_id'])) {
switch ($_POST['ajax_id']) {
case 'todo':
handle_todo();
break;
}
} else
echo 'Received malformed request.';
function handle_todo()
{
$response = [];
include 'functions/todo_functions.php';
if (isset($_POST['todo_id']) && isset($_POST['action_id']) && isset($_POST['status'])) {
switch ($_POST['action_id']) {
case 'status':
$response['todo_status'] = $_POST['status'];
change_status($_POST['todo_id'], $_POST['status']);
break;
}
}
echo json_encode($response);
}
+1 -1
View File
@@ -243,7 +243,7 @@ function delete_account($user_id, $password = null, $verify_password = null)
exec_stmt('DELETE FROM user WHERE user_id = ?', 'i', $user_id); exec_stmt('DELETE FROM user WHERE user_id = ?', 'i', $user_id);
logout(); logout();
} else if ($_SESSION['role_id'] <= 2) { } else if ($_SESSION['role_id'] <= admin) {
$user = exec_stmt('SELECT user_id, profile_picture FROM user WHERE user_id = ?', 'i', $user_id)->fetch_assoc(); $user = exec_stmt('SELECT user_id, profile_picture FROM user WHERE user_id = ?', 'i', $user_id)->fetch_assoc();
if ($user['user_id'] == 2025) { if ($user['user_id'] == 2025) {
+3
View File
@@ -16,6 +16,7 @@ function notify_users($emails, $auther_username, $article_id, $article_title, $e
<p>' . $excerpt . '</p> <p>' . $excerpt . '</p>
'; ';
$client = new PostmarkClient($_ENV['POSTMARK_API_TOKEN']); $client = new PostmarkClient($_ENV['POSTMARK_API_TOKEN']);
$client->sendEmail( $client->sendEmail(
@@ -171,7 +172,9 @@ function check_csv_upload($target)
function pretty_dump($arr) function pretty_dump($arr)
{ {
ob_start();
echo '<pre>'; echo '<pre>';
print_r($arr); print_r($arr);
echo '</pre>'; echo '</pre>';
return ob_get_clean();
} }
+5
View File
@@ -20,6 +20,11 @@ if (!isset($_SESSION['initialized'])) {
unset($_POST['theme']); unset($_POST['theme']);
} }
define('owner', 1);
define('admin', 2);
define('contributor', 3);
define('reader', 4);
// Update the database and cookies to keep the user logged in. // Update the database and cookies to keep the user logged in.
if (isset($_SESSION['user_id'])) { if (isset($_SESSION['user_id'])) {
$conn = get_connection(); $conn = get_connection();
+55
View File
@@ -0,0 +1,55 @@
<?php
// class Todo
// {
// private $todo_id;
// private $user_id;
// private $task;
// private $description;
// private $priority;
// private $due_date;
// private $category;
// private $status;
// private $created_at;
// private $update_at;
// private $completed_at;
// private $is_recurring;
// private $recurrence_rule;
// private $reminder_at;
//
// function __construct(
// $todo_id,
// $user_id,
// $task,
// $description,
// $priority,
// $due_date,
// $category,
// $status,
// $created_at,
// $update_at,
// $completed_at,
// $is_recurring,
// $recurrence_rule,
// $reminder_at,
// ) {
// $this->todo_id = $todo_id;
// $this->user_id = $user_id;
// $this->task = $task;
// $this->description = $description;
// $this->priority = $priority;
// $this->due_date = $due_date;
// $this->category = $category;
// $this->status = $status;
// $this->created_at = $created_at;
// $this->update_at = $update_at;
// $this->completed_at = $completed_at;
// $this->is_recurring = $is_recurring;
// $this->recurrence_rule = $recurrence_rule;
// $this->reminder_at = $reminder_at;
// }
// }
function change_status($todo_id, $status)
{
exec_stmt('UPDATE todos SET status = ? WHERE todo_id = ?', 'si', $status, $todo_id);
}
+1
View File
@@ -0,0 +1 @@
../vendor
+48
View File
@@ -0,0 +1,48 @@
/*
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json(); // Or handle other response formats
})
.then(responseData => {
console.log('Response received:', responseData);
// Handle the server's response
});
*/
document.addEventListener('DOMContentLoaded', function() {
var todos = document.getElementsByClassName('todo_item');
//var todos = document.querySelectorAll('todo_item');
for (let i = 0; i < todos.length; i++) {
var item = todos[i];
var checkbox = item.querySelector('input[type="checkbox"]');
checkbox.todo_id = item.querySelector('input[name="todo_id"]').value;
checkbox.is_checked = checkbox.checked;
checkbox.addEventListener('click', function() {
if (!this.is_checked) {
this.is_checked = true;
fetch('director.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'ajax_id=todo&action_id=status&todo_id=' + this.todo_id + '&status=completed',
});
} else {
this.is_checked = false;
fetch('director.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'ajax_id=todo&action_id=status&todo_id=' + this.todo_id + '&status=open',
});
}
});
}
});
+29
View File
@@ -0,0 +1,29 @@
<?php
require_once 'functions/init.php';
require_once 'functions/functions.php';
require_once 'functions/todo_functions.php';
// UI Components
foreach (glob('components/todo/*.php') as $file)
require_once $file;
include_once 'components/head.php';
if (!isset($_SESSION['role_id'])) {
$redirect = 'todo.php?view=display';
header('Location: user.php?view=login&redirect=' . urlencode($redirect));
}
if (isset($_GET['view']))
$view = $_GET['view'];
else
$view = 'display';
switch ($view) {
case 'display':
$todos = exec_stmt('SELECT * FROM todos WHERE user_id = ? ORDER BY updated_at DESC', 'i', $_SESSION['user_id']);
echo todo_display($todos);
break;
}
include_once 'components/foot.php';
+4 -4
View File
@@ -45,7 +45,7 @@ if (isset($_POST['form_id'])) {
break; break;
case 'reset_pw_form': case 'reset_pw_form':
$msg = reset_password( $msg = reset_password(
($_SESSION['role_id'] <= 2 && $_SESSION['user_id'] != $_POST['user_id'] ? $_POST['user_id'] : $_SESSION['user_id']), ($_SESSION['role_id'] <= admin && $_SESSION['user_id'] != $_POST['user_id'] ? $_POST['user_id'] : $_SESSION['user_id']),
$_POST['new_pw'], $_POST['new_pw'],
$_POST['verify_new_pw'] $_POST['verify_new_pw']
); );
@@ -53,7 +53,7 @@ if (isset($_POST['form_id'])) {
break; break;
case 'update_email_form': case 'update_email_form':
$msg = update_email( $msg = update_email(
($_SESSION['role_id'] <= 2 && $_SESSION['user_id'] != $_POST['user_id'] ? $_POST['user_id'] : $_SESSION['user_id']), ($_SESSION['role_id'] <= admin && $_SESSION['user_id'] != $_POST['user_id'] ? $_POST['user_id'] : $_SESSION['user_id']),
$_POST['new_email'], $_POST['new_email'],
$_POST['verify_new_email'] $_POST['verify_new_email']
); );
@@ -61,7 +61,7 @@ if (isset($_POST['form_id'])) {
break; break;
case 'update_username_form': case 'update_username_form':
$msg = update_username( $msg = update_username(
($_SESSION['role_id'] <= 2 && $_SESSION['user_id'] != $_POST['user_id'] ? $_POST['user_id'] : $_SESSION['user_id']), ($_SESSION['role_id'] <= admin && $_SESSION['user_id'] != $_POST['user_id'] ? $_POST['user_id'] : $_SESSION['user_id']),
$_POST['new_username'], $_POST['new_username'],
$_POST['verify_new_username'] $_POST['verify_new_username']
); );
@@ -77,7 +77,7 @@ if (isset($_POST['form_id'])) {
break; break;
case 'delete_account_form': case 'delete_account_form':
$msg = delete_account( $msg = delete_account(
($_SESSION['role_id'] <= 2 && $_SESSION['user_id'] != $_POST['user_id'] ? $_POST['user_id'] : $_SESSION['user_id']), ($_SESSION['role_id'] <= admin && $_SESSION['user_id'] != $_POST['user_id'] ? $_POST['user_id'] : $_SESSION['user_id']),
$_POST['delete_password'], $_POST['delete_password'],
$_POST['delete_verify_password'] $_POST['delete_verify_password']
); );
-76
View File
@@ -1,76 +0,0 @@
### vintagecoding.net
#### Content:
- [ ] Setting up CI/CD with GitHub Actions
- [ ] General
- [x] Ensure a consistent design & UX aesthetic --- v0.1.0
- [ ] Sensible CSS class names for a modular styling approach --- v0.2.0
#### Security
- [x] Convert db_functions.php queries/statements into prepared SQL for protection against SQL injection --- v0.2.0
- [ ] XSS prevention --- v0.2.0
- [ ] Email Handler:
- [ ] Email users subscribed to author or tag whenever a new article is posted. --- v0.3.0
- [ ] Email me whenever a user requests a role change. --- v0.3.0
#### Systems Interfaces
- [x] Admin panel (manage articles & accounts) --- v0.2.0
- [ ] Implement a notification modal system for handling error and success messages. --- v0.3.0
- [ ] Accounts:
#### Account CRUD --- account_functions.php
- [x] Self Auth Level (a simple get, though should always get from the DB since that'll reflect the latest changes.) --- v0.1.0
- [x] Modify Self ---v0.1.0
- [x] Delete Self (user opt-out of the deletion of articles they've written.) --- v0.1.0
- [x] Create User (either new user or admin or higher auth) --- v0.1.0
- [ ] Implement OAuth accounts --- v0.2.0
- [x] Login --- v0.1.0
- [ ] Implement OAuth 2.0 accounts --- v0.2.0
- [x] Modify User (requires auth) --- v0.2.0
- [x] Delete User --- v0.2.0
- [x] Get User Admin (requires auth, shows limited information for privacy) --- v0.2.0
- [x] Get Users (requires auth) --- v0.2.0
- [x] Create Users (requires auth) --- v0.2.0
- [x] Delete Users --- v0.2.0
- [x] Get User (for public facing account page) --- v0.2.0
#### Analytics on Accounts (requires auth) --- account_analytic_functions.php
- [ ] Get Users by Creation --- v0.3.0
- [ ] Get Users by Articles Written --- v0.3.0
- [ ] Get Users by Last Login --- v0.3.0
- [ ] Get Users by Is Active --- v0.3.0
#### Account Systems Interfaces
- [x] Sign Up & Login Form --- v0.1.0
- [x] Account Settings (requires login, self) --- v0.1.0
- [x] Account Page (of each user, hidden by default) --- v0.2.0
- [ ] Articles:
#### Article CRUD --- article_functions.php
- [x] Create Article (requires contributor or higher) --- v0.1.0
- [x] Prompt for tags
- [x] Use account information to populate author information
- [x] Get Article by ID --- v0.1.0
- [x] Get Articles by ID --- v0.1.0
- [x] Get Articles by Recency --- v0.1.0
- [x] Get Articles by Tag --- v0.1.0
- [x] Delete Article by ID --- v0.1.0
- [x] Delete Articles by Author (for account deletion) --- v0.1.0
- [ ] Draft/unpublished status --- v0.2.0
- [x] Update Article by ID (required to be the author updating) --- v0.2.0
- [x] Get Articles by Author --- v0.2.0
- [x] Sort / filter system --- v0.2.0
#### Article System Interface
- [x] Convert articles.php layout to a grid, to display a left hand column with a search/filtering system or table of contents. --- v0.2.0
- [ ] Advanced markdown editor or upload markdown, with media upload support (images & code files, requires contributor or higher auth) --- v0.3.0
### Unplanned but implemented
- [ ] Vim motions for navigation
- [ ] Terminal access? security challenge.
- [ ] Allow for user customization of their account page (colors, layout, maybe even let them have their own CSS file to make changes) --- v0.?.0
- Image cropper. 12 hoursish, learned a lot though. Opted not to use cropper.js or cropper, wanted the challenge. Needs to be refactored/rewritten. --- v0.1.0 @ 29/3/2025