Compare commits
10
Commits
ab8f1b9ec8
...
ae76b11a87
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae76b11a87 | ||
|
|
becfbc3628 | ||
|
|
088e0cc5a3 | ||
|
|
d3fa1733f4 | ||
|
|
54a01f0f1f | ||
|
|
a93c30c40f | ||
|
|
228cf1137b | ||
|
|
bd59f428ba | ||
|
|
693d11c506 | ||
|
|
275e6cb153 |
@@ -4,4 +4,6 @@ composer.lock
|
||||
data/profile_pictures
|
||||
data/articles
|
||||
data/tmp
|
||||
data/neo4j
|
||||
import.sql
|
||||
eula.txt
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
<?php
|
||||
require_once 'functions/init.php';
|
||||
require_once 'functions/functions.php';
|
||||
|
||||
include_once 'components/head.php';
|
||||
|
||||
include_once 'functions/article_functions.php';
|
||||
include_once 'functions/account_functions.php';
|
||||
|
||||
// UI Components
|
||||
foreach (glob('components/article/*.php') as $file)
|
||||
require_once $file;
|
||||
|
||||
if (isset($_POST['form_id'])) {
|
||||
switch ($_POST['form_id']) {
|
||||
case 'compose':
|
||||
if (isset($_POST['article_id'])) {
|
||||
$tags = [];
|
||||
for ($i = 0; $i < count($_POST['tags']); $i++)
|
||||
$tags[] = $_POST['tags'][$i];
|
||||
|
||||
update_article($_POST['article_id'], $_POST['title'], $_POST['excerpt'], $tags, $_POST['markdown']);
|
||||
header('Location: articles.php?article_id=' . $_POST['article_id']);
|
||||
} else {
|
||||
$id = create_article($_SESSION['user_id'], $_POST['title'], $_POST['excerpt'], (isset($_POST['tags']) ? $_POST['tags'] : []), $_POST['markdown']);
|
||||
$emails = exec_stmt('SELECT email FROM user INNER JOIN follows ON user.user_id = follows.follower_user_id WHERE follows.following_user_id = ? AND follows.notify_user = 1', 'i', $_SESSION['user_id'])->fetch_assoc();
|
||||
notify_users($emails, $_SESSION['username'], $id, $_POST['title'], $_POST['excerpt']);
|
||||
header('Location: articles.php?article_id=' . $id);
|
||||
}
|
||||
|
||||
break;
|
||||
case 'follow':
|
||||
follow_user($_SESSION['user_id'], $_POST['author_id'], ($_POST['follow'] == 'email_notify' ? 1 : 0));
|
||||
break;
|
||||
case 'unfollow':
|
||||
unfollow_user($_SESSION['user_id'], $_POST['author_id']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_GET['view']))
|
||||
$view = $_GET['view'];
|
||||
else
|
||||
$view = 'list';
|
||||
|
||||
switch ($view) {
|
||||
case 'list':
|
||||
echo article_list();
|
||||
break;
|
||||
case 'filter':
|
||||
if (isset($_GET['tag']))
|
||||
echo article_list(article_ids_by_tag($_GET['tag']));
|
||||
else if (isset($_GET['author_id']))
|
||||
echo article_list(articles_ids_by_author($_GET['author_id']));
|
||||
break;
|
||||
case 'sort':
|
||||
if (isset($_GET['sort']) && $_GET['sort'] == 'oldest')
|
||||
echo article_list(article_ids_by_oldest());
|
||||
else if (isset($_GET['sort']) && $_GET['sort'] == 'newest')
|
||||
echo article_list(article_ids_by_newest());
|
||||
break;
|
||||
case 'read':
|
||||
if (isset($_SESSION['user_id']) && isset($_GET['article_id'])) {
|
||||
increment_read_counter($_GET['article_id']);
|
||||
echo article_page_from_markdown($_GET['article_id']);
|
||||
} else {
|
||||
$redirect = (isset($_GET['article_id']) ? 'articles.php?view=read&article_id=' . $_GET['article_id'] : '');
|
||||
if ($redirect)
|
||||
header('Location: user.php?view=login&redirect=' . urlencode($redirect));
|
||||
else
|
||||
header('Location: articles.php');
|
||||
}
|
||||
break;
|
||||
case 'compose':
|
||||
echo compose_view((isset($_GET['article_id']) ? $_GET['article_id'] : ''));
|
||||
break;
|
||||
}
|
||||
|
||||
if (($view == 'list' || $view == 'sort') && (isset($_SESSION['role_id']) && $_SESSION['role_id'] <= contributor)) {
|
||||
echo '
|
||||
<div id="floating_compose">
|
||||
<a href="articles.php?view=compose"><i class="nf nf-md-note_plus"></i></a>
|
||||
</div>
|
||||
';
|
||||
}
|
||||
|
||||
include_once 'components/foot.php';
|
||||
@@ -1,49 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Generates cards for a given article.
|
||||
*/
|
||||
function article_card($article_id)
|
||||
{
|
||||
$article = exec_stmt('SELECT * FROM article WHERE article_id = ?', 'i', $article_id)->fetch_assoc();
|
||||
|
||||
$tags_results = exec_stmt('SELECT tag FROM article_tags INNER JOIN tags ON article_tags.tag_id = tags.tag_id WHERE article_id = ?', 'i', $article_id);
|
||||
|
||||
$tags_html = '';
|
||||
if ($tags_results != null) {
|
||||
$tags_html .= '<div class="tag_row">';
|
||||
|
||||
while ($row = $tags_results->fetch_assoc())
|
||||
$tags_html .= '<a href="/articles.php?view=filter&tag=' . $row['tag'] . '" class="tag">#' . $row['tag'] . '</a>';
|
||||
|
||||
$tags_html .= '</div>';
|
||||
}
|
||||
|
||||
$author = exec_stmt('SELECT user_id, username, profile_picture FROM user WHERE user_id = ?', 'i', $article['author_id'])->fetch_assoc();
|
||||
|
||||
$card = '
|
||||
<div class="article_card">
|
||||
<div class="row_space_between">
|
||||
<h4>' . $article['title'] . '</h4>
|
||||
<div class="card_info_box">
|
||||
<div class="col-right">
|
||||
<a href="user.php?view=display&user_id=' . $author['user_id'] . '">Written by: ' . $author['username'] . '</a>
|
||||
<small>Published: ' . $article['published_at'] . '</small>
|
||||
<small>Updated: ' . $article['updated_at'] . '</small>
|
||||
</div>
|
||||
<div class="card_pic_box">
|
||||
<img src="' . $_ENV['PROFILE_IMAGES_PQ_PATH'] . $author['profile_picture'] . '" class="card_profile_picture">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<p>' . $article['excerpt'] . '</p>
|
||||
<div class="row_space_between">
|
||||
<a href="/articles.php?view=read&article_id=' . $article['article_id'] . '" class="button">Read More</a>
|
||||
<div class="tag_box">' . $tags_html . '</div>
|
||||
</div>
|
||||
</div>
|
||||
';
|
||||
|
||||
return $card;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
require_once 'functions/space.php';
|
||||
|
||||
/*
|
||||
* Generates a card for a given Space.
|
||||
*
|
||||
* @* @param int $space_id "Retrieves information from the database using this ID."
|
||||
* @* @param int $user_id "Retrieves information from the database using this ID. Default is -1, which will limit queries to a singular Open Space."
|
||||
* @* @return String $html "The HTML card component for a Space."
|
||||
*/
|
||||
function spaceCard(Space $space)
|
||||
{
|
||||
$html = '';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generates a card for a given Thought.
|
||||
*
|
||||
* @* @param Integer $post_id "Retrieves information from the database using this ID."
|
||||
* @* @return String $html "The HTML card component for a Thought."
|
||||
*/
|
||||
function thoughtCard(Post $post)
|
||||
{
|
||||
$html = '';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generates a card for a given Moment.
|
||||
*
|
||||
* @* @param Integer $post_id "Retrieves information from the database using this ID."
|
||||
* @* @return String $html "The HTML card component for a Moment."
|
||||
*/
|
||||
function momentCard(Post $post)
|
||||
{
|
||||
$html = '';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generates a card for a given Moment.
|
||||
*
|
||||
* @* @param Integer $post_id "Retrieves information from the database using this ID."
|
||||
* @* @return String $html "The HTML card component for a Moment."
|
||||
*/
|
||||
function essayCard(Post $post)
|
||||
{
|
||||
$topics_html = '';
|
||||
$topics_html .= '<div class="tag_row">';
|
||||
$topics_html .= '<a href="/articles.php?view=filter&tag=' . $row['tag'] . '" class="tag">#' . $row['tag'] . '</a>';
|
||||
$topics_html .= '</div>';
|
||||
|
||||
$author = exec_stmt('SELECT user_id, username, profile_picture FROM user WHERE user_id = ?', 'i', $essay['author_id'])->fetch_assoc();
|
||||
|
||||
$html = '
|
||||
<div class="article_card">
|
||||
<div class="row_space_between">
|
||||
<h4>' . $essay['title'] . '</h4>
|
||||
<div class="card_info_box">
|
||||
<div class="col-right">
|
||||
<a href="user.php?view=display&user_id=' . $author['user_id'] . '">Written by: ' . $author['username'] . '</a>
|
||||
<small>Published: ' . $essay['published_at'] . '</small>
|
||||
<small>Updated: ' . $essay['updated_at'] . '</small>
|
||||
</div>
|
||||
<div class="card_pic_box">
|
||||
<img src="' . $_ENV['PROFILE_IMAGES_PQ_PATH'] . $author['profile_picture'] . '" class="card_profile_picture">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<p>' . $essay['excerpt'] . '</p>
|
||||
<div class="row_space_between">
|
||||
<a href="/articles.php?view=read&article_id=' . $essay['article_id'] . '" class="button">Read More</a>
|
||||
<div class="tag_box">' . $topics_html . '</div>
|
||||
</div>
|
||||
</div>
|
||||
';
|
||||
|
||||
return $html;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
</body>
|
||||
|
||||
<footer>
|
||||
<script src="js/util.js"></script>
|
||||
<script src="js/nav.js" defer></script>
|
||||
<script src="js/user.js" defer></script>
|
||||
|
||||
<?php
|
||||
// <script src="js/theme.js" defer></script>
|
||||
if ($_SERVER['SCRIPT_NAME'] == '/spaces.php' && isset($_SESSION['user'])) {
|
||||
echo '
|
||||
<script src="js/actionBar.js" defer></script>
|
||||
<script src="js/dropdown.js" defer></script>
|
||||
';
|
||||
}
|
||||
?>
|
||||
</footer>
|
||||
|
||||
</html>
|
||||
@@ -5,13 +5,14 @@
|
||||
<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="icon" type="image/x-icon" href="data/vintagecoding-favicon.png" </link>
|
||||
<link rel="icon" type="image/x-icon" href="data/vintagecoding-favicon.png">
|
||||
|
||||
<?php
|
||||
if (!isset($_SESSION['theme']) || $_SESSION['theme'] == 'dark')
|
||||
if (!isset($_SESSION['theme']) || $_SESSION['theme'] == 'dark')
|
||||
echo '<link href="css/dark.css" rel="stylesheet" type="text/css">';
|
||||
else
|
||||
else
|
||||
echo '<link href="css/light.css" rel="stylesheet" type="text/css">';
|
||||
?>
|
||||
?>
|
||||
|
||||
</head>
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
$current_page = $_SERVER['SCRIPT_NAME'];
|
||||
$nav = '
|
||||
<nav>
|
||||
<div class="row space_between no_margin full_width">
|
||||
<div class="site_navigation">
|
||||
<ul>
|
||||
<li><a href="/spaces.php?view=list"' . ($current_page == '/spaces.php' ? ' class="underline"' : '') . '>Spaces</a></li>
|
||||
';
|
||||
|
||||
/* <li><a href="/index.php"' . ($current_page == '/index.php' ? ' class="underline"' : '') . '>Home</a></li> */
|
||||
if (isset($_SESSION['user'])) {
|
||||
/* $nav .= ' */
|
||||
/* <li><a href="/user.php?view=display&user_id=' . unserialize($_SESSION['user'])->getId() . '"' . ($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> */
|
||||
/* '; */
|
||||
|
||||
if (unserialize($_SESSION['user'])->getRole() <= developer) {
|
||||
$nav .= '
|
||||
<li><a href="/admin.php?view=users"' . ($current_page == '/admin.php' ? ' class="underline"' : '') . '>Admin</a></li>
|
||||
';
|
||||
}
|
||||
}
|
||||
|
||||
$nav .= '
|
||||
</ul>
|
||||
</div>
|
||||
<div class="nav_right_hand">
|
||||
<form method="post">
|
||||
';
|
||||
|
||||
$theme_toggle = '';
|
||||
if ($_SESSION['theme'] == 'dark')
|
||||
$theme_toggle = 'light';
|
||||
else
|
||||
$theme_toggle = 'dark';
|
||||
|
||||
$nav .= '
|
||||
<button id="theme_toggle" value="' . $theme_toggle . '" name="theme"><i class="nf ' . ($theme_toggle == 'dark' ? 'nf-oct-moon' : 'nf-oct-sun') . '"></i></button>
|
||||
</form>
|
||||
';
|
||||
|
||||
if (isset($_SESSION['user'])) {
|
||||
$nav .= '
|
||||
<p class="link underline" id="logout">Log Out</p>
|
||||
';
|
||||
} else {
|
||||
$nav .= '
|
||||
<p class="link underline" id="login">Login</p>
|
||||
<p class="link underline" id="signup">Sign Up</p>
|
||||
';
|
||||
}
|
||||
|
||||
$nav .= '
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
<div id="notificationModal"></div>
|
||||
<div id="stdModal"></div>
|
||||
';
|
||||
|
||||
echo $nav;
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
function slideshow(array $images) {}
|
||||
@@ -1,70 +0,0 @@
|
||||
</body>
|
||||
|
||||
<footer>
|
||||
<?php
|
||||
function get_args_from_url()
|
||||
{
|
||||
$args = [];
|
||||
$arr = explode('&', $_SERVER['QUERY_STRING']);
|
||||
|
||||
foreach ($arr as $a) {
|
||||
$tmp = explode('=', $a);
|
||||
$key = $tmp[0];
|
||||
$value = $tmp[1];
|
||||
|
||||
$args[$key] = $value;
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
if ($_SERVER['SCRIPT_NAME'] == '/user.php') {
|
||||
$args = get_args_from_url();
|
||||
|
||||
if (isset($args['view'])) {
|
||||
if ($args['view'] == 'signup') {
|
||||
echo '
|
||||
<script src="js/profile_picture_cropper_modal.js"></script>
|
||||
<script src="js/upload.js"></script>
|
||||
';
|
||||
} else if ($args['view'] == 'display') {
|
||||
echo '
|
||||
<script src="js/user_actions_modal.js"></script>
|
||||
<script src="js/upload.js"></script>
|
||||
';
|
||||
}
|
||||
}
|
||||
} else if ($_SERVER['SCRIPT_NAME'] == '/admin.php') {
|
||||
echo '
|
||||
<script src="js/clickable_rows.js"></script>
|
||||
';
|
||||
$args = get_args_from_url();
|
||||
|
||||
if (isset($args['view'])) {
|
||||
if ($args['view'] == 'users') {
|
||||
echo '
|
||||
<script src="js/upload.js"></script>
|
||||
';
|
||||
}
|
||||
}
|
||||
} else if ($_SERVER['SCRIPT_NAME'] == '/articles.php') {
|
||||
$args = get_args_from_url();
|
||||
|
||||
if (isset($args['view'])) {
|
||||
if ($args['view'] == 'compose') {
|
||||
echo '
|
||||
<script src="js/md_preview.js"></script>
|
||||
';
|
||||
}
|
||||
}
|
||||
} else if ($_SERVER['SCRIPT_NAME'] == '/todo.php') {
|
||||
echo '<script src="js/todo.js"></script>';
|
||||
}
|
||||
|
||||
echo '
|
||||
<script src="js/override_browser_styles.js"></script>
|
||||
';
|
||||
?>
|
||||
</footer>
|
||||
|
||||
</html>
|
||||
@@ -1,60 +0,0 @@
|
||||
<?php
|
||||
$current_page = $_SERVER['SCRIPT_NAME'];
|
||||
$nav = '
|
||||
<nav>
|
||||
<div class="row_space_between no_margin">
|
||||
<div class="site_navigation">
|
||||
<ul>
|
||||
<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>
|
||||
';
|
||||
|
||||
if (isset($_SESSION['role_id']) && $_SESSION['role_id'] <= admin) {
|
||||
$nav .= '
|
||||
<li><a href="/admin.php?view=users"' . ($current_page == '/admin.php' ? ' class="underline"' : '') . '>Admin</a></li>
|
||||
';
|
||||
}
|
||||
|
||||
if (isset($_SESSION['user_id'])) {
|
||||
$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="/todo.php?view=display"' . ($current_page == '/todo.php' ? ' class="underline"' : '') . '>Todos</a></li>
|
||||
';
|
||||
}
|
||||
|
||||
$nav .= '
|
||||
</ul>
|
||||
</div>
|
||||
<div class="nav_right_hand">
|
||||
<form method="post">
|
||||
';
|
||||
|
||||
$theme_toggle = '';
|
||||
if ($_SESSION['theme'] == 'dark')
|
||||
$theme_toggle = 'light';
|
||||
else
|
||||
$theme_toggle = 'dark';
|
||||
|
||||
$nav .= '
|
||||
<button id="theme_toggle" value="' . $theme_toggle . '" name="theme"><i class="nf ' . ($theme_toggle == 'dark' ? 'nf-oct-moon' : 'nf-oct-sun') . '"></i></button>
|
||||
</form>
|
||||
';
|
||||
|
||||
if (isset($_SESSION['username'])) {
|
||||
$nav .= '
|
||||
<a href="user.php?view=logout">Log Out</a>
|
||||
';
|
||||
} else {
|
||||
$nav .= '
|
||||
<a href="user.php?view=login">Login</a>
|
||||
<a href="user.php?view=signup">Sign Up</a>
|
||||
';
|
||||
}
|
||||
|
||||
$nav .= '
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
';
|
||||
|
||||
echo $nav;
|
||||
@@ -1,28 +0,0 @@
|
||||
<?php
|
||||
function login_form($error_msg = '')
|
||||
{
|
||||
$form = '
|
||||
<div class="form_card">
|
||||
<h3 class="underline">Log In</h3>
|
||||
<form method="post">
|
||||
<input type="hidden" name="form_id" value="login_form">
|
||||
|
||||
<label for="username">Username / Email</label>
|
||||
<input id="username" name="username" spellcheck="false" required>
|
||||
|
||||
<label for="password">Password</label>
|
||||
<input id="password" name="password" type="password" spellcheck="false" required>
|
||||
|
||||
<label class="form_checkbox_container">Stay Logged In?
|
||||
<input name="stay_logged_in" type="checkbox" value="true">
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
|
||||
<input class="button" type="submit" value="Log In">
|
||||
' . $error_msg . '
|
||||
</form>
|
||||
</div>
|
||||
';
|
||||
|
||||
return $form;
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
<?php
|
||||
function signup_form($error_msg = '')
|
||||
{
|
||||
$form = '
|
||||
<div class="form_card">
|
||||
<h3 class="underline">Sign Up</h3>
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<input type="hidden" name="form_id" value="signup_form">
|
||||
<input type="hidden" name="crop_x" value="" id="crop_x">
|
||||
<input type="hidden" name="crop_y" value="" id="crop_y">
|
||||
<input type="hidden" name="crop_width" value="" id="crop_width">
|
||||
<input name="required_field" id="required_field" value="">
|
||||
|
||||
<label for="username">Username</label>
|
||||
<input id="username" name="username" required>
|
||||
|
||||
<label for="email">Email Address</label>
|
||||
<input id="email" name="email" required>
|
||||
|
||||
<label for="password">Password</label>
|
||||
<input id="password" name="password" type="password" required>
|
||||
|
||||
<label for="verify_password">Verify Password</label>
|
||||
<input id="verify_password" name="verify_password" type="password" required>
|
||||
|
||||
<label for="profile_picture_input" class="upload_button modal_button" id="profile_cropper_button">Upload a Profile Picture</label>
|
||||
<input id="profile_picture_input" class="file_input" name="profile_picture" type="file" accept="image/png, image/jpeg, image/jpg">
|
||||
<small class="file_input_feedback">No file selected.</small>
|
||||
|
||||
<label class="form_checkbox_container">Stay Logged In?
|
||||
<input name="stay_logged_in" type="checkbox" value="true">
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
|
||||
<input class="button" type="submit" value="Sign Up">
|
||||
' . $error_msg . '
|
||||
</form>
|
||||
|
||||
<div id="modal" class="modal">
|
||||
<div id="display_modal"></div>
|
||||
</div>
|
||||
|
||||
<div style="display: none;">
|
||||
<div id="profile_cropper" class="modal_form">' . profile_cropper() . '</div>
|
||||
</div>
|
||||
</div>
|
||||
';
|
||||
|
||||
return $form;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
include_once 'components/article/card.php';
|
||||
include_once 'components/core/card.php';
|
||||
|
||||
function user_view($user_id)
|
||||
{
|
||||
|
||||
+8
-2
@@ -5,12 +5,18 @@
|
||||
"require": {
|
||||
"erusev/parsedown": "^1.7",
|
||||
"vlucas/phpdotenv": "^5.6",
|
||||
"wildbit/postmark-php": "^6.0"
|
||||
"wildbit/postmark-php": "^6.0",
|
||||
"laudis/neo4j-php-client": "^3.2"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "Josh Ashton",
|
||||
"email": "me@joshashton.dev"
|
||||
}
|
||||
]
|
||||
],
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"php-http/discovery": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+14
-351
@@ -1,6 +1,6 @@
|
||||
@font-face {
|
||||
font-family: 'Hack Nerd Font Mono';
|
||||
src: url('/data/resources/HackNerdFontMono-Regular.woff');
|
||||
font-family: "Hack Nerd Font Mono";
|
||||
src: url("/data/resources/HackNerdFontMono-Regular.woff");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
@@ -14,167 +14,11 @@ body {
|
||||
padding-bottom: 50px;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
p,
|
||||
small,
|
||||
label,
|
||||
input,
|
||||
input:-webkit-autofill,
|
||||
input:-webkit-autofill:hover,
|
||||
input:-webkit-autofill:focus,
|
||||
textarea,
|
||||
a,
|
||||
.modal_button,
|
||||
th,
|
||||
td,
|
||||
li,
|
||||
select,
|
||||
option,
|
||||
span {
|
||||
font-family: 'Hack Nerd Font Mono', Hack, sans-serif;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3vw;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 2.5vw;
|
||||
}
|
||||
|
||||
h3,
|
||||
h3 a {
|
||||
font-size: 2vw;
|
||||
}
|
||||
|
||||
h4,
|
||||
h4 a {
|
||||
font-size: 1.75vw;
|
||||
}
|
||||
|
||||
h5,
|
||||
h5 a {
|
||||
font-size: 1.5vw;
|
||||
}
|
||||
|
||||
h6,
|
||||
h6 a {
|
||||
font-size: 1.25vw;
|
||||
}
|
||||
|
||||
p,
|
||||
a,
|
||||
label,
|
||||
li,
|
||||
.modal_button,
|
||||
.button,
|
||||
span {
|
||||
font-size: 1vw;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: .75vw;
|
||||
}
|
||||
|
||||
a,
|
||||
.modal_button {
|
||||
color: orange;
|
||||
transition-duration: 1s;
|
||||
}
|
||||
|
||||
a {
|
||||
-webkit-tap-highlight-color: transparent !important;
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
a.fill_div {
|
||||
display: block;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
nav {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
position: sticky;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
backdrop-filter: blur(50px);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
nav ul {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
nav ul li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
nav ul li a {
|
||||
font-size: 2vw;
|
||||
font-weight: 800;
|
||||
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 15px;
|
||||
|
||||
transition-duration: 500ms;
|
||||
}
|
||||
|
||||
nav ul li a:hover {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
nav form {
|
||||
padding: 15px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.nav_right_hand {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.nav_right_hand * {
|
||||
margin: 0px 15px 0px 15px;
|
||||
}
|
||||
|
||||
code {
|
||||
padding: 1px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.line {
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.center-h {
|
||||
margin: 0 auto;
|
||||
}
|
||||
@@ -238,7 +82,7 @@ tbody tr {
|
||||
}
|
||||
|
||||
tbody tr:hover {
|
||||
outline: solid 3px orange;
|
||||
outline: solid 3px red;
|
||||
}
|
||||
|
||||
tbody tr td {
|
||||
@@ -271,15 +115,6 @@ table tr td label {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.button {
|
||||
background-color: transparent;
|
||||
padding: 15px;
|
||||
text-decoration: none;
|
||||
border-radius: 12px;
|
||||
transition-duration: 1s;
|
||||
border: 3px solid orange;
|
||||
}
|
||||
|
||||
.narrow {
|
||||
width: 20%;
|
||||
}
|
||||
@@ -288,7 +123,7 @@ table tr td label {
|
||||
margin: 15px;
|
||||
padding: 10px;
|
||||
border-radius: 18px;
|
||||
border: 2px solid orange;
|
||||
border: 2px solid red;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@@ -307,26 +142,11 @@ table tr td label {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.underline {
|
||||
text-decoration: underline;
|
||||
text-decoration-thickness: 3px;
|
||||
text-decoration-color: orange;
|
||||
}
|
||||
|
||||
i {
|
||||
border: none;
|
||||
background: transparent;
|
||||
font-size: 1.5vw;
|
||||
transition-duration: 500ms;
|
||||
}
|
||||
|
||||
#theme_toggle {
|
||||
background: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
i:hover {
|
||||
color: orange;
|
||||
.divLink {
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.article {
|
||||
@@ -347,122 +167,15 @@ i:hover {
|
||||
justify-content: left;
|
||||
}
|
||||
|
||||
input,
|
||||
.autofilled,
|
||||
input:-webkit-autofill,
|
||||
textarea:-webkit-autofill,
|
||||
input:-webkit-autofill:hover,
|
||||
textarea:-webkit-autofill:hover,
|
||||
input:-webkit-autofill:focus,
|
||||
select,
|
||||
option,
|
||||
textarea {
|
||||
/* Try this first */
|
||||
border-radius: 12px;
|
||||
width: 100%;
|
||||
padding: 15px;
|
||||
margin: 15px 15px 15px 0px;
|
||||
box-sizing: border-box;
|
||||
transition-duration: 500ms;
|
||||
resize: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
input[type="datetime_local"] {
|
||||
color: white;
|
||||
}
|
||||
|
||||
input:focus,
|
||||
textarea:focus,
|
||||
input:hover,
|
||||
textarea:hover {
|
||||
border: 3px solid orange;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
border-radius: 18px;
|
||||
height: 70%;
|
||||
}
|
||||
|
||||
.checkboxes {
|
||||
height: max-content;
|
||||
}
|
||||
|
||||
input[type="radio"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.form_checkbox_container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
padding-left: 35px;
|
||||
margin: 15px 15px 15px 0px;
|
||||
cursor: pointer;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
|
||||
height: 29px;
|
||||
width: max-content;
|
||||
|
||||
}
|
||||
|
||||
.checkmark {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 25px;
|
||||
width: 25px;
|
||||
|
||||
}
|
||||
|
||||
.form_checkbox_container input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
height: 0;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
/* Create the checkmark/indicator (hidden when not checked) */
|
||||
.checkmark:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Show the checkmark when checked */
|
||||
.form_checkbox_container input:checked~.checkmark:after {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* When the checkbox is checked, add a blue background */
|
||||
.form_checkbox_container input:checked~.checkmark {
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
/* Style the checkmark/indicator */
|
||||
.form_checkbox_container .checkmark:after {
|
||||
left: 9px;
|
||||
top: 5px;
|
||||
width: 5px;
|
||||
height: 10px;
|
||||
border: solid white;
|
||||
border-width: 0 3px 3px 0;
|
||||
-webkit-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
input[type="file"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.upload_button {
|
||||
.uploadButton {
|
||||
border-radius: 12px;
|
||||
display: inline-block;
|
||||
padding: 6px 12px;
|
||||
@@ -557,7 +270,7 @@ input[type="file"] {
|
||||
|
||||
.modal_close:hover,
|
||||
.modal_close:focus {
|
||||
color: orange;
|
||||
color: red;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -581,7 +294,7 @@ input[type="file"] {
|
||||
height: 128px;
|
||||
width: 128px;
|
||||
|
||||
outline: dashed 4px orange;
|
||||
outline: dashed 4px red;
|
||||
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
@@ -593,7 +306,7 @@ input[type="file"] {
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background-color: orange;
|
||||
background-color: red;
|
||||
border-radius: 50%;
|
||||
cursor: nwse-resize;
|
||||
/* Default cursor for resizing */
|
||||
@@ -673,7 +386,7 @@ input[type="file"] {
|
||||
|
||||
::selection {
|
||||
color: black;
|
||||
background: orange;
|
||||
background: red;
|
||||
}
|
||||
|
||||
.grid-2x1 {
|
||||
@@ -681,7 +394,6 @@ input[type="file"] {
|
||||
width: 90%;
|
||||
display: grid;
|
||||
grid-template-columns: 50% 50%;
|
||||
|
||||
}
|
||||
|
||||
.grid-2x1 .form_card,
|
||||
@@ -709,55 +421,6 @@ hr {
|
||||
margin: 15px 0px 15px 0px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
background-color: transparent;
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
display: none;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: orange;
|
||||
border-radius: 9px;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
position: relative;
|
||||
display: block;
|
||||
margin-right: 15px;
|
||||
padding: 15px;
|
||||
border-radius: 9px;
|
||||
}
|
||||
|
||||
.dropdown_content {
|
||||
display: none;
|
||||
position: absolute;
|
||||
min-width: 50px;
|
||||
padding: 15px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.dropdown:hover .dropdown_content {
|
||||
display: block;
|
||||
margin-left: -15px;
|
||||
margin-top: 15px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.dropdown_content form * {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@media screen and (max-width: 992px) {
|
||||
body {
|
||||
padding-bottom: 160px;
|
||||
|
||||
+10
-75
@@ -11,10 +11,12 @@ h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
p,
|
||||
small,
|
||||
label,
|
||||
span {
|
||||
span,
|
||||
i {
|
||||
color: white;
|
||||
}
|
||||
|
||||
@@ -31,24 +33,9 @@ nav ul li a {
|
||||
color: white;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: #2F2F2F;
|
||||
}
|
||||
|
||||
.line {
|
||||
background-color: white;
|
||||
border-top: 1px solid white;
|
||||
}
|
||||
|
||||
.article_card,
|
||||
.form_card,
|
||||
.view_card {
|
||||
border: 5px solid white;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
table tr {
|
||||
outline: solid 3px white;
|
||||
border-top: 2px solid white;
|
||||
}
|
||||
|
||||
.button {
|
||||
@@ -57,21 +44,13 @@ table tr {
|
||||
|
||||
.button:hover,
|
||||
.button:hover i {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
.tag {
|
||||
color: white;
|
||||
color: red;
|
||||
}
|
||||
|
||||
#theme_toggle {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.article ul li {
|
||||
color: white;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea {
|
||||
background-color: transparent;
|
||||
@@ -95,57 +74,13 @@ select:-webkit-autofill {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.upload_button {
|
||||
border: 3px solid white;
|
||||
.std_border,
|
||||
.med_border,
|
||||
.sm_border {
|
||||
border-color: white;
|
||||
}
|
||||
|
||||
/* .form_card:hover, */
|
||||
/* .form_card:focus, */
|
||||
/* .article_card:hover, */
|
||||
/* .article_card:focus { */
|
||||
/* box-shadow: 0 2px 4px 0 white, 0 4px 8px 0 white; */
|
||||
/* } */
|
||||
|
||||
.modal {
|
||||
background-color: black;
|
||||
background-color: rgba(0, 0, 0, 0.9);
|
||||
}
|
||||
|
||||
.modal_close {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.user_actions {
|
||||
border: 3px solid white;
|
||||
}
|
||||
|
||||
#floating_compose {
|
||||
border: 2px solid white;
|
||||
}
|
||||
|
||||
#floating_compose,
|
||||
#floating_compose * {
|
||||
background-color: white;
|
||||
color: black;
|
||||
transition-duration: 500ms;
|
||||
}
|
||||
|
||||
#floating_compose:hover,
|
||||
#floating_compose:hover * {
|
||||
background-color: black;
|
||||
color: orange;
|
||||
}
|
||||
|
||||
#floating_compose:hover {
|
||||
border: 2px solid orange;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
border: 2px solid white;
|
||||
}
|
||||
|
||||
.dropdown_content {
|
||||
background-color: black;
|
||||
.uploadButton {
|
||||
border: 2px solid white;
|
||||
}
|
||||
|
||||
|
||||
+10
-72
@@ -14,7 +14,8 @@ h5,
|
||||
p,
|
||||
small,
|
||||
label,
|
||||
span {
|
||||
span,
|
||||
i {
|
||||
color: black;
|
||||
}
|
||||
|
||||
@@ -32,23 +33,12 @@ nav ul li a {
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: #C6C6C6;
|
||||
background-color: #c6c6c6;
|
||||
}
|
||||
|
||||
.line {
|
||||
background-color: black;
|
||||
border-top: 1px solid black;
|
||||
}
|
||||
|
||||
.article_card,
|
||||
.form_card,
|
||||
.view_card {
|
||||
border: 5px solid black;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
table tr {
|
||||
outline: solid 3px black;
|
||||
border-top: 2px solid black;
|
||||
}
|
||||
|
||||
.button {
|
||||
@@ -57,21 +47,13 @@ table tr {
|
||||
|
||||
.button:hover,
|
||||
.button:hover * {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
.tag {
|
||||
color: black;
|
||||
color: red;
|
||||
}
|
||||
|
||||
#theme_toggle {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.article ul li {
|
||||
color: black;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea {
|
||||
background-color: transparent;
|
||||
@@ -95,57 +77,13 @@ select:-webkit-autofill {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.upload_button {
|
||||
border: 3px solid black;
|
||||
.std_border,
|
||||
.med_border,
|
||||
.sm_border {
|
||||
border-color: black;
|
||||
}
|
||||
|
||||
/* .form_card:hover, */
|
||||
/* .form_card:focus, */
|
||||
/* .article_card:hover, */
|
||||
/* .article_card:focus { */
|
||||
/* box-shadow: 0 2px 4px 0 black, 0 4px 8px 0 black; */
|
||||
/* } */
|
||||
|
||||
.modal {
|
||||
background-color: white;
|
||||
background-color: rgba(256, 256, 256, 0.9);
|
||||
}
|
||||
|
||||
.modal_close {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.user_actions {
|
||||
border: 3px solid black;
|
||||
}
|
||||
|
||||
#floating_compose {
|
||||
border: 2px solid black;
|
||||
}
|
||||
|
||||
#floating_compose,
|
||||
#floating_compose * {
|
||||
background-color: black;
|
||||
color: white;
|
||||
transition-duration: 500ms;
|
||||
}
|
||||
|
||||
#floating_compose:hover,
|
||||
#floating_compose:hover * {
|
||||
background-color: white;
|
||||
color: orange;
|
||||
}
|
||||
|
||||
#floating_compose:hover {
|
||||
border: 2px solid orange;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
border: 2px solid black;
|
||||
}
|
||||
|
||||
.dropdown_content {
|
||||
background-color: white;
|
||||
.uploadButton {
|
||||
border: 2px solid black;
|
||||
}
|
||||
|
||||
|
||||
+503
-53
@@ -1,8 +1,258 @@
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
p,
|
||||
small,
|
||||
label,
|
||||
input,
|
||||
input:-webkit-autofill,
|
||||
input:-webkit-autofill:hover,
|
||||
input:-webkit-autofill:focus,
|
||||
textarea,
|
||||
a,
|
||||
.modal_button,
|
||||
th,
|
||||
td,
|
||||
li,
|
||||
select,
|
||||
option,
|
||||
span {
|
||||
font-family: "Hack Nerd Font Mono", Hack, sans-serif;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3vw;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 2.5vw;
|
||||
}
|
||||
|
||||
h3,
|
||||
h3 a {
|
||||
font-size: 2vw;
|
||||
}
|
||||
|
||||
h4,
|
||||
h4 a {
|
||||
font-size: 1.75vw;
|
||||
}
|
||||
|
||||
h5,
|
||||
h5 a {
|
||||
font-size: 1.5vw;
|
||||
}
|
||||
|
||||
h6,
|
||||
h6 a {
|
||||
font-size: 1.25vw;
|
||||
}
|
||||
|
||||
p,
|
||||
a,
|
||||
label,
|
||||
li,
|
||||
.modal_button,
|
||||
.button,
|
||||
span {
|
||||
font-size: 1vw;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.75vw;
|
||||
}
|
||||
|
||||
a,
|
||||
.modal_button {
|
||||
color: red;
|
||||
transition-duration: 1s;
|
||||
}
|
||||
|
||||
a {
|
||||
-webkit-tap-highlight-color: transparent !important;
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
a.fillDiv {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.button {
|
||||
background-color: transparent;
|
||||
padding: 15px;
|
||||
text-decoration: none;
|
||||
border-radius: 12px;
|
||||
transition-duration: 1s;
|
||||
border: 3px solid red;
|
||||
}
|
||||
|
||||
.link {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.underline {
|
||||
text-decoration: underline;
|
||||
text-decoration-thickness: 3px;
|
||||
text-decoration-color: red;
|
||||
}
|
||||
|
||||
i {
|
||||
border: none;
|
||||
background: transparent;
|
||||
font-size: 1.5vw;
|
||||
transition-duration: 500ms;
|
||||
}
|
||||
|
||||
#theme_toggle {
|
||||
background: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
i:hover {
|
||||
color: red;
|
||||
}
|
||||
|
||||
/********** Forms ************/
|
||||
|
||||
input,
|
||||
.autofilled,
|
||||
input:-webkit-autofill,
|
||||
textarea:-webkit-autofill,
|
||||
input:-webkit-autofill:hover,
|
||||
textarea:-webkit-autofill:hover,
|
||||
input:-webkit-autofill:focus,
|
||||
select,
|
||||
option,
|
||||
textarea {
|
||||
/* Try this first */
|
||||
border-radius: 12px;
|
||||
width: 100%;
|
||||
padding: 15px;
|
||||
margin: 15px 15px 15px 0px;
|
||||
box-sizing: border-box;
|
||||
transition-duration: 500ms;
|
||||
resize: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
input:focus,
|
||||
textarea:focus,
|
||||
input:hover,
|
||||
textarea:hover {
|
||||
border: 3px solid red;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
border-radius: 18px;
|
||||
height: 70%;
|
||||
}
|
||||
|
||||
input[type="radio"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.form_checkbox_container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
padding-left: 35px;
|
||||
margin: 15px 15px 15px 0px;
|
||||
cursor: pointer;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
|
||||
height: 29px;
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
.checkmark {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 25px;
|
||||
width: 25px;
|
||||
}
|
||||
|
||||
.form_checkbox_container input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
height: 0;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
/* Create the checkmark/indicator (hidden when not checked) */
|
||||
.checkmark:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Show the checkmark when checked */
|
||||
.form_checkbox_container input:checked ~ .checkmark:after {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* When the checkbox is checked, add a blue background */
|
||||
.form_checkbox_container input:checked ~ .checkmark {
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
/* Style the checkmark/indicator */
|
||||
.form_checkbox_container .checkmark:after {
|
||||
left: 9px;
|
||||
top: 5px;
|
||||
width: 5px;
|
||||
height: 10px;
|
||||
border: solid white;
|
||||
border-width: 0 3px 3px 0;
|
||||
-webkit-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
/********** Width & Sizing **********/
|
||||
.full_width {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.std_width {
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
.med_width {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.sm_width {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
/********** Borders & Outlines **********/
|
||||
.std_border,
|
||||
.med_border,
|
||||
@@ -11,33 +261,34 @@
|
||||
}
|
||||
|
||||
.std_border {
|
||||
border: 3px solid white;
|
||||
border: 3px solid black;
|
||||
}
|
||||
|
||||
.med_border {
|
||||
border: 2px solid white;
|
||||
border: 2px solid black;
|
||||
}
|
||||
|
||||
.sm_border {
|
||||
border: 1px solid white;
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
.debug {
|
||||
border: 1px solid red;
|
||||
}
|
||||
|
||||
.line {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
/********** Rows & Columns **********/
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.row_space_between {
|
||||
display: flex;
|
||||
.space_between {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
margin: 15px 0px 15px 0px;
|
||||
}
|
||||
|
||||
.column {
|
||||
@@ -46,10 +297,15 @@
|
||||
}
|
||||
|
||||
.center {
|
||||
margin: 0 auto;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.rel {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/********** Margins & Padding **********/
|
||||
.margin {
|
||||
margin: 15px;
|
||||
@@ -103,72 +359,266 @@
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
/********** FORMS **********/
|
||||
/*********** Nav **********/
|
||||
nav {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
position: sticky;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
backdrop-filter: blur(50px);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
nav ul {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
nav ul li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
nav ul li a {
|
||||
font-size: 2vw;
|
||||
font-weight: 800;
|
||||
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 15px;
|
||||
|
||||
transition-duration: 500ms;
|
||||
}
|
||||
|
||||
nav ul li a:hover {
|
||||
color: red;
|
||||
}
|
||||
|
||||
nav form {
|
||||
padding: 15px;
|
||||
|
||||
/********** TODO ITEMS **********/
|
||||
.todo_display {
|
||||
margin: 0 auto;
|
||||
margin-top: 25px;
|
||||
width: 80%;
|
||||
height: 80vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#todo_actions {
|
||||
padding: 15px;
|
||||
border: 2px solid white;
|
||||
border-radius: 8px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 25px;
|
||||
|
||||
width: 100%;
|
||||
.nav_right_hand {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-evenly;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.todo_category_window {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
.nav_right_hand * {
|
||||
margin: 0px 15px 0px 15px;
|
||||
}
|
||||
|
||||
/*********** Dropdowns **********/
|
||||
.dropdown {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.dropdownContent {
|
||||
display: none;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
/******* Space Selector *********/
|
||||
#postSpaces {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/************ Modals ************/
|
||||
#stdModal {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-x: scroll;
|
||||
overflow-y: none;
|
||||
}
|
||||
display: none;
|
||||
backdrop-filter: blur(20px);
|
||||
|
||||
.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;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.todo_item {
|
||||
width: 100%;
|
||||
#stdModal > * {
|
||||
}
|
||||
|
||||
.todo_item_details {
|
||||
.glass {
|
||||
background-color: transparent;
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
|
||||
#actionBar {
|
||||
position: absolute;
|
||||
bottom: 3.5%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -5%);
|
||||
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
/********** Animations **********/
|
||||
@view-transition {
|
||||
navigation: auto;
|
||||
animation-duration: 1s;
|
||||
}
|
||||
|
||||
::view-transition-old(root) {
|
||||
animation: fade-out 1s forwards;
|
||||
}
|
||||
|
||||
::view-transition-new(root) {
|
||||
animation: fade-in 1s forwards;
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-out {
|
||||
from {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/********** Misc. **********/
|
||||
::-webkit-scrollbar {
|
||||
background-color: transparent;
|
||||
border-radius: 18px;
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.modal_activation_area {}
|
||||
::-webkit-scrollbar-track {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.modal_activation_area:hover {
|
||||
cursor: pointer;
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: red;
|
||||
border-radius: 9px;
|
||||
}
|
||||
|
||||
#backButton {
|
||||
position: absolute;
|
||||
top: 11%;
|
||||
left: 8%;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
#backButton:hover > i {
|
||||
color: red;
|
||||
}
|
||||
|
||||
/********** Mobile **********/
|
||||
@media screen and (max-width: 1200px) {
|
||||
h1 {
|
||||
font-size: 6vw;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 5vw;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 4vw;
|
||||
}
|
||||
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: 3.5vw;
|
||||
}
|
||||
|
||||
p,
|
||||
a,
|
||||
nav ul li a,
|
||||
li,
|
||||
i,
|
||||
span,
|
||||
input,
|
||||
label,
|
||||
input[type="submit"] {
|
||||
font-size: 2.5vw;
|
||||
}
|
||||
|
||||
.std_width,
|
||||
.stdWidth {
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
.med_width,
|
||||
.medWidth {
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
nav {
|
||||
position: fixed;
|
||||
bottom: -2px;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 25px 0px 25px 0px;
|
||||
backdrop-filter: blur(50px);
|
||||
}
|
||||
|
||||
nav ul li a {
|
||||
font-size: 3vw;
|
||||
}
|
||||
|
||||
.site_navigation ul {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
nav .row_space_between .no_margin {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
.nav_right_hand {
|
||||
flex-direction: row-reverse;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.nav_right_hand * {
|
||||
margin: 0px 0px 0px 15px;
|
||||
}
|
||||
|
||||
#backButton {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#actionBar {
|
||||
bottom: 125px;
|
||||
}
|
||||
|
||||
.modalContent {
|
||||
max-height: 600px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 258 KiB |
+330
-29
@@ -1,42 +1,343 @@
|
||||
<?php
|
||||
include 'functions/functions.php';
|
||||
include 'functions/init.php';
|
||||
|
||||
if (isset($_POST['ajax_id'])) {
|
||||
switch ($_POST['ajax_id']) {
|
||||
case 'todo':
|
||||
handle_todo();
|
||||
error_log('RECEIVED: ' . pretty_dump($_POST));
|
||||
error_log('ALSO: ' . pretty_dump($_FILES));
|
||||
|
||||
if (isset($_POST['ajaxId'])) {
|
||||
switch ($_POST['ajaxId']) {
|
||||
case 'login':
|
||||
handle_login();
|
||||
break;
|
||||
case 'loginHTML':
|
||||
handleLoginHTML();
|
||||
break;
|
||||
case 'signupHTML':
|
||||
handleSignupHTML();
|
||||
break;
|
||||
case 'usernameCheck':
|
||||
handleUsernameCheck();
|
||||
break;
|
||||
case 'logout':
|
||||
User::logout();
|
||||
break;
|
||||
case 'newPostHTML':
|
||||
handleNewPostHTML();
|
||||
break;
|
||||
case 'newSpaceHTML':
|
||||
handleNewSpaceHTML();
|
||||
break;
|
||||
case 'editPostHTML':
|
||||
handleEditPostHTML();
|
||||
break;
|
||||
case 'deletePost':
|
||||
handleDeletePost();
|
||||
break;
|
||||
case 'deleteSpace':
|
||||
handleDeleteSpace();
|
||||
break;
|
||||
case 'viewEssay':
|
||||
handleViewEssay();
|
||||
break;
|
||||
case 'viewTodo':
|
||||
handleViewTodo();
|
||||
break;
|
||||
case 'todoStatusChange':
|
||||
handleTodoStatusChange();
|
||||
break;
|
||||
}
|
||||
} else if (isset($_POST['formID'])) {
|
||||
switch ($_POST['formID']) {
|
||||
case 'spaceNew':
|
||||
break;
|
||||
case 'signup':
|
||||
handleSignup();
|
||||
break;
|
||||
case 'newPost':
|
||||
handleNewPost();
|
||||
break;
|
||||
case 'editPost':
|
||||
handleEditPost();
|
||||
break;
|
||||
case 'newSpace':
|
||||
handleNewSpace();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$response = [
|
||||
'error' => 'Malformed URI request.',
|
||||
];
|
||||
|
||||
echo json_encode($response);
|
||||
if (!isset($_POST['redirect']))
|
||||
header('Location: .');
|
||||
else
|
||||
header('Location: ' . $_POST['redirect']);
|
||||
}
|
||||
|
||||
function handle_todo()
|
||||
function handleViewTodo()
|
||||
{
|
||||
include 'functions/todo_functions.php';
|
||||
$response = ['log' => []];
|
||||
if (isset($_POST['todo_id']) && isset($_POST['action_id'])) {
|
||||
$response['log'][] = 'Required parameters met.';
|
||||
switch ($_POST['action_id']) {
|
||||
case 'status':
|
||||
$response['log'][] = 'Changing status on ' . $_POST['todo_id'] . ' to ' . $_POST['status'] . '.';
|
||||
change_status($_POST['todo_id'], $_POST['status']);
|
||||
break;
|
||||
case 'create_update_todo':
|
||||
if ($_POST['todo_id'] != -1) {
|
||||
$response['log'][] = 'Updating todo information on ' . $_POST['todo_id'] . '.';
|
||||
update_todo($_POST['todo_id'], urldecode($_POST['todo']));
|
||||
} else {
|
||||
$response['log'][] = 'Creating todo information on ' . $_POST['todo_id'] . '.';
|
||||
create_todo(urldecode($_POST['todo']));
|
||||
}
|
||||
break;
|
||||
if (!isset($_POST['space']) || !is_int($_POST['space']))
|
||||
return;
|
||||
|
||||
$user = unserialize($_SESSION['user']);
|
||||
// TODO: Add checks here if the user is authorized. JWT stuff.
|
||||
}
|
||||
|
||||
function handleTodoStatusChange()
|
||||
{
|
||||
if (!isset($_POST['id']) || !isset($_POST['status']) || !is_int($_POST['id']) || !is_string($_POST['status']))
|
||||
return;
|
||||
}
|
||||
|
||||
function handleViewEssay()
|
||||
{
|
||||
if (!isset($_POST['id']))
|
||||
return;
|
||||
|
||||
$essay = Post::retrieveFromDB($_POST['id']);
|
||||
if (!is_a($essay, 'Essay'))
|
||||
return;
|
||||
|
||||
return json_encode(['html' => $essay->getHTML()]);
|
||||
}
|
||||
|
||||
function handleDeleteSpace()
|
||||
{
|
||||
if (!isset($_POST['id'])) {
|
||||
echo json_encode(['error' => 'Missing required Space ID.']);
|
||||
return;
|
||||
}
|
||||
|
||||
$stmt = 'DELETE FROM spaceMembers where space = ?';
|
||||
exec_stmt($stmt, 'i', $_POST['id']);
|
||||
|
||||
$stmt = 'DELETE FROM space WHERE id = ?';
|
||||
exec_stmt($stmt, 'i', $_POST['id']);
|
||||
}
|
||||
|
||||
function handleNewSpace()
|
||||
{
|
||||
if (!isset($_POST['name']) || !isset($_POST['description']) || !isset($_POST['visibility'])) {
|
||||
error_log('ruh roh');
|
||||
return;
|
||||
}
|
||||
|
||||
$id = randomId(2) * -1;
|
||||
/* $name = htmlspecialchars($_POST['name'], ENT_QUOTES, 'UTF-8'); */
|
||||
/* $description = htmlspecialchars($_POST['description'], ENT_QUOTES, 'UTF-8'); */
|
||||
$space = new Space($id, $_POST['name'], $_POST['description'], $_POST['visibility'], null, null, isset($_POST['space']) ? Space::retrieveFromDB($_POST['space']) : null, true);
|
||||
error_log(pretty_dump($space));
|
||||
Space::addUserToSpace(unserialize($_SESSION['user'])->getId(), $id * -1, 1, true);
|
||||
}
|
||||
|
||||
function handleNewPost()
|
||||
{
|
||||
if (!isset($_POST['postType']) || !isset($_POST['space']) || !isset($_SESSION['user']))
|
||||
return;
|
||||
|
||||
// TODO: Better input validation for SQL Inj. and XSS
|
||||
switch ($_POST['postType']) {
|
||||
case 'Thought':
|
||||
if (!isset($_POST['thought']))
|
||||
return;
|
||||
$id = randomId(1) * -1;
|
||||
new Thought($_POST['space'], $id, unserialize($_SESSION['user']), 3, 2, urldecode($_POST['thought']));
|
||||
break;
|
||||
case 'Moment':
|
||||
if (!isset($_FILES['image']) || !isset($_POST['caption']))
|
||||
return;
|
||||
$id = randomId(1) * -1;
|
||||
new Moment($_POST['space'], $id, unserialize($_SESSION['user']), 2, 2, $_FILES['image'], $_POST['caption']);
|
||||
break;
|
||||
case 'Essay':
|
||||
if (!isset($_POST['title']) || !isset($_POST['markdown']) || !isset($_POST['excerpt']))
|
||||
return;
|
||||
$id = randomId(1) * -1;
|
||||
new Essay($_POST['space'], $id, unserialize($_SESSION['user']), 3, 2, $_POST['title'], $_POST['markdown'], $_POST['excerpt']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function handleSignup()
|
||||
{
|
||||
if (!isset($_POST['username']) || !isset($_POST['password']) || !isset($_POST['vPassword']))
|
||||
return;
|
||||
|
||||
if ($_POST['password'] != $_POST['vPassword'])
|
||||
return;
|
||||
|
||||
$_SESSION['user'] = serialize(new User(randomId(0) * -1, null, $_POST['username'], null, null, null, 3, password_hash($_POST['password'], PASSWORD_DEFAULT)));
|
||||
header('Location: .');
|
||||
}
|
||||
|
||||
function handleUsernameCheck()
|
||||
{
|
||||
if (!isset($_POST['username']))
|
||||
return;
|
||||
|
||||
echo json_encode(['exists' => User::exists($_POST['username'])]);
|
||||
}
|
||||
|
||||
function handleSignupHTML()
|
||||
{
|
||||
if (isset($_SESSION['user']))
|
||||
header('Location: .');
|
||||
|
||||
echo json_encode(['html' => User::getSignupHTML()]);
|
||||
}
|
||||
|
||||
function handleLoginHTML()
|
||||
{
|
||||
if (isset($_SESSION['user']))
|
||||
header('Location: .');
|
||||
|
||||
echo json_encode(['html' => User::getLoginHTML()]);
|
||||
}
|
||||
|
||||
function handleDeletePost()
|
||||
{
|
||||
if (!isset($_POST['id'])) {
|
||||
echo json_encode(['error' => 'Missing required Post ID.']);
|
||||
return;
|
||||
}
|
||||
|
||||
$stmt = 'DELETE FROM post WHERE id = ?';
|
||||
exec_stmt($stmt, 'i', $_POST['id']);
|
||||
}
|
||||
|
||||
function handleNewSpaceHTML()
|
||||
{
|
||||
$user = unserialize($_SESSION['user']);
|
||||
|
||||
$html = '
|
||||
<div class="med_width std_border center padding modalContent">
|
||||
<h3>New Space</h3>
|
||||
<form method="post" action="director.php">
|
||||
<input type="hidden" name="formID" value="newSpace">
|
||||
<input type="hidden" name="redirect" value="" id="redirect">
|
||||
<input name="name" placeholder="Name" required autofocus>
|
||||
<input name="description" placeholder="Description" required>
|
||||
<select name="visibility">
|
||||
<option value="1">Open</option>
|
||||
<option value="2">Public</option>
|
||||
<option value="3">Request</option>
|
||||
<option value="4">Invite</option>
|
||||
<option value="5">Private</option>
|
||||
</select>
|
||||
';
|
||||
|
||||
$spaces = $user->getAllSpaces();
|
||||
foreach ($spaces as $s) {
|
||||
$html .= '
|
||||
<label class="form_checkbox_container">' . $s->getName() . ' <i class="nf ' . getSpaceIcon($s) . ' left_margin"></i>
|
||||
<input type="radio" name="space" value="' . $s->getId() . '" id="space-' . $s->getId() . '">
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
';
|
||||
}
|
||||
|
||||
$html .= '
|
||||
<input class="button" type="submit" value="Create" id="create">
|
||||
</form>
|
||||
</div>
|
||||
';
|
||||
|
||||
echo json_encode(['html' => $html]);
|
||||
}
|
||||
|
||||
function getSpaceIcon($space)
|
||||
{
|
||||
switch ($space->getVisibility()) {
|
||||
case 1:
|
||||
return 'nf-cod-globe';
|
||||
case 2:
|
||||
return 'nf-fa-group';
|
||||
case 3:
|
||||
case 4:
|
||||
return 'nf-fa-user_group';
|
||||
case 5:
|
||||
return 'nf-fa-lock';
|
||||
}
|
||||
}
|
||||
|
||||
function handleEditPost()
|
||||
{
|
||||
if (!isset($_POST['id']) || !isset($_POST['postType']) || !isset($_POST['space']))
|
||||
return;
|
||||
|
||||
switch ($_POST['postType']) {
|
||||
case 1:
|
||||
if (!isset($_POST['title']) || !isset($_POST['markdown']) || !isset($_POST['excerpt']) || !isset($_POST['space']))
|
||||
return;
|
||||
Essay::edit($_POST['id'], $_POST['title'], $_POST['markdown'], $_POST['excerpt'], $_POST['space']);
|
||||
break;
|
||||
case 2:
|
||||
if (!isset($_POST['caption']))
|
||||
return;
|
||||
Moment::edit($_POST['id'], $_POST['caption'], $_POST['space']);
|
||||
break;
|
||||
case 3:
|
||||
if (!isset($_POST['thought']))
|
||||
return;
|
||||
Thought::edit($_POST['id'], $_POST['thought'], $_POST['space']);
|
||||
break;
|
||||
}
|
||||
|
||||
if (isset($_POST['redirect']))
|
||||
header('Location: ' . $_POST['redirect']);
|
||||
else
|
||||
header('Location: .');
|
||||
}
|
||||
|
||||
function handleEditPostHTML()
|
||||
{
|
||||
if (!isset($_POST['id']))
|
||||
return;
|
||||
|
||||
echo json_encode(['html' => Post::getEditHTML($_POST['id'])]);
|
||||
}
|
||||
|
||||
function handleNewPostHTML()
|
||||
{
|
||||
echo json_encode(['html' => Post::getComposeHTML()]);
|
||||
}
|
||||
|
||||
function handle_login()
|
||||
{
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$response = [];
|
||||
|
||||
if (isset($_POST['username']) && isset($_POST['password'])) { // Corrected check
|
||||
// Ensure LoginCredentials and User classes are loaded
|
||||
// e.g., require_once 'path/to/LoginCredentials.php';
|
||||
// require_once 'path/to/User.php';
|
||||
|
||||
try {
|
||||
$creds = new LoginCredentials($_POST['username'], $_POST['password']);
|
||||
$user = User::login($creds); // Assuming User::login() can return null or throw an exception
|
||||
|
||||
if ($user != null) {
|
||||
$response['status'] = 'success'; // Use a clear status field
|
||||
$response['message'] = 'Login Successful.'; // Renamed 'log' to 'message' for clarity
|
||||
$response['redirect'] = 'spaces.php?view=list';
|
||||
|
||||
// Serialize the user object and store it in the session
|
||||
$_SESSION['user'] = serialize($user);
|
||||
$spaces = $user->getSpaces();
|
||||
foreach ($spaces as $s)
|
||||
$_SESSION['spaces'][] = serialize($s);
|
||||
} else {
|
||||
$response['status'] = 'error';
|
||||
$response['message'] = 'Incorrect username and/or password.';
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
error_log('Login Error: ' . $e->getMessage() . ' in ' . $e->getFile() . ' on line ' . $e->getLine());
|
||||
|
||||
$response['status'] = 'error';
|
||||
$response['message'] = 'An internal error occurred. Please try again later.';
|
||||
}
|
||||
} else {
|
||||
$response['status'] = 'error';
|
||||
$response['message'] = 'Invalid Request: Username and/or password not provided.';
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
@@ -1,265 +0,0 @@
|
||||
<?php
|
||||
require_once 'db_functions.php';
|
||||
require_once 'article_functions.php';
|
||||
|
||||
use Postmark\PostmarkClient;
|
||||
|
||||
function follow_user($follower_user_id, $following_user_id, $notify)
|
||||
{
|
||||
exec_stmt('INSERT INTO follows (follower_user_id, following_user_id, notify_user) VALUES (?, ?, ?)', 'iii', $follower_user_id, $following_user_id, $notify);
|
||||
}
|
||||
|
||||
function unfollow_user($follower_user_id, $following_user_id)
|
||||
{
|
||||
exec_stmt('DELETE FROM follows WHERE follower_user_id = ? AND following_user_id = ?', 'ii', $follower_user_id, $following_user_id);
|
||||
}
|
||||
|
||||
function user_id_exists($user_id)
|
||||
{
|
||||
$result = exec_stmt('SELECT user_id FROM user WHERE user_id = ?', 'i', $user_id)->fetch_assoc();
|
||||
|
||||
if ($result == null)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
function username_exists($username)
|
||||
{
|
||||
$result = exec_stmt('SELECT username FROM user WHERE username = ?', 'i', $username)->fetch_assoc();
|
||||
|
||||
if ($result == null)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
function logout()
|
||||
{
|
||||
foreach (array_keys($_SESSION) as $key)
|
||||
unset($_SESSION[$key]);
|
||||
|
||||
header('Location: .');
|
||||
}
|
||||
|
||||
function login($username, $password, $stay_logged_in)
|
||||
{
|
||||
$password_hash = hash('sha256', $password);
|
||||
|
||||
$user = exec_stmt('SELECT user_id, username, role_id FROM user WHERE username = ? OR email = ? AND password_hash = ?', 'sss', $username, $username, $password_hash)->fetch_assoc();
|
||||
|
||||
if ($user == null) {
|
||||
$error_msg = '
|
||||
<div class="error">
|
||||
Username and/or Password are invalid!
|
||||
</div>
|
||||
';
|
||||
|
||||
return $error_msg;
|
||||
}
|
||||
|
||||
$_SESSION['user_id'] = $user['user_id'];
|
||||
$_SESSION['username'] = $user['username'];
|
||||
$_SESSION['role_id'] = $user['role_id'];
|
||||
|
||||
if ($stay_logged_in) {
|
||||
$token = bin2hex(random_bytes(64));
|
||||
// echo $token . '<br>';
|
||||
// echo strlen($token);
|
||||
setcookie('remember_user', $token, time() + 60 * 60 * 24 * 30, '/', '', true, true);
|
||||
|
||||
exec_stmt('INSERT INTO remember_user (token, user_id, remote_addr, http_forward) VALUES (?, ?, ?, ?)', 'siss', $token, $user['user_id'], hash('sha256', $_SERVER['REMOTE_ADDR']), (isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? hash('sha256', $_SERVER['HTTP_X_FORWARDED_FOR']) : null));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function create_user($username, $email, $password, $verify_password, $role_id, $upload = null, $x = null, $y = null, $crop_width = null, $honeypot = null)
|
||||
{
|
||||
if (!empty($honeypot)) {
|
||||
$error_msg = '
|
||||
<div class="error">
|
||||
You are a bot. Leave now.
|
||||
</div>
|
||||
';
|
||||
|
||||
return $error_msg;
|
||||
}
|
||||
|
||||
if ($password != $verify_password) {
|
||||
$error_msg = '
|
||||
<div class="error">
|
||||
Passwords do not match!
|
||||
</div>
|
||||
';
|
||||
|
||||
return $error_msg;
|
||||
}
|
||||
|
||||
if (username_exists($username)) {
|
||||
$error_msg = '
|
||||
<div class="error">
|
||||
Username is taken!
|
||||
</div>
|
||||
';
|
||||
}
|
||||
|
||||
$password_hash = hash('sha256', $password);
|
||||
|
||||
$id = rand(1000, 999999999);
|
||||
while (user_id_exists($id))
|
||||
$id = rand(1000, 999999999);
|
||||
|
||||
if (!empty($upload['profile_picture']['tmp_name'])) {
|
||||
$orig_size = getimagesize($upload['profile_picture']['tmp_name']);
|
||||
$orig_width = $orig_size[0];
|
||||
$orig_height = $orig_size[1];
|
||||
|
||||
$crop_size = min($orig_width, $orig_height) * 0.56;
|
||||
|
||||
crop_image($upload['profile_picture']['tmp_name'], $x, $y, $crop_size, $crop_size);
|
||||
$target = upload($upload['profile_picture'], $_ENV['PROFILE_IMAGES_FQ_PATH'], $id);
|
||||
} else {
|
||||
$target = 'default-profile.png';
|
||||
}
|
||||
|
||||
exec_stmt('INSERT INTO user (user_id, username, email, password_hash, role_id, profile_picture) VALUES (?, ?, ?, ?, ?, ?)', 'isssis', $id, $username, $email, $password_hash, $role_id, $target);
|
||||
return true;
|
||||
}
|
||||
|
||||
function reset_password($user_id, $new_password, $verify_new_password)
|
||||
{
|
||||
if ($new_password != $verify_new_password) {
|
||||
$error_msg = '
|
||||
<div class="error">
|
||||
Passwords do not match!
|
||||
</div>
|
||||
';
|
||||
|
||||
return $error_msg;
|
||||
}
|
||||
|
||||
$password_hash = hash('sha256', $new_password);
|
||||
exec_stmt('UPDATE user SET password_hash = ? WHERE user_id = ?', 'si', $password_hash, $user_id);
|
||||
}
|
||||
|
||||
function update_email($user_id, $new_email, $verify_new_email)
|
||||
{
|
||||
if ($new_email != $verify_new_email) {
|
||||
$error_msg = '
|
||||
<div class="error">
|
||||
Emails do not match!
|
||||
</div>
|
||||
';
|
||||
|
||||
return $error_msg;
|
||||
}
|
||||
|
||||
exec_stmt('UPDATE user SET email = ? WHERE user_id = ?', 'si', $new_email, $user_id);
|
||||
}
|
||||
|
||||
function update_username($user_id, $new_username, $verify_new_username)
|
||||
{
|
||||
if ($new_username != $verify_new_username) {
|
||||
$error_msg = '
|
||||
<div class="error">
|
||||
Usernames do not match!
|
||||
</div>
|
||||
';
|
||||
|
||||
return $error_msg;
|
||||
}
|
||||
|
||||
if ($result = username_exists($new_username))
|
||||
return $result;
|
||||
|
||||
exec_stmt('UPDATE user SET username = ? WHERE user_id = ?', 'si', $new_username, $user_id);
|
||||
}
|
||||
|
||||
function update_profile_picture($user_id) {}
|
||||
|
||||
function request_role_change($user_id, $new_role_id)
|
||||
{
|
||||
$user = exec_stmt('SELECT user_id, username, email, roles.role, created_at FROM user INNER JOIN roles WHERE user.role_id = roles.role_id AND user_id = ?', 'i', $user_id)->fetch_assoc();
|
||||
$new_role = exec_stmt('SELECT role FROM roles WHERE role_id = ?', 'i', $new_role_id)->fetch_array();
|
||||
|
||||
$email_html = '
|
||||
<h1>User Role Change Request</h1>
|
||||
<p>The following user has requested their role on vintagecoding.net to be changed:</p>
|
||||
<p><strong>User ID: </strong>' . $user['user_id'] . '</p>
|
||||
<p><strong>Username: </strong>' . $user['username'] . '</p>
|
||||
<p><strong>Email: </strong>' . $user['email'] . '</p>
|
||||
<p><strong>Current Role: </strong>' . $user['role'] . ' -> ' . $new_role[0] . '</p>
|
||||
<p><strong>Created At: </strong>' . $user['created_at'] . '</p>
|
||||
';
|
||||
|
||||
$client = new PostmarkClient($_ENV['POSTMARK_API_TOKEN']);
|
||||
|
||||
$client->sendEmail(
|
||||
'mailer@joshashton.dev',
|
||||
'me@joshashton.dev',
|
||||
'User Role Change Request - ' . $user['user_id'],
|
||||
$email_html
|
||||
);
|
||||
}
|
||||
|
||||
function delete_account($user_id, $password = null, $verify_password = null)
|
||||
{
|
||||
if ($user_id == 2025) {
|
||||
$error_msg = '
|
||||
<div class="error">
|
||||
I am the owner, and I cannot delete myself...
|
||||
</div>
|
||||
';
|
||||
|
||||
return $error_msg;
|
||||
}
|
||||
|
||||
if ($password != $verify_password) {
|
||||
$error_msg = '
|
||||
<div class="error">
|
||||
Passwords do not match!
|
||||
</div>
|
||||
';
|
||||
|
||||
return $error_msg;
|
||||
}
|
||||
|
||||
if ($password && $verify_password) {
|
||||
$password_hash = hash('sha256', $password);
|
||||
$user = exec_stmt('SELECT user_id, profile_picture FROM user WHERE user_id = ? AND password_hash = ?', 'is', $user_id, $password_hash)->fetch_assoc();
|
||||
|
||||
if ($user == null) {
|
||||
$error_msg = '
|
||||
<div class="error">
|
||||
Username and/or Password are invalid!
|
||||
</div>
|
||||
';
|
||||
|
||||
return $error_msg;
|
||||
}
|
||||
|
||||
// Hardcoded prevention of deleting the owner's profile picture
|
||||
if (!empty($user['profile_picture']) && $user['profile_picture'] != '2025.jpg')
|
||||
delete_file($_ENV['PROFILE_IMAGES_FQ_PATH'] . $user['profile_picture']);
|
||||
|
||||
exec_stmt('DELETE FROM user WHERE user_id = ?', 'i', $user_id);
|
||||
logout();
|
||||
} else if ($_SESSION['role_id'] <= admin) {
|
||||
$user = exec_stmt('SELECT user_id, profile_picture FROM user WHERE user_id = ?', 'i', $user_id)->fetch_assoc();
|
||||
|
||||
if ($user['user_id'] == 2025) {
|
||||
$error_msg = '
|
||||
<div class="error">
|
||||
Cannot delete the owner!
|
||||
</div>
|
||||
';
|
||||
|
||||
return $error_msg;
|
||||
}
|
||||
|
||||
// Hardcoded prevention of deleting the owner's profile picture
|
||||
if (!empty($user['profile_picture']) && $user['profile_picture'] != '2025.jpg')
|
||||
delete_file($_ENV['PROFILE_IMAGES_FQ_PATH'] . $user['profile_picture']);
|
||||
|
||||
exec_stmt('DELETE FROM user WHERE user_id = ?', 'i', $user_id);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
require_once 'db_functions.php';
|
||||
require_once 'db.php';
|
||||
require_once 'functions.php';
|
||||
require_once 'account_functions.php';
|
||||
require_once 'article_functions.php';
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
<?php
|
||||
require_once 'db_functions.php';
|
||||
|
||||
function article_ids_by_newest()
|
||||
{
|
||||
$conn = get_connection();
|
||||
$results = $conn->query('SELECT article_id FROM article ORDER BY published_at DESC');
|
||||
$ids = [];
|
||||
|
||||
while ($row = $results->fetch_assoc())
|
||||
$ids[] = $row['article_id'];
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
function article_ids_by_oldest()
|
||||
{
|
||||
$conn = get_connection();
|
||||
$results = $conn->query('SELECT article_id FROM article ORDER BY published_at ASC');
|
||||
$ids = [];
|
||||
|
||||
while ($row = $results->fetch_assoc())
|
||||
$ids[] = $row['article_id'];
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
function articles_ids_by_author($author_id)
|
||||
{
|
||||
$results = exec_stmt('SELECT article_id FROM article WHERE author_id = ? ORDER BY published_at DESC', 'i', $author_id);
|
||||
$ids = [];
|
||||
|
||||
while ($row = $results->fetch_assoc())
|
||||
$ids[] = $row['article_id'];
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
function article_tags()
|
||||
{
|
||||
$conn = get_connection();
|
||||
$results = $conn->query('SELECT * FROM tags');
|
||||
$tags = [];
|
||||
|
||||
while ($row = $results->fetch_assoc())
|
||||
$tags[] = $row;
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
function article_ids_by_tag($tag)
|
||||
{
|
||||
$results = exec_stmt('SELECT article_id FROM article WHERE article.article_id IN ( SELECT article_tags.article_id FROM article_tags INNER JOIN tags ON article_tags.tag_id = tags.tag_id WHERE tag = ?) ORDER BY published_at DESC', 's', $tag);
|
||||
$ids = [];
|
||||
|
||||
while ($row = $results->fetch_assoc())
|
||||
$ids[] = $row['article_id'];
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
function create_article($author_id, $title, $excerpt, $tags, $markdown_file_contents)
|
||||
{
|
||||
$id = exec_stmt('INSERT INTO article (author_id, title, excerpt, published_at) VALUES (?, ?, ?, CURRENT_TIMESTAMP)', 'iss', $author_id, $title, $excerpt);
|
||||
|
||||
$path = $_ENV['ARTICLES_FQ_PATH'] . $id . '/';
|
||||
mkdir($path);
|
||||
|
||||
$fs = fopen($path . 'article.md', 'a');
|
||||
fwrite($fs, $markdown_file_contents);
|
||||
fclose($fs);
|
||||
|
||||
if (count($tags) > 0) {
|
||||
$tag_insert_stmt = 'INSERT INTO article_tags (article_id, tag_id) VALUES ';
|
||||
$types = '';
|
||||
for ($i = 0; $i < count($tags); $i++) {
|
||||
$tag_insert_stmt .= '(' . $id . ', ?)';
|
||||
|
||||
if ($i < count($tags) - 1)
|
||||
$tag_insert_stmt .= ', ';
|
||||
|
||||
$types .= 'i';
|
||||
}
|
||||
|
||||
exec_stmt($tag_insert_stmt, $types, ...$tags);
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
function update_article($article_id, $title, $excerpt, $tags, $markdown_file_contents)
|
||||
{
|
||||
exec_stmt('UPDATE article SET title = ?, excerpt = ?, updated_at = CURRENT_TIMESTAMP WHERE article_id = ?', 'ssi', $title, $excerpt, $article_id);
|
||||
|
||||
$path = $_ENV['ARTICLES_FQ_PATH'] . $article_id . '/';
|
||||
$fs = fopen($path . 'article.md', 'w');
|
||||
fwrite($fs, $markdown_file_contents);
|
||||
fclose($fs);
|
||||
|
||||
exec_stmt('DELETE from article_tags WHERE article_id = ?', 'i', $article_id);
|
||||
|
||||
if (count($tags) > 0) {
|
||||
$tag_insert_stmt = 'INSERT INTO article_tags (article_id, tag_id) VALUES ';
|
||||
$types = '';
|
||||
for ($i = 0; $i < count($tags); $i++) {
|
||||
$tag_insert_stmt .= '(' . $article_id . ', ?)';
|
||||
|
||||
if ($i < count($tags) - 1)
|
||||
$tag_insert_stmt .= ', ';
|
||||
|
||||
$types .= 'i';
|
||||
}
|
||||
|
||||
exec_stmt($tag_insert_stmt, $types, ...$tags);
|
||||
}
|
||||
}
|
||||
|
||||
function delete_article($article_id)
|
||||
{
|
||||
exec_stmt('DELETE FROM article_tags WHERE article_id = ?', 'i', $article_id);
|
||||
exec_stmt('DELETE FROM article WHERE article_id = ?', 'i', $article_id);
|
||||
|
||||
delete_dir($_ENV['ARTICLES_FQ_PATH'] . $article_id . '/');
|
||||
}
|
||||
|
||||
function delete_articles_by_author($author_id)
|
||||
{
|
||||
exec_stmt('DELETE FROM article WHERE author_id = ?', 'i', $author_id);
|
||||
}
|
||||
|
||||
function increment_read_counter($article_id)
|
||||
{
|
||||
exec_stmt('UPDATE article SET read_count = read_count + 1 WHERE article_id = ?', 'i', $article_id);
|
||||
}
|
||||
@@ -1,11 +1,36 @@
|
||||
<?php
|
||||
include_once 'functions/init.php';
|
||||
require_once 'init.php';
|
||||
|
||||
use Postmark\PostmarkClient;
|
||||
|
||||
if (!empty($_FILES['upload']))
|
||||
upload($_FILES['upload'], $_ENV['UPLOAD_TMP_FQ_PATH'], isset($_POST['filename']) ? $_POST['filename'] : null);
|
||||
|
||||
/*
|
||||
* @* @param int $mode 0 for User, 1 for Post, 2 for Space
|
||||
*/
|
||||
function randomId(int $mode)
|
||||
{
|
||||
$id = rand(10000000, 999999999);
|
||||
switch ($mode) {
|
||||
case 0:
|
||||
if (User::exists($id))
|
||||
return randomId($mode);
|
||||
else
|
||||
return $id;
|
||||
case 1:
|
||||
if (Post::exists($id))
|
||||
return randomId($mode);
|
||||
else
|
||||
return $id;
|
||||
case 2:
|
||||
if (Space::exists($id))
|
||||
return randomId($mode);
|
||||
else
|
||||
return $id;
|
||||
}
|
||||
}
|
||||
|
||||
function notify_users($emails, $auther_username, $article_id, $article_title, $excerpt)
|
||||
{
|
||||
foreach ($emails as $email) {
|
||||
@@ -16,7 +41,6 @@ function notify_users($emails, $auther_username, $article_id, $article_title, $e
|
||||
<p>' . $excerpt . '</p>
|
||||
';
|
||||
|
||||
|
||||
$client = new PostmarkClient($_ENV['POSTMARK_API_TOKEN']);
|
||||
|
||||
$client->sendEmail(
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
require_once 'vendor/autoload.php';
|
||||
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__ . '/..');
|
||||
$dotenv = Dotenv\Dotenv::createImmutable('/home/jashton/dev/me/weave.space/');
|
||||
$dotenv->safeLoad();
|
||||
|
||||
// Use environment variables for the database password and IP address.
|
||||
@@ -29,10 +29,15 @@ function exec_stmt($stmt, $param_types, ...$args)
|
||||
$stmt->bind_param($param_types, ...$args);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
if ($result)
|
||||
|
||||
if ($result) {
|
||||
$conn->close();
|
||||
return $result;
|
||||
else
|
||||
return mysqli_insert_id($conn);
|
||||
} else {
|
||||
$id = mysqli_insert_id($conn);
|
||||
$conn->close();
|
||||
return $id;
|
||||
}
|
||||
}
|
||||
|
||||
function get_connection()
|
||||
+23
-53
@@ -1,66 +1,36 @@
|
||||
<?php
|
||||
session_start();
|
||||
header("Content-Security-Policy: default-src 'self'; font-src 'self' https://www.nerdfonts.com/assets/fonts/Symbols-2048-em%20Nerd%20Font%20Complete.woff2; style-src 'self' 'unsafe-inline' https://nerdfonts.com/assets/css/webfont.css https://www.nerdfonts.com/assets/css/webfont.css; script-src 'self' 'unsafe-inline'; img-src 'self';");
|
||||
header("Content-Security-Policy: default-src 'self' localhost:*; font-src 'self' https://www.nerdfonts.com/assets/fonts/Symbols-2048-em%20Nerd%20Font%20Complete.woff2; style-src 'self' 'unsafe-inline' https://nerdfonts.com/assets/css/webfont.css https://www.nerdfonts.com/assets/css/webfont.css; script-src 'self' 'unsafe-inline'; img-src 'self';");
|
||||
|
||||
// Initialize Composer.
|
||||
require_once 'vendor/autoload.php';
|
||||
require_once 'db_functions.php';
|
||||
require_once 'account_functions.php';
|
||||
|
||||
// Load environment variables.
|
||||
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__ . '/../');
|
||||
require_once 'functions/vendor/autoload.php';
|
||||
$dotenv = Dotenv\Dotenv::createImmutable('/home/jashton/dev/me/weave.space/');
|
||||
$dotenv->safeLoad();
|
||||
|
||||
require_once 'functions/db.php';
|
||||
require_once 'functions/core.php';
|
||||
require_once 'functions/user.php';
|
||||
require_once 'functions/post.php';
|
||||
require_once 'functions/space.php';
|
||||
|
||||
// Set SESSION variable.
|
||||
if (!isset($_SESSION['initialized'])) {
|
||||
$_SESSION['initialized'] = true;
|
||||
$_SESSION['theme'] = 'dark';
|
||||
$_SESSION['initialized'] = true;
|
||||
$_SESSION['theme'] = 'dark';
|
||||
if (isset($_SESSION['user'])) {
|
||||
$tmp = unserialize($_SESSION['user'])->getSpaces();
|
||||
foreach ($tmp as $s)
|
||||
$_SESSION['spaces'][] = serialize($s->getSpace());
|
||||
}
|
||||
} else if (isset($_POST['theme'])) {
|
||||
$_SESSION['theme'] = $_POST['theme'];
|
||||
unset($_POST['theme']);
|
||||
$_SESSION['theme'] = $_POST['theme'];
|
||||
unset($_POST['theme']);
|
||||
} else {
|
||||
$_SESSION['theme'] = 'light';
|
||||
}
|
||||
|
||||
define('owner', 1);
|
||||
define('admin', 2);
|
||||
define('contributor', 3);
|
||||
define('reader', 4);
|
||||
define('developer', 2);
|
||||
define('user', 3);
|
||||
|
||||
// Update the database and cookies to keep the user logged in.
|
||||
if (isset($_SESSION['user_id'])) {
|
||||
$conn = get_connection();
|
||||
$stmt = $conn->prepare('UPDATE user SET is_active = true WHERE user_id = ?');
|
||||
$stmt->bind_param('i', $_SESSION['user_id']);
|
||||
$stmt->execute();
|
||||
|
||||
$stmt = $conn->prepare('UPDATE user SET last_active = CURRENT_TIMESTAMP WHERE user_id = ?');
|
||||
$stmt->bind_param('i', $_SESSION['user_id']);
|
||||
$stmt->execute();
|
||||
} else if (isset($_COOKIE['remember_user'])) {
|
||||
$conn = get_connection();
|
||||
$stmt = $conn->prepare('SELECT * FROM remember_user WHERE token = ?');
|
||||
$stmt->bind_param('s', $_COOKIE['remember_user']);
|
||||
$stmt->execute();
|
||||
$remember = $stmt->get_result()->fetch_assoc();
|
||||
|
||||
if (hash('sha256', $_SERVER['REMOTE_ADDR']) != $remember['remote_addr'] || (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && hash('sha256', $_SERVER['HTTP_X_FORWARDED_FOR']) != $remember['forwarded_for'])) {
|
||||
// TODO: Log the attempt to use a cookie from a different browser/device than the cookie was created
|
||||
echo "Naughty, you are trying to use someone else's cookie...";
|
||||
} else {
|
||||
$stmt = $conn->prepare('SELECT user_id, username, role_id FROM user WHERE user_id = ?');
|
||||
$stmt->bind_param('s', $remember['user_id']);
|
||||
$stmt->execute();
|
||||
$user = $stmt->get_result()->fetch_assoc();
|
||||
|
||||
$_SESSION['user_id'] = $user['user_id'];
|
||||
$_SESSION['username'] = $user['username'];
|
||||
$_SESSION['role_id'] = $user['role_id'];
|
||||
|
||||
$stmt = $conn->prepare('UPDATE user SET is_active = true WHERE user_id = ?');
|
||||
$stmt->bind_param('i', $_SESSION['user_id']);
|
||||
$stmt->execute();
|
||||
|
||||
$stmt = $conn->prepare('UPDATE user SET last_active = CURRENT_TIMESTAMP WHERE user_id = ?');
|
||||
$stmt->bind_param('i', $_SESSION['user_id']);
|
||||
$stmt->execute();
|
||||
}
|
||||
if (isset($_SESSION['user']) && !isset($GLOBALS['spaces'])) {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,595 @@
|
||||
<?php
|
||||
|
||||
// It's good practice to use namespaces, e.g.:
|
||||
// namespace VintageCoding\Models;
|
||||
// namespace VintageCoding\Repositories;
|
||||
|
||||
require_once 'functions/db.php'; // For exec_stmt() and get_connection() (though get_connection is used by exec_stmt)
|
||||
require_once 'functions/user.php'; // For User and Author classes
|
||||
require_once 'functions/space.php';
|
||||
|
||||
// -- Data Transfer Object for Topics --
|
||||
class Topic
|
||||
{
|
||||
public int $topicId;
|
||||
public string $name;
|
||||
|
||||
public function __construct(int $topicId, string $name)
|
||||
{
|
||||
$this->topicId = $topicId;
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->topicId;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
}
|
||||
|
||||
// -- Post Data Models (as previously defined, with setReadCount in Post) --
|
||||
class Post
|
||||
{
|
||||
private int $space;
|
||||
private ?int $id;
|
||||
private User $creator;
|
||||
private int $postType;
|
||||
private ?int $status;
|
||||
private int $seenCount;
|
||||
private ?DateTime $createdAt;
|
||||
private ?DateTime $updatedAt;
|
||||
|
||||
public function __construct(int $space = 2025, ?int $id = null, User $creator, int $postType, int $status)
|
||||
{
|
||||
error_log('Instantiating a post');
|
||||
$this->space = $space;
|
||||
$this->id = $id;
|
||||
$this->creator = $creator;
|
||||
$this->postType = $postType;
|
||||
$this->status = $status;
|
||||
|
||||
$this->seenCount = 0;
|
||||
}
|
||||
|
||||
public static function exists(int $id): bool
|
||||
{
|
||||
$stmt = 'SELECT count(id) FROM post WHERE id = ?';
|
||||
$result = exec_stmt($stmt, 'i', $id)->fetch_assoc();
|
||||
if ($result['count(id)'] == 1)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function retrieveFromDB(int $id): ?Post
|
||||
{
|
||||
$stmt = 'SELECT * FROM post WHERE id = ?';
|
||||
$post = exec_stmt($stmt, 'i', $id)->fetch_assoc();
|
||||
if ($post) {
|
||||
$creator = User::retrieveFromDB($post['creator']);
|
||||
|
||||
switch ($post['postType']) {
|
||||
case 1:
|
||||
return new Essay($post['space'], $id, $creator, 1, $post['status'], $post['title'], $post['markdown'], $post['excerpt']);
|
||||
case 2:
|
||||
return new Moment($post['space'], $id, $creator, 2, $post['status'], $post['images'], $post['caption']);
|
||||
case 3:
|
||||
return new Thought($post['space'], $id, $creator, 3, $post['status'], $post['thought']);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function getComposeHTML(): string
|
||||
{
|
||||
$user = unserialize($_SESSION['user']);
|
||||
|
||||
// TODO: Need to store the current space in SESSION and use that to auto-select a Space
|
||||
// TODO: List the user's spaces or let them search for a space or quick select a favorited space
|
||||
$html = '
|
||||
<div class="med_width std_border center padding modalContent">
|
||||
<h3 id="newPostLabel">New Thought</h3>
|
||||
<form method="post" action="director.php" enctype="multipart/form-data">
|
||||
<input type="hidden" name="formID" value="newPost">
|
||||
<input type="hidden" name="redirect" value="" id="redirect">
|
||||
<input type="hidden" name="postType" value="Thought" id="postType">
|
||||
|
||||
<div id="newThought" class="column">
|
||||
<input type="text" name="thought" placeholder="Jot a Thought." autofocus id="thought">
|
||||
</div>
|
||||
|
||||
<div id="newMoment" class="column" style="display: none;">
|
||||
<input type="file" name="image" accept="image/png" id="momentImageUpload">
|
||||
<input type="text" name="caption" placeholder="Caption goes here." id="caption">
|
||||
</div>
|
||||
|
||||
<div id="newEssay" class="column" style="display: none;">
|
||||
<input type="text" name="title" placeholder="Title" autofocus id="title">
|
||||
<textarea name="markdown" placeholder="#Heading" id="markdown"></textarea>
|
||||
<input type="text" name="excerpt" placeholder="A 2-3 sentence summary." id="excerpt">
|
||||
</div>
|
||||
|
||||
<div class="column" id="postSpaces">
|
||||
';
|
||||
|
||||
$spaces = $user->getAllSpaces();
|
||||
foreach ($spaces as $s) {
|
||||
$html .= '
|
||||
<label class="form_checkbox_container">' . $s->getName() . ' <i class="nf ' . getSpaceIcon($s) . ' left_margin"></i>
|
||||
<input type="radio" name="space" value="' . $s->getId() . '" id="space-' . $s->getId() . '">
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
';
|
||||
}
|
||||
|
||||
$html .= '
|
||||
</div>
|
||||
|
||||
<input class="button" type="submit" value="Share" id="share">
|
||||
</form>
|
||||
<div class="line std_border"></div>
|
||||
<div id="newModalNav" class="row space_between">
|
||||
<span id="newNavThought" class="link">Thought</span>
|
||||
<span id="newNavMoment" class="link">Moment</span>
|
||||
<span id="newNavEssay" class="link">Essay</span>
|
||||
</div>
|
||||
</div>
|
||||
';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
public static function getEditHTML($id)
|
||||
{
|
||||
$user = unserialize($_SESSION['user']);
|
||||
$post = Post::retrieveFromDB($id);
|
||||
if (!$post)
|
||||
return '';
|
||||
|
||||
// TODO: Need to plumb this into the DB via AJAX.
|
||||
// TODO: Need to store the current space in SESSION and use that to auto-select a Space
|
||||
// TODO: List the user's spaces or let them search for a space or quick select a favorited space
|
||||
$html = '
|
||||
<div class="med_width std_border center padding modalContent">
|
||||
<h3 id="editPostLabel">New Thought</h3>
|
||||
<form method="post" action="director.php">
|
||||
<input type="hidden" name="formID" value="editPost">
|
||||
<input type="hidden" name="id" value="' . $id . '">
|
||||
<input type="hidden" name="redirect" value="" id="redirect">
|
||||
<input type="hidden" name="postType" value="' . $post->getPostType() . '" id="postType" value="' . $post->getPostType() . '">
|
||||
<input type="hidden" name="space" value="' . $post->getSpace() . '">
|
||||
';
|
||||
|
||||
switch ($post->getPostType()) {
|
||||
case 1:
|
||||
if (!is_a($post, 'Essay'))
|
||||
return;
|
||||
|
||||
$html .= '
|
||||
|
||||
<div id="newEssay" class="column" style="display: none;">
|
||||
<input type="text" name="title" placeholder="Title" autofocus id="title" value="' . $post->getTitle() . '">
|
||||
<textarea name="markdown" placeholder="#Heading" id="markdown" value="' . $post->getMarkdown() . '"></textarea>
|
||||
<input type="text" name="excerpt" placeholder="A 2-3 sentence summary." id="excerpt" value="' . $post->getExcerpt() . '">
|
||||
</div>
|
||||
|
||||
<div class="column" id="postSpaces">
|
||||
';
|
||||
|
||||
$spaces = $user->getAllSpaces();
|
||||
foreach ($spaces as $s) {
|
||||
$html .= '
|
||||
<label class="form_checkbox_container">' . $s->getName() . ' <i class="nf ' . getSpaceIcon($s) . ' left_margin"></i>
|
||||
<input type="radio" name="space" value="' . $s->getId() . '" id="space-' . $s->getId() . '"' . ($post->getSpace() == $s->getId() ? ' checked' : '') . '>
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
';
|
||||
}
|
||||
|
||||
$html .= '
|
||||
</div>
|
||||
';
|
||||
break;
|
||||
case 2:
|
||||
if (!is_a($post, 'Moment'))
|
||||
return;
|
||||
|
||||
$html .= '
|
||||
<div id="newMoment" class="column" style="display: none;">
|
||||
<input type="text" name="caption" placeholder="Caption goes here." autofocus id="caption" value="' . $post->getCaption() . '">
|
||||
</div>
|
||||
';
|
||||
break;
|
||||
case 3:
|
||||
if (!is_a($post, 'Thought'))
|
||||
return;
|
||||
|
||||
$html .= '
|
||||
<div id="newThought" class="column">
|
||||
<input type="text" name="thought" placeholder="Jot a Thought." autofocus id="thought" value="' . $post->getThought() . '">
|
||||
</div>
|
||||
';
|
||||
break;
|
||||
}
|
||||
|
||||
$html .= '
|
||||
<input class="button" type="submit" value="Share" id="share">
|
||||
</form>
|
||||
<div class="line std_border"></div>
|
||||
</div>
|
||||
';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
public function setId(int $id): void
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getCreator(): User
|
||||
{
|
||||
return $this->creator;
|
||||
}
|
||||
|
||||
public function getPostType(): int
|
||||
{
|
||||
return $this->postType;
|
||||
}
|
||||
|
||||
public function getSeenCount(): int
|
||||
{
|
||||
return $this->seenCount;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): ?DateTime
|
||||
{
|
||||
return $this->createdAt;
|
||||
}
|
||||
|
||||
public function getUpdatedAt(): ?DateTime
|
||||
{
|
||||
return $this->updatedAt;
|
||||
}
|
||||
|
||||
public function getStatus(): ?DateTime
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
public function incrementSeenCount(): void
|
||||
{
|
||||
$this->seenCount++;
|
||||
}
|
||||
|
||||
public function setStatus(?int $status): void
|
||||
{
|
||||
$this->status = $status;
|
||||
}
|
||||
|
||||
public function setSpace(int $space): void
|
||||
{
|
||||
$this->space = $space;
|
||||
}
|
||||
|
||||
public function getSpace(): int
|
||||
{
|
||||
if (!isset($this->space)) {
|
||||
$stmt = 'SELECT space from spacePosts WHERE post = ?';
|
||||
$rawSpace = exec_stmt($stmt, 'i', $this->id)->fetch_assoc();
|
||||
}
|
||||
return $this->space;
|
||||
}
|
||||
}
|
||||
|
||||
class Essay extends Post
|
||||
{
|
||||
private string $title;
|
||||
private string $markdown;
|
||||
private string $excerpt;
|
||||
/* private array $files; */
|
||||
|
||||
public function __construct(int $space, ?int $id = null, User $creator, int $postType, int $status, string $title, string $markdown, string $excerpt)
|
||||
{
|
||||
parent::__construct($space, $id, $creator, 1, $postType, $status);
|
||||
|
||||
$this->title = $title;
|
||||
$this->excerpt = $excerpt;
|
||||
$this->markdown = $markdown;
|
||||
|
||||
if ($id < 0) {
|
||||
parent::setId($id * -1);
|
||||
$stmt = 'INSERT INTO post (id, space, creator, postType, status, title, markdown, excerpt) VALUES (?, ?, ?, ?, ?, ?, ?, ?)';
|
||||
$space = isset($space) ? $space : $creator->getHomeSpace()->getId();
|
||||
exec_stmt($stmt, 'iiiiisss', $id * -1, $space, $creator->getId(), 1, 2, $title, $markdown, $excerpt);
|
||||
$stmt = 'INSERT INTO spacePosts (post, space) VALUES (?, ?)';
|
||||
exec_stmt($stmt, 'ii', $id * -1, $space);
|
||||
}
|
||||
}
|
||||
|
||||
public static function edit(int $id, string $title, string $markdown, string $excerpt, int $space)
|
||||
{
|
||||
$post = Post::retrieveFromDB($id);
|
||||
if (!is_a($post, 'Essay'))
|
||||
return;
|
||||
|
||||
$post->setTitle($title);
|
||||
$post->setMarkdown($markdown);
|
||||
$post->setExcerpt($excerpt);
|
||||
$post->setSpace($space);
|
||||
|
||||
$stmt = 'UPDATE post SET title = ?, markdown = ?, excerpt = ?, space = ? WHERE id = ?';
|
||||
exec_stmt($stmt, 'sssii', $title, $markdown, $excerpt, $space, $id);
|
||||
}
|
||||
|
||||
public function getCardHTML(): ?string
|
||||
{
|
||||
/* <a href="user.php?view=display&id=' . parent::getCreator()->getId() . '">@' . parent::getCreator()->getUsername() . '</a> */
|
||||
$html = '
|
||||
<div class="full_width std_border padding center top_margin bottom_margin">
|
||||
<a href="spaces.php?view=essay&id=' . $this->getId() . '" class="divLink">
|
||||
<div class="row space_between full_width">
|
||||
<div class="column std_width">
|
||||
<h4>' . $this->title . '</h4>
|
||||
</div>
|
||||
|
||||
';
|
||||
|
||||
if (isset($_SESSION['user'])) {
|
||||
$user = unserialize($_SESSION['user']);
|
||||
if ($user->getId() == parent::getCreator()->getId()) {
|
||||
$html .= '
|
||||
<div class="dropdown" style="z-index: 1;">
|
||||
<i class="nf nf-md-dots_horizontal"></i>
|
||||
<div class="sm_border padding glass dropdownContent">
|
||||
<a class="underline link" onclick="editPost(' . parent::getId() . ')">Edit</a>
|
||||
<a class="underline link" onclick="deletePost(' . parent::getId() . ')">Delete</a>
|
||||
</div>
|
||||
</div>
|
||||
';
|
||||
}
|
||||
}
|
||||
|
||||
$html .= '
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<div class="row full_width">
|
||||
<p>' . $this->excerpt . '</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
public function setTitle(string $title)
|
||||
{
|
||||
$this->title = $title;
|
||||
}
|
||||
|
||||
public function getTitle(): ?string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function setMarkdown(string $markdown)
|
||||
{
|
||||
$this->markdown = $markdown;
|
||||
}
|
||||
|
||||
public function getMarkdown(): ?string
|
||||
{
|
||||
return $this->markdown;
|
||||
}
|
||||
|
||||
public function getHTML(): string
|
||||
{
|
||||
$parsedown = new Parsedown();
|
||||
$parsedown->setSafeMode(true);
|
||||
return $parsedown->parse($this->markdown);
|
||||
}
|
||||
|
||||
public function setExcerpt(string $excerpt)
|
||||
{
|
||||
$this->excerpt = $excerpt;
|
||||
}
|
||||
|
||||
public function getExcerpt(): ?string
|
||||
{
|
||||
return $this->excerpt;
|
||||
}
|
||||
}
|
||||
|
||||
class Moment extends Post
|
||||
{
|
||||
private ?string $caption;
|
||||
private $image;
|
||||
|
||||
public function __construct(int $space, ?int $id = null, User $creator, int $postType, int $status, $image, string $caption)
|
||||
{
|
||||
parent::__construct($space, $id, $creator, $postType, $status);
|
||||
$this->caption = $caption;
|
||||
$this->image = $image;
|
||||
|
||||
if ($id < 0) {
|
||||
if (!isset($image['tmp_name']))
|
||||
return;
|
||||
mkdir($_ENV['IMG_UPLOAD'] . ($id * -1));
|
||||
move_uploaded_file($image['tmp_name'], $_ENV['IMG_UPLOAD'] . ($id * -1) . '/' . $image['name']);
|
||||
|
||||
$this->image = $image['name'];
|
||||
|
||||
$stmt = 'INSERT INTO post (id, space, creator, postType, status, images, caption) VALUES (?, ?, ?, ?, ?, ?, ?)';
|
||||
parent::setId($id * -1);
|
||||
$space = isset($space) ? $space : $creator->getHomeSpace()->getId();
|
||||
exec_stmt($stmt, 'iiiiiss', $id * -1, $space, $creator->getId(), 2, 2, $this->image, $this->caption);
|
||||
$stmt = 'INSERT INTO spacePosts (post, space) VALUES (?, ?)';
|
||||
exec_stmt($stmt, 'ii', $id * -1, $space);
|
||||
}
|
||||
}
|
||||
|
||||
public function getCardHTML(): ?string
|
||||
{
|
||||
$html = '
|
||||
<div class="std_border padding center full_width top_margin bottom_margin rel" id="post-' . parent::getId() . '">
|
||||
<div class="row space_between full_width">
|
||||
<a href="user.php?view=display&id=' . parent::getCreator()->getId() . '">@' . parent::getCreator()->getUsername() . '</a>
|
||||
|
||||
|
||||
';
|
||||
|
||||
if (isset($_SESSION['user'])) {
|
||||
$user = unserialize($_SESSION['user']);
|
||||
if ($user->getId() == parent::getCreator()->getId()) {
|
||||
$html .= '
|
||||
<div class="dropdown" style="z-index: 1;">
|
||||
<i class="nf nf-md-dots_horizontal"></i>
|
||||
<div class="sm_border padding glass dropdownContent">
|
||||
<a class="underline link" onclick="editPost(' . parent::getId() . ')">Edit</a>
|
||||
<a class="underline link" onclick="deletePost(' . parent::getId() . ')">Delete</a>
|
||||
</div>
|
||||
</div>
|
||||
';
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: If multiple photos, use components/core/slideshow.php
|
||||
$html .= '
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<div class="column">
|
||||
<img src="/data/img/' . parent::getId() . '/' . $this->image . '" class="margin sm_border" style="max-width: 100%; height: auto;">
|
||||
<div class="line"></div>
|
||||
<p class="margin">' . $this->caption . '</p>
|
||||
</div>
|
||||
</div>
|
||||
';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
public static function edit(int $id, string $caption, int $space)
|
||||
{
|
||||
$post = Post::retrieveFromDB($id);
|
||||
if (!is_a($post, 'Moment'))
|
||||
return;
|
||||
|
||||
$post->setCaption($caption);
|
||||
$post->setSpace($space);
|
||||
|
||||
$stmt = 'UPDATE post SET caption = ?, space = ? WHERE id = ?';
|
||||
exec_stmt($stmt, 'sii', $caption, $space, $id);
|
||||
}
|
||||
|
||||
public function getCaption(): ?string
|
||||
{
|
||||
return $this->caption;
|
||||
}
|
||||
|
||||
public function getImages(): ?array
|
||||
{
|
||||
return $this->image;
|
||||
}
|
||||
|
||||
public function setCaption(?string $caption): void
|
||||
{
|
||||
$this->caption = $caption;
|
||||
}
|
||||
|
||||
public function setImages(?array $image): void
|
||||
{
|
||||
$this->image = $image;
|
||||
}
|
||||
}
|
||||
|
||||
class Thought extends Post
|
||||
{
|
||||
private ?string $thought;
|
||||
|
||||
public function __construct(int $space, ?int $id = null, User $creator, int $postType, int $status, string $thought)
|
||||
{
|
||||
parent::__construct($space, $id, $creator, $postType, $status);
|
||||
$this->thought = $thought;
|
||||
|
||||
if ($id < 0) {
|
||||
$stmt = 'INSERT INTO post (id, space, creator, postType, status, thought) VALUES (?, ?, ?, ?, ?, ?)';
|
||||
parent::setId($id * -1);
|
||||
$space = isset($space) ? $space : $creator->getHomeSpace()->getId();
|
||||
exec_stmt($stmt, 'iiiiis', $id * -1, $space, $creator->getId(), 3, 2, $this->thought);
|
||||
$stmt = 'INSERT INTO spacePosts (post, space) VALUES (?, ?)';
|
||||
exec_stmt($stmt, 'ii', $id * -1, $space);
|
||||
}
|
||||
}
|
||||
|
||||
public static function edit(int $id, string $thought, int $space)
|
||||
{
|
||||
error_log('Updating post ' . $id . ' to have thought = ' . $thought);
|
||||
$post = Post::retrieveFromDB($id);
|
||||
if (!is_a($post, 'Thought'))
|
||||
return;
|
||||
|
||||
$post->setThought($thought);
|
||||
$post->setSpace($space);
|
||||
|
||||
$stmt = 'UPDATE post SET thought = ?, space = ? WHERE id = ?';
|
||||
exec_stmt($stmt, 'sii', $thought, $space, $id);
|
||||
}
|
||||
|
||||
public function getCardHTML(): ?string
|
||||
{
|
||||
$html = '
|
||||
<div class="std_border padding center full_width top_margin bottom_margin rel" id="post-' . parent::getId() . '">
|
||||
<div class="row space_between full_width">
|
||||
<a href="user.php?view=display&id=' . parent::getCreator()->getId() . '">@' . parent::getCreator()->getUsername() . '</a>
|
||||
|
||||
|
||||
';
|
||||
|
||||
if (isset($_SESSION['user'])) {
|
||||
$user = unserialize($_SESSION['user']);
|
||||
if ($user->getId() == parent::getCreator()->getId()) {
|
||||
$html .= '
|
||||
<div class="dropdown" style="z-index: 1;">
|
||||
<i class="nf nf-md-dots_horizontal"></i>
|
||||
<div class="sm_border padding glass dropdownContent">
|
||||
<a class="underline link" onclick="editPost(' . parent::getId() . ')">Edit</a>
|
||||
<a class="underline link" onclick="deletePost(' . parent::getId() . ')">Delete</a>
|
||||
</div>
|
||||
</div>
|
||||
';
|
||||
}
|
||||
}
|
||||
|
||||
$html .= '
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
<div class="row full_width">
|
||||
<p>' . $this->thought . '</p>
|
||||
</div>
|
||||
</div>
|
||||
';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
public function getThought(): ?string
|
||||
{
|
||||
return $this->thought;
|
||||
}
|
||||
|
||||
public function setThought(?string $thought): void
|
||||
{
|
||||
$this->thought = $thought;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
class SpaceMember
|
||||
{
|
||||
private int $id;
|
||||
private User $user;
|
||||
private Space $space;
|
||||
private int $role;
|
||||
private DateTime $addedAt;
|
||||
private bool $favorited;
|
||||
|
||||
public function __construct(int $id, User $user, Space $space, int $role, DateTime $addedAt, bool $favorited)
|
||||
{
|
||||
error_log('Instantiating a space member');
|
||||
if (!User::exists($user->getId()) || !Space::exists($space->getId()))
|
||||
return;
|
||||
|
||||
$this->user = $user;
|
||||
$this->space = $space;
|
||||
$this->role = $role;
|
||||
$this->addedAt = $addedAt;
|
||||
$this->favorited = $favorited;
|
||||
|
||||
if ($id < 0) {
|
||||
$this->id = $id * -1;
|
||||
|
||||
$stmt = 'INSERT INTO spaceMembers (id, user, space, role, favorited) VALUES (?, ?, ?, ?, ?)';
|
||||
exec_stmt($stmt, 'iiiii', $this->id, $user->getId(), $space->getId(), $role, $favorited);
|
||||
}
|
||||
}
|
||||
|
||||
public function getUser()
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
public function getSpace()
|
||||
{
|
||||
return $this->space;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
require_once 'core.php';
|
||||
require_once 'db.php';
|
||||
require_once 'user.php';
|
||||
require_once 'post.php';
|
||||
|
||||
class Space
|
||||
{
|
||||
private int $id;
|
||||
private string $name;
|
||||
private string $description;
|
||||
private int $visibility;
|
||||
private ?array $posts;
|
||||
private ?Space $parent;
|
||||
|
||||
public function __construct(int $id, string $name, string $description, int $visibility, ?array $posts, ?Space $parent = null, bool $favorited = false)
|
||||
{
|
||||
error_log('Constructing a space with id: ' . $id);
|
||||
$this->name = $name;
|
||||
$this->description = $description;
|
||||
$this->visibility = $visibility;
|
||||
$this->posts[] = $posts;
|
||||
$this->parent = $parent;
|
||||
|
||||
if ($id < 0) {
|
||||
$this->id = $id * -1;
|
||||
error_log('ID: ' . $this->id);
|
||||
|
||||
$stmt = 'INSERT INTO space (id, name, description, visibility, parentSpace) VALUES (?, ?, ?, ?, ?)';
|
||||
exec_stmt($stmt, 'issii', $this->id, $name, $description, $visibility, (isset($parent) ? $parent->getId() : null));
|
||||
error_log('Added space in DB');
|
||||
} else
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
public static function exists(int $id): bool
|
||||
{
|
||||
$stmt = 'SELECT count(id) FROM space WHERE id = ?';
|
||||
$result = exec_stmt($stmt, 'i', $id)->fetch_assoc();
|
||||
|
||||
if ($result['count(id)'] == 1)
|
||||
return true;
|
||||
else if ($result['count(id)'] > 1)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function addUserToSpace(int $user, int $space, int $role = 3, bool $favorited = false)
|
||||
{
|
||||
$stmt = 'INSERT INTO spaceMembers (user, space, role, favorited) VALUES (?, ?, ?, ?)';
|
||||
exec_stmt($stmt, 'iiii', $user, $space, $role, $favorited);
|
||||
}
|
||||
|
||||
public function getSubSpaces(): ?array
|
||||
{
|
||||
$stmt = 'SELECT id FROM space WHERE parent = ?';
|
||||
$rawSubSpaces = exec_stmt($stmt, 'i', $this->id);
|
||||
|
||||
$subSpaces = [];
|
||||
foreach ($rawSubSpaces as $ss) {
|
||||
$subSpaces[] = Space::retrieveFromDB($ss['id']);
|
||||
}
|
||||
|
||||
return $subSpaces;
|
||||
}
|
||||
|
||||
public function getParentSpace(): ?Space
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
public function hasParent(): bool
|
||||
{
|
||||
return isset($this->parent);
|
||||
}
|
||||
|
||||
public function getCardHTML(): string
|
||||
{
|
||||
$html = '
|
||||
<div class="full_width std_border padding center top_margin bottom_margin rel" id="space-' . $this->id . '">
|
||||
<a href="spaces.php?view=show&id=' . $this->id . '" class="fillDiv spaceCard"></a>
|
||||
<div class="row space_between full_width">
|
||||
<div class="column std_width">
|
||||
<h4>' . $this->name . '</h4>
|
||||
</div>
|
||||
|
||||
';
|
||||
|
||||
if (isset($_SESSION['user'])) {
|
||||
$user = unserialize($_SESSION['user']);
|
||||
if ($user->getId() == $this->getOwner()->getId()) {
|
||||
$html .= '
|
||||
<div class="dropdown">
|
||||
<i class="nf nf-md-dots_horizontal"></i>
|
||||
<div class="sm_border padding glass dropdownContent">
|
||||
<a class="underline link" onclick="deleteSpace(' . $this->id . ')">Delete</a>
|
||||
</div>
|
||||
</div>
|
||||
';
|
||||
}
|
||||
}
|
||||
|
||||
$html .= '
|
||||
</div>
|
||||
<div class="row full_width">
|
||||
<p>' . $this->description . '</p>
|
||||
</div>
|
||||
</div>
|
||||
';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
public function getOwner(): User
|
||||
{
|
||||
$stmt = 'SELECT user FROM spaceMembers WHERE space = ? AND role = ?';
|
||||
$user = exec_stmt($stmt, 'ii', $this->id, 1)->fetch_assoc();
|
||||
|
||||
return User::retrieveFromDB($user['user']);
|
||||
}
|
||||
|
||||
public static function retrieveFromDB(int $space, int $user = -1): ?Space
|
||||
{
|
||||
error_log('Retrieving a space from DB.');
|
||||
if ($user != -1) {
|
||||
$stmt = 'SELECT * FROM spaceMembers WHERE space = ? AND user = ?';
|
||||
$isMember = exec_stmt($stmt, 'ii', $space, $user)->fetch_assoc();
|
||||
if (!$isMember)
|
||||
return null;
|
||||
} else {
|
||||
$stmt = 'SELECT visibility FROM space WHERE id = ?';
|
||||
$isOpen = exec_stmt($stmt, 'i', $space);
|
||||
if (!$isOpen)
|
||||
return null;
|
||||
}
|
||||
|
||||
$stmt = 'SELECT * FROM space WHERE id = ?';
|
||||
$rawSpace = exec_stmt($stmt, 'i', $space)->fetch_assoc();
|
||||
|
||||
if ($rawSpace) {
|
||||
if (!empty($rawSpace['parentSpace']))
|
||||
$parent = Space::retrieveFromDB($rawSpace['parentSpace'], $user);
|
||||
else
|
||||
$parent = null;
|
||||
|
||||
$stmt = 'SELECT post FROM spacePosts INNER JOIN post ON spacePosts.post = post.id WHERE post.space = ? ORDER BY post.createdAt DESC';
|
||||
$posts = [];
|
||||
$rawPosts = exec_stmt($stmt, 'i', $rawSpace['id']);
|
||||
while ($row = $rawPosts->fetch_assoc())
|
||||
$posts[] = Post::retrieveFromDB($row['post']);
|
||||
|
||||
return new Space($rawSpace['id'], $rawSpace['name'], $rawSpace['description'], $rawSpace['visibility'], $posts, $parent);
|
||||
} else
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getPosts()
|
||||
{
|
||||
return $this->posts;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
echo 'todo: this should be JSON';
|
||||
}
|
||||
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
public function getVisibility(): int
|
||||
{
|
||||
return $this->visibility;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
class Todo
|
||||
{
|
||||
private int $id;
|
||||
private int $space;
|
||||
private string $title;
|
||||
private ?string $description;
|
||||
private ?DateTime $due;
|
||||
private ?int $priority;
|
||||
private ?string $link;
|
||||
private DateTime $createdAt;
|
||||
|
||||
public function __construct(int $id, int $space, string $title, ?string $description, ?DateTime $due, ?int $priority, ?string $link, ?DateTime $createdAt)
|
||||
{
|
||||
if ($space < 0) {
|
||||
error_log('Tried creating a new space and todo at the same time.');
|
||||
return;
|
||||
}
|
||||
|
||||
$this->title = $title;
|
||||
$this->description = $description;
|
||||
$this->due = $due;
|
||||
$this->priority = $priority;
|
||||
$this->link = $link;
|
||||
$this->createdAt = $createdAt;
|
||||
|
||||
if ($id < 0) {
|
||||
$this->id = $id * -1;
|
||||
$stmt = 'INSERT INTO todo (id, space, title, description, due, priority, link) VALUES (?, ?, ?, ?, ?, ?, ?)';
|
||||
exec_stmt($stmt, 'iisssiss', $this->id, $space, $title, $description, $due, $priority, $link);
|
||||
} else
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
public function getHTML()
|
||||
{
|
||||
$html = '
|
||||
<div class="row">
|
||||
<label class="form_checkbox_container">' . $this->title . '
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
</div>
|
||||
';
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
<?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);
|
||||
}
|
||||
|
||||
function create_todo($todo)
|
||||
{
|
||||
exec_stmt('INSERT INTO todos (title, description, priority, due_date, category, status) VALUES (?,?,?,?,?,?)', 'ssssss', $todo['title'], $todo['description'], $todo['priority'], $todo['due_date'], $todo['category'], 'open');
|
||||
}
|
||||
function update_todo($todo_id, $todo)
|
||||
{
|
||||
exec_stmt('UPDATE todos SET title = ? WHERE todo_id = ?', 'si', $todo['title'], $todo_id);
|
||||
exec_stmt('UPDATE todos SET description = ? WHERE todo_id = ?', 'si', $todo['description'], $todo_id);
|
||||
exec_stmt('UPDATE todos SET priority = ? WHERE todo_id = ?', 'si', $todo['priority'], $todo_id);
|
||||
exec_stmt('UPDATE todos SET due_date = ? WHERE todo_id = ?', 'si', $todo['due_date'], $todo_id);
|
||||
exec_stmt('UPDATE todos SET category = ? WHERE todo_id = ?', 'si', $todo['category'], $todo_id);
|
||||
exec_stmt('UPDATE todos SET status = ? WHERE todo_id = ?', 'si', $todo['status'], $todo_id);
|
||||
}
|
||||
@@ -0,0 +1,315 @@
|
||||
<?php
|
||||
require_once 'relationships/spaceMember.php';
|
||||
|
||||
class LoginCredentials
|
||||
{
|
||||
private string $username;
|
||||
private string $password;
|
||||
|
||||
public function __construct(string $username, string $password)
|
||||
{
|
||||
// More intensive SQL injection checks (example - adapt as needed)
|
||||
if (preg_match('/[\'";\-\_]/', $username) || preg_match('/[\'";\-\_]/', $password)) {
|
||||
throw new InvalidArgumentException('Invalid characters in username or password.');
|
||||
}
|
||||
// Consider using a more robust validation library
|
||||
|
||||
$this->username = $username;
|
||||
$this->password = $password;
|
||||
}
|
||||
|
||||
public function getUsername(): string
|
||||
{
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
public function getPassword(): string
|
||||
{
|
||||
return $this->password;
|
||||
}
|
||||
}
|
||||
|
||||
class User
|
||||
{
|
||||
private int $id;
|
||||
private ?array $spaces;
|
||||
private string $username;
|
||||
private bool $isActive;
|
||||
private ?string $profilePicture;
|
||||
private ?string $bio;
|
||||
private ?string $website;
|
||||
private int $role;
|
||||
private ?string $passwordHash;
|
||||
|
||||
public function __construct(int $id, ?array $spaces, string $username, ?string $profilePicture = null, ?string $bio = null, ?string $website = null, int $role = 3, ?string $passwordHash)
|
||||
{
|
||||
error_log('Constructing a User with id: ' . $id);
|
||||
// Basic XSS prevention on construction (can be enhanced)
|
||||
$username = htmlspecialchars($username, ENT_QUOTES, 'UTF-8');
|
||||
$bio = htmlspecialchars($bio ?? '', ENT_QUOTES, 'UTF-8');
|
||||
$website = htmlspecialchars($website ?? '', ENT_QUOTES, 'UTF-8');
|
||||
$profilePicture = htmlspecialchars($profilePicture ?? 'default-profile.png', ENT_QUOTES, 'UTF-8');
|
||||
|
||||
// Basic SQL injection prevention (should primarily rely on prepared statements)
|
||||
/* if (preg_match('/[\'";\-\_]/', $username) || preg_match('/[\'";\-\_]/', $bio) || preg_match('/[\'";\-\_]/', $website) || preg_match('/[\'";\-\_]/', $profilePicture)) { */
|
||||
/* throw new InvalidArgumentException('Invalid characters in user data.'); */
|
||||
/* } */
|
||||
|
||||
$this->username = $username;
|
||||
$this->profilePicture = $profilePicture;
|
||||
$this->bio = $bio;
|
||||
$this->website = $website;
|
||||
$this->isActive = false;
|
||||
$this->role = $role;
|
||||
$this->spaces = $spaces;
|
||||
$this->passwordHash = $passwordHash;
|
||||
|
||||
if ($id < 0) {
|
||||
$this->id = $id * -1;
|
||||
$stmt = 'INSERT INTO user (id, username, passwordHash, profilePicture, bio, website) VALUES (?, ?, ?, ?, ?, ?)';
|
||||
exec_stmt($stmt, 'isssss', $this->id, $this->username, $passwordHash, $this->profilePicture, $this->bio, $this->website);
|
||||
|
||||
Space::addUserToSpace($this->id, 2025);
|
||||
$space = new Space($id, $this->username, $this->username . "'s private Space.", 5, [], null, true);
|
||||
$this->spaces[] = new SpaceMember(randomId(4), $this, $space, 1, new Datetime('now'), true);
|
||||
} else
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
public static function exists($identifier): bool
|
||||
{
|
||||
if (is_int($identifier)) {
|
||||
$stmt = 'SELECT count(id) FROM user WHERE id = ?';
|
||||
$result = exec_stmt($stmt, 'i', $identifier)->fetch_assoc();
|
||||
|
||||
if ($result['count(id)'] == 1)
|
||||
return true;
|
||||
else if ($result['count(id)'] > 1)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
} else if (is_string($identifier)) {
|
||||
$stmt = 'SELECT count(id) FROM user WHERE username = ?';
|
||||
$result = exec_stmt($stmt, 's', $identifier)->fetch_assoc();
|
||||
|
||||
if ($result['count(id)'] == 1)
|
||||
return true;
|
||||
else if ($result['count(id)'] > 1)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function add(SpaceMember $sm)
|
||||
{
|
||||
$this->spaces[] = $sm;
|
||||
}
|
||||
|
||||
public static function retrieveFromDB($identifier): ?User
|
||||
{
|
||||
error_log('Instantiating a user');
|
||||
if (is_int($identifier)) {
|
||||
$stmt = 'SELECT id, username, profilePicture, bio, website, role, passwordHash FROM user WHERE id = ?';
|
||||
$rawUser = exec_stmt($stmt, 'i', $identifier)->fetch_assoc();
|
||||
if (!$rawUser)
|
||||
return null;
|
||||
} else if (is_string($identifier)) {
|
||||
$stmt = 'SELECT id, username, profilePicture, bio, website, role, passwordHash FROM user WHERE username = ?';
|
||||
$rawUser = exec_stmt($stmt, 'i', $identifier)->fetch_assoc();
|
||||
if (!$rawUser)
|
||||
return null;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
$user = new User($rawUser['id'], null, $rawUser['username'], $rawUser['profilePicture'], $rawUser['bio'], $rawUser['website'], $rawUser['role'], $rawUser['passwordHash']);
|
||||
|
||||
$stmt = 'SELECT id, space, role, addedAt, favorited from spaceMembers WHERE user = ?';
|
||||
$rels = exec_stmt($stmt, 'i', $user->getId());
|
||||
if (!$rels)
|
||||
return null;
|
||||
|
||||
while ($r = $rels->fetch_assoc())
|
||||
$user->add(new SpaceMember($r['id'], $user, Space::retrieveFromDB($r['space'], $user->getId()), $r['role'], new DateTime($r['addedAt']), $r['favorited']));
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
public static function login(LoginCredentials $credentials): ?User
|
||||
{
|
||||
$user = User::retrieveFromDB($credentials->getUsername());
|
||||
|
||||
if (!password_verify($credentials->getPassword(), $user->getPasswordHash()))
|
||||
return null;
|
||||
else
|
||||
return $user;
|
||||
}
|
||||
|
||||
public static function logout(): void
|
||||
{
|
||||
foreach (array_keys($_SESSION) as $key) {
|
||||
unset($_SESSION[$key]);
|
||||
}
|
||||
// Consider destroying the session cookie as well: session_destroy();
|
||||
header('Location: .'); // Redirect to the homepage or login page
|
||||
exit();
|
||||
}
|
||||
|
||||
public function getPasswordHash()
|
||||
{
|
||||
return $this->passwordHash;
|
||||
}
|
||||
|
||||
public function getHomeSpace()
|
||||
{
|
||||
// TODO: Need to implement. Requires fleshing out additional space types.
|
||||
return Space::retrieveFromDB(1, 1);
|
||||
}
|
||||
|
||||
public function getSpaces()
|
||||
{
|
||||
$baseSpaces = [];
|
||||
|
||||
foreach ($this->spaces as $s)
|
||||
if (!$s->getSpace()->hasParent())
|
||||
$baseSpaces[] = $s;
|
||||
|
||||
return $baseSpaces;
|
||||
}
|
||||
|
||||
public function getAllSpaces()
|
||||
{
|
||||
$stmt = 'SELECT space FROM spaceMembers WHERE user = ?';
|
||||
$rawSpaces = exec_stmt($stmt, 'i', $this->id);
|
||||
$spaces = [];
|
||||
while ($r = $rawSpaces->fetch_assoc())
|
||||
$spaces[] = Space::retrieveFromDB($r['space']);
|
||||
|
||||
return $spaces;
|
||||
}
|
||||
|
||||
public function getRole(): int
|
||||
{
|
||||
return $this->role;
|
||||
}
|
||||
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getUsername(): string
|
||||
{
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
public function isActive(): bool
|
||||
{
|
||||
return $this->isActive;
|
||||
}
|
||||
|
||||
public function getProfilePicture(): ?string
|
||||
{
|
||||
return $this->profilePicture;
|
||||
}
|
||||
|
||||
public function getBio(): ?string
|
||||
{
|
||||
return $this->bio;
|
||||
}
|
||||
|
||||
public function getWebsite(): ?string
|
||||
{
|
||||
return $this->website;
|
||||
}
|
||||
|
||||
public function setIsActive(bool $isActive): void
|
||||
{
|
||||
$this->isActive = $isActive;
|
||||
}
|
||||
|
||||
public static function getSignupHTML()
|
||||
{
|
||||
$experimentalHTML = '
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
|
||||
<input name="required_field" id="required_field" value="">
|
||||
|
||||
<input type="hidden" name="crop_x" value="" id="crop_x">
|
||||
<input type="hidden" name="crop_y" value="" id="crop_y">
|
||||
<input type="hidden" name="crop_width" value="" id="crop_width">
|
||||
|
||||
<label for="email">Email Address</label>
|
||||
<input id="email" name="email" required>
|
||||
|
||||
<label for="profile_picture_input" class="upload_button modal_button" id="profile_cropper_button">Upload a Profile Picture</label>
|
||||
<input id="profile_picture_input" class="file_input" name="profile_picture" type="file" accept="image/png, image/jpeg, image/jpg">
|
||||
<small class="file_input_feedback">No file selected.</small>
|
||||
|
||||
<label class="form_checkbox_container">Stay Logged In?
|
||||
<input name="stay_logged_in" type="checkbox" value="true">
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
';
|
||||
|
||||
$html = '
|
||||
<div class="med_width std_border padding center modalContent">
|
||||
<h3 class="underline">Sign Up</h3>
|
||||
<div class="line"></div>
|
||||
<form method="post" action="director.php">
|
||||
<input type="hidden" name="formID" value="signup">
|
||||
|
||||
<label for="username">Username</label>
|
||||
<input id="username" name="username" required autofocus>
|
||||
|
||||
<label for="password">Password</label>
|
||||
<input id="password" name="password" type="password" required>
|
||||
|
||||
<label for="vPassword">Verify Password</label>
|
||||
<input id="vPassword" name="vPassword" type="password" required>
|
||||
|
||||
<input class="button" type="submit" value="Sign Up">
|
||||
</form>
|
||||
|
||||
<div id="signupError"></div>
|
||||
</div>
|
||||
';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
public static function getLoginHTML()
|
||||
{
|
||||
$stayCheckedIn = '
|
||||
<label class="form_checkbox_container">Stay Logged In?
|
||||
<input name="stay_logged_in" type="checkbox" value="true">
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
';
|
||||
|
||||
$html = '
|
||||
<div class="med_width std_border padding center modalContent">
|
||||
<h3 class="underline">Log In</h3>
|
||||
<div class="line"></div>
|
||||
<form method="post" action="director.php">
|
||||
<input type="hidden" name="formID" value="login">
|
||||
|
||||
<label for="username">Username</label>
|
||||
<input id="username" name="username" spellcheck="false" required autofocus>
|
||||
|
||||
<label for="password">Password</label>
|
||||
<input id="password" name="password" type="password" spellcheck="false" required>
|
||||
|
||||
<input class="button" type="submit" value="Log In">
|
||||
</form>
|
||||
|
||||
<div id="loginError"></div>
|
||||
</div>
|
||||
';
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
require_once 'functions/init.php';
|
||||
require_once 'functions/core.php';
|
||||
include_once 'components/core/head.php';
|
||||
|
||||
echo home_content();
|
||||
|
||||
include_once 'components/core/foot.php';
|
||||
|
||||
function home_content()
|
||||
{
|
||||
$content = '
|
||||
<div class="article">
|
||||
<h1>Vintage Coding</h1>
|
||||
<h3>Intentional Craftsmanship Over Ephemeral Trends</h3>
|
||||
<div class="line"></div>
|
||||
<p>Vintage Coding, much like appreciating a well-crafted antique or a timeless piece of art, prioritizes quality, longevity, and deep understanding. It\'s about building software with a focus on robust architecture, maintainable code, and a thorough comprehension of the underlying principles. The analogy to vintage clothing is apt – these garments were often made with superior materials and construction, designed to last. Similarly, Vintage Coding aims to create software that withstands the test of time, is easier to understand and modify in the future, and is less prone to the rapid obsolescence that can plague hastily assembled codebases.</p>
|
||||
<p>This site is built in collaboration with Google Gemini, and this highlights a key aspect of Vintage Coding: it\'s not about rejecting modern tools, but rather about employing them thoughtfully and strategically. Gemini, in this context, acts as a knowledgeable partner, offering insights and examples, but the ultimate direction and architectural decisions remain with the human developer. This partnership emphasizes augmented intelligence rather than complete reliance.</p>
|
||||
<p>The following are the cornerstones of Vintage Coding:</p>
|
||||
|
||||
<ol>
|
||||
<li>AI is a partner for exploration and insight, with human oversight and critical evaluation remaining central.</li>
|
||||
<li>Focus on core infrastructure built by humans, with AI used to identify omissions, ensuring a solid foundation.</li>
|
||||
<li>AI tackles specific, well-defined issues, allowing for careful assessment of its output.</li>
|
||||
<li>Emphasis on clean, concise, and readable code for long-term sustainability.</li>
|
||||
</ol><br>
|
||||
|
||||
<p>Vibe Coding\'s potential for uncritical AI adoption and reactive development risks creating fragile, difficult-to-manage systems and hindering developer growth. However, it can serve a purpose in specific contexts where rapid prototyping, immediate experimentation, or disposable solutions are prioritized over long-term maintainability and deep understanding.</p>
|
||||
<p>While seemingly opposing forces, like Yin and Yang, both Vibe Coding and Vintage Coding represent different points on the spectrum of software development. Having the wisdom and understanding to know when to prioritize rapid iteration and when to invest in deliberate craftsmanship is crucial for achieving a balanced and effective approach.</p>
|
||||
</div>
|
||||
';
|
||||
|
||||
return $content;
|
||||
}
|
||||
@@ -1,34 +1,5 @@
|
||||
<?php
|
||||
require_once 'functions/init.php';
|
||||
require_once 'functions/functions.php';
|
||||
include_once 'components/head.php';
|
||||
|
||||
echo home_content();
|
||||
|
||||
include_once 'components/foot.php';
|
||||
|
||||
function home_content()
|
||||
{
|
||||
$content = '
|
||||
<div class="article">
|
||||
<h1>Vintage Coding</h1>
|
||||
<h3>Intentional Craftsmanship Over Ephemeral Trends</h3>
|
||||
<div class="line"></div>
|
||||
<p>Vintage Coding, much like appreciating a well-crafted antique or a timeless piece of art, prioritizes quality, longevity, and deep understanding. It\'s about building software with a focus on robust architecture, maintainable code, and a thorough comprehension of the underlying principles. The analogy to vintage clothing is apt – these garments were often made with superior materials and construction, designed to last. Similarly, Vintage Coding aims to create software that withstands the test of time, is easier to understand and modify in the future, and is less prone to the rapid obsolescence that can plague hastily assembled codebases.</p>
|
||||
<p>This site is built in collaboration with Google Gemini, and this highlights a key aspect of Vintage Coding: it\'s not about rejecting modern tools, but rather about employing them thoughtfully and strategically. Gemini, in this context, acts as a knowledgeable partner, offering insights and examples, but the ultimate direction and architectural decisions remain with the human developer. This partnership emphasizes augmented intelligence rather than complete reliance.</p>
|
||||
<p>The following are the cornerstones of Vintage Coding:</p>
|
||||
|
||||
<ol>
|
||||
<li>AI is a partner for exploration and insight, with human oversight and critical evaluation remaining central.</li>
|
||||
<li>Focus on core infrastructure built by humans, with AI used to identify omissions, ensuring a solid foundation.</li>
|
||||
<li>AI tackles specific, well-defined issues, allowing for careful assessment of its output.</li>
|
||||
<li>Emphasis on clean, concise, and readable code for long-term sustainability.</li>
|
||||
</ol><br>
|
||||
|
||||
<p>Vibe Coding\'s potential for uncritical AI adoption and reactive development risks creating fragile, difficult-to-manage systems and hindering developer growth. However, it can serve a purpose in specific contexts where rapid prototyping, immediate experimentation, or disposable solutions are prioritized over long-term maintainability and deep understanding.</p>
|
||||
<p>While seemingly opposing forces, like Yin and Yang, both Vibe Coding and Vintage Coding represent different points on the spectrum of software development. Having the wisdom and understanding to know when to prioritize rapid iteration and when to invest in deliberate craftsmanship is crucial for achieving a balanced and effective approach.</p>
|
||||
</div>
|
||||
';
|
||||
|
||||
return $content;
|
||||
}
|
||||
if (isset($_SESSION['user']))
|
||||
header('Location: spaces.php?view=list');
|
||||
else
|
||||
header('Location: spaces.php?view=show&id=2025');
|
||||
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
const bar = document.querySelector("#actionBar");
|
||||
const actionSpace = bar.querySelector("#actionSpace");
|
||||
const actionPost = bar.querySelector("#actionPost");
|
||||
|
||||
actionSpace.addEventListener("click", () => {
|
||||
document.querySelector("#primaryActions").style.display = "none";
|
||||
document.querySelector("#spaceActions").style.display = "flex";
|
||||
|
||||
document.querySelector("#spaceBack").addEventListener("click", () => {
|
||||
document.querySelector("#primaryActions").style.display = "flex";
|
||||
document.querySelector("#spaceActions").style.display = "none";
|
||||
});
|
||||
|
||||
let home = document.querySelector("#spaceHome");
|
||||
home.addEventListener("click", () => {
|
||||
applyTransition(home.getAttribute("href"));
|
||||
});
|
||||
|
||||
document.querySelector("#spaceNew").addEventListener("click", () => {
|
||||
fetch("director.php", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
body: "ajaxId=newSpaceHTML",
|
||||
})
|
||||
.then((response) => {
|
||||
return response.json();
|
||||
})
|
||||
.then((data) => {
|
||||
openModal(data["html"]);
|
||||
document.querySelector("#redirect").value = window.location.href;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
actionPost.addEventListener("click", () => {
|
||||
document.querySelector("#primaryActions").style.display = "none";
|
||||
document.querySelector("#postActions").style.display = "flex";
|
||||
|
||||
document.querySelector("#postBack").addEventListener("click", () => {
|
||||
document.querySelector("#primaryActions").style.display = "flex";
|
||||
document.querySelector("#postActions").style.display = "none";
|
||||
});
|
||||
|
||||
document.querySelector("#postNew").addEventListener("click", (e) => {
|
||||
fetch("director.php", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
body: "ajaxId=newPostHTML",
|
||||
})
|
||||
.then((response) => {
|
||||
return response.json();
|
||||
})
|
||||
.then((data) => {
|
||||
console.log(data["html"]);
|
||||
openModal(data["html"]);
|
||||
|
||||
document.querySelector("#redirect").value = window.location.href;
|
||||
|
||||
let newNavThought = document.querySelector("#newNavThought");
|
||||
let newThought = document.querySelector("#newThought");
|
||||
let newNavMoment = document.querySelector("#newNavMoment");
|
||||
let newMoment = document.querySelector("#newMoment");
|
||||
let newNavEssay = document.querySelector("#newNavEssay");
|
||||
let newEssay = document.querySelector("#newEssay");
|
||||
let newPostLabel = document.querySelector("#newPostLabel");
|
||||
let postType = document.querySelector("#postType");
|
||||
|
||||
newNavThought.addEventListener("click", () => {
|
||||
newMoment.style.display = "none";
|
||||
newEssay.style.display = "none";
|
||||
|
||||
newThought.style.display = "flex";
|
||||
newPostLabel.innerText = "New Thought";
|
||||
newThought.querySelector('input[type="text"]').focus();
|
||||
postType.value = "Thought";
|
||||
});
|
||||
|
||||
newNavMoment.addEventListener("click", () => {
|
||||
newThought.style.display = "none";
|
||||
newEssay.style.display = "none";
|
||||
|
||||
newMoment.style.display = "flex";
|
||||
newPostLabel.innerText = "New Moment";
|
||||
postType.value = "Moment";
|
||||
});
|
||||
|
||||
newNavEssay.addEventListener("click", () => {
|
||||
newThought.style.display = "none";
|
||||
newMoment.style.display = "none";
|
||||
|
||||
newEssay.style.display = "flex";
|
||||
newPostLabel.innerText = "New Essay";
|
||||
newEssay.querySelector('input[type="text"]').focus();
|
||||
postType.value = "Essay";
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,66 @@
|
||||
let dropdowns = document.querySelectorAll(".dropdown");
|
||||
|
||||
dropdowns.forEach((el) => {
|
||||
el.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
let dropContent = el.querySelector(".dropdownContent");
|
||||
dropContent.style.display = "block";
|
||||
|
||||
dropContent.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
window.addEventListener("click", () => {
|
||||
document.querySelectorAll(".dropdownContent").forEach((dc) => {
|
||||
dc.style.display = "none";
|
||||
});
|
||||
});
|
||||
|
||||
function editPost(id) {
|
||||
fetch("director.php", {
|
||||
method: "POST",
|
||||
|
||||
// TODO: Add Authorization header with JWT
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
body: "ajaxId=editPostHTML&id=" + id,
|
||||
})
|
||||
.then((response) => {
|
||||
return response.json();
|
||||
})
|
||||
.then((data) => {
|
||||
openModal(data["html"]);
|
||||
document.querySelector("#redirect").value = window.location.href;
|
||||
});
|
||||
}
|
||||
|
||||
function deleteSpace(id) {
|
||||
document.querySelector("#space-" + id).remove();
|
||||
|
||||
fetch("director.php", {
|
||||
method: "POST",
|
||||
|
||||
// TODO: Add Authorization header with JWT
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
body: "ajaxId=deleteSpace&id=" + id,
|
||||
});
|
||||
}
|
||||
|
||||
function deletePost(id) {
|
||||
document.querySelector("#post-" + id).remove();
|
||||
|
||||
fetch("director.php", {
|
||||
method: "POST",
|
||||
|
||||
// TODO: Add Authorization header with JWT
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
body: "ajaxId=deletePost&id=" + id,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
let essays = document.querySelectorAll(".divLink");
|
||||
|
||||
essays.forEach((e) => {
|
||||
let link = e.querySelector("a").href;
|
||||
let id = link.split("=")[2];
|
||||
|
||||
e.addEventListener("click", () => {
|
||||
fetch("director.php", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
body: "ajaxId=viewEssay&id=" + id,
|
||||
})
|
||||
.then((response) => {
|
||||
return response.json();
|
||||
})
|
||||
.then((data) => {
|
||||
if (!data["html"]) return;
|
||||
|
||||
openModal(data["html"]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
const nav = document.querySelector("nav");
|
||||
const nav_links = nav.querySelectorAll("ul li a");
|
||||
const theme_toggle = nav.querySelector("button");
|
||||
const back = document.querySelector("#backButton");
|
||||
const links = document.querySelectorAll(".fillDiv");
|
||||
|
||||
if (back)
|
||||
back.addEventListener("click", () => {
|
||||
console.log("back");
|
||||
history.back();
|
||||
});
|
||||
|
||||
links.forEach((el) => {
|
||||
el.addEventListener("click", () => {
|
||||
el.preventDefault();
|
||||
applyTransition(el.getAttribute("href"));
|
||||
});
|
||||
});
|
||||
|
||||
nav_links.forEach((el) => {
|
||||
el.addEventListener("click", () => {
|
||||
el.preventDefault();
|
||||
applyTransition(el.getAttribute("href"));
|
||||
});
|
||||
});
|
||||
|
||||
function applyTransition(href) {
|
||||
if ("startViewTransition" in document) {
|
||||
document.startViewTransition(() => {
|
||||
window.location.href = href;
|
||||
});
|
||||
} else {
|
||||
window.location.href = href;
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
const darkThemeMq = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
if (darkThemeMq.matches) {
|
||||
const link = document.createElement("link");
|
||||
link.rel = "stylesheet";
|
||||
link.type = "text/css";
|
||||
link.href = "css/dark.css";
|
||||
document.head.appendChild(link);
|
||||
// Theme set to dark.
|
||||
} else {
|
||||
const link = document.createElement("link");
|
||||
link.rel = "stylesheet";
|
||||
link.type = "text/css";
|
||||
link.href = "css/light.css";
|
||||
document.head.appendChild(link);
|
||||
// Theme set to light.
|
||||
}
|
||||
|
||||
darkThemeMq.addEventListener("change", (e) => {
|
||||
if (e.matches) {
|
||||
const link = document.createElement("link");
|
||||
link.rel = "stylesheet";
|
||||
link.type = "text/css";
|
||||
link.href = "css/dark.css";
|
||||
document.head.appendChild(link);
|
||||
// Theme set to dark.
|
||||
} else {
|
||||
const link = document.createElement("link");
|
||||
link.rel = "stylesheet";
|
||||
link.type = "text/css";
|
||||
link.href = "css/light.css";
|
||||
document.head.appendChild(link);
|
||||
// Theme set to light.
|
||||
}
|
||||
});
|
||||
+2
-63
@@ -15,72 +15,11 @@
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var todos = document.getElementsByClassName('todo_item');
|
||||
var action_items = (document.getElementById('todo_actions')).querySelectorAll('button');
|
||||
|
||||
// General Modal handling
|
||||
function handle_modal(modal) {
|
||||
console.log('handling modal');
|
||||
let modal_close = modal.querySelector('.modal_close');
|
||||
let submit_button = modal.querySelector('input[type="submit"]');
|
||||
modal.style.display = 'block';
|
||||
|
||||
modal_close.addEventListener('click', function() {
|
||||
modal.style.display = "none";
|
||||
});
|
||||
|
||||
submit_button.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
let todo = {
|
||||
'title': modal.querySelector('#title').value,
|
||||
'description': modal.querySelector('#description'),
|
||||
'priority': modal.querySelector('#priority'),
|
||||
'due_date': modal.querySelector('#due_date'),
|
||||
};
|
||||
|
||||
fetch('director.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
body: 'ajax_id=todo&action_id=create_update_todo&todo_id=' + this.todo_id + '&todo=' + encodeURIComponent(JSON.stringify(todo)),
|
||||
})
|
||||
.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
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
for (let i = 0; i < action_items.length; i++) {
|
||||
let action = action_items[i];
|
||||
|
||||
action.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
switch (action.value) {
|
||||
case 'new':
|
||||
let new_todo_item = document.querySelector('#new_todo_item');
|
||||
handle_modal(new_todo_item);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
//var todos = document.querySelectorAll('todo_item');
|
||||
|
||||
for (let i = 0; i < todos.length; i++) {
|
||||
let item = todos[i];
|
||||
var item = todos[i];
|
||||
|
||||
// Detailed todo item view via a modal
|
||||
let modal_button = item.querySelector('.modal_activation_area');
|
||||
let modal = item.querySelector('.modal');
|
||||
modal_button.addEventListener('click', () => handle_modal(modal));
|
||||
|
||||
// Checkboxes & AJAX for updating the DB
|
||||
var checkbox = item.querySelector('input[type="checkbox"]');
|
||||
checkbox.todo_id = item.querySelector('input[name="todo_id"]').value;
|
||||
checkbox.is_checked = checkbox.checked;
|
||||
|
||||
+243
@@ -0,0 +1,243 @@
|
||||
const login = document.querySelector("#login");
|
||||
const logout = document.querySelector("#logout");
|
||||
const signup = document.querySelector("#signup");
|
||||
|
||||
if (logout) {
|
||||
logout.addEventListener("click", () => {
|
||||
fetch("director.php", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
body: "ajaxId=logout",
|
||||
}).then(() => {
|
||||
if ("startViewTransition" in document) {
|
||||
document.startViewTransition(() => {
|
||||
window.location.href = "spaces.php?view=list";
|
||||
});
|
||||
} else {
|
||||
window.location.href = "spaces.php?view=list";
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (login) {
|
||||
login.addEventListener("click", () => {
|
||||
fetch("director.php", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
body: "ajaxId=loginHTML",
|
||||
})
|
||||
.then((response) => {
|
||||
return response.json();
|
||||
})
|
||||
.then((data) => {
|
||||
openModal(data["html"]);
|
||||
|
||||
const username_field = modalContent.querySelector("#username");
|
||||
const passwordField = modalContent.querySelector("#password");
|
||||
const submit_button = modalContent.querySelector(
|
||||
'input[type="submit"]',
|
||||
);
|
||||
|
||||
submit_button.addEventListener("click", async (e) => {
|
||||
e.preventDefault();
|
||||
requestAuth(username_field.value, passwordField.value);
|
||||
});
|
||||
|
||||
function requestAuth(username, password) {
|
||||
fetch("director.php", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
body: "ajaxId=login&username=" + username + "&password=" + password,
|
||||
})
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
console.log("Login Failed!");
|
||||
}
|
||||
|
||||
return response.json();
|
||||
})
|
||||
.then((data) => {
|
||||
if ("startViewTransition" in document) {
|
||||
document.startViewTransition(() => {
|
||||
window.location.href = data["redirect"];
|
||||
});
|
||||
} else {
|
||||
// Fallback for browsers that don't support View Transitions
|
||||
window.location.href = data["redirect"];
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (signup) {
|
||||
signup.addEventListener("click", () => {
|
||||
fetch("director.php", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
body: "ajaxId=signupHTML",
|
||||
})
|
||||
.then((response) => {
|
||||
return response.json();
|
||||
})
|
||||
.then((data) => {
|
||||
openModal(data["html"]);
|
||||
|
||||
const submit = modalContent.querySelector('input[type="submit"]');
|
||||
submit.disabled = true;
|
||||
|
||||
const signupErrorArea = modalContent.querySelector("#signupError");
|
||||
|
||||
const usernameField = modalContent.querySelector("#username");
|
||||
usernameField.addEventListener("blur", checkUsername);
|
||||
|
||||
const passwordField = modalContent.querySelector("#password");
|
||||
passwordField.addEventListener("input", checkPW);
|
||||
|
||||
const vPasswordField = modalContent.querySelector("#vPassword");
|
||||
vPasswordField.addEventListener("input", matchPW);
|
||||
|
||||
submit.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
checkUsername();
|
||||
checkPW();
|
||||
matchPW();
|
||||
|
||||
if (
|
||||
usernameField.value != "" &&
|
||||
passwordField.value != "" &&
|
||||
vPasswordField.value != "" &&
|
||||
signupErrorArea.innerHTML == ""
|
||||
)
|
||||
modalContent.querySelector("form").submit();
|
||||
});
|
||||
|
||||
function checkUsername() {
|
||||
const username = usernameField.value;
|
||||
|
||||
fetch("director.php", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
body: "ajaxId=usernameCheck&username=" + username,
|
||||
})
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
console.log("Failed to check if username exists!");
|
||||
}
|
||||
|
||||
return response.json(); // Parse response body as JSON
|
||||
})
|
||||
.then((data) => {
|
||||
if (data["exists"]) {
|
||||
console.log("user exists");
|
||||
if (!document.querySelector("#userExists")) {
|
||||
let p = document.createElement("p");
|
||||
p.id = "userExists";
|
||||
p.innerText = "Username is taken.";
|
||||
|
||||
signupErrorArea.append(p);
|
||||
submit.disabled = true;
|
||||
}
|
||||
} else {
|
||||
let p = signupErrorArea.querySelector("#userExists");
|
||||
if (p) p.remove();
|
||||
matchPW();
|
||||
|
||||
if (
|
||||
signupErrorArea.innerHTML == "" &&
|
||||
passwordField.value != "" &&
|
||||
vPasswordField.value != ""
|
||||
)
|
||||
submit.disabled = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function checkPW() {
|
||||
let pw = passwordField.value;
|
||||
if (pw.length < 8) {
|
||||
if (!document.querySelector("#pwLength")) {
|
||||
let p = document.createElement("p");
|
||||
p.id = "pwLength";
|
||||
p.innerText =
|
||||
"Password length must be greater than 8 characters.";
|
||||
|
||||
signupErrorArea.append(p);
|
||||
}
|
||||
} else {
|
||||
let p = signupErrorArea.querySelector("#pwLength");
|
||||
if (p) p.remove();
|
||||
matchPW();
|
||||
|
||||
if (
|
||||
signupErrorArea.innerHTML == "" &&
|
||||
passwordField.value != "" &&
|
||||
vPasswordField.value != ""
|
||||
)
|
||||
submit.disabled = false;
|
||||
}
|
||||
|
||||
const num_regex = /\d/;
|
||||
if (!num_regex.test(pw)) {
|
||||
if (!document.querySelector("#pwNum")) {
|
||||
let p = document.createElement("p");
|
||||
p.id = "pwNum";
|
||||
p.innerText = "Password must have at least 1 digit.";
|
||||
|
||||
signupErrorArea.append(p);
|
||||
submit.disabled = true;
|
||||
}
|
||||
} else {
|
||||
let p = signupErrorArea.querySelector("#pwNum");
|
||||
if (p) p.remove();
|
||||
matchPW();
|
||||
|
||||
if (
|
||||
signupErrorArea.innerHTML == "" &&
|
||||
passwordField.value != "" &&
|
||||
vPasswordField.value != ""
|
||||
)
|
||||
submit.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
function matchPW() {
|
||||
let pw = passwordField.value;
|
||||
let vPW = vPasswordField.value;
|
||||
|
||||
if (pw != vPW) {
|
||||
if (!document.querySelector("#pwMatch")) {
|
||||
let p = document.createElement("p");
|
||||
p.id = "pwMatch";
|
||||
p.innerText = "Passwords must match.";
|
||||
|
||||
signupErrorArea.append(p);
|
||||
submit.disabled = true;
|
||||
}
|
||||
} else {
|
||||
let p = signupErrorArea.querySelector("#pwMatch");
|
||||
if (p) p.remove();
|
||||
if (
|
||||
signupErrorArea.innerHTML == "" &&
|
||||
passwordField.value != "" &&
|
||||
vPasswordField.value != ""
|
||||
)
|
||||
submit.disabled = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
const stdModal = document.querySelector("#stdModal");
|
||||
let modalContent = document.querySelector(".modalContent");
|
||||
|
||||
function openModal(html) {
|
||||
stdModal.innerHTML = html;
|
||||
stdModal.style.display = "flex";
|
||||
modalContent = document.querySelector(".modalContent");
|
||||
|
||||
window.addEventListener("click", () => {
|
||||
closeModal();
|
||||
});
|
||||
|
||||
modalContent.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
});
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
stdModal.innerHTML = "";
|
||||
stdModal.style.display = "none";
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
USE vintagecoding;
|
||||
|
||||
INSERT INTO user (user_id, username, email, password_hash, role_id, profile_picture)
|
||||
VALUES (5749248, 'jsmith', 'jsmith@email.com', 'f0e4c2f76c58916ec258f246851bea091d14d4247a2fc3e18694461b1816e13b', 4, '2025.jpg'),
|
||||
(5789203, 'dummy', 'dummy@iamdumb.com', 'f0e4c2f76c58916ec258f246851bea091d14d4247a2fc3e18694461b1816e13b', 4, '2025.jpg'),
|
||||
(5723948, 'writer', 'writer@something.com', 'f0e4c2f76c58916ec258f246851bea091d14d4247a2fc3e18694461b1816e13b', 3, '5723948.jpg')
|
||||
;
|
||||
|
||||
INSERT INTO article (author_id, title, excerpt, published_at)
|
||||
VALUES (2025, 'Testing vintagecoding.net', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas a mauris sit amet dui pellentesque sodales. Pellentesque non viverra leo, et congue metus.', CURRENT_TIMESTAMP),
|
||||
(5723948, 'Something Else', 'Here goes some random crap. Lorem ipsum akdfljskjlag IDK what to put here. I am just filling the space requirement. Blah blah blah blah, what does this look like? Is vintagecoding.net cool?', CURRENT_TIMESTAMP)
|
||||
;
|
||||
|
||||
INSERT INTO article_tags (article_id, tag_id) VALUES (21, 2), (21, 6);
|
||||
@@ -1,85 +0,0 @@
|
||||
CREATE DATABASE vintagecoding;
|
||||
USE vintagecoding;
|
||||
|
||||
CREATE TABLE roles (
|
||||
role_id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
role VARCHAR(16) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE tags (
|
||||
tag_id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
tag VARCHAR(16) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE user (
|
||||
user_id INT PRIMARY KEY,
|
||||
username VARCHAR(32) NOT NULL UNIQUE,
|
||||
email VARCHAR(64) NOT NULL UNIQUE,
|
||||
password_hash VARCHAR(256) NOT NULL,
|
||||
role_id INT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
last_active TIMESTAMP DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
is_active BOOLEAN DEFAULT FALSE,
|
||||
profile_picture VARCHAR(256),
|
||||
bio VARCHAR(256),
|
||||
x_username VARCHAR(32),
|
||||
fb_username VARCHAR(32),
|
||||
ig_username VARCHAR(32),
|
||||
website VARCHAR(64),
|
||||
FOREIGN KEY (role_id) REFERENCES roles (role_id)
|
||||
);
|
||||
|
||||
CREATE TABLE remember_user (
|
||||
token VARCHAR(128) PRIMARY KEY,
|
||||
user_id INT NOT NULL,
|
||||
remote_addr VARCHAR(64) NOT NULL,
|
||||
http_forward VARCHAR(64),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES user (user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE article (
|
||||
article_id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
author_id INT NOT NULL,
|
||||
title VARCHAR(26) NOT NULL,
|
||||
slug VARCHAR(32),
|
||||
read_count INT DEFAULT 0,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
published_at TIMESTAMP DEFAULT NULL,
|
||||
published BOOLEAN DEFAULT TRUE,
|
||||
excerpt VARCHAR(256),
|
||||
FOREIGN KEY (author_id) REFERENCES user(user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE article_tags (
|
||||
article_id INT NOT NULL,
|
||||
tag_id INT NOT NULL,
|
||||
PRIMARY KEY (article_id, tag_id),
|
||||
FOREIGN KEY (article_id) REFERENCES article(article_id),
|
||||
FOREIGN KEY (tag_id) REFERENCES tags(tag_id)
|
||||
);
|
||||
|
||||
CREATE TABLE follows (
|
||||
follower_user_id INT NOT NULL,
|
||||
following_user_id INT NOT NULL,
|
||||
notify_user BOOLEAN DEFAULT FALSE,
|
||||
followed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (follower_user_id, following_user_id),
|
||||
FOREIGN KEY (follower_user_id) REFERENCES user(user_id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (following_user_id) REFERENCES user(user_id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
INSERT INTO roles (role)
|
||||
VALUES ('owner'), ('admin'), ('contributor'), ('reader');
|
||||
|
||||
INSERT INTO tags (tag)
|
||||
VALUES ('linux'), ('web-dev'), ('raspberry-pi'), ('self-hosting'), ('devlog'), ('testing');
|
||||
|
||||
INSERT INTO user (user_id, username, email, password_hash, role_id, profile_picture)
|
||||
VALUES (2025, 'quaxlyqueen', 'me@joshashton.dev', '057ba03d6c44104863dc7361fe4578965d1887360f90a0895882e58a6248fc86', 1, '2025.jpg');
|
||||
|
||||
INSERT INTO article (author_id, title, excerpt, published_at)
|
||||
VALUES (2025, 'Building vintagecoding.net', 'A devlog of the creation of vintagecoding.net and a test at the formatting of article cards and articles. Let the great experiment begin!', CURRENT_TIMESTAMP);
|
||||
|
||||
INSERT INTO article_tags (article_id, tag_id) VALUES (1, 2), (1, 4), (1, 5);
|
||||
@@ -1,54 +0,0 @@
|
||||
ARGS_COUNT=$#
|
||||
help () {
|
||||
echo "CLI Tool used to initialize the database for vintagecoding.net."
|
||||
echo "With no arguments, it creates the application user in MariaDB,"
|
||||
echo "and creates the following tables:"
|
||||
echo "- roles (populated);"
|
||||
echo "- tags (populated);"
|
||||
echo "- user;"
|
||||
echo "- articles;"
|
||||
echo "- article_tags;"
|
||||
echo ""
|
||||
echo "The following flags are accepted:"
|
||||
echo " init_db.sh { --help | -h }"
|
||||
echo " init_db.sh { --delete | -d } { --verbose | -v }"
|
||||
}
|
||||
|
||||
if [[ $ARGS_COUNT > 0 ]]; then
|
||||
if [[ "$1" == "--help" || "$1" == "-h" ]]; then
|
||||
help
|
||||
exit
|
||||
fi
|
||||
|
||||
# Delete the existing database and start over.
|
||||
if [[ "$1" == "--delete" || "$1" == "-d" ]]; then
|
||||
if [[ "$2" == "--verbose" || "$2" == "-v" ]]; then
|
||||
echo "Deleting the existing database vintagecoding..."
|
||||
fi
|
||||
echo "vintage user pw"
|
||||
mariadb -u vintage -p -e "DROP DATABASE vintagecoding;"
|
||||
|
||||
if [[ "$2" == "--verbose" || "$2" == "-v" ]]; then
|
||||
echo "Deleting the vintage user..."
|
||||
fi
|
||||
echo "root user pw"
|
||||
mariadb -u root -p -e "DROP USER vintage@localhost;"
|
||||
|
||||
if [[ "$2" == "--verbose" || "$2" == "-v" ]]; then
|
||||
echo "Creating the vintage user..."
|
||||
fi
|
||||
echo "root user pw"
|
||||
mariadb -u root -p < setup.sql;
|
||||
|
||||
if [[ "$2" == "--verbose" || "$2" == "-v" ]]; then
|
||||
echo "Creating (and populating enum/static data) tables..."
|
||||
fi
|
||||
echo "vintage user pw"
|
||||
mariadb -u vintage -p < init.sql;
|
||||
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
|
||||
#mariadb -u root -p < setup.sql;
|
||||
mariadb -u vintage -p < init.sql;
|
||||
@@ -1,3 +0,0 @@
|
||||
--This must be ran as the root user in MariaDB
|
||||
CREATE USER vintage@localhost IDENTIFIED BY 'changeme';
|
||||
GRANT ALL PRIVILEGES ON vintagecoding.* TO vintage@localhost IDENTIFIED BY 'changeme';
|
||||
+202
@@ -0,0 +1,202 @@
|
||||
<?php
|
||||
require_once 'functions/init.php';
|
||||
|
||||
// UI Components
|
||||
/* foreach (glob('components/spaces/*.php') as $file) */
|
||||
/* require_once $file; */
|
||||
|
||||
require_once 'components/core/head.php';
|
||||
|
||||
if (isset($_GET['view'])) {
|
||||
switch ($_GET['view']) {
|
||||
case 'essay':
|
||||
if (isset($_GET['id'])) {
|
||||
// TODO: Need another check here to verify the user is in the Essay's space.
|
||||
$essay = Post::retrieveFromDB($_GET['id']);
|
||||
if ($essay)
|
||||
echo displayEssay($essay);
|
||||
else
|
||||
echo errorScreen('Essay does not exist!', 'The Essay ID provided does not exist in the database.');
|
||||
} else
|
||||
echo displaySpace(2025);
|
||||
break;
|
||||
case 'show':
|
||||
// TODO: After implementing the notification modal, notify the user on success/fail auth events.
|
||||
if (isset($_GET['id'])) {
|
||||
if (isset($_SESSION['user'])) {
|
||||
$availableSpaces = unserialize($_SESSION['user'])->getSpaces();
|
||||
foreach ($availableSpaces as $s) {
|
||||
$space = $s->getSpace();
|
||||
if ($space->getId() == $_GET['id']) {
|
||||
echo displaySpace($_GET['id']);
|
||||
break;
|
||||
} else if ($space->getVisibility() == 1) {
|
||||
echo displaySpace($_GET['id']);
|
||||
break;
|
||||
} else
|
||||
echo 'TODO: Notification Modal -> User not a member';
|
||||
}
|
||||
} else {
|
||||
if ($space->getVisibility() == 1)
|
||||
echo displaySpace($_GET['id']);
|
||||
else
|
||||
echo 'TODO: Notification Modal -> Space is not Open';
|
||||
}
|
||||
} else
|
||||
echo displaySpaceList();
|
||||
break;
|
||||
case 'list':
|
||||
if (isset($_SESSION['user']))
|
||||
echo displaySpaceList();
|
||||
else
|
||||
echo displaySpace(2025);
|
||||
break;
|
||||
default:
|
||||
echo displaySpaceList();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
echo displaySpace(2025);
|
||||
}
|
||||
|
||||
if (isset($_SESSION['user']))
|
||||
echo actionBar();
|
||||
|
||||
if (isset($_GET['id']))
|
||||
echo backButton();
|
||||
|
||||
require_once 'components/core/foot.php';
|
||||
|
||||
function backButton()
|
||||
{
|
||||
$html = '
|
||||
<div class="link" id="backButton">
|
||||
<i class="nf nf-fa-arrow_left"></i>
|
||||
</div>
|
||||
';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
function actionBar()
|
||||
{
|
||||
$user = unserialize($_SESSION['user']);
|
||||
|
||||
$html = '
|
||||
<div class="std_border med_width padding glass" id="actionBar">
|
||||
<div class="row space_between" id="primaryActions">
|
||||
<div class="column center link med_width" id="actionSpace"><i class="nf nf-md-layers_outline"></i><p class="link">Space</p></div>
|
||||
<div class="column center link med_width" id="actionPost"><i class="nf nf-md-text"></i><p class="link">Post</p></div>
|
||||
</div>
|
||||
<div class="row space_between" id="postActions" style="display: none;">
|
||||
<div class="column center link med_width" id="postBack"><i class="nf nf-cod-arrow_circle_left"></i><p class="link">Back</p></div>
|
||||
<div class="column center link med_width" id="postNew"><i class="nf nf-md-chat_plus"></i><p class="link">New</p></div>
|
||||
</div>
|
||||
<div class="row space_between" id="spaceActions" style="display: none;">
|
||||
<div class="column center link med_width" id="spaceBack"><i class="nf nf-cod-arrow_circle_left"></i><p class="link">Back</p></div>
|
||||
<div class="column center link med_width" id="spaceHome" href="spaces.php?view=show&id=' . $user->getId() . '"><i class="nf nf-fa-home"></i><p class="link">Home</p></div>
|
||||
<div class="column center link med_width" id="spaceNew"><i class="nf nf-md-layers_plus"></i><p class="link">New</p></div>
|
||||
</div>
|
||||
</div>
|
||||
';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
function errorScreen(String $heading, String $msg)
|
||||
{
|
||||
$html = '
|
||||
<div class="column std_border med_width padding center top_margin">
|
||||
<h1>' . $heading . '</h1>
|
||||
<p>' . $msg . '</p>
|
||||
</div>
|
||||
';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
function displayEssay(Essay $e)
|
||||
{
|
||||
/* if (isset($_SESSION['user'])) */
|
||||
/* if ($e->allowUser(unserialize($_SESSION['user'])) || $e->getSpace()->getVisibility() != 1) */
|
||||
/* return errorScreen('Access Denied!', 'You do not have access to the Space that this Essay is in.'); */
|
||||
|
||||
$parsedown = new Parsedown();
|
||||
$parsedown->setSafeMode(true);
|
||||
|
||||
$html = '
|
||||
<div class="std_width std_border padding center top_margin" style="height: 75vh; overflow-y: auto;">
|
||||
' . $parsedown->parse($e->getMarkdown()) . '
|
||||
</div>
|
||||
';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
function displaySpaceList()
|
||||
{
|
||||
if (!isset($_SESSION['user']))
|
||||
return displaySpace();
|
||||
|
||||
$user = unserialize($_SESSION['user']);
|
||||
|
||||
$html = '
|
||||
<div class="std_width std_border padding center top_margin" style="height: 75vh; overflow-y: auto;">
|
||||
<div class="column space_between full_width">
|
||||
<h1>Spaces</h4>
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
';
|
||||
|
||||
$spaces = $user->getSpaces();
|
||||
foreach ($spaces as $s)
|
||||
$html .= $s->getSpace()->getCardHTML();
|
||||
|
||||
$html .= '
|
||||
</div>
|
||||
';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
function displaySpace($id = 2025)
|
||||
{
|
||||
$spaces = unserialize($_SESSION['user'])->getSpaces();
|
||||
foreach ($spaces as $s) {
|
||||
$space = $s->getSpace();
|
||||
if ($space->getId() == $id) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$space)
|
||||
return;
|
||||
|
||||
if ($space) {
|
||||
$html = '
|
||||
<div class="std_width std_border padding center top_margin" style="height: 75vh; overflow-y: auto;">
|
||||
<div class="column space_between full_width">
|
||||
<h1>' . $space->getName() . '</h4>
|
||||
<p>' . $space->getDescription() . '</p>
|
||||
</div>
|
||||
<div class="line"></div>
|
||||
';
|
||||
|
||||
$subspaces = $space->getSubSpaces();
|
||||
foreach ($subspaces as $ss) {
|
||||
$html .= $ss->getCardHTML();
|
||||
}
|
||||
|
||||
// TODO: Need to investigate this bug in Posts
|
||||
$posts = $space->getPosts();
|
||||
foreach ($posts as $post)
|
||||
foreach ($post as $p)
|
||||
$html .= $p->getCardHTML();
|
||||
|
||||
$html .= '
|
||||
</div>
|
||||
';
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<?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';
|
||||
@@ -1,113 +0,0 @@
|
||||
<?php
|
||||
require_once 'functions/init.php';
|
||||
require_once 'functions/functions.php';
|
||||
include_once 'functions/account_functions.php';
|
||||
|
||||
// UI Components
|
||||
foreach (glob('components/user/*.php') as $file)
|
||||
require_once $file;
|
||||
|
||||
$msg = '';
|
||||
|
||||
if (isset($_POST['form_id'])) {
|
||||
switch ($_POST['form_id']) {
|
||||
case 'signup_form':
|
||||
$msg = create_user(
|
||||
$_POST['username'],
|
||||
$_POST['email'],
|
||||
$_POST['password'],
|
||||
$_POST['verify_password'],
|
||||
4, // TODO: Need to allow for other roles to be created, if the submission is from an administrator or owner.
|
||||
(!empty($_FILES) ? $_FILES : ''),
|
||||
(!empty($_POST['crop_x']) ? $_POST['crop_x'] : ''),
|
||||
(!empty($_POST['crop_y']) ? $_POST['crop_y'] : ''),
|
||||
(!empty($_POST['crop_width']) ? $_POST['crop_width'] : ''),
|
||||
$_POST['required_field']
|
||||
);
|
||||
|
||||
if ($msg === true) {
|
||||
login($_POST['username'], $_POST['password'], false);
|
||||
header('Location: user.php?view=display&user_id=' . $_SESSION['user_id']);
|
||||
}
|
||||
break;
|
||||
case 'login_form':
|
||||
$msg = login(
|
||||
$_POST['username'],
|
||||
$_POST['password'],
|
||||
(isset($_POST['stay_logged_in']) ? true : false)
|
||||
);
|
||||
|
||||
if ($msg === true)
|
||||
if (isset($_GET['redirect']))
|
||||
header('Location: ' . urldecode($_GET['redirect']));
|
||||
else
|
||||
header('Location: .');
|
||||
break;
|
||||
case 'reset_pw_form':
|
||||
$msg = reset_password(
|
||||
($_SESSION['role_id'] <= admin && $_SESSION['user_id'] != $_POST['user_id'] ? $_POST['user_id'] : $_SESSION['user_id']),
|
||||
$_POST['new_pw'],
|
||||
$_POST['verify_new_pw']
|
||||
);
|
||||
|
||||
break;
|
||||
case 'update_email_form':
|
||||
$msg = update_email(
|
||||
($_SESSION['role_id'] <= admin && $_SESSION['user_id'] != $_POST['user_id'] ? $_POST['user_id'] : $_SESSION['user_id']),
|
||||
$_POST['new_email'],
|
||||
$_POST['verify_new_email']
|
||||
);
|
||||
|
||||
break;
|
||||
case 'update_username_form':
|
||||
$msg = update_username(
|
||||
($_SESSION['role_id'] <= admin && $_SESSION['user_id'] != $_POST['user_id'] ? $_POST['user_id'] : $_SESSION['user_id']),
|
||||
$_POST['new_username'],
|
||||
$_POST['verify_new_username']
|
||||
);
|
||||
break;
|
||||
case 'update_profile_picture_form':
|
||||
update_profile_picture($_SESSION['user_id']);
|
||||
break;
|
||||
case 'request_role_change_form':
|
||||
request_role_change(
|
||||
$_SESSION['user_id'],
|
||||
$_POST['requested_role']
|
||||
);
|
||||
break;
|
||||
case 'delete_account_form':
|
||||
$msg = delete_account(
|
||||
($_SESSION['role_id'] <= admin && $_SESSION['user_id'] != $_POST['user_id'] ? $_POST['user_id'] : $_SESSION['user_id']),
|
||||
$_POST['delete_password'],
|
||||
$_POST['delete_verify_password']
|
||||
);
|
||||
|
||||
break;
|
||||
case 'follow':
|
||||
follow_user($_SESSION['user_id'], $_POST['author_id'], ($_POST['follow'] == 'email_notify' ? 1 : 0));
|
||||
break;
|
||||
case 'unfollow':
|
||||
unfollow_user($_SESSION['user_id'], $_POST['author_id']);
|
||||
break;
|
||||
}
|
||||
echo $msg;
|
||||
}
|
||||
|
||||
include_once 'components/head.php';
|
||||
|
||||
switch ($_GET['view']) {
|
||||
case 'login':
|
||||
echo login_form(($msg ? $msg : ''));
|
||||
break;
|
||||
case 'signup':
|
||||
echo signup_form(($msg ? $msg : ''));
|
||||
break;
|
||||
case 'logout':
|
||||
logout();
|
||||
break;
|
||||
case 'display':
|
||||
echo (isset($_GET['user_id']) ? user_view($_GET['user_id']) : header('Location: .'));
|
||||
break;
|
||||
}
|
||||
|
||||
include_once 'components/foot.php';
|
||||
Reference in New Issue
Block a user