Compare commits

..

2 Commits

8 changed files with 265 additions and 1736 deletions

View File

@@ -1,6 +1,5 @@
DEBUG=False DEBUG=False
ENVIRONMENT=production ENVIRONMENT=production
DJANGO_ENVIRONMENT=production
DJANGO_SETTINGS_MODULE=dbapp.settings.production DJANGO_SETTINGS_MODULE=dbapp.settings.production
SECRET_KEY=django-insecure-dev-key-only-for-production SECRET_KEY=django-insecure-dev-key-only-for-production

View File

@@ -4,18 +4,12 @@ Celery configuration for dbapp project.
import os import os
from celery import Celery from celery import Celery
# Use the environment variable to determine the settings module
os.environ.setdefault('DJANGO_SETTINGS_MODULE', os.getenv('DJANGO_SETTINGS_MODULE', 'dbapp.settings.development')) os.environ.setdefault('DJANGO_SETTINGS_MODULE', os.getenv('DJANGO_SETTINGS_MODULE', 'dbapp.settings.development'))
app = Celery('dbapp') app = Celery('dbapp')
# Using a string here means the worker doesn't have to serialize
# the configuration object to child processes.
# - namespace='CELERY' means all celery-related configuration keys
# should have a `CELERY_` prefix.
app.config_from_object('django.conf:settings', namespace='CELERY') app.config_from_object('django.conf:settings', namespace='CELERY')
# Load task modules from all registered Django apps.
app.autodiscover_tasks() app.autodiscover_tasks()

View File

@@ -57,7 +57,7 @@ TEMPLATES = [
"DIRS": [ "DIRS": [
BASE_DIR / "templates", BASE_DIR / "templates",
], ],
"APP_DIRS": False, # Must be False when using custom loaders "APP_DIRS": False,
"OPTIONS": { "OPTIONS": {
"context_processors": [ "context_processors": [
"django.template.context_processors.debug", "django.template.context_processors.debug",
@@ -88,6 +88,13 @@ STATICFILES_STORAGE = "django.contrib.staticfiles.storage.ManifestStaticFilesSto
# ============================================================================ # ============================================================================
# LOGGING CONFIGURATION # LOGGING CONFIGURATION
# ============================================================================ # ============================================================================
LOGS_DIR = BASE_DIR.parent / "logs"
LOGS_DIR.mkdir(parents=True, exist_ok=True)
# ============================================================================
# CELERY LOGGING CONFIGURATION
# ============================================================================
CELERY_WORKER_HIJACK_ROOT_LOGGER = False
LOGGING = { LOGGING = {
"version": 1, "version": 1,
@@ -116,7 +123,13 @@ LOGGING = {
"file": { "file": {
"level": "ERROR", "level": "ERROR",
"class": "logging.FileHandler", "class": "logging.FileHandler",
"filename": BASE_DIR.parent / "logs" / "django_errors.log", "filename": LOGS_DIR / "django_errors.log",
"formatter": "verbose",
},
"celery_file": {
"level": "INFO",
"class": "logging.FileHandler",
"filename": LOGS_DIR / "celery.log",
"formatter": "verbose", "formatter": "verbose",
}, },
"mail_admins": { "mail_admins": {
@@ -137,5 +150,15 @@ LOGGING = {
"level": "ERROR", "level": "ERROR",
"propagate": False, "propagate": False,
}, },
"celery": {
"handlers": ["console", "celery_file"],
"level": "INFO",
"propagate": False,
},
"celery.task": {
"handlers": ["console", "celery_file"],
"level": "INFO",
"propagate": False,
},
}, },
} }

View File

@@ -6,7 +6,13 @@ ENVIRONMENT=${ENVIRONMENT:-production}
echo "Starting in $ENVIRONMENT mode..." echo "Starting in $ENVIRONMENT mode..."
# Ждем PostgreSQL if [ -d "logs" ]; then
echo "Directory logs already exists."
else
echo "Creating logs directory..."
mkdir -p logs
fi
echo "Waiting for PostgreSQL..." echo "Waiting for PostgreSQL..."
until PGPASSWORD=$DB_PASSWORD psql -h "$DB_HOST" -U "$DB_USER" -d "$DB_NAME" -c '\q' 2>/dev/null; do until PGPASSWORD=$DB_PASSWORD psql -h "$DB_HOST" -U "$DB_USER" -d "$DB_NAME" -c '\q' 2>/dev/null; do
echo "PostgreSQL is unavailable - sleeping" echo "PostgreSQL is unavailable - sleeping"
@@ -14,17 +20,14 @@ until PGPASSWORD=$DB_PASSWORD psql -h "$DB_HOST" -U "$DB_USER" -d "$DB_NAME" -c
done done
echo "PostgreSQL started" echo "PostgreSQL started"
# Выполняем миграции
echo "Running migrations..." echo "Running migrations..."
uv run python manage.py migrate --noinput uv run python manage.py migrate --noinput
# Собираем статику (только для production)
if [ "$ENVIRONMENT" = "production" ]; then if [ "$ENVIRONMENT" = "production" ]; then
echo "Collecting static files..." echo "Collecting static files..."
uv run python manage.py collectstatic --noinput uv run python manage.py collectstatic --noinput
fi fi
# Запускаем сервер в зависимости от окружения
if [ "$ENVIRONMENT" = "development" ]; then if [ "$ENVIRONMENT" = "development" ]; then
echo "Starting Django development server..." echo "Starting Django development server..."
exec uv run python manage.py runserver 0.0.0.0:8000 exec uv run python manage.py runserver 0.0.0.0:8000

View File

@@ -554,7 +554,29 @@
}); });
} }
// Остальной ваш JavaScript код остается без изменений // Column visibility functions with localStorage support
function getColumnVisibilityKey() {
return 'objitemListColumnVisibility';
}
function saveColumnVisibility() {
const columnCheckboxes = document.querySelectorAll('.column-toggle');
const visibility = {};
columnCheckboxes.forEach(checkbox => {
const columnIndex = checkbox.getAttribute('data-column');
visibility[columnIndex] = checkbox.checked;
});
localStorage.setItem(getColumnVisibilityKey(), JSON.stringify(visibility));
}
function loadColumnVisibility() {
const saved = localStorage.getItem(getColumnVisibilityKey());
if (saved) {
return JSON.parse(saved);
}
return null;
}
function toggleColumn(checkbox) { function toggleColumn(checkbox) {
const columnIndex = parseInt(checkbox.getAttribute('data-column')); const columnIndex = parseInt(checkbox.getAttribute('data-column'));
const table = document.querySelector('.table'); const table = document.querySelector('.table');
@@ -569,7 +591,27 @@
cell.style.display = 'none'; cell.style.display = 'none';
}); });
} }
// Save state after toggle
saveColumnVisibility();
} }
function toggleColumnWithoutSave(checkbox) {
const columnIndex = parseInt(checkbox.getAttribute('data-column'));
const table = document.querySelector('.table');
const cells = table.querySelectorAll(`td:nth-child(${columnIndex + 1}), th:nth-child(${columnIndex + 1})`);
if (checkbox.checked) {
cells.forEach(cell => {
cell.style.display = '';
});
} else {
cells.forEach(cell => {
cell.style.display = 'none';
});
}
}
function toggleAllColumns(selectAllCheckbox) { function toggleAllColumns(selectAllCheckbox) {
const columnCheckboxes = document.querySelectorAll('.column-toggle'); const columnCheckboxes = document.querySelectorAll('.column-toggle');
columnCheckboxes.forEach(checkbox => { columnCheckboxes.forEach(checkbox => {
@@ -734,36 +776,32 @@
// Initialize column visibility - hide creation columns by default // Initialize column visibility - hide creation columns by default
function initColumnVisibility() { function initColumnVisibility() {
const creationDateCheckbox = document.querySelector('input[data-column="15"]'); const savedVisibility = loadColumnVisibility();
const creationUserCheckbox = document.querySelector('input[data-column="16"]');
if (creationDateCheckbox) {
creationDateCheckbox.checked = false;
toggleColumn(creationDateCheckbox);
}
if (creationUserCheckbox) { if (savedVisibility) {
creationUserCheckbox.checked = false; // Restore saved state
toggleColumn(creationUserCheckbox); const columnCheckboxes = document.querySelectorAll('.column-toggle');
} columnCheckboxes.forEach(checkbox => {
const columnIndex = checkbox.getAttribute('data-column');
if (savedVisibility.hasOwnProperty(columnIndex)) {
checkbox.checked = savedVisibility[columnIndex];
toggleColumnWithoutSave(checkbox);
}
});
} else {
// Default state: hide specific columns
const columnsToHide = [15, 16, 17, 18, 19]; // Создано, Кем(созд), Комментарий, Усреднённое, Стандарт
// Hide comment, is_average, and standard columns by default columnsToHide.forEach(columnIndex => {
const commentCheckbox = document.querySelector('input[data-column="17"]'); const checkbox = document.querySelector(`input[data-column="${columnIndex}"]`);
const isAverageCheckbox = document.querySelector('input[data-column="18"]'); if (checkbox) {
const standardCheckbox = document.querySelector('input[data-column="19"]'); checkbox.checked = false;
toggleColumnWithoutSave(checkbox);
}
});
if (commentCheckbox) { // Save initial state
commentCheckbox.checked = false; saveColumnVisibility();
toggleColumn(commentCheckbox);
}
if (isAverageCheckbox) {
isAverageCheckbox.checked = false;
toggleColumn(isAverageCheckbox);
}
if (standardCheckbox) {
standardCheckbox.checked = false;
toggleColumn(standardCheckbox);
} }
} }
// Filter counter functionality // Filter counter functionality

View File

@@ -1054,7 +1054,29 @@ function updateFilterCounter() {
} }
} }
// Column visibility functions // Column visibility functions with localStorage support
function getColumnVisibilityKey() {
return 'sourceListColumnVisibility';
}
function saveColumnVisibility() {
const columnCheckboxes = document.querySelectorAll('.column-toggle');
const visibility = {};
columnCheckboxes.forEach(checkbox => {
const columnIndex = checkbox.getAttribute('data-column');
visibility[columnIndex] = checkbox.checked;
});
localStorage.setItem(getColumnVisibilityKey(), JSON.stringify(visibility));
}
function loadColumnVisibility() {
const saved = localStorage.getItem(getColumnVisibilityKey());
if (saved) {
return JSON.parse(saved);
}
return null;
}
function toggleColumn(checkbox) { function toggleColumn(checkbox) {
const columnIndex = parseInt(checkbox.getAttribute('data-column')); const columnIndex = parseInt(checkbox.getAttribute('data-column'));
const table = document.querySelector('.table'); const table = document.querySelector('.table');
@@ -1069,6 +1091,9 @@ function toggleColumn(checkbox) {
cell.style.display = 'none'; cell.style.display = 'none';
}); });
} }
// Save state after toggle
saveColumnVisibility();
} }
function toggleAllColumns(selectAllCheckbox) { function toggleAllColumns(selectAllCheckbox) {
@@ -1081,17 +1106,52 @@ function toggleAllColumns(selectAllCheckbox) {
// Initialize column visibility - hide Создано and Обновлено columns by default // Initialize column visibility - hide Создано and Обновлено columns by default
function initColumnVisibility() { function initColumnVisibility() {
const createdAtCheckbox = document.querySelector('input[data-column="11"]'); const savedVisibility = loadColumnVisibility();
const updatedAtCheckbox = document.querySelector('input[data-column="12"]');
if (createdAtCheckbox) { if (savedVisibility) {
createdAtCheckbox.checked = false; // Restore saved state
toggleColumn(createdAtCheckbox); const columnCheckboxes = document.querySelectorAll('.column-toggle');
columnCheckboxes.forEach(checkbox => {
const columnIndex = checkbox.getAttribute('data-column');
if (savedVisibility.hasOwnProperty(columnIndex)) {
checkbox.checked = savedVisibility[columnIndex];
toggleColumnWithoutSave(checkbox);
}
});
} else {
// Default state: hide Создано and Обновлено columns
const createdAtCheckbox = document.querySelector('input[data-column="11"]');
const updatedAtCheckbox = document.querySelector('input[data-column="12"]');
if (createdAtCheckbox) {
createdAtCheckbox.checked = false;
toggleColumnWithoutSave(createdAtCheckbox);
}
if (updatedAtCheckbox) {
updatedAtCheckbox.checked = false;
toggleColumnWithoutSave(updatedAtCheckbox);
}
// Save initial state
saveColumnVisibility();
} }
}
if (updatedAtCheckbox) { // Helper function to toggle without saving (used during initialization)
updatedAtCheckbox.checked = false; function toggleColumnWithoutSave(checkbox) {
toggleColumn(updatedAtCheckbox); const columnIndex = parseInt(checkbox.getAttribute('data-column'));
const table = document.querySelector('.table');
const cells = table.querySelectorAll(`td:nth-child(${columnIndex + 1}), th:nth-child(${columnIndex + 1})`);
if (checkbox.checked) {
cells.forEach(cell => {
cell.style.display = '';
});
} else {
cells.forEach(cell => {
cell.style.display = 'none';
});
} }
} }
@@ -1366,6 +1426,29 @@ function setupModalSelectAll() {
} }
} }
// Modal column visibility functions with localStorage support
function getModalColumnVisibilityKey() {
return 'sourceListModalColumnVisibility';
}
function saveModalColumnVisibility() {
const columnCheckboxes = document.querySelectorAll('.modal-column-toggle');
const visibility = {};
columnCheckboxes.forEach(checkbox => {
const columnIndex = checkbox.getAttribute('data-column');
visibility[columnIndex] = checkbox.checked;
});
localStorage.setItem(getModalColumnVisibilityKey(), JSON.stringify(visibility));
}
function loadModalColumnVisibility() {
const saved = localStorage.getItem(getModalColumnVisibilityKey());
if (saved) {
return JSON.parse(saved);
}
return null;
}
// Function to toggle modal column visibility // Function to toggle modal column visibility
function toggleModalColumn(checkbox) { function toggleModalColumn(checkbox) {
const columnIndex = parseInt(checkbox.getAttribute('data-column')); const columnIndex = parseInt(checkbox.getAttribute('data-column'));
@@ -1390,6 +1473,9 @@ function toggleModalColumn(checkbox) {
} }
} }
}); });
// Save state after toggle
saveModalColumnVisibility();
} }
// Function to toggle all modal columns // Function to toggle all modal columns
@@ -1401,38 +1487,80 @@ function toggleAllModalColumns(selectAllCheckbox) {
}); });
} }
// Initialize modal column visibility // Helper function to toggle modal column without saving
function initModalColumnVisibility() { function toggleModalColumnWithoutSave(checkbox) {
// Hide columns by default: Создано (16), Кем(созд) (17), Комментарий (18), Усреднённое (19), Стандарт (20), Sigma (22) const columnIndex = parseInt(checkbox.getAttribute('data-column'));
const columnsToHide = [16, 17, 18, 19, 20, 22];
// Get the specific tbody for objitems
const tbody = document.getElementById('objitemTableBody'); const tbody = document.getElementById('objitemTableBody');
if (!tbody) { if (!tbody) return;
console.log('objitemTableBody not found');
return;
}
// Get the parent table
const table = tbody.closest('table'); const table = tbody.closest('table');
if (!table) { if (!table) return;
console.log('Table not found');
return;
}
// Hide columns that should be hidden by default const rows = table.querySelectorAll('tr');
columnsToHide.forEach(columnIndex => { rows.forEach(row => {
// Get all rows in the table (including thead and tbody) const cells = row.children;
const rows = table.querySelectorAll('tr'); if (cells[columnIndex]) {
rows.forEach(row => { if (checkbox.checked) {
const cells = row.children; cells[columnIndex].style.removeProperty('display');
if (cells[columnIndex]) { } else {
cells[columnIndex].style.setProperty('display', 'none', 'important'); cells[columnIndex].style.setProperty('display', 'none', 'important');
} }
}); }
}); });
} }
// Initialize modal column visibility
function initModalColumnVisibility() {
const savedVisibility = loadModalColumnVisibility();
if (savedVisibility) {
// Restore saved state
const columnCheckboxes = document.querySelectorAll('.modal-column-toggle');
columnCheckboxes.forEach(checkbox => {
const columnIndex = checkbox.getAttribute('data-column');
if (savedVisibility.hasOwnProperty(columnIndex)) {
checkbox.checked = savedVisibility[columnIndex];
toggleModalColumnWithoutSave(checkbox);
}
});
} else {
// Default state: hide columns by default: Создано (16), Кем(созд) (17), Комментарий (18), Усреднённое (19), Стандарт (20), Sigma (22)
const columnsToHide = [16, 17, 18, 19, 20, 22];
const tbody = document.getElementById('objitemTableBody');
if (!tbody) {
console.log('objitemTableBody not found');
return;
}
const table = tbody.closest('table');
if (!table) {
console.log('Table not found');
return;
}
// Update checkboxes and hide columns
columnsToHide.forEach(columnIndex => {
const checkbox = document.querySelector(`.modal-column-toggle[data-column="${columnIndex}"]`);
if (checkbox) {
checkbox.checked = false;
}
const rows = table.querySelectorAll('tr');
rows.forEach(row => {
const cells = row.children;
if (cells[columnIndex]) {
cells[columnIndex].style.setProperty('display', 'none', 'important');
}
});
});
// Save initial state
saveModalColumnVisibility();
}
}
// Function to show LyngSat modal // Function to show LyngSat modal
function showLyngsatModal(lyngsatId) { function showLyngsatModal(lyngsatId) {
const modal = new bootstrap.Modal(document.getElementById('lyngsatModal')); const modal = new bootstrap.Modal(document.getElementById('lyngsatModal'));

File diff suppressed because it is too large Load Diff

View File

@@ -9,6 +9,7 @@ services:
- db - db
volumes: volumes:
- static_volume:/app/staticfiles - static_volume:/app/staticfiles
- ./logs:/app/logs
expose: expose:
- 8000 - 8000
@@ -18,12 +19,14 @@ services:
dockerfile: Dockerfile dockerfile: Dockerfile
env_file: env_file:
- .env.prod - .env.prod
entrypoint: [] #entrypoint: []
command: ["uv", "run", "celery", "-A", "dbapp", "worker", "--loglevel=INFO"] command: ["uv", "run", "celery", "-A", "dbapp", "worker", "--loglevel=INFO"]
depends_on: depends_on:
- db - db
- redis - redis
- web - web
volumes:
- ./logs:/app/logs
redis: redis:
image: redis:7-alpine image: redis:7-alpine
@@ -53,7 +56,6 @@ services:
volumes: volumes:
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
- static_volume:/usr/share/nginx/html/static - static_volume:/usr/share/nginx/html/static
# если у тебя медиа — можно замонтировать том media
volumes: volumes:
pgdata: pgdata: