From 63f7d733dc29f79a7d6616679bbe20395585e929 Mon Sep 17 00:00:00 2001 From: Marco Zeisler Date: Mon, 11 Jan 2021 21:45:14 +0100 Subject: [PATCH] implement image post, put, delete; --- frontend/package-lock.json | 15 +++++ frontend/package.json | 1 + frontend/src/app/app.module.ts | 59 ++++++++++--------- .../component/images/images.component.html | 25 ++++++-- .../app/component/images/images.component.ts | 37 +++++++++++- frontend/src/app/interfaces/interface.ts | 1 + frontend/src/app/services/rest.service.ts | 59 ++++++++++++------- frontend/src/index.html | 4 +- frontend/src/styles.css | 10 +++- middleware/app_be/services/mongodbservice.py | 1 + middleware/app_be/urls.py | 8 +-- 11 files changed, 154 insertions(+), 66 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index e8ed7d7..1d8c39d 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -3334,6 +3334,21 @@ "dev": true, "optional": true }, + "angular-file-uploader": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/angular-file-uploader/-/angular-file-uploader-7.0.3.tgz", + "integrity": "sha512-0wkr/3Vn3toG/2sTSiD5vJ5EK3HKYXwzyFd3M3hRegcHhQnagN34licn4r+CBWJQQED5aRWUVB9OWOCtuNwimw==", + "requires": { + "tslib": "^2.0.0" + }, + "dependencies": { + "tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" + } + } + }, "ansi-colors": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", diff --git a/frontend/package.json b/frontend/package.json index a3bca3c..84fee1d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -26,6 +26,7 @@ "@angular/platform-browser-dynamic": "~9.1.9", "@angular/router": "~9.1.9", "@types/uuid": "8.3.0", + "angular-file-uploader": "^7.0.3", "bootstrap": "~4.3.1", "jquery": "3.5.1", "ngx-logger": "4.1.9", diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 1d253a5..23c06be 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -18,39 +18,40 @@ import {MatCardModule} from '@angular/material/card'; import {MatPaginatorModule} from '@angular/material/paginator'; import {MatTableModule} from '@angular/material/table'; import {MatTabsModule} from '@angular/material/tabs'; -import { ImagesComponent } from './component/images/images.component'; -import { MapComponent } from './component/map/map.component'; +import {ImagesComponent} from './component/images/images.component'; +import {MapComponent} from './component/map/map.component'; import {AgmCoreModule} from '@agm/core'; +import {AngularFileUploaderModule} from 'angular-file-uploader'; @NgModule({ declarations: [LandingComponent, ImagesComponent, MapComponent], - imports: [ - ReactiveFormsModule, - BrowserModule, - BrowserAnimationsModule, - LoggerModule.forRoot({level: environment.log_level, serverLogLevel: NgxLoggerLevel.ERROR}), - HttpClientModule, - MatFormFieldModule, - FormsModule, - MatButtonModule, - MatInputModule, - MatSlideToggleModule, - MatListModule, - MatExpansionModule, - MatCardModule, - MatPaginatorModule, - MatTableModule, - MatTabsModule, - // GoogleMapsModule, - AgmCoreModule.forRoot({ - apiKey: 'AIzaSyBDgLJ1sL48IQg7e5jrwmUyXkqeEfVnf78' - /* apiKey is required, unless you are a - premium customer, in which case you can - use clientId - */ - }) - - ], + imports: [ + ReactiveFormsModule, + BrowserModule, + BrowserAnimationsModule, + LoggerModule.forRoot({level: environment.log_level, serverLogLevel: NgxLoggerLevel.ERROR}), + HttpClientModule, + MatFormFieldModule, + FormsModule, + MatButtonModule, + MatInputModule, + MatSlideToggleModule, + MatListModule, + MatExpansionModule, + MatCardModule, + MatPaginatorModule, + MatTableModule, + MatTabsModule, + // GoogleMapsModule, + AgmCoreModule.forRoot({ + apiKey: 'AIzaSyBDgLJ1sL48IQg7e5jrwmUyXkqeEfVnf78' + /* apiKey is required, unless you are a + premium customer, in which case you can + use clientId + */ + }), + AngularFileUploaderModule, + ], // enables injecting providers: [ RestService, diff --git a/frontend/src/app/component/images/images.component.html b/frontend/src/app/component/images/images.component.html index 8e618f6..2ca4fa3 100644 --- a/frontend/src/app/component/images/images.component.html +++ b/frontend/src/app/component/images/images.component.html @@ -1,18 +1,30 @@

Available Images

-
- Name +
+ Name Date
- + {{image.name}} {{image.datetime}} - TEST + +
+ IMAGE +
+ + + + + +
+ +

Upload New Image

+ + diff --git a/frontend/src/app/component/images/images.component.ts b/frontend/src/app/component/images/images.component.ts index a74c42b..bf35946 100644 --- a/frontend/src/app/component/images/images.component.ts +++ b/frontend/src/app/component/images/images.component.ts @@ -1,13 +1,16 @@ -import {Component, Input, OnInit} from '@angular/core'; +import {AfterViewInit, Component, Input, OnInit} from '@angular/core'; import {PageEvent} from '@angular/material/paginator'; import {ImageMetadata} from '../../interfaces/interface'; +import {RestService} from '../../services/rest.service'; +import {NGXLogger} from 'ngx-logger'; +import {AngularFileUploaderConfig} from 'angular-file-uploader'; @Component({ selector: 'app-images', templateUrl: './images.component.html', styleUrls: ['./images.component.css'] }) -export class ImagesComponent implements OnInit { +export class ImagesComponent implements OnInit, AfterViewInit { @Input() images: ImageMetadata[]; @@ -15,12 +18,26 @@ export class ImagesComponent implements OnInit { pageSizeOptions: number[] = [5, 10, 25, 100]; lastPageEvent: PageEvent; - constructor() { } + imageUploadConfig: AngularFileUploaderConfig = { + uploadAPI: { + url: this.restService.getPostImageUrl() + } + }; + + constructor( + public restService: RestService, + private logger: NGXLogger + ) { + } ngOnInit(): void { this.lastPageEvent = {pageIndex: 0, pageSize: this.pageSizeOptions[0], length: this.images.length}; } + ngAfterViewInit(): void { + + } + paginationGetStart(): number { return this.lastPageEvent.pageIndex * this.lastPageEvent.pageSize; } @@ -29,4 +46,18 @@ export class ImagesComponent implements OnInit { return this.paginationGetStart() + this.lastPageEvent.pageSize; } + getImageUpdateConfig(filename: string): AngularFileUploaderConfig { + return { + uploadAPI: { + url: this.restService.getUpdateImageUrl(filename), + method: 'PUT' + } + }; + } + + deleteImage(image: ImageMetadata) { + this.restService.deleteImage(image.filename).toPromise().then(() => { + this.images = this.images.filter(im => im !== image); + }).catch(err => this.logger.error(err)); + } } diff --git a/frontend/src/app/interfaces/interface.ts b/frontend/src/app/interfaces/interface.ts index e7b0fa2..ddb4390 100644 --- a/frontend/src/app/interfaces/interface.ts +++ b/frontend/src/app/interfaces/interface.ts @@ -3,6 +3,7 @@ export interface StorageHealth { } export interface ImageMetadata { + id: string; datetime: string; device_id: string; filename: string; diff --git a/frontend/src/app/services/rest.service.ts b/frontend/src/app/services/rest.service.ts index bf073dd..8eceac0 100644 --- a/frontend/src/app/services/rest.service.ts +++ b/frontend/src/app/services/rest.service.ts @@ -8,34 +8,42 @@ import {StorageHealth} from '../interfaces/interface'; @Injectable() export class RestService { - private currentLocation = 'http://' + environment.location + ':' + environment.port + '/'; - private imageUrl = this.currentLocation + 'image/'; - private getImageUrl = this.imageUrl + 'get/'; - private deleteImageUrl = this.imageUrl + 'delete/'; - private postImageUrl = this.imageUrl + 'post$/'; - private updateImageUrl = this.imageUrl + 'update/'; - private healthCheckUrl = this.currentLocation + 'check'; constructor( private logger: NGXLogger, private http: HttpClient ) { } + private currentLocation = 'http://' + environment.location + ':' + environment.port; + private imageUrl = this.currentLocation + '/image'; + private getImageUrl = this.imageUrl + '/get'; + private deleteImageUrl = this.imageUrl + '/delete'; + private postImageUrl = this.imageUrl + '/post'; + private updateImageUrl = this.imageUrl + '/update'; + private healthCheckUrl = this.currentLocation + '/check'; + + private static stripUploadFileName(name: string) { + // const generalUploadFileName: string = + // (document.getElementById('generalUpload').firstChild as HTMLElement).children[5].children[0].textContent; + // this.logger.debug('Get filename', generalUploadFileName); + const temp: string[] = name.split('.'); + return temp.slice(0, temp.length - 1).join('.'); + } public getAllImages(): Observable { - return this.http.get(this.getImageUrl + 'all').pipe( + return this.http.get(this.getImageUrl + '/all').pipe( tap(next => this.logger.debug('getAllImages', next)) ); } public getImage(id: string): Observable { return this.http.get(this.getImageUrl + id).pipe( - tap(next => this.logger.debug('getImage', id, next)) + tap(next => this.logger.debug('/getImage', id, next)) ); } public getImageVersion(id: string, version: string): Observable { - return this.http.get(this.getImageUrl + id + '/version/' + version).pipe( + return this.http.get(this.getImageUrl + '/' + id + '/version/' + version).pipe( tap(next => this.logger.debug('getImageVersion', id, version, next)) ); } @@ -46,22 +54,31 @@ export class RestService { ); } - public deleteImage(id: string): Observable { - return this.http.delete(this.deleteImageUrl + id).pipe( - tap(next => this.logger.debug('deleteImage', id, next)) + public deleteImage(filenameWithExtension: string): Observable { + const stripped = RestService.stripUploadFileName(filenameWithExtension); + return this.http.delete(this.deleteImageUrl + '/' + stripped).pipe( + tap(next => this.logger.debug('deleteImage', stripped, next)) ); } - public postImage(id: string, image: any): Observable { - return this.http.post(this.postImageUrl + id, image).pipe( - tap(next => this.logger.debug('postImage', id, image, next)) - ); + // public postImage(id: string, image: any): Observable { + // return this.http.post(this.postImageUrl + '/' + id, image).pipe( + // tap(next => this.logger.debug('postImage', id, image, next)) + // ); + // } + + public getPostImageUrl(): string { + return this.postImageUrl; } - public updateImage(id: string, image: any): Observable { - return this.http.put(this.updateImageUrl + id, image).pipe( - tap(next => this.logger.debug('updateImage', id, image, next)) - ); + // public updateImage(id: string, image: any): Observable { + // return this.http.put(this.updateImageUrl + '/' + id, image).pipe( + // tap(next => this.logger.debug('updateImage', id, image, next)) + // ); + // } + + public getUpdateImageUrl(filenameWithExtension: string): string { + return this.updateImageUrl + '/' + RestService.stripUploadFileName(filenameWithExtension); } public healthCheck(): Observable { diff --git a/frontend/src/index.html b/frontend/src/index.html index efc5b2e..aad521b 100644 --- a/frontend/src/index.html +++ b/frontend/src/index.html @@ -12,6 +12,4 @@ - - - + diff --git a/frontend/src/styles.css b/frontend/src/styles.css index 99d58e2..6ff0f14 100644 --- a/frontend/src/styles.css +++ b/frontend/src/styles.css @@ -5,7 +5,7 @@ body { width: 95%; - margin: auto; + margin: auto !important; } h1, h2 { @@ -13,5 +13,11 @@ h1, h2 { } h2 { - margin-bottom: 1.5em; + padding-bottom: 1.5em; +} + +#default { + margin-left: 0 !important; + padding-left: 0 !important; + margin-bottom: 1em; } diff --git a/middleware/app_be/services/mongodbservice.py b/middleware/app_be/services/mongodbservice.py index b44d6ef..e2d590e 100644 --- a/middleware/app_be/services/mongodbservice.py +++ b/middleware/app_be/services/mongodbservice.py @@ -23,6 +23,7 @@ class MongoDBService: try: for meta in col.find(): + meta['id'] = str(meta['_id']) del meta['_id'] resp.append(meta) except: diff --git a/middleware/app_be/urls.py b/middleware/app_be/urls.py index f4d73de..e6ec0af 100644 --- a/middleware/app_be/urls.py +++ b/middleware/app_be/urls.py @@ -23,12 +23,12 @@ from app_be.views.rest_api import TestApiClass, ImageEndpoint, HealthEndpoint urlpatterns = [ path('admin/', admin.site.urls), url(r'^image/get/all$', ImageEndpoint.image_api_get_all), - url(r'^image/get/(?P[\w-]+)$', ImageEndpoint.image_api_get_single), - url(r'^image/get/(?P[\w-]+)/version/(?P[\w-]+)$', ImageEndpoint.image_api_get_single_version), + url(r'^image/get/(?P[\w.-]+)$', ImageEndpoint.image_api_get_single), + url(r'^image/get/(?P[\w.-]+)/version/(?P[\w-]+)$', ImageEndpoint.image_api_get_single_version), url(r'^image/delete/all$', ImageEndpoint.image_api_delete_all), - url(r'^image/delete/(?P[\w-]+)$', ImageEndpoint.image_api_delete), + url(r'^image/delete/(?P[\w.-]+)$', ImageEndpoint.image_api_delete), url(r'^image/post$', ImageEndpoint.image_api_post), - url(r'^image/update/(?P[\w-]+)$', ImageEndpoint.image_api_update), + url(r'^image/update/(?P[\w.-]+)$', ImageEndpoint.image_api_update), url(r'^check', HealthEndpoint.check_systems) ]