mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	more metadata #32
This commit is contained in:
		| @@ -19,6 +19,7 @@ This release focusses primarily on many small issues with the UI. | ||||
|   * There's a new filter to filter for documents that do *not* have a certain tag. | ||||
|   * The file upload box now shows upload progress. | ||||
|   * The document edit page was reorganized. | ||||
|   * The document edit page shows various information about a document. | ||||
|   * Table issues with too long document titles fixed. | ||||
|  | ||||
| * API | ||||
|   | ||||
| @@ -47,6 +47,7 @@ import { UploadFileWidgetComponent } from './components/dashboard/widgets/upload | ||||
| import { WidgetFrameComponent } from './components/dashboard/widgets/widget-frame/widget-frame.component'; | ||||
| import { WelcomeWidgetComponent } from './components/dashboard/widgets/welcome-widget/welcome-widget.component'; | ||||
| import { YesNoPipe } from './pipes/yes-no.pipe'; | ||||
| import { FileSizePipe } from './pipes/file-size.pipe'; | ||||
|  | ||||
| @NgModule({ | ||||
|   declarations: [ | ||||
| @@ -86,7 +87,8 @@ import { YesNoPipe } from './pipes/yes-no.pipe'; | ||||
|     UploadFileWidgetComponent, | ||||
|     WidgetFrameComponent, | ||||
|     WelcomeWidgetComponent, | ||||
|     YesNoPipe | ||||
|     YesNoPipe, | ||||
|     FileSizePipe | ||||
|   ], | ||||
|   imports: [ | ||||
|     BrowserModule, | ||||
|   | ||||
| @@ -83,25 +83,29 @@ | ||||
|                                     <td>Date added</td> | ||||
|                                     <td>{{document.added | date}}</td> | ||||
|                                 </tr> | ||||
|                                 <tr> | ||||
|                                     <td>Media filename</td> | ||||
|                                     <td>{{metadata?.media_filename}}</td> | ||||
|                                 </tr> | ||||
|                                 <tr> | ||||
|                                     <td>Original MD5 Checksum</td> | ||||
|                                     <td>{{metadata?.original_checksum}}</td> | ||||
|                                 </tr> | ||||
|                                 <tr> | ||||
|                                     <td>Archive MD5 Checksum</td> | ||||
|                                     <td>{{metadata?.archived_checksum}}</td> | ||||
|                                     <td>Original file size</td> | ||||
|                                     <td>{{metadata?.original_size | fileSize}}</td> | ||||
|                                 </tr> | ||||
|                                 <tr> | ||||
|                                     <td>Original mime type</td> | ||||
|                                     <td>{{metadata?.original_mime_type}}</td> | ||||
|                                 </tr> | ||||
|                                 <tr> | ||||
|                                     <td>Is archived?</td> | ||||
|                                     <td>{{metadata?.has_archive_version | yesno}}</td> | ||||
|                                 <tr *ngIf="metadata?.has_archive_version"> | ||||
|                                     <td>Archive MD5 Checksum</td> | ||||
|                                     <td>{{metadata?.archive_checksum}}</td> | ||||
|                                 </tr> | ||||
|                                 <tr> | ||||
|                                     <td>Media filename</td> | ||||
|                                     <td>{{metadata?.media_filename}}</td> | ||||
|                                 <tr *ngIf="metadata?.has_archive_version"> | ||||
|                                     <td>Archive file size</td> | ||||
|                                     <td>{{metadata?.archive_size | fileSize}}</td> | ||||
|                                 </tr> | ||||
|                             </tbody> | ||||
|                         </table> | ||||
|   | ||||
							
								
								
									
										8
									
								
								src-ui/src/app/pipes/file-size.pipe.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src-ui/src/app/pipes/file-size.pipe.spec.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| import { FileSizePipe } from './file-size.pipe'; | ||||
|  | ||||
| describe('FileSizePipe', () => { | ||||
|   it('create an instance', () => { | ||||
|     const pipe = new FileSizePipe(); | ||||
|     expect(pipe).toBeTruthy(); | ||||
|   }); | ||||
| }); | ||||
							
								
								
									
										77
									
								
								src-ui/src/app/pipes/file-size.pipe.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src-ui/src/app/pipes/file-size.pipe.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | ||||
| /** | ||||
|  * https://gist.github.com/JonCatmull/ecdf9441aaa37336d9ae2c7f9cb7289a | ||||
|  *  | ||||
|  * @license | ||||
|  * Copyright (c) 2019 Jonathan Catmull. | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in all | ||||
|  * copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
|  * SOFTWARE. | ||||
|  */ | ||||
| import { Pipe, PipeTransform } from '@angular/core'; | ||||
|  | ||||
| type unit = 'bytes' | 'KB' | 'MB' | 'GB' | 'TB' | 'PB'; | ||||
| type unitPrecisionMap = { | ||||
|   [u in unit]: number; | ||||
| }; | ||||
|  | ||||
| const defaultPrecisionMap: unitPrecisionMap = { | ||||
|   bytes: 0, | ||||
|   KB: 0, | ||||
|   MB: 1, | ||||
|   GB: 1, | ||||
|   TB: 2, | ||||
|   PB: 2 | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * Convert bytes into largest possible unit. | ||||
|  * Takes an precision argument that can be a number or a map for each unit. | ||||
|  * Usage: | ||||
|  *   bytes | fileSize:precision | ||||
|  * @example | ||||
|  * // returns 1 KB | ||||
|  * {{ 1500 | fileSize }} | ||||
|  * @example | ||||
|  * // returns 2.1 GB | ||||
|  * {{ 2100000000 | fileSize }} | ||||
|  * @example | ||||
|  * // returns 1.46 KB | ||||
|  * {{ 1500 | fileSize:2 }} | ||||
|  */ | ||||
| @Pipe({ name: 'fileSize' }) | ||||
| export class FileSizePipe implements PipeTransform { | ||||
|   private readonly units: unit[] = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB']; | ||||
|  | ||||
|   transform(bytes: number = 0, precision: number | unitPrecisionMap = defaultPrecisionMap): string { | ||||
|     if (isNaN(parseFloat(String(bytes))) || !isFinite(bytes)) return '?'; | ||||
|  | ||||
|     let unitIndex = 0; | ||||
|  | ||||
|     while (bytes >= 1024) { | ||||
|       bytes /= 1024; | ||||
|       unitIndex++; | ||||
|     } | ||||
|  | ||||
|     const unit = this.units[unitIndex]; | ||||
|  | ||||
|     if (typeof precision === 'number') { | ||||
|       return `${bytes.toFixed(+precision)} ${unit}`; | ||||
|     } | ||||
|     return `${bytes.toFixed(precision[unit])} ${unit}`; | ||||
|   } | ||||
| } | ||||
| @@ -496,7 +496,7 @@ class TestDocumentApi(DirectoriesMixin, APITestCase): | ||||
|         async_task.assert_not_called() | ||||
|  | ||||
|     def test_get_metadata(self): | ||||
|         doc = Document.objects.create(title="test", filename="file.pdf", mime_type="image/png") | ||||
|         doc = Document.objects.create(title="test", filename="file.pdf", mime_type="image/png", archive_checksum="A") | ||||
|  | ||||
|         shutil.copy(os.path.join(os.path.dirname(__file__), "samples", "documents", "thumbnails", "0000001.png"), doc.source_path) | ||||
|         shutil.copy(os.path.join(os.path.dirname(__file__), "samples", "simple.pdf"), doc.archive_path) | ||||
|   | ||||
| @@ -196,17 +196,28 @@ class DocumentViewSet(RetrieveModelMixin, | ||||
|     def metadata(self, request, pk=None): | ||||
|         try: | ||||
|             doc = Document.objects.get(pk=pk) | ||||
|             return Response({ | ||||
|  | ||||
|             meta = { | ||||
|                 "original_checksum": doc.checksum, | ||||
|                 "archived_checksum": doc.archive_checksum, | ||||
|                 "original_size": os.stat(doc.source_path).st_size, | ||||
|                 "original_mime_type": doc.mime_type, | ||||
|                 "media_filename": doc.filename, | ||||
|                 "has_archive_version": os.path.isfile(doc.archive_path), | ||||
|                 "original_metadata": self.get_metadata( | ||||
|                     doc.source_path, doc.mime_type), | ||||
|                 "archive_metadata": self.get_metadata( | ||||
|                     doc.source_path, doc.mime_type) | ||||
|             } | ||||
|  | ||||
|             if doc.archive_checksum and os.path.isfile(doc.archive_path): | ||||
|                 meta['archive_checksum'] = doc.archive_checksum | ||||
|                 meta['archive_size'] = os.stat(doc.archive_path).st_size, | ||||
|                 meta['archive_metadata'] = self.get_metadata( | ||||
|                     doc.archive_path, "application/pdf") | ||||
|             }) | ||||
|             else: | ||||
|                 meta['archive_checksum'] = None | ||||
|                 meta['archive_size'] = None | ||||
|                 meta['archive_metadata'] = None | ||||
|  | ||||
|             return Response(meta) | ||||
|         except Document.DoesNotExist: | ||||
|             raise Http404() | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 jonaswinkler
					jonaswinkler