From 5af0547864f730091c98d64cc18014bc69d0a041 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Wed, 19 Mar 2025 23:27:20 -0600 Subject: [PATCH] implemented database, article cards, and parsing from markdown. --- .gitignore | 2 + article.php | 10 ++++ components/foot.php | 4 ++ components/head.php | 10 ++++ composer.json | 15 ++++++ css/base.css | 82 ++++++++++++++++++++++++++++++--- css/images.css | 5 ++ css/text.css | 28 +++++++++++ functions/article_functions.php | 71 ++++++++++++++++++++++++++++ functions/db_functions.php | 53 +++++++++++++++++++++ functions/functions.php | 20 ++++++++ functions/init.php | 11 +++++ index.php | 24 +++++----- scripts/init.sql | 54 ++++++++++++++++++++++ scripts/init_db.sh | 54 ++++++++++++++++++++++ scripts/setup.sql | 3 ++ 16 files changed, 426 insertions(+), 20 deletions(-) create mode 100644 article.php create mode 100644 components/foot.php create mode 100644 components/head.php create mode 100644 composer.json create mode 100644 css/images.css create mode 100644 functions/article_functions.php create mode 100644 functions/db_functions.php create mode 100644 functions/functions.php create mode 100644 functions/init.php create mode 100644 scripts/init.sql create mode 100755 scripts/init_db.sh create mode 100644 scripts/setup.sql diff --git a/.gitignore b/.gitignore index ffd6450..f6a681e 100755 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ *.env +composer.lock /vendor/ +profile_pictures diff --git a/article.php b/article.php new file mode 100644 index 0000000..0aec9e4 --- /dev/null +++ b/article.php @@ -0,0 +1,10 @@ + + + + diff --git a/components/head.php b/components/head.php new file mode 100644 index 0000000..fe942c9 --- /dev/null +++ b/components/head.php @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..53a1387 --- /dev/null +++ b/composer.json @@ -0,0 +1,15 @@ +{ + "name": "quaxlyqueen/vintagecoding.net", + "description": "My personal blogging platform.", + "type": "project", + "require": { + "erusev/parsedown": "^1.7", + "vlucas/phpdotenv": "^5.6" + }, + "authors": [ + { + "name": "Josh Ashton", + "email": "me@joshashton.dev" + } + ] +} diff --git a/css/base.css b/css/base.css index 0cc023f..54662ba 100644 --- a/css/base.css +++ b/css/base.css @@ -7,16 +7,84 @@ body { background-color: black; } -.card { - margin: 20% auto; - width: 60%; - padding-top: 50px; - padding-bottom: 50px; +.line { + height: 1px; + width: 100%; + background-color: white; + border-top: 1px solid white; + margin-top: 5px; + margin-bottom: 5px; +} - border: 1px solid white; +.row { + display: flex; + justify-content: space-between; + width: 100%; + margin: 15px 0px 15px 0px; +} + +.center-h { + margin: 0 auto; +} + +.article_card { + margin: 0 auto; + margin-top: 15%; + padding: 18px; + height: max-content; + width: 60%; + border: 5px solid white; border-radius: 18px; - text-align: center; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +.card_info_box { + display: flex; +} + +.col-right { + margin-right: 25px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: end; +} + +.card_pic_box { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +.button { + padding: 15px; + text-decoration: none; + border: 2px solid #00FF41; + color: white; + border-radius: 9px; +} + +.tag { + margin: 15px; + padding: 10px; + border-radius: 18px; + border: 2px solid #008F11; + color: white; + text-decoration: none; +} + +.tag_row {} + +.tag_box { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; } @media (max-width: 980px) { diff --git a/css/images.css b/css/images.css new file mode 100644 index 0000000..b977a60 --- /dev/null +++ b/css/images.css @@ -0,0 +1,5 @@ +.card_profile_picture { + height: 64px; + width: auto; + border-radius: 50%; +} diff --git a/css/text.css b/css/text.css index d3688da..5c46118 100644 --- a/css/text.css +++ b/css/text.css @@ -3,11 +3,39 @@ h1 { color: white; } +h2 { + font-size: 5vw; +} + +h3 { + font-size: 4vw; +} + +h4 { + font-size: 3vw; + color: white; +} + +h5 { + font-size: 2vw; +} + p { font-size: 1vw; color: white; } +small { + color: white; +} + +a.fill_div { + display: block; + height: 100%; + width: 100%; + text-decoration: none; +} + @media (max-width: 980px) { h1 { font-size: 4vw; diff --git a/functions/article_functions.php b/functions/article_functions.php new file mode 100644 index 0000000..14af910 --- /dev/null +++ b/functions/article_functions.php @@ -0,0 +1,71 @@ +text($markdown); + + return $html; +} + +/* + * Generates cards for a given article. + */ +function article_card($article_id) +{ + $article_query = 'SELECT * FROM articles WHERE article_id = ' . $article_id . ';'; + $article = query_db_one_result($article_query); + + $article_tags_query = 'SELECT tag FROM article_tags INNER JOIN tags ON article_tags.tag_id = tags.tag_id WHERE article_id = ' . $article_id . ';'; + $tags_results = query_db_one_or_more_results($article_tags_query); + $tags_html = '
'; + + while ($row = mysqli_fetch_array($tags_results)) + $tags_html .= '#' . $row['tag'] . ''; + + $tags_html .= '
'; + + $author_query = 'SELECT username, profile_picture FROM user WHERE user_id = ' . $article['author_id'] . ';'; + $author = query_db_one_result($author_query); + + $card = ' +
+
+

' . $article['title'] . '

+
+
+ Written by: ' . $author['username'] . ' + Published: ' . $article['published_at'] . ' +
+
+ +
+
+
+
+

' . $article['excerpt'] . '

+
+ Read More +
' . $tags_html . '
+
+
+ '; + + return $card; +} + +/* + * Displays the article creation wizard and opens a new markdown file. + */ +function create_article() {} diff --git a/functions/db_functions.php b/functions/db_functions.php new file mode 100644 index 0000000..ae71f38 --- /dev/null +++ b/functions/db_functions.php @@ -0,0 +1,53 @@ + 1) + return null; + else + return mysqli_fetch_assoc($results); +} + +function query_db_one_or_more_results($query_stmt) +{ + $conn = get_connection(); + $results = mysqli_query($conn, $query_stmt); + mysqli_close($conn); + + if (mysqli_num_rows($results) == 0) + return null; + else + return $results; +} + +function get_connection() +{ + // Connect to the DB + $conn = mysqli_connect(HOST, USER, PASS, DB); + + return $conn; +} diff --git a/functions/functions.php b/functions/functions.php new file mode 100644 index 0000000..dabe532 --- /dev/null +++ b/functions/functions.php @@ -0,0 +1,20 @@ + + ' . print_r($arr) . ' + + '; +} diff --git a/functions/init.php b/functions/init.php new file mode 100644 index 0000000..cd22382 --- /dev/null +++ b/functions/init.php @@ -0,0 +1,11 @@ +safeLoad(); + +// Set SESSION variable. +$_SESSION['initialized'] = true; diff --git a/index.php b/index.php index 419b009..22e0a92 100644 --- a/index.php +++ b/index.php @@ -1,16 +1,14 @@ - - + - - - +// Initializes environment variables and other stuff. +// if (!isset($_SESSION['initialized'])) +require_once 'functions/init.php'; - -
-

Under Construction

-

Come back 5.25.2025

-
- +require_once 'functions/functions.php'; - +include_once 'components/head.php'; + +include_once 'functions/article_functions.php'; +echo article_card(1); + +include_once 'components/foot.php'; diff --git a/scripts/init.sql b/scripts/init.sql new file mode 100644 index 0000000..3b03797 --- /dev/null +++ b/scripts/init.sql @@ -0,0 +1,54 @@ +CREATE DATABASE vintagecoding; +USE vintagecoding; + +CREATE TABLE roles ( + role_id INT PRIMARY KEY AUTO_INCREMENT, + role VARCHAR(16) NOT NULL +); + +INSERT INTO roles (role) + VALUES ('owner'), ('admin'), ('contributor'), ('reader'); + +CREATE TABLE tags ( + tag_id INT PRIMARY KEY AUTO_INCREMENT, + tag VARCHAR(16) NOT NULL +); + +INSERT INTO tags (tag) + VALUES ('linux'), ('web-dev'), ('raspberry-pi'), ('self-hosting'); + +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, + last_active TIMESTAMP DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, + role_id INT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + is_active BOOLEAN DEFAULT FALSE, + profile_picture VARCHAR(256), + FOREIGN KEY (role_id) REFERENCES roles (role_id) +); + +CREATE TABLE articles ( + article_id INT PRIMARY KEY AUTO_INCREMENT, + author_id INT NOT NULL, + markdown_file_path VARCHAR(256) NOT NULL UNIQUE, + title VARCHAR(64) 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 FALSE, + 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 articles(article_id), + FOREIGN KEY (tag_id) REFERENCES tags(tag_id) +); diff --git a/scripts/init_db.sh b/scripts/init_db.sh new file mode 100755 index 0000000..fbbb69c --- /dev/null +++ b/scripts/init_db.sh @@ -0,0 +1,54 @@ +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; diff --git a/scripts/setup.sql b/scripts/setup.sql new file mode 100644 index 0000000..b0dece4 --- /dev/null +++ b/scripts/setup.sql @@ -0,0 +1,3 @@ +--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';