remove analytics system

This commit is contained in:
Aidan 2024-11-07 13:59:02 -05:00
parent bdd7f6f7e9
commit f4c1697dc0
14 changed files with 50 additions and 337 deletions

View File

@ -9,7 +9,7 @@ This project is released under the CC0-1.0 license. The code and content are in
# Install and self-host
Have a weird obsession? Want a pre-built site you can use for free? Host aidxnFUN!
As the code is available under the CC0-1.0 license, which means you should feel free and encouraged to change content, design, whatever!
During this process, `node` (20.08.0), `npm`, and `docker` will be installed on your computer.
During this process, `node` (20.08.0), `npm`, and `netcat` will be installed on your computer.
Please note the /status endpoint will be broken with the original servers as CORS is blocked on sites not requesting from my personal domain.
@ -23,26 +23,17 @@ Please note the /status endpoint will be broken with the original servers as COR
```bash
./manage setup
```
3. Edit example files
```bash
nano docker-compose.yml # Edit Docker Compose (database server)
nano config.json # Edit config.json (database config)
```
When editing config.json, use server details from docker-compose.yml so they are linked together. Ensure you double-check the IP or hostname of the Docker container, and link that with the .env file. This is crucial, or your database will not be connected.
Database features are only for analytics, at this time.
4. Start the server
3. Start the server
```bash
./manage up
```
A server will now start on port :5566, and be accessible from your web browser at http://localhost:5566/. I highly suggest creating a NGINX reverse proxy for this, especially if you plan to point this to a domain.
## Windows
Windows is currently not supported by aidxnFUN yet. I suggest you use WSL, and follow the Linux instructions, or purchase a server.
Windows is currently not supported by aidxnFUN yet. I suggest you use WSL, and follow the Ubuntu instructions, or purchase a VPS.
# How it works
This website uses Node.js, Express.js for a server, EJS for templating, and Tailwind CSS for the frontend CSS. It additionally uses Docker (w/ MariaDB and optionally PhpMyAdmin) for managing the database, which is used in the analytics system.
This website uses Node.js, Express.js for a server, EJS for templating, and Tailwind CSS for the frontend CSS.
The `manage` script uses all of those tools to manage the server for you executes the repetitive tasks for you automatically.
The views contain both regular page shards (full-ish pages) and generic shards (fragments of pages, widgets, etc.). I define a "shard" as an EJS template, which are pieced together into a pretty little website. The shards hold individual elements like music widgets, while a regular page shard is the page that contains the music widget, which the end user sees. This is helpful for understanding the code.
@ -50,56 +41,6 @@ Thus far, shards are included for a music widget, the header, and the footer of
Music (as featured on the home page) is fetched from an API (hosted on https://biancarosa.com.br), which I am in the process of setting up for myself. It works with a LastFM account (I linked this to my Spotify) and can track your live listening with amazing accuracy. The repo can be found at [biancarosa/lastfm-last-played](https://github.com/biancarosa/lastfm-last-played).
# Sample docker-compose.yml - (suggested)
```dockerfile
services:
aidxnfun-db:
image: mariadb:latest
networks:
aidxnfun-n:
ipv4_address: 10.5.0.5
environment:
MYSQL_ROOT_PASSWORD: iloveaidxnfun123
MYSQL_DATABASE: aidxnfun
MYSQL_USER: aidxnfun
MYSQL_PASSWORD: iloveaidxnfun
volumes:
- ./db_storage:/var/lib/mysql
restart: unless-stopped
phpmyadmin:
image: phpmyadmin
restart: always
networks:
aidxnfun-n:
ipv4_address: 10.5.0.6
ports:
- 80:80
environment:
- PMA_ARBITRARY=1
networks:
aidxnfun-n:
external: true
ipam:
config:
- subnet: 10.5.0.0/16
gateway: 10.5.0.1
```
This can be used in conjunction with this example config.json file:
```json
{
"DB_HOST": "10.5.0.05",
"DB_PORT": 3306,
"DB_USER": "root",
"DB_PASSWORD": "iloveaidxnfun123",
"DB_NAME": "aidxnfun"
}
```
This config will create a MariaDB instance, with a pre-created database, as long well as supplied user credentials. A PhpMyAdmin instance will additionally be spun up for easy management and inspection of the database. You may plug in `10.5.0.5` as the host on [your ip]:80 in your web browser (on the computer running Docker).
# Using the `manage` script
You may have noticed you have a `manage` file after cloning.
`manage` is a command-line tool to manage the server. It can automatically start, stop, and restart your instance.
@ -121,20 +62,12 @@ After doing that, you are now ready to use the script.
+ `./manage status, -s, --status` - Checks if the server is running.
+ `./manage help, -h, --help` - Shows the help message.
## `manage` options
+ `--db-alive` - Do not restart Docker services (database).
# Troubleshooting
I highly suggest you take a peek at the `node.log` file's contents. It's in the same directory as the `manage` script. This shows the web server's full startup, which can help you find out if the database isn't configured right, or something else is going wrong.
If the database just started, give it 30 or so seconds and issue `./manage restart --db-alive` to restart the server without touching the database. It's common to get into a Docker-and-Node restart loop (which are not in sync) which I'm fixing.
I highly suggest you take a peek at the `node.log` file's contents. It's in the same directory as the `manage` script. This file contains the NodeJS server logs, which can be very helpful for debugging and/or troubleshooting.
# To-Do
- [ ] Implement PGP message verification
- [ ] Improve `manage` handling of waiting for database to start (switch from predefined number of seconds)
- [X] Add menu link to tilde website
- [X] Add database support
- [X] Add view counter
- [X] Update projects page to latest information
# License

84
app.js
View File

@ -1,97 +1,13 @@
const express = require('express');
const path = require('path');
const mysql = require('mysql2');
const fs = require('fs');
const config = JSON.parse(fs.readFileSync('./config.json', 'utf8'));
const app = express();
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.json());
const db = mysql.createConnection({
host: config.DB_HOST,
port: config.DB_PORT,
user: config.DB_USER,
password: config.DB_PASSWORD,
database: config.DB_NAME,
});
const dbInit = () => {
if (!fs.existsSync('.db_init')) {
console.log('.db_init not found, initializing db...');
const createVT = `
CREATE TABLE page_views (
page VARCHAR(255) PRIMARY KEY,
views INT DEFAULT 0
)`;
db.query(createVT, (error) => {
if (error) throw error;
console.log('Views table created successfully.');
insertPages();
fs.writeFileSync('.db_init', 'complete');
});
db.query(`SHOW TABLES LIKE 'page_views'`, (err, results) => {
if (err) throw err;
if (results.length === 0) {
const createVT = `
CREATE TABLE page_views (
page VARCHAR(255) PRIMARY KEY,
views INT DEFAULT 0
)`;
db.query(createVT, (error) => {
if (error) throw error;
console.log('Views table created successfully.');
insertPages();
fs.writeFileSync('.db_init', 'complete');
});
} else {
console.log('Views table already exists, skipping.');
insertPages();
}
});
} else {
console.log('.db_init file found, skipping database initialization.');
}
};
const insertPages = () => {
const pages = ['/', '/about', '/contact', '/verify', '/status', '/design', '/projects', '/cloud'];
pages.forEach(page => {
const sql = `INSERT IGNORE INTO page_views (page, views) VALUES (?, 0)`;
db.query(sql, [page], (error) => {
if (error) throw error;
});
});
};
db.connect((err) => {
if (err) throw err;
console.log('Connected to database.');
dbInit();
});
app.post('/api/log-view', (req, res) => {
const { page } = req.body;
const sql = `UPDATE page_views SET views = views + 1 WHERE page = ?`;
db.query(sql, [page], (error) => {
if (error) return res.status(500).json({ error });
const selectSql = `SELECT views FROM page_views WHERE page = ?`;
db.query(selectSql, [page], (error, results) => {
if (error) return res.status(500).json({ error });
res.json({ views: results[0].views });
});
});
});
const routes = ['/', '/about', '/contact', '/verify', '/status', '/design', '/projects', '/cloud'];
routes.forEach(route => {
app.get(route, (req, res) => {

View File

@ -1,7 +0,0 @@
{
"DB_HOST": "10.5.0.5",
"DB_PORT": 3306,
"DB_USER": "root",
"DB_PASSWORD": "iloveaidxnfun123",
"DB_NAME": "aidxnfun"
}

View File

@ -1,11 +0,0 @@
services:
db:
image: mariadb:latest
environment:
MYSQL_ROOT_PASSWORD: iloveaidxnfun123
MYSQL_DATABASE: aidxnfun
MYSQL_USER: aidxnfun
MYSQL_PASSWORD: iloveaidxnfun
volumes:
- /docker/db/mysql:/var/lib/mysql
restart: unless-stopped

129
manage
View File

@ -1,6 +1,6 @@
#!/bin/bash
SC_VERSION=1.1.0
SC_VERSION=1.2.0
SC_CODENAME="bionic"
PORT=5566
SETUP_FILE=".setup_complete"
@ -11,43 +11,7 @@ COLOR_YELLOW="\033[1;33m"
COLOR_BLUE="\033[1;34m"
COLOR_CYAN="\033[1;36m"
check_db() {
nc -z "$DB_HOST" "$DB_PORT"
}
function install_docker() {
sudo apt-get update
sudo apt-get install docker.io
echo -e "\n${COLOR_GREEN}Docker installed successfully.${COLOR_RESET}"
if [ ! -f "docker-compose.yml" ]; then
if [ ! -f "docker-compose.yml.example" ]; then
echo "Couldn't find example Docker Compose file"
else
sudo cp docker-compose.yml.example docker-compose.yml
echo -e "${COLOR_GREEN}Done!${COLOR_RESET}"
fi
else
echo -e "${COLOR_GREEN}Docker Compose file already exists, skipping.${COLOR_RESET}"
fi
echo -e "${COLOR_BLUE}Creating Docker network...${COLOR_RESET}"
if ! sudo docker network inspect aidxnfun-n >/dev/null 2>&1; then
sudo docker network create --subnet=10.5.0.0/16 aidxnfun-n >/dev/null 2>&1
echo "${COLOR_GREEN}Created Docker network.${COLOR_RESET}"
else
echo "${COLOR_YELLOW}Docker network already exists.${COLOR_RESET}"
fi
}
function install_tools() {
if ! command -v curl &> /dev/null 2>&1; then
echo -e "${COLOR_RED}curl is not installed. Installing now...${COLOR_RESET}"
echo -e "${COLOR_YELLOW}You may need to enter your sudo password.${COLOR_RESET}\n"
sudo apt-get install curl
echo -e "\n${COLOR_GREEN}curl installed successfully.${COLOR_RESET}\n"
else
echo -e "${COLOR_GREEN}curl is installed.${COLOR_RESET}"
fi
if ! command -v node &> /dev/null 2>&1; then
echo -e "${COLOR_RED}NodeJS is not installed. Installing now...${COLOR_RESET}"
echo -e "${COLOR_YELLOW}You may need to enter your sudo password.${COLOR_RESET}\n"
@ -69,15 +33,6 @@ function install_tools() {
echo -e "${COLOR_GREEN}Netcat is installed.${COLOR_RESET}"
fi
if ! command -v docker &> /dev/null 2>&1; then
echo -e "${COLOR_RED}Docker is not installed. Installing now...${COLOR_RESET}"
echo -e "${COLOR_YELLOW}You may need to enter your sudo password.${COLOR_RESET}\n"
install_docker
echo -e "\n${COLOR_GREEN}Docker installed successfully.${COLOR_RESET}\n"
else
echo -e "${COLOR_GREEN}Docker is installed. Version: $(docker --version)${COLOR_RESET}"
fi
if ! command -v npm &> /dev/null 2>&1; then
echo -e "${COLOR_RED}NPM is not installed. Installing now...${COLOR_RESET}"
echo -e "${COLOR_YELLOW}You may need to enter your sudo password.${COLOR_RESET}\n"
@ -88,13 +43,13 @@ function install_tools() {
if [ ! -f "config.json.example" ]; then
echo "Couldn't find example config file"
else
sudo cp config.json.example config.json
cp config.json.example config.json
fi
else
echo -e "${COLOR_GREEN}config file already exists, skipping.${COLOR_RESET}"
fi
echo -e "${COLOR_BLUE}Installing NPM deps...${COLOR_RESET}"
npm install > node.log 2>&1
npm install
echo -e "\n${COLOR_GREEN}NPM installed successfully.${COLOR_RESET}\n"
touch $SETUP_FILE
else
@ -112,8 +67,6 @@ function show_help() {
echo -e " ${COLOR_CYAN}down${COLOR_RESET} Stops the server."
echo -e " ${COLOR_CYAN}restart${COLOR_RESET} Restarts the server."
echo -e " ${COLOR_CYAN}status, -s, --status${COLOR_RESET} Checks if the server is running.\n"
echo -e "${COLOR_YELLOW}Options:${COLOR_RESET}"
echo -e " ${COLOR_CYAN}--db-alive${COLOR_RESET} Do not restart Docker services.\n"
}
function check_dirs() {
@ -155,9 +108,6 @@ function check_dirs() {
function restart_server() {
check_setup
if [ "$DB_ALIVE" == "true" ]; then
echo -e "${COLOR_YELLOW}Database services will not be restarted. Skipping Docker operations.${COLOR_RESET}"
else
if [ -d './public' ]; then
echo -e "${COLOR_BLUE}Deleting public directories...${COLOR_RESET}"
check_dirs "delete"
@ -181,22 +131,9 @@ function restart_server() {
echo -e "${COLOR_YELLOW}No process found on port $PORT.${COLOR_RESET}"
fi
echo -e "${COLOR_BLUE}Stopping database...${COLOR_RESET}"
echo "This may require your sudo password"
sudo docker compose down
echo -e "${COLOR_GREEN}Done.${COLOR_RESET}"
echo -e "${COLOR_BLUE}Creating public directories...${COLOR_RESET}"
check_dirs "create"
echo -e "${COLOR_BLUE}Starting database...${COLOR_RESET}"
echo "This may require your sudo password"
sudo docker compose up -d
echo -e "${COLOR_BLUE}Waiting 30 seconds for database startup...${COLOR_RESET}"
sleep 30
echo -e "${COLOR_GREEN}Done.${COLOR_RESET}"
fi
echo -e "${COLOR_BLUE}Building project...${COLOR_RESET}"
if ! npm run build > node.log 2>&1; then
echo -e "${COLOR_RED}Build failed. Please check for errors above.${COLOR_RESET}"
@ -219,27 +156,23 @@ function restart_server() {
echo -e "${COLOR_BLUE}Starting server...${COLOR_RESET}"
npm start > node.log 2>&1 &
echo -e "${COLOR_GREEN}Done. Server up and running on port $PORT!${COLOR_RESET}"
sleep 1
PIDS=$(lsof -t -i:$PORT)
if [ -n "$PIDS" ]; then
echo -e "${COLOR_GREEN}\nDone. Server up and running on port $PORT!\n${COLOR_RESET}"
else
echo -e "${COLOR_RED}Something went wrong... Check node.log for more details${COLOR_RESET} (no process on port)"
fi
}
function start_server() {
check_setup
if [ "$DB_ALIVE" == "true" ]; then
echo -e "${COLOR_YELLOW}Database services will not be restarted. Skipping Docker operations.${COLOR_RESET}"
else
echo -e "${COLOR_BLUE}Starting database...${COLOR_RESET}"
echo "This may require your sudo password"
sudo docker compose up -d
echo -e "${COLOR_BLUE}Waiting 30 seconds for database startup...${COLOR_RESET}"
sleep 30
echo -e "${COLOR_GREEN}Done.${COLOR_RESET}"
fi
PID=$(lsof -t -i:$PORT)
if [ -n "$PID" ]; then
echo -e "${COLOR_YELLOW}Server process already running on port $PORT. Skipping server start.${COLOR_RESET}"
echo -e "${COLOR_YELLOW}Server already running on port $PORT. Skipping server startup.${COLOR_RESET}"
return
fi
@ -274,22 +207,20 @@ function start_server() {
echo -e "${COLOR_BLUE}Starting server...${COLOR_RESET}"
npm start > node.log 2>&1 &
echo -e "${COLOR_GREEN}Done. Server up and running on port $PORT!${COLOR_RESET}"
sleep 1
PIDS=$(lsof -t -i:$PORT)
if [ -n "$PIDS" ]; then
echo -e "${COLOR_GREEN}\nDone. Server up and running on port $PORT!\n${COLOR_RESET}"
else
echo -e "${COLOR_RED}Something went wrong... Check node.log for more details${COLOR_RESET} (no process on port)"
fi
}
function stop_server() {
check_setup
PID=$(lsof -t -i:$PORT)
if [ "$DB_ALIVE" == "true" ]; then
echo -e "${COLOR_YELLOW}Database services will not be stopped. Skipping Docker operations.${COLOR_RESET}"
else
echo -e "${COLOR_BLUE}Stopping database...${COLOR_RESET}"
echo "This may require your sudo password"
sudo docker compose down
echo -e "${COLOR_GREEN}Done.${COLOR_RESET}"
fi
if [ -d './public' ]; then
echo -e "${COLOR_BLUE}Deleting public directories...${COLOR_RESET}"
check_dirs "delete"
@ -340,12 +271,12 @@ function setup() {
read -n 1 -s -r -p ""
clear
echo -e "This script requires Node.js, NPM, and Docker to be installed on your system."
echo -e "This script requires Node.js, NPM, and Netcat to be installed on your system."
echo "Please ensure you have these tools installed before proceeding."
echo -e "\nPress any key to continue with tool installation..."
read -n 1 -s -r -p ""
clear
install_tools
echo -e "\n${COLOR_GREEN}Dependancy installation complete!${COLOR_RESET}"
@ -359,8 +290,7 @@ function setup() {
read -n 1 -s -r -p ""
clear
echo -e "${COLOR_BLUE}Now, you should disconnect your SSH session or logout from your computer, and reconnect/login again for the best results.${COLOR_RESET}"
echo -e "\n${COLOR_BLUE}Then, start the server with this command:${COLOR_RESET}"
echo -e "${COLOR_BLUE}Now, you may start the server with this command:${COLOR_RESET}"
echo -e "${COLOR_GREEN}./manage up${COLOR_RESET}\n"
echo -e "\n${COLOR_BLUE}If you need help, or to get info about other commands, simply use:${COLOR_RESET}"
echo -e "${COLOR_GREEN}./manage help${COLOR_RESET}"
@ -377,19 +307,6 @@ function check_setup() {
fi
}
DB_ALIVE="false"
if [[ $# -eq 0 ]]; then
show_help
exit 0
fi
for arg in "$@"; do
if [[ "$arg" == "--db-alive" ]]; then
DB_ALIVE="true"
break
fi
done
case $1 in
up)
check_setup

View File

View File

@ -69,8 +69,5 @@
<p class="text-slate-300 mt-4">You can learn more about my opinions on cloud platforms <a class="underline" href="/cloud">on this page</a>.</p>
</div>
<div class="mt-3">
<%- include('shards/views.ejs') %>
</div>
<script src="js/main.js"></script>
<%- include('shards/footer.ejs') %>

View File

@ -38,8 +38,5 @@
</li>
</ol>
</div>
<div class="mt-3">
<%- include('shards/views.ejs') %>
</div>
<script src="js/main.js"></script>
<%- include('shards/footer.ejs') %>

View File

@ -41,8 +41,5 @@
</li>
</ul>
</div>
<div class="mt-3">
<%- include('shards/views.ejs') %>
</div>
<script src="js/main.js"></script>
<%- include('shards/footer.ejs') %>

View File

@ -47,7 +47,6 @@
<p class="text-slate-300 mt-3">Some of my favorite artists include tobi lou, Skizzy Mars, and Kali Uchis. Some of my classics are Mike Stud (before his name change to "mike."), Skizzy Mars, tobi lou, The Neighbourhood, and Ryan Caraveo.</p>
</div>
</div>
<%- include('shards/views.ejs') %>
<script src="js/main.js"></script>
<script src="js/music.js"></script>
<%- include('shards/footer.ejs') %>

View File

@ -40,8 +40,5 @@
<h3 class="text-2xl font-bold mb-4 mt-4 text-white">Finished projects</h3>
<p class="text-slate-300 mb-4">I currently have only one public project which is in finished state. It's my old website, which is now being hosted at <a class="underline" href="https://old.aidxn.fun/">old.aidxn.fun</a>. It features a 2000s design and flashy graphics!</p>
</div>
<div class="mt-3">
<%- include('shards/views.ejs') %>
</div>
<script src="js/main.js"></script>
<%- include('shards/footer.ejs') %>

View File

@ -1,16 +0,0 @@
<div class="bg-gradient-to-br from-slate-800/80 to-slate-900/80 border border-slate-800 backdrop-blur-md shadow-xl rounded-2xl p-8 mx-4 mb-8">
<h1 class="text-4xl font-bold mb-2">Analytics</h1>
<p class="text-gray-400 italic mb-4">Our analytics system does not track you, ever. Only a simple counter is used, and your IP address is never stored or shared.</p>
<p>Total Views: <span id="totalViews">0</span></p>
</div>
<script>
fetch('/api/log-view', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ page: '<%= req.originalUrl %>' }),
})
.then(response => response.json())
.then(data => {
document.getElementById('totalViews').innerText = data.views;
});
</script>

View File

@ -27,9 +27,6 @@
<h3 class="text-2xl font-bold mb-4 text-white">Status | Backend</h3>
<p class="text-slate-300 mb-4"><span class="text-gray-500 font-bold" id="status1">[UNKNOWN - LOADING ms]</span> kantor.aidxn.fun (Oracle Cloud - Germany - backend server)</p>
</div>
<div class="mt-3">
<%- include('shards/views.ejs') %>
</div>
<script src="js/main.js"></script>
<script src="js/status.js"></script>
<%- include('shards/footer.ejs') %>

View File

@ -26,8 +26,5 @@
<h3 class="text-2xl font-bold mb-4 text-white">Check Message</h3>
<p class="text-slate-300 font-bold">THIS FORM IS NOT CURRENTLY AVAILABLE</p>
</div>
<div class="mt-3">
<%- include('shards/views.ejs') %>
</div>
<script src="js/main.js"></script>
<%- include('shards/footer.ejs') %>