mirror of
				https://github.com/Alexander-D-Karpov/akarpov
				synced 2025-10-31 03:27:25 +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