Merge branch 'master' into 4-mongodb_api

This commit is contained in:
Tobias Eidelpes 2021-01-19 12:10:59 +01:00
commit 400d03492b
15 changed files with 330 additions and 74 deletions

View File

@ -3,6 +3,8 @@ import {RestService} from '../../services/rest.service';
import {NGXLogger} from 'ngx-logger'; import {NGXLogger} from 'ngx-logger';
import {MatSnackBar} from '@angular/material/snack-bar'; import {MatSnackBar} from '@angular/material/snack-bar';
import {ImageMetadata} from '../../interfaces/interface'; import {ImageMetadata} from '../../interfaces/interface';
// @ts-ignore
import metaFile from '../../../../../iotclient/metadata_full.json';
@Component({ @Component({
selector: 'app-file-uploader', selector: 'app-file-uploader',
@ -40,34 +42,36 @@ export class FileUploaderComponent implements OnInit {
if (this.filename) { if (this.filename) {
this.id = this.filename; this.id = this.filename;
metaDict['filename'] = this.filename;
} else { } else {
this.id = this.currentFileName; this.id = this.currentFileName;
metaDict['filename'] = this.currentFileName;
} }
metaDict['filename'] = this.currentFileName;
if (this.mode === 'post') { if (this.mode === 'post') {
if (this.longitude && this.latitude) { if (this.meta && this.meta.longitude && this.meta.latitude) {
metaDict['longitude'] = Number.parseFloat(this.longitude);
metaDict['latitude'] = Number.parseFloat(this.latitude);
} else if (this.meta && this.meta.longitude && this.meta.latitude) {
metaDict['longitude'] = this.meta.longitude; metaDict['longitude'] = this.meta.longitude;
metaDict['latitude'] = this.meta.latitude; metaDict['latitude'] = this.meta.latitude;
} else if (this.longitude && this.latitude) {
metaDict['longitude'] = Number.parseFloat(this.longitude);
metaDict['latitude'] = Number.parseFloat(this.latitude);
} else { } else {
throw new Error('Long/Lat necessary if new file!'); throw new Error('Long/Lat necessary if new file!');
} }
} }
if (this.name) { if (this.meta && this.meta.name) {
metaDict['name'] = this.name;
} else if (this.meta && this.meta.name) {
metaDict['name'] = this.meta.name; metaDict['name'] = this.meta.name;
} else if (this.name) {
metaDict['name'] = this.name;
} else { } else {
if (this.mode === 'post') { if (this.mode === 'post') {
throw new Error('Name necessary if new file'); throw new Error('Name necessary if new file');
} }
} }
// metaDict['name'] = this.currentFileName;
if (this.tag) { if (this.tag) {
metaDict['tag'] = this.tag; metaDict['tag'] = this.tag;
} else if (this.meta && this.meta.tag) { } else if (this.meta && this.meta.tag) {
@ -95,6 +99,7 @@ export class FileUploaderComponent implements OnInit {
} }
ngOnInit(): void { ngOnInit(): void {
this.logger.debug('meta', metaFile);
} }
onFileSelected(fileEvent: Event) { onFileSelected(fileEvent: Event) {
@ -109,6 +114,12 @@ export class FileUploaderComponent implements OnInit {
this.file = e.target.result; this.file = e.target.result;
this.currentFileName = file.name; this.currentFileName = file.name;
this.logger.debug('Selected file', this.currentFileName, this.file); this.logger.debug('Selected file', this.currentFileName, this.file);
const metaData = this.loadMetaForFile();
if (metaData) {
this.name = metaData.name;
this.longitude = metaData.longitude + '';
this.latitude = metaData.latitude + '';
}
}; };
reader.readAsArrayBuffer(file); reader.readAsArrayBuffer(file);
@ -150,4 +161,14 @@ export class FileUploaderComponent implements OnInit {
} }
} }
private loadMetaForFile() {
const metaData = (metaFile as {
filename: string,
latitude: number;
longitude: number;
name: string;
}[]).find(m => m.filename === this.currentFileName);
this.logger.debug('Found corresponding meta', this.currentFileName, metaData);
return metaData;
}
} }

View File

@ -3,21 +3,27 @@
<div style="font-weight: bolder; font-size: 20px"> <div style="font-weight: bolder; font-size: 20px">
<span style="width: 22.5em; display: inline-block; margin-left: 1.15em">Name</span> <span style="width: 22.5em; display: inline-block; margin-left: 1.15em">Name</span>
<span style="width: 22.5em; display: inline-block">Date</span> <span style="width: 22.5em; display: inline-block">Date</span>
<span style="width: 22.5em; display: inline-block">File valid</span> <span style="width: 22.5em; display: inline-block">File available | valid</span>
</div> </div>
<mat-expansion-panel <mat-expansion-panel
*ngFor="let image of filterOnlyNewestImageVersion() | slice:paginationGetStart():paginationGetEnd()" *ngFor="let image of filterOnlyNewestImageVersion() | slice:paginationGetStart():paginationGetEnd(); let i = index"
(opened)="loadImage(getImageIndex(image), image.filename.split('.')[0])" (opened)="openImageExpansion[i][0] = true; loadImage(getImageIndex(image), image.identifier)"
(closed)="openImageExpansion[i][0] = false;"
[expanded]="openImageExpansion[i][0]"
> >
<!-- (opened)="loadImage(getImageIndex(image), image.filename.split('.')[0])"-->
<mat-expansion-panel-header (click)="$event.stopPropagation()"> <mat-expansion-panel-header (click)="$event.stopPropagation()">
<h4 style="width: 25em" <h4 style="width: 25em"
>{{image.name}}</h4> >{{image.name}}</h4>
<h4 style="width: 25em" <h4 style="width: 25em"
>{{image.datetime}}</h4> >{{image.datetime}}</h4>
<h4 style="width: 25em; color: red"> <h4 style="width: 25em; margin-left: 6em;" *ngIf="image.available !== undefined || image.valid !== undefined;
✓ | X (TO BE DONE) else loadingValidity">
{{image.available ? '✓' : 'X' }} | {{image.valid ? '✓' : 'X' }}
</h4> </h4>
<ng-template #loadingValidity>
<h4 style="width: 25em; margin-left: 7em;">...</h4>
</ng-template>
<span style="float: right; margin-left: auto; margin-right: 1em;"> <span style="float: right; margin-left: auto; margin-right: 1em;">
<button mat-raised-button color="warn" <button mat-raised-button color="warn"
(click)="deleteImage(image); $event.stopPropagation()"> (click)="deleteImage(image); $event.stopPropagation()">
@ -43,17 +49,16 @@
<ng-template #loadingImage> <ng-template #loadingImage>
<mat-spinner style="margin: auto;"></mat-spinner> <mat-spinner style="margin: auto;"></mat-spinner>
</ng-template> </ng-template>
</div> </div>
</mat-grid-tile> </mat-grid-tile>
<mat-grid-tile colspan="3"> <mat-grid-tile colspan="3">
<div style="display: block; width: 100%"> <div style="display: block; width: 100%">
<h3>Metadata:</h3> <h3>Metadata:</h3>
<p *ngIf="image.version">version: {{image.version}}</p>
<p *ngIf="image.filename">filename: {{image.filename}}</p> <p *ngIf="image.filename">filename: {{image.filename}}</p>
<p *ngIf="image.latitude">latitude: {{image.latitude}}</p> <p *ngIf="image.latitude">latitude: {{image.latitude}}</p>
<p *ngIf="image.longitude">longitude: {{image.longitude}}</p> <p *ngIf="image.longitude">longitude: {{image.longitude}}</p>
<p *ngIf="image.version">version: {{image.version}}</p>
</div> </div>
</mat-grid-tile> </mat-grid-tile>
</mat-grid-list> </mat-grid-list>
@ -61,21 +66,57 @@
<app-file-uploader [mode]="'put'" <app-file-uploader [mode]="'put'"
[filename]="image.filename.split('.')[0]" [filename]="image.filename.split('.')[0]"
[meta]=image [meta]=image
(reload)="this.reload.emit()" (reload)="reload.emit(); checkValidity()"
></app-file-uploader> ></app-file-uploader>
<!-- (reload)="image.image_b64 = undefined; this.loadImage(getImageIndex(image), image.identifier)"-->
<ng-container *ngIf="getRelatedImageMeta(image); let relatedImageMetadata"> <ng-container *ngIf="getRelatedImageMeta(image); let relatedImages">
<mat-expansion-panel *ngIf="relatedImageMetadata.length > 0"> <mat-expansion-panel *ngIf="relatedImages.length > 0" [expanded]="openImageExpansion[i][1]">
<mat-expansion-panel-header> <mat-expansion-panel-header>
Previous version meta Previous versions
</mat-expansion-panel-header> </mat-expansion-panel-header>
<ng-template matExpansionPanelContent> <ng-template matExpansionPanelContent>
<div *ngFor="let imageMeta of relatedImageMetadata">
<p *ngIf="imageMeta.filename">filename: {{imageMeta.filename}}</p> <mat-expansion-panel *ngFor="let relImage of relatedImages.slice().reverse(); let j = index"
<p *ngIf="imageMeta.latitude">latitude: {{imageMeta.latitude}}</p> (opened)="loadImage(-1, relImage.identifier, relImage);
<p *ngIf="imageMeta.longitude">longitude: {{imageMeta.longitude}}</p> openImageExpansion[i][2+j]=true"
<p *ngIf="imageMeta.version">version: {{imageMeta.version}}</p> (closed)="openImageExpansion[i][2+j] = false"
[expanded]="openImageExpansion[i][2+j]"
>
<!-- <mat-divider></mat-divider>-->
<!-- <p *ngIf="imageMeta.version">version: {{imageMeta.version}}</p>-->
<!-- <p *ngIf="imageMeta.name">name: {{imageMeta.name}}</p>-->
<!-- <p *ngIf="imageMeta.tag">tag: {{imageMeta.tag}}</p>-->
<!-- <p *ngIf="imageMeta.filename">filename: {{imageMeta.filename}}</p>-->
<!-- <p *ngIf="imageMeta.latitude">latitude: {{imageMeta.latitude}}</p>-->
<!-- <p *ngIf="imageMeta.longitude">longitude: {{imageMeta.longitude}}</p>-->
<mat-expansion-panel-header>
<p>version: {{relImage.version ? relImage.version : 0}}</p>
</mat-expansion-panel-header>
<mat-grid-list cols="4" rowHeight="22em" style="width: 100%; margin: auto">
<mat-grid-tile style="justify-content: left!important;" colspan="1">
<div style="width: 20em; height: 20em; border: solid; margin-bottom: 1em; display: flex">
<img *ngIf="relImage.image_b64, let subB64; else loadingSubImage"
[src]="subB64"
style="width: 100%; margin: auto" [alt]="image.filename"/>
<ng-template #loadingSubImage>
<mat-spinner style="margin: auto;"></mat-spinner>
</ng-template>
</div> </div>
</mat-grid-tile>
<mat-grid-tile colspan="3">
<div style="display: block; width: 100%">
<p *ngIf="relImage.filename">filename: {{relImage.filename}}</p>
<p *ngIf="relImage.latitude">latitude: {{relImage.latitude}}</p>
<p *ngIf="relImage.longitude">longitude: {{relImage.longitude}}</p>
</div>
</mat-grid-tile>
</mat-grid-list>
</mat-expansion-panel>
</ng-template> </ng-template>
</mat-expansion-panel> </mat-expansion-panel>
</ng-container> </ng-container>
@ -87,11 +128,12 @@
[length]="filterOnlyNewestImageVersion().length" [length]="filterOnlyNewestImageVersion().length"
[pageSize]="pageSizeOptions[0]" [pageSize]="pageSizeOptions[0]"
[pageSizeOptions]="pageSizeOptions" [pageSizeOptions]="pageSizeOptions"
(page)="lastPageEvent = $event" (page)="lastPageEvent = $event; openImageExpansion = ALL_CLOSED_DEFAULT; checkValidity()"
showFirstLastButtons showFirstLastButtons
hidePageSize
></mat-paginator> ></mat-paginator>
<mat-divider style="margin-top: 2em"></mat-divider> <mat-divider style="margin-top: 2em"></mat-divider>
<h3>Upload New Image</h3> <h3>Upload New Image</h3>
<app-file-uploader [mode]="'post'" (reload)="reload.emit()"></app-file-uploader> <app-file-uploader [mode]="'post'" (reload)="reload.emit(); checkValidity()"></app-file-uploader>
<mat-divider style="margin-top: 2em"></mat-divider> <mat-divider style="margin-top: 2em"></mat-divider>

View File

@ -20,6 +20,9 @@ export class ImagesComponent implements OnInit, AfterViewInit {
pageSizeOptions: number[] = [5, 10, 25, 100]; pageSizeOptions: number[] = [5, 10, 25, 100];
lastPageEvent: PageEvent; lastPageEvent: PageEvent;
ALL_CLOSED_DEFAULT = [...Array(5)].map(() => this.getDefaultBoolDict(false));
openImageExpansion = this.ALL_CLOSED_DEFAULT;
constructor( constructor(
public restService: RestService, public restService: RestService,
private logger: NGXLogger, private logger: NGXLogger,
@ -27,8 +30,15 @@ export class ImagesComponent implements OnInit, AfterViewInit {
) { ) {
} }
private getDefaultBoolDict(value: boolean) {
return new Proxy({}, {
get: (target, name) => name in target ? target[name] : value
});
}
ngOnInit(): void { ngOnInit(): void {
this.lastPageEvent = {pageIndex: 0, pageSize: this.pageSizeOptions[0], length: this.images.length}; this.lastPageEvent = {pageIndex: 0, pageSize: this.pageSizeOptions[0], length: this.images.length};
this.checkValidity();
} }
ngAfterViewInit(): void { ngAfterViewInit(): void {
@ -50,29 +60,58 @@ export class ImagesComponent implements OnInit, AfterViewInit {
}).catch(err => this.logger.error(err)); }).catch(err => this.logger.error(err));
} }
loadImage(i: number, id: string): void { loadImage(i: number, id: string, relImage?: ImageMetadata): void {
if (!relImage) {
this.restService.getImage(id).toPromise().then(image => { this.restService.getImage(id).toPromise().then(image => {
this.images[i].image_b64 = 'data:image/jpg;base64,' + image.image_data; this.images[i].image_b64 = 'data:image/jpg;base64,' + image.image_data;
this.logger.debug('image_b64', i, id, this.images[i].image_b64); this.logger.debug('image_b64', i, id, this.images[i].image_b64);
}).catch(err => { }).catch(err => {
this.logger.error('loadImage', i, id, err); this.logger.error('loadImage', i, id, err);
}); });
} else {
this.restService.getImage(id).toPromise().then(image => {
relImage.image_b64 = 'data:image/jpg;base64,' + image.image_data;
this.logger.debug('image_b64', i, id, relImage.image_b64);
}).catch(err => {
this.logger.error('loadImage', i, id, err);
});
}
} }
filterOnlyNewestImageVersion() { filterOnlyNewestImageVersion() {
return this.images.filter(image => !image.previous); return this.images.filter(image => !image.identifier.includes('_'));
} }
getImageIndex(image: ImageMetadata) { getImageIndex(image: ImageMetadata) {
return this.images.findIndex(img => image === img); return this.images.findIndex(img => image === img);
} }
getRelatedImageMeta(image: ImageMetadata, images: ImageMetadata[] = []) { getRelatedImageMeta(image: ImageMetadata) {
const found = this.images.find(im => im.previous === image.identifier); return this.images.filter(im => im.identifier.includes(image.identifier) && im.identifier !== image.identifier);
if (found) {
return this.getRelatedImageMeta(found, images.concat(found));
} else {
return images;
} }
checkValidity() {
setTimeout(() => {
const start = this.paginationGetStart();
const end = this.paginationGetEnd();
const filteredImages = this.filterOnlyNewestImageVersion();
this.logger.debug('check validity', start, end, filteredImages);
for (let i = start; i < end; i++) {
try {
filteredImages[i].valid = undefined;
filteredImages[i].available = undefined;
this.restService.checkImageValid(filteredImages[i].identifier).toPromise().then(
res => {
filteredImages[i].valid = res.valid;
filteredImages[i].available = res.available;
}
);
} catch {
this.logger.debug('skip non-existing index', i);
}
}
}, 500);
} }
} }

View File

@ -28,7 +28,19 @@ export class LandingComponent implements OnInit {
} }
loadImages(): void { loadImages(): void {
this.restService.getAllImages().toPromise().then(images => this.images = images).catch(err => this.logger.error(err)); this.restService.getAllImages().toPromise().then(images =>
this.images = images.sort((im1, im2) => {
if (im1.name > im2.name) {
return 1;
}
if (im1.name < im2.name) {
return -1;
}
return 0;
})
).catch(err => this.logger.error(err));
} }

View File

@ -5,15 +5,33 @@
[longitude]="longitude" [longitude]="longitude"
[zoom]="2"> [zoom]="2">
<agm-marker <agm-marker
*ngFor="let image of images" *ngFor="let image of getImagesForMap()"
[latitude]="image.latitude" [latitude]="image.latitude"
[longitude]="image.longitude" [longitude]="image.longitude"
[opacity]="1" [opacity]="1"
[markerDraggable]="true" [markerDraggable]="false"
(markerClick)="selectMarker($event)" (markerClick)="loadImage(selectMarker($event))"
></agm-marker> ></agm-marker>
</agm-map> </agm-map>
<p *ngIf="selectedImage"> <div *ngIf="selectedImage">
Latitude: {{ selectedImage.latitude }} Longitude: {{ selectedImage.longitude }} Name: {{selectedImage.name}} Latitude: {{ selectedImage.latitude }} Longitude: {{ selectedImage.longitude }} Name: {{selectedImage.name}}
</p>
<mat-divider style="margin-bottom: 1em;"></mat-divider>
<div style="width: 20em; height: 20em; border: solid; margin-bottom: 1em; display: flex">
<img *ngIf="selectedImage.image_b64, let b64; else loadingImage"
[src]="b64"
style="width: 100%; margin: auto" [alt]="selectedImage.filename"/>
<ng-template #loadingImage>
<mat-spinner style="margin: auto;"></mat-spinner>
</ng-template>
</div>
<p *ngIf="selectedImage.filename">filename: {{selectedImage.filename}}</p>
<!-- <p *ngIf="selectedImage.latitude">latitude: {{selectedImage.latitude}}</p>-->
<!-- <p *ngIf="selectedImage.longitude">longitude: {{selectedImage.longitude}}</p>-->
<p *ngIf="selectedImage.version">version: {{selectedImage.version}}</p>
<p *ngIf="selectedImage.tag">tag: {{selectedImage.tag}}</p>
<!-- <p *ngIf="selectedImage.name">name: {{selectedImage.name}}</p>-->
</div>

View File

@ -1,5 +1,6 @@
import {Component, Input, OnInit} from '@angular/core'; import {Component, Input, OnInit} from '@angular/core';
import {ImageMetadata} from '../../interfaces/interface'; import {ImageMetadata} from '../../interfaces/interface';
import {RestService} from '../../services/rest.service';
// @ts-ignore // @ts-ignore
@Component({ @Component({
@ -16,7 +17,7 @@ export class MapComponent implements OnInit {
latitude = 43.879078; latitude = 43.879078;
longitude = -103.4615581; longitude = -103.4615581;
constructor() { constructor(private restService: RestService) {
} }
@ -25,6 +26,25 @@ export class MapComponent implements OnInit {
} }
selectMarker(event) { selectMarker(event) {
this.selectedImage = this.images.find(image => image.latitude === event.latitude && image.longitude === event.longitude); console.log(event, this.images);
this.selectedImage = this.images.find(image =>
image.latitude === event.latitude && image.longitude === event.longitude && !image.identifier.includes('_')
);
return this.selectedImage;
} }
getImagesForMap() {
return this.images.filter(im => !im.identifier.includes('_'));
}
loadImage(image: ImageMetadata): void {
image.image_b64 = '';
this.restService.getImage(image.identifier).toPromise().then(im => {
image.image_b64 = 'data:image/jpg;base64,' + im.image_data;
}).catch(err => {
console.error('loadImage', image, err);
});
}
} }

View File

@ -3,6 +3,8 @@ export interface StorageHealth {
} }
export interface ImageMetadata { export interface ImageMetadata {
available?: boolean;
valid?: boolean;
id: string; id: string;
datetime: string; datetime: string;
device_id: string; device_id: string;
@ -34,3 +36,8 @@ export interface ImagePostResponse {
id: string; id: string;
filename: string; filename: string;
} }
export interface Validity {
available: boolean;
valid: boolean;
}

View File

@ -4,11 +4,10 @@ import {NGXLogger} from 'ngx-logger';
import {environment} from '../../environments/environment'; import {environment} from '../../environments/environment';
import {Observable} from 'rxjs'; import {Observable} from 'rxjs';
import {tap} from 'rxjs/operators'; import {tap} from 'rxjs/operators';
import {GetImageResponse, ImagePostResponse, StorageHealth} from '../interfaces/interface'; import {GetImageResponse, ImagePostResponse, StorageHealth, Validity} from '../interfaces/interface';
@Injectable() @Injectable()
export class RestService { export class RestService {
constructor( constructor(
private logger: NGXLogger, private logger: NGXLogger,
private http: HttpClient private http: HttpClient
@ -21,6 +20,7 @@ export class RestService {
private deleteImageUrl = this.imageUrl + '/delete'; private deleteImageUrl = this.imageUrl + '/delete';
private postImageUrl = this.imageUrl + '/post'; private postImageUrl = this.imageUrl + '/post';
private updateImageUrl = this.imageUrl + '/update'; private updateImageUrl = this.imageUrl + '/update';
private getValidityOfImageUrl = this.imageUrl + '/status';
private healthCheckUrl = this.currentLocation + '/check'; private healthCheckUrl = this.currentLocation + '/check';
public getAllImages(): Observable<any> { public getAllImages(): Observable<any> {
@ -78,4 +78,10 @@ export class RestService {
tap(next => this.logger.debug('healthCheck', next)) tap(next => this.logger.debug('healthCheck', next))
); );
} }
public checkImageValid(id: string): Observable<Validity> {
return this.http.get<Validity>(this.getValidityOfImageUrl + '/' + id).pipe(
tap(next => this.logger.debug('checkValid', id, next))
);
}
} }

View File

@ -17,7 +17,9 @@
"es2017", "es2017",
"dom" "dom"
], ],
"allowJs": true "allowJs": true,
"resolveJsonModule": true,
"esModuleInterop": true
} }
} }

View File

@ -4,7 +4,7 @@ import requests
import json import json
import time import time
from datetime import datetime from datetime import datetime
import sys, getopt import sys, getopt, random
def build_post_payload(identifier, metadata_payload, file_payload): def build_post_payload(identifier, metadata_payload, file_payload):
return { return {
@ -233,16 +233,75 @@ def print_cursor():
print('Cursor on ' + str(index) + " out of " + str(len(metadata)) + " - " + metadata[index]['filename']) print('Cursor on ' + str(index) + " out of " + str(len(metadata)) + " - " + metadata[index]['filename'])
testCommands=[]
testscriptData=[]
def test_script(argv):
try:
testscriptData.append(False)
testscriptData.append(0)
opts, args=getopt.getopt(argv,"t")
except getopt.GetoptError:
print("Error by starting test script")
sys.exit(2)
for opt, arg in opts:
if opt == '-t':
testscriptData.clear()
testscriptData.append(True)
testCommands.append("deleteall")
for i in range(2):
testCommands.append("trigger")
testCommands.append("fetchall")
testCommands.append("delete")
testCommands.append("fetchall")
for i in range(3):
testCommands.append("trigger")
testCommands.append("update")
testCommands.append("fetchall")
for i in range(2):
testCommands.append("trigger")
testCommands.append("update")
testCommands.append("trigger")
testCommands.append("delete")
testCommands.append("fetchall")
for i in range(3):
testCommands.append("trigger")
testCommands.append("update")
testCommands.append("fetchall")
for i in range(2):
testCommands.append("trigger")
testCommands.append("fetchall")
testCommands.append("delete")
testCommands.append("fetchall")
for i in range(5):
testCommands.append("trigger")
testCommands.append("fetchall")
testCommands.append("exit")
testscriptData.append(len(testCommands))
else:
testscriptData.append(False)
testscriptData.append(0)
# main input loop # main input loop
command = "dummy" command = "dummy"
test_script(sys.argv[1:])
i = 0
while (command.lower() not in ["exit", "quit", "end"]): while (command.lower() not in ["exit", "quit", "end"]):
try: try:
if testscriptData[0] and i < testscriptData[1]:
command = testCommands[i]
if i > 0:
time.sleep(random.randrange(5, 60))
print(datetime.now())
if command == "delete" or command == "update":
index -= 1
i+=1
else:
command = input("Please enter command: ") command = input("Please enter command: ")
except: except Exception as ex:
print() print(ex)
print("Error while reading keyboard input") print("Error while reading keyboard input")
break break
command_split = command.split(" ") command_split = command.split(" ")

View File

@ -70,7 +70,7 @@ class DropboxService(StorageServiceInterface):
return file_bytes return file_bytes
@staticmethod @staticmethod
def move_file(identifier_from: str, identifier_to: str, file: bytes) -> bool: def move_file(identifier_from: str, identifier_to: str) -> bool:
"""Move/Rename a file on the dropbox storage. """Move/Rename a file on the dropbox storage.
:param identifier_from: Location of the file to be moved :param identifier_from: Location of the file to be moved

View File

@ -66,7 +66,7 @@ class MinioService(StorageServiceInterface):
return True return True
@staticmethod @staticmethod
def move_file(identifier_from: str, identifier_to: str, file: bytes) -> bool: def move_file(identifier_from: str, identifier_to: str) -> bool:
"""Move/Rename a file on the S3 storage. """Move/Rename a file on the S3 storage.
Consists of a PUT method (copying the object) and a delete method. Consists of a PUT method (copying the object) and a delete method.
@ -79,6 +79,8 @@ class MinioService(StorageServiceInterface):
filename_from = identifier_from + '.jpg' filename_from = identifier_from + '.jpg'
filename_to = identifier_to filename_to = identifier_to
file = MinioService.read_file(filename_from)
if not MinioService.delete_file(filename_from): if not MinioService.delete_file(filename_from):
print("MinioService: Updating (delete) file {} failed".format(filename_from)) print("MinioService: Updating (delete) file {} failed".format(filename_from))
return False return False

View File

@ -74,20 +74,22 @@ class MongoDBService:
old = {"identifier": identifier} # Query for old version old = {"identifier": identifier} # Query for old version
metadata_orig = MongoDBService.getSingle(identifier) existing_meta_data_copy = MongoDBService.getSingle(identifier)
metadata_new = metadata_orig id_for_previous = identifier + '_' + str(meta['version'])
metadata_new['previous'] = identifier + '_' + str(metadata_orig['version']) existing_meta_data_copy['previous'] = id_for_previous
identifier_changed = identifier + '_' + str(metadata_orig['version']) # Set identifier to include version identifier_changed = id_for_previous # Set identifier to include version
metadata_new['version'] = str(int(metadata_new['version']) + 1) # Increment version by one
metadata_new.update(meta) del meta['filename']
existing_meta_data_copy.update(meta)
existing_meta_data_copy['version'] = meta['version'] + 1 # Increment version by one
print("MongoDBService: identifier_changed: ", identifier_changed) print("MongoDBService: identifier_changed: ", identifier_changed)
col.update_one(old, {"$set": {"identifier": identifier_changed, "filename": identifier_changed + '.jpg'}}) col.update_one(old, {"$set": {"identifier": identifier_changed, "filename": identifier_changed + '.jpg'}})
print("MongoDBService: Old object is ", col.find_one({"identifier": identifier_changed})) print("MongoDBService: Old object is ", col.find_one({"identifier": identifier_changed}))
MongoDBService.createSingle(metadata_new, identifier, decoded_image) MongoDBService.createSingle(existing_meta_data_copy, identifier, decoded_image)
print("MongoDBService: New object is ", col.find_one({"identifier": identifier})) print("MongoDBService: New object is ", col.find_one({"identifier": identifier}))
return True return True

View File

@ -24,6 +24,7 @@ urlpatterns = [
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
url(r'^image/get/all$', ImageEndpoint.image_api_get_all), url(r'^image/get/all$', ImageEndpoint.image_api_get_all),
url(r'^image/get/(?P<identifier>[\w-]+)$', ImageEndpoint.image_api_get_single), url(r'^image/get/(?P<identifier>[\w-]+)$', ImageEndpoint.image_api_get_single),
url(r'^image/status/(?P<identifier>[\w-]+)$', ImageEndpoint.image_api_get_status),
url(r'^image/get/(?P<identifier>[\w-]+)/version/(?P<version>[\w-]+)$', ImageEndpoint.image_api_get_single_version), url(r'^image/get/(?P<identifier>[\w-]+)/version/(?P<version>[\w-]+)$', ImageEndpoint.image_api_get_single_version),
url(r'^image/delete/all$', ImageEndpoint.image_api_delete_all), url(r'^image/delete/all$', ImageEndpoint.image_api_delete_all),
url(r'^image/delete/(?P<identifier>[\w-]+)$', ImageEndpoint.image_api_delete), url(r'^image/delete/(?P<identifier>[\w-]+)$', ImageEndpoint.image_api_delete),

View File

@ -48,6 +48,31 @@ class ImageEndpoint:
logger.debug('Image GET single call: {}'.format(request)) logger.debug('Image GET single call: {}'.format(request))
return ImageEndpoint.get_image(identifier) return ImageEndpoint.get_image(identifier)
@staticmethod
@api_view(['GET'])
def image_api_get_status(request, identifier):
# get metadata from MongoDB
metadata = MongoDBService.getSingle(identifier)
if not metadata:
return JsonResponse({'valid': False, 'available': False})
# get stored SHA512 hash
stored_hash = metadata.get('sha512', '')
no_image = True
for service in ImageEndpoint.storageServiceList:
service_image_bytes = service.read_file(metadata['filename'])
if service_image_bytes is not None:
no_image = False
actual_service_hash = create_sha512(service_image_bytes)
if stored_hash != actual_service_hash:
return JsonResponse({'valid': False, 'available': True})
if no_image:
JsonResponse({'valid': False, 'available': False})
return JsonResponse({'valid': True, 'available': True})
@staticmethod @staticmethod
def get_image(identifier): def get_image(identifier):
@ -210,7 +235,6 @@ class ImageEndpoint:
def image_api_update(request, identifier): def image_api_update(request, identifier):
logger.debug('Image UPDATE single call: {}'.format(request)) logger.debug('Image UPDATE single call: {}'.format(request))
try: try:
payload = json.loads(request.body) payload = json.loads(request.body)
except json.decoder.JSONDecodeError: except json.decoder.JSONDecodeError:
@ -222,7 +246,7 @@ class ImageEndpoint:
'Error': str(e)}, status=500, safe=False) 'Error': str(e)}, status=500, safe=False)
b64encoded_image = payload['image_data'] b64encoded_image = payload['image_data']
identifier = payload['id'] # identifier = identifier
metadata = payload['metadata'] metadata = payload['metadata']
filename = payload['metadata']['filename'] filename = payload['metadata']['filename']
@ -233,6 +257,7 @@ class ImageEndpoint:
'id': identifier}, status=404, safe=False) 'id': identifier}, status=404, safe=False)
metadata['version'] = mongodb_metadata['version'] metadata['version'] = mongodb_metadata['version']
filename = mongodb_metadata['filename']
decoded_image = WrapperService.unwrap_file(b64encoded_image) decoded_image = WrapperService.unwrap_file(b64encoded_image)
@ -240,7 +265,7 @@ class ImageEndpoint:
for service in ImageEndpoint.storageServiceList: for service in ImageEndpoint.storageServiceList:
orig_new_name = identifier + '_' + str(metadata['version']) + '.jpg' orig_new_name = identifier + '_' + str(metadata['version']) + '.jpg'
if not service.move_file(identifier, orig_new_name, decoded_image): if not service.move_file(identifier, orig_new_name):
print("Could not move file from {} to {}".format(identifier, orig_new_name)) print("Could not move file from {} to {}".format(identifier, orig_new_name))
if not service.create_file(filename, decoded_image): if not service.create_file(filename, decoded_image):
print("Could not save updated image to " + service.name) print("Could not save updated image to " + service.name)