diff --git a/logs_collector/account/__init__.py b/logs_collector/apps/__init__.py similarity index 100% rename from logs_collector/account/__init__.py rename to logs_collector/apps/__init__.py diff --git a/logs_collector/account/migrations/__init__.py b/logs_collector/apps/account/__init__.py similarity index 100% rename from logs_collector/account/migrations/__init__.py rename to logs_collector/apps/account/__init__.py diff --git a/logs_collector/account/admin.py b/logs_collector/apps/account/admin.py similarity index 100% rename from logs_collector/account/admin.py rename to logs_collector/apps/account/admin.py diff --git a/logs_collector/account/apps.py b/logs_collector/apps/account/apps.py similarity index 62% rename from logs_collector/account/apps.py rename to logs_collector/apps/account/apps.py index 2b08f1a..7b95a04 100644 --- a/logs_collector/account/apps.py +++ b/logs_collector/apps/account/apps.py @@ -3,4 +3,5 @@ from django.apps import AppConfig class AccountConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' - name = 'account' + name = 'apps.account' + verbose_name = 'Auth and account management' diff --git a/logs_collector/collector/__init__.py b/logs_collector/apps/account/migrations/__init__.py similarity index 100% rename from logs_collector/collector/__init__.py rename to logs_collector/apps/account/migrations/__init__.py diff --git a/logs_collector/account/models.py b/logs_collector/apps/account/models.py similarity index 100% rename from logs_collector/account/models.py rename to logs_collector/apps/account/models.py diff --git a/logs_collector/account/tests.py b/logs_collector/apps/account/tests.py similarity index 100% rename from logs_collector/account/tests.py rename to logs_collector/apps/account/tests.py diff --git a/logs_collector/account/urls.py b/logs_collector/apps/account/urls.py similarity index 96% rename from logs_collector/account/urls.py rename to logs_collector/apps/account/urls.py index f7f1785..e900925 100644 --- a/logs_collector/account/urls.py +++ b/logs_collector/apps/account/urls.py @@ -14,7 +14,7 @@ app_name = 'account' urlpatterns = [ # WEB LOGOUT: path( - 'accounts/logout/', + 'account/logout/', LogoutView.as_view(next_page=settings.LOGOUT_REDIRECT_URL), name='logout' ) diff --git a/logs_collector/account/utils.py b/logs_collector/apps/account/utils.py similarity index 100% rename from logs_collector/account/utils.py rename to logs_collector/apps/account/utils.py diff --git a/logs_collector/account/views.py b/logs_collector/apps/account/views.py similarity index 100% rename from logs_collector/account/views.py rename to logs_collector/apps/account/views.py diff --git a/logs_collector/collector/migrations/__init__.py b/logs_collector/apps/collector/__init__.py similarity index 100% rename from logs_collector/collector/migrations/__init__.py rename to logs_collector/apps/collector/__init__.py diff --git a/logs_collector/collector/admin.py b/logs_collector/apps/collector/admin.py similarity index 100% rename from logs_collector/collector/admin.py rename to logs_collector/apps/collector/admin.py diff --git a/logs_collector/collector/templatetags/__init__.py b/logs_collector/apps/collector/api/__init__.py similarity index 100% rename from logs_collector/collector/templatetags/__init__.py rename to logs_collector/apps/collector/api/__init__.py diff --git a/logs_collector/collector/filters.py b/logs_collector/apps/collector/api/filters.py similarity index 94% rename from logs_collector/collector/filters.py rename to logs_collector/apps/collector/api/filters.py index ab1b9c6..be4e913 100644 --- a/logs_collector/collector/filters.py +++ b/logs_collector/apps/collector/api/filters.py @@ -5,7 +5,7 @@ from django_filters.rest_framework import ( ) from django_filters import widgets -from .models import Archive, Ticket +from apps.collector.models import Archive, Ticket from .utils import DateTimeFilterMixin diff --git a/logs_collector/collector/permissions.py b/logs_collector/apps/collector/api/permissions.py similarity index 100% rename from logs_collector/collector/permissions.py rename to logs_collector/apps/collector/api/permissions.py diff --git a/logs_collector/collector/serializers.py b/logs_collector/apps/collector/api/serializers.py similarity index 96% rename from logs_collector/collector/serializers.py rename to logs_collector/apps/collector/api/serializers.py index 00bb7fa..affc8d8 100644 --- a/logs_collector/collector/serializers.py +++ b/logs_collector/apps/collector/api/serializers.py @@ -3,7 +3,7 @@ from rest_framework import serializers from drf_spectacular.utils import extend_schema_field from drf_spectacular.openapi import OpenApiTypes -from .models import Archive, Platform, Ticket +from apps.collector.models import Archive, Platform, Ticket @extend_schema_field(OpenApiTypes.NUMBER) diff --git a/logs_collector/apps/collector/api/urls.py b/logs_collector/apps/collector/api/urls.py new file mode 100644 index 0000000..ab94f7b --- /dev/null +++ b/logs_collector/apps/collector/api/urls.py @@ -0,0 +1,21 @@ +from django.urls import path, include + +from rest_framework import routers + +from . import views + +# ▄▀█ █▀█ █ +# █▀█ █▀▀ █ +# -- -- -- + +app_name = 'collector_api' + +router = routers.DefaultRouter() +router.register(r'archives', views.ArchiveViewSet) +router.register(r'platforms', views.PlatformViewSet) +router.register(r'tickets', views.TicketViewSet) + +urlpatterns = [ + # CRUD: + path('v1/', include(router.urls)), +] diff --git a/logs_collector/apps/collector/api/utils.py b/logs_collector/apps/collector/api/utils.py new file mode 100644 index 0000000..7f04647 --- /dev/null +++ b/logs_collector/apps/collector/api/utils.py @@ -0,0 +1,20 @@ +from django_filters import NumberFilter + + +class DateTimeFilterMixin: + year__gte = NumberFilter( + field_name='time_create', + lookup_expr='year__gte' + ) + year__lte = NumberFilter( + field_name='time_create', + lookup_expr='year__lte' + ) + month__gte = NumberFilter( + field_name='time_create', + lookup_expr='month__gte' + ) + month__lte = NumberFilter( + field_name='time_create', + lookup_expr='month__lte' + ) diff --git a/logs_collector/collector/views.py b/logs_collector/apps/collector/api/views.py similarity index 52% rename from logs_collector/collector/views.py rename to logs_collector/apps/collector/api/views.py index 0ff5bd4..1b26aa5 100644 --- a/logs_collector/collector/views.py +++ b/logs_collector/apps/collector/api/views.py @@ -1,9 +1,4 @@ from django.core.exceptions import ValidationError, ObjectDoesNotExist -from django.contrib.auth.mixins import LoginRequiredMixin -from django.http import FileResponse -from django.views import generic -from django.views.generic.detail import SingleObjectMixin -from django.db.models import Q from rest_framework import status # from rest_framework.decorators import action @@ -15,14 +10,10 @@ from rest_framework import filters from django_filters.rest_framework import DjangoFilterBackend -from two_factor.views import OTPRequiredMixin +from apps.collector.models import Archive, Ticket, Platform # ??????? -from .models import Archive, Ticket, Platform -from .forms import TicketForm from .filters import ArchiveFilter, TicketFilter -from .utils import PageTitleViewMixin from .permissions import IsGuestUpload - from .serializers import ( PublicArchiveUploadSerializer, ArchiveSerializer, @@ -31,104 +22,6 @@ from .serializers import ( ) -class ArchiveHandlerView( - OTPRequiredMixin, - LoginRequiredMixin, - SingleObjectMixin, - generic.View): - model = Archive - slug_field = 'file' - slug_url_kwarg = 'path' - - def get(self, request, path): - self.object = self.get_object() - return FileResponse(self.object.file) - - -class CreateTicket(LoginRequiredMixin, PageTitleViewMixin, generic.CreateView): - model = Ticket - form_class = TicketForm - template_name = 'collector/ticket_create.html' - - def get_title(self): - return f'{self.title} - create' - - def form_valid(self, form): - form.instance.user = self.request.user - return super().form_valid(form) - - -class UpdateTicket(LoginRequiredMixin, PageTitleViewMixin, generic.UpdateView): - model = Ticket - form_class = TicketForm - template_name = 'collector/ticket_create.html' - slug_field = 'number' - slug_url_kwarg = 'ticket' - - def get_title(self, **kwargs): - return f'{self.title} - {self.kwargs.get("ticket", "update")}' - - def form_valid(self, form): - form.instance.user = self.request.user - return super().form_valid(form) - - -class ListAllTickets(LoginRequiredMixin, PageTitleViewMixin, generic.ListView): - model = Ticket - template_name = 'collector/tickets.html' - context_object_name = 'tickets' - paginate_by = 5 - title = 'Collector - tickets' - - def get_queryset(self): - search_query = self.request.GET.get('search', '') - if search_query: - query_list = [] - try: - for item in search_query.split(','): - query_list.append(int(item)) - except ValueError: - return super().get_queryset() - queryset = self.model.objects.filter( - Q(number__in=query_list) | Q(number__icontains=query_list[0]) - ) - self.paginate_by = 100 # ? fake disable pagination) - return queryset - - return super().get_queryset() - - -class ListPlatformTickets( - LoginRequiredMixin, - PageTitleViewMixin, - generic.ListView - ): - model = Ticket - template_name = 'collector/tickets.html' - context_object_name = 'tickets' - # allow_empty = False - paginate_by = 5 - - def get_title(self, **kwargs): - return f'{self.title} - {self.kwargs.get("platform", "tickets")}' - - def get_queryset(self): - return Ticket.objects.filter( - platform__name=self.kwargs.get('platform') - ) - - -class DetailTicket(LoginRequiredMixin, PageTitleViewMixin, generic.DetailView): - model = Ticket - template_name = 'collector/ticket.html' - context_object_name = 'ticket' - slug_field = 'number' - slug_url_kwarg = 'ticket' - - def get_title(self, **kwargs): - return f'{self.title} - {self.kwargs.get("ticket", "show")}' - - class ArchiveViewSet(viewsets.ModelViewSet): queryset = Archive.objects.order_by('-time_create') serializer_class = ArchiveSerializer diff --git a/logs_collector/collector/apps.py b/logs_collector/apps/collector/apps.py similarity index 61% rename from logs_collector/collector/apps.py rename to logs_collector/apps/collector/apps.py index 0117b57..0db3de5 100644 --- a/logs_collector/collector/apps.py +++ b/logs_collector/apps/collector/apps.py @@ -3,4 +3,5 @@ from django.apps import AppConfig class CollectorConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' - name = 'collector' + name = 'apps.collector' + verbose_name = 'Collector archives for analyse' diff --git a/logs_collector/collector/forms.py b/logs_collector/apps/collector/forms.py similarity index 100% rename from logs_collector/collector/forms.py rename to logs_collector/apps/collector/forms.py diff --git a/logs_collector/collector/migrations/0001_initial.py b/logs_collector/apps/collector/migrations/0001_initial.py similarity index 63% rename from logs_collector/collector/migrations/0001_initial.py rename to logs_collector/apps/collector/migrations/0001_initial.py index 68419ac..4fd914f 100644 --- a/logs_collector/collector/migrations/0001_initial.py +++ b/logs_collector/apps/collector/migrations/0001_initial.py @@ -1,11 +1,13 @@ -# Generated by Django 4.2 on 2023-07-28 14:40 +# Generated by Django 4.2 on 2023-08-14 09:07 -import collector.utils +import apps.collector.utils from django.conf import settings import django.core.files.storage +import django.core.validators from django.db import migrations, models import django.db.models.deletion import pathlib +import uuid class Migration(migrations.Migration): @@ -21,7 +23,7 @@ class Migration(migrations.Migration): name='Platform', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=20)), + ('name', models.CharField(max_length=20, unique=True)), ('pretty_name', models.CharField(max_length=20)), ], ), @@ -29,26 +31,29 @@ class Migration(migrations.Migration): name='Ticket', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('number', models.IntegerField()), + ('number', models.IntegerField(db_index=True, unique=True)), ('resolved', models.BooleanField(default=False)), ('note', models.TextField(blank=True)), + ('token', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)), + ('attempts', models.IntegerField(default=5, validators=[django.core.validators.MaxValueValidator(10), django.core.validators.MinValueValidator(0)])), ('time_create', models.DateTimeField(auto_now_add=True)), ('time_update', models.DateTimeField(auto_now=True)), - ('platform', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='collector.platform')), + ('platform', models.ForeignKey(db_column='platform_name', on_delete=django.db.models.deletion.CASCADE, to='collector.platform', to_field='name')), ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], + options={ + 'ordering': ['-time_create'], + }, ), migrations.CreateModel( name='Archive', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('file', models.FileField(blank=True, null=True, storage=django.core.files.storage.FileSystemStorage(base_url='/archives/', location=pathlib.PurePosixPath('/home/stepan/Documents/Dev/ISPsystem/logs-collector/logs_collector/archives')), upload_to=collector.utils.logs_dir_path)), - ('size', models.CharField(blank=True, max_length=50)), - ('sha1', models.CharField(editable=False, max_length=1024)), + ('file', models.FileField(blank=True, null=True, storage=django.core.files.storage.FileSystemStorage(base_url='/archives/', location=pathlib.PurePosixPath('/home/stepan/Documents/Dev/ISPsystem/logs-collector/logs_collector/archives')), upload_to=apps.collector.utils.logs_dir_path)), + ('md5', models.CharField(editable=False, max_length=1024)), ('time_create', models.DateTimeField(auto_now_add=True)), ('time_update', models.DateTimeField(auto_now=True)), - ('ticket', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='collector.ticket')), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ('ticket', models.ForeignKey(db_column='ticket_number', on_delete=django.db.models.deletion.CASCADE, to='collector.ticket', to_field='number')), ], ), ] diff --git a/logs_collector/apps/collector/migrations/__init__.py b/logs_collector/apps/collector/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/logs_collector/collector/models.py b/logs_collector/apps/collector/models.py similarity index 100% rename from logs_collector/collector/models.py rename to logs_collector/apps/collector/models.py diff --git a/logs_collector/collector/static/collector/css/bootstrap.min.css b/logs_collector/apps/collector/static/collector/css/bootstrap.min.css similarity index 100% rename from logs_collector/collector/static/collector/css/bootstrap.min.css rename to logs_collector/apps/collector/static/collector/css/bootstrap.min.css diff --git a/logs_collector/collector/static/collector/css/bootstrap.min.css.map b/logs_collector/apps/collector/static/collector/css/bootstrap.min.css.map similarity index 100% rename from logs_collector/collector/static/collector/css/bootstrap.min.css.map rename to logs_collector/apps/collector/static/collector/css/bootstrap.min.css.map diff --git a/logs_collector/collector/static/collector/img/android-chrome-192x192.png b/logs_collector/apps/collector/static/collector/img/android-chrome-192x192.png similarity index 100% rename from logs_collector/collector/static/collector/img/android-chrome-192x192.png rename to logs_collector/apps/collector/static/collector/img/android-chrome-192x192.png diff --git a/logs_collector/collector/static/collector/img/android-chrome-512x512.png b/logs_collector/apps/collector/static/collector/img/android-chrome-512x512.png similarity index 100% rename from logs_collector/collector/static/collector/img/android-chrome-512x512.png rename to logs_collector/apps/collector/static/collector/img/android-chrome-512x512.png diff --git a/logs_collector/collector/static/collector/img/apple-touch-icon.png b/logs_collector/apps/collector/static/collector/img/apple-touch-icon.png similarity index 100% rename from logs_collector/collector/static/collector/img/apple-touch-icon.png rename to logs_collector/apps/collector/static/collector/img/apple-touch-icon.png diff --git a/logs_collector/collector/static/collector/img/favicon-16x16.png b/logs_collector/apps/collector/static/collector/img/favicon-16x16.png similarity index 100% rename from logs_collector/collector/static/collector/img/favicon-16x16.png rename to logs_collector/apps/collector/static/collector/img/favicon-16x16.png diff --git a/logs_collector/collector/static/collector/img/favicon-32x32.png b/logs_collector/apps/collector/static/collector/img/favicon-32x32.png similarity index 100% rename from logs_collector/collector/static/collector/img/favicon-32x32.png rename to logs_collector/apps/collector/static/collector/img/favicon-32x32.png diff --git a/logs_collector/collector/static/collector/img/favicon.ico b/logs_collector/apps/collector/static/collector/img/favicon.ico similarity index 100% rename from logs_collector/collector/static/collector/img/favicon.ico rename to logs_collector/apps/collector/static/collector/img/favicon.ico diff --git a/logs_collector/collector/static/collector/img/site.webmanifest b/logs_collector/apps/collector/static/collector/img/site.webmanifest similarity index 100% rename from logs_collector/collector/static/collector/img/site.webmanifest rename to logs_collector/apps/collector/static/collector/img/site.webmanifest diff --git a/logs_collector/collector/static/collector/js/bootstrap.bundle.min.js b/logs_collector/apps/collector/static/collector/js/bootstrap.bundle.min.js similarity index 100% rename from logs_collector/collector/static/collector/js/bootstrap.bundle.min.js rename to logs_collector/apps/collector/static/collector/js/bootstrap.bundle.min.js diff --git a/logs_collector/collector/static/collector/js/bootstrap.bundle.min.js.map b/logs_collector/apps/collector/static/collector/js/bootstrap.bundle.min.js.map similarity index 100% rename from logs_collector/collector/static/collector/js/bootstrap.bundle.min.js.map rename to logs_collector/apps/collector/static/collector/js/bootstrap.bundle.min.js.map diff --git a/logs_collector/collector/static/collector/js/bs.theme.mode.js b/logs_collector/apps/collector/static/collector/js/bs.theme.mode.js similarity index 100% rename from logs_collector/collector/static/collector/js/bs.theme.mode.js rename to logs_collector/apps/collector/static/collector/js/bs.theme.mode.js diff --git a/logs_collector/collector/static/collector/js/bs.tooltip.js b/logs_collector/apps/collector/static/collector/js/bs.tooltip.js similarity index 100% rename from logs_collector/collector/static/collector/js/bs.tooltip.js rename to logs_collector/apps/collector/static/collector/js/bs.tooltip.js diff --git a/logs_collector/collector/static/collector/js/jq.ticket.detail.js b/logs_collector/apps/collector/static/collector/js/jq.ticket.detail.js similarity index 100% rename from logs_collector/collector/static/collector/js/jq.ticket.detail.js rename to logs_collector/apps/collector/static/collector/js/jq.ticket.detail.js diff --git a/logs_collector/collector/static/collector/js/jquery-3.7.0.min.js b/logs_collector/apps/collector/static/collector/js/jquery-3.7.0.min.js similarity index 100% rename from logs_collector/collector/static/collector/js/jquery-3.7.0.min.js rename to logs_collector/apps/collector/static/collector/js/jquery-3.7.0.min.js diff --git a/logs_collector/apps/collector/templates/collector/base.html b/logs_collector/apps/collector/templates/collector/base.html new file mode 100644 index 0000000..53003c2 --- /dev/null +++ b/logs_collector/apps/collector/templates/collector/base.html @@ -0,0 +1,30 @@ +{% extends 'base.html' %} +{% load static %} + +{% block collector_head %} +
`s get reset. However, we also reset the\n// bottom margin to use `rem` units instead of `em`.\n\np {\n margin-top: 0;\n margin-bottom: $paragraph-margin-bottom;\n}\n\n\n// Abbreviations\n//\n// 1. Add the correct text decoration in Chrome, Edge, Opera, and Safari.\n// 2. Add explicit cursor to indicate changed behavior.\n// 3. Prevent the text-decoration to be skipped.\n\nabbr[title] {\n text-decoration: underline dotted; // 1\n cursor: help; // 2\n text-decoration-skip-ink: none; // 3\n}\n\n\n// Address\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\n\n// Lists\n\nol,\nul {\n padding-left: 2rem;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: $dt-font-weight;\n}\n\n// 1. Undo browser default\n\ndd {\n margin-bottom: .5rem;\n margin-left: 0; // 1\n}\n\n\n// Blockquote\n\nblockquote {\n margin: 0 0 1rem;\n}\n\n\n// Strong\n//\n// Add the correct font weight in Chrome, Edge, and Safari\n\nb,\nstrong {\n font-weight: $font-weight-bolder;\n}\n\n\n// Small\n//\n// Add the correct font size in all browsers\n\nsmall {\n @include font-size($small-font-size);\n}\n\n\n// Mark\n\nmark {\n padding: $mark-padding;\n background-color: var(--#{$prefix}highlight-bg);\n}\n\n\n// Sub and Sup\n//\n// Prevent `sub` and `sup` elements from affecting the line height in\n// all browsers.\n\nsub,\nsup {\n position: relative;\n @include font-size($sub-sup-font-size);\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub { bottom: -.25em; }\nsup { top: -.5em; }\n\n\n// Links\n\na {\n color: rgba(var(--#{$prefix}link-color-rgb), var(--#{$prefix}link-opacity, 1));\n text-decoration: $link-decoration;\n\n &:hover {\n --#{$prefix}link-color-rgb: var(--#{$prefix}link-hover-color-rgb);\n text-decoration: $link-hover-decoration;\n }\n}\n\n// And undo these styles for placeholder links/named anchors (without href).\n// It would be more straightforward to just use a[href] in previous block, but that\n// causes specificity issues in many other styles that are too complex to fix.\n// See https://github.com/twbs/bootstrap/issues/19402\n\na:not([href]):not([class]) {\n &,\n &:hover {\n color: inherit;\n text-decoration: none;\n }\n}\n\n\n// Code\n\npre,\ncode,\nkbd,\nsamp {\n font-family: $font-family-code;\n @include font-size(1em); // Correct the odd `em` font sizing in all browsers.\n}\n\n// 1. Remove browser default top margin\n// 2. Reset browser default of `1em` to use `rem`s\n// 3. Don't allow content to break outside\n\npre {\n display: block;\n margin-top: 0; // 1\n margin-bottom: 1rem; // 2\n overflow: auto; // 3\n @include font-size($code-font-size);\n color: $pre-color;\n\n // Account for some code outputs that place code tags in pre tags\n code {\n @include font-size(inherit);\n color: inherit;\n word-break: normal;\n }\n}\n\ncode {\n @include font-size($code-font-size);\n color: var(--#{$prefix}code-color);\n word-wrap: break-word;\n\n // Streamline the style when inside anchors to avoid broken underline and more\n a > & {\n color: inherit;\n }\n}\n\nkbd {\n padding: $kbd-padding-y $kbd-padding-x;\n @include font-size($kbd-font-size);\n color: $kbd-color;\n background-color: $kbd-bg;\n @include border-radius($border-radius-sm);\n\n kbd {\n padding: 0;\n @include font-size(1em);\n font-weight: $nested-kbd-font-weight;\n }\n}\n\n\n// Figures\n//\n// Apply a consistent margin strategy (matches our type styles).\n\nfigure {\n margin: 0 0 1rem;\n}\n\n\n// Images and content\n\nimg,\nsvg {\n vertical-align: middle;\n}\n\n\n// Tables\n//\n// Prevent double borders\n\ntable {\n caption-side: bottom;\n border-collapse: collapse;\n}\n\ncaption {\n padding-top: $table-cell-padding-y;\n padding-bottom: $table-cell-padding-y;\n color: $table-caption-color;\n text-align: left;\n}\n\n// 1. Removes font-weight bold by inheriting\n// 2. Matches default `