Initial commit. Included are scripts to initialize the mariaDB or Neo4J databases, the entrypoint and backup for the web version, and the podman compose.yaml file.

This commit is contained in:
2025-08-10 19:00:48 -06:00
commit 06c4e6f73b
9 changed files with 581 additions and 0 deletions
+17
View File
@@ -0,0 +1,17 @@
#!/bin/bash
set -e
BACKUP_DIR="/var/www/html/backups"
BACKUP_FILE="${BACKUP_DIR}/db_backup_$(date +%Y-%m-%d_%H-%M-%S).sql.gz"
echo "Starting database backup..."
# Ensure the backup directory exists
mkdir -p ${BACKUP_DIR}
# Dump the database, gzip it, and save to the file
mariadb-dump -h ${MARIADB_HOST} -u ${MARIADB_USER} -p${MARIADB_PASSWORD} ${MARIADB_DATABASE} | gzip > ${BACKUP_FILE}
echo "Backup created at ${BACKUP_FILE}"
# TODO: Setup rclone to Google Drive? Or a seperate server?
+50
View File
@@ -0,0 +1,50 @@
---
services:
app:
build: .
container_name: spaces
ports:
- "2025:2025"
volumes:
# Mounts the project code into the container.
# This makes git pulls faster after the first run.
- ./web:/var/www/html
environment:
# --- Git Settings ---
# ⚠️ Use a secure Personal Access Token (PAT) for the URL
- GIT_REPO_URL=https://${GITHUB_USER}:${GITHUB_PAT}@github.com/${GITHUB_USER}/${SPACES_REPO}.git
- GIT_BRANCH=main
# --- Database Connection Settings (for your PHP app) ---
- DB_HOST=db
- DB_DATABASE=mydatabase
- DB_USER=myuser
- DB_PASSWORD=mypassword
# --- Backup Script Settings ---
# These credentials are used by mysqldump inside the container
- MARIADB_USER=${DB_USER}
- MARIADB_PASSWORD=${DB_PASSWORD}
- MARIADB_DATABASE=${DB_DATABASE}
- MARIADB_HOST=db # The service name from this compose file
depends_on:
- db # Ensures the 'db' container starts before the 'app' container
db:
image: mariadb:latest
container_name: spaces_db
restart: unless-stopped
volumes:
# Persists database data on the host machine
- db_data:/var/lib/mysql
environment:
- MARIADB_ROOT_PASSWORD=supersecretrootpassword
- MARIADB_DATABASE=mydatabase
- MARIADB_USER=myuser
- MARIADB_PASSWORD=mypassword
ports:
# Optional: Expose DB port to host for debugging with a GUI client
- "3306:3306"
volumes:
db_data: # Defines the named volume for the database
+14
View File
@@ -0,0 +1,14 @@
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);
+209
View File
@@ -0,0 +1,209 @@
CREATE
(owner:Role {name: 'Owner'}),
(developer:Role {name: 'Developer'}),
(user:Role {name: 'User'}),
(essay:essay_postType {name: 'Essay'}),
(moment:essay_postType {name: 'Moment'}),
(thought:essay_postType {name: 'Thought'}),
(web_dev:essay_postCategory {name: 'Web-dev'}),
(devlog:essay_postCategory {name: 'Devlog'}),
(published:essay_postStatus {name: 'Published'}),
(draft:essay_postStatus {name: 'Draft'}),
(open:SpaceType {name: 'Open'}),
(public:SpaceType {name: 'Public'}),
(shared:SpaceType {name: 'Shared'}),
(private:SpaceType {name: 'Private'}),
(open_space:Space
{
name: 'Open Space',
description: 'World Wide access, no account required.',
created_at: datetime()
})-
[:SPACE_TYPE]->
(open),
(public_space:Space
{
name: 'Public Space',
description: 'Available to everyone with an account.',
created_at: datetime()
})-
[:SPACE_TYPE]->
(public),
(shared_space:Space
{
name: 'Dummy Shared Space',
description: 'Dummy shared space. Weird.',
created_at: datetime()
})-
[:SPACE_TYPE]->
(shared),
(owner_space:Space
{
name: 'Owner Space',
description: 'My space. Wait. Is that what this is?',
created_at: datetime()
})-
[:SPACE_TYPE]->
(private),
(dummy_space:Space
{
name: 'Dummy Space',
description: 'Dummy space. Weird.',
created_at: datetime()
})-
[:SPACE_TYPE]->
(private),
(owner_user:User
{
username: 'joshashton',
email: 'me@joshashton.dev',
password_hash:
'057ba03d6c44104863dc7361fe4578965d1887360f90a0895882e58a6248fc86',
created_at: datetime(),
profile_picture: '2025.jpg'
})-
[:USER_TYPE]->
(owner),
(owner_user)-[:USER_TYPE]->(developer),
(owner_user)-[:USER_TYPE]->(user),
(owner_user)-[:SPACE_MEMBER]->(open_space),
(owner_user)-[:SPACE_MEMBER]->(owner_space),
(owner_user)-[:SPACE_MEMBER]->(shared_space),
(dummy_user:User
{
username: 'dummy',
email: 'joshuatashton@gmail.com',
password_hash:
'057ba03d6c44104863dc7361fe4578965d1887360f90a0895882e58a6248fc86',
created_at: datetime(),
profile_picture: '2025.jpg'
})-
[:USER_TYPE]->
(user),
(dummy_user)-[:FOLLOWS {start_at: datetime()}]->(owner_user),
(dummy_user)-[:SPACE_MEMBER]->(open_space),
(dummy_user)-[:SPACE_MEMBER]->(dummy_space),
(dummy_user)-[:SPACE_MEMBER]->(shared_space),
(essay_post:Post
{
title: 'Building vintagecoding.net',
view_count: 0,
excerpt:
'Follow the journey of the creation of vintagecoding.net, where I discuss roadblocks and solutions. Hello world!',
content:
"
#### Overview:
This site is built in PHP with MariaDB and a Golang HTTP server. Composer is being used to supply the following PHP packages:
- `vlucas/phpdotenv`
- `erusev/parsedown`
- `wildbit/postmark-php`
---
#### 19/03/2025 - Foundations:
Tonight, I [pushed](https://github.com/quaxlyqueen/vintagecoding.net/tree/5af0547864f730091c98d64cc18014bc69d0a041) the first major feature implementation. The database is designed, and a component has been created for article cards, and markdown parsing into HTML for the articles themselves.
---
#### 20/03/2025 - Refining UX:
Just now, I [pushed](https://github.com/quaxlyqueen/vintagecoding.net/tree/c0fc9e9d0053975837ae48fa1db93b5095d33146) the second major feature implementation. I've narrowed in on the database design with small tweaks, setup some dynamic page loading on articles.php, created a navigation bar, a dark/light mode button, and styled everything up. It's shaping up pretty well!
There's a lot more work to be done. The entire login system needs to be implemented, user homepages, account management, admin panels, the article composer...the list goes on.
---
#### 25/03/2025 - Account Management:
Just now, I [pushed](https://github.com/quaxlyqueen/vintagecoding.net/tree/9a45075010434a4dedd0c5d48a78ff6be3bcfddc) the third major feature implementation: account management! Not the most exciting thing ever, but it is important for the long term success of this project. With that completed, v0.0.9 is completed! Though I prematurely labeled the commit v0.1.0...But in any case there's a lot to go before release.
There is now a sign up and login user flow, a user page with basic settings, and authorization for accessing things like the article composer. Oh yeah, I got a basic version of that running in [this commit](https://github.com/quaxlyqueen/vintagecoding.net/tree/0a27cd1f5cd02735d06a64090a05937a5d6bcf3a) a few hours ago.
Two major tasks remain prior to v0.1.0. First, I still need to finish implementing the image upload on new sign ups (and for changing a profile picture), but that should be relatively minor. Second, I need to use author information to flesh out article pages.
I'm now setting my sights on v0.2.0, and the myriad of features I'm planning on implementing for that. It'll be the account and customization overhaul. Tools for the owner and administrator(s), enabling users to request their role to be changed to contributor or administrator, user home pages with their own custom CSS, the ability to theme the site however they please, and mobile support! I'm excited just thinking about it. It'll require a MAJOR overhaul of the CSS, but thanks to the minimalist aesthetic, the CSS file is only a few hundred disorganized lines.
I've put maybe 30 hours into this project so far. I'm not sure if that's good or bad, but not getting crazy with the CSS has saved a **ton** of time. And, I really like how it's looking. I'm really excited about this project and I am giddy to see how much I can get implemented by the release on 25/05/2025 -- two months! I'm starting an *unpaid* internship tomorrow, so I probably won't have the time to put 30 hours a week into this. For now, I'm just excited to see what the future holds.
---
#### 01/04/2025 - Basic Security & Administration:
Earlier today, I [pushed](https://github.com/quaxlyqueen/vintagecoding.net/tree/cec9091ee01839b133ecbbc5616463a759837dda) a major security fix along with getting CI/CD setup, and last night I [pushed](https://github.com/quaxlyqueen/vintagecoding.net/tree/b9bb620ae01134431ff1941e7577ba58eee84e42) a secure overhaul of the 'Remember Me' functionality. I didn't write about it then, but a few days ago I also [pushed](https://github.com/quaxlyqueen/vintagecoding.net/tree/ff7e799b7fd2822cf27e0afe47274de222b2b508) the image upload along with a image cropper. Still buggy as hell, but its a start. And a couple days ago I [committed](https://github.com/quaxlyqueen/vintagecoding.net/tree/e6735a9a206a207b6fab704785451a6309944ddd) admin functionality to manage users and articles. I would've thought I'd slow down, but I'm just trucking along.
Specifically, the 'Remember Me' functionality is now using a token system, a randomly generated 1024 bit string, associated with the user ID and hashed values of both the remote address and (if used) forwarded for headers. If these don't match what is stored in the database, this should mean that the client browser/device is not the original browser/device used to create the token.
For the other security fix, I converted all of the `mysqli` statements to prepared statements. This is to mitigate the risk of SQL Injection attacks. Particularly since this site is live (though I'm not promoting it so it is still 'unreleased'), it is important to ensure that despite the lack of sensitive information, would-be attackers are unable to access user information, gain admin access, or compromise the server in any way.
Onto the user home pages! Here's a general breakdown of what I have in mind. Every user has a homepage that they can customize the CSS for. Effectively, give the users a place to make their own. Eventually even change the layout and structure of their page. For now, the page is going to have some pretty simple information: a list of articles written by the user, the number of articles they have read, and the number their articles have been read. More is to come in the future, but that's a long way out.
---
#### 08/04/2025 - Image Cropping & Editing Articles:
Yesterday, I [pushed](https://github.com/quaxlyqueen/vintagecoding.net/tree/e5b3e048b8dc6731fa383778c26eba47186e5310) an update to the image cropper. In other words, it *actually* works now lol. I was driving home from class and I just realized that I needed to both offset the position from the window to the image, and scale the coordinates based on the size of the image. And just a moment ago, I [pushed](https://github.com/quaxlyqueen/vintagecoding.net/tree/e829e2e56695af5b77074f926c8d0c270e501f4b) editing articles. And here and there, I've worked on some basic Cross Site Scripting preventative measures, honeypots on signup to help prevent bots, and basic mobile responsiveness.
With some work being done with security now, I'm having second thoughts about allowing users to have custom CSS on their homepages. I'll punt that off till later.
All in all, things are going smoothly! I'm pretty proud of what I've built so far, and it has been quite educational. From prepared SQL statements, to XSS, form processing, and secure 'remember me' functionality. I'm not sure how much this site will be used by anyone else, and if that is the case I'll eventually just use this as a personal blog.
---
#### 12/04/2025 - Enhanced Markdown Editing Experience:
This was my first foray into the world of AJAX. I just [pushed](https://github.com/quaxlyqueen/vintagecoding.net/tree/fb35e9322647878386bcc3be572cd404b38fd91b) the implementation of a markdown preview while composing or editing articles. The possibilities are **very** exciting, I'm already thinking of other places that the AJAX would be useful for.
Next, I'm looking to introduce Vim motions to the site, for general navigation and also for article composition and editing. It'll be an interesting challenge I think, and I could use the JavaScript practice.
I haven't said this previously, but I am *loving* PHP. Such a joy to work with, and pair that with AJAX for a very interactive experience? Phenomenal DX. I've been looking at an interesting project, [NativePHP](https://nativephp.com), that I'd like to eventually use for another project.
"
})-
[:STATUS]->
(published),
(essay_post)-[:POST_TYPE]->(essay),
(essay_post)-[:POST_CATEGORY]->(web_dev),
(essay_post)-[:POST_CATEGORY]->(devlog),
(essay_post)-[:IN_SPACE]->(open_space),
(owner_user)-[:WRITTEN {created_at: datetime(), updated_at: datetime()}]->
(essay_post),
(moment_post:Post
{
media_filepath: 'moments/open.png',
text_content:
'A hub for everything. A social network and messaging hub. A documentation hub. A photos and video hub. A note taking and task management hub. A private hub. An AI hub. Welcome to the.hub.'
})-
[:STATUS]->
(published),
(moment_post)-[:POST_TYPE]->(moment),
(moment_post)-[:POST_CATEGORY]->(devlog),
(moment_post)-[:IN_SPACE]->(shared_space),
(moment_post_2:Post
{
media_filepath: 'moments/test.png',
text_content:
'Here is a photo from a hike I went on a while back. Nothing quite beats the look over a long trail.'
})-
[:STATUS]->
(published),
(moment_post_2)-[:POST_TYPE]->(moment),
(moment_post_2)-[:POST_CATEGORY]->(devlog),
(moment_post_2)-[:IN_SPACE]->(shared_space),
(owner_user)-[:WRITTEN {created_at: datetime(), updated_at: datetime()}]->
(moment_post_2),
(thought_post:Post
{
content:
'I wonder if this is really smart or really dumb. Guess we will see...'
})-
[:STATUS]->
(published),
(thought_post)-[:POST_TYPE]->(thought),
(thought_post)-[:POST_CATEGORY]->(devlog),
(thought_post)-[:IN_SPACE]->(owner_space),
(owner_user)-[:WRITTEN {created_at: datetime(), updated_at: datetime()}]->
(thought_post),
(thought_post_2:Post
{content: 'I wonder if it was a bad idea to share my idea with Izzi.'})-
[:STATUS]->
(draft),
(thought_post_2)-[:POST_TYPE]->(thought),
(thought_post_2)-[:POST_CATEGORY]->(devlog),
(thought_post_2)-[:IN_SPACE]->(owner_space),
(owner_user)-[:WRITTEN {created_at: datetime(), updated_at: datetime()}]->
(thought_post_2),
(thought_post_3:Post {content: 'Hello cruel world!'})-[:STATUS]->(published),
(thought_post_3)-[:POST_TYPE]->(thought),
(thought_post_3)-[:POST_CATEGORY]->(devlog),
(thought_post_3)-[:IN_SPACE]->(public_space),
(owner_user)-[:WRITTEN {created_at: datetime(), updated_at: datetime()}]->
(thought_post_3);
+178
View File
@@ -0,0 +1,178 @@
DROP DATABASE vintagecoding;
CREATE DATABASE vintagecoding;
USE vintagecoding;
CREATE TABLE roles (
id INT PRIMARY KEY AUTO_INCREMENT,
role VARCHAR(16) NOT NULL
);
INSERT INTO roles (role)
VALUES ('owner'), ('developer'), ('user');
CREATE TABLE user (
id INT PRIMARY KEY,
username VARCHAR(32) NOT NULL UNIQUE,
email VARCHAR(64),
passwordHash VARCHAR(256) NOT NULL,
role INT DEFAULT 3,
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
lastActive TIMESTAMP DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
isActive BOOLEAN DEFAULT FALSE,
profilePicture VARCHAR(256),
bio VARCHAR(256),
website VARCHAR(64),
FOREIGN KEY (role) REFERENCES roles (id) ON DELETE CASCADE
);
INSERT INTO user (id, username, email, passwordHash, role, profilePicture)
VALUES (1, 'joshashton', 'me@joshashton.dev', '$2y$12$CDMWB7IzcURWaxPxb1RrZezgy5acNFU7kSogM/ObohAZPT0.3H75K', 1, '2025.jpg');
CREATE TABLE rememberUser (
token VARCHAR(128) PRIMARY KEY,
id INT NOT NULL,
remoteAddr VARCHAR(64) NOT NULL,
httpForward VARCHAR(64),
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (id) REFERENCES user (id) ON DELETE CASCADE
); -- TODO: Need cron job to auto-delete after 30 days of inactivity
CREATE TABLE postTypes (
id INT PRIMARY KEY AUTO_INCREMENT,
postType VARCHAR(16)
);
INSERT INTO postTypes (postType)
VALUES ('essay'), ('moment'), ('thought');
CREATE TABLE postStatus (
id INT PRIMARY KEY AUTO_INCREMENT,
status VARCHAR(16)
);
INSERT INTO postStatus (status)
VALUES ('draft'), ('published');
CREATE TABLE spaceVisibility (
id INT PRIMARY KEY AUTO_INCREMENT,
spaceVisibility VARCHAR(16)
);
INSERT INTO spaceVisibility (spaceVisibility)
VALUES ('open'), ('public'), ('request'), ('invite'), ('private');
CREATE TABLE space (
id INT PRIMARY KEY,
visibility INT NOT NULL,
name VARCHAR(64) NOT NULL,
description TEXT,
parent INT DEFAULT NULL,
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (parent) REFERENCES space(id) ON DELETE SET NULL,
FOREIGN KEY (visibility) REFERENCES spaceVisibility(id)
);
INSERT INTO space (id, visibility, name, description)
VALUES (1, 5, "joshashton", "Thoughts, Moments, and Essays that I braindump."),
(2025, 1, "Open", "Thoughts, Moments, and Essays that are open for all.");
CREATE TABLE spaceRoles (
id INT PRIMARY KEY AUTO_INCREMENT,
role VARCHAR(16) NOT NULL
);
INSERT INTO spaceRoles (role)
VALUES ("owner"), ("administrator"), ("moderator"), ("viewer");
CREATE TABLE spaceMembers (
id INT PRIMARY KEY AUTO_INCREMENT,
user INT NOT NULL,
space INT NOT NULL,
role INT NOT NULL,
addedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
favorited BOOLEAN DEFAULT FALSE,
FOREIGN KEY (user) REFERENCES user(id),
FOREIGN KEY (space) REFERENCES space(id),
FOREIGN KEY (role) REFERENCES spaceRoles(id)
);
INSERT INTO spaceMembers (id, user, space, role)
VALUES (2, 1, 2025, 1), (1, 1, 1, 1);
CREATE TABLE post (
id INT PRIMARY KEY,
space INT NOT NULL,
creator INT NOT NULL,
postType INT NOT NULL,
status INT NOT NULL,
title VARCHAR(255), -- Make title nullable to accommodate Moments and Thoughts
markdown TEXT, -- For Essays
excerpt VARCHAR(255), -- For Essays
caption TEXT, -- For Moments
images TEXT, -- Store image filenames as JSON for Moments
thought TEXT, -- For Thoughts
seenCount INT DEFAULT 0,
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (space) REFERENCES space(id) ON DELETE CASCADE,
FOREIGN KEY (status) REFERENCES postStatus(id) ON DELETE CASCADE,
FOREIGN KEY (creator) REFERENCES user(id) ON DELETE CASCADE,
FOREIGN KEY (postType) REFERENCES postTypes(id)
);
CREATE TABLE spacePosts (
post INT NOT NULL,
space INT NOT NULL,
PRIMARY KEY (post, space),
FOREIGN KEY (post) REFERENCES post(id) ON DELETE CASCADE,
FOREIGN KEY (space) REFERENCES space(id) ON DELETE CASCADE
);
CREATE TABLE topics (
id INT PRIMARY KEY AUTO_INCREMENT,
topic VARCHAR(16) NOT NULL
);
CREATE TABLE postTopics (
post INT NOT NULL,
topic INT NOT NULL,
PRIMARY KEY (post, topic),
FOREIGN KEY (post) REFERENCES post(id) ON DELETE CASCADE,
FOREIGN KEY (topic) REFERENCES topics(id) ON DELETE CASCADE
);
CREATE TABLE todoPriority (
id INT PRIMARY KEY AUTO_INCREMENT,
priority VARCHAR(16) NOT NULL
);
INSERT INTO todoPriority (priority)
VALUES ("Low"), ("Medium"), ("High"), ("Urgent");
CREATE TABLE todo (
id INT NOT NULL,
space INT NOT NULL,
title VARCHAR(32) NOT NULL,
description TEXT,
due DATETIME,
priority INT NOT NULL,
link TEXT,
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id, space),
FOREIGN KEY (space) REFERENCES space(id) ON DELETE CASCADE,
FOREIGN KEY (priority) REFERENCES todoPriority(id)
);
INSERT INTO todo (id, space, title, description, due, priority, link)
VALUES (2026, 1, "weave.space", "Need to finish building this site.", CURRENT_TIMESTAMP, 3, "weave.space");
CREATE TABLE follows (
follower INT NOT NULL,
following INT NOT NULL,
notifyUser BOOLEAN DEFAULT FALSE,
followed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (follower, following),
FOREIGN KEY (follower) REFERENCES user(id) ON DELETE CASCADE,
FOREIGN KEY (following) REFERENCES user(id) ON DELETE CASCADE
);
Executable
+54
View File
@@ -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;
+3
View File
@@ -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';
+26
View File
@@ -0,0 +1,26 @@
USE vintagecoding;
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
post_id INT PRIMARY KEY AUTO_INCREMENT,
author_id INT NOT NULL,
post_type_id INT NOT NULL,
title VARCHAR(255), -- Make title nullable to accommodate Moments and Thoughts
slug VARCHAR(255) UNIQUE,
markdown TEXT, -- For Essays
excerpt VARCHAR(255), -- For Essays
caption TEXT, -- For Moments
images TEXT, -- Store image filenames as JSON for Moments
thought TEXT, -- For Thoughts
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,
FOREIGN KEY (author_id) REFERENCES user(user_id) ON DELETE CASCADE,
FOREIGN KEY (post_type_id) REFERENCES post_types(post_type_id)
);
-- Re-insert the initial post, adjusting for the new schema
INSERT INTO post (author_id, post_type_id, title, excerpt, published_at)
VALUES (1, 1, 'Building vintagecoding.net', 'A devlog of the creation of vintagecoding.net and a test at the formatting of post cards and posts. Let the great experiment begin!', CURRENT_TIMESTAMP);
+30
View File
@@ -0,0 +1,30 @@
#!/bin/bash
set -e
# --- Shutdown Handler ---
# This function will be called when the container receives a shutdown signal
cleanup() {
echo "SIGTERM received, initiating backup..."
/usr/local/bin/backup.sh # Execute the backup script
echo "Backup script finished. Exiting."
exit 0
}
# Trap the SIGTERM signal (sent by 'podman-compose down') and call the cleanup function
trap 'cleanup' SIGTERM
# --- Startup Logic ---
# Check if the target directory is a git repo. If not, clone it.
if [ ! -d "/var/www/html/.git" ]; then
echo "No git repository found. Cloning..."
# Clone the specified branch of the repository
git clone --branch ${GIT_BRANCH} ${GIT_REPO_URL} .
else
echo "Git repository found. Pulling latest changes..."
git pull origin ${GIT_BRANCH}
fi
echo "Starting PHP built-in web server..."
# Use 'exec' to replace the script process with the PHP server process.
# This is crucial for the trap to work correctly.
exec php -S 0.0.0.0:2025