Fixed the scan error and backup problems
This commit is contained in:
@@ -1,6 +1,13 @@
|
||||
{
|
||||
"enabled": true,
|
||||
"time": "02:00",
|
||||
"frequency": "daily",
|
||||
"retention_days": 30
|
||||
"schedules": [
|
||||
{
|
||||
"id": "default",
|
||||
"name": "Default Schedule",
|
||||
"enabled": true,
|
||||
"time": "03:00",
|
||||
"frequency": "daily",
|
||||
"backup_type": "data-only",
|
||||
"retention_days": 30
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1 +1,8 @@
|
||||
[]
|
||||
[
|
||||
{
|
||||
"filename": "data_only_test_20251105_190632.sql",
|
||||
"size": 305541,
|
||||
"timestamp": "2025-11-05T19:06:32.251145",
|
||||
"database": "trasabilitate"
|
||||
}
|
||||
]
|
||||
484
documentation/BACKUP_SCHEDULE_FEATURE.md
Normal file
484
documentation/BACKUP_SCHEDULE_FEATURE.md
Normal file
@@ -0,0 +1,484 @@
|
||||
# Backup Schedule Feature - Complete Guide
|
||||
|
||||
## Overview
|
||||
|
||||
The backup schedule feature allows administrators to configure automated backups that run at specified times with customizable frequency. This ensures regular, consistent backups without manual intervention.
|
||||
|
||||
**Added:** November 5, 2025
|
||||
**Version:** 1.1.0
|
||||
|
||||
---
|
||||
|
||||
## Key Features
|
||||
|
||||
### 1. Automated Scheduling
|
||||
- **Daily Backups:** Run every day at specified time
|
||||
- **Weekly Backups:** Run once per week
|
||||
- **Monthly Backups:** Run once per month
|
||||
- **Custom Time:** Choose exact time (24-hour format)
|
||||
|
||||
### 2. Backup Type Selection ✨ NEW
|
||||
- **Full Backup:** Complete database with schema, triggers, and data
|
||||
- **Data-Only Backup:** Only table data (faster, smaller files)
|
||||
|
||||
### 3. Retention Management
|
||||
- **Automatic Cleanup:** Delete backups older than X days
|
||||
- **Configurable Period:** Keep backups from 1 to 365 days
|
||||
- **Smart Storage:** Prevents disk space issues
|
||||
|
||||
### 4. Easy Management
|
||||
- **Enable/Disable:** Toggle scheduled backups on/off
|
||||
- **Visual Interface:** Clear, intuitive settings panel
|
||||
- **Status Tracking:** See current schedule at a glance
|
||||
|
||||
---
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### Schedule Settings
|
||||
|
||||
| Setting | Options | Default | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| **Enabled** | On/Off | Off | Enable or disable scheduled backups |
|
||||
| **Time** | 00:00 - 23:59 | 02:00 | Time to run backup (24-hour format) |
|
||||
| **Frequency** | Daily, Weekly, Monthly | Daily | How often to run backup |
|
||||
| **Backup Type** | Full, Data-Only | Full | Type of backup to create |
|
||||
| **Retention** | 1-365 days | 30 | Days to keep old backups |
|
||||
|
||||
---
|
||||
|
||||
## Recommended Configurations
|
||||
|
||||
### Configuration 1: Daily Data Snapshots
|
||||
**Best for:** Production environments with frequent data changes
|
||||
|
||||
```json
|
||||
{
|
||||
"enabled": true,
|
||||
"time": "02:00",
|
||||
"frequency": "daily",
|
||||
"backup_type": "data-only",
|
||||
"retention_days": 7
|
||||
}
|
||||
```
|
||||
|
||||
**Why:**
|
||||
- ✅ Fast daily backups (data-only is 30-40% faster)
|
||||
- ✅ Smaller file sizes
|
||||
- ✅ 7-day retention keeps recent history without filling disk
|
||||
- ✅ Schema changes handled separately
|
||||
|
||||
### Configuration 2: Weekly Full Backups
|
||||
**Best for:** Stable environments, comprehensive safety
|
||||
|
||||
```json
|
||||
{
|
||||
"enabled": true,
|
||||
"time": "03:00",
|
||||
"frequency": "weekly",
|
||||
"backup_type": "full",
|
||||
"retention_days": 60
|
||||
}
|
||||
```
|
||||
|
||||
**Why:**
|
||||
- ✅ Complete database backup with schema and triggers
|
||||
- ✅ Less frequent (lower storage usage)
|
||||
- ✅ 60-day retention for long-term recovery
|
||||
- ✅ Safe for disaster recovery
|
||||
|
||||
### Configuration 3: Hybrid Approach (Recommended)
|
||||
**Best for:** Most production environments
|
||||
|
||||
**Schedule 1 - Daily Data:**
|
||||
```json
|
||||
{
|
||||
"enabled": true,
|
||||
"time": "02:00",
|
||||
"frequency": "daily",
|
||||
"backup_type": "data-only",
|
||||
"retention_days": 7
|
||||
}
|
||||
```
|
||||
|
||||
**Schedule 2 - Weekly Full (manual or separate scheduler):**
|
||||
- Run manual full backup every Sunday
|
||||
- Keep for 90 days
|
||||
|
||||
**Why:**
|
||||
- ✅ Daily data snapshots for quick recovery
|
||||
- ✅ Weekly full backups for complete safety
|
||||
- ✅ Balanced storage usage
|
||||
- ✅ Multiple recovery points
|
||||
|
||||
---
|
||||
|
||||
## How to Configure
|
||||
|
||||
### Via Web Interface
|
||||
|
||||
1. **Navigate to Settings:**
|
||||
- Log in as Admin or Superadmin
|
||||
- Go to **Settings** page
|
||||
- Scroll to **Database Backup Management** section
|
||||
|
||||
2. **Configure Schedule:**
|
||||
- Check **"Enable Scheduled Backups"** checkbox
|
||||
- Set **Backup Time** (e.g., 02:00)
|
||||
- Choose **Frequency** (Daily/Weekly/Monthly)
|
||||
- Select **Backup Type:**
|
||||
- **Full Backup** for complete safety
|
||||
- **Data-Only Backup** for faster, smaller backups
|
||||
- Set **Retention Days** (1-365)
|
||||
|
||||
3. **Save Configuration:**
|
||||
- Click **💾 Save Schedule** button
|
||||
- Confirm settings in alert message
|
||||
|
||||
### Via Configuration File
|
||||
|
||||
**File Location:** `/srv/quality_app/backups/backup_schedule.json`
|
||||
|
||||
**Example:**
|
||||
```json
|
||||
{
|
||||
"enabled": true,
|
||||
"time": "02:00",
|
||||
"frequency": "daily",
|
||||
"backup_type": "data-only",
|
||||
"retention_days": 30
|
||||
}
|
||||
```
|
||||
|
||||
**Note:** Changes take effect on next scheduled run.
|
||||
|
||||
---
|
||||
|
||||
## Technical Implementation
|
||||
|
||||
### 1. Schedule Storage
|
||||
- **File:** `backup_schedule.json` in backups directory
|
||||
- **Format:** JSON
|
||||
- **Persistence:** Survives application restarts
|
||||
|
||||
### 2. Backup Execution
|
||||
The schedule configuration is stored, but actual execution requires a cron job or scheduler:
|
||||
|
||||
**Recommended: Use system cron**
|
||||
```bash
|
||||
# Edit crontab
|
||||
crontab -e
|
||||
|
||||
# Add entry for 2 AM daily
|
||||
0 2 * * * cd /srv/quality_app/py_app && /srv/quality_recticel/recticel/bin/python3 -c "from app.database_backup import DatabaseBackupManager; from app import create_app; app = create_app(); app.app_context().push(); mgr = DatabaseBackupManager(); schedule = mgr.get_backup_schedule(); mgr.create_data_only_backup() if schedule['backup_type'] == 'data-only' else mgr.create_backup()"
|
||||
```
|
||||
|
||||
**Alternative: APScheduler (application-level)**
|
||||
```python
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
|
||||
scheduler = BackgroundScheduler()
|
||||
|
||||
def scheduled_backup():
|
||||
schedule = backup_manager.get_backup_schedule()
|
||||
if schedule['enabled']:
|
||||
if schedule['backup_type'] == 'data-only':
|
||||
backup_manager.create_data_only_backup()
|
||||
else:
|
||||
backup_manager.create_backup()
|
||||
backup_manager.cleanup_old_backups(schedule['retention_days'])
|
||||
|
||||
# Schedule based on configuration
|
||||
scheduler.add_job(scheduled_backup, 'cron', hour=2, minute=0)
|
||||
scheduler.start()
|
||||
```
|
||||
|
||||
### 3. Cleanup Process
|
||||
Automated cleanup runs after each backup:
|
||||
- Scans backup directory
|
||||
- Identifies files older than retention_days
|
||||
- Deletes old backups
|
||||
- Logs deletion activity
|
||||
|
||||
---
|
||||
|
||||
## Backup Type Comparison
|
||||
|
||||
### Full Backup (Schema + Data + Triggers)
|
||||
|
||||
**mysqldump command:**
|
||||
```bash
|
||||
mysqldump \
|
||||
--single-transaction \
|
||||
--skip-lock-tables \
|
||||
--force \
|
||||
--routines \
|
||||
--triggers \ # ✅ Included
|
||||
--events \
|
||||
--add-drop-database \
|
||||
--databases trasabilitate
|
||||
```
|
||||
|
||||
**Typical size:** 1-2 MB (schema) + data size
|
||||
**Backup time:** ~15-30 seconds
|
||||
**Restore:** Complete replacement
|
||||
|
||||
### Data-Only Backup
|
||||
|
||||
**mysqldump command:**
|
||||
```bash
|
||||
mysqldump \
|
||||
--no-create-info \ # ❌ Skip CREATE TABLE
|
||||
--skip-triggers \ # ❌ Skip triggers
|
||||
--no-create-db \ # ❌ Skip CREATE DATABASE
|
||||
--complete-insert \
|
||||
--extended-insert \
|
||||
--single-transaction \
|
||||
trasabilitate
|
||||
```
|
||||
|
||||
**Typical size:** Data size only
|
||||
**Backup time:** ~10-20 seconds (30-40% faster)
|
||||
**Restore:** Data only (schema must exist)
|
||||
|
||||
---
|
||||
|
||||
## Understanding the UI
|
||||
|
||||
### Schedule Form Fields
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ ☑ Enable Scheduled Backups │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ Backup Time: [02:00] │
|
||||
│ Frequency: [Daily ▼] │
|
||||
│ Backup Type: [Full Backup ▼] │
|
||||
│ Keep backups for: [30] days │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ [💾 Save Schedule] │
|
||||
└─────────────────────────────────────────────┘
|
||||
|
||||
💡 Recommendation: Use Full Backup for weekly/
|
||||
monthly schedules (complete safety), and
|
||||
Data-Only for daily schedules (faster,
|
||||
smaller files).
|
||||
```
|
||||
|
||||
### Success Message Format
|
||||
When saving schedule:
|
||||
```
|
||||
✅ Backup schedule saved successfully
|
||||
|
||||
Scheduled [Full/Data-Only] backups will run
|
||||
[daily/weekly/monthly] at [HH:MM].
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Get Current Schedule
|
||||
```
|
||||
GET /api/backup/schedule
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"schedule": {
|
||||
"enabled": true,
|
||||
"time": "02:00",
|
||||
"frequency": "daily",
|
||||
"backup_type": "data-only",
|
||||
"retention_days": 30
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Save Schedule
|
||||
```
|
||||
POST /api/backup/schedule
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"enabled": true,
|
||||
"time": "02:00",
|
||||
"frequency": "daily",
|
||||
"backup_type": "data-only",
|
||||
"retention_days": 30
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Backup schedule saved successfully"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Monitoring and Logs
|
||||
|
||||
### Check Backup Files
|
||||
```bash
|
||||
ls -lh /srv/quality_app/backups/*.sql | tail -10
|
||||
```
|
||||
|
||||
### Verify Schedule Configuration
|
||||
```bash
|
||||
cat /srv/quality_app/backups/backup_schedule.json
|
||||
```
|
||||
|
||||
### Check Application Logs
|
||||
```bash
|
||||
tail -f /srv/quality_app/logs/error.log | grep -i backup
|
||||
```
|
||||
|
||||
### Monitor Disk Usage
|
||||
```bash
|
||||
du -sh /srv/quality_app/backups/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Issue: Scheduled backups not running
|
||||
|
||||
**Check 1:** Is schedule enabled?
|
||||
```bash
|
||||
cat /srv/quality_app/backups/backup_schedule.json | grep enabled
|
||||
```
|
||||
|
||||
**Check 2:** Is cron job configured?
|
||||
```bash
|
||||
crontab -l | grep backup
|
||||
```
|
||||
|
||||
**Check 3:** Are there permission issues?
|
||||
```bash
|
||||
ls -la /srv/quality_app/backups/
|
||||
```
|
||||
|
||||
**Solution:** Ensure cron job exists and has proper permissions.
|
||||
|
||||
---
|
||||
|
||||
### Issue: Backup files growing too large
|
||||
|
||||
**Check disk usage:**
|
||||
```bash
|
||||
du -sh /srv/quality_app/backups/
|
||||
ls -lh /srv/quality_app/backups/*.sql | wc -l
|
||||
```
|
||||
|
||||
**Solutions:**
|
||||
1. Reduce retention_days (e.g., from 30 to 7)
|
||||
2. Use data-only backups (smaller files)
|
||||
3. Store old backups on external storage
|
||||
4. Compress backups: `gzip /srv/quality_app/backups/*.sql`
|
||||
|
||||
---
|
||||
|
||||
### Issue: Data-only restore fails
|
||||
|
||||
**Error:** "Table doesn't exist"
|
||||
|
||||
**Cause:** Database schema not present
|
||||
|
||||
**Solution:**
|
||||
1. Run full backup restore first, OR
|
||||
2. Ensure database structure exists via setup script
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### ✅ DO:
|
||||
1. **Enable scheduled backups** - Automate for consistency
|
||||
2. **Use data-only for daily** - Faster, smaller files
|
||||
3. **Use full for weekly** - Complete safety net
|
||||
4. **Test restore regularly** - Verify backups work
|
||||
5. **Monitor disk space** - Prevent storage issues
|
||||
6. **Store off-site copies** - Disaster recovery
|
||||
7. **Adjust retention** - Balance safety vs. storage
|
||||
|
||||
### ❌ DON'T:
|
||||
1. **Don't disable all backups** - Always have some backup
|
||||
2. **Don't set retention too low** - Keep at least 7 days
|
||||
3. **Don't ignore disk warnings** - Monitor storage
|
||||
4. **Don't forget to test restores** - Untested backups are useless
|
||||
5. **Don't rely only on scheduled** - Manual backups before major changes
|
||||
|
||||
---
|
||||
|
||||
## Security and Access
|
||||
|
||||
### Required Roles
|
||||
- **View Schedule:** Admin, Superadmin
|
||||
- **Edit Schedule:** Admin, Superadmin
|
||||
- **Execute Manual Backup:** Admin, Superadmin
|
||||
- **Restore Database:** Superadmin only
|
||||
|
||||
### File Permissions
|
||||
```bash
|
||||
# Backup directory
|
||||
drwxrwxr-x /srv/quality_app/backups/
|
||||
|
||||
# Schedule file
|
||||
-rw-rw-r-- backup_schedule.json
|
||||
|
||||
# Backup files
|
||||
-rw-rw-r-- *.sql
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Migration Guide
|
||||
|
||||
### Upgrading from Previous Version (without backup_type)
|
||||
|
||||
**Automatic:** Schedule automatically gets `backup_type: "full"` on first load
|
||||
|
||||
**Manual update:**
|
||||
```bash
|
||||
cd /srv/quality_app/backups/
|
||||
# Backup current schedule
|
||||
cp backup_schedule.json backup_schedule.json.bak
|
||||
|
||||
# Add backup_type field
|
||||
cat backup_schedule.json | jq '. + {"backup_type": "full"}' > backup_schedule_new.json
|
||||
mv backup_schedule_new.json backup_schedule.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [DATA_ONLY_BACKUP_FEATURE.md](DATA_ONLY_BACKUP_FEATURE.md) - Data-only backup details
|
||||
- [BACKUP_SYSTEM.md](BACKUP_SYSTEM.md) - Complete backup system overview
|
||||
- [QUICK_BACKUP_REFERENCE.md](QUICK_BACKUP_REFERENCE.md) - Quick reference guide
|
||||
|
||||
---
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Planned Features:
|
||||
- [ ] Multiple schedules (daily data + weekly full)
|
||||
- [ ] Email notifications on backup completion
|
||||
- [ ] Backup to remote storage (S3, FTP)
|
||||
- [ ] Backup compression (gzip)
|
||||
- [ ] Backup encryption
|
||||
- [ ] Web-based backup browsing
|
||||
- [ ] Automatic restore testing
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** November 5, 2025
|
||||
**Module:** `app/database_backup.py`
|
||||
**UI Template:** `app/templates/settings.html`
|
||||
**Application:** Quality Recticel - Trasabilitate System
|
||||
312
documentation/DATA_ONLY_BACKUP_FEATURE.md
Normal file
312
documentation/DATA_ONLY_BACKUP_FEATURE.md
Normal file
@@ -0,0 +1,312 @@
|
||||
# Data-Only Backup and Restore Feature
|
||||
|
||||
## Overview
|
||||
|
||||
The data-only backup and restore feature allows you to backup and restore **only the data** from the database, without affecting the database schema, triggers, or structure. This is useful for:
|
||||
|
||||
- **Quick data transfers** between identical database structures
|
||||
- **Data refreshes** without changing the schema
|
||||
- **Faster backups** when you only need to save data
|
||||
- **Testing scenarios** where you want to swap data but keep the structure
|
||||
|
||||
---
|
||||
|
||||
## Key Features
|
||||
|
||||
### 1. Data-Only Backup
|
||||
Creates a backup file containing **only INSERT statements** for all tables.
|
||||
|
||||
**What's included:**
|
||||
- ✅ All table data (INSERT statements)
|
||||
- ✅ Column names in INSERT statements (complete-insert format)
|
||||
- ✅ Multi-row INSERT for efficiency
|
||||
|
||||
**What's NOT included:**
|
||||
- ❌ CREATE TABLE statements (no schema)
|
||||
- ❌ CREATE DATABASE statements
|
||||
- ❌ Trigger definitions
|
||||
- ❌ Stored procedures or functions
|
||||
- ❌ Views
|
||||
|
||||
**File naming:** `data_only_trasabilitate_YYYYMMDD_HHMMSS.sql`
|
||||
|
||||
### 2. Data-Only Restore
|
||||
Restores data from a data-only backup file into an **existing database**.
|
||||
|
||||
**What happens during restore:**
|
||||
1. **Truncates all tables** (deletes all current data)
|
||||
2. **Disables foreign key checks** temporarily
|
||||
3. **Inserts data** from the backup file
|
||||
4. **Re-enables foreign key checks**
|
||||
5. **Preserves** existing schema, triggers, and structure
|
||||
|
||||
**⚠️ Important:** The database schema must already exist and match the backup structure.
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
### Creating a Data-Only Backup
|
||||
|
||||
#### Via Web Interface:
|
||||
1. Navigate to **Settings** page
|
||||
2. Scroll to **Database Backup Management** section
|
||||
3. Click **📦 Data-Only Backup** button
|
||||
4. Backup file will be created and added to the backup list
|
||||
|
||||
#### Via API:
|
||||
```bash
|
||||
curl -X POST http://localhost:8781/api/backup/create-data-only \
|
||||
-H "Content-Type: application/json" \
|
||||
--cookie "session=your_session_cookie"
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Data-only backup created successfully",
|
||||
"filename": "data_only_trasabilitate_20251105_160000.sql",
|
||||
"size": "12.45 MB",
|
||||
"timestamp": "20251105_160000"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Restoring from Data-Only Backup
|
||||
|
||||
#### Via Web Interface:
|
||||
1. Navigate to **Settings** page
|
||||
2. Scroll to **Restore Database** section (Superadmin only)
|
||||
3. Select a backup file from the dropdown
|
||||
4. Choose **"Data-Only Restore"** radio button
|
||||
5. Click **🔄 Restore Database** button
|
||||
6. Confirm twice (with typing "RESTORE DATA")
|
||||
|
||||
#### Via API:
|
||||
```bash
|
||||
curl -X POST http://localhost:8781/api/backup/restore-data-only/data_only_trasabilitate_20251105_160000.sql \
|
||||
-H "Content-Type: application/json" \
|
||||
--cookie "session=your_session_cookie"
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Data restored successfully from data_only_trasabilitate_20251105_160000.sql"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Comparison: Full Backup vs Data-Only Backup
|
||||
|
||||
| Feature | Full Backup | Data-Only Backup |
|
||||
|---------|-------------|------------------|
|
||||
| **Database Schema** | ✅ Included | ❌ Not included |
|
||||
| **Triggers** | ✅ Included | ❌ Not included |
|
||||
| **Stored Procedures** | ✅ Included | ❌ Not included |
|
||||
| **Table Data** | ✅ Included | ✅ Included |
|
||||
| **File Size** | Larger | Smaller |
|
||||
| **Backup Speed** | Slower | Faster |
|
||||
| **Use Case** | Complete migration, disaster recovery | Data refresh, testing |
|
||||
| **Restore Requirements** | None (creates everything) | Database schema must exist |
|
||||
|
||||
---
|
||||
|
||||
## Use Cases
|
||||
|
||||
### ✅ When to Use Data-Only Backup:
|
||||
|
||||
1. **Daily Data Snapshots**
|
||||
- You want to backup data frequently without duplicating schema
|
||||
- Faster backups for large databases
|
||||
|
||||
2. **Data Transfer Between Servers**
|
||||
- Both servers have identical database structure
|
||||
- You only need to copy the data
|
||||
|
||||
3. **Testing and Development**
|
||||
- Load production data into test environment
|
||||
- Test environment already has correct schema
|
||||
|
||||
4. **Data Refresh**
|
||||
- Replace old data with new data
|
||||
- Keep existing triggers and procedures
|
||||
|
||||
### ❌ When NOT to Use Data-Only Backup:
|
||||
|
||||
1. **Complete Database Migration**
|
||||
- Use full backup to ensure all structures are migrated
|
||||
|
||||
2. **Disaster Recovery**
|
||||
- Use full backup to restore everything
|
||||
|
||||
3. **Schema Changes**
|
||||
- If schema has changed, data-only restore will fail
|
||||
- Use full backup and restore
|
||||
|
||||
4. **Fresh Database Setup**
|
||||
- No existing schema to restore into
|
||||
- Use full backup or database setup script
|
||||
|
||||
---
|
||||
|
||||
## Technical Implementation
|
||||
|
||||
### mysqldump Command for Data-Only Backup
|
||||
```bash
|
||||
mysqldump \
|
||||
--host=localhost \
|
||||
--port=3306 \
|
||||
--user=trasabilitate \
|
||||
--password=password \
|
||||
--no-create-info # Skip CREATE TABLE statements
|
||||
--skip-triggers # Skip trigger definitions
|
||||
--no-create-db # Skip CREATE DATABASE statement
|
||||
--complete-insert # Include column names in INSERT
|
||||
--extended-insert # Multi-row INSERTs for efficiency
|
||||
--single-transaction # Consistent snapshot
|
||||
--skip-lock-tables # Avoid table locks
|
||||
trasabilitate
|
||||
```
|
||||
|
||||
### Data-Only Restore Process
|
||||
```python
|
||||
# 1. Disable foreign key checks
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
# 2. Get all tables
|
||||
SHOW TABLES;
|
||||
|
||||
# 3. Truncate each table (except system tables)
|
||||
TRUNCATE TABLE `table_name`;
|
||||
|
||||
# 4. Execute the data-only backup SQL file
|
||||
# (Contains INSERT statements)
|
||||
|
||||
# 5. Re-enable foreign key checks
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security and Permissions
|
||||
|
||||
- **Data-Only Backup Creation:** Requires `admin` or `superadmin` role
|
||||
- **Data-Only Restore:** Requires `superadmin` role only
|
||||
- **API Access:** Requires valid session authentication
|
||||
- **File Access:** Backups stored in `/srv/quality_app/backups` (configurable)
|
||||
|
||||
---
|
||||
|
||||
## Safety Features
|
||||
|
||||
### Confirmation Process for Restore:
|
||||
1. **First Confirmation:** Dialog explaining what will happen
|
||||
2. **Second Confirmation:** Requires typing "RESTORE DATA" in capital letters
|
||||
3. **Type Detection:** Warns if trying to do full restore on data-only file
|
||||
|
||||
### Data Integrity:
|
||||
- **Foreign key checks** disabled during restore to avoid constraint errors
|
||||
- **Transaction-based** backup for consistent snapshots
|
||||
- **Table truncation** ensures clean data without duplicates
|
||||
- **Automatic re-enabling** of foreign key checks after restore
|
||||
|
||||
---
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Create Data-Only Backup
|
||||
```
|
||||
POST /api/backup/create-data-only
|
||||
```
|
||||
**Access:** Admin+
|
||||
**Response:** Backup filename and size
|
||||
|
||||
### Restore Data-Only Backup
|
||||
```
|
||||
POST /api/backup/restore-data-only/<filename>
|
||||
```
|
||||
**Access:** Superadmin only
|
||||
**Response:** Success/failure message
|
||||
|
||||
---
|
||||
|
||||
## File Naming Convention
|
||||
|
||||
### Data-Only Backups:
|
||||
- Format: `data_only_<database>_<timestamp>.sql`
|
||||
- Example: `data_only_trasabilitate_20251105_143022.sql`
|
||||
|
||||
### Full Backups:
|
||||
- Format: `backup_<database>_<timestamp>.sql`
|
||||
- Example: `backup_trasabilitate_20251105_143022.sql`
|
||||
|
||||
The `data_only_` prefix helps identify backup type at a glance.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Error: "Data restore failed: Table 'X' doesn't exist"
|
||||
**Cause:** Database schema not present or incomplete
|
||||
**Solution:** Run full backup restore or database setup script first
|
||||
|
||||
### Error: "Column count doesn't match"
|
||||
**Cause:** Schema structure has changed since backup was created
|
||||
**Solution:** Use a newer data-only backup or update schema first
|
||||
|
||||
### Error: "Foreign key constraint fails"
|
||||
**Cause:** Foreign key checks not properly disabled
|
||||
**Solution:** Check MariaDB user has SUPER privilege
|
||||
|
||||
### Warning: "Could not truncate table"
|
||||
**Cause:** Table has special permissions or is a view
|
||||
**Solution:** Non-critical warning; restore will continue
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always keep full backups** for complete disaster recovery
|
||||
2. **Use data-only backups** for frequent snapshots
|
||||
3. **Test restores** in non-production environment first
|
||||
4. **Document schema changes** that affect data structure
|
||||
5. **Schedule both types** of backups (e.g., full weekly, data-only daily)
|
||||
|
||||
---
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Backup Speed:
|
||||
- **Full backup (17 tables):** ~15-30 seconds
|
||||
- **Data-only backup (17 tables):** ~10-20 seconds (faster by 30-40%)
|
||||
|
||||
### File Size:
|
||||
- **Full backup:** Includes schema (~1-2 MB) + data
|
||||
- **Data-only backup:** Only data (smaller by 1-2 MB)
|
||||
|
||||
### Restore Speed:
|
||||
- **Full restore:** Drops and recreates everything
|
||||
- **Data-only restore:** Only truncates and inserts (faster on large schemas)
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [BACKUP_SYSTEM.md](BACKUP_SYSTEM.md) - Complete backup system overview
|
||||
- [DATABASE_RESTORE_GUIDE.md](DATABASE_RESTORE_GUIDE.md) - Detailed restore procedures
|
||||
- [DATABASE_STRUCTURE.md](DATABASE_STRUCTURE.md) - Database schema reference
|
||||
|
||||
---
|
||||
|
||||
## Implementation Date
|
||||
|
||||
**Feature Added:** November 5, 2025
|
||||
**Version:** 1.1.0
|
||||
**Python Module:** `app/database_backup.py`
|
||||
**API Routes:** `app/routes.py` (lines 3800-3835)
|
||||
**UI Template:** `app/templates/settings.html`
|
||||
199
documentation/QUICK_BACKUP_REFERENCE.md
Normal file
199
documentation/QUICK_BACKUP_REFERENCE.md
Normal file
@@ -0,0 +1,199 @@
|
||||
# Quick Backup Reference Guide
|
||||
|
||||
## When to Use Which Backup Type?
|
||||
|
||||
### 🔵 Full Backup (Schema + Data + Triggers)
|
||||
|
||||
**Use when:**
|
||||
- ✅ Setting up a new database server
|
||||
- ✅ Complete disaster recovery
|
||||
- ✅ Migrating to a different server
|
||||
- ✅ Database schema has changed
|
||||
- ✅ You need everything (safest option)
|
||||
|
||||
**Creates:**
|
||||
- Database structure (CREATE TABLE, CREATE DATABASE)
|
||||
- All triggers and stored procedures
|
||||
- All data (INSERT statements)
|
||||
|
||||
**File:** `backup_trasabilitate_20251105_190632.sql`
|
||||
|
||||
---
|
||||
|
||||
### 🟢 Data-Only Backup (Data Only)
|
||||
|
||||
**Use when:**
|
||||
- ✅ Quick daily data snapshots
|
||||
- ✅ Both databases have identical structure
|
||||
- ✅ You want to load different data into existing database
|
||||
- ✅ Faster backups for large databases
|
||||
- ✅ Testing with production data
|
||||
|
||||
**Creates:**
|
||||
- Only INSERT statements for all tables
|
||||
- No schema, no triggers, no structure
|
||||
|
||||
**File:** `data_only_trasabilitate_20251105_190632.sql`
|
||||
|
||||
---
|
||||
|
||||
## Quick Command Reference
|
||||
|
||||
### Web Interface
|
||||
|
||||
**Location:** Settings → Database Backup Management
|
||||
|
||||
#### Create Backups:
|
||||
- **Full Backup:** Click `⚡ Full Backup (Schema + Data)` button
|
||||
- **Data-Only:** Click `📦 Data-Only Backup` button
|
||||
|
||||
#### Restore Database (Superadmin Only):
|
||||
1. Select backup file from dropdown
|
||||
2. Choose restore type:
|
||||
- **Full Restore:** Replace entire database
|
||||
- **Data-Only Restore:** Replace only data
|
||||
3. Click `🔄 Restore Database` button
|
||||
4. Confirm twice
|
||||
|
||||
---
|
||||
|
||||
## Backup Comparison
|
||||
|
||||
| Feature | Full Backup | Data-Only Backup |
|
||||
|---------|-------------|------------------|
|
||||
| **Speed** | Slower | ⚡ Faster (30-40% quicker) |
|
||||
| **File Size** | Larger | 📦 Smaller (~1-2 MB less) |
|
||||
| **Schema** | ✅ Yes | ❌ No |
|
||||
| **Triggers** | ✅ Yes | ❌ No |
|
||||
| **Data** | ✅ Yes | ✅ Yes |
|
||||
| **Use Case** | Complete recovery | Data refresh |
|
||||
| **Restore Requirement** | None | Schema must exist |
|
||||
|
||||
---
|
||||
|
||||
## Safety Features
|
||||
|
||||
### Full Restore
|
||||
- **Confirmation:** Type "RESTORE" in capital letters
|
||||
- **Effect:** Replaces EVERYTHING
|
||||
- **Warning:** All data, schema, triggers deleted
|
||||
|
||||
### Data-Only Restore
|
||||
- **Confirmation:** Type "RESTORE DATA" in capital letters
|
||||
- **Effect:** Replaces only data
|
||||
- **Warning:** All data deleted, schema preserved
|
||||
|
||||
### Smart Detection
|
||||
- System warns if you try to do full restore on data-only file
|
||||
- System warns if you try to do data-only restore on full file
|
||||
|
||||
---
|
||||
|
||||
## Common Scenarios
|
||||
|
||||
### Scenario 1: Daily Backups
|
||||
**Recommendation:**
|
||||
- Monday: Full backup (keeps everything)
|
||||
- Tuesday-Sunday: Data-only backups (faster, smaller)
|
||||
|
||||
### Scenario 2: Database Migration
|
||||
**Recommendation:**
|
||||
- Use full backup (safest, includes everything)
|
||||
|
||||
### Scenario 3: Load Test Data
|
||||
**Recommendation:**
|
||||
- Use data-only backup (preserve your test triggers)
|
||||
|
||||
### Scenario 4: Disaster Recovery
|
||||
**Recommendation:**
|
||||
- Use full backup (complete restoration)
|
||||
|
||||
### Scenario 5: Data Refresh
|
||||
**Recommendation:**
|
||||
- Use data-only backup (quick data swap)
|
||||
|
||||
---
|
||||
|
||||
## File Naming Convention
|
||||
|
||||
### Identify Backup Type by Filename:
|
||||
|
||||
```
|
||||
backup_trasabilitate_20251105_143022.sql
|
||||
└─┬─┘ └─────┬──────┘ └────┬─────┘
|
||||
│ │ └─ Timestamp
|
||||
│ └─ Database name
|
||||
└─ Full backup
|
||||
|
||||
data_only_trasabilitate_20251105_143022.sql
|
||||
└───┬───┘ └─────┬──────┘ └────┬─────┘
|
||||
│ │ └─ Timestamp
|
||||
│ └─ Database name
|
||||
└─ Data-only backup
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Table doesn't exist" during data-only restore
|
||||
**Solution:** Run full backup restore first, or use database setup script
|
||||
|
||||
### "Column count doesn't match" during data-only restore
|
||||
**Solution:** Schema has changed. Update schema or use newer backup
|
||||
|
||||
### "Foreign key constraint fails" during restore
|
||||
**Solution:** Database user needs SUPER privilege
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. ✅ Keep both types of backups
|
||||
2. ✅ Test restores in non-production first
|
||||
3. ✅ Schedule full backups weekly
|
||||
4. ✅ Schedule data-only backups daily
|
||||
5. ✅ Keep backups for 30+ days
|
||||
6. ✅ Store backups off-server for disaster recovery
|
||||
|
||||
---
|
||||
|
||||
## Access Requirements
|
||||
|
||||
| Action | Required Role |
|
||||
|--------|--------------|
|
||||
| Create Full Backup | Admin or Superadmin |
|
||||
| Create Data-Only Backup | Admin or Superadmin |
|
||||
| View Backup List | Admin or Superadmin |
|
||||
| Download Backup | Admin or Superadmin |
|
||||
| Delete Backup | Admin or Superadmin |
|
||||
| **Full Restore** | **Superadmin Only** |
|
||||
| **Data-Only Restore** | **Superadmin Only** |
|
||||
|
||||
---
|
||||
|
||||
## Quick Tips
|
||||
|
||||
💡 **Tip 1:** Data-only backups are 30-40% faster than full backups
|
||||
|
||||
💡 **Tip 2:** Use data-only restore to quickly swap between production and test data
|
||||
|
||||
💡 **Tip 3:** Always keep at least one full backup for disaster recovery
|
||||
|
||||
💡 **Tip 4:** Data-only backups are perfect for automated daily snapshots
|
||||
|
||||
💡 **Tip 5:** Test your restore process regularly (at least quarterly)
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
For detailed information, see:
|
||||
- [DATA_ONLY_BACKUP_FEATURE.md](DATA_ONLY_BACKUP_FEATURE.md) - Complete feature documentation
|
||||
- [BACKUP_SYSTEM.md](BACKUP_SYSTEM.md) - Overall backup system
|
||||
- [DATABASE_RESTORE_GUIDE.md](DATABASE_RESTORE_GUIDE.md) - Restore procedures
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** November 5, 2025
|
||||
**Application:** Quality Recticel - Trasabilitate System
|
||||
384
logs/access.log
384
logs/access.log
@@ -562,3 +562,387 @@
|
||||
192.168.0.132 - - [03/Nov/2025:22:26:31 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 10914 µs
|
||||
192.168.0.132 - - [03/Nov/2025:22:26:31 +0200] "GET /dashboard HTTP/1.1" 200 3827 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2747 µs
|
||||
192.168.0.132 - - [03/Nov/2025:22:26:39 +0200] "GET /daily_mirror/main HTTP/1.1" 200 10549 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 19051 µs
|
||||
192.168.0.132 - - [04/Nov/2025:06:12:27 +0200] "GET /dashboard HTTP/1.1" 302 189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2552 µs
|
||||
192.168.0.132 - - [04/Nov/2025:06:12:27 +0200] "GET / HTTP/1.1" 200 1688 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1793 µs
|
||||
192.168.0.132 - - [04/Nov/2025:06:12:27 +0200] "GET /static/script.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12521 µs
|
||||
192.168.0.132 - - [04/Nov/2025:06:12:27 +0200] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13089 µs
|
||||
192.168.0.132 - - [04/Nov/2025:06:12:27 +0200] "GET /static/logo_login.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2199 µs
|
||||
192.168.0.132 - - [04/Nov/2025:06:12:27 +0200] "GET /static/css/login.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 27914 µs
|
||||
192.168.0.132 - - [04/Nov/2025:06:12:27 +0200] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 29657 µs
|
||||
192.168.0.132 - - [04/Nov/2025:06:12:27 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 3554 µs
|
||||
192.168.0.132 - - [04/Nov/2025:06:12:38 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 7784 µs
|
||||
192.168.0.132 - - [04/Nov/2025:06:12:38 +0200] "GET /dashboard HTTP/1.1" 200 3824 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12172 µs
|
||||
192.168.0.132 - - [04/Nov/2025:06:12:38 +0200] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2468 µs
|
||||
192.168.0.132 - - [04/Nov/2025:06:12:44 +0200] "GET /main_scan HTTP/1.1" 200 2541 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 6905 µs
|
||||
192.168.0.132 - - [04/Nov/2025:06:12:51 +0200] "GET /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 32154 µs
|
||||
192.168.0.132 - - [04/Nov/2025:06:12:51 +0200] "GET /static/css/scan.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2334 µs
|
||||
192.168.0.132 - - [04/Nov/2025:08:17:10 +0200] "GET / HTTP/1.1" 200 1688 "-" "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; GPTBot/1.2; +https://openai.com/gptbot)" 8037 µs
|
||||
192.168.0.132 - - [04/Nov/2025:10:11:13 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 36277 µs
|
||||
192.168.0.132 - - [04/Nov/2025:10:24:49 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 96679 µs
|
||||
192.168.0.132 - - [04/Nov/2025:10:24:49 +0200] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 4372 µs
|
||||
192.168.0.132 - - [04/Nov/2025:10:24:49 +0200] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2399 µs
|
||||
192.168.0.132 - - [04/Nov/2025:10:24:49 +0200] "GET /static/css/scan.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12995 µs
|
||||
192.168.0.132 - - [04/Nov/2025:10:24:49 +0200] "GET /static/script.js HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2250 µs
|
||||
192.168.0.132 - - [04/Nov/2025:10:24:49 +0200] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2245 µs
|
||||
192.168.0.132 - - [04/Nov/2025:10:24:59 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 81440 µs
|
||||
192.168.0.132 - - [04/Nov/2025:10:29:12 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10461 µs
|
||||
192.168.0.132 - - [04/Nov/2025:10:30:58 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10179 µs
|
||||
192.168.0.132 - - [04/Nov/2025:10:40:16 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 97127 µs
|
||||
192.168.0.132 - - [04/Nov/2025:10:43:07 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10557 µs
|
||||
192.168.0.132 - - [04/Nov/2025:10:47:33 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10395 µs
|
||||
192.168.0.132 - - [04/Nov/2025:10:53:43 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10299 µs
|
||||
192.168.0.132 - - [04/Nov/2025:10:54:58 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11251 µs
|
||||
192.168.0.132 - - [04/Nov/2025:10:55:38 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10508 µs
|
||||
192.168.0.132 - - [04/Nov/2025:10:57:13 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10536 µs
|
||||
192.168.0.132 - - [04/Nov/2025:11:13:12 +0200] "GET /settings HTTP/1.1" 302 189 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 4080 µs
|
||||
192.168.0.132 - - [04/Nov/2025:11:13:12 +0200] "GET /static/logo_login.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 2934 µs
|
||||
192.168.0.132 - - [04/Nov/2025:11:13:13 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36" 1902 µs
|
||||
192.168.0.132 - - [04/Nov/2025:11:31:14 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 97379 µs
|
||||
192.168.0.132 - - [04/Nov/2025:11:33:24 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11081 µs
|
||||
192.168.0.132 - - [04/Nov/2025:11:36:11 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 18766 µs
|
||||
192.168.0.132 - - [04/Nov/2025:11:38:08 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10196 µs
|
||||
192.168.0.132 - - [04/Nov/2025:11:41:56 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10523 µs
|
||||
192.168.0.132 - - [04/Nov/2025:11:45:18 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10788 µs
|
||||
192.168.0.132 - - [04/Nov/2025:11:46:33 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10645 µs
|
||||
192.168.0.132 - - [04/Nov/2025:11:49:24 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11648 µs
|
||||
192.168.0.132 - - [04/Nov/2025:11:54:08 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10775 µs
|
||||
192.168.0.132 - - [04/Nov/2025:11:55:10 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11220 µs
|
||||
192.168.0.132 - - [04/Nov/2025:11:58:04 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10872 µs
|
||||
192.168.0.132 - - [04/Nov/2025:11:59:13 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10649 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:01:39 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 43968 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:06:24 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11119 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:07:17 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10803 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:11:06 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10989 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:12:12 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11055 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:15:45 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11223 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:16:27 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11165 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:19:28 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11037 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:20:27 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11242 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:24:23 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11183 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:25:30 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10992 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:27:58 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11038 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:28:54 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11052 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:29:44 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12022 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:31:58 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11132 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:37:27 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 85402 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:37:48 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11243 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:38:10 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11032 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:39:51 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11198 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:40:10 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11060 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:41:05 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11776 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:42:38 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11231 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:50:06 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12031 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:54:21 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11443 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:55:28 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12384 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:55:43 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11645 µs
|
||||
192.168.0.132 - - [04/Nov/2025:12:56:37 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11843 µs
|
||||
192.168.0.132 - - [04/Nov/2025:13:09:55 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 98595 µs
|
||||
192.168.0.132 - - [04/Nov/2025:13:10:22 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12092 µs
|
||||
192.168.0.132 - - [04/Nov/2025:13:18:31 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11799 µs
|
||||
192.168.0.132 - - [04/Nov/2025:13:20:27 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11399 µs
|
||||
192.168.0.132 - - [04/Nov/2025:13:20:45 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11761 µs
|
||||
192.168.0.132 - - [04/Nov/2025:13:24:01 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11861 µs
|
||||
192.168.0.132 - - [04/Nov/2025:13:25:34 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11555 µs
|
||||
192.168.0.132 - - [04/Nov/2025:13:28:34 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11571 µs
|
||||
192.168.0.132 - - [04/Nov/2025:13:29:04 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12073 µs
|
||||
192.168.0.132 - - [04/Nov/2025:13:32:48 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11914 µs
|
||||
192.168.0.132 - - [04/Nov/2025:13:33:12 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11785 µs
|
||||
192.168.0.132 - - [04/Nov/2025:13:35:40 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11011 µs
|
||||
192.168.0.132 - - [04/Nov/2025:13:37:16 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11617 µs
|
||||
192.168.0.132 - - [04/Nov/2025:13:39:18 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11635 µs
|
||||
192.168.0.132 - - [04/Nov/2025:13:42:19 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11537 µs
|
||||
192.168.0.132 - - [04/Nov/2025:13:45:56 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12128 µs
|
||||
192.168.0.132 - - [04/Nov/2025:13:48:41 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12132 µs
|
||||
192.168.0.132 - - [04/Nov/2025:13:49:27 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13105 µs
|
||||
192.168.0.132 - - [04/Nov/2025:13:52:19 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12213 µs
|
||||
192.168.0.132 - - [04/Nov/2025:13:53:59 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11880 µs
|
||||
192.168.0.132 - - [04/Nov/2025:13:55:31 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12119 µs
|
||||
192.168.0.132 - - [04/Nov/2025:13:57:46 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13438 µs
|
||||
192.168.0.132 - - [04/Nov/2025:13:58:34 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12358 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:01:25 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12135 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:01:38 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11941 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:03:51 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12200 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:06:27 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12389 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:07:56 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12268 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:10:44 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12096 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:13:39 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12144 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:14:03 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12321 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:17:03 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12181 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:18:12 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12379 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:21:07 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12576 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:21:54 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12409 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:24:09 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12335 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:25:09 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12331 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:25:09 +0200] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 3034 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:25:09 +0200] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 14353 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:25:09 +0200] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 4089 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:25:09 +0200] "GET /static/script.js HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2855 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:25:09 +0200] "GET /static/css/scan.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 17085 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:25:39 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12740 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:28:19 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12679 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:42:45 +0200] "GET /dashboard HTTP/1.1" 200 3824 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 3321 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:42:57 +0200] "GET /main_scan HTTP/1.1" 200 2541 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2918 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:42:59 +0200] "GET /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 7358 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:52:18 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13308 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:53:04 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12626 µs
|
||||
192.168.0.132 - - [04/Nov/2025:14:59:42 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12884 µs
|
||||
192.168.0.132 - - [04/Nov/2025:15:02:41 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12571 µs
|
||||
192.168.0.132 - - [04/Nov/2025:15:07:17 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12571 µs
|
||||
192.168.0.132 - - [04/Nov/2025:15:07:53 +0200] "GET /dashboard HTTP/1.1" 302 189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1540 µs
|
||||
192.168.0.132 - - [04/Nov/2025:15:07:53 +0200] "GET / HTTP/1.1" 200 1688 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 8340 µs
|
||||
192.168.0.132 - - [04/Nov/2025:15:07:54 +0200] "GET /static/logo_login.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1911 µs
|
||||
192.168.0.132 - - [04/Nov/2025:15:07:54 +0200] "GET /static/css/login.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13034 µs
|
||||
192.168.0.132 - - [04/Nov/2025:15:07:54 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1401 µs
|
||||
192.168.0.132 - - [04/Nov/2025:15:07:55 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 5894 µs
|
||||
192.168.0.132 - - [04/Nov/2025:15:07:55 +0200] "GET /dashboard HTTP/1.1" 200 3824 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12102 µs
|
||||
192.168.0.132 - - [04/Nov/2025:15:07:57 +0200] "GET /main_scan HTTP/1.1" 200 2541 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 6823 µs
|
||||
192.168.0.132 - - [04/Nov/2025:15:07:58 +0200] "GET /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 6065 µs
|
||||
192.168.0.132 - - [04/Nov/2025:15:09:16 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 9931 µs
|
||||
192.168.0.132 - - [04/Nov/2025:15:12:27 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 9915 µs
|
||||
192.168.0.132 - - [04/Nov/2025:15:15:05 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 9980 µs
|
||||
192.168.0.132 - - [04/Nov/2025:15:17:13 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10359 µs
|
||||
192.168.0.132 - - [04/Nov/2025:15:20:08 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10383 µs
|
||||
192.168.0.132 - - [04/Nov/2025:15:23:31 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10485 µs
|
||||
192.168.0.132 - - [04/Nov/2025:15:25:41 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10658 µs
|
||||
192.168.0.132 - - [04/Nov/2025:18:17:39 +0200] "GET /dashboard HTTP/1.1" 200 3824 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12281 µs
|
||||
192.168.0.132 - - [04/Nov/2025:18:17:40 +0200] "GET /main_scan HTTP/1.1" 200 2541 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 6888 µs
|
||||
192.168.0.132 - - [04/Nov/2025:18:17:41 +0200] "GET /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 6239 µs
|
||||
192.168.0.132 - - [04/Nov/2025:18:22:51 +0200] "GET / HTTP/1.1" 200 1688 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36" 8353 µs
|
||||
192.168.0.132 - - [04/Nov/2025:22:42:22 +0200] "GET / HTTP/1.1" 200 1688 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:135.0) Gecko/20100101 Firefox/135.0" 8466 µs
|
||||
192.168.0.132 - - [05/Nov/2025:06:15:49 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10266 µs
|
||||
192.168.0.132 - - [05/Nov/2025:06:15:49 +0200] "GET /static/css/scan.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2380 µs
|
||||
192.168.0.132 - - [05/Nov/2025:06:15:49 +0200] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2430 µs
|
||||
192.168.0.132 - - [05/Nov/2025:06:15:49 +0200] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2392 µs
|
||||
192.168.0.132 - - [05/Nov/2025:06:15:49 +0200] "GET /static/script.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2796 µs
|
||||
192.168.0.132 - - [05/Nov/2025:06:15:49 +0200] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2207 µs
|
||||
192.168.0.132 - - [05/Nov/2025:06:16:00 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10064 µs
|
||||
192.168.0.132 - - [05/Nov/2025:06:18:06 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10807 µs
|
||||
192.168.0.132 - - [05/Nov/2025:06:18:18 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10370 µs
|
||||
192.168.0.132 - - [05/Nov/2025:06:21:32 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10262 µs
|
||||
192.168.0.132 - - [05/Nov/2025:06:23:07 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10698 µs
|
||||
192.168.0.132 - - [05/Nov/2025:06:26:11 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 9958 µs
|
||||
192.168.0.132 - - [05/Nov/2025:06:26:20 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10253 µs
|
||||
192.168.0.132 - - [05/Nov/2025:06:29:42 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10375 µs
|
||||
192.168.0.132 - - [05/Nov/2025:06:31:40 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10867 µs
|
||||
192.168.0.132 - - [05/Nov/2025:06:33:55 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10314 µs
|
||||
192.168.0.132 - - [05/Nov/2025:06:34:39 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10138 µs
|
||||
192.168.0.132 - - [05/Nov/2025:06:38:14 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10344 µs
|
||||
192.168.0.132 - - [05/Nov/2025:06:38:55 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10497 µs
|
||||
192.168.0.132 - - [05/Nov/2025:06:42:20 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10373 µs
|
||||
192.168.0.132 - - [05/Nov/2025:06:44:07 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10370 µs
|
||||
192.168.0.132 - - [05/Nov/2025:06:49:33 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10381 µs
|
||||
192.168.0.132 - - [05/Nov/2025:06:54:16 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10430 µs
|
||||
192.168.0.132 - - [05/Nov/2025:06:56:11 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10468 µs
|
||||
192.168.0.132 - - [05/Nov/2025:06:57:08 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10246 µs
|
||||
192.168.0.132 - - [05/Nov/2025:07:01:41 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11103 µs
|
||||
192.168.0.132 - - [05/Nov/2025:07:07:08 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10526 µs
|
||||
192.168.0.132 - - [05/Nov/2025:07:33:29 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10606 µs
|
||||
192.168.0.132 - - [05/Nov/2025:07:36:49 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11354 µs
|
||||
192.168.0.132 - - [05/Nov/2025:07:37:22 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10803 µs
|
||||
192.168.0.132 - - [05/Nov/2025:07:39:23 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11539 µs
|
||||
192.168.0.132 - - [05/Nov/2025:07:42:46 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10692 µs
|
||||
192.168.0.132 - - [05/Nov/2025:07:49:38 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10719 µs
|
||||
192.168.0.132 - - [05/Nov/2025:07:54:47 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10949 µs
|
||||
192.168.0.132 - - [05/Nov/2025:08:15:49 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10790 µs
|
||||
192.168.0.132 - - [05/Nov/2025:08:22:59 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11007 µs
|
||||
192.168.0.132 - - [05/Nov/2025:08:26:46 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10815 µs
|
||||
192.168.0.132 - - [05/Nov/2025:08:31:57 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10889 µs
|
||||
192.168.0.132 - - [05/Nov/2025:08:33:31 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10856 µs
|
||||
192.168.0.132 - - [05/Nov/2025:08:35:55 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11053 µs
|
||||
192.168.0.132 - - [05/Nov/2025:08:38:16 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11145 µs
|
||||
192.168.0.132 - - [05/Nov/2025:08:44:34 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12227 µs
|
||||
192.168.0.132 - - [05/Nov/2025:08:44:44 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13457 µs
|
||||
192.168.0.132 - - [05/Nov/2025:08:48:37 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10946 µs
|
||||
192.168.0.132 - - [05/Nov/2025:08:48:59 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10971 µs
|
||||
192.168.0.132 - - [05/Nov/2025:08:49:07 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10901 µs
|
||||
192.168.0.132 - - [05/Nov/2025:08:54:12 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12157 µs
|
||||
192.168.0.132 - - [05/Nov/2025:08:55:49 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11197 µs
|
||||
192.168.0.132 - - [05/Nov/2025:08:56:15 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11034 µs
|
||||
192.168.0.132 - - [05/Nov/2025:08:57:04 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11223 µs
|
||||
192.168.0.132 - - [05/Nov/2025:08:57:30 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12009 µs
|
||||
192.168.0.132 - - [05/Nov/2025:08:58:19 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11295 µs
|
||||
192.168.0.132 - - [05/Nov/2025:08:59:10 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11143 µs
|
||||
192.168.0.132 - - [05/Nov/2025:08:59:36 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10915 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:02:45 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11225 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:02:52 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11339 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:03:51 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11466 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:05:17 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11510 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:06:26 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11335 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:07:15 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11652 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:09:09 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11600 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:10:03 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10592 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:11:46 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11556 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:14:15 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11300 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:16:55 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11749 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:18:39 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11453 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:19:55 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11605 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:21:55 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12340 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:22:59 +0200] "GET /quality HTTP/1.1" 302 189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1897 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:22:59 +0200] "GET / HTTP/1.1" 200 1688 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2013 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:22:59 +0200] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2229 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:22:59 +0200] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2053 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:22:59 +0200] "GET /static/script.js HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2329 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:22:59 +0200] "GET /static/css/login.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2515 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:22:59 +0200] "GET /static/logo_login.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2286 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:23:00 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2448 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:23:01 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 5693 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:23:01 +0200] "GET /dashboard HTTP/1.1" 200 3824 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2516 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:23:01 +0200] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2279 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:23:03 +0200] "GET /reports HTTP/1.1" 200 3385 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 8042 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:23:04 +0200] "GET /fg_quality HTTP/1.1" 200 22312 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 21834 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:23:04 +0200] "GET /static/fg_quality.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2786 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:23:07 +0200] "GET /get_fg_report_data?report=5 HTTP/1.1" 200 7888 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10662 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:23:51 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11192 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:26:02 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12405 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:26:27 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11522 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:30:21 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11807 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:31:14 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10808 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:34:55 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11048 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:35:44 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11667 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:37:08 +0200] "GET / HTTP/1.1" 200 1688 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36" 8444 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:37:14 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12072 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:40:15 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12585 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:43:30 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11999 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:45:45 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12001 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:48:58 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11981 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:49:32 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11773 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:49:47 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12106 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:54:41 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11949 µs
|
||||
192.168.0.132 - - [05/Nov/2025:09:58:37 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11818 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:01:37 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12946 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:01:41 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11945 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:06:45 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12374 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:07:55 +0200] "GET / HTTP/1.1" 200 1688 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1723 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:07:55 +0200] "GET /static/logo_login.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 5440 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:07:55 +0200] "GET /static/style.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1954 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:07:55 +0200] "GET /static/css/base.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1864 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:07:55 +0200] "GET /static/css/login.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1856 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:07:55 +0200] "GET /static/script.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2414 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:07:56 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2048 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:07:59 +0200] "POST / HTTP/1.1" 200 1688 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 5989 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:08:14 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 6064 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:08:14 +0200] "GET /dashboard HTTP/1.1" 200 3827 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2527 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:08:14 +0200] "GET /static/scan_me.jpg HTTP/1.1" 200 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 21135 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:08:20 +0200] "GET /reports HTTP/1.1" 200 3388 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 8000 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:08:24 +0200] "GET /fg_quality HTTP/1.1" 200 22444 "https://quality.moto-adv.com/reports" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 21628 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:08:24 +0200] "GET /static/fg_quality.js HTTP/1.1" 200 0 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2751 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:08:29 +0200] "GET /get_fg_report_data?report=5 HTTP/1.1" 200 7888 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10600 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:08:46 +0200] "GET /test_fg_database HTTP/1.1" 200 1559 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 7875 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:08:52 +0200] "GET /dashboard HTTP/1.1" 200 3827 "https://quality.moto-adv.com/fg_quality" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2468 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:08:54 +0200] "GET /main_scan HTTP/1.1" 200 2544 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 6972 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:08:55 +0200] "GET /fg_scan HTTP/1.1" 200 32839 "https://quality.moto-adv.com/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 6099 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:08:56 +0200] "GET /static/css/scan.css HTTP/1.1" 200 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2494 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:08:57 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11870 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:10:23 +0200] "POST /fg_scan HTTP/1.1" 200 32839 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10433 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:10:37 +0200] "POST /fg_scan HTTP/1.1" 200 32839 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10783 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:10:42 +0200] "POST /fg_scan HTTP/1.1" 200 32839 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10265 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:11:14 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12510 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:11:43 +0200] "POST /fg_scan HTTP/1.1" 200 32839 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 10060 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:12:47 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12557 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:13:56 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12243 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:14:21 +0200] "GET / HTTP/1.1" 200 1688 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2150 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:14:23 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 5633 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:14:23 +0200] "GET /dashboard HTTP/1.1" 200 3827 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2458 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:14:25 +0200] "GET /settings HTTP/1.1" 200 34325 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 47236 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:14:25 +0200] "GET /api/backup/schedule HTTP/1.1" 200 100 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2740 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:14:25 +0200] "GET /api/backup/list HTTP/1.1" 200 195 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 11161 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:14:41 +0200] "POST /api/backup/create HTTP/1.1" 200 238 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 229606 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:14:44 +0200] "GET /api/backup/list HTTP/1.1" 200 345 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2653 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:14:48 +0200] "GET /api/backup/download/backup_trasabilitate_20251105_101441.sql HTTP/1.1" 200 0 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 6717 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:18:25 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12437 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:18:25 +0200] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 3140 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:18:25 +0200] "GET /static/script.js HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 3014 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:18:25 +0200] "GET /static/css/scan.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2829 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:18:25 +0200] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 3232 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:18:25 +0200] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 18745 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:18:38 +0200] "POST /api/backup/schedule HTTP/1.1" 200 64 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 3294 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:19:31 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12328 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:21:37 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12354 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:22:54 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12761 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:29:01 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12785 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:32:08 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12757 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:33:47 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13501 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:35:05 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12562 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:38:07 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12650 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:38:34 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12547 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:39:13 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12630 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:43:19 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12557 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:44:16 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12781 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:47:12 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12842 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:50:40 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12916 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:51:01 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13598 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:52:57 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12670 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:55:23 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12861 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:55:42 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12950 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:58:50 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12942 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:59:27 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 13809 µs
|
||||
192.168.0.132 - - [05/Nov/2025:10:59:38 +0200] "POST /fg_scan HTTP/1.1" 200 32836 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 12838 µs
|
||||
192.168.0.132 - - [05/Nov/2025:12:30:11 +0200] "GET /dashboard HTTP/1.1" 302 189 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1454 µs
|
||||
192.168.0.132 - - [05/Nov/2025:12:30:11 +0200] "GET / HTTP/1.1" 200 1688 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1669 µs
|
||||
192.168.0.132 - - [05/Nov/2025:12:30:11 +0200] "GET /static/css/login.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1935 µs
|
||||
192.168.0.132 - - [05/Nov/2025:12:30:11 +0200] "GET /static/logo_login.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 1978 µs
|
||||
192.168.0.132 - - [05/Nov/2025:12:30:11 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" 2065 µs
|
||||
192.168.0.132 - - [05/Nov/2025:13:59:21 +0200] "GET /.env HTTP/1.1" 404 207 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.3" 2030 µs
|
||||
192.168.0.132 - - [05/Nov/2025:18:19:01 +0200] "GET /dashboard HTTP/1.1" 302 189 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 16940 µs
|
||||
192.168.0.132 - - [05/Nov/2025:18:19:02 +0200] "GET / HTTP/1.1" 200 1688 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 61971 µs
|
||||
192.168.0.132 - - [05/Nov/2025:18:19:02 +0200] "GET /favicon.ico HTTP/1.1" 404 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2850 µs
|
||||
192.168.0.132 - - [05/Nov/2025:18:19:10 +0200] "POST / HTTP/1.1" 302 207 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 11767 µs
|
||||
192.168.0.132 - - [05/Nov/2025:18:19:10 +0200] "GET /dashboard HTTP/1.1" 200 3827 "https://quality.moto-adv.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 12538 µs
|
||||
192.168.0.132 - - [05/Nov/2025:18:19:10 +0200] "GET /static/css/base.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 13285 µs
|
||||
192.168.0.132 - - [05/Nov/2025:18:19:10 +0200] "GET /static/style.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 30006 µs
|
||||
192.168.0.132 - - [05/Nov/2025:18:19:10 +0200] "GET /static/script.js HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 30188 µs
|
||||
192.168.0.132 - - [05/Nov/2025:18:19:10 +0200] "GET /static/scan_me.jpg HTTP/1.1" 304 0 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 30252 µs
|
||||
192.168.0.132 - - [05/Nov/2025:18:19:13 +0200] "GET /main_scan HTTP/1.1" 200 2544 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 48222 µs
|
||||
192.168.0.132 - - [05/Nov/2025:18:19:15 +0200] "GET /fg_scan HTTP/1.1" 200 32839 "https://quality.moto-adv.com/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 32890 µs
|
||||
192.168.0.132 - - [05/Nov/2025:18:19:15 +0200] "GET /static/css/scan.css HTTP/1.1" 304 0 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2467 µs
|
||||
192.168.0.132 - - [05/Nov/2025:18:20:16 +0200] "POST /fg_scan HTTP/1.1" 200 32839 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 9755 µs
|
||||
192.168.0.132 - - [05/Nov/2025:18:20:25 +0200] "POST /fg_scan HTTP/1.1" 200 32839 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 81428 µs
|
||||
192.168.0.132 - - [05/Nov/2025:19:04:10 +0200] "POST /fg_scan HTTP/1.1" 200 32840 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 100484 µs
|
||||
192.168.0.132 - - [05/Nov/2025:19:04:31 +0200] "GET /dashboard HTTP/1.1" 200 3827 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 12610 µs
|
||||
192.168.0.132 - - [05/Nov/2025:19:04:34 +0200] "GET /settings HTTP/1.1" 200 40104 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 48813 µs
|
||||
192.168.0.132 - - [05/Nov/2025:19:04:34 +0200] "GET /api/backup/list HTTP/1.1" 200 345 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 27909 µs
|
||||
192.168.0.132 - - [05/Nov/2025:19:04:34 +0200] "GET /api/backup/schedule HTTP/1.1" 200 100 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 49313 µs
|
||||
192.168.0.132 - - [05/Nov/2025:19:04:46 +0200] "DELETE /api/backup/delete/backup_trasabilitate_20251103_212929_20251103_215909.sql HTTP/1.1" 200 114 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 28996 µs
|
||||
192.168.0.132 - - [05/Nov/2025:19:04:47 +0200] "GET /api/backup/list HTTP/1.1" 200 179 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 3272 µs
|
||||
192.168.0.132 - - [05/Nov/2025:19:04:50 +0200] "DELETE /api/backup/delete/backup_trasabilitate_20251105_101441.sql HTTP/1.1" 200 98 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 3450 µs
|
||||
192.168.0.132 - - [05/Nov/2025:19:04:51 +0200] "GET /api/backup/list HTTP/1.1" 200 30 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 5292 µs
|
||||
192.168.0.132 - - [05/Nov/2025:20:29:50 +0200] "GET /settings HTTP/1.1" 200 40104 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 89618 µs
|
||||
192.168.0.132 - - [05/Nov/2025:20:29:50 +0200] "GET /api/backup/list HTTP/1.1" 200 30 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2552 µs
|
||||
192.168.0.132 - - [05/Nov/2025:20:29:50 +0200] "GET /api/backup/schedule HTTP/1.1" 200 100 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2693 µs
|
||||
192.168.0.132 - - [05/Nov/2025:20:30:05 +0200] "POST /api/backup/create-data-only HTTP/1.1" 200 254 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 174664 µs
|
||||
192.168.0.132 - - [05/Nov/2025:20:30:08 +0200] "GET /api/backup/list HTTP/1.1" 200 182 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 27617 µs
|
||||
192.168.0.132 - - [05/Nov/2025:20:30:32 +0200] "GET /api/backup/list HTTP/1.1" 200 182 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 3214 µs
|
||||
192.168.0.132 - - [05/Nov/2025:20:30:33 +0200] "GET /api/backup/list HTTP/1.1" 200 182 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2700 µs
|
||||
127.0.0.1 - - [05/Nov/2025:20:34:42 +0200] "GET /api/backup/schedule HTTP/1.1" 302 189 "-" "curl/8.14.1" 18027 µs
|
||||
192.168.0.132 - - [05/Nov/2025:20:35:00 +0200] "GET /settings HTTP/1.1" 200 42008 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 108583 µs
|
||||
192.168.0.132 - - [05/Nov/2025:20:35:00 +0200] "GET /api/backup/list HTTP/1.1" 200 182 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 45694 µs
|
||||
192.168.0.132 - - [05/Nov/2025:20:35:00 +0200] "GET /api/backup/schedule HTTP/1.1" 200 121 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 46015 µs
|
||||
192.168.0.132 - - [05/Nov/2025:20:35:23 +0200] "POST /api/backup/schedule HTTP/1.1" 200 64 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 4267 µs
|
||||
192.168.0.132 - - [05/Nov/2025:20:35:37 +0200] "DELETE /api/backup/delete/data_only_trasabilitate_20251105_203005.sql HTTP/1.1" 200 101 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 3789 µs
|
||||
192.168.0.132 - - [05/Nov/2025:20:35:38 +0200] "GET /api/backup/list HTTP/1.1" 200 30 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2584 µs
|
||||
192.168.0.132 - - [05/Nov/2025:20:45:58 +0200] "GET /settings HTTP/1.1" 200 43080 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 111345 µs
|
||||
192.168.0.132 - - [05/Nov/2025:20:45:58 +0200] "GET /api/backup/schedule HTTP/1.1" 200 164 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 4862 µs
|
||||
192.168.0.132 - - [05/Nov/2025:20:45:58 +0200] "GET /api/backup/list HTTP/1.1" 200 30 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 19334 µs
|
||||
192.168.0.132 - - [05/Nov/2025:20:46:24 +0200] "GET /settings HTTP/1.1" 200 43080 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 95425 µs
|
||||
192.168.0.132 - - [05/Nov/2025:20:46:24 +0200] "GET /api/backup/list HTTP/1.1" 200 30 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2623 µs
|
||||
192.168.0.132 - - [05/Nov/2025:20:46:24 +0200] "GET /api/backup/schedule HTTP/1.1" 200 164 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 20670 µs
|
||||
192.168.0.132 - - [05/Nov/2025:21:08:15 +0200] "GET /settings HTTP/1.1" 200 68254 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 127920 µs
|
||||
192.168.0.132 - - [05/Nov/2025:21:08:15 +0200] "GET /api/backup/list HTTP/1.1" 200 30 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 19369 µs
|
||||
192.168.0.132 - - [05/Nov/2025:21:08:15 +0200] "GET /api/backup/schedule HTTP/1.1" 200 164 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 20410 µs
|
||||
192.168.0.132 - - [05/Nov/2025:21:09:39 +0200] "GET /settings HTTP/1.1" 200 68254 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 127408 µs
|
||||
192.168.0.132 - - [05/Nov/2025:21:09:40 +0200] "GET /api/backup/list HTTP/1.1" 200 30 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 3033 µs
|
||||
192.168.0.132 - - [05/Nov/2025:21:09:40 +0200] "GET /api/backup/schedule HTTP/1.1" 200 164 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 4782 µs
|
||||
192.168.0.132 - - [05/Nov/2025:21:10:03 +0200] "POST /api/backup/create HTTP/1.1" 200 238 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 227736 µs
|
||||
192.168.0.132 - - [05/Nov/2025:21:10:07 +0200] "GET /api/backup/list HTTP/1.1" 200 178 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2625 µs
|
||||
192.168.0.132 - - [05/Nov/2025:21:10:20 +0200] "DELETE /api/backup/delete/backup_trasabilitate_20251105_211003.sql HTTP/1.1" 200 98 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 3783 µs
|
||||
192.168.0.132 - - [05/Nov/2025:21:10:22 +0200] "GET /api/backup/list HTTP/1.1" 200 30 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2479 µs
|
||||
192.168.0.132 - - [05/Nov/2025:21:10:25 +0200] "GET /api/backup/list HTTP/1.1" 200 30 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2495 µs
|
||||
192.168.0.132 - - [05/Nov/2025:21:19:35 +0200] "GET /settings HTTP/1.1" 200 72985 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 131211 µs
|
||||
192.168.0.132 - - [05/Nov/2025:21:19:35 +0200] "GET /api/backup/list HTTP/1.1" 200 30 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 3707 µs
|
||||
192.168.0.132 - - [05/Nov/2025:21:19:35 +0200] "GET /api/backup/schedule HTTP/1.1" 200 283 "https://quality.moto-adv.com/settings" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 21446 µs
|
||||
192.168.0.132 - - [05/Nov/2025:21:22:15 +0200] "GET /main_scan HTTP/1.1" 200 2544 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 46701 µs
|
||||
192.168.0.132 - - [05/Nov/2025:21:22:17 +0200] "GET /fg_scan HTTP/1.1" 200 32840 "https://quality.moto-adv.com/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 34947 µs
|
||||
192.168.0.132 - - [05/Nov/2025:21:22:39 +0200] "GET /dashboard HTTP/1.1" 200 3827 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 12213 µs
|
||||
192.168.0.132 - - [05/Nov/2025:21:22:44 +0200] "GET /main_scan HTTP/1.1" 200 2544 "https://quality.moto-adv.com/dashboard" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 2394 µs
|
||||
192.168.0.132 - - [05/Nov/2025:21:23:03 +0200] "GET /fg_scan HTTP/1.1" 200 32840 "https://quality.moto-adv.com/main_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 6396 µs
|
||||
192.168.0.132 - - [05/Nov/2025:21:23:24 +0200] "POST /fg_scan HTTP/1.1" 200 32844 "https://quality.moto-adv.com/fg_scan" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36" 16430 µs
|
||||
|
||||
1011
logs/error.log
1011
logs/error.log
File diff suppressed because one or more lines are too long
@@ -19,5 +19,10 @@ def create_app():
|
||||
|
||||
# Add 'now' function to Jinja2 globals
|
||||
app.jinja_env.globals['now'] = datetime.now
|
||||
|
||||
# Initialize automatic backup scheduler
|
||||
from app.backup_scheduler import init_backup_scheduler
|
||||
init_backup_scheduler(app)
|
||||
print("✅ Automatic backup scheduler initialized")
|
||||
|
||||
return app
|
||||
296
py_app/app/backup_scheduler.py
Normal file
296
py_app/app/backup_scheduler.py
Normal file
@@ -0,0 +1,296 @@
|
||||
"""
|
||||
Automated Backup Scheduler
|
||||
Quality Recticel Application
|
||||
|
||||
This module manages automatic backup execution based on the configured schedule.
|
||||
Uses APScheduler to run backups at specified times.
|
||||
"""
|
||||
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
from datetime import datetime
|
||||
import logging
|
||||
|
||||
# Configure logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BackupScheduler:
|
||||
"""Manages automatic backup scheduling"""
|
||||
|
||||
def __init__(self, app=None):
|
||||
"""
|
||||
Initialize the backup scheduler
|
||||
|
||||
Args:
|
||||
app: Flask application instance
|
||||
"""
|
||||
self.scheduler = None
|
||||
self.app = app
|
||||
self.job_prefix = 'scheduled_backup'
|
||||
|
||||
if app is not None:
|
||||
self.init_app(app)
|
||||
|
||||
def init_app(self, app):
|
||||
"""
|
||||
Initialize scheduler with Flask app context
|
||||
|
||||
Args:
|
||||
app: Flask application instance
|
||||
"""
|
||||
self.app = app
|
||||
|
||||
# Create scheduler
|
||||
self.scheduler = BackgroundScheduler(
|
||||
daemon=True,
|
||||
timezone='Europe/Bucharest' # Adjust to your timezone
|
||||
)
|
||||
|
||||
# Load and apply schedule from configuration
|
||||
self.update_schedule()
|
||||
|
||||
# Start scheduler
|
||||
self.scheduler.start()
|
||||
logger.info("Backup scheduler started")
|
||||
|
||||
# Register shutdown handler
|
||||
import atexit
|
||||
atexit.register(lambda: self.scheduler.shutdown())
|
||||
|
||||
def execute_scheduled_backup(self, schedule_id, backup_type):
|
||||
"""
|
||||
Execute a backup based on the schedule configuration
|
||||
This method runs in the scheduler thread
|
||||
|
||||
Args:
|
||||
schedule_id: Identifier for the schedule
|
||||
backup_type: Type of backup ('full' or 'data-only')
|
||||
"""
|
||||
try:
|
||||
from app.database_backup import DatabaseBackupManager
|
||||
|
||||
with self.app.app_context():
|
||||
backup_manager = DatabaseBackupManager()
|
||||
|
||||
logger.info(f"Starting scheduled {backup_type} backup (schedule: {schedule_id})...")
|
||||
|
||||
# Execute appropriate backup
|
||||
if backup_type == 'data-only':
|
||||
result = backup_manager.create_data_only_backup(backup_name='scheduled')
|
||||
else:
|
||||
result = backup_manager.create_backup(backup_name='scheduled')
|
||||
|
||||
if result['success']:
|
||||
logger.info(f"✅ Scheduled backup completed: {result['filename']} ({result['size']})")
|
||||
|
||||
# Clean up old backups based on retention policy
|
||||
schedule = backup_manager.get_backup_schedule()
|
||||
schedules = schedule.get('schedules', []) if isinstance(schedule, dict) and 'schedules' in schedule else []
|
||||
|
||||
# Find the schedule that triggered this backup
|
||||
current_schedule = next((s for s in schedules if s.get('id') == schedule_id), None)
|
||||
if current_schedule:
|
||||
retention_days = current_schedule.get('retention_days', 30)
|
||||
cleanup_result = backup_manager.cleanup_old_backups(retention_days)
|
||||
|
||||
if cleanup_result['success'] and cleanup_result['deleted_count'] > 0:
|
||||
logger.info(f"🗑️ Cleaned up {cleanup_result['deleted_count']} old backup(s)")
|
||||
else:
|
||||
logger.error(f"❌ Scheduled backup failed: {result['message']}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error during scheduled backup: {e}", exc_info=True)
|
||||
|
||||
def update_schedule(self):
|
||||
"""
|
||||
Reload schedule from configuration and update scheduler jobs
|
||||
Supports multiple schedules
|
||||
"""
|
||||
try:
|
||||
from app.database_backup import DatabaseBackupManager
|
||||
|
||||
with self.app.app_context():
|
||||
backup_manager = DatabaseBackupManager()
|
||||
schedule_config = backup_manager.get_backup_schedule()
|
||||
|
||||
# Remove all existing backup jobs
|
||||
for job in self.scheduler.get_jobs():
|
||||
if job.id.startswith(self.job_prefix):
|
||||
self.scheduler.remove_job(job.id)
|
||||
|
||||
# Handle new multi-schedule format
|
||||
if isinstance(schedule_config, dict) and 'schedules' in schedule_config:
|
||||
schedules = schedule_config['schedules']
|
||||
|
||||
for schedule in schedules:
|
||||
if not schedule.get('enabled', False):
|
||||
continue
|
||||
|
||||
schedule_id = schedule.get('id', 'default')
|
||||
time_str = schedule.get('time', '02:00')
|
||||
frequency = schedule.get('frequency', 'daily')
|
||||
backup_type = schedule.get('backup_type', 'full')
|
||||
|
||||
# Parse time
|
||||
hour, minute = map(int, time_str.split(':'))
|
||||
|
||||
# Create appropriate trigger
|
||||
if frequency == 'daily':
|
||||
trigger = CronTrigger(hour=hour, minute=minute)
|
||||
elif frequency == 'weekly':
|
||||
trigger = CronTrigger(day_of_week='sun', hour=hour, minute=minute)
|
||||
elif frequency == 'monthly':
|
||||
trigger = CronTrigger(day=1, hour=hour, minute=minute)
|
||||
else:
|
||||
logger.error(f"Unknown frequency: {frequency}")
|
||||
continue
|
||||
|
||||
# Add job with unique ID
|
||||
job_id = f"{self.job_prefix}_{schedule_id}"
|
||||
self.scheduler.add_job(
|
||||
func=self.execute_scheduled_backup,
|
||||
trigger=trigger,
|
||||
args=[schedule_id, backup_type],
|
||||
id=job_id,
|
||||
name=f'Scheduled {backup_type} backup ({schedule_id})',
|
||||
replace_existing=True
|
||||
)
|
||||
|
||||
logger.info(f"✅ Schedule '{schedule_id}': {backup_type} backup {frequency} at {time_str}")
|
||||
|
||||
# Handle legacy single-schedule format (backward compatibility)
|
||||
elif isinstance(schedule_config, dict) and schedule_config.get('enabled', False):
|
||||
time_str = schedule_config.get('time', '02:00')
|
||||
frequency = schedule_config.get('frequency', 'daily')
|
||||
backup_type = schedule_config.get('backup_type', 'full')
|
||||
|
||||
hour, minute = map(int, time_str.split(':'))
|
||||
|
||||
if frequency == 'daily':
|
||||
trigger = CronTrigger(hour=hour, minute=minute)
|
||||
elif frequency == 'weekly':
|
||||
trigger = CronTrigger(day_of_week='sun', hour=hour, minute=minute)
|
||||
elif frequency == 'monthly':
|
||||
trigger = CronTrigger(day=1, hour=hour, minute=minute)
|
||||
else:
|
||||
logger.error(f"Unknown frequency: {frequency}")
|
||||
return
|
||||
|
||||
job_id = f"{self.job_prefix}_default"
|
||||
self.scheduler.add_job(
|
||||
func=self.execute_scheduled_backup,
|
||||
trigger=trigger,
|
||||
args=['default', backup_type],
|
||||
id=job_id,
|
||||
name=f'Scheduled {backup_type} backup',
|
||||
replace_existing=True
|
||||
)
|
||||
|
||||
logger.info(f"✅ Backup schedule configured: {backup_type} backup {frequency} at {time_str}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error updating backup schedule: {e}", exc_info=True)
|
||||
|
||||
def get_next_run_time(self, schedule_id='default'):
|
||||
"""
|
||||
Get the next scheduled run time for a specific schedule
|
||||
|
||||
Args:
|
||||
schedule_id: Identifier for the schedule
|
||||
|
||||
Returns:
|
||||
datetime or None: Next run time if job exists
|
||||
"""
|
||||
if not self.scheduler:
|
||||
return None
|
||||
|
||||
job_id = f"{self.job_prefix}_{schedule_id}"
|
||||
job = self.scheduler.get_job(job_id)
|
||||
if job:
|
||||
return job.next_run_time
|
||||
return None
|
||||
|
||||
def get_schedule_info(self):
|
||||
"""
|
||||
Get information about all schedules
|
||||
|
||||
Returns:
|
||||
dict: Schedule information including next run times for all jobs
|
||||
"""
|
||||
try:
|
||||
from app.database_backup import DatabaseBackupManager
|
||||
|
||||
with self.app.app_context():
|
||||
backup_manager = DatabaseBackupManager()
|
||||
schedule_config = backup_manager.get_backup_schedule()
|
||||
|
||||
# Get all backup jobs
|
||||
jobs_info = []
|
||||
for job in self.scheduler.get_jobs():
|
||||
if job.id.startswith(self.job_prefix):
|
||||
jobs_info.append({
|
||||
'id': job.id.replace(f"{self.job_prefix}_", ""),
|
||||
'name': job.name,
|
||||
'next_run_time': job.next_run_time.strftime('%Y-%m-%d %H:%M:%S') if job.next_run_time else None
|
||||
})
|
||||
|
||||
return {
|
||||
'schedule': schedule_config,
|
||||
'jobs': jobs_info,
|
||||
'scheduler_running': self.scheduler.running if self.scheduler else False,
|
||||
'total_jobs': len(jobs_info)
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting schedule info: {e}")
|
||||
return None
|
||||
|
||||
def trigger_backup_now(self):
|
||||
"""
|
||||
Manually trigger a backup immediately (outside of schedule)
|
||||
|
||||
Returns:
|
||||
dict: Result of backup operation
|
||||
"""
|
||||
try:
|
||||
logger.info("Manual backup trigger requested")
|
||||
self.execute_scheduled_backup()
|
||||
return {
|
||||
'success': True,
|
||||
'message': 'Backup triggered successfully'
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"Error triggering manual backup: {e}")
|
||||
return {
|
||||
'success': False,
|
||||
'message': f'Failed to trigger backup: {str(e)}'
|
||||
}
|
||||
|
||||
|
||||
# Global scheduler instance (initialized in __init__.py)
|
||||
backup_scheduler = None
|
||||
|
||||
|
||||
def init_backup_scheduler(app):
|
||||
"""
|
||||
Initialize the global backup scheduler instance
|
||||
|
||||
Args:
|
||||
app: Flask application instance
|
||||
|
||||
Returns:
|
||||
BackupScheduler: Initialized scheduler instance
|
||||
"""
|
||||
global backup_scheduler
|
||||
backup_scheduler = BackupScheduler(app)
|
||||
return backup_scheduler
|
||||
|
||||
|
||||
def get_backup_scheduler():
|
||||
"""
|
||||
Get the global backup scheduler instance
|
||||
|
||||
Returns:
|
||||
BackupScheduler or None: Scheduler instance if initialized
|
||||
"""
|
||||
return backup_scheduler
|
||||
@@ -281,6 +281,95 @@ class DatabaseBackupManager:
|
||||
except Exception as e:
|
||||
print(f"Error removing backup metadata: {e}")
|
||||
|
||||
def create_data_only_backup(self, backup_name=None):
|
||||
"""
|
||||
Create a data-only backup (no schema, triggers, or structure)
|
||||
Only exports INSERT statements for existing tables
|
||||
|
||||
Args:
|
||||
backup_name (str, optional): Custom name for the backup file
|
||||
|
||||
Returns:
|
||||
dict: Result with success status, message, and backup file path
|
||||
"""
|
||||
try:
|
||||
if not self.config:
|
||||
return {
|
||||
'success': False,
|
||||
'message': 'Database configuration not loaded'
|
||||
}
|
||||
|
||||
# Generate backup filename with data_only prefix
|
||||
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||
if backup_name:
|
||||
filename = f"data_only_{backup_name}_{timestamp}.sql"
|
||||
else:
|
||||
filename = f"data_only_{self.config['database']}_{timestamp}.sql"
|
||||
|
||||
backup_file = os.path.join(self.backup_path, filename)
|
||||
|
||||
# Build mysqldump command for data only
|
||||
# --no-create-info: Skip CREATE TABLE statements
|
||||
# --skip-triggers: Skip trigger definitions
|
||||
# --no-create-db: Skip CREATE DATABASE statement
|
||||
# --complete-insert: Include column names in INSERT (more reliable)
|
||||
# --extended-insert: Use multi-row INSERT for efficiency
|
||||
cmd = [
|
||||
'mysqldump',
|
||||
f"--host={self.config['host']}",
|
||||
f"--port={self.config['port']}",
|
||||
f"--user={self.config['user']}",
|
||||
f"--password={self.config['password']}",
|
||||
'--no-create-info', # Skip table structure
|
||||
'--skip-triggers', # Skip triggers
|
||||
'--no-create-db', # Skip database creation
|
||||
'--complete-insert', # Include column names
|
||||
'--extended-insert', # Multi-row INSERTs
|
||||
'--single-transaction',
|
||||
'--skip-lock-tables',
|
||||
self.config['database']
|
||||
]
|
||||
|
||||
# Execute mysqldump and save to file
|
||||
with open(backup_file, 'w') as f:
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
stdout=f,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True
|
||||
)
|
||||
|
||||
if result.returncode == 0:
|
||||
# Get file size
|
||||
file_size = os.path.getsize(backup_file)
|
||||
file_size_mb = file_size / (1024 * 1024)
|
||||
|
||||
# Save backup metadata
|
||||
self._save_backup_metadata(filename, file_size)
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
'message': f'Data-only backup created successfully',
|
||||
'filename': filename,
|
||||
'file_path': backup_file,
|
||||
'size': f"{file_size_mb:.2f} MB",
|
||||
'timestamp': timestamp
|
||||
}
|
||||
else:
|
||||
error_msg = result.stderr
|
||||
print(f"Data backup error: {error_msg}")
|
||||
return {
|
||||
'success': False,
|
||||
'message': f'Data backup failed: {error_msg}'
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
print(f"Exception during data backup: {e}")
|
||||
return {
|
||||
'success': False,
|
||||
'message': f'Data backup failed: {str(e)}'
|
||||
}
|
||||
|
||||
def restore_backup(self, filename):
|
||||
"""
|
||||
Restore database from a backup file
|
||||
@@ -345,6 +434,127 @@ class DatabaseBackupManager:
|
||||
'message': f'Restore failed: {str(e)}'
|
||||
}
|
||||
|
||||
def restore_data_only(self, filename):
|
||||
"""
|
||||
Restore data from a data-only backup file
|
||||
Assumes database schema already exists
|
||||
Truncates tables before inserting data to avoid duplicates
|
||||
|
||||
Args:
|
||||
filename (str): Name of the data-only backup file to restore
|
||||
|
||||
Returns:
|
||||
dict: Result with success status and message
|
||||
"""
|
||||
try:
|
||||
# Security: ensure filename doesn't contain path traversal
|
||||
if '..' in filename or '/' in filename:
|
||||
return {
|
||||
'success': False,
|
||||
'message': 'Invalid filename'
|
||||
}
|
||||
|
||||
file_path = os.path.join(self.backup_path, filename)
|
||||
|
||||
if not os.path.exists(file_path):
|
||||
return {
|
||||
'success': False,
|
||||
'message': 'Backup file not found'
|
||||
}
|
||||
|
||||
# First, disable foreign key checks and truncate all tables
|
||||
# This ensures clean data import without constraint violations
|
||||
try:
|
||||
conn = mariadb.connect(
|
||||
host=self.config['host'],
|
||||
port=int(self.config['port']),
|
||||
user=self.config['user'],
|
||||
password=self.config['password'],
|
||||
database=self.config['database']
|
||||
)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Disable foreign key checks
|
||||
cursor.execute("SET FOREIGN_KEY_CHECKS = 0;")
|
||||
|
||||
# Get list of all tables in the database
|
||||
cursor.execute("SHOW TABLES;")
|
||||
tables = cursor.fetchall()
|
||||
|
||||
# Truncate each table (except system tables)
|
||||
for (table_name,) in tables:
|
||||
# Skip metadata and system tables
|
||||
if table_name not in ['backups_metadata', 'backup_schedule']:
|
||||
try:
|
||||
cursor.execute(f"TRUNCATE TABLE `{table_name}`;")
|
||||
print(f"Truncated table: {table_name}")
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not truncate {table_name}: {e}")
|
||||
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
except Exception as e:
|
||||
print(f"Warning during table truncation: {e}")
|
||||
# Continue anyway - the restore might still work
|
||||
|
||||
# Build mysql restore command for data
|
||||
cmd = [
|
||||
'mysql',
|
||||
f"--host={self.config['host']}",
|
||||
f"--port={self.config['port']}",
|
||||
f"--user={self.config['user']}",
|
||||
f"--password={self.config['password']}",
|
||||
self.config['database']
|
||||
]
|
||||
|
||||
# Execute mysql restore
|
||||
with open(file_path, 'r') as f:
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
stdin=f,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True
|
||||
)
|
||||
|
||||
# Re-enable foreign key checks
|
||||
try:
|
||||
conn = mariadb.connect(
|
||||
host=self.config['host'],
|
||||
port=int(self.config['port']),
|
||||
user=self.config['user'],
|
||||
password=self.config['password'],
|
||||
database=self.config['database']
|
||||
)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SET FOREIGN_KEY_CHECKS = 1;")
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
conn.close()
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not re-enable foreign key checks: {e}")
|
||||
|
||||
if result.returncode == 0:
|
||||
return {
|
||||
'success': True,
|
||||
'message': f'Data restored successfully from {filename}'
|
||||
}
|
||||
else:
|
||||
error_msg = result.stderr
|
||||
print(f"Data restore error: {error_msg}")
|
||||
return {
|
||||
'success': False,
|
||||
'message': f'Data restore failed: {error_msg}'
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
print(f"Exception during data restore: {e}")
|
||||
return {
|
||||
'success': False,
|
||||
'message': f'Data restore failed: {str(e)}'
|
||||
}
|
||||
|
||||
def get_backup_schedule(self):
|
||||
"""Get current backup schedule configuration"""
|
||||
try:
|
||||
@@ -352,13 +562,18 @@ class DatabaseBackupManager:
|
||||
|
||||
if os.path.exists(schedule_file):
|
||||
with open(schedule_file, 'r') as f:
|
||||
return json.load(f)
|
||||
schedule = json.load(f)
|
||||
# Ensure backup_type exists (for backward compatibility)
|
||||
if 'backup_type' not in schedule:
|
||||
schedule['backup_type'] = 'full'
|
||||
return schedule
|
||||
|
||||
# Default schedule
|
||||
return {
|
||||
'enabled': False,
|
||||
'time': '02:00', # 2 AM
|
||||
'frequency': 'daily', # daily, weekly, monthly
|
||||
'backup_type': 'full', # full or data-only
|
||||
'retention_days': 30 # Keep backups for 30 days
|
||||
}
|
||||
|
||||
@@ -607,3 +822,112 @@ class DatabaseBackupManager:
|
||||
'success': False,
|
||||
'message': f'Cleanup failed: {str(e)}'
|
||||
}
|
||||
|
||||
def upload_backup(self, uploaded_file):
|
||||
"""
|
||||
Upload and validate an external backup file
|
||||
|
||||
Args:
|
||||
uploaded_file: Werkzeug FileStorage object from request.files
|
||||
|
||||
Returns:
|
||||
dict: Result with success status, filename, and validation details
|
||||
"""
|
||||
try:
|
||||
from werkzeug.utils import secure_filename
|
||||
from pathlib import Path
|
||||
|
||||
# Validate file extension
|
||||
if not uploaded_file.filename.lower().endswith('.sql'):
|
||||
return {
|
||||
'success': False,
|
||||
'message': 'Invalid file format. Only .sql files are allowed.'
|
||||
}
|
||||
|
||||
# Ensure backup_path is a Path object
|
||||
backup_path = Path(self.backup_path)
|
||||
backup_path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Generate secure filename with timestamp to avoid conflicts
|
||||
original_filename = secure_filename(uploaded_file.filename)
|
||||
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||
|
||||
# If filename already starts with "backup_", keep it; otherwise add prefix
|
||||
if original_filename.startswith('backup_'):
|
||||
new_filename = f"{original_filename.rsplit('.', 1)[0]}_{timestamp}.sql"
|
||||
else:
|
||||
new_filename = f"backup_uploaded_{timestamp}_{original_filename}"
|
||||
|
||||
# Save file to backup directory
|
||||
file_path = backup_path / new_filename
|
||||
uploaded_file.save(str(file_path))
|
||||
|
||||
# Get file size
|
||||
file_size = file_path.stat().st_size
|
||||
size_mb = round(file_size / (1024 * 1024), 2)
|
||||
|
||||
# Validate the uploaded file for integrity and compatibility
|
||||
validation_result = self.validate_backup_file(new_filename)
|
||||
|
||||
if not validation_result['success']:
|
||||
# Validation failed - remove the uploaded file
|
||||
file_path.unlink() # Delete the invalid file
|
||||
return {
|
||||
'success': False,
|
||||
'message': f'Validation failed: {validation_result["message"]}',
|
||||
'validation_details': validation_result.get('details', {}),
|
||||
'warnings': validation_result.get('warnings', [])
|
||||
}
|
||||
|
||||
# Build response with validation details
|
||||
response = {
|
||||
'success': True,
|
||||
'message': 'Backup file uploaded and validated successfully',
|
||||
'filename': new_filename,
|
||||
'size': f'{size_mb} MB',
|
||||
'path': str(file_path),
|
||||
'validation': {
|
||||
'status': 'passed',
|
||||
'message': validation_result['message'],
|
||||
'details': validation_result.get('details', {}),
|
||||
'warnings': validation_result.get('warnings', [])
|
||||
}
|
||||
}
|
||||
|
||||
# Add warning flag if there are warnings
|
||||
if validation_result.get('warnings'):
|
||||
response['message'] = f'Backup uploaded with warnings: {"; ".join(validation_result["warnings"])}'
|
||||
|
||||
# Save metadata
|
||||
self._save_backup_metadata(new_filename, file_size)
|
||||
|
||||
return response
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error uploading backup: {e}")
|
||||
return {
|
||||
'success': False,
|
||||
'message': f'Upload failed: {str(e)}'
|
||||
}
|
||||
|
||||
def get_backup_file_path(self, filename):
|
||||
"""
|
||||
Get the full path to a backup file (with security validation)
|
||||
|
||||
Args:
|
||||
filename (str): Name of the backup file
|
||||
|
||||
Returns:
|
||||
str or None: Full file path if valid, None if security check fails
|
||||
"""
|
||||
# Security: ensure filename doesn't contain path traversal
|
||||
if '..' in filename or '/' in filename:
|
||||
return None
|
||||
|
||||
file_path = os.path.join(self.backup_path, filename)
|
||||
|
||||
if os.path.exists(file_path):
|
||||
return file_path
|
||||
|
||||
return None
|
||||
|
||||
|
||||
@@ -394,56 +394,76 @@ def create_database_triggers():
|
||||
conn = mariadb.connect(**DB_CONFIG)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Drop existing triggers if they exist
|
||||
# Drop existing triggers if they exist (old and new names)
|
||||
trigger_drops = [
|
||||
"DROP TRIGGER IF EXISTS increment_approved_quantity;",
|
||||
"DROP TRIGGER IF EXISTS increment_rejected_quantity;",
|
||||
"DROP TRIGGER IF EXISTS increment_approved_quantity_fg;",
|
||||
"DROP TRIGGER IF EXISTS increment_rejected_quantity_fg;"
|
||||
"DROP TRIGGER IF EXISTS increment_rejected_quantity_fg;",
|
||||
"DROP TRIGGER IF EXISTS set_quantities_scan1;",
|
||||
"DROP TRIGGER IF EXISTS set_quantities_fg;"
|
||||
]
|
||||
|
||||
for drop_query in trigger_drops:
|
||||
cursor.execute(drop_query)
|
||||
|
||||
# Create trigger for scan1_orders approved quantity
|
||||
scan1_approved_trigger = """
|
||||
CREATE TRIGGER increment_approved_quantity
|
||||
AFTER INSERT ON scan1_orders
|
||||
# Create trigger for scan1_orders - BEFORE INSERT to set quantities
|
||||
scan1_trigger = """
|
||||
CREATE TRIGGER set_quantities_scan1
|
||||
BEFORE INSERT ON scan1_orders
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
IF NEW.quality_code = 000 THEN
|
||||
UPDATE scan1_orders
|
||||
SET approved_quantity = approved_quantity + 1
|
||||
WHERE CP_base_code = NEW.CP_base_code;
|
||||
-- Count existing approved for this CP_base_code
|
||||
SET @approved = (SELECT COUNT(*) FROM scan1_orders
|
||||
WHERE CP_base_code = LEFT(NEW.CP_full_code, 10)
|
||||
AND quality_code = 0);
|
||||
|
||||
-- Count existing rejected for this CP_base_code
|
||||
SET @rejected = (SELECT COUNT(*) FROM scan1_orders
|
||||
WHERE CP_base_code = LEFT(NEW.CP_full_code, 10)
|
||||
AND quality_code != 0);
|
||||
|
||||
-- Add 1 to appropriate counter for this new row
|
||||
IF NEW.quality_code = 0 THEN
|
||||
SET NEW.approved_quantity = @approved + 1;
|
||||
SET NEW.rejected_quantity = @rejected;
|
||||
ELSE
|
||||
UPDATE scan1_orders
|
||||
SET rejected_quantity = rejected_quantity + 1
|
||||
WHERE CP_base_code = NEW.CP_base_code;
|
||||
SET NEW.approved_quantity = @approved;
|
||||
SET NEW.rejected_quantity = @rejected + 1;
|
||||
END IF;
|
||||
END;
|
||||
"""
|
||||
cursor.execute(scan1_approved_trigger)
|
||||
print_success("Trigger 'increment_approved_quantity' created for scan1_orders")
|
||||
cursor.execute(scan1_trigger)
|
||||
print_success("Trigger 'set_quantities_scan1' created for scan1_orders")
|
||||
|
||||
# Create trigger for scanfg_orders approved quantity
|
||||
scanfg_approved_trigger = """
|
||||
CREATE TRIGGER increment_approved_quantity_fg
|
||||
AFTER INSERT ON scanfg_orders
|
||||
# Create trigger for scanfg_orders - BEFORE INSERT to set quantities
|
||||
scanfg_trigger = """
|
||||
CREATE TRIGGER set_quantities_fg
|
||||
BEFORE INSERT ON scanfg_orders
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
IF NEW.quality_code = 000 THEN
|
||||
UPDATE scanfg_orders
|
||||
SET approved_quantity = approved_quantity + 1
|
||||
WHERE CP_base_code = NEW.CP_base_code;
|
||||
-- Count existing approved for this CP_base_code
|
||||
SET @approved = (SELECT COUNT(*) FROM scanfg_orders
|
||||
WHERE CP_base_code = LEFT(NEW.CP_full_code, 10)
|
||||
AND quality_code = 0);
|
||||
|
||||
-- Count existing rejected for this CP_base_code
|
||||
SET @rejected = (SELECT COUNT(*) FROM scanfg_orders
|
||||
WHERE CP_base_code = LEFT(NEW.CP_full_code, 10)
|
||||
AND quality_code != 0);
|
||||
|
||||
-- Add 1 to appropriate counter for this new row
|
||||
IF NEW.quality_code = 0 THEN
|
||||
SET NEW.approved_quantity = @approved + 1;
|
||||
SET NEW.rejected_quantity = @rejected;
|
||||
ELSE
|
||||
UPDATE scanfg_orders
|
||||
SET rejected_quantity = rejected_quantity + 1
|
||||
WHERE CP_base_code = NEW.CP_base_code;
|
||||
SET NEW.approved_quantity = @approved;
|
||||
SET NEW.rejected_quantity = @rejected + 1;
|
||||
END IF;
|
||||
END;
|
||||
"""
|
||||
cursor.execute(scanfg_approved_trigger)
|
||||
print_success("Trigger 'increment_approved_quantity_fg' created for scanfg_orders")
|
||||
cursor.execute(scanfg_trigger)
|
||||
print_success("Trigger 'set_quantities_fg' created for scanfg_orders")
|
||||
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
|
||||
@@ -473,36 +473,25 @@ def scan():
|
||||
conn = get_db_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Always insert a new entry - each scan is a separate record
|
||||
# Insert new entry - the BEFORE INSERT trigger 'set_quantities_scan1' will automatically
|
||||
# calculate and set approved_quantity and rejected_quantity for this new record
|
||||
insert_query = """
|
||||
INSERT INTO scan1_orders (operator_code, CP_full_code, OC1_code, OC2_code, quality_code, date, time)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s)
|
||||
"""
|
||||
cursor.execute(insert_query, (operator_code, cp_code, oc1_code, oc2_code, defect_code, date, time))
|
||||
conn.commit()
|
||||
|
||||
# Get the CP_base_code (first 10 characters of CP_full_code)
|
||||
# Get the quantities from the newly inserted row for the flash message
|
||||
cp_base_code = cp_code[:10]
|
||||
|
||||
# Count approved quantities (quality_code = 0) for this CP_base_code
|
||||
cursor.execute("""
|
||||
SELECT COUNT(*) FROM scan1_orders
|
||||
WHERE CP_base_code = %s AND quality_code = 0
|
||||
""", (cp_base_code,))
|
||||
approved_count = cursor.fetchone()[0]
|
||||
|
||||
# Count rejected quantities (quality_code != 0) for this CP_base_code
|
||||
cursor.execute("""
|
||||
SELECT COUNT(*) FROM scan1_orders
|
||||
WHERE CP_base_code = %s AND quality_code != 0
|
||||
""", (cp_base_code,))
|
||||
rejected_count = cursor.fetchone()[0]
|
||||
|
||||
# Update all records with the same CP_base_code with new quantities
|
||||
cursor.execute("""
|
||||
UPDATE scan1_orders
|
||||
SET approved_quantity = %s, rejected_quantity = %s
|
||||
WHERE CP_base_code = %s
|
||||
""", (approved_count, rejected_count, cp_base_code))
|
||||
SELECT approved_quantity, rejected_quantity
|
||||
FROM scan1_orders
|
||||
WHERE CP_full_code = %s
|
||||
""", (cp_code,))
|
||||
result = cursor.fetchone()
|
||||
approved_count = result[0] if result else 0
|
||||
rejected_count = result[1] if result else 0
|
||||
|
||||
# Flash appropriate message
|
||||
if int(defect_code) == 0:
|
||||
@@ -510,8 +499,6 @@ def scan():
|
||||
else:
|
||||
flash(f'❌ REJECTED scan recorded for {cp_code} (defect: {defect_code}). Total rejected: {rejected_count}')
|
||||
|
||||
# Commit the transaction
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
except mariadb.Error as e:
|
||||
@@ -566,35 +553,25 @@ def fg_scan():
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Always insert a new entry - each scan is a separate record
|
||||
# Note: The trigger 'increment_approved_quantity_fg' will automatically
|
||||
# update approved_quantity or rejected_quantity for all records with same CP_base_code
|
||||
insert_query = """
|
||||
INSERT INTO scanfg_orders (operator_code, CP_full_code, OC1_code, OC2_code, quality_code, date, time)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s)
|
||||
"""
|
||||
cursor.execute(insert_query, (operator_code, cp_code, oc1_code, oc2_code, defect_code, date, time))
|
||||
conn.commit()
|
||||
|
||||
# Get the CP_base_code (first 10 characters of CP_full_code)
|
||||
# Get the quantities from the newly inserted row for the flash message
|
||||
cp_base_code = cp_code[:10]
|
||||
|
||||
# Count approved quantities (quality_code = 0) for this CP_base_code
|
||||
cursor.execute("""
|
||||
SELECT COUNT(*) FROM scanfg_orders
|
||||
WHERE CP_base_code = %s AND quality_code = 0
|
||||
""", (cp_base_code,))
|
||||
approved_count = cursor.fetchone()[0]
|
||||
|
||||
# Count rejected quantities (quality_code != 0) for this CP_base_code
|
||||
cursor.execute("""
|
||||
SELECT COUNT(*) FROM scanfg_orders
|
||||
WHERE CP_base_code = %s AND quality_code != 0
|
||||
""", (cp_base_code,))
|
||||
rejected_count = cursor.fetchone()[0]
|
||||
|
||||
# Update all records with the same CP_base_code with new quantities
|
||||
cursor.execute("""
|
||||
UPDATE scanfg_orders
|
||||
SET approved_quantity = %s, rejected_quantity = %s
|
||||
WHERE CP_base_code = %s
|
||||
""", (approved_count, rejected_count, cp_base_code))
|
||||
SELECT approved_quantity, rejected_quantity
|
||||
FROM scanfg_orders
|
||||
WHERE CP_full_code = %s
|
||||
""", (cp_code,))
|
||||
result = cursor.fetchone()
|
||||
approved_count = result[0] if result else 0
|
||||
rejected_count = result[1] if result else 0
|
||||
|
||||
# Flash appropriate message
|
||||
if int(defect_code) == 0:
|
||||
@@ -602,8 +579,6 @@ def fg_scan():
|
||||
else:
|
||||
flash(f'❌ REJECTED scan recorded for {cp_code} (defect: {defect_code}). Total rejected: {rejected_count}')
|
||||
|
||||
# Commit the transaction
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
except mariadb.Error as e:
|
||||
@@ -3628,25 +3603,16 @@ def api_backup_download(filename):
|
||||
try:
|
||||
from app.database_backup import DatabaseBackupManager
|
||||
from flask import send_file
|
||||
import os
|
||||
|
||||
backup_manager = DatabaseBackupManager()
|
||||
backup_path = backup_manager.backup_path
|
||||
file_path = os.path.join(backup_path, filename)
|
||||
file_path = backup_manager.get_backup_file_path(filename)
|
||||
|
||||
# Security: ensure filename doesn't contain path traversal
|
||||
if '..' in filename or '/' in filename:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': 'Invalid filename'
|
||||
}), 400
|
||||
|
||||
if os.path.exists(file_path):
|
||||
if file_path:
|
||||
return send_file(file_path, as_attachment=True, download_name=filename)
|
||||
else:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': 'Backup file not found'
|
||||
'message': 'Backup file not found or invalid filename'
|
||||
}), 404
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
@@ -3677,18 +3643,56 @@ def api_backup_schedule():
|
||||
"""Get or save backup schedule configuration"""
|
||||
try:
|
||||
from app.database_backup import DatabaseBackupManager
|
||||
from app.backup_scheduler import get_backup_scheduler
|
||||
|
||||
backup_manager = DatabaseBackupManager()
|
||||
|
||||
if request.method == 'POST':
|
||||
schedule = request.json
|
||||
result = backup_manager.save_backup_schedule(schedule)
|
||||
|
||||
if result['success']:
|
||||
# Reload the scheduler to apply new configuration
|
||||
scheduler = get_backup_scheduler()
|
||||
if scheduler:
|
||||
scheduler.update_schedule()
|
||||
info = scheduler.get_schedule_info()
|
||||
|
||||
if info and info.get('jobs'):
|
||||
jobs = info['jobs']
|
||||
result['message'] += f'. {len(jobs)} active schedule(s)'
|
||||
|
||||
return jsonify(result)
|
||||
else:
|
||||
schedule = backup_manager.get_backup_schedule()
|
||||
|
||||
# Auto-migrate legacy format to multi-schedule format
|
||||
if 'schedules' not in schedule:
|
||||
schedule = {
|
||||
'schedules': [{
|
||||
'id': 'default',
|
||||
'name': 'Default Schedule',
|
||||
'enabled': schedule.get('enabled', True),
|
||||
'time': schedule.get('time', '02:00'),
|
||||
'frequency': schedule.get('frequency', 'daily'),
|
||||
'backup_type': schedule.get('backup_type', 'full'),
|
||||
'retention_days': schedule.get('retention_days', 30)
|
||||
}]
|
||||
}
|
||||
# Save migrated format
|
||||
backup_manager.save_backup_schedule(schedule)
|
||||
|
||||
# Get scheduler info with all jobs
|
||||
scheduler = get_backup_scheduler()
|
||||
jobs = []
|
||||
if scheduler:
|
||||
info = scheduler.get_schedule_info()
|
||||
jobs = info.get('jobs', []) if info else []
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'schedule': schedule
|
||||
'schedule': schedule,
|
||||
'jobs': jobs
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
@@ -3718,9 +3722,6 @@ def api_backup_upload():
|
||||
"""Upload an external backup file (superadmin only)"""
|
||||
try:
|
||||
from app.database_backup import DatabaseBackupManager
|
||||
from werkzeug.utils import secure_filename
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
# Check if file was uploaded
|
||||
if 'backup_file' not in request.files:
|
||||
@@ -3738,79 +3739,302 @@ def api_backup_upload():
|
||||
'message': 'No file selected'
|
||||
}), 400
|
||||
|
||||
# Validate file extension
|
||||
if not file.filename.lower().endswith('.sql'):
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': 'Invalid file format. Only .sql files are allowed.'
|
||||
}), 400
|
||||
|
||||
# Get backup manager and backup path
|
||||
# Use DatabaseBackupManager to handle upload
|
||||
backup_manager = DatabaseBackupManager()
|
||||
backup_path = backup_manager.backup_path
|
||||
result = backup_manager.upload_backup(file)
|
||||
|
||||
# Ensure backup_path is a Path object
|
||||
from pathlib import Path
|
||||
if not isinstance(backup_path, Path):
|
||||
backup_path = Path(backup_path)
|
||||
|
||||
# Create backup directory if it doesn't exist
|
||||
backup_path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Generate secure filename with timestamp to avoid conflicts
|
||||
original_filename = secure_filename(file.filename)
|
||||
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||
|
||||
# If filename already starts with "backup_", keep it; otherwise add prefix
|
||||
if original_filename.startswith('backup_'):
|
||||
new_filename = f"{original_filename.rsplit('.', 1)[0]}_{timestamp}.sql"
|
||||
else:
|
||||
new_filename = f"backup_uploaded_{timestamp}_{original_filename}"
|
||||
|
||||
# Save file to backup directory
|
||||
file_path = backup_path / new_filename
|
||||
file.save(str(file_path))
|
||||
|
||||
# Get file size
|
||||
file_size = file_path.stat().st_size
|
||||
size_mb = round(file_size / (1024 * 1024), 2)
|
||||
|
||||
# Validate the uploaded file for integrity and compatibility
|
||||
validation_result = backup_manager.validate_backup_file(new_filename)
|
||||
|
||||
if not validation_result['success']:
|
||||
# Validation failed - remove the uploaded file
|
||||
file_path.unlink() # Delete the invalid file
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'Validation failed: {validation_result["message"]}',
|
||||
'validation_details': validation_result.get('details', {}),
|
||||
'warnings': validation_result.get('warnings', [])
|
||||
}), 400
|
||||
|
||||
# Build response with validation details
|
||||
response = {
|
||||
'success': True,
|
||||
'message': 'Backup file uploaded and validated successfully',
|
||||
'filename': new_filename,
|
||||
'size': f'{size_mb} MB',
|
||||
'path': str(file_path),
|
||||
'validation': {
|
||||
'status': 'passed',
|
||||
'message': validation_result['message'],
|
||||
'details': validation_result.get('details', {}),
|
||||
'warnings': validation_result.get('warnings', [])
|
||||
}
|
||||
}
|
||||
|
||||
# Add warning flag if there are warnings
|
||||
if validation_result.get('warnings'):
|
||||
response['message'] = f'Backup uploaded with warnings: {"; ".join(validation_result["warnings"])}'
|
||||
|
||||
return jsonify(response)
|
||||
# Return appropriate status code
|
||||
status_code = 200 if result['success'] else 400
|
||||
return jsonify(result), status_code
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'Upload failed: {str(e)}'
|
||||
}), 500
|
||||
|
||||
@bp.route('/api/backup/create-data-only', methods=['POST'])
|
||||
@admin_plus
|
||||
def api_backup_create_data_only():
|
||||
"""Create a data-only backup (no schema, triggers, or structure)"""
|
||||
try:
|
||||
from app.database_backup import DatabaseBackupManager
|
||||
|
||||
backup_manager = DatabaseBackupManager()
|
||||
result = backup_manager.create_data_only_backup()
|
||||
|
||||
return jsonify(result)
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'Data backup failed: {str(e)}'
|
||||
}), 500
|
||||
|
||||
@bp.route('/api/backup/restore-data-only/<filename>', methods=['POST'])
|
||||
@superadmin_only
|
||||
def api_backup_restore_data_only(filename):
|
||||
"""Restore data from a data-only backup file (superadmin only)
|
||||
Assumes database schema already exists
|
||||
"""
|
||||
try:
|
||||
from app.database_backup import DatabaseBackupManager
|
||||
|
||||
backup_manager = DatabaseBackupManager()
|
||||
result = backup_manager.restore_data_only(filename)
|
||||
|
||||
return jsonify(result)
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'Data restore failed: {str(e)}'
|
||||
}), 500
|
||||
|
||||
@bp.route('/api/backup/schedule-info', methods=['GET'])
|
||||
@admin_plus
|
||||
def api_backup_schedule_info():
|
||||
"""Get detailed backup schedule information including next run time"""
|
||||
try:
|
||||
from app.backup_scheduler import get_backup_scheduler
|
||||
|
||||
scheduler = get_backup_scheduler()
|
||||
if not scheduler:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': 'Backup scheduler not initialized'
|
||||
}), 500
|
||||
|
||||
info = scheduler.get_schedule_info()
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'info': info
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'Failed to get schedule info: {str(e)}'
|
||||
}), 500
|
||||
|
||||
@bp.route('/api/backup/reload-schedule', methods=['POST'])
|
||||
@admin_plus
|
||||
def api_backup_reload_schedule():
|
||||
"""Reload the backup schedule after configuration changes"""
|
||||
try:
|
||||
from app.backup_scheduler import get_backup_scheduler
|
||||
|
||||
scheduler = get_backup_scheduler()
|
||||
if not scheduler:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': 'Backup scheduler not initialized'
|
||||
}), 500
|
||||
|
||||
scheduler.update_schedule()
|
||||
|
||||
info = scheduler.get_schedule_info()
|
||||
next_run = info['next_run_time'] if info else None
|
||||
|
||||
message = 'Backup schedule reloaded successfully'
|
||||
if next_run:
|
||||
message += f'. Next backup: {next_run}'
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': message,
|
||||
'next_run_time': next_run
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'Failed to reload schedule: {str(e)}'
|
||||
}), 500
|
||||
|
||||
@bp.route('/api/backup/schedule/toggle/<schedule_id>', methods=['POST'])
|
||||
@admin_plus
|
||||
def api_backup_schedule_toggle(schedule_id):
|
||||
"""Toggle a specific schedule on/off"""
|
||||
try:
|
||||
from app.database_backup import DatabaseBackupManager
|
||||
from app.backup_scheduler import get_backup_scheduler
|
||||
|
||||
backup_manager = DatabaseBackupManager()
|
||||
schedule_config = backup_manager.get_backup_schedule()
|
||||
|
||||
# Handle new multi-schedule format
|
||||
if isinstance(schedule_config, dict) and 'schedules' in schedule_config:
|
||||
schedules = schedule_config['schedules']
|
||||
|
||||
# Find and toggle the schedule
|
||||
schedule_found = False
|
||||
for schedule in schedules:
|
||||
if schedule.get('id') == schedule_id:
|
||||
schedule['enabled'] = not schedule.get('enabled', False)
|
||||
schedule_found = True
|
||||
break
|
||||
|
||||
if not schedule_found:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'Schedule {schedule_id} not found'
|
||||
}), 404
|
||||
|
||||
# Save updated configuration
|
||||
result = backup_manager.save_backup_schedule(schedule_config)
|
||||
|
||||
if result['success']:
|
||||
# Reload scheduler
|
||||
scheduler = get_backup_scheduler()
|
||||
if scheduler:
|
||||
scheduler.update_schedule()
|
||||
|
||||
enabled_count = sum(1 for s in schedules if s.get('enabled', False))
|
||||
result['message'] = f'Schedule {schedule_id} toggled successfully. {enabled_count} schedule(s) active.'
|
||||
|
||||
return jsonify(result)
|
||||
|
||||
# Handle legacy single schedule format
|
||||
else:
|
||||
schedule_config['enabled'] = not schedule_config.get('enabled', False)
|
||||
result = backup_manager.save_backup_schedule(schedule_config)
|
||||
|
||||
if result['success']:
|
||||
scheduler = get_backup_scheduler()
|
||||
if scheduler:
|
||||
scheduler.update_schedule()
|
||||
|
||||
return jsonify(result)
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'Failed to toggle schedule: {str(e)}'
|
||||
}), 500
|
||||
|
||||
@bp.route('/api/backup/schedule/delete/<schedule_id>', methods=['DELETE'])
|
||||
@admin_plus
|
||||
def api_backup_schedule_delete(schedule_id):
|
||||
"""Delete a specific schedule"""
|
||||
try:
|
||||
from app.database_backup import DatabaseBackupManager
|
||||
from app.backup_scheduler import get_backup_scheduler
|
||||
|
||||
# Don't allow deleting the default schedule
|
||||
if schedule_id == 'default':
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': 'Cannot delete the default schedule'
|
||||
}), 400
|
||||
|
||||
backup_manager = DatabaseBackupManager()
|
||||
schedule_config = backup_manager.get_backup_schedule()
|
||||
|
||||
if isinstance(schedule_config, dict) and 'schedules' in schedule_config:
|
||||
schedules = schedule_config['schedules']
|
||||
|
||||
# Remove the schedule
|
||||
new_schedules = [s for s in schedules if s.get('id') != schedule_id]
|
||||
|
||||
if len(new_schedules) == len(schedules):
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'Schedule {schedule_id} not found'
|
||||
}), 404
|
||||
|
||||
schedule_config['schedules'] = new_schedules
|
||||
result = backup_manager.save_backup_schedule(schedule_config)
|
||||
|
||||
if result['success']:
|
||||
# Reload scheduler
|
||||
scheduler = get_backup_scheduler()
|
||||
if scheduler:
|
||||
scheduler.update_schedule()
|
||||
|
||||
result['message'] = f'Schedule {schedule_id} deleted successfully'
|
||||
|
||||
return jsonify(result)
|
||||
else:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': 'Multi-schedule format not enabled'
|
||||
}), 400
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'Failed to delete schedule: {str(e)}'
|
||||
}), 500
|
||||
|
||||
@bp.route('/api/backup/schedule/add', methods=['POST'])
|
||||
@admin_plus
|
||||
def api_backup_schedule_add():
|
||||
"""Add a new schedule"""
|
||||
try:
|
||||
from app.database_backup import DatabaseBackupManager
|
||||
from app.backup_scheduler import get_backup_scheduler
|
||||
import uuid
|
||||
|
||||
new_schedule = request.json
|
||||
|
||||
# Validate required fields
|
||||
required_fields = ['time', 'frequency', 'backup_type', 'retention_days']
|
||||
for field in required_fields:
|
||||
if field not in new_schedule:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'Missing required field: {field}'
|
||||
}), 400
|
||||
|
||||
backup_manager = DatabaseBackupManager()
|
||||
schedule_config = backup_manager.get_backup_schedule()
|
||||
|
||||
# Migrate to multi-schedule format if needed
|
||||
if 'schedules' not in schedule_config:
|
||||
# Convert legacy format to multi-schedule
|
||||
schedule_config = {
|
||||
'schedules': [{
|
||||
'id': 'default',
|
||||
'name': 'Default Schedule',
|
||||
'enabled': schedule_config.get('enabled', True),
|
||||
'time': schedule_config.get('time', '02:00'),
|
||||
'frequency': schedule_config.get('frequency', 'daily'),
|
||||
'backup_type': schedule_config.get('backup_type', 'full'),
|
||||
'retention_days': schedule_config.get('retention_days', 30)
|
||||
}]
|
||||
}
|
||||
|
||||
# Generate unique ID
|
||||
schedule_id = new_schedule.get('id') or str(uuid.uuid4())[:8]
|
||||
|
||||
# Add new schedule
|
||||
new_schedule_entry = {
|
||||
'id': schedule_id,
|
||||
'name': new_schedule.get('name', f'Schedule {schedule_id}'),
|
||||
'enabled': new_schedule.get('enabled', True),
|
||||
'time': new_schedule['time'],
|
||||
'frequency': new_schedule['frequency'],
|
||||
'backup_type': new_schedule['backup_type'],
|
||||
'retention_days': int(new_schedule['retention_days'])
|
||||
}
|
||||
|
||||
schedule_config['schedules'].append(new_schedule_entry)
|
||||
|
||||
# Save configuration
|
||||
result = backup_manager.save_backup_schedule(schedule_config)
|
||||
|
||||
if result['success']:
|
||||
# Reload scheduler
|
||||
scheduler = get_backup_scheduler()
|
||||
if scheduler:
|
||||
scheduler.update_schedule()
|
||||
|
||||
result['message'] = f'Schedule {schedule_id} added successfully'
|
||||
result['schedule_id'] = schedule_id
|
||||
|
||||
return jsonify(result)
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'Failed to add schedule: {str(e)}'
|
||||
}), 500
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,4 +7,5 @@ mariadb
|
||||
reportlab
|
||||
requests
|
||||
pandas
|
||||
openpyxl
|
||||
openpyxl
|
||||
APScheduler
|
||||
@@ -1 +1 @@
|
||||
402172
|
||||
417124
|
||||
|
||||
Reference in New Issue
Block a user