mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-11-03 03:16:10 -06: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