diff --git a/backup/Dockerfile b/backup/Dockerfile index 522fd59..c32d39e 100644 --- a/backup/Dockerfile +++ b/backup/Dockerfile @@ -1,9 +1,16 @@ 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 -RUN chmod +x /backup.sh +WORKDIR /app -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"] diff --git a/backup/backup.sh b/backup/backup.sh index f018d88..31eca8b 100644 --- a/backup/backup.sh +++ b/backup/backup.sh @@ -2,29 +2,29 @@ echo "[INFO] Backup entry success" -# === Configuration === +# Configuration PG_CONTAINER_NAME=$(docker ps --filter "name=_db" --format "{{.Names}}" | head -n 1) PG_USER="user" PG_PASSWORD="password" PG_DB="mydatabase" BACKUP_DIR="/backups" LOG_DIR="/backups/logs" -RETENTION_DAYS=7 +RETENTION_DAYS=1 TIMESTAMP=$(date +"%Y%m%d-%H%M%S") FILENAME="$BACKUP_DIR/backup-$TIMESTAMP.sql" LOGFILE="$LOG_DIR/backup-$TIMESTAMP.log" -# === Setup Directories === +# Setup Directories mkdir -p "$BACKUP_DIR" mkdir -p "$LOG_DIR" -# === Begin Logging === +# Begin Logging exec > "$LOGFILE" 2>&1 echo "[INFO] Backup script started at $TIMESTAMP" 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" if [ $? -eq 0 ]; then @@ -34,11 +34,11 @@ else exit 1 fi -# === Rotate Old Backups === +# Rotate Old Backups echo "[INFO] Removing backups older than $RETENTION_DAYS days..." 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..." find "$LOG_DIR" -type f -name "backup-*.log" -mtime +$RETENTION_DAYS -exec rm -f {} \; diff --git a/backup/crontab.txt b/backup/crontab.txt new file mode 100644 index 0000000..445eaab --- /dev/null +++ b/backup/crontab.txt @@ -0,0 +1 @@ +*/15 * * * * /app/backup.sh diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index f8f16c6..df1b5cc 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -9,6 +9,9 @@ import { useState, useEffect } from "react"; import ReactMarkdown from "react-markdown"; import { BlogViewer } from "./utils/BlogViewer"; import { BlogList } from "./utils/BlogList"; +import { RequireAdmin } from "./utils/RouteGuard"; +import { AdminPage } from "./utils/AdminPage"; +import Unauthorized from "./utils/UnauthorizedPage"; function App() { const [darkMode, setDarkMode] = useState(true); @@ -25,6 +28,15 @@ function App() { } /> } /> } /> + + + + } + /> + } /> diff --git a/frontend/src/helper/auth.ts b/frontend/src/helper/auth.ts new file mode 100644 index 0000000..7e07376 --- /dev/null +++ b/frontend/src/helper/auth.ts @@ -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); + }); +}; diff --git a/frontend/src/utils/AdminPage.tsx b/frontend/src/utils/AdminPage.tsx new file mode 100644 index 0000000..496d0c2 --- /dev/null +++ b/frontend/src/utils/AdminPage.tsx @@ -0,0 +1,3 @@ +export function AdminPage() { + return {"adminpage"}; +} diff --git a/frontend/src/utils/RouteGuard.tsx b/frontend/src/utils/RouteGuard.tsx new file mode 100644 index 0000000..2283979 --- /dev/null +++ b/frontend/src/utils/RouteGuard.tsx @@ -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(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 Checking permissions...; + + if (!isAdmin) { + return ; + } + + return children; +}; diff --git a/frontend/src/utils/UnauthorizedPage.tsx b/frontend/src/utils/UnauthorizedPage.tsx new file mode 100644 index 0000000..0caeff7 --- /dev/null +++ b/frontend/src/utils/UnauthorizedPage.tsx @@ -0,0 +1,10 @@ +const Unauthorized = () => { + return ( + + 403 - Unauthorized + You do not have permission to view this page. + + ); +}; + +export default Unauthorized;
You do not have permission to view this page.