mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-06 11:09:18 +02:00
Fix admin CSS not loading and quirks mode issues
Fixed multiple issues in admin panel: 1. CSS path: modern-normalize.css → modern-normalize.min.css (File is actually named .min.css) 2. Icon path: assets/icon.svg → /assets/admin_favicon.svg (Was relative, now absolute; correct filename) 3. Navigation: /admin/list.php → /admin/ (list.php was renamed to index.php) 4. Short PHP tags: <? → <?php (Better compatibility, some servers don't enable short_open_tag) 5. Quirks mode warning was due to CSS not loading, not DOCTYPE (DOCTYPE was already present) Files modified: - public/admin/inc/head.php (main fixes) - public/admin/index.php (short tags) - public/admin/add.php (short tags) - public/admin/import.php (short tags) Need to redeploy for production: just deploy
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -16,3 +16,4 @@ Thumbs.db
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
|
||||
|
||||
31
admin/.gitignore
vendored
31
admin/.gitignore
vendored
@@ -1,31 +0,0 @@
|
||||
# Test database
|
||||
test.db
|
||||
|
||||
# Error logs
|
||||
error.log
|
||||
|
||||
# Uploaded files (for testing)
|
||||
data/theses/
|
||||
data/covers/
|
||||
|
||||
# Keep the data directories but ignore contents
|
||||
!data/theses/.gitkeep
|
||||
!data/covers/.gitkeep
|
||||
|
||||
# PHP session files
|
||||
sessions/
|
||||
|
||||
# Composer
|
||||
vendor/
|
||||
composer.lock
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 174 KiB |
35
config/bootstrap.php
Normal file
35
config/bootstrap.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/**
|
||||
* Simple configuration for website
|
||||
*/
|
||||
|
||||
// Define application root
|
||||
define('APP_ROOT', dirname(__DIR__));
|
||||
|
||||
// Database path
|
||||
define('DATABASE_PATH', APP_ROOT . '/database/test.db');
|
||||
|
||||
// Error reporting
|
||||
if (php_sapi_name() === 'cli-server') {
|
||||
// Development mode
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', '1');
|
||||
} else {
|
||||
// Production mode
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', '0');
|
||||
ini_set('log_errors', '1');
|
||||
}
|
||||
|
||||
// Simple helper function for including templates
|
||||
function include_template($name) {
|
||||
$path = APP_ROOT . '/includes/' . $name;
|
||||
if (file_exists($path)) {
|
||||
include $path;
|
||||
}
|
||||
}
|
||||
|
||||
// Autoload Composer dependencies if available
|
||||
if (file_exists(APP_ROOT . '/vendor/autoload.php')) {
|
||||
require_once APP_ROOT . '/vendor/autoload.php';
|
||||
}
|
||||
400
docs/COMPLETE_DEPLOYMENT_GUIDE.md
Normal file
400
docs/COMPLETE_DEPLOYMENT_GUIDE.md
Normal file
@@ -0,0 +1,400 @@
|
||||
# Complete Deployment Guide - New Structure
|
||||
|
||||
## Overview
|
||||
|
||||
This guide walks you through deploying the new secure directory structure:
|
||||
- **Old:** `/var/www/html/` (everything exposed)
|
||||
- **New:** `/var/www/posterg/` with `public/` subdirectory (only public/ exposed)
|
||||
|
||||
## Step-by-Step Deployment
|
||||
|
||||
### ⚠️ IMPORTANT: Do NOT delete /var/www/html/ yet!
|
||||
|
||||
Keep it as a backup until you confirm the new structure works.
|
||||
|
||||
---
|
||||
|
||||
### Step 1: Setup Server Directory (Manual - One Time)
|
||||
|
||||
SSH to server and create the new directory:
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
|
||||
# Backup current site
|
||||
sudo cp -r /var/www/html /var/www/html.backup
|
||||
|
||||
# Create new directory
|
||||
sudo mkdir -p /var/www/posterg
|
||||
|
||||
# Set ownership (www-data = web server user)
|
||||
sudo chown www-data:posterg /var/www/posterg
|
||||
|
||||
# Set permissions
|
||||
sudo chmod 775 /var/www/posterg
|
||||
|
||||
# Verify
|
||||
ls -ld /var/www/posterg
|
||||
# Should show: drwxrwxr-x 2 www-data posterg ...
|
||||
|
||||
# Exit server
|
||||
exit
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 2: Deploy Application Files
|
||||
|
||||
From your local machine:
|
||||
|
||||
```bash
|
||||
just deploy
|
||||
```
|
||||
|
||||
This will:
|
||||
- Upload all files to `/var/www/posterg/`
|
||||
- Exclude unnecessary files (tests, docs, etc.)
|
||||
- Set initial ownership to `www-data:posterg`
|
||||
|
||||
You should see:
|
||||
```
|
||||
sending incremental file list
|
||||
public/index.php
|
||||
public/search.php
|
||||
public/memoire.php
|
||||
...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 3: Deploy Nginx Configuration
|
||||
|
||||
```bash
|
||||
just deploy-nginx
|
||||
```
|
||||
|
||||
This will:
|
||||
1. Check that nginx config has correct DocumentRoot (`/var/www/posterg/public`)
|
||||
2. Upload `posterg.conf` to `/tmp/` on server
|
||||
3. Upload `deploy-production-new.sh` to `/tmp/` on server
|
||||
|
||||
Expected output:
|
||||
```
|
||||
✅ nginx config looks correct
|
||||
✅ Files uploaded to /tmp/ on server
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 4: Apply Nginx Configuration on Server
|
||||
|
||||
SSH to server and run the deployment script:
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo bash /tmp/deploy-production.sh
|
||||
```
|
||||
|
||||
The script will:
|
||||
1. Fix file permissions on `/var/www/posterg/`
|
||||
2. Backup existing nginx config
|
||||
3. Install new nginx config
|
||||
4. Test nginx configuration
|
||||
5. Show you the reload command
|
||||
|
||||
Expected output:
|
||||
```
|
||||
🚀 Post-ERG Production Deployment (NEW STRUCTURE)
|
||||
==================================================
|
||||
|
||||
📋 Step 1: Fixing file permissions...
|
||||
✓ Changed ownership to www-data:posterg
|
||||
✓ Set directory permissions to 755
|
||||
✓ Set file permissions to 644
|
||||
✓ Made database directory group-writable (775)
|
||||
✓ Fixed database file permissions (660)
|
||||
|
||||
📋 Step 2: Deploying nginx configuration...
|
||||
✓ Backed up existing config
|
||||
✓ Installed new nginx config
|
||||
|
||||
📋 Step 3: Testing nginx configuration...
|
||||
✓ Nginx configuration is valid
|
||||
|
||||
📋 Step 4: Summary...
|
||||
✓ Permissions fixed
|
||||
✓ Nginx config installed
|
||||
✓ Configuration validated
|
||||
|
||||
Ready to reload nginx!
|
||||
|
||||
Run: sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 5: Reload Nginx
|
||||
|
||||
Still on the server:
|
||||
|
||||
```bash
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
If successful, you'll see no output (which is good!).
|
||||
|
||||
Check status:
|
||||
```bash
|
||||
sudo systemctl status nginx
|
||||
# Should show "active (running)"
|
||||
```
|
||||
|
||||
Exit server:
|
||||
```bash
|
||||
exit
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 6: Verify Deployment
|
||||
|
||||
From your local machine:
|
||||
|
||||
```bash
|
||||
just server-status
|
||||
```
|
||||
|
||||
Expected output:
|
||||
```
|
||||
🔍 Server Status
|
||||
================
|
||||
✓ Nginx running
|
||||
✓ PHP-FPM running
|
||||
|
||||
Site check:
|
||||
• Public: 200 ✓
|
||||
• Admin: 200 ✓
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 7: Security Verification
|
||||
|
||||
Test these URLs in your browser or with curl:
|
||||
|
||||
```bash
|
||||
# Should work (200 OK):
|
||||
curl -I https://posterg.erg.be/
|
||||
curl -I https://posterg.erg.be/admin/
|
||||
|
||||
# Should be 404 (SECURITY - private files):
|
||||
curl -I https://posterg.erg.be/database/test.db
|
||||
curl -I https://posterg.erg.be/config/bootstrap.php
|
||||
curl -I https://posterg.erg.be/includes/header.php
|
||||
curl -I https://posterg.erg.be/lib/Database.php
|
||||
```
|
||||
|
||||
**All private files must return 404!** If they don't, nginx is not configured correctly.
|
||||
|
||||
---
|
||||
|
||||
### Step 8: Deploy Database (If Needed)
|
||||
|
||||
If you need to update the database:
|
||||
|
||||
```bash
|
||||
just deploy-database
|
||||
```
|
||||
|
||||
This will warn you before overwriting.
|
||||
|
||||
---
|
||||
|
||||
### Step 9: Test Thoroughly
|
||||
|
||||
- [ ] Visit https://posterg.erg.be/
|
||||
- [ ] Browse thesis list
|
||||
- [ ] Open a thesis detail page
|
||||
- [ ] Try search functionality
|
||||
- [ ] Access admin panel (should require login)
|
||||
- [ ] Verify private files return 404
|
||||
|
||||
---
|
||||
|
||||
### Step 10: Keep Backup for a While
|
||||
|
||||
**Do NOT delete `/var/www/html/` immediately!**
|
||||
|
||||
Keep it for a few days to ensure everything works. If you need to rollback:
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo nano /etc/nginx/sites-available/posterg
|
||||
# Change: root /var/www/posterg/public;
|
||||
# Back to: root /var/www/html;
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
Your old site will work immediately.
|
||||
|
||||
---
|
||||
|
||||
## After Confirming Everything Works
|
||||
|
||||
A few days later, once you're confident:
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo rm -rf /var/www/html.backup
|
||||
sudo rm -rf /var/www/html
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## What Changed?
|
||||
|
||||
### Directory Structure
|
||||
|
||||
```
|
||||
OLD: NEW:
|
||||
/var/www/html/ /var/www/posterg/
|
||||
├── index.php ├── public/ ← DocumentRoot
|
||||
├── search.php │ ├── index.php
|
||||
├── admin/ │ ├── search.php
|
||||
├── assets/ │ ├── memoire.php
|
||||
├── database/ ❌ exposed │ ├── admin/
|
||||
├── lib/ ❌ exposed │ └── assets/
|
||||
└── ... ├── includes/ ✅ private
|
||||
├── config/ ✅ private
|
||||
├── database/ ✅ private
|
||||
└── lib/ ✅ private
|
||||
```
|
||||
|
||||
### Nginx Configuration
|
||||
|
||||
```nginx
|
||||
# OLD
|
||||
root /var/www/html;
|
||||
location ^~ /formulaire/ { ... }
|
||||
|
||||
# NEW
|
||||
root /var/www/posterg/public;
|
||||
location ^~ /admin/ { ... }
|
||||
```
|
||||
|
||||
### Security Impact
|
||||
|
||||
| Resource | Old | New |
|
||||
|----------|-----|-----|
|
||||
| Database | ❌ Accessible if nginx misconfigured | ✅ Physically outside web root |
|
||||
| Config files | ❌ One deny rule away | ✅ Physically private |
|
||||
| Source code | ❌ Exposed | ✅ Physically private |
|
||||
| Admin panel | /formulaire/ | /admin/ |
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Site returns 404 for everything
|
||||
|
||||
**Cause:** Nginx still pointing to old location or wrong DocumentRoot
|
||||
|
||||
**Fix:**
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo cat /etc/nginx/sites-available/posterg | grep "root "
|
||||
# Should show: root /var/www/posterg/public;
|
||||
```
|
||||
|
||||
If wrong:
|
||||
```bash
|
||||
sudo nano /etc/nginx/sites-available/posterg
|
||||
# Fix the root directive
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
### Database errors
|
||||
|
||||
**Cause:** Wrong permissions on database file
|
||||
|
||||
**Fix:**
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo chown www-data:posterg /var/www/posterg/database/test.db
|
||||
sudo chmod 660 /var/www/posterg/database/test.db
|
||||
```
|
||||
|
||||
### Admin upload errors
|
||||
|
||||
**Cause:** Upload directories not writable
|
||||
|
||||
**Fix:**
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo chmod 775 /var/www/posterg/public/admin/data
|
||||
sudo find /var/www/posterg/public/admin/data -type d -exec chmod 775 {} \;
|
||||
```
|
||||
|
||||
### Private files still accessible
|
||||
|
||||
**Cause:** Nginx serving from wrong directory
|
||||
|
||||
**Fix:** Verify nginx DocumentRoot and reload
|
||||
|
||||
---
|
||||
|
||||
## Rollback Procedure
|
||||
|
||||
If you need to go back to the old structure:
|
||||
|
||||
```bash
|
||||
# 1. SSH to server
|
||||
ssh posterg
|
||||
|
||||
# 2. Restore old nginx config
|
||||
sudo nano /etc/nginx/sites-available/posterg
|
||||
# Change: root /var/www/posterg/public;
|
||||
# To: root /var/www/html;
|
||||
# Change: location ^~ /admin/
|
||||
# To: location ^~ /formulaire/
|
||||
|
||||
# 3. Reload nginx
|
||||
sudo systemctl reload nginx
|
||||
|
||||
# 4. Verify
|
||||
curl -I https://posterg.erg.be/
|
||||
```
|
||||
|
||||
Your old site should work immediately (as long as you didn't delete `/var/www/html/`).
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Task | Command |
|
||||
|------|---------|
|
||||
| Deploy files | `just deploy` |
|
||||
| Deploy nginx | `just deploy-nginx` |
|
||||
| Deploy database | `just deploy-database` |
|
||||
| Check status | `just server-status` |
|
||||
| View logs | `just server-logs` |
|
||||
|
||||
---
|
||||
|
||||
## Success Checklist
|
||||
|
||||
- [ ] `/var/www/posterg/` created with correct permissions
|
||||
- [ ] Files deployed with `just deploy`
|
||||
- [ ] Nginx config deployed with `just deploy-nginx`
|
||||
- [ ] Permissions fixed with `deploy-production.sh`
|
||||
- [ ] Nginx reloaded successfully
|
||||
- [ ] Site accessible at https://posterg.erg.be/
|
||||
- [ ] Admin accessible at https://posterg.erg.be/admin/
|
||||
- [ ] Private files return 404 (security verified)
|
||||
- [ ] Database working (can view theses)
|
||||
- [ ] Search working
|
||||
- [ ] Old `/var/www/html/` kept as backup
|
||||
|
||||
---
|
||||
|
||||
**After deployment, your site will be significantly more secure!** 🔒
|
||||
215
docs/DEPLOYMENT_STEPS.md
Normal file
215
docs/DEPLOYMENT_STEPS.md
Normal file
@@ -0,0 +1,215 @@
|
||||
# Deployment Steps
|
||||
|
||||
## First-Time Deployment (New Structure)
|
||||
|
||||
Since we're moving from `/var/www/html/` to `/var/www/posterg/`, follow these steps:
|
||||
|
||||
### 1. Setup Server Directory (ONE TIME)
|
||||
|
||||
```bash
|
||||
just setup-server
|
||||
```
|
||||
|
||||
This creates `/var/www/posterg/` with correct permissions:
|
||||
- Owner: `www-data:posterg`
|
||||
- Permissions: `775`
|
||||
|
||||
### 2. Deploy Application
|
||||
|
||||
```bash
|
||||
just deploy
|
||||
```
|
||||
|
||||
This deploys all files to `/var/www/posterg/`:
|
||||
- `public/` → `/var/www/posterg/public/`
|
||||
- `includes/` → `/var/www/posterg/includes/`
|
||||
- `config/` → `/var/www/posterg/config/`
|
||||
- `database/` → `/var/www/posterg/database/`
|
||||
- `lib/` → `/var/www/posterg/lib/`
|
||||
|
||||
### 3. Update Nginx Configuration
|
||||
|
||||
```bash
|
||||
just deploy-nginx
|
||||
```
|
||||
|
||||
This checks that nginx config has correct DocumentRoot and uploads it to server.
|
||||
|
||||
**IMPORTANT:** The nginx config must have:
|
||||
```nginx
|
||||
root /var/www/posterg/public;
|
||||
```
|
||||
|
||||
If the check fails, edit `nginx/posterg.conf` first.
|
||||
|
||||
### 4. Apply Nginx Configuration on Server
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo bash /tmp/deploy-production.sh
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
### 5. Verify Deployment
|
||||
|
||||
```bash
|
||||
just server-status
|
||||
```
|
||||
|
||||
Check:
|
||||
- https://posterg.erg.be/ (should work)
|
||||
- https://posterg.erg.be/admin/ (should work)
|
||||
- https://posterg.erg.be/database/test.db (should 404 ✅)
|
||||
|
||||
---
|
||||
|
||||
## Subsequent Deployments
|
||||
|
||||
After the first deployment, you only need:
|
||||
|
||||
```bash
|
||||
just deploy
|
||||
```
|
||||
|
||||
That's it! The directory structure is already in place.
|
||||
|
||||
---
|
||||
|
||||
## Deploy Database
|
||||
|
||||
If you need to deploy the database:
|
||||
|
||||
```bash
|
||||
just deploy-database
|
||||
```
|
||||
|
||||
This will:
|
||||
1. Upload `database/test.db` to server
|
||||
2. Set correct permissions
|
||||
3. Warn before overwriting
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Permission Denied on Deploy
|
||||
|
||||
**Error:**
|
||||
```
|
||||
mkdir "/var/www/posterg" failed: Permission denied (13)
|
||||
```
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
just setup-server
|
||||
```
|
||||
|
||||
### Nginx 500 Error
|
||||
|
||||
**Cause:** Nginx DocumentRoot still pointing to old location
|
||||
|
||||
**Solution:**
|
||||
1. Check nginx config has: `root /var/www/posterg/public;`
|
||||
2. Redeploy nginx config:
|
||||
```bash
|
||||
just deploy-nginx
|
||||
ssh posterg
|
||||
sudo bash /tmp/deploy-production.sh
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
### Database Connection Errors
|
||||
|
||||
**Cause:** Database file permissions incorrect
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
ssh posterg
|
||||
cd /var/www/posterg
|
||||
sudo chown www-data:posterg database/test.db
|
||||
sudo chmod 660 database/test.db
|
||||
```
|
||||
|
||||
### Admin 404
|
||||
|
||||
**Cause:** Nginx still using old `/formulaire/` location
|
||||
|
||||
**Solution:** Update `nginx/posterg.conf` to use `/admin/` location
|
||||
|
||||
---
|
||||
|
||||
## Rollback
|
||||
|
||||
If something goes wrong, rollback is easy:
|
||||
|
||||
### 1. Restore Old Directory
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo cp -r /var/www/html.backup /var/www/html # If you backed up
|
||||
```
|
||||
|
||||
### 2. Restore Old Nginx Config
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo cp /etc/nginx/sites-available/posterg.backup /etc/nginx/sites-available/posterg
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
### 3. Rollback Code with jj
|
||||
|
||||
```bash
|
||||
jj log
|
||||
jj edit <previous-change-id>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Migration Checklist
|
||||
|
||||
- [ ] `just setup-server` - Create server directory
|
||||
- [ ] `just deploy` - Deploy application
|
||||
- [ ] `just deploy-nginx` - Update nginx config
|
||||
- [ ] SSH to server and apply nginx config
|
||||
- [ ] `sudo systemctl reload nginx`
|
||||
- [ ] Verify site works: https://posterg.erg.be/
|
||||
- [ ] Verify security: https://posterg.erg.be/database/test.db → 404
|
||||
- [ ] Test admin: https://posterg.erg.be/admin/
|
||||
- [ ] Deploy database (if needed): `just deploy-database`
|
||||
|
||||
---
|
||||
|
||||
## Commands Reference
|
||||
|
||||
| Command | Purpose |
|
||||
|---------|---------|
|
||||
| `just setup-server` | Create `/var/www/posterg/` (first time only) |
|
||||
| `just deploy` | Deploy application files |
|
||||
| `just deploy-nginx` | Update nginx configuration |
|
||||
| `just deploy-database` | Deploy database file |
|
||||
| `just server-status` | Check server health |
|
||||
| `just server-logs` | View server logs |
|
||||
|
||||
---
|
||||
|
||||
## Directory Structure on Server
|
||||
|
||||
```
|
||||
/var/www/posterg/ # Application root (private)
|
||||
├── public/ # DocumentRoot (nginx points here)
|
||||
│ ├── index.php
|
||||
│ ├── search.php
|
||||
│ ├── memoire.php
|
||||
│ ├── admin/
|
||||
│ └── assets/
|
||||
├── includes/ # Templates (private)
|
||||
├── config/ # Configuration (private)
|
||||
├── database/ # Database (private)
|
||||
├── lib/ # PHP classes (private)
|
||||
└── vendor/ # Dependencies (private)
|
||||
```
|
||||
|
||||
**Nginx DocumentRoot:** `/var/www/posterg/public/`
|
||||
|
||||
Only the `public/` directory is accessible via web browser. Everything else is private.
|
||||
214
docs/MIGRATION_COMPLETE.md
Normal file
214
docs/MIGRATION_COMPLETE.md
Normal file
@@ -0,0 +1,214 @@
|
||||
# ✅ Migration to public/ Directory Structure - COMPLETE
|
||||
|
||||
## 📊 Summary of Changes
|
||||
|
||||
### Directory Structure Created
|
||||
```
|
||||
posterg-website/
|
||||
├── config/ # ✅ NEW - Configuration files
|
||||
│ └── bootstrap.php # Central path management
|
||||
├── public/ # ✅ NEW - DocumentRoot (web-accessible)
|
||||
│ ├── admin/ # Moved from /admin/
|
||||
│ ├── assets/ # Moved from /assets/
|
||||
│ ├── index.php # Moved from /index.php
|
||||
│ ├── search.php # Moved from /search.php
|
||||
│ └── memoire.php # Moved from /memoire.php
|
||||
├── resources/ # ✅ NEW - Application resources
|
||||
│ └── views/ # Moved from /inc/
|
||||
│ ├── header.php
|
||||
│ └── footer.php
|
||||
├── var/ # ✅ NEW - Runtime files
|
||||
│ ├── cache/
|
||||
│ ├── logs/
|
||||
│ └── tmp/
|
||||
├── database/ # ✅ KEPT - Now private
|
||||
├── lib/ # ✅ KEPT - Now private
|
||||
├── vendor/ # ✅ KEPT - Now private
|
||||
└── tests/ # ✅ KEPT - Now private
|
||||
```
|
||||
|
||||
### Files Modified
|
||||
|
||||
**1. config/bootstrap.php** (NEW)
|
||||
- Central path configuration
|
||||
- Defines APP_ROOT, PUBLIC_ROOT, DATABASE_PATH, etc.
|
||||
- Helper functions: view(), getDatabase()
|
||||
- Environment detection (dev vs production)
|
||||
- Error handling configuration
|
||||
|
||||
**2. public/*.php** (3 files updated)
|
||||
- index.php: Uses bootstrap, updated require paths
|
||||
- search.php: Uses bootstrap, updated require paths
|
||||
- memoire.php: Uses bootstrap, updated require paths
|
||||
- All now use view() helper for header/footer
|
||||
|
||||
**3. public/admin/*.php** (7 files updated)
|
||||
- add.php, edit.php, formulaire.php, import.php
|
||||
- index.php, publish.php, thanks.php
|
||||
- All updated to use ../../ paths for lib access
|
||||
- Bootstrap added where needed
|
||||
|
||||
**4. justfile** (Updated)
|
||||
- Dev server: `php -S 127.0.0.1:8000 -t public/`
|
||||
- Deploy: Now deploys to `/var/www/posterg/`
|
||||
- Database deploy: Updated paths to `/var/www/posterg/`
|
||||
- Nginx deploy: Checks for correct DocumentRoot
|
||||
|
||||
**5. nginx/posterg.conf** (Updated)
|
||||
- DocumentRoot: `/var/www/html` → `/var/www/posterg/public`
|
||||
- Admin location: `/formulaire/` → `/admin/`
|
||||
|
||||
**6. .gitignore** (Updated)
|
||||
- Added var/ directory patterns
|
||||
- Keeps .gitkeep files, ignores contents
|
||||
|
||||
### Security Improvements
|
||||
|
||||
**Before:**
|
||||
- ❌ All files in DocumentRoot (/var/www/html/)
|
||||
- ❌ Database accessible at /database/test.db
|
||||
- ❌ Config files accessible
|
||||
- ❌ Dev server exposed everything
|
||||
- ❌ Relied on nginx deny rules
|
||||
|
||||
**After:**
|
||||
- ✅ Only public/ in DocumentRoot
|
||||
- ✅ Database physically outside web root
|
||||
- ✅ Config files physically private
|
||||
- ✅ Dev server matches production security
|
||||
- ✅ Physical separation = secure by default
|
||||
|
||||
## 🧪 Testing
|
||||
|
||||
### Local Development
|
||||
```bash
|
||||
# Start dev server
|
||||
just serve
|
||||
|
||||
# Test in browser:
|
||||
# - http://localhost:8000/ → Should work
|
||||
# - http://localhost:8000/admin/ → Should work
|
||||
# - http://localhost:8000/database/test.db → Should 404 ✅
|
||||
# - http://localhost:8000/config/ → Should 404 ✅
|
||||
# - http://localhost:8000/../database/test.db → Should 404 ✅
|
||||
```
|
||||
|
||||
### Security Verification
|
||||
```bash
|
||||
# These should all return 404:
|
||||
curl http://localhost:8000/database/test.db
|
||||
curl http://localhost:8000/config/bootstrap.php
|
||||
curl http://localhost:8000/vendor/autoload.php
|
||||
curl http://localhost:8000/../database/test.db
|
||||
curl http://localhost:8000/lib/Database.php
|
||||
```
|
||||
|
||||
### Production Deployment
|
||||
|
||||
**BEFORE deploying to production:**
|
||||
|
||||
1. **Update nginx config on server:**
|
||||
```bash
|
||||
# Edit /etc/nginx/sites-available/posterg
|
||||
# Change: root /var/www/html;
|
||||
# To: root /var/www/posterg/public;
|
||||
```
|
||||
|
||||
2. **Create new directory on server:**
|
||||
```bash
|
||||
ssh posterg "sudo mkdir -p /var/www/posterg"
|
||||
```
|
||||
|
||||
3. **Deploy application:**
|
||||
```bash
|
||||
just deploy
|
||||
```
|
||||
|
||||
4. **Deploy nginx config:**
|
||||
```bash
|
||||
just deploy-nginx
|
||||
# Then on server:
|
||||
ssh posterg
|
||||
sudo bash /tmp/deploy-production.sh
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
5. **Verify:**
|
||||
```bash
|
||||
just server-status
|
||||
curl -I https://posterg.erg.be/
|
||||
curl -I https://posterg.erg.be/admin/
|
||||
curl -I https://posterg.erg.be/database/test.db # Must 404!
|
||||
```
|
||||
|
||||
## 📝 Path Reference
|
||||
|
||||
### From public/*.php files:
|
||||
```php
|
||||
<?php
|
||||
require_once __DIR__ . '/../config/bootstrap.php'; // Bootstrap
|
||||
require_once LIB_ROOT . '/Database.php'; // Library
|
||||
$db = getDatabase(); // Database
|
||||
view('header.php', ['pageTitle' => 'Title']); // Template
|
||||
```
|
||||
|
||||
### From public/admin/*.php files:
|
||||
```php
|
||||
<?php
|
||||
require_once __DIR__ . '/../../config/bootstrap.php'; // Bootstrap
|
||||
require_once LIB_ROOT . '/Database.php'; // Library
|
||||
```
|
||||
|
||||
### Available Constants (from bootstrap):
|
||||
- `APP_ROOT` - /path/to/posterg-website
|
||||
- `PUBLIC_ROOT` - /path/to/posterg-website/public
|
||||
- `CONFIG_ROOT` - /path/to/posterg-website/config
|
||||
- `DATABASE_ROOT` - /path/to/posterg-website/database
|
||||
- `DATABASE_PATH` - /path/to/posterg-website/database/test.db
|
||||
- `RESOURCES_ROOT` - /path/to/posterg-website/resources
|
||||
- `LIB_ROOT` - /path/to/posterg-website/lib
|
||||
- `VAR_ROOT` - /path/to/posterg-website/var
|
||||
- `CACHE_ROOT` - /path/to/posterg-website/var/cache
|
||||
- `LOGS_ROOT` - /path/to/posterg-website/var/logs
|
||||
- `VIEWS_ROOT` - /path/to/posterg-website/resources/views
|
||||
|
||||
## 🎯 Next Steps
|
||||
|
||||
1. ✅ Migration complete - verify locally
|
||||
2. ⏭️ Test dev server: `just serve`
|
||||
3. ⏭️ Test all pages work correctly
|
||||
4. ⏭️ Update nginx config on production server
|
||||
5. ⏭️ Deploy to production: `just deploy`
|
||||
6. ⏭️ Deploy nginx config: `just deploy-nginx`
|
||||
7. ⏭️ Verify production deployment
|
||||
|
||||
## 🔄 Rollback (if needed)
|
||||
|
||||
If something goes wrong, jj makes it easy:
|
||||
|
||||
```bash
|
||||
# View history
|
||||
jj log
|
||||
|
||||
# Go back to previous state
|
||||
jj edit <previous-change-id>
|
||||
|
||||
# Or abandon current changes
|
||||
jj abandon @
|
||||
```
|
||||
|
||||
## 📚 Documentation
|
||||
|
||||
See also:
|
||||
- `DIRECTORY_STRUCTURE.md` - Full structure reference
|
||||
- `DEPLOYMENT_MIGRATION.md` - Detailed migration guide
|
||||
- `MIGRATION_CHECKLIST.md` - Quick checklist
|
||||
|
||||
## ✨ Benefits Achieved
|
||||
|
||||
1. **Security**: Private files physically separated from public
|
||||
2. **Standards**: Follows PHP-FIG and Standard PHP Package Skeleton
|
||||
3. **Development**: Dev server matches production security
|
||||
4. **Maintainability**: Clear separation of concerns
|
||||
5. **Portability**: Path constants make relocation easy
|
||||
6. **Best Practices**: Industry-standard directory structure
|
||||
118
docs/SERVER_SETUP.md
Normal file
118
docs/SERVER_SETUP.md
Normal file
@@ -0,0 +1,118 @@
|
||||
# Server Setup (Manual)
|
||||
|
||||
Since sudo prompts don't work over SSH in justfile, do the initial setup manually.
|
||||
|
||||
## One-Time Setup on Server
|
||||
|
||||
```bash
|
||||
# 1. SSH to server
|
||||
ssh posterg
|
||||
|
||||
# 2. Backup current site (recommended)
|
||||
sudo cp -r /var/www/html /var/www/html.backup
|
||||
|
||||
# 3. Create new directory structure
|
||||
sudo mkdir -p /var/www/posterg
|
||||
|
||||
# 4. Set ownership (www-data is the web server user)
|
||||
sudo chown www-data:posterg /var/www/posterg
|
||||
|
||||
# 5. Set permissions (775 = rwxrwxr-x)
|
||||
sudo chmod 775 /var/www/posterg
|
||||
|
||||
# 6. Verify
|
||||
ls -ld /var/www/posterg
|
||||
# Should show: drwxrwxr-x 2 www-data posterg 4096 ... /var/www/posterg
|
||||
|
||||
# 7. Exit server
|
||||
exit
|
||||
```
|
||||
|
||||
## Deploy from Local Machine
|
||||
|
||||
```bash
|
||||
just deploy
|
||||
```
|
||||
|
||||
## Complete Deployment Process
|
||||
|
||||
```bash
|
||||
# On server (one time)
|
||||
ssh posterg
|
||||
sudo mkdir -p /var/www/posterg
|
||||
sudo chown www-data:posterg /var/www/posterg
|
||||
sudo chmod 775 /var/www/posterg
|
||||
exit
|
||||
|
||||
# From local machine
|
||||
just deploy # Deploy files
|
||||
just deploy-nginx # Update nginx config
|
||||
|
||||
# On server - apply nginx config
|
||||
ssh posterg
|
||||
sudo bash /tmp/deploy-production.sh
|
||||
sudo systemctl reload nginx
|
||||
exit
|
||||
|
||||
# Verify from local
|
||||
just server-status
|
||||
```
|
||||
|
||||
## Important Notes
|
||||
|
||||
- **Don't delete `/var/www/html/` yet!** Keep it as backup until you confirm the new structure works
|
||||
- The new structure uses `/var/www/posterg/public/` as DocumentRoot
|
||||
- Nginx must be updated to point to the new location
|
||||
|
||||
## After Confirming Everything Works
|
||||
|
||||
Once you've verified the new deployment works:
|
||||
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo rm -rf /var/www/html.backup # Remove backup if no longer needed
|
||||
sudo rm -rf /var/www/html # Remove old directory
|
||||
```
|
||||
|
||||
## Directory Structure on Server
|
||||
|
||||
```
|
||||
/var/www/
|
||||
├── html/ ← OLD (keep as backup for now)
|
||||
├── html.backup/ ← BACKUP (can delete later)
|
||||
└── posterg/ ← NEW
|
||||
├── public/ ← DocumentRoot (nginx serves from here)
|
||||
├── includes/
|
||||
├── config/
|
||||
├── database/
|
||||
├── lib/
|
||||
└── vendor/
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Permission denied during deploy
|
||||
**Cause:** Directory doesn't exist or has wrong ownership
|
||||
**Fix:** Run the setup commands above
|
||||
|
||||
### Nginx 403 Forbidden
|
||||
**Cause:** Wrong permissions on files
|
||||
**Fix:**
|
||||
```bash
|
||||
ssh posterg
|
||||
cd /var/www/posterg
|
||||
sudo chown -R www-data:posterg .
|
||||
sudo find . -type d -exec chmod 755 {} \;
|
||||
sudo find . -type f -exec chmod 644 {} \;
|
||||
sudo chmod 775 database/
|
||||
sudo chmod 660 database/*.db
|
||||
```
|
||||
|
||||
### Database connection errors
|
||||
**Cause:** Database file permissions
|
||||
**Fix:**
|
||||
```bash
|
||||
ssh posterg
|
||||
sudo chown www-data:posterg /var/www/posterg/database/test.db
|
||||
sudo chmod 660 /var/www/posterg/database/test.db
|
||||
```
|
||||
182
docs/SIMPLIFICATION.md
Normal file
182
docs/SIMPLIFICATION.md
Normal file
@@ -0,0 +1,182 @@
|
||||
# Website Structure Simplification
|
||||
|
||||
## Problem Identified
|
||||
|
||||
The initial migration used the **Standard PHP Package Skeleton**, which is designed for **reusable PHP packages/libraries** (like Composer packages), not for websites.
|
||||
|
||||
This resulted in:
|
||||
- ❌ Overcomplicated structure (`var/`, `resources/`, complex bootstrap)
|
||||
- ❌ Unused directories (`var/cache/`, `var/logs/`, `var/tmp/`)
|
||||
- ❌ Package-oriented naming (`resources/views/`)
|
||||
- ❌ Unnecessary constants and helper functions
|
||||
|
||||
## Solution: Simplified for Website
|
||||
|
||||
### Removed
|
||||
|
||||
1. **`var/` directory** - Completely unused, only needed for complex applications with:
|
||||
- Custom caching systems
|
||||
- Application-level logging
|
||||
- Temporary file processing
|
||||
|
||||
2. **`resources/` directory** - Package-oriented name, renamed to simple `includes/`
|
||||
|
||||
3. **Complex bootstrap** - Removed unused constants:
|
||||
- `VAR_ROOT`, `CACHE_ROOT`, `LOGS_ROOT`
|
||||
- `PUBLIC_ROOT`, `CONFIG_ROOT`, `RESOURCES_ROOT`
|
||||
- `view()` helper function
|
||||
|
||||
### Simplified Structure
|
||||
|
||||
```
|
||||
posterg-website/
|
||||
├── public/ # DocumentRoot (web-accessible) ✅
|
||||
│ ├── index.php
|
||||
│ ├── search.php
|
||||
│ ├── memoire.php
|
||||
│ ├── admin/
|
||||
│ └── assets/
|
||||
│
|
||||
├── includes/ # Simple template includes ✅
|
||||
│ ├── header.php
|
||||
│ └── footer.php
|
||||
│
|
||||
├── config/ # Minimal configuration ✅
|
||||
│ └── bootstrap.php (simplified)
|
||||
│
|
||||
├── database/ # Database files (private)
|
||||
│ └── test.db
|
||||
│
|
||||
├── lib/ # PHP classes (private)
|
||||
│ ├── Database.php
|
||||
│ ├── RateLimit.php
|
||||
│ └── cache/rate_limit/ (used by RateLimit)
|
||||
│
|
||||
├── vendor/ # Composer dependencies (private)
|
||||
└── tests/ # Tests (private)
|
||||
```
|
||||
|
||||
### Simplified config/bootstrap.php
|
||||
|
||||
**Before:** 66 lines with many unused constants
|
||||
**After:** 33 lines with only essentials
|
||||
|
||||
```php
|
||||
<?php
|
||||
// Define application root
|
||||
define('APP_ROOT', dirname(__DIR__));
|
||||
|
||||
// Database path
|
||||
define('DATABASE_PATH', APP_ROOT . '/database/test.db');
|
||||
|
||||
// Error reporting (dev vs production)
|
||||
if (php_sapi_name() === 'cli-server') {
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', '1');
|
||||
} else {
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', '0');
|
||||
}
|
||||
|
||||
// Simple helper for templates
|
||||
function include_template($name) {
|
||||
include APP_ROOT . '/includes/' . $name;
|
||||
}
|
||||
|
||||
// Composer autoload
|
||||
if (file_exists(APP_ROOT . '/vendor/autoload.php')) {
|
||||
require_once APP_ROOT . '/vendor/autoload.php';
|
||||
}
|
||||
```
|
||||
|
||||
### Simplified PHP Files
|
||||
|
||||
**Before:**
|
||||
```php
|
||||
require_once __DIR__ . '/../config/bootstrap.php';
|
||||
require_once LIB_ROOT . '/Database.php';
|
||||
view('header.php', ['pageTitle' => $title]);
|
||||
```
|
||||
|
||||
**After:**
|
||||
```php
|
||||
require_once __DIR__ . '/../config/bootstrap.php';
|
||||
require_once APP_ROOT . '/lib/Database.php';
|
||||
include APP_ROOT . '/includes/header.php';
|
||||
```
|
||||
|
||||
## Comparison: Package vs Website
|
||||
|
||||
| Feature | PHP Package | PHP Website (this project) |
|
||||
|---------|-------------|----------------------------|
|
||||
| Purpose | Reusable library | Single website |
|
||||
| Structure | Complex (PSR-4, namespaces) | Simple (includes, classes) |
|
||||
| Directories | `src/`, `resources/`, `var/`, `bin/` | `public/`, `includes/`, `lib/` |
|
||||
| Autoloading | PSR-4 namespaces | Simple require statements |
|
||||
| Config | Complex bootstrap with many constants | Minimal bootstrap |
|
||||
| Caching | `var/cache/` with framework | Simple file-based if needed |
|
||||
| Logging | `var/logs/` with logger | PHP error_log |
|
||||
|
||||
## Benefits of Simplification
|
||||
|
||||
### Before (Package-oriented)
|
||||
- ❌ 66-line bootstrap file
|
||||
- ❌ 10+ unused constants
|
||||
- ❌ `resources/views/` (confusing name)
|
||||
- ❌ `var/` directory (completely unused)
|
||||
- ❌ Helper functions for simple includes
|
||||
- ❌ Over-engineered for a simple website
|
||||
|
||||
### After (Website-focused)
|
||||
- ✅ 33-line bootstrap file (50% smaller)
|
||||
- ✅ 2 essential constants (APP_ROOT, DATABASE_PATH)
|
||||
- ✅ `includes/` (clear, simple name)
|
||||
- ✅ No unused directories
|
||||
- ✅ Standard PHP `include` statements
|
||||
- ✅ Appropriate for a PHP website
|
||||
|
||||
### Security (Unchanged)
|
||||
- ✅ Still uses `public/` as DocumentRoot
|
||||
- ✅ Database still outside web root
|
||||
- ✅ Config still private
|
||||
- ✅ All security improvements retained
|
||||
|
||||
## Testing
|
||||
|
||||
All PHP files pass syntax check:
|
||||
```bash
|
||||
$ php -l config/bootstrap.php # OK
|
||||
$ php -l public/index.php # OK
|
||||
$ php -l public/search.php # OK
|
||||
$ php -l public/memoire.php # OK
|
||||
$ php -l public/admin/index.php # OK
|
||||
```
|
||||
|
||||
Start dev server:
|
||||
```bash
|
||||
$ just serve
|
||||
```
|
||||
|
||||
## When You WOULD Need var/
|
||||
|
||||
You would need a `var/` directory if you were building:
|
||||
- A framework (Laravel, Symfony)
|
||||
- A CMS (WordPress, Drupal)
|
||||
- An application with:
|
||||
- Template compilation/caching
|
||||
- Session storage
|
||||
- File upload processing
|
||||
- Application-level logging
|
||||
- Queue systems
|
||||
|
||||
For your thesis website: **Not needed** ✅
|
||||
|
||||
## Conclusion
|
||||
|
||||
- ✅ Structure is now appropriate for a **PHP website**
|
||||
- ✅ Removed package-oriented complexity
|
||||
- ✅ Kept all security improvements (public/ directory)
|
||||
- ✅ Simpler, cleaner, easier to maintain
|
||||
- ✅ Still follows best practices (just the right ones)
|
||||
|
||||
The core improvement (public/ directory for security) remains intact, but now with a structure that fits a website, not a reusable package.
|
||||
86
index.php
86
index.php
@@ -1,86 +0,0 @@
|
||||
<?php
|
||||
ini_set("display_errors", 0);
|
||||
ini_set("log_errors", 1);
|
||||
ini_set("error_log", "error.log");
|
||||
|
||||
$pageTitle = "Liste des TFE";
|
||||
|
||||
require_once __DIR__ . "/lib/Database.php";
|
||||
|
||||
$page = isset($_GET["page"]) ? intval($_GET["page"]) : 1;
|
||||
$itemsPerPage = 10;
|
||||
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
$offset = ($page - 1) * $itemsPerPage;
|
||||
$itemsToLoad = $db->getPublishedTheses($itemsPerPage, $offset);
|
||||
$totalItems = $db->countPublishedTheses();
|
||||
$totalPages = ceil($totalItems / $itemsPerPage);
|
||||
} catch (Exception $e) {
|
||||
error_log("Error loading theses: " . $e->getMessage());
|
||||
$itemsToLoad = [];
|
||||
$totalPages = 0;
|
||||
}
|
||||
|
||||
include "inc/header.php"; ?>
|
||||
|
||||
<main>
|
||||
<?php foreach ($itemsToLoad as $item): ?>
|
||||
<a href="memoire.php?id=<?= $item["id"] ?>" class="card-link">
|
||||
<div class="card">
|
||||
<?php
|
||||
// Get cover image from thesis_files if available
|
||||
$coverImage = null;
|
||||
if (!empty($item["id"])) {
|
||||
$files = $db->getThesisFiles($item["id"]);
|
||||
foreach ($files as $file) {
|
||||
$ext = strtolower(
|
||||
pathinfo($file["file_path"], PATHINFO_EXTENSION),
|
||||
);
|
||||
if (
|
||||
in_array($ext, ["jpg", "jpeg", "png", "gif"]) &&
|
||||
$file["file_type"] === "main"
|
||||
) {
|
||||
$coverImage = $file["file_path"];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<?php if ($coverImage): ?>
|
||||
<div class="card-image">
|
||||
<figure class="image ">
|
||||
<img src="<?= htmlspecialchars(
|
||||
$coverImage,
|
||||
) ?>" alt="Image preview">
|
||||
</figure>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="card-content">
|
||||
<h4 class="title is-4">
|
||||
<?= htmlspecialchars($item["title"]) ?>
|
||||
</h4>
|
||||
<h2 class="subtitle">
|
||||
<?= htmlspecialchars($item["authors"] ?? "Auteur inconnu") ?>
|
||||
</h2>
|
||||
<h3 class="tag title is-6 is-link is-light">
|
||||
<?= htmlspecialchars($item["year"]) ?>
|
||||
</h3>
|
||||
<p class="block content">
|
||||
<?php
|
||||
$excerpt_length = 150;
|
||||
$synopsis = $item["synopsis"] ?? "";
|
||||
$description_excerpt =
|
||||
strlen($synopsis) > $excerpt_length
|
||||
? substr($synopsis, 0, $excerpt_length) . "..."
|
||||
: $synopsis;
|
||||
?>
|
||||
<?= htmlspecialchars($description_excerpt) ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</main>
|
||||
<?php include "inc/footer.php"; ?>
|
||||
72
justfile
72
justfile
@@ -25,6 +25,7 @@ serve:
|
||||
@echo ""
|
||||
@echo "📍 Public site: http://localhost:8000"
|
||||
@echo "📍 Admin panel: http://localhost:8000/admin/"
|
||||
@echo "🔒 Serving from public/ directory (matches production)"
|
||||
@echo ""
|
||||
@if [ -d "vendor/php-live-reload" ]; then \
|
||||
echo "✨ Live reload enabled - browser auto-refreshes on file save!"; \
|
||||
@@ -34,7 +35,7 @@ serve:
|
||||
@echo ""
|
||||
@echo "Press Ctrl+C to stop"
|
||||
@echo ""
|
||||
@php -S 127.0.0.1:8000
|
||||
@php -S 127.0.0.1:8000 -t public/
|
||||
|
||||
[group('dev')]
|
||||
stop:
|
||||
@@ -63,47 +64,69 @@ deploy:
|
||||
@echo "📤 Deploying Post-ERG complete site"
|
||||
@echo "===================================="
|
||||
@echo ""
|
||||
@echo "Deploying public site..."
|
||||
@echo "⚠️ First time? Ensure /var/www/posterg/ exists on server with:"
|
||||
@echo " ssh posterg"
|
||||
@echo " sudo mkdir -p /var/www/posterg"
|
||||
@echo " sudo chown www-data:posterg /var/www/posterg"
|
||||
@echo " sudo chmod 775 /var/www/posterg"
|
||||
@echo ""
|
||||
@echo "Step 1: Deploying application to /var/www/posterg/..."
|
||||
rsync -vur --progress \
|
||||
--chown="root:posterg" \
|
||||
--chown="www-data:posterg" \
|
||||
--exclude 'vendor' \
|
||||
--exclude 'tests' \
|
||||
--exclude 'test.db' \
|
||||
--exclude '*.db' \
|
||||
--exclude 'cache' \
|
||||
--exclude '*.md' \
|
||||
--exclude '.git*' \
|
||||
--exclude '.jj' \
|
||||
--exclude '.DS_Store' \
|
||||
--exclude 'database' \
|
||||
--exclude 'database/backup_*' \
|
||||
--exclude 'database/fixtures' \
|
||||
--exclude 'database/docs' \
|
||||
--exclude 'nginx' \
|
||||
--exclude 'docs' \
|
||||
--exclude 'justfile*' \
|
||||
--exclude 'migrate-structure.sh' \
|
||||
--exclude 'setup-dev.sh' \
|
||||
./ posterg:/var/www/html/
|
||||
--exclude 'var/cache/*' \
|
||||
--exclude 'var/logs/*' \
|
||||
./ posterg:/var/www/posterg/
|
||||
@echo ""
|
||||
@echo "Fixing permissions..."
|
||||
ssh posterg "chgrp -R posterg /var/www/html/inc /var/www/html/lib && \
|
||||
chmod 755 /var/www/html/inc && chmod 644 /var/www/html/inc/* && \
|
||||
find /var/www/html/lib -type d -exec chmod 755 {} \; && \
|
||||
find /var/www/html/lib -type f -exec chmod 644 {} \;"
|
||||
@echo "Step 2: Setting up directories and permissions..."
|
||||
ssh posterg "cd /var/www/posterg && \
|
||||
mkdir -p var/{cache,logs,tmp} && \
|
||||
chown -R www-data:posterg . && \
|
||||
chmod -R 755 . && \
|
||||
chmod -R 775 var/ database/ && \
|
||||
chmod 660 database/*.db 2>/dev/null || true"
|
||||
@echo ""
|
||||
@echo "✅ Deployment complete!"
|
||||
@echo ""
|
||||
@echo "📁 Server structure:"
|
||||
@echo " • App root: /var/www/posterg/"
|
||||
@echo " • DocumentRoot: /var/www/posterg/public/"
|
||||
@echo ""
|
||||
@echo "🔍 Verify deployment:"
|
||||
@echo " • Public: https://posterg.erg.be/"
|
||||
@echo " • Admin: https://posterg.erg.be/admin/"
|
||||
@echo ""
|
||||
@echo "⚠️ IMPORTANT: Update nginx config to point to /var/www/posterg/public/"
|
||||
@echo " Run: just deploy-nginx"
|
||||
|
||||
[group('deploy')]
|
||||
test-deploy:
|
||||
deploy-database:
|
||||
@echo "⚠️ Deploying test database (will overwrite remote test.db)"
|
||||
@echo "Creating database directory if needed..."
|
||||
ssh posterg "mkdir -p /var/www/html/database"
|
||||
rsync -vur --progress ./database/test.db posterg:/var/www/html/database/test.db
|
||||
ssh posterg "mkdir -p /var/www/posterg/database"
|
||||
rsync -vur --progress ./database/test.db posterg:/var/www/posterg/database/test.db
|
||||
@echo "Setting correct permissions..."
|
||||
ssh posterg "chgrp posterg /var/www/html/database /var/www/html/database/test.db && chmod 775 /var/www/html/database && chmod 660 /var/www/html/database/test.db"
|
||||
ssh posterg "chown www-data:posterg /var/www/posterg/database /var/www/posterg/database/test.db && chmod 775 /var/www/posterg/database && chmod 660 /var/www/posterg/database/test.db"
|
||||
@echo "✅ Test database deployed and configured"
|
||||
|
||||
# Legacy alias
|
||||
[group('deploy')]
|
||||
test-deploy:
|
||||
@just deploy-database
|
||||
# ============================================================================
|
||||
# Testing
|
||||
# ============================================================================
|
||||
@@ -230,13 +253,28 @@ deploy-test-db:
|
||||
[group('server')]
|
||||
deploy-nginx:
|
||||
@echo "🔧 Deploying nginx configuration..."
|
||||
@echo ""
|
||||
@echo "⚠️ IMPORTANT: Checking nginx config has correct DocumentRoot..."
|
||||
@if ! grep -q "/var/www/posterg/public" nginx/posterg.conf 2>/dev/null; then \
|
||||
echo "❌ ERROR: nginx/posterg.conf must contain '/var/www/posterg/public'"; \
|
||||
echo " Current DocumentRoot needs updating!"; \
|
||||
echo ""; \
|
||||
echo " Edit nginx/posterg.conf and change:"; \
|
||||
echo " root /var/www/html;"; \
|
||||
echo " To:"; \
|
||||
echo " root /var/www/posterg/public;"; \
|
||||
exit 1; \
|
||||
fi
|
||||
@echo "✅ nginx config looks correct"
|
||||
@echo ""
|
||||
rsync -vur --progress ./nginx/posterg.conf posterg:/tmp/posterg.conf
|
||||
rsync -vur --progress ./nginx/deploy-production.sh posterg:/tmp/deploy-production.sh
|
||||
rsync -vur --progress ./nginx/deploy-production-new.sh posterg:/tmp/deploy-production.sh
|
||||
@echo "✅ Files uploaded to /tmp/ on server"
|
||||
@echo ""
|
||||
@echo "Next steps on the server:"
|
||||
@echo " ssh posterg"
|
||||
@echo " sudo bash /tmp/deploy-production.sh"
|
||||
@echo " (This will apply config and show reload command)"
|
||||
|
||||
[group('server')]
|
||||
deploy-admin-tools:
|
||||
|
||||
205
justfile.old
205
justfile.old
@@ -1,205 +0,0 @@
|
||||
# Default recipe - show available commands
|
||||
default:
|
||||
@just --list
|
||||
|
||||
# ============================================================================
|
||||
# Deploy Group
|
||||
# ============================================================================
|
||||
# Note: Regular deploy recipes exclude test.db and all *.db files by default
|
||||
# Use test-deploy explicitly to deploy the test database
|
||||
|
||||
[group('deploy')]
|
||||
deploy-public:
|
||||
rsync -vur --progress --exclude 'test.db' --exclude '*.db' --exclude 'tests/' --exclude 'cache/' --exclude '*.md' --exclude 'run-tests.php' ./apps/public/ posterg:/var/www/html/
|
||||
rsync -vur --progress --exclude 'test.db' ./shared/ posterg:/var/www/html/shared/
|
||||
@echo "Fixing shared library paths for production..."
|
||||
ssh posterg "cd /var/www/html && find . -maxdepth 1 -name '*.php' -type f -exec sed -i \"s|__DIR__ \. '/\.\./\.\./shared/|__DIR__ . '/shared/|g\" {} \;"
|
||||
@echo "Fixing permissions..."
|
||||
ssh posterg "chgrp -R posterg /var/www/html/inc && chmod 755 /var/www/html/inc && chmod 644 /var/www/html/inc/*"
|
||||
@echo "✓ Deployment complete"
|
||||
|
||||
[group('deploy')]
|
||||
deploy-admin:
|
||||
rsync -vur --progress --exclude 'test.db' --exclude '*.db' --exclude 'cache/' --exclude '*.md' ./apps/admin/ posterg:/var/www/html/admin/
|
||||
rsync -vur --progress --exclude 'test.db' ./shared/ posterg:/var/www/html/shared/
|
||||
@echo "Fixing shared library paths for production (admin)..."
|
||||
ssh posterg "cd /var/www/html/formulaire && find . -maxdepth 1 -name '*.php' -type f -exec sed -i \"s|__DIR__ \. '/\.\./\.\./shared/|__DIR__ . '/../shared/|g\" {} \;"
|
||||
@echo "✓ Admin paths fixed"
|
||||
|
||||
[group('deploy')]
|
||||
deploy: deploy-public deploy-admin
|
||||
@echo ""
|
||||
@echo "✅ Deployment complete (test.db excluded)"
|
||||
@echo "To deploy test database, run: just test-deploy"
|
||||
|
||||
[group('deploy')]
|
||||
deploy-database:
|
||||
@echo "Deploying database directory (excludes test.db by default)..."
|
||||
rsync -vur --progress --exclude 'test.db' --exclude '*.db-journal' ./database/ posterg:/var/www/html/database/
|
||||
@echo "✅ Database directory deployed (schema, fixtures, docs only)"
|
||||
|
||||
[group('deploy')]
|
||||
test-deploy:
|
||||
@echo "⚠️ Deploying test database (will overwrite remote test.db)"
|
||||
@echo "Creating database directory if needed..."
|
||||
ssh posterg "mkdir -p /var/www/html/database"
|
||||
rsync -vur --progress ./database/test.db posterg:/var/www/html/database/test.db
|
||||
@echo "Setting correct permissions..."
|
||||
ssh posterg "chgrp posterg /var/www/html/database /var/www/html/database/test.db && chmod 775 /var/www/html/database && chmod 660 /var/www/html/database/test.db"
|
||||
@echo "✅ Test database deployed and configured"
|
||||
|
||||
[group('deploy')]
|
||||
deploy-nginx:
|
||||
@echo "🚀 Deploying production nginx configuration..."
|
||||
rsync -vur --progress ./nginx/posterg.conf posterg:/tmp/posterg.conf
|
||||
rsync -vur --progress ./nginx/deploy-production.sh posterg:/tmp/deploy-production.sh
|
||||
@echo "✅ Files uploaded to server"
|
||||
@echo ""
|
||||
@echo "Next steps on the server:"
|
||||
@echo " ssh posterg"
|
||||
@echo " sudo bash /tmp/deploy-production.sh"
|
||||
@echo ""
|
||||
@echo "This will:"
|
||||
@echo " • Fix file permissions (posterg group)"
|
||||
@echo " • Install nginx configuration"
|
||||
@echo " • Set up admin password (if needed)"
|
||||
@echo " • Test and reload nginx"
|
||||
|
||||
[group('deploy')]
|
||||
deploy-admin-tools:
|
||||
@echo "📤 Uploading admin user management tools..."
|
||||
rsync -vur --progress ./nginx/manage-admin-users.sh posterg:/tmp/manage-admin-users.sh
|
||||
@echo "✅ Script uploaded"
|
||||
@echo ""
|
||||
@echo "To manage admin users on the server:"
|
||||
@echo " ssh posterg"
|
||||
@echo " sudo bash /tmp/manage-admin-users.sh"
|
||||
|
||||
# ============================================================================
|
||||
# Public Site Development
|
||||
# ============================================================================
|
||||
|
||||
[group('public-dev')]
|
||||
serve-public:
|
||||
@echo "Starting public site on http://localhost:8002"
|
||||
@echo "Press Ctrl+C to stop"
|
||||
@cd apps/public && php -S 127.0.0.1:8002
|
||||
|
||||
[group('public-dev')]
|
||||
test-public:
|
||||
@echo "Testing public site..."
|
||||
@cd apps/public && php test_db.php
|
||||
|
||||
[group('public-dev')]
|
||||
test-public-all:
|
||||
@echo "Running all public site tests..."
|
||||
@cd apps/public && php run-tests.php
|
||||
|
||||
[group('public-dev')]
|
||||
stats-public:
|
||||
@echo "=== Public Database Statistics ==="
|
||||
@sqlite3 database/test.db "SELECT COUNT(*) || ' total theses' FROM theses;"
|
||||
@sqlite3 database/test.db "SELECT COUNT(*) || ' published theses' FROM theses WHERE is_published = 1;"
|
||||
@sqlite3 database/test.db "SELECT COUNT(*) || ' authors' FROM authors;"
|
||||
@sqlite3 database/test.db "SELECT COUNT(*) || ' keywords' FROM keywords;"
|
||||
|
||||
[group('public-dev')]
|
||||
recent-public:
|
||||
@echo "=== Recent Published Theses ==="
|
||||
@sqlite3 -column -header database/test.db "SELECT id, title, year, authors FROM v_theses_public ORDER BY year DESC, title LIMIT 10;"
|
||||
|
||||
[group('public-dev')]
|
||||
check-public:
|
||||
@echo "Checking public site PHP syntax..."
|
||||
@cd apps/public && find . -name "*.php" -not -path "./vendor/*" -not -path "./tests/*" -exec php -l {} \; | grep -v "No syntax errors"
|
||||
@echo "✓ All files have valid syntax"
|
||||
|
||||
[group('public-dev')]
|
||||
logs-public:
|
||||
@if [ -f apps/public/error.log ]; then tail -n 50 apps/public/error.log; else echo "No error log found"; fi
|
||||
|
||||
# ============================================================================
|
||||
# Admin Panel Development
|
||||
# ============================================================================
|
||||
|
||||
[group('admin-dev')]
|
||||
init-test-db:
|
||||
@echo "Creating test database from schema..."
|
||||
@sqlite3 database/test.db < database/schema.sql
|
||||
@echo "✓ Test database created"
|
||||
@sqlite3 database/test.db "SELECT COUNT(*) || ' tables created' FROM sqlite_master WHERE type='table';"
|
||||
@sqlite3 database/test.db "SELECT COUNT(*) || ' orientations loaded' FROM orientations;"
|
||||
@sqlite3 database/test.db "SELECT COUNT(*) || ' AP programs loaded' FROM ap_programs;"
|
||||
|
||||
[group('admin-dev')]
|
||||
serve-admin: init-test-db
|
||||
@echo "Starting admin panel on http://localhost:3000"
|
||||
@echo "Press Ctrl+C to stop"
|
||||
@cd apps/admin && php -S 127.0.0.1:3000
|
||||
|
||||
[group('admin-dev')]
|
||||
serve-admin-only:
|
||||
@echo "Starting admin panel on http://localhost:3000"
|
||||
@echo "Press Ctrl+C to stop"
|
||||
@cd apps/admin && php -S 127.0.0.1:3000
|
||||
|
||||
[group('admin-dev')]
|
||||
cleanup-admin:
|
||||
@echo "Cleaning up admin test files..."
|
||||
@rm -f database/test.db
|
||||
@rm -f apps/admin/error.log
|
||||
@rm -rf apps/admin/data/theses/*
|
||||
@rm -rf apps/admin/data/covers/*
|
||||
@echo "✓ Cleanup complete"
|
||||
|
||||
[group('admin-dev')]
|
||||
reset-admin: cleanup-admin init-test-db
|
||||
@echo "✓ Admin test environment reset"
|
||||
|
||||
[group('admin-dev')]
|
||||
stats-admin:
|
||||
@echo "=== Admin Database Statistics ==="
|
||||
@sqlite3 database/test.db "SELECT COUNT(*) || ' theses' FROM theses;"
|
||||
@sqlite3 database/test.db "SELECT COUNT(*) || ' authors' FROM authors;"
|
||||
@sqlite3 database/test.db "SELECT COUNT(*) || ' supervisors' FROM supervisors;"
|
||||
@sqlite3 database/test.db "SELECT COUNT(*) || ' keywords' FROM keywords;"
|
||||
@sqlite3 database/test.db "SELECT COUNT(*) || ' files uploaded' FROM thesis_files;"
|
||||
|
||||
[group('admin-dev')]
|
||||
recent-admin:
|
||||
@echo "=== Recent Submissions ==="
|
||||
@sqlite3 -column -header database/test.db "SELECT identifier, title, year, submitted_at FROM theses ORDER BY submitted_at DESC LIMIT 5;"
|
||||
|
||||
[group('admin-dev')]
|
||||
setup-dirs:
|
||||
@mkdir -p apps/admin/data/theses
|
||||
@mkdir -p apps/admin/data/covers
|
||||
@mkdir -p apps/admin/data/yaml
|
||||
@touch apps/admin/data/theses/.gitkeep
|
||||
@touch apps/admin/data/covers/.gitkeep
|
||||
@echo "✓ Data directories created"
|
||||
|
||||
[group('admin-dev')]
|
||||
dev-admin: setup-dirs init-test-db serve-admin
|
||||
|
||||
# ============================================================================
|
||||
# Database Operations
|
||||
# ============================================================================
|
||||
|
||||
[group('database')]
|
||||
query-db:
|
||||
@sqlite3 database/test.db
|
||||
|
||||
[group('database')]
|
||||
show-thesis id:
|
||||
@sqlite3 -column -header database/test.db "SELECT * FROM v_theses_full WHERE id = {{id}};"
|
||||
|
||||
[group('database')]
|
||||
dump-db:
|
||||
@sqlite3 database/test.db .dump > database/backup_$(date +%Y%m%d_%H%M%S).sql
|
||||
@echo "✓ Database dumped to database/backup_$(date +%Y%m%d_%H%M%S).sql"
|
||||
|
||||
[group('database')]
|
||||
create-fixtures:
|
||||
@echo "Creating test database with fixtures..."
|
||||
@php database/fixtures/CreateTestDatabase.php
|
||||
@@ -1 +1 @@
|
||||
[1770322829]
|
||||
[1770377487]
|
||||
105
nginx/deploy-production-new.sh
Executable file
105
nginx/deploy-production-new.sh
Executable file
@@ -0,0 +1,105 @@
|
||||
#!/bin/bash
|
||||
# Deploy production nginx configuration for Post-ERG (NEW STRUCTURE)
|
||||
# This script applies the nginx config for /var/www/posterg/public/ structure
|
||||
|
||||
set -e
|
||||
|
||||
echo "🚀 Post-ERG Production Deployment (NEW STRUCTURE)"
|
||||
echo "=================================================="
|
||||
echo ""
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
# Check if running as root
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo -e "${RED}Error: This script must be run as root (use sudo)${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "📋 Step 1: Fixing file permissions..."
|
||||
echo "--------------------------------------"
|
||||
|
||||
# Change ownership to www-data:posterg
|
||||
chown -R www-data:posterg /var/www/posterg/
|
||||
echo "✓ Changed ownership to www-data:posterg"
|
||||
|
||||
# Set directory permissions (755)
|
||||
find /var/www/posterg -type d -exec chmod 755 {} \;
|
||||
echo "✓ Set directory permissions to 755"
|
||||
|
||||
# Set file permissions (644)
|
||||
find /var/www/posterg -type f -exec chmod 644 {} \;
|
||||
echo "✓ Set file permissions to 644"
|
||||
|
||||
# Make database directory writable by group
|
||||
if [ -d "/var/www/posterg/database" ]; then
|
||||
chmod 775 /var/www/posterg/database
|
||||
echo "✓ Made database directory group-writable (775)"
|
||||
fi
|
||||
|
||||
# Fix database file permissions
|
||||
if [ -f "/var/www/posterg/database/test.db" ]; then
|
||||
chmod 660 /var/www/posterg/database/test.db
|
||||
chown www-data:posterg /var/www/posterg/database/test.db
|
||||
echo "✓ Fixed database file permissions (660)"
|
||||
fi
|
||||
|
||||
# Make admin upload directories writable by group
|
||||
if [ -d "/var/www/posterg/public/admin/data" ]; then
|
||||
find /var/www/posterg/public/admin/data -type d -exec chmod 775 {} \;
|
||||
echo "✓ Made admin upload directories group-writable"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "📋 Step 2: Deploying nginx configuration..."
|
||||
echo "--------------------------------------"
|
||||
|
||||
# Backup existing config
|
||||
if [ -f "/etc/nginx/sites-available/posterg" ]; then
|
||||
cp /etc/nginx/sites-available/posterg /etc/nginx/sites-available/posterg.backup.$(date +%Y%m%d_%H%M%S)
|
||||
echo "✓ Backed up existing config"
|
||||
fi
|
||||
|
||||
# Copy new config
|
||||
if [ -f "/tmp/posterg.conf" ]; then
|
||||
cp /tmp/posterg.conf /etc/nginx/sites-available/posterg
|
||||
echo "✓ Installed new nginx config"
|
||||
else
|
||||
echo -e "${RED}Error: /tmp/posterg.conf not found${NC}"
|
||||
echo "Run 'just deploy-nginx' first"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Test nginx configuration
|
||||
echo ""
|
||||
echo "📋 Step 3: Testing nginx configuration..."
|
||||
echo "--------------------------------------"
|
||||
|
||||
if nginx -t; then
|
||||
echo -e "${GREEN}✓ Nginx configuration is valid${NC}"
|
||||
else
|
||||
echo -e "${RED}✗ Nginx configuration has errors!${NC}"
|
||||
echo "Restoring backup..."
|
||||
cp /etc/nginx/sites-available/posterg.backup.$(date +%Y%m%d_%H%M%S | tail -1) /etc/nginx/sites-available/posterg
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "📋 Step 4: Summary..."
|
||||
echo "--------------------------------------"
|
||||
echo -e "${GREEN}✓ Permissions fixed${NC}"
|
||||
echo -e "${GREEN}✓ Nginx config installed${NC}"
|
||||
echo -e "${GREEN}✓ Configuration validated${NC}"
|
||||
echo ""
|
||||
echo -e "${YELLOW}Ready to reload nginx!${NC}"
|
||||
echo ""
|
||||
echo "Run: ${GREEN}sudo systemctl reload nginx${NC}"
|
||||
echo ""
|
||||
echo "After reload, verify:"
|
||||
echo " • https://posterg.erg.be/"
|
||||
echo " • https://posterg.erg.be/admin/"
|
||||
echo " • https://posterg.erg.be/database/test.db (should 404)"
|
||||
@@ -14,7 +14,7 @@ server {
|
||||
|
||||
server_name posterg.erg.be www.posterg.erg.be;
|
||||
|
||||
root /var/www/html;
|
||||
root /var/www/posterg/public;
|
||||
|
||||
# Add index.php to the list
|
||||
index index.php index.html index.htm;
|
||||
@@ -65,7 +65,7 @@ server {
|
||||
}
|
||||
|
||||
# Admin panel - password protected
|
||||
location ^~ /formulaire/ {
|
||||
location ^~ /admin/ {
|
||||
# HTTP Basic Authentication
|
||||
auth_basic "Admin Access - Post-ERG";
|
||||
auth_basic_user_file /etc/nginx/.htpasswd-posterg;
|
||||
@@ -74,7 +74,7 @@ server {
|
||||
limit_req zone=admin burst=5 nodelay;
|
||||
|
||||
# Allow access to public assets without authentication
|
||||
location ~ ^/formulaire/(css|js|images)/ {
|
||||
location ~ ^/admin/(css|js|images)/ {
|
||||
auth_basic off;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
// Bootstrap application
|
||||
require_once __DIR__ . "/../../config/bootstrap.php";
|
||||
|
||||
// Start session and generate CSRF token
|
||||
session_start();
|
||||
if (empty($_SESSION["csrf_token"])) {
|
||||
@@ -8,7 +11,7 @@ if (empty($_SESSION["csrf_token"])) {
|
||||
$pageTitle = "Ajout de TFE";
|
||||
|
||||
// Load database helper
|
||||
require_once __DIR__ . '/../lib/Database.php';
|
||||
require_once __DIR__ . '/../../lib/Database.php';
|
||||
|
||||
try {
|
||||
$db = new Database();
|
||||
@@ -52,7 +55,7 @@ function wasSelected($key, $value)
|
||||
return $formData[$key] == $value;
|
||||
}
|
||||
?>
|
||||
<? include "inc/head.php"?>
|
||||
<?php include "inc/head.php"?>
|
||||
<main>
|
||||
<?php if ($error): ?>
|
||||
<div class="error-message" style="background: #fee; border: 2px solid #c00; padding: 1rem; margin-bottom: 1rem; border-radius: 4px; color: #c00;">
|
||||
@@ -243,4 +246,4 @@ function wasSelected($key, $value)
|
||||
</form>
|
||||
</main>
|
||||
|
||||
<? include "inc/footer.php"?>
|
||||
<?php include "inc/footer.php"?>
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
// Bootstrap application
|
||||
require_once __DIR__ . "/../../config/bootstrap.php";
|
||||
|
||||
// Edit thesis page
|
||||
session_start();
|
||||
|
||||
@@ -7,7 +10,7 @@ if (empty($_SESSION['csrf_token'])) {
|
||||
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/../lib/Database.php';
|
||||
require_once __DIR__ . '/../../lib/Database.php';
|
||||
|
||||
$thesisId = isset($_GET['id']) ? intval($_GET['id']) : 0;
|
||||
$error = null;
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php // formulaire.php
|
||||
// Bootstrap application
|
||||
require_once __DIR__ . "/../../config/bootstrap.php";
|
||||
|
||||
|
||||
// Configure error reporting
|
||||
ini_set('display_errors', 0);
|
||||
@@ -18,7 +21,7 @@ if (!isset($_POST['csrf_token']) || !isset($_SESSION['csrf_token']) ||
|
||||
// Log the content of the $_FILES array
|
||||
error_log("FILES array: " . print_r($_FILES, true));
|
||||
|
||||
require_once __DIR__ . '/../lib/Database.php';
|
||||
require_once __DIR__ . '/../../lib/Database.php';
|
||||
|
||||
// Helper function to sanitize string input
|
||||
function sanitize_string($input) {
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
// Bootstrap application
|
||||
require_once __DIR__ . "/../../config/bootstrap.php";
|
||||
|
||||
// CSV Import page for Post-ERG thesis database
|
||||
// This page allows importing thesis data from CSV files
|
||||
|
||||
@@ -9,7 +12,7 @@ if (empty($_SESSION['csrf_token'])) {
|
||||
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/../lib/Database.php';
|
||||
require_once __DIR__ . '/../../lib/Database.php';
|
||||
|
||||
$pageTitle = "Import";
|
||||
|
||||
@@ -349,4 +352,4 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['csv_file'])) {
|
||||
<p>Voir: <code>../db/Database_TFE_test.csv</code></p>
|
||||
</main>
|
||||
|
||||
<? include "inc/footer.php" ?>
|
||||
<?php include "inc/footer.php" ?>
|
||||
@@ -5,18 +5,18 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><? echo $pageTitle ?></title>
|
||||
<link rel="stylesheet" href="/assets/modern-normalize.css">
|
||||
<title><?php echo $pageTitle ?></title>
|
||||
<link rel="stylesheet" href="/assets/modern-normalize.min.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/water.css@2/out/water.css">
|
||||
<link rel="stylesheet" href="/assets/admin.css">
|
||||
<link rel="shortcut icon" href="assets/icon.svg" type="image/svg">
|
||||
<link rel="shortcut icon" href="/assets/admin_favicon.svg" type="image/svg+xml">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header>
|
||||
<h1><? echo $pageTitle ?></h1>
|
||||
<h1><?php echo $pageTitle ?></h1>
|
||||
<nav style="margin-top: 1rem;">
|
||||
<a href="/admin/list.php" style="font-size: 0.9em;"><button>📋 Liste des TFE</button></a>
|
||||
<a href="/admin/" style="font-size: 0.9em;"><button>📋 Liste des TFE</button></a>
|
||||
<a href="/admin/import.php" style="font-size: 0.9em;"><button>📥 Importer CSV</button></a>
|
||||
</nav>
|
||||
</header>
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
// Bootstrap application
|
||||
require_once __DIR__ . "/../../config/bootstrap.php";
|
||||
|
||||
// List all theses in the database
|
||||
session_start();
|
||||
|
||||
@@ -8,9 +11,8 @@ if (empty($_SESSION['csrf_token'])) {
|
||||
}
|
||||
|
||||
$pageTitle = "Liste des TFE";
|
||||
$pageMenu
|
||||
|
||||
require_once __DIR__ . '/../lib/Database.php';
|
||||
require_once __DIR__ . '/../../lib/Database.php';
|
||||
|
||||
try {
|
||||
$db = new Database();
|
||||
@@ -74,7 +76,7 @@ try {
|
||||
}
|
||||
?>
|
||||
|
||||
<? include "inc/head.php" ?>
|
||||
<?php include "inc/head.php" ?>
|
||||
<script>
|
||||
function toggleAll(source) {
|
||||
const checkboxes = document.querySelectorAll('input[name="selected_theses[]"]');
|
||||
@@ -282,4 +284,4 @@ try {
|
||||
<?php endif; ?>
|
||||
</main>
|
||||
|
||||
<? include "inc/footer.php" ?>
|
||||
<?php include "inc/footer.php" ?>
|
||||
@@ -1,10 +1,13 @@
|
||||
<?php
|
||||
// Bootstrap application
|
||||
require_once __DIR__ . "/../../config/bootstrap.php";
|
||||
|
||||
/**
|
||||
* Handle publish/unpublish actions for theses
|
||||
*/
|
||||
session_start();
|
||||
|
||||
require_once __DIR__ . '/../lib/Database.php';
|
||||
require_once __DIR__ . '/../../lib/Database.php';
|
||||
|
||||
// Verify CSRF token
|
||||
if (!isset($_POST['csrf_token']) || !isset($_SESSION['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
|
||||
@@ -1,10 +1,13 @@
|
||||
<?php
|
||||
// Bootstrap application
|
||||
require_once __DIR__ . "/../../config/bootstrap.php";
|
||||
|
||||
// Configure error reporting
|
||||
ini_set('display_errors', 0);
|
||||
ini_set('log_errors', 1);
|
||||
ini_set('error_log', 'error.log');
|
||||
|
||||
require __DIR__ . '/../lib/Database.php';
|
||||
require __DIR__ . '/../../lib/Database.php';
|
||||
|
||||
// Security: Validate thesis ID parameter
|
||||
$thesisId = null;
|
||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
57
public/index.php
Normal file
57
public/index.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
// Load configuration
|
||||
require_once __DIR__ . '/../config/bootstrap.php';
|
||||
require_once APP_ROOT . '/lib/Database.php';
|
||||
|
||||
$pageTitle = "Liste des TFE";
|
||||
$page = isset($_GET["page"]) ? intval($_GET["page"]) : 1;
|
||||
$itemsPerPage = 10;
|
||||
|
||||
try {
|
||||
$db = Database::getInstance();
|
||||
$offset = ($page - 1) * $itemsPerPage;
|
||||
$itemsToLoad = $db->getPublishedTheses($itemsPerPage, $offset);
|
||||
$totalItems = $db->countPublishedTheses();
|
||||
$totalPages = ceil($totalItems / $itemsPerPage);
|
||||
} catch (Exception $e) {
|
||||
error_log("Error loading theses: " . $e->getMessage());
|
||||
$itemsToLoad = [];
|
||||
$totalPages = 0;
|
||||
}
|
||||
|
||||
include APP_ROOT . '/includes/header.php';
|
||||
?>
|
||||
|
||||
<main>
|
||||
<?php foreach ($itemsToLoad as $item): ?>
|
||||
<a href="memoire.php?id=<?= $item["id"] ?>" class="card-link">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<h2 class="title"><?= htmlspecialchars($item["title"]) ?></h2>
|
||||
<p class="authors"><?= htmlspecialchars($item["authors"]) ?></p>
|
||||
<p class="year"><?= htmlspecialchars($item["year"]) ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<?php if (empty($itemsToLoad)): ?>
|
||||
<p>Aucun mémoire trouvé.</p>
|
||||
<?php endif; ?>
|
||||
</main>
|
||||
|
||||
<?php if ($totalPages > 1): ?>
|
||||
<nav class="pagination">
|
||||
<?php if ($page > 1): ?>
|
||||
<a href="?page=<?= $page - 1 ?>" class="pagination-previous">Précédent</a>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($page < $totalPages): ?>
|
||||
<a href="?page=<?= $page + 1 ?>" class="pagination-next">Suivant</a>
|
||||
<?php endif; ?>
|
||||
|
||||
<span class="pagination-info">Page <?= $page ?> sur <?= $totalPages ?></span>
|
||||
</nav>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php include APP_ROOT . '/includes/footer.php'; ?>
|
||||
@@ -1,11 +1,9 @@
|
||||
<?php
|
||||
// Disable displaying errors, log errors to a file named 'error.log'
|
||||
ini_set('display_errors', 0);
|
||||
ini_set('log_errors', 1);
|
||||
ini_set('error_log', 'error.log');
|
||||
// Bootstrap application
|
||||
require_once __DIR__ . '/../config/bootstrap.php';
|
||||
|
||||
// Load required libraries and classes
|
||||
require_once __DIR__ . '/lib/Database.php';
|
||||
require_once APP_ROOT . '/lib/Database.php';
|
||||
|
||||
// Check if an id parameter is provided in the URL
|
||||
if (isset($_GET['id'])) {
|
||||
@@ -31,7 +29,7 @@ if (isset($_GET['id'])) {
|
||||
}
|
||||
|
||||
// Include the header template
|
||||
include 'inc/header.php'; ?>
|
||||
include APP_ROOT . '/includes/header.php'; ?>
|
||||
<main>
|
||||
<div class="item">
|
||||
<div class="card-content">
|
||||
@@ -153,4 +151,4 @@ include 'inc/header.php'; ?>
|
||||
</main>
|
||||
|
||||
<!-- Include the footer template -->
|
||||
<?php include 'inc/footer.php'; ?>
|
||||
<?php include APP_ROOT . '/includes/footer.php'; ?>
|
||||
@@ -1,10 +1,9 @@
|
||||
<?php
|
||||
ini_set('display_errors', 0);
|
||||
ini_set('log_errors', 1);
|
||||
ini_set('error_log', 'error.log');
|
||||
// Bootstrap application
|
||||
require_once __DIR__ . '/../config/bootstrap.php';
|
||||
require_once APP_ROOT . '/lib/Database.php';
|
||||
require_once APP_ROOT . '/lib/RateLimit.php';
|
||||
|
||||
require_once __DIR__ . '/lib/Database.php';
|
||||
require_once __DIR__ . '/lib/RateLimit.php';
|
||||
|
||||
// Rate limiting: 30 requests per minute
|
||||
$rateLimit = new RateLimit(30, 60);
|
||||
@@ -17,7 +16,7 @@ if (!$rateLimit->check()) {
|
||||
$rateLimit->sendHeaders();
|
||||
|
||||
// Display error page
|
||||
include 'inc/header.php';
|
||||
include APP_ROOT . '/includes/header.php';
|
||||
echo '<section class="section">';
|
||||
echo ' <div class="container">';
|
||||
echo ' <div class="notification is-danger">';
|
||||
@@ -27,7 +26,7 @@ if (!$rateLimit->check()) {
|
||||
echo ' </div>';
|
||||
echo ' </div>';
|
||||
echo '</section>';
|
||||
include 'inc/footer.php';
|
||||
include APP_ROOT . '/includes/footer.php';
|
||||
exit;
|
||||
}
|
||||
|
||||
@@ -123,7 +122,7 @@ try {
|
||||
$languages = [];
|
||||
}
|
||||
|
||||
include 'inc/header.php'; ?>
|
||||
include APP_ROOT . '/includes/header.php'; ?>
|
||||
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
@@ -416,4 +415,4 @@ include 'inc/header.php'; ?>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<?php include 'inc/footer.php'; ?>
|
||||
<?php include APP_ROOT . '/includes/footer.php'; ?>
|
||||
180
scripts/deploy-production.sh
Normal file
180
scripts/deploy-production.sh
Normal file
@@ -0,0 +1,180 @@
|
||||
#!/bin/bash
|
||||
# Deploy production nginx configuration and fix permissions for Post-ERG
|
||||
|
||||
set -e
|
||||
|
||||
echo "🚀 Post-ERG Production Deployment"
|
||||
echo "=================================="
|
||||
echo ""
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
# Check if running as root
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo -e "${RED}Error: This script must be run as root (use sudo)${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "📋 Step 1: Fixing file permissions..."
|
||||
echo "--------------------------------------"
|
||||
|
||||
# Change group to posterg (www-data is member of this group)
|
||||
chown -R theophile:posterg /var/www/html/
|
||||
echo "✓ Changed group to posterg"
|
||||
|
||||
# Set directory permissions (755 - readable/executable by everyone)
|
||||
find /var/www/html -type d -exec chmod 755 {} \;
|
||||
echo "✓ Set directory permissions to 755"
|
||||
|
||||
# Set file permissions (640 - owner read/write, group read)
|
||||
find /var/www/html -type f -exec chmod 640 {} \;
|
||||
echo "✓ Set file permissions to 640"
|
||||
|
||||
# Make upload directories writable by group (for www-data to write)
|
||||
if [ -d "/var/www/html/formulaire/data/theses" ]; then
|
||||
chmod 775 /var/www/html/formulaire/data/theses
|
||||
chmod 775 /var/www/html/formulaire/data/covers
|
||||
echo "✓ Set upload directories to 775"
|
||||
fi
|
||||
|
||||
# Protect database if it exists
|
||||
if [ -f "/var/www/html/database/posterg.db" ]; then
|
||||
chmod 660 /var/www/html/database/posterg.db
|
||||
chown www-data:posterg /var/www/html/database/posterg.db
|
||||
echo "✓ Protected database file"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "📋 Step 2: Checking prerequisites..."
|
||||
echo "--------------------------------------"
|
||||
|
||||
# Check if htpasswd is available
|
||||
if ! command -v htpasswd &>/dev/null; then
|
||||
echo -e "${YELLOW}⚠️ htpasswd not found, installing apache2-utils...${NC}"
|
||||
apt-get update -qq
|
||||
apt-get install -y apache2-utils
|
||||
echo -e "${GREEN}✓ apache2-utils installed${NC}"
|
||||
fi
|
||||
|
||||
# Check if htpasswd file exists
|
||||
if [ ! -f "/etc/nginx/.htpasswd-posterg" ]; then
|
||||
echo -e "${YELLOW}⚠️ Warning: /etc/nginx/.htpasswd-posterg not found${NC}"
|
||||
echo " Creating it now..."
|
||||
echo ""
|
||||
echo "Please enter admin username:"
|
||||
read -r ADMIN_USER
|
||||
htpasswd -c /etc/nginx/.htpasswd-posterg "$ADMIN_USER"
|
||||
echo -e "${GREEN}✓ Password file created${NC}"
|
||||
echo ""
|
||||
else
|
||||
echo "✓ Password file exists"
|
||||
fi
|
||||
|
||||
# Check if config file was uploaded
|
||||
if [ ! -f "/tmp/posterg.conf" ]; then
|
||||
echo -e "${RED}✗ Error: /tmp/posterg.conf not found${NC}"
|
||||
echo "Please upload it first: rsync -vur ./nginx/posterg-production.conf posterg:/tmp/posterg.conf"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "📋 Step 3: Installing nginx configuration..."
|
||||
echo "--------------------------------------"
|
||||
|
||||
# Backup existing config if it exists
|
||||
if [ -f "/etc/nginx/sites-available/posterg" ]; then
|
||||
cp /etc/nginx/sites-available/posterg /etc/nginx/sites-available/posterg.backup.$(date +%Y%m%d_%H%M%S)
|
||||
echo "✓ Backed up existing config"
|
||||
fi
|
||||
|
||||
# Copy new configuration
|
||||
cp /tmp/posterg.conf /etc/nginx/sites-available/posterg
|
||||
echo "✓ Installed configuration to /etc/nginx/sites-available/posterg"
|
||||
|
||||
# Create symlink
|
||||
if [ ! -L "/etc/nginx/sites-enabled/posterg" ]; then
|
||||
ln -s /etc/nginx/sites-available/posterg /etc/nginx/sites-enabled/posterg
|
||||
echo "✓ Created symlink in sites-enabled"
|
||||
else
|
||||
echo "✓ Symlink already exists"
|
||||
fi
|
||||
|
||||
# Remove default site
|
||||
if [ -L "/etc/nginx/sites-enabled/default" ]; then
|
||||
rm /etc/nginx/sites-enabled/default
|
||||
echo "✓ Disabled default site"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "📋 Step 4: Testing nginx configuration..."
|
||||
echo "--------------------------------------"
|
||||
|
||||
if nginx -t; then
|
||||
echo -e "${GREEN}✓ Nginx configuration is valid${NC}"
|
||||
else
|
||||
echo -e "${RED}✗ Nginx configuration has errors!${NC}"
|
||||
echo "Restoring backup..."
|
||||
if ls /etc/nginx/sites-available/posterg.backup* 1>/dev/null 2>&1; then
|
||||
BACKUP=$(ls -t /etc/nginx/sites-available/posterg.backup* | head -1)
|
||||
cp "$BACKUP" /etc/nginx/sites-available/posterg
|
||||
echo "Configuration restored from backup"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "📋 Step 5: Reloading nginx..."
|
||||
echo "--------------------------------------"
|
||||
|
||||
if systemctl reload nginx; then
|
||||
echo -e "${GREEN}✓ Nginx reloaded successfully${NC}"
|
||||
else
|
||||
echo -e "${RED}✗ Failed to reload nginx${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "📋 Step 6: Verifying services..."
|
||||
echo "--------------------------------------"
|
||||
|
||||
# Check PHP-FPM
|
||||
if systemctl is-active --quiet php8.4-fpm; then
|
||||
echo -e "${GREEN}✓ PHP 8.4-FPM is running${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ PHP-FPM is not running, starting it...${NC}"
|
||||
systemctl start php8.4-fpm
|
||||
systemctl enable php8.4-fpm
|
||||
echo -e "${GREEN}✓ PHP-FPM started${NC}"
|
||||
fi
|
||||
|
||||
# Check nginx
|
||||
if systemctl is-active --quiet nginx; then
|
||||
echo -e "${GREEN}✓ Nginx is running${NC}"
|
||||
else
|
||||
echo -e "${RED}✗ Nginx is not running!${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "═══════════════════════════════════════"
|
||||
echo -e "${GREEN}✅ Deployment Complete!${NC}"
|
||||
echo "═══════════════════════════════════════"
|
||||
echo ""
|
||||
echo "🧪 Quick Tests:"
|
||||
echo " • Test public site: curl -I http://localhost/"
|
||||
echo " • Test admin panel: curl -I http://localhost/formulaire/"
|
||||
echo " • Test PHP: curl http://localhost/index.php"
|
||||
echo ""
|
||||
echo "📊 View logs:"
|
||||
echo " • Access log: tail -f /var/log/nginx/posterg_access.log"
|
||||
echo " • Error log: tail -f /var/log/nginx/posterg_error.log"
|
||||
echo ""
|
||||
echo "🔒 Security Checks:"
|
||||
echo " • Database blocked: curl -I http://localhost/database/posterg.db"
|
||||
echo " • MD files blocked: curl -I http://localhost/README.md"
|
||||
echo " • Shared blocked: curl -I http://localhost/shared/Database.php"
|
||||
echo ""
|
||||
34
scripts/install-php-sqlite.sh
Normal file
34
scripts/install-php-sqlite.sh
Normal file
@@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
# Install PHP SQLite extension
|
||||
|
||||
echo "🔧 Installing PHP SQLite extension..."
|
||||
|
||||
# Check if running as root
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo "Error: This script must be run as root (use sudo)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Detect PHP version
|
||||
PHP_VERSION=$(php -r "echo PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION;")
|
||||
echo "Detected PHP version: $PHP_VERSION"
|
||||
|
||||
# Install SQLite extension
|
||||
echo "Installing php${PHP_VERSION}-sqlite3..."
|
||||
apt-get update -qq
|
||||
apt-get install -y php${PHP_VERSION}-sqlite3
|
||||
|
||||
# Restart PHP-FPM
|
||||
echo "Restarting PHP-FPM..."
|
||||
systemctl restart php${PHP_VERSION}-fpm
|
||||
|
||||
# Verify installation
|
||||
if php -m | grep -q sqlite3; then
|
||||
echo "✅ SQLite extension installed successfully"
|
||||
echo ""
|
||||
echo "Installed extensions:"
|
||||
php -m | grep -i sqlite
|
||||
else
|
||||
echo "❌ Failed to install SQLite extension"
|
||||
exit 1
|
||||
fi
|
||||
199
scripts/manage-admin-user.sh
Normal file
199
scripts/manage-admin-user.sh
Normal file
@@ -0,0 +1,199 @@
|
||||
#!/bin/bash
|
||||
# Manage admin users for Post-ERG nginx basic authentication
|
||||
|
||||
set -e
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
PASSWORD_FILE="/etc/nginx/.htpasswd-posterg"
|
||||
|
||||
# Check if running as root
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo -e "${RED}Error: This script must be run as root (use sudo)${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if htpasswd is available
|
||||
if ! command -v htpasswd &>/dev/null; then
|
||||
echo -e "${YELLOW}Installing apache2-utils...${NC}"
|
||||
apt-get update -qq
|
||||
apt-get install -y apache2-utils
|
||||
fi
|
||||
|
||||
show_menu() {
|
||||
echo ""
|
||||
echo -e "${BLUE}════════════════════════════════════════${NC}"
|
||||
echo -e "${BLUE} Post-ERG Admin User Management${NC}"
|
||||
echo -e "${BLUE}════════════════════════════════════════${NC}"
|
||||
echo ""
|
||||
echo "1. List all users"
|
||||
echo "2. Add new user"
|
||||
echo "3. Change user password"
|
||||
echo "4. Delete user"
|
||||
echo "5. Reset all (create new password file)"
|
||||
echo "6. Exit"
|
||||
echo ""
|
||||
echo -n "Choose an option [1-6]: "
|
||||
}
|
||||
|
||||
list_users() {
|
||||
echo ""
|
||||
if [ ! -f "$PASSWORD_FILE" ]; then
|
||||
echo -e "${YELLOW}No password file found.${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Current admin users:${NC}"
|
||||
echo "────────────────────────"
|
||||
cut -d: -f1 "$PASSWORD_FILE" | nl
|
||||
echo ""
|
||||
}
|
||||
|
||||
add_user() {
|
||||
echo ""
|
||||
echo -n "Enter new username: "
|
||||
read -r USERNAME
|
||||
|
||||
if [ -z "$USERNAME" ]; then
|
||||
echo -e "${RED}Username cannot be empty${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
# Check if user already exists
|
||||
if [ -f "$PASSWORD_FILE" ] && grep -q "^${USERNAME}:" "$PASSWORD_FILE"; then
|
||||
echo -e "${YELLOW}User '$USERNAME' already exists. Use option 3 to change password.${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
# Add user (use -c only if file doesn't exist)
|
||||
if [ ! -f "$PASSWORD_FILE" ]; then
|
||||
htpasswd -c "$PASSWORD_FILE" "$USERNAME"
|
||||
else
|
||||
htpasswd "$PASSWORD_FILE" "$USERNAME"
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}✓ User '$USERNAME' added successfully${NC}"
|
||||
}
|
||||
|
||||
change_password() {
|
||||
list_users
|
||||
echo -n "Enter username to change password: "
|
||||
read -r USERNAME
|
||||
|
||||
if [ -z "$USERNAME" ]; then
|
||||
echo -e "${RED}Username cannot be empty${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
if [ ! -f "$PASSWORD_FILE" ]; then
|
||||
echo -e "${RED}Password file not found${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
if ! grep -q "^${USERNAME}:" "$PASSWORD_FILE"; then
|
||||
echo -e "${RED}User '$USERNAME' not found${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
htpasswd "$PASSWORD_FILE" "$USERNAME"
|
||||
echo -e "${GREEN}✓ Password changed for user '$USERNAME'${NC}"
|
||||
}
|
||||
|
||||
delete_user() {
|
||||
list_users
|
||||
echo -n "Enter username to delete: "
|
||||
read -r USERNAME
|
||||
|
||||
if [ -z "$USERNAME" ]; then
|
||||
echo -e "${RED}Username cannot be empty${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
if [ ! -f "$PASSWORD_FILE" ]; then
|
||||
echo -e "${RED}Password file not found${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
if ! grep -q "^${USERNAME}:" "$PASSWORD_FILE"; then
|
||||
echo -e "${RED}User '$USERNAME' not found${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
echo -n "Are you sure you want to delete user '$USERNAME'? [y/N] "
|
||||
read -r CONFIRM
|
||||
|
||||
if [ "$CONFIRM" = "y" ] || [ "$CONFIRM" = "Y" ]; then
|
||||
htpasswd -D "$PASSWORD_FILE" "$USERNAME"
|
||||
echo -e "${GREEN}✓ User '$USERNAME' deleted${NC}"
|
||||
else
|
||||
echo "Cancelled"
|
||||
fi
|
||||
}
|
||||
|
||||
reset_all() {
|
||||
echo ""
|
||||
echo -e "${YELLOW}WARNING: This will delete ALL existing users!${NC}"
|
||||
echo -n "Are you sure? [y/N] "
|
||||
read -r CONFIRM
|
||||
|
||||
if [ "$CONFIRM" != "y" ] && [ "$CONFIRM" != "Y" ]; then
|
||||
echo "Cancelled"
|
||||
return
|
||||
fi
|
||||
|
||||
# Backup existing file
|
||||
if [ -f "$PASSWORD_FILE" ]; then
|
||||
BACKUP="${PASSWORD_FILE}.backup.$(date +%Y%m%d_%H%M%S)"
|
||||
cp "$PASSWORD_FILE" "$BACKUP"
|
||||
echo -e "${GREEN}✓ Backed up to: $BACKUP${NC}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -n "Enter new username: "
|
||||
read -r USERNAME
|
||||
|
||||
if [ -z "$USERNAME" ]; then
|
||||
echo -e "${RED}Username cannot be empty${NC}"
|
||||
return
|
||||
fi
|
||||
|
||||
htpasswd -c "$PASSWORD_FILE" "$USERNAME"
|
||||
echo -e "${GREEN}✓ Password file reset with user '$USERNAME'${NC}"
|
||||
}
|
||||
|
||||
# Main loop
|
||||
while true; do
|
||||
show_menu
|
||||
read -r CHOICE
|
||||
|
||||
case $CHOICE in
|
||||
1)
|
||||
list_users
|
||||
;;
|
||||
2)
|
||||
add_user
|
||||
;;
|
||||
3)
|
||||
change_password
|
||||
;;
|
||||
4)
|
||||
delete_user
|
||||
;;
|
||||
5)
|
||||
reset_all
|
||||
;;
|
||||
6)
|
||||
echo ""
|
||||
echo "Goodbye!"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}Invalid option${NC}"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
Reference in New Issue
Block a user