mirror of
https://github.com/Alexander-D-Karpov/akarpov
synced 2024-11-29 09:43:43 +03:00
Merge branch 'main' into dependabot/pip/django-structlog-5.1.0
This commit is contained in:
commit
62c965b584
|
@ -1,6 +1,8 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from akarpov.files.models import File, Folder
|
from akarpov.files.models import File, FileInTrash, FileReport, Folder
|
||||||
|
|
||||||
admin.site.register(File)
|
admin.site.register(File)
|
||||||
admin.site.register(Folder)
|
admin.site.register(Folder)
|
||||||
|
admin.site.register(FileInTrash)
|
||||||
|
admin.site.register(FileReport)
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
"docx": application.docx.view,
|
"docx": application.docx.view,
|
||||||
"vnd.oasis.opendocument.text": application.odt.view,
|
"vnd.oasis.opendocument.text": application.odt.view,
|
||||||
"x-httpd-php": text.common.view,
|
"x-httpd-php": text.common.view,
|
||||||
|
"json": application.json.view,
|
||||||
},
|
},
|
||||||
"audio": {
|
"audio": {
|
||||||
"aac": audio.basic.view,
|
"aac": audio.basic.view,
|
||||||
|
@ -77,6 +78,7 @@
|
||||||
"oga": audio.oga.view,
|
"oga": audio.oga.view,
|
||||||
"pdf": application.pdf.view,
|
"pdf": application.pdf.view,
|
||||||
"html": text.html.view,
|
"html": text.html.view,
|
||||||
|
"json": application.json.view,
|
||||||
}
|
}
|
||||||
| source_code
|
| source_code
|
||||||
| fonts_ext
|
| fonts_ext
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
from . import doc, docx, odt, pdf, zip # noqa
|
from . import doc, docx, json, odt, pdf, zip # noqa
|
||||||
|
|
84
akarpov/files/previews/application/json.py
Normal file
84
akarpov/files/previews/application/json.py
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
from akarpov.files.models import File
|
||||||
|
|
||||||
|
|
||||||
|
def view(file: File):
|
||||||
|
static = """
|
||||||
|
<style>
|
||||||
|
pre {outline: 1px solid #ccc; padding: 5px; margin: 5px; }
|
||||||
|
.string { color: green; }
|
||||||
|
.number { color: darkorange; }
|
||||||
|
.boolean { color: blue; }
|
||||||
|
.null { color: magenta; }
|
||||||
|
.key { color: red; }
|
||||||
|
</style>
|
||||||
|
"""
|
||||||
|
if file.file_size < 200 * 1024:
|
||||||
|
req = (
|
||||||
|
f"""
|
||||||
|
getJSON('{file.file.url}',
|
||||||
|
"""
|
||||||
|
+ """
|
||||||
|
function(err, data) {
|
||||||
|
if (err !== null) {
|
||||||
|
console.log('Something went wrong: ' + err);
|
||||||
|
} else {
|
||||||
|
var str = JSON.stringify(data, undefined, 4);
|
||||||
|
output(syntaxHighlight(str));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
req = """
|
||||||
|
output("file is too large, download to view")
|
||||||
|
"""
|
||||||
|
|
||||||
|
content = (
|
||||||
|
"""
|
||||||
|
<div id="json" class="col-auto"></div>
|
||||||
|
<script>
|
||||||
|
function output(inp) {
|
||||||
|
document.getElementById("json").appendChild(document.createElement('pre')).innerHTML = inp;
|
||||||
|
}
|
||||||
|
|
||||||
|
function syntaxHighlight(json) {
|
||||||
|
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||||
|
return json.replace(
|
||||||
|
/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\\s*:)?|\b(true|false|null)\b|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?)/g,
|
||||||
|
function (match) {
|
||||||
|
var cls = 'number';
|
||||||
|
if (/^"/.test(match)) {
|
||||||
|
if (/:$/.test(match)) {
|
||||||
|
cls = 'key';
|
||||||
|
} else {
|
||||||
|
cls = 'string';
|
||||||
|
}
|
||||||
|
} else if (/true|false/.test(match)) {
|
||||||
|
cls = 'boolean';
|
||||||
|
} else if (/null/.test(match)) {
|
||||||
|
cls = 'null';
|
||||||
|
}
|
||||||
|
return '<span class="' + cls + '">' + match + '</span>';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var getJSON = function(url, callback) {
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('GET', url, true);
|
||||||
|
xhr.responseType = 'json';
|
||||||
|
xhr.onload = function() {
|
||||||
|
var status = xhr.status;
|
||||||
|
if (status === 200) {
|
||||||
|
callback(null, xhr.response);
|
||||||
|
} else {
|
||||||
|
callback(status, xhr.response);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhr.send();
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
+ req
|
||||||
|
+ """
|
||||||
|
</script>
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
return static, content
|
|
@ -30,6 +30,8 @@
|
||||||
|
|
||||||
|
|
||||||
def view(file: File) -> (str, str):
|
def view(file: File) -> (str, str):
|
||||||
|
if file.file_size > 10 * 1024 * 1024:
|
||||||
|
return "", "file is too large to view"
|
||||||
extension = file.file.path.split(".")[-1]
|
extension = file.file.path.split(".")[-1]
|
||||||
if extension in language_previews:
|
if extension in language_previews:
|
||||||
extension = language_previews[extension]
|
extension = language_previews[extension]
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
|
|
||||||
def view(file: File) -> (str, str):
|
def view(file: File) -> (str, str):
|
||||||
|
if file.file_size > 10 * 1024 * 1024:
|
||||||
|
return "", "file is too large to view"
|
||||||
static = f"""
|
static = f"""
|
||||||
<meta property="og:title" content="{file.name}" />
|
<meta property="og:title" content="{file.name}" />
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/atom-one-light.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/atom-one-light.min.css">
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
|
|
||||||
def view(file: File) -> (str, str):
|
def view(file: File) -> (str, str):
|
||||||
|
if file.file_size > 10 * 1024 * 1024:
|
||||||
|
return "", "file is too large to view"
|
||||||
extension = file.file.path.split(".")[-1]
|
extension = file.file.path.split(".")[-1]
|
||||||
if hasattr(text, extension):
|
if hasattr(text, extension):
|
||||||
return getattr(text, extension).view(file)
|
return getattr(text, extension).view(file)
|
||||||
|
|
|
@ -17,11 +17,14 @@
|
||||||
from django_tables2 import SingleTableView
|
from django_tables2 import SingleTableView
|
||||||
from django_tables2.export import ExportMixin
|
from django_tables2.export import ExportMixin
|
||||||
|
|
||||||
|
from akarpov.common.views import SuperUserRequiredMixin
|
||||||
from akarpov.contrib.chunked_upload.exceptions import ChunkedUploadError
|
from akarpov.contrib.chunked_upload.exceptions import ChunkedUploadError
|
||||||
from akarpov.contrib.chunked_upload.models import ChunkedUpload
|
from akarpov.contrib.chunked_upload.models import ChunkedUpload
|
||||||
from akarpov.contrib.chunked_upload.views import (
|
from akarpov.contrib.chunked_upload.views import (
|
||||||
ChunkedUploadCompleteView,
|
ChunkedUploadCompleteView as ChunkedUploadABSCompleteView,
|
||||||
ChunkedUploadView,
|
)
|
||||||
|
from akarpov.contrib.chunked_upload.views import (
|
||||||
|
ChunkedUploadView as ChunkedUploadABSView,
|
||||||
)
|
)
|
||||||
from akarpov.files.filters import FileFilter
|
from akarpov.files.filters import FileFilter
|
||||||
from akarpov.files.forms import FileForm, FolderForm
|
from akarpov.files.forms import FileForm, FolderForm
|
||||||
|
@ -207,7 +210,7 @@ def get_redirect_url(self, *args, **kwargs):
|
||||||
delete_file_view = DeleteFileView.as_view()
|
delete_file_view = DeleteFileView.as_view()
|
||||||
|
|
||||||
|
|
||||||
class ChunkedUploadView(ChunkedUploadView):
|
class ChunkedUploadView(ChunkedUploadABSView):
|
||||||
model = ChunkedUpload
|
model = ChunkedUpload
|
||||||
field_name = "the_file"
|
field_name = "the_file"
|
||||||
|
|
||||||
|
@ -218,7 +221,7 @@ def check_permissions(self, request):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ChunkedUploadCompleteView(ChunkedUploadCompleteView):
|
class ChunkedUploadCompleteView(ChunkedUploadABSCompleteView):
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.message = {}
|
self.message = {}
|
||||||
|
@ -298,14 +301,10 @@ def get_redirect_url(self, *args, **kwargs):
|
||||||
report_file = ReportFileView.as_view()
|
report_file = ReportFileView.as_view()
|
||||||
|
|
||||||
|
|
||||||
class ListFileReports(LoginRequiredMixin, ListView):
|
class ListFileReports(SuperUserRequiredMixin, ListView):
|
||||||
model = FileReport
|
model = FileReport
|
||||||
|
queryset = FileReport.objects.all()
|
||||||
template_name = "files/reports.html"
|
template_name = "files/reports.html"
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
if self.request.user.is_superuser:
|
|
||||||
return FileReport.objects.all()
|
|
||||||
return FileReport.objects.none()
|
|
||||||
|
|
||||||
|
|
||||||
file_report_list = ListFileReports.as_view()
|
file_report_list = ListFileReports.as_view()
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
<div class="ms-3 row">
|
<div class="ms-3 row">
|
||||||
{% if is_folder_owner %}
|
{% if is_folder_owner %}
|
||||||
{% if folder_slug %}
|
{% if folder_slug %}
|
||||||
<nav aria-label="breadcrumb">
|
<nav class="col" aria-label="breadcrumb">
|
||||||
<ol class="breadcrumb">
|
<ol class="breadcrumb">
|
||||||
<li class="breadcrumb-item active" aria-current="page"><a href="{% url 'files:main' %}">home</a></li>
|
<li class="breadcrumb-item active" aria-current="page"><a href="{% url 'files:main' %}">home</a></li>
|
||||||
{% for f in folders %}
|
{% for f in folders %}
|
||||||
|
@ -45,7 +45,7 @@
|
||||||
</ol>
|
</ol>
|
||||||
</nav>
|
</nav>
|
||||||
{% else %}
|
{% else %}
|
||||||
<nav aria-label="breadcrumb">
|
<nav class="col" aria-label="breadcrumb">
|
||||||
<ol class="breadcrumb">
|
<ol class="breadcrumb">
|
||||||
<li class="breadcrumb-item active" aria-current="page"><a href="{% url 'files:main' %}">home</a></li>
|
<li class="breadcrumb-item active" aria-current="page"><a href="{% url 'files:main' %}">home</a></li>
|
||||||
</ol>
|
</ol>
|
||||||
|
@ -53,9 +53,13 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if request.user.is_authenticated and is_folder_owner %}
|
{% if request.user.is_authenticated and is_folder_owner %}
|
||||||
<div class="d-flex justify-content-end me-5">
|
<div class="d-flex justify-content-end me-5 col">
|
||||||
<a class="me-5" href="{% url 'files:table' %}">table view</a>
|
<a class="me-5" href="{% url 'files:table' %}">table view</a>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
{% if request.user.is_authenticated and is_folder_owner %}
|
||||||
<div class="col-lg-2 col-xxl-2 col-md-4 col-sm-6 col-xs-12 mb-3 m-3 d-flex align-items-stretch card">
|
<div class="col-lg-2 col-xxl-2 col-md-4 col-sm-6 col-xs-12 mb-3 m-3 d-flex align-items-stretch card">
|
||||||
<div class="card-body d-flex flex-column justify-content-center align-items-center">
|
<div class="card-body d-flex flex-column justify-content-center align-items-center">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% load humanize %}
|
{% load humanize %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
{% for file in filereport_list %}
|
{% for file in filereport_list %}
|
||||||
<a href="{{ file.file.get_absolute_url }}" class="list-group-item list-group-item-action">
|
<a href="{{ file.file.get_absolute_url }}" class="list-group-item list-group-item-action">
|
||||||
|
@ -12,3 +13,4 @@
|
||||||
</a>
|
</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
10
poetry.lock
generated
10
poetry.lock
generated
|
@ -5527,13 +5527,13 @@ files = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yandex-music"
|
name = "yandex-music"
|
||||||
version = "2.0.1"
|
version = "2.1.0"
|
||||||
description = "Неофициальная Python библиотека для работы с API сервиса Яндекс.Музыка."
|
description = "Неофициальная Python библиотека для работы с API сервиса Яндекс.Музыка."
|
||||||
category = "main"
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "~=3.7"
|
python-versions = "~=3.7"
|
||||||
files = [
|
files = [
|
||||||
{file = "yandex-music-2.0.1.tar.gz", hash = "sha256:d01f35d72aa0a6deca474566fff18109af7fcc8ef0377876e6c83da1ae096671"},
|
{file = "yandex-music-2.1.0.tar.gz", hash = "sha256:6211e8ffe0bad8d79815578a1cd86ee45630784f93c5f5ec73bf2228b7ab27ba"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
|
@ -5631,14 +5631,14 @@ multidict = ">=4.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ytmusicapi"
|
name = "ytmusicapi"
|
||||||
version = "0.25.2"
|
version = "1.0.2"
|
||||||
description = "Unofficial API for YouTube Music"
|
description = "Unofficial API for YouTube Music"
|
||||||
category = "main"
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "ytmusicapi-0.25.2-py3-none-any.whl", hash = "sha256:3d47a8803dceeb0289c7cf29a0317c5d6051d0b7c28fda067f6abb001746f7ac"},
|
{file = "ytmusicapi-1.0.2-py3-none-any.whl", hash = "sha256:8e3f364dbb0d4e9bbbbcac65e65c2449e7e236478ecc00e6b5bc25455e488eee"},
|
||||||
{file = "ytmusicapi-0.25.2.tar.gz", hash = "sha256:aa3165100ff5c0e1f49f9a046312f878c31eea83fde14af0707e3368ae923fe4"},
|
{file = "ytmusicapi-1.0.2.tar.gz", hash = "sha256:f798bfedd49738bece82aac15b2d97f04578ccb1572f347a350cb704df4d0e10"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
|
|
|
@ -75,10 +75,10 @@ preview-generator = "^0.29"
|
||||||
uuid = "^1.30"
|
uuid = "^1.30"
|
||||||
mutagen = "^1.46.0"
|
mutagen = "^1.46.0"
|
||||||
pytube = "^12.1.3"
|
pytube = "^12.1.3"
|
||||||
ytmusicapi = "^0.25.2"
|
ytmusicapi = "^1.0.2"
|
||||||
pydub = "^0.25.1"
|
pydub = "^0.25.1"
|
||||||
python-mpd2 = "^3.0.5"
|
python-mpd2 = "^3.0.5"
|
||||||
yandex-music = "^2.0.1"
|
yandex-music = "^2.1.0"
|
||||||
pyjwt = "^2.6.0"
|
pyjwt = "^2.6.0"
|
||||||
rawpy = "^0.18.0"
|
rawpy = "^0.18.0"
|
||||||
xvfbwrapper = "^0.2.9"
|
xvfbwrapper = "^0.2.9"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user