partially implemented todo tracker
This commit is contained in:
@@ -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
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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') {
|
||||||
|
|||||||
+4
-2
@@ -37,7 +37,7 @@
|
|||||||
} else if ($_SERVER['SCRIPT_NAME'] == '/admin.php') {
|
} else if ($_SERVER['SCRIPT_NAME'] == '/admin.php') {
|
||||||
echo '
|
echo '
|
||||||
<script src="js/clickable_rows.js"></script>
|
<script src="js/clickable_rows.js"></script>
|
||||||
';
|
';
|
||||||
$args = get_args_from_url();
|
$args = get_args_from_url();
|
||||||
|
|
||||||
if (isset($args['view'])) {
|
if (isset($args['view'])) {
|
||||||
@@ -57,11 +57,13 @@
|
|||||||
';
|
';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if ($_SERVER['SCRIPT_NAME'] == '/todo.php') {
|
||||||
|
echo '<script src="js/todo.js"></script>';
|
||||||
}
|
}
|
||||||
|
|
||||||
echo '
|
echo '
|
||||||
<script src="js/override_browser_styles.js"></script>
|
<script src="js/override_browser_styles.js"></script>
|
||||||
';
|
';
|
||||||
?>
|
?>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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>
|
||||||
';
|
';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
<?php
|
||||||
|
function modal() {}
|
||||||
@@ -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
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
../vendor
|
||||||
+48
@@ -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',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -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';
|
||||||
@@ -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']
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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
|
|
||||||
Reference in New Issue
Block a user