PMS_integrations admin template

This commit is contained in:
2024-12-11 18:59:06 +09:00
parent 806c611cc7
commit 6a3e6d5a65
5 changed files with 162 additions and 35 deletions

View File

@@ -1,13 +1,13 @@
from django.contrib import admin
# Register your models here.
from .manager import PluginLoader
from django.http import HttpResponseRedirect
from django.urls import path
from django.utils.html import format_html
from django.shortcuts import render
from django import forms
from django.utils.html import format_html
from django.http import HttpResponseRedirect
from .manager import PluginLoader
from pms_integration.models import PMSConfiguration, PMSIntegrationLog
from django import forms
from pms_integration.utils import get_all_plugins
from django.urls import reverse
class PMSConfigurationForm(forms.ModelForm):
class Meta:
@@ -16,7 +16,6 @@ class PMSConfigurationForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Загружаем доступные плагины
plugins = PluginLoader.load_plugins()
plugin_choices = [(plugin_name, plugin_name) for plugin_name in plugins.keys()]
self.fields['plugin_name'] = forms.ChoiceField(choices=plugin_choices, required=False)
@@ -24,21 +23,40 @@ class PMSConfigurationForm(forms.ModelForm):
@admin.register(PMSConfiguration)
class PMSConfigurationAdmin(admin.ModelAdmin):
form = PMSConfigurationForm
list_display = ('name', 'plugin_name', 'created_at')
list_display = ('name', 'plugin_name', 'created_at', 'check_plugins_button')
search_fields = ('name', 'plugin_name')
ordering = ('-created_at',)
def save_model(self, request, obj, form, change):
# Проверка на наличие плагина
plugins = PluginLoader.load_plugins()
if obj.plugin_name and obj.plugin_name not in plugins.keys():
raise ValueError(f"Выберите корректный плагин. '{obj.plugin_name}' нет среди допустимых значений.")
super().save_model(request, obj, form, change)
def check_plugins_button(self, obj=None):
"""
Возвращает кнопку для проверки плагинов.
"""
url = reverse('admin:check-plugins') # Генерируем URL с помощью reverse
return format_html(
'<a class="button" href="{}">Проверить плагины</a>',
url
)
check_plugins_button.short_description = "Действия"
def check_plugins_view(self, request, *args, **kwargs):
"""
Custom admin view to check and display available plugins.
"""
plugins = get_all_plugins()
return render(request, "pms_integration/admin/check_plugins.html", {"plugins": plugins})
def get_urls(self):
"""
Add custom URLs to the admin panel.
"""
urls = super().get_urls()
custom_urls = [
path("check-plugins/", self.admin_site.admin_view(self.check_plugins_view), name="check-plugins"),
]
return custom_urls + urls
@admin.register(PMSIntegrationLog)
class PMSIntegrationLogAdmin(admin.ModelAdmin):
list_display = ('hotel', 'checked_at', 'status', 'message')
search_fields = ('hotel__name', 'status', 'message')
list_filter = ('status', 'checked_at')
ordering = ('-checked_at',)
ordering = ('-checked_at',)

View File

@@ -1,16 +0,0 @@
{% extends "admin/base_site.html" %}
{% block content %}
<h1>Проверка доступных плагинов</h1>
<p>Ниже перечислены плагины, доступные в системе:</p>
<ul>
{% for plugin_name in plugins.keys %}
<li>
<strong>{{ plugin_name }}</strong>: {{ plugins[plugin_name].__doc__ }}
</li>
{% endfor %}
</ul>
<p>
<a class="button" href="{% url 'admin:index' %}">Вернуться в админку</a>
</p>
{% endblock %}

View File

@@ -0,0 +1,104 @@
{% extends 'admin/base.html' %}
{% block content %}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<div class="container mt-4">
<div class="row justify-content-center">
<div class="col-xl-10 col-xxl-9">
<div class="card shadow">
<div class="card-header d-flex flex-wrap justify-content-center align-items-center justify-content-sm-between gap-3">
<h5 class="display-6 text-nowrap text-capitalize mb-0">Загруженные плагины PMS систем</h5>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Plugin Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{% for plugin_name, plugin_info in plugins.items %}
<tr>
<td>{{ plugin_name }}</td>
<td>{{ plugin_info.description|default:"No description available" }}</td>
</tr>
{% empty %}
<tr>
<td colspan="3" class="text-center">Нет доступных плагинов.</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="card-footer">
<a href="{% url 'admin:index' %}" class="btn btn-primary">Вернуться в админку</a>
</div>
</div>
</div>
</div>
</div>
<!-- Modal -->
<div class="modal fade" id="pluginCodeModal" tabindex="-1" aria-labelledby="pluginCodeModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="pluginCodeModalLabel">Подробнее</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<h6><strong>Имя класса:</strong> <span id="className"></span></h6>
<h6><strong>Модуль:</strong> <span id="module"></span></h6>
<hr>
<h6><strong>Код:</strong></h6>
<pre><code id="pluginCode"></code></pre>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Закрыть</button>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
// Настройка модального окна
const modalElement = document.getElementById('pluginCodeModal');
const modal = new bootstrap.Modal(modalElement);
// Обработка кнопки открытия
document.querySelectorAll('.view-plugin').forEach(button => {
button.addEventListener('click', () => {
const pluginName = button.getAttribute('data-plugin-name');
const pluginCode = button.getAttribute('data-plugin-code') || 'Code unavailable';
const className = button.getAttribute('data-class-name') || 'Class name unavailable';
const module = button.getAttribute('data-module') || 'Module unavailable';
// Установка данных в модальное окно
document.getElementById('pluginCodeModalLabel').textContent = `Plugin: ${pluginName}`;
document.getElementById('pluginCode').textContent = pluginCode;
document.getElementById('className').textContent = className;
document.getElementById('module').textContent = module;
modal.show();
});
});
// Убираем размытие после закрытия
modalElement.addEventListener('hidden.bs.modal', () => {
const backdrop = document.querySelector('.modal-backdrop');
if (backdrop) backdrop.remove();
document.body.classList.remove('modal-open');
});
});
</script>
{% endblock %}

21
pms_integration/utils.py Normal file
View File

@@ -0,0 +1,21 @@
from pms_integration.admin import PluginLoader
def get_all_plugins():
"""
Загружает все плагины и возвращает их данные.
:return: Словарь с данными о плагинах.
"""
plugins_data = {}
try:
# Загружаем плагины
plugins = PluginLoader.load_plugins()
for plugin_name, plugin_class in plugins.items():
plugins_data[plugin_name] = {
"class_name": plugin_class.__name__, # Имя класса
"description": plugin_class.__doc__, # Описание из DocString
"module": plugin_class.__module__, # Модуль, где определён класс
}
except Exception as e:
print(f"[ERROR] Ошибка загрузки данных о плагинах: {e}")
return plugins_data