Create: collector models, protect storage, download view

This commit is contained in:
Stepan Zhukovsky 2023-07-27 11:26:27 +09:00
parent 4f288f04ff
commit b944d58943
9 changed files with 195 additions and 18 deletions

3
.gitignore vendored
View File

@ -160,3 +160,6 @@ cython_debug/
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
# Project specific
**/archives
**/media

View File

@ -1,3 +1,21 @@
from django.contrib import admin
from .models import Platform, Archive, Ticket
# Register your models here.
class PlatformAdmin(admin.ModelAdmin):
pass
class TicketAdmin(admin.ModelAdmin):
pass
class ArchiveAdmin(admin.ModelAdmin):
pass
admin.site.register(Platform, PlatformAdmin)
admin.site.register(Ticket, TicketAdmin)
admin.site.register(Archive, ArchiveAdmin)

View File

@ -0,0 +1,52 @@
# Generated by Django 4.2 on 2023-07-27 02:04
import collector.models
from django.conf import settings
import django.core.files.storage
from django.db import migrations, models
import django.db.models.deletion
import pathlib
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Platform',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=20)),
],
),
migrations.CreateModel(
name='Ticket',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('number', models.IntegerField()),
('resolved', models.BooleanField(default=False)),
('note', models.TextField(blank=True)),
('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')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
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.models.logs_dir_path)),
('sha1', 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)),
],
),
]

View File

@ -1,3 +1,69 @@
from django.db import models
import hashlib
from functools import partial
# Create your models here.
from django.contrib.auth.models import User
from django.db import models
from django.conf import settings
from django.core.files.storage import FileSystemStorage
from django.db.models import FileField
# Create a custom storage location, using a value from your settings file
sensitive_upload_storage = FileSystemStorage(
location=settings.MEDIA_ROOT_FOR_SENSITIVE_FILES,
base_url=settings.MEDIA_URL_FOR_SENSITIVE_FILES
)
# ... and a file field that will use the custom storage
AuthenticatedFileField = partial(FileField, storage=sensitive_upload_storage)
def logs_dir_path(instance, filename):
# file will be uploaded to
# MEDIA_ROOT_FOR_SENSITIVE_FILES/<ticket>/<filename>
return f'{instance.ticket}/{filename}'
class Archive(models.Model):
file = AuthenticatedFileField(
upload_to=logs_dir_path,
blank=True,
null=True
)
sha1 = models.CharField(max_length=1024, editable=False)
time_create = models.DateTimeField(auto_now_add=True)
time_update = models.DateTimeField(auto_now=True)
ticket = models.ForeignKey('Ticket', on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
def save(self, *args, **kwargs):
# calculate sha 1 hash sum and write sha1 field to db
with self.file.open('rb') as f:
sha1 = hashlib.sha1()
for byte_block in iter(lambda: f.read(4096), b""):
sha1.update(byte_block)
self.sha1 = sha1.hexdigest()
# Call the "real" save() method
super().save(*args, **kwargs)
def __str__(self):
return str(self.file)
class Platform(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
class Ticket(models.Model):
number = models.IntegerField()
resolved = models.BooleanField(default=False)
note = models.TextField(blank=True)
time_create = models.DateTimeField(auto_now_add=True)
time_update = models.DateTimeField(auto_now=True)
platform = models.ForeignKey('Platform', on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return str(self.number)

View File

@ -0,0 +1,9 @@
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index',),
path('test/<str:path>/', views.test_page, name='test_page'),
path('archives/<ticket>/<archive>', views.download, name="download")
]

View File

View File

@ -1,3 +1,25 @@
from django.shortcuts import render
# from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from django.http import FileResponse, HttpResponse, Http404
from .models import Archive
# Create your views here.
# handles the url "/archives/{PATH}"".
@login_required
def download(request, ticket, file):
path = f'{ticket}/{file}'
try:
file = Archive.objects.get(file=path)
except Archive.DoesNotExist:
return Http404
return FileResponse(file.file)
def index(request):
return HttpResponse('<h1>Index Page</h1>')
def test_page(request, path):
return HttpResponse(f'<h1>{path} Page</h1>')

View File

@ -1,14 +1,3 @@
"""
Django settings for logs_collector project.
Generated by 'django-admin startproject' using Django 4.2.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.2/ref/settings/
"""
import environ
from pathlib import Path
@ -22,8 +11,6 @@ BASE_DIR = Path(__file__).resolve().parent.parent
environ.Env.read_env(BASE_DIR / '.env')
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = env('SECRET_KEY')
@ -32,7 +19,9 @@ SECRET_KEY = env('SECRET_KEY')
DEBUG = env('DEBUG')
ALLOWED_HOSTS = env.list("ALLOWED_HOSTS", default=["*"])
CSRF_TRUSTED_ORIGINS = env.list("CSRF_TRUSTED_ORIGINS", default=["*"])
# TODO: required for docker image
# CSRF_TRUSTED_ORIGINS = env.list("CSRF_TRUSTED_ORIGINS", default=["*"])
# Application definition
@ -46,6 +35,7 @@ INSTALLED_APPS = [
'django.contrib.staticfiles',
'collector.apps.CollectorConfig', # main app
'rest_framework',
'django_cleanup.apps.CleanupConfig', # required bottom
]
MIDDLEWARE = [
@ -130,3 +120,9 @@ STATIC_URL = 'static/'
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
MEDIA_ROOT = BASE_DIR / 'media'
MEDIA_URL = 'media/'
MEDIA_ROOT_FOR_SENSITIVE_FILES = BASE_DIR / 'archives'
MEDIA_URL_FOR_SENSITIVE_FILES = '/archives/'

View File

@ -14,9 +14,20 @@ Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path
from django.urls import path, include
from logs_collector import settings
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('collector.urls')),
]
if settings.DEBUG:
urlpatterns += static(
settings.MEDIA_URL, document_root=settings.MEDIA_ROOT
)