117 lines
4.0 KiB
Python
117 lines
4.0 KiB
Python
import re
|
|
from collections import namedtuple
|
|
|
|
from django.conf import settings
|
|
from django.contrib import messages
|
|
from django.contrib.contenttypes.models import ContentType
|
|
from django.core.cache import cache
|
|
from django.shortcuts import redirect, render
|
|
from django.utils.translation import gettext_lazy as _
|
|
from django.views.generic import View
|
|
from django_tables2 import RequestConfig
|
|
from packaging import version
|
|
|
|
from extras.constants import DEFAULT_DASHBOARD
|
|
from extras.dashboard.utils import get_dashboard, get_default_dashboard
|
|
from netbox.forms import SearchForm
|
|
from netbox.search import LookupTypes
|
|
from netbox.search.backends import search_backend
|
|
from netbox.tables import SearchTable
|
|
from utilities.htmx import htmx_partial
|
|
from utilities.paginator import EnhancedPaginator, get_paginate_count
|
|
|
|
__all__ = (
|
|
'HomeView',
|
|
'SearchView',
|
|
)
|
|
|
|
Link = namedtuple('Link', ('label', 'viewname', 'permission', 'count'))
|
|
|
|
|
|
class HomeView(View):
|
|
template_name = 'home.html'
|
|
|
|
def get(self, request):
|
|
if settings.LOGIN_REQUIRED and not request.user.is_authenticated:
|
|
return redirect('login')
|
|
|
|
# Construct the user's custom dashboard layout
|
|
try:
|
|
dashboard = get_dashboard(request.user).get_layout()
|
|
except Exception:
|
|
messages.error(request, _(
|
|
"There was an error loading the dashboard configuration. A default dashboard is in use."
|
|
))
|
|
dashboard = get_default_dashboard(config=DEFAULT_DASHBOARD).get_layout()
|
|
|
|
# Check whether a new release is available. (Only for staff/superusers.)
|
|
new_release = None
|
|
if request.user.is_staff or request.user.is_superuser:
|
|
latest_release = cache.get('latest_release')
|
|
if latest_release:
|
|
release_version, release_url = latest_release
|
|
if release_version > version.parse(settings.VERSION):
|
|
new_release = {
|
|
'version': str(release_version),
|
|
'url': release_url,
|
|
}
|
|
|
|
return render(request, self.template_name, {
|
|
'dashboard': dashboard,
|
|
'new_release': new_release,
|
|
})
|
|
|
|
|
|
class SearchView(View):
|
|
|
|
def get(self, request):
|
|
results = []
|
|
highlight = None
|
|
|
|
# Initialize search form
|
|
form = SearchForm(request.GET) if 'q' in request.GET else SearchForm()
|
|
|
|
if form.is_valid():
|
|
|
|
# Restrict results by object type
|
|
object_types = []
|
|
for obj_type in form.cleaned_data['obj_types']:
|
|
app_label, model_name = obj_type.split('.')
|
|
object_types.append(ContentType.objects.get_by_natural_key(app_label, model_name))
|
|
|
|
lookup = form.cleaned_data['lookup'] or LookupTypes.PARTIAL
|
|
results = search_backend.search(
|
|
form.cleaned_data['q'],
|
|
user=request.user,
|
|
object_types=object_types,
|
|
lookup=lookup
|
|
)
|
|
|
|
# If performing a regex search, pass the highlight value as a compiled pattern
|
|
if form.cleaned_data['lookup'] == LookupTypes.REGEX:
|
|
try:
|
|
highlight = re.compile(f"({form.cleaned_data['q']})", flags=re.IGNORECASE)
|
|
except re.error:
|
|
pass
|
|
elif form.cleaned_data['lookup'] != LookupTypes.EXACT:
|
|
highlight = form.cleaned_data['q']
|
|
|
|
table = SearchTable(results, highlight=highlight)
|
|
|
|
# Paginate the table results
|
|
RequestConfig(request, {
|
|
'paginator_class': EnhancedPaginator,
|
|
'per_page': get_paginate_count(request)
|
|
}).configure(table)
|
|
|
|
# If this is an HTMX request, return only the rendered table HTML
|
|
if htmx_partial(request):
|
|
return render(request, 'htmx/table.html', {
|
|
'table': table,
|
|
})
|
|
|
|
return render(request, 'search.html', {
|
|
'form': form,
|
|
'table': table,
|
|
})
|