feat: cron done, admin unfinished

This commit is contained in:
2025-05-31 06:02:48 -04:00
parent b8ce9ded76
commit a91469257b
8 changed files with 81 additions and 11 deletions
+11 -4
View File
@@ -1,9 +1,16 @@
FROM alpine:latest FROM alpine:latest
RUN apk add --no-cache docker-cli bash findutils postgresql-client RUN apk add --no-cache docker-cli bash findutils postgresql-client cronie
COPY backup.sh /backup.sh WORKDIR /app
RUN chmod +x /backup.sh
CMD ["/backup.sh"] COPY backup.sh crontab.txt ./
RUN chmod +x backup.sh
RUN crontab crontab.txt
RUN touch /var/log/cron.log
CMD ["crond", "-f"]
+7 -7
View File
@@ -2,29 +2,29 @@
echo "[INFO] Backup entry success" echo "[INFO] Backup entry success"
# === Configuration === # Configuration
PG_CONTAINER_NAME=$(docker ps --filter "name=_db" --format "{{.Names}}" | head -n 1) PG_CONTAINER_NAME=$(docker ps --filter "name=_db" --format "{{.Names}}" | head -n 1)
PG_USER="user" PG_USER="user"
PG_PASSWORD="password" PG_PASSWORD="password"
PG_DB="mydatabase" PG_DB="mydatabase"
BACKUP_DIR="/backups" BACKUP_DIR="/backups"
LOG_DIR="/backups/logs" LOG_DIR="/backups/logs"
RETENTION_DAYS=7 RETENTION_DAYS=1
TIMESTAMP=$(date +"%Y%m%d-%H%M%S") TIMESTAMP=$(date +"%Y%m%d-%H%M%S")
FILENAME="$BACKUP_DIR/backup-$TIMESTAMP.sql" FILENAME="$BACKUP_DIR/backup-$TIMESTAMP.sql"
LOGFILE="$LOG_DIR/backup-$TIMESTAMP.log" LOGFILE="$LOG_DIR/backup-$TIMESTAMP.log"
# === Setup Directories === # Setup Directories
mkdir -p "$BACKUP_DIR" mkdir -p "$BACKUP_DIR"
mkdir -p "$LOG_DIR" mkdir -p "$LOG_DIR"
# === Begin Logging === # Begin Logging
exec > "$LOGFILE" 2>&1 exec > "$LOGFILE" 2>&1
echo "[INFO] Backup script started at $TIMESTAMP" echo "[INFO] Backup script started at $TIMESTAMP"
echo "[INFO] Backing up database '$PG_DB' from container '$PG_CONTAINER_NAME'..." echo "[INFO] Backing up database '$PG_DB' from container '$PG_CONTAINER_NAME'..."
# === Perform Backup === # Perform Backup
PGPASSWORD="$PG_PASSWORD" pg_dump -h db -U "$PG_USER" -d "$PG_DB" > "$FILENAME" PGPASSWORD="$PG_PASSWORD" pg_dump -h db -U "$PG_USER" -d "$PG_DB" > "$FILENAME"
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
@@ -34,11 +34,11 @@ else
exit 1 exit 1
fi fi
# === Rotate Old Backups === # Rotate Old Backups
echo "[INFO] Removing backups older than $RETENTION_DAYS days..." echo "[INFO] Removing backups older than $RETENTION_DAYS days..."
find "$BACKUP_DIR" -type f -name "backup-*.sql" -mtime +$RETENTION_DAYS -exec rm -f {} \; find "$BACKUP_DIR" -type f -name "backup-*.sql" -mtime +$RETENTION_DAYS -exec rm -f {} \;
# === Rotate Old Logs === # Rotate Old Logs
echo "[INFO] Removing logs older than $RETENTION_DAYS days..." echo "[INFO] Removing logs older than $RETENTION_DAYS days..."
find "$LOG_DIR" -type f -name "backup-*.log" -mtime +$RETENTION_DAYS -exec rm -f {} \; find "$LOG_DIR" -type f -name "backup-*.log" -mtime +$RETENTION_DAYS -exec rm -f {} \;
+1
View File
@@ -0,0 +1 @@
*/15 * * * * /app/backup.sh
+12
View File
@@ -9,6 +9,9 @@ import { useState, useEffect } from "react";
import ReactMarkdown from "react-markdown"; import ReactMarkdown from "react-markdown";
import { BlogViewer } from "./utils/BlogViewer"; import { BlogViewer } from "./utils/BlogViewer";
import { BlogList } from "./utils/BlogList"; import { BlogList } from "./utils/BlogList";
import { RequireAdmin } from "./utils/RouteGuard";
import { AdminPage } from "./utils/AdminPage";
import Unauthorized from "./utils/UnauthorizedPage";
function App() { function App() {
const [darkMode, setDarkMode] = useState(true); const [darkMode, setDarkMode] = useState(true);
@@ -25,6 +28,15 @@ function App() {
<Route path="/blog/:slug" element={<BlogViewer />} /> <Route path="/blog/:slug" element={<BlogViewer />} />
<Route path="/about" element={<About />} /> <Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} /> <Route path="/contact" element={<Contact />} />
<Route
path="/admin"
element={
<RequireAdmin>
<AdminPage />
</RequireAdmin>
}
/>
<Route path="/unauthorized" element={<Unauthorized />} />
</Routes> </Routes>
</div> </div>
</div> </div>
+11
View File
@@ -0,0 +1,11 @@
export const getCurrentUser = async () => {
// Simulate fetching user info from an API
return new Promise<{ username: string; isAdmin: boolean }>((resolve) => {
setTimeout(() => {
resolve({
username: "john_doe",
isAdmin: true, // change to false to simulate non-admin
});
}, 200);
});
};
+3
View File
@@ -0,0 +1,3 @@
export function AdminPage() {
return <div>{"adminpage"}</div>;
}
+26
View File
@@ -0,0 +1,26 @@
import { useEffect, useState, type JSX } from "react";
import { Navigate, useLocation } from "react-router-dom";
import { getCurrentUser } from "../helper/auth";
export const RequireAdmin = ({ children }: { children: JSX.Element }) => {
const [isAdmin, setIsAdmin] = useState<boolean | null>(null);
const [loading, setLoading] = useState(true);
const location = useLocation();
useEffect(() => {
const checkAdmin = async () => {
const user = await getCurrentUser();
setIsAdmin(user.isAdmin);
setLoading(false);
};
checkAdmin();
}, []);
if (loading) return <div>Checking permissions...</div>;
if (!isAdmin) {
return <Navigate to="/unauthorized" state={{ from: location }} replace />;
}
return children;
};
+10
View File
@@ -0,0 +1,10 @@
const Unauthorized = () => {
return (
<div className="p-4 text-red-600">
<h1 className="text-xl font-bold">403 - Unauthorized</h1>
<p>You do not have permission to view this page.</p>
</div>
);
};
export default Unauthorized;