[DEV] add drag & drop

This commit is contained in:
Edouard DUPIN 2024-04-17 23:38:00 +02:00
parent 334d68ac1f
commit d8ceaef3f9
30 changed files with 498 additions and 309 deletions

View File

@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.kar</groupId>
<artifactId>karideo</artifactId>
<version>0.2.0</version>
<version>0.3.0</version>
<properties>
<maven.compiler.version>3.1</maven.compiler.version>
<maven.compiler.source>21</maven.compiler.source>
@ -20,7 +20,7 @@
<dependency>
<groupId>kangaroo-and-rabbit</groupId>
<artifactId>archidata</artifactId>
<version>0.7.1</version>
<version>0.7.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>

View File

@ -35,7 +35,6 @@ import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
@Path("/media")
@Produces(MediaType.APPLICATION_JSON)
@ -63,7 +62,7 @@ public class MediaResource {
@Consumes(MediaType.APPLICATION_JSON)
@Operation(description = "Modify a specific Media", tags = "GLOBAL")
public Media patch(@PathParam("id") final Long id, @AsyncType(Media.class) final String jsonRequest) throws Exception {
System.out.println("update video " + id + " ==> '" + jsonRequest + "'");
LOGGER.info("update video {} ==> '{}'", id, jsonRequest);
DataAccess.updateWithJson(Media.class, id, jsonRequest);
return DataAccess.get(Media.class, id);
}
@ -85,12 +84,19 @@ public class MediaResource {
@RolesAllowed("ADMIN")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@Operation(description = "Create a new Media", tags = "GLOBAL")
@AsyncType(Media.class)
@TypeScriptProgress
public Response uploadFile(@FormDataParam("fileName") String fileName, @FormDataParam("universe") String universe, @FormDataParam("series") String series,
//@FormDataParam("seriesId") String seriesId, Not used ...
@FormDataParam("season") String season, @FormDataParam("episode") String episode, @FormDataParam("title") String title, @FormDataParam("typeId") String typeId,
@FormDataParam("file") final InputStream fileInputStream, @FormDataParam("file") final FormDataContentDisposition fileMetaData) throws FailException {
public Media uploadFile( //
@FormDataParam("fileName") String fileName, //
@FormDataParam("universe") String universe, //
@FormDataParam("series") String series, //
//@FormDataParam("seriesId") String seriesId, // Not used ...
@FormDataParam("season") String season, //
@FormDataParam("episode") String episode, //
@FormDataParam("title") String title, //
@FormDataParam("typeId") String typeId, //
@FormDataParam("file") final InputStream fileInputStream, //
@FormDataParam("file") final FormDataContentDisposition fileMetaData //
) throws FailException {
try {
// correct input string stream :
fileName = multipartCorrection(fileName);
@ -102,16 +108,16 @@ public class MediaResource {
typeId = multipartCorrection(typeId);
//public NodeSmall uploadFile(final FormDataMultiPart form) {
System.out.println("Upload media file: " + fileMetaData);
System.out.println(" - fileName: " + fileName);
System.out.println(" - universe: " + universe);
System.out.println(" - series: " + series);
System.out.println(" - season: " + season);
System.out.println(" - episode: " + episode);
System.out.println(" - title: " + title);
System.out.println(" - type: " + typeId);
System.out.println(" - fileInputStream: " + fileInputStream);
System.out.println(" - fileMetaData: " + fileMetaData);
LOGGER.info("Upload media file: {}", fileMetaData);
LOGGER.info(" - fileName: {}", fileName);
LOGGER.info(" - universe: {}", universe);
LOGGER.info(" - series: {}", series);
LOGGER.info(" - season: {}", season);
LOGGER.info(" - episode: {}", episode);
LOGGER.info(" - title: {}", title);
LOGGER.info(" - type: {}", typeId);
LOGGER.info(" - fileInputStream: {}", fileInputStream);
LOGGER.info(" - fileMetaData: {}", fileMetaData);
System.out.flush();
if (typeId == null) {
throw new InputException("typeId", "TypiId is not specified");
@ -121,7 +127,7 @@ public class MediaResource {
final String sha512 = DataResource.saveTemporaryFile(fileInputStream, tmpUID);
Data data = DataResource.getWithSha512(sha512);
if (data == null) {
System.out.println("Need to add the data in the BDD ... ");
LOGGER.info("Need to add the data in the BDD ... ");
System.out.flush();
try {
data = DataResource.createNewData(tmpUID, fileName, sha512);
@ -130,33 +136,33 @@ public class MediaResource {
ex.printStackTrace();
throw new FailException("can not create input media (the data model has an internal error");
}
} else if (data!= null && data.deleted) {
System.out.println("Data already exist but deleted");
} else if (data!= null && data.deleted != null && data.deleted) {
LOGGER.info("Data already exist but deleted");
System.out.flush();
DataTools.undelete(data.id);
data.deleted = false;
} else {
System.out.println("Data already exist ... all good");
LOGGER.info("Data already exist ... all good");
System.out.flush();
}
// Fist step: retieve all the Id of each parents:...
System.out.println("Find typeNode");
LOGGER.info("Find typeNode");
// check if id of type exist:
final Type typeNode = TypeResource.getId(Long.parseLong(typeId));
if (typeNode == null) {
DataResource.removeTemporaryFile(tmpUID);
throw new InputException("typeId", "TypeId does not exist ...");
}
System.out.println(" ==> " + typeNode);
System.out.println("Find seriesNode");
LOGGER.info(" ==> {}", typeNode);
LOGGER.info("Find seriesNode");
// get uid of group:
Series seriesNode = null;
if (series != null) {
seriesNode = SeriesResource.getOrCreate(series, typeNode.id);
}
System.out.println(" ==> " + seriesNode);
System.out.println("Find seasonNode");
LOGGER.info(" ==> {}", seriesNode);
LOGGER.info("Find seasonNode");
// get uid of season:
Season seasonNode = null;
if (seriesNode == null && season != null) {
@ -167,10 +173,9 @@ public class MediaResource {
seasonNode = SeasonResource.getOrCreate(season, seriesNode.id);
}
System.out.println(" ==> " + seasonNode);
System.out.println("add media");
LOGGER.info(" ==> {}", seasonNode);
LOGGER.info("add media");
final long uniqueSQLID = -1;
try {
final Media media = new Media();
media.name = title;
@ -189,17 +194,17 @@ public class MediaResource {
media.episode = Integer.parseInt(episode);
}
final Media out = DataAccess.insert(media);
DataResource.removeTemporaryFile(tmpUID);
System.out.println("uploaded .... compleate: " + uniqueSQLID);
final Media creation = get(uniqueSQLID);
return Response.ok(creation).build();
LOGGER.info("Generate new media {}", out);
return out;
} catch (final SQLException ex) {
ex.printStackTrace();
System.out.println("Catch error:" + ex.getMessage());
LOGGER.error("Catch error: {}", ex.getMessage());
throw new FailException("Catch SQLerror ==> check server logs");
} finally {
DataResource.removeTemporaryFile(tmpUID);
}
} catch (final Exception ex) {
System.out.println("Catch an unexpected error ... " + ex.getMessage());
LOGGER.error("Catch an unexpected error ... {} ", ex.getMessage());
ex.printStackTrace();
throw new FailException("Catch Exception ==> check server logs");
}

View File

@ -119,9 +119,17 @@ public class Migration20240226 extends MigrationSqlStep {
}
}
});
/* I am not sure then I prefer keep the primary key for the moment
addAction("""
ALTER TABLE `data` DROP `id`;
""");
*/
addAction("""
ALTER TABLE `data` CHANGE `id` `idOld` bigint NOT NULL DEFAULT 0;
""");
addAction("""
ALTER TABLE `data` DROP PRIMARY KEY;
""");
addAction("""
ALTER TABLE `data` CHANGE `uuid` `id` binary(16) DEFAULT (UUID_TO_BIN(UUID(), TRUE));
""");

View File

@ -49,4 +49,13 @@ public class Media extends GenericDataSoftDelete {
// List of Id of the specific covers
@DataJson(targetEntity = Data.class)
public List<UUID> covers = null;
@Override
public String toString() {
return "Media [name=" + this.name + ", description=" + this.description + ", dataId=" + this.dataId + ", typeId=" + this.typeId
+ ", seriesId=" + this.seriesId + ", seasonId=" + this.seasonId + ", episode=" + this.episode + ", date=" + this.date
+ ", time=" + this.time + ", ageLimit=" + this.ageLimit + ", covers=" + this.covers + "]";
}
}

View File

@ -19,31 +19,31 @@
},
"private": true,
"dependencies": {
"@angular/animations": "^17.3.4",
"@angular/cdk": "^17.3.4",
"@angular/common": "^17.3.4",
"@angular/compiler": "^17.3.4",
"@angular/core": "^17.3.4",
"@angular/forms": "^17.3.4",
"@angular/material": "^17.3.4",
"@angular/platform-browser": "^17.3.4",
"@angular/platform-browser-dynamic": "^17.3.4",
"@angular/router": "^17.3.4",
"@angular/animations": "^17.3.5",
"@angular/cdk": "^17.3.5",
"@angular/common": "^17.3.5",
"@angular/compiler": "^17.3.5",
"@angular/core": "^17.3.5",
"@angular/forms": "^17.3.5",
"@angular/material": "^17.3.5",
"@angular/platform-browser": "^17.3.5",
"@angular/platform-browser-dynamic": "^17.3.5",
"@angular/router": "^17.3.5",
"rxjs": "^7.8.1",
"zone.js": "^0.14.4",
"zod": "3.22.4",
"@kangaroo-and-rabbit/kar-cw": "^0.2.0"
"@kangaroo-and-rabbit/kar-cw": "^0.2.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "^17.3.4",
"@angular-devkit/build-angular": "^17.3.5",
"@angular-eslint/builder": "17.3.0",
"@angular-eslint/eslint-plugin": "17.3.0",
"@angular-eslint/eslint-plugin-template": "17.3.0",
"@angular-eslint/schematics": "17.3.0",
"@angular-eslint/template-parser": "17.3.0",
"@angular/cli": "^17.3.4",
"@angular/compiler-cli": "^17.3.4",
"@angular/language-service": "^17.3.4",
"@angular/cli": "^17.3.5",
"@angular/compiler-cli": "^17.3.5",
"@angular/language-service": "^17.3.5",
"npm-check-updates": "^16.14.18",
"tslib": "^2.6.2"
}

View File

@ -37,6 +37,7 @@ import { environment } from 'environments/environment';
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import { CommonModule } from '@angular/common';
import { FileDragNDropDirective } from './scene/upload/file-drag-n-drop.directive';
@NgModule({
declarations: [
@ -58,7 +59,8 @@ import { CommonModule } from '@angular/common';
VideoEditScene,
SeasonEditScene,
SeriesEditScene,
UploadScene
UploadScene,
FileDragNDropDirective,
],
imports: [
FormsModule,

View File

@ -1,7 +1,7 @@
/**
* API of the server (auto-generated code)
*/
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, ProgressCallback, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTCallbacks, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import {UUID, } from "./model"
export namespace DataResource {

View File

@ -1,7 +1,7 @@
/**
* API of the server (auto-generated code)
*/
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, ProgressCallback, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTCallbacks, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import {} from "./model"
export namespace Front {

View File

@ -1,7 +1,7 @@
/**
* API of the server (auto-generated code)
*/
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, ProgressCallback, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTCallbacks, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import {HealthResult, isHealthResult, } from "./model"
export namespace HealthCheck {

View File

@ -1,7 +1,7 @@
/**
* API of the server (auto-generated code)
*/
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, ProgressCallback, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTCallbacks, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import {UUID, Long, Media, isMedia, } from "./model"
export namespace MediaResource {
@ -66,33 +66,6 @@ export namespace MediaResource {
data,
}, isMedia);
};
/**
* Upload a new season cover media
*/
export function uploadCover({ restConfig, params, data, progress, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: {
fileName: string,
file: File,
},
progress?: ProgressCallback,
}): Promise<Media> {
return RESTRequestJson({
restModel: {
endPoint: "/media/{id}/cover",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
progress,
}, isMedia);
};
/**
* Get all Media
*/
@ -108,6 +81,33 @@ export namespace MediaResource {
restConfig,
}, isMedia);
};
/**
* Upload a new season cover media
*/
export function uploadCover({ restConfig, params, data, callback, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: {
fileName: string,
file: File,
},
callback?: RESTCallbacks,
}): Promise<Media> {
return RESTRequestJson({
restModel: {
endPoint: "/media/{id}/cover",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
callback,
}, isMedia);
};
/**
* Remove a specific cover of a media
*/
@ -132,7 +132,7 @@ export namespace MediaResource {
/**
* Create a new Media
*/
export function uploadFile({ restConfig, data, progress, }: {
export function uploadFile({ restConfig, data, callback, }: {
restConfig: RESTConfig,
data: {
fileName: string,
@ -144,7 +144,7 @@ export namespace MediaResource {
typeId: string,
title: string,
},
progress?: ProgressCallback,
callback?: RESTCallbacks,
}): Promise<Media> {
return RESTRequestJson({
restModel: {
@ -155,7 +155,7 @@ export namespace MediaResource {
},
restConfig,
data,
progress,
callback,
}, isMedia);
};
}

View File

@ -122,9 +122,9 @@ export function isLocalTime(data: any): data is LocalTime {
export const ZodRestErrorResponse = zod.object({
uuid: ZodUUID.optional(),
time: zod.string().max(255).optional(),
error: zod.string().max(255).optional(),
name: zod.string().max(255).optional(),
message: zod.string().max(255).optional(),
time: zod.string().max(255).optional(),
status: ZodInteger,
statusMessage: zod.string().max(255).optional()
});

View File

@ -41,7 +41,7 @@ export interface RESTModel {
accept?: HTTPMimeType;
// Content of the local data.
contentType?: HTTPMimeType;
// Mode of the TOKEN in urk or Header
// Mode of the TOKEN in URL or Header (?token:${tokenInUrl})
tokenInUrl?: boolean;
}
@ -71,13 +71,28 @@ function isNullOrUndefined(data: any): data is undefined | null {
return data === undefined || data === null;
}
export type RESTRequestType = {
// generic progression callback
export type ProgressCallback = (count: number, total: number) => void;
export interface RESTAbort {
abort?: () => boolean
}
// Rest generic callback have a basic model to upload and download advancement.
export interface RESTCallbacks {
progressUpload?: ProgressCallback,
progressDownload?: ProgressCallback,
abortHandle?: RESTAbort,
};
export interface RESTRequestType {
restModel: RESTModel,
restConfig: RESTConfig,
data?: any,
params?: object,
queries?: object,
progress?: ProgressCallback,
callback?: RESTCallbacks,
};
function removeTrailingSlashes(input: string): string {
@ -124,63 +139,91 @@ export function RESTUrl({ restModel, restConfig, params, queries }: RESTRequestT
}
export type ProgressCallback = (count: number, total: number) => void;
// input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
export function fetchProgress<TYPE>(generateUrl: string, { method, headers, body }: {
export function fetchProgress(generateUrl: string, { method, headers, body }: {
method: HTTPRequestModel,
headers: any,
body: any,
}, progress: ProgressCallback): Promise<Response> {
//async function fetchForm(form, options = {}) {
const action = generateUrl;
const data = body;
const xhr = new XMLHttpRequest();
console.log(`call fetch progress ...`);
}, { progressUpload, progressDownload, abortHandle }: RESTCallbacks): Promise<Response> {
const xhr = {
io: new XMLHttpRequest()
}
return new Promise((resolve, reject) => {
xhr.responseType = 'blob';
xhr.onreadystatechange = () => {
if (xhr.readyState != 4) {
console.log(` ==> READY state`);
// done
return;
}
console.log(` ==> has finish ...`);
const response = new Response(xhr.response, {
status: xhr.status,
statusText: xhr.statusText
// Stream the upload progress
if (progressUpload) {
xhr.io.upload.addEventListener("progress", (dataEvent) => {
if (dataEvent.lengthComputable) {
//console.log(` ==> has a progress event: ${dataEvent.loaded} / ${dataEvent.total}`);
progressUpload(dataEvent.loaded, dataEvent.total);
}
});
resolve(response);
}
// If fail:
xhr.addEventListener('error', () => {
console.log(` ==> IS REJECTED`);
// Stream the download progress
if (progressDownload) {
xhr.io.addEventListener("progress", (dataEvent) => {
if (dataEvent.lengthComputable) {
//console.log(` ==> download progress:: ${dataEvent.loaded} / ${dataEvent.total}`);
progressUpload(dataEvent.loaded, dataEvent.total);
}
});
}
if (abortHandle) {
abortHandle.abort = () => {
if (xhr.io) {
console.log(`Request abort on the XMLHttpRequest: ${generateUrl}`);
xhr.io.abort();
return true;
}
console.log(`Request abort (FAIL) on the XMLHttpRequest: ${generateUrl}`);
return false;
}
}
// Check if we have an internal Fail:
xhr.io.addEventListener('error', () => {
xhr.io = undefined;
reject(new TypeError('Failed to fetch'))
});
// Link the progression callback
if (progress) {
xhr.addEventListener('progress', (dataEvent) => {
console.log(` ==> has a progress event: ${dataEvent.loaded} / ${dataEvent.total}`);
progress(dataEvent.loaded, dataEvent.total);
// Capture the end of the stream
xhr.io.addEventListener("loadend", () => {
if (xhr.io.readyState !== XMLHttpRequest.DONE) {
//console.log(` ==> READY state`);
return;
}
if (xhr.io.status === 0) {
//the stream has been aborted
reject(new TypeError('Fetch has been aborted'));
return;
}
// Stream is ended, transform in a generic response:
const response = new Response(xhr.io.response, {
status: xhr.io.status,
statusText: xhr.io.statusText
});
}
console.log(` ==> open`);
// open the socket
xhr.open(method, action, true);
console.log(` ==> set header`);
// configure the header
const headersArray = xhr.io.getAllResponseHeaders().trim().replaceAll("\r\n", "\n").split('\n');
headersArray.forEach(function (header) {
const firstColonIndex = header.indexOf(':');
if (firstColonIndex !== -1) {
var key = header.substring(0, firstColonIndex).trim();
var value = header.substring(firstColonIndex + 1).trim();
response.headers.set(key, value);
} else {
response.headers.set(header, "");
}
});
xhr.io = undefined;
resolve(response);
});
xhr.io.open(method, generateUrl, true);
if (!isNullOrUndefined(headers)) {
for (const [key, value] of Object.entries(headers)) {
xhr.setRequestHeader(key, value as string);
xhr.io.setRequestHeader(key, value as string);
}
}
console.log(` ==> send`);
xhr.send(data);
console.log(` ==> send done`);
xhr.io.send(body);
});
}
export function RESTRequest({ restModel, restConfig, data, params, queries, progress }: RESTRequestType): Promise<ModelResponseHttp> {
export function RESTRequest({ restModel, restConfig, data, params, queries, callback }: RESTRequestType): Promise<ModelResponseHttp> {
// Create the URL PATH:
let generateUrl = RESTUrl({ restModel, restConfig, data, params, queries });
let headers: any = {};
@ -207,21 +250,25 @@ export function RESTRequest({ restModel, restConfig, data, params, queries, prog
}
body = formData
}
console.log(`Call ${generateUrl}`)
return new Promise((resolve, reject) => {
let action: Promise<Response> = undefined;
if (isNullOrUndefined(progress)) {
let action: undefined | Promise<Response> = undefined;
if (isNullOrUndefined(callback)
|| (isNullOrUndefined(callback.progressDownload)
&& isNullOrUndefined(callback.progressUpload)
&& isNullOrUndefined(callback.abortHandle))) {
// No information needed: call the generic fetch interface
action = fetch(generateUrl, {
method: restModel.requestType,
headers,
body,
});
} else {
// need progression information: call old fetch model (XMLHttpRequest) that permit to keep % upload and % download for HTTP1.x
action = fetchProgress(generateUrl, {
method: restModel.requestType,
method: restModel.requestType ?? HTTPRequestModel.GET,
headers,
body,
}, progress);
}, callback);
}
action.then((response: Response) => {
if (response.status >= 200 && response.status <= 299) {
@ -268,7 +315,7 @@ export function RESTRequest({ restModel, restConfig, data, params, queries, prog
status: 999,
error: error,
statusMessage: "Fetch catch error",
message: "http-wrapper.ts detect an error in the fetch request"
message: "rest-tools.ts detect an error in the fetch request"
});
});
});

View File

@ -1,7 +1,7 @@
/**
* API of the server (auto-generated code)
*/
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, ProgressCallback, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTCallbacks, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import {UUID, Long, Season, isSeason, } from "./model"
export namespace SeasonResource {
@ -85,33 +85,6 @@ export namespace SeasonResource {
data,
}, isSeason);
};
/**
* Upload a new season cover season
*/
export function uploadCover({ restConfig, params, data, progress, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: {
fileName: string,
file: File,
},
progress?: ProgressCallback,
}): Promise<Season> {
return RESTRequestJson({
restModel: {
endPoint: "/season/{id}/cover",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
progress,
}, isSeason);
};
/**
* Get a specific Season with his ID
*/
@ -127,6 +100,33 @@ export namespace SeasonResource {
restConfig,
}, isSeason);
};
/**
* Upload a new season cover season
*/
export function uploadCover({ restConfig, params, data, callback, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: {
fileName: string,
file: File,
},
callback?: RESTCallbacks,
}): Promise<Season> {
return RESTRequestJson({
restModel: {
endPoint: "/season/{id}/cover",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
callback,
}, isSeason);
};
/**
* Remove a specific cover of a season
*/

View File

@ -1,8 +1,8 @@
/**
* API of the server (auto-generated code)
*/
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, ProgressCallback, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import { UUID, Long, Series, isSeries, } from "./model"
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTCallbacks, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import {UUID, Long, Series, isSeries, } from "./model"
export namespace SeriesResource {
/**
@ -85,33 +85,6 @@ export namespace SeriesResource {
data,
}, isSeries);
};
/**
* Upload a new season cover Series
*/
export function uploadCover({ restConfig, params, data, progress, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: {
fileName: string,
file: File,
},
progress?: ProgressCallback,
}): Promise<Series> {
return RESTRequestJson({
restModel: {
endPoint: "/series/{id}/cover",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
progress,
}, isSeries);
};
/**
* Get all Series
*/
@ -127,6 +100,33 @@ export namespace SeriesResource {
restConfig,
}, isSeries);
};
/**
* Upload a new season cover Series
*/
export function uploadCover({ restConfig, params, data, callback, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: {
fileName: string,
file: File,
},
callback?: RESTCallbacks,
}): Promise<Series> {
return RESTRequestJson({
restModel: {
endPoint: "/series/{id}/cover",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
callback,
}, isSeries);
};
/**
* Remove a specific Series of a season
*/

View File

@ -1,7 +1,7 @@
/**
* API of the server (auto-generated code)
*/
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, ProgressCallback, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTCallbacks, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import {UUID, Long, Type, isType, } from "./model"
export namespace TypeResource {
@ -85,33 +85,6 @@ export namespace TypeResource {
data,
}, isType);
};
/**
* Upload a new season cover Type
*/
export function uploadCover({ restConfig, params, data, progress, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: {
fileName: string,
file: File,
},
progress?: ProgressCallback,
}): Promise<Type> {
return RESTRequestJson({
restModel: {
endPoint: "/type/{id}/cover",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
progress,
}, isType);
};
/**
* Get all Type
*/
@ -127,6 +100,33 @@ export namespace TypeResource {
restConfig,
}, isType);
};
/**
* Upload a new season cover Type
*/
export function uploadCover({ restConfig, params, data, callback, }: {
restConfig: RESTConfig,
params: {
id: Long,
},
data: {
fileName: string,
file: File,
},
callback?: RESTCallbacks,
}): Promise<Type> {
return RESTRequestJson({
restModel: {
endPoint: "/type/{id}/cover",
requestType: HTTPRequestModel.POST,
contentType: HTTPMimeType.MULTIPART,
accept: HTTPMimeType.JSON,
},
restConfig,
params,
data,
callback,
}, isType);
};
/**
* Remove a specific cover of a type
*/

View File

@ -1,7 +1,7 @@
/**
* API of the server (auto-generated code)
*/
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, ProgressCallback, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTCallbacks, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import {Long, UserMediaAdvancement, MediaInformationsDelta, isUserMediaAdvancement, } from "./model"
export namespace UserMediaAdvancementResource {

View File

@ -1,7 +1,7 @@
/**
* API of the server (auto-generated code)
*/
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, ProgressCallback, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import { HTTPMimeType, HTTPRequestModel, ModelResponseHttp, RESTConfig, RESTCallbacks, RESTRequestJson, RESTRequestJsonArray, RESTRequestVoid } from "./rest-tools"
import {Long, UserKarideo, UserOut, isUserKarideo, isUserOut, } from "./model"
export namespace UserResource {

View File

@ -147,7 +147,8 @@
[mediaUploaded]="upload.mediaSendSize"
[mediaSize]="upload.mediaSize"
[result]="upload.result"
[error]="upload.error"></upload-progress>
[error]="upload.error"
(abort)="abortUpload()"></upload-progress>
<delete-confirm
[comment]="confirmDeleteComment"
[imageUrl]=confirmDeleteImageUrl

View File

@ -7,6 +7,7 @@
import { Component, OnInit } from '@angular/core';
import { PopInService, UploadProgress, isNumberFinite } from '@kangaroo-and-rabbit/kar-cw';
import { Season, UUID } from 'app/back-api';
import { RESTAbort } from 'app/back-api/rest-tools';
import { SeasonService, ArianeService, DataService } from 'app/service';
@ -29,11 +30,11 @@ export class SeasonEditScene implements OnInit {
error: string = '';
numberVal: number = null;
numberVal: string = null;
description: string = '';
coverFile: File;
coverFile?: File;
uploadFileValue: string = '';
selectedFiles: FileList;
selectedFiles?: FileList;
videoCount: string = null;
@ -45,6 +46,7 @@ export class SeasonEditScene implements OnInit {
public confirmDeleteImageUrl: string = null;
private deleteCoverId: UUID = null;
private deleteItemId: number = null;
cancelHandle: RESTAbort = {};
deleteConfirmed() {
if (this.deleteCoverId !== null) {
this.removeCoverAfterConfirm(this.deleteCoverId);
@ -147,6 +149,10 @@ export class SeasonEditScene implements OnInit {
event.preventDefault();
}
abortUpload(): void {
this.cancelHandle.abort();
}
// At the file input element
// (change)="selectFile($event)"
onChangeCover(value: any): void {
@ -169,7 +175,7 @@ export class SeasonEditScene implements OnInit {
this.seasonService.uploadCover(this.idSeason, file, (count, total) => {
self.upload.mediaSendSize = count;
self.upload.mediaSize = total;
})
}, this.cancelHandle)
.then((response: any) => {
self.upload.result = 'Cover added done';
// we retrive the whiole media ==> update data ...

View File

@ -171,7 +171,8 @@
[mediaUploaded]="upload.mediaSendSize"
[mediaSize]="upload.mediaSize"
[result]="upload.result"
[error]="upload.error"></upload-progress>
[error]="upload.error"
(abort)="abortUpload()"></upload-progress>
<delete-confirm
[comment]="confirmDeleteComment"
[imageUrl]=confirmDeleteImageUrl

View File

@ -7,6 +7,7 @@
import { Component, OnInit } from '@angular/core';
import { PopInService, UploadProgress } from '@kangaroo-and-rabbit/kar-cw';
import { UUID } from 'app/back-api';
import { RESTAbort } from 'app/back-api/rest-tools';
import { SeriesService, DataService, TypeService, ArianeService } from 'app/service';
@ -55,6 +56,7 @@ export class SeriesEditScene implements OnInit {
public confirmDeleteImageUrl: string = null;
private deleteCoverId: UUID = null;
private deleteItemId: number = null;
cancelHandle: RESTAbort = {};
deleteConfirmed() {
if (this.deleteCoverId !== null) {
this.removeCoverAfterConfirm(this.deleteCoverId);
@ -129,6 +131,10 @@ export class SeriesEditScene implements OnInit {
});
}
abortUpload(): void {
this.cancelHandle.abort();
}
updateCoverList(covers: any) {
this.coversDisplay = [];
if (covers !== undefined && covers !== null) {
@ -208,7 +214,7 @@ export class SeriesEditScene implements OnInit {
this.seriesService.uploadCover(this.idSeries, file, (count, total) => {
self.upload.mediaSendSize = count;
self.upload.mediaSize = total;
})
}, this.cancelHandle)
.then((response: any) => {
self.upload.result = 'Cover added done';
// we retrive the whiole media ==> update data ...

View File

@ -0,0 +1,44 @@
import { Directive, HostListener, HostBinding, Output, EventEmitter, Input } from '@angular/core';
@Directive({
selector: '[fileDragDrop]'
})
export class FileDragNDropDirective {
//@Input() private allowed_extensions : Array<string> = ['png', 'jpg', 'bmp'];
@Output() private filesChangeEmiter: EventEmitter<File[]> = new EventEmitter();
//@Output() private filesInvalidEmiter : EventEmitter<File[]> = new EventEmitter();
@HostBinding('style.background') private background = '#eee';
@HostBinding('style.border') private borderStyle = '2px dashed';
@HostBinding('style.border-color') private borderColor = '#696D7D';
@HostBinding('style.border-radius') private borderRadius = '10px';
constructor() { }
@HostListener('dragover', ['$event']) public onDragOver(evt) {
evt.preventDefault();
evt.stopPropagation();
this.background = 'lightgray';
this.borderColor = 'cadetblue';
this.borderStyle = '3px solid';
}
@HostListener('dragleave', ['$event']) public onDragLeave(evt) {
evt.preventDefault();
evt.stopPropagation();
this.background = '#eee';
this.borderColor = '#696D7D';
this.borderStyle = '2px dashed';
}
@HostListener('drop', ['$event']) public onDrop(evt) {
evt.preventDefault();
evt.stopPropagation();
this.background = '#eee';
this.borderColor = '#696D7D';
this.borderStyle = '2px dashed';
let files = evt.dataTransfer.files;
let valid_files: Array<File> = files;
this.filesChangeEmiter.emit(valid_files);
}
}

View File

@ -3,34 +3,19 @@
Upload Media
</div>
<div class="clear"><br/></div>
<div class="request_raw_table">
<table>
<colgroup>
<col style="width:10%">
<col style="width:80%">
</colgroup>
<tbody>
<tr>
<td class="left-colomn">format:</td>
<td class="right-colomn">
The format of the media permit to automatic find meta-data:<br/>
Univers:Series name-sXX-eXX-my name of my media.mkv<br/>
<b>example:</b> Stargate:SG1-s55-e22-Asgard.mkv <br/>
</td>
</tr>
<tr>
<td class="left-colomn">Media:</td>
<td class="right-colomn">
<input type="file"
(change)="onChangeFile($event.target)"
placeholder="Select a media file"
accept=".mkv,.webm"
width="90%"
multiple/>
</td>
</tr>
</tbody>
</table>
<div class="request_raw_table drop-area" fileDragDrop
(filesChangeEmiter)="onChangeFile($event)">
<div class="clear"><br/></div>
<div class="centered">
<input type="file" name="file" id="file" (change)="onChangeFile($event.target.files)" multiple>
<label for="file"><span class="textLink"><span class="material-icons">cloud_upload</span> Select your file</span> or <i>Drop it here!</i></label>
</div>
<div class="clear"><br/></div>
<div class="centered">
The format of the media permit to automatic find meta-data:<br/>
Univers:Series name-sXX-eXX-my name of my media.mkv<br/>
<b>example:</b> Stargate:SG1-s55-e22-Asgard.mkv <br/>
</div>
</div>
@if(parsedElement.length !== 0) {
<div class="title">
@ -210,11 +195,13 @@
</div>
}
</div>
<upload-progress [mediaTitle]="upload.labelMediaTitle"
<upload-progress
[mediaTitle]="upload.labelMediaTitle"
[mediaUploaded]="upload.mediaSendSize"
[mediaSize]="upload.mediaSize"
[result]="upload.result"
[error]="upload.error"></upload-progress>
[error]="upload.error"
(abort)="abortUpload()"></upload-progress>
<!--
TODO: add a pop-in with:

View File

@ -1,43 +1,79 @@
.title {
//background-color: green;
font-size: 45px;
font-weight: bold;
line-height: 60px;
width:100%;
width: 100%;
text-align: center;
vertical-align: middle;
margin: 10px 0 10px 0;
text-shadow: 1px 1px 2px white, 0 0 1em white, 0 0 0.2em white;
text-transform: uppercase;
font-family: "Roboto","Helvetica","Arial",sans-serif;
font-family: "Roboto", "Helvetica", "Arial", sans-serif;
}
.drop-area {
height: 230px;
display: table;
width: 100%;
background-color: #eee;
border: dotted 1px #aaa;
cursor: pointer;
}
.text-wrapper {
display: table-cell;
vertical-align: middle;
}
.centered {
font-family: sans-serif;
font-size: 1.3em;
text-align: center;
}
.textLink {
background-color: #217500;
color: #fff;
padding: 10px;
border-radius: 5px;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
}
input[type="file"] {
display: none;
}
.request_raw_table {
display: block;
width: 90%;
margin: 0 auto;
table {
width: 100%;
th {
text-align: left;
}
.left-colomn {
text-align: right;
font-weight: bold;
input {
width: 95%;
font-size: 20px;
border: 0px;
}
}
.right-colomn {
input {
width: 95%;
font-size: 20px;
border: 0px;
}
select {
width: 95%;
font-size: 20px;
@ -45,14 +81,16 @@
}
}
}
.error {
border-color: rgba(200,0,0,1.0);
background-color: rgba(256,220,220,1.0);
border-color: rgba(200, 0, 0, 1.0);
background-color: rgba(256, 220, 220, 1.0);
}
}
.send_value {
width: 300px;
margin: 0 auto;
padding: 10px;
display: block;
}
}

View File

@ -7,6 +7,7 @@
import { Component, OnInit } from '@angular/core';
import { PopInService, UploadProgress } from '@kangaroo-and-rabbit/kar-cw';
import { Series } from 'app/back-api';
import { RESTAbort } from 'app/back-api/rest-tools';
import { TypeService, SeriesService, MediaService, SeasonService } from 'app/service';
@ -51,7 +52,7 @@ export class UploadScene implements OnInit {
selectedFiles: FileList;
typeId: number = null;
seriesId: number = null;
saisonId: number = null;
seasonId: number = null;
needSend: boolean = false;
// list of all files already registered in the bdd to compare with the current list of files.
@ -92,12 +93,14 @@ export class UploadScene implements OnInit {
];
globalSeries: string = '';
globalSeason: number = null;
cancelHandle: RESTAbort = {};
constructor(
private MediaService: MediaService,
private seasonService: SeasonService,
private seriesService: SeriesService,
private typeService: TypeService,
private popInService: PopInService) {
private popInService: PopInService,
) {
// nothing to do.
}
@ -238,7 +241,7 @@ export class UploadScene implements OnInit {
this.typeId = null;
this.seriesId = null;
this.saisonId = null;
this.seasonId = null;
this.listSeries = [{ value: null, label: '---' }];
this.listSeason = [{ value: null, label: '---' }];
}
@ -302,7 +305,7 @@ export class UploadScene implements OnInit {
if (isNaN(season)) {
season = null;
}
// remove extention
// remove extension
title = title.replace(new RegExp('\\.(mkv|MKV|Mkv|webm|WEBM|Webm|mp4)'), '');
let tmp = new FileParsedElement(file, series, season, episode, title);
console.log(`==>${JSON.stringify(tmp)}`);
@ -310,14 +313,13 @@ export class UploadScene implements OnInit {
this.parsedElement.push(tmp);
}
// At the file input element
// (change)="selectFile($event)"
onChangeFile(value: any): void {
onChangeFile(files: File[]): void {
this.clearData();
for (let iii = 0; iii < value.files.length; iii++) {
this.addFileWithMetaData(value.files[iii]);
for (let iii = 0; iii < files.length; iii++) {
this.addFileWithMetaData(files[iii]);
}
// check if all global parameters are generic:
if (this.parsedElement.length === 0) {
@ -350,7 +352,7 @@ export class UploadScene implements OnInit {
this.updateNeedSend();
this.seriesId = null;
this.saisonId = null;
this.seasonId = null;
let self = this;
if (this.globalSeries !== '') {
this.seriesService.getLike(this.globalSeries)
@ -362,9 +364,9 @@ export class UploadScene implements OnInit {
if (response.length === 0) {
self.seriesId = null;
} else if (response.length === 1) {
let serieElem = response[0];
self.seriesId = serieElem.id;
self.updateType(serieElem.parentId);
let seriesElem = response[0];
self.seriesId = seriesElem.id;
self.updateType(seriesElem.parentId);
}
self.updateListOfVideoToCheck();
}).catch((response) => {
@ -392,10 +394,11 @@ export class UploadScene implements OnInit {
self.upload.result = 'Media creation done';
}
}, (value: string) => {
console.log("Detect error from serveur ...********************");
self.upload.error = `Error in the upload of the data...${value}`;
});
}
uploadFile(eleemnent: FileParsedElement, id: number, total: number, sendDone: any, errorOccured: any): void {
uploadFile(element: FileParsedElement, id: number, total: number, sendDone: () => void, errorOccurred: (string) => void): void {
let self = this;
self.upload.labelMediaTitle = '';
@ -414,37 +417,38 @@ export class UploadScene implements OnInit {
self.upload.labelMediaTitle = `${self.upload.labelMediaTitle}s${self.globalSeason.toString()}`;
}
// add episode ID
if (eleemnent.episode !== null && eleemnent.episode !== undefined && eleemnent.episode.toString().length !== 0) {
if (element.episode !== null && element.episode !== undefined && element.episode.toString().length !== 0) {
if (self.upload.labelMediaTitle.length !== 0) {
self.upload.labelMediaTitle = `${self.upload.labelMediaTitle}-`;
}
self.upload.labelMediaTitle = `${self.upload.labelMediaTitle}e${eleemnent.episode.toString()}`;
self.upload.labelMediaTitle = `${self.upload.labelMediaTitle}e${element.episode.toString()}`;
}
// add title
if (self.upload.labelMediaTitle.length !== 0) {
self.upload.labelMediaTitle = `${self.upload.labelMediaTitle}-`;
}
self.upload.labelMediaTitle = `[${id + 1}/${total}]${self.upload.labelMediaTitle}${eleemnent.title}`;
self.upload.labelMediaTitle = `[${id + 1}/${total}]${self.upload.labelMediaTitle}${element.title}`;
self.MediaService.uploadFile(eleemnent.file,
self.MediaService.uploadFile(element.file,
self.globalSeries,
self.seriesId,
self.globalSeason,
eleemnent.episode,
eleemnent.title,
element.episode,
element.title,
self.typeId,
(count, totalTmp) => {
// console.log("upload : " + count*100/totalTmp);
self.upload.mediaSendSize = count;
self.upload.mediaSize = totalTmp;
})
}, this.cancelHandle)
.then((response) => {
console.log(`get response of video : ${JSON.stringify(response, null, 2)}`);
sendDone();
}).catch((response) => {
})
.catch((response) => {
// self.error = "Can not get the data";
console.log('Can not add the data in the system...');
errorOccured(JSON.stringify(response, null, 2));
errorOccurred(JSON.stringify(response, null, 2));
});
}
@ -518,7 +522,7 @@ export class UploadScene implements OnInit {
return;
}
self.saisonId = null;
self.seasonId = null;
// set 1 find the ID of the season:
this.seriesService.getSeason(this.seriesId)
.then((response: any[]) => {
@ -526,14 +530,14 @@ export class UploadScene implements OnInit {
for (let iii = 0; iii < response.length; iii++) {
// console.log(" - " + JSON.stringify(response[iii]) + 'compare with : ' + JSON.stringify(self.globalSeason));
if (response[iii].name === `${self.globalSeason}`) {
self.saisonId = response[iii].id;
self.seasonId = response[iii].id;
break;
}
}
if (self.saisonId === null) {
if (self.seasonId === null) {
return;
}
self.seasonService.getVideo(self.saisonId)
self.seasonService.getVideo(self.seasonId)
.then((response2: any[]) => {
self.listFileInBdd = response2;
// console.log("find video: " + response2.length);
@ -549,6 +553,10 @@ export class UploadScene implements OnInit {
});
}
abortUpload(): void {
this.cancelHandle.abort();
}
eventPopUpSeason(event: string): void {
console.log(`GET event: ${event}`);
this.popInService.close('popin-new-season');
@ -575,3 +583,7 @@ export class UploadScene implements OnInit {
this.popInService.open('popin-create-type');
}
}
function isNullOrUndefined(abort: () => boolean) {
throw new Error('Function not implemented.');
}

View File

@ -213,7 +213,8 @@
[mediaUploaded]="upload.mediaSendSize"
[mediaSize]="upload.mediaSize"
[result]="upload.result"
[error]="upload.error"></upload-progress>
[error]="upload.error"
(abort)="abortUpload()"></upload-progress>
<delete-confirm
[comment]="confirmDeleteComment"

View File

@ -9,6 +9,7 @@ import { Component, OnInit } from '@angular/core';
import { DataService, TypeService, SeriesService, MediaService, ArianeService } from 'app/service';
import { PopInService, UploadProgress } from '@kangaroo-and-rabbit/kar-cw';
import { Media, Season, Series, UUID } from 'app/back-api';
import { RESTAbort } from 'app/back-api/rest-tools';
export interface ElementList {
value?: number;
@ -90,6 +91,7 @@ export class VideoEditScene implements OnInit {
listSeason: ElementList[] = [
{ value: undefined, label: '---' },
];
cancelHandle: RESTAbort = {};
constructor(
private dataService: DataService,
private MediaService: MediaService,
@ -101,6 +103,10 @@ export class VideoEditScene implements OnInit {
}
abortUpload(): void {
this.cancelHandle.abort();
}
updateNeedSend(): boolean {
this.needSend = false;
if (this.data.name !== this.dataOri.name) {
@ -371,7 +377,7 @@ export class VideoEditScene implements OnInit {
this.MediaService.uploadCover(this.idVideo, file, (count, total) => {
self.upload.mediaSendSize = count;
self.upload.mediaSize = total;
})
}, this.cancelHandle)
.then((response: any) => {
console.log(`get response of cover : ${JSON.stringify(response, null, 2)}`);
self.upload.result = 'Cover added done';

View File

@ -7,7 +7,7 @@
import { Injectable } from '@angular/core';
import { SessionService, DataStore } from '@kangaroo-and-rabbit/kar-cw';
import { Media, MediaResource, UUID } from 'app/back-api';
import { ProgressCallback, RESTConfig } from 'app/back-api/rest-tools';
import { ProgressCallback, RESTAbort, RESTConfig } from 'app/back-api/rest-tools';
import { environment } from 'environments/environment';
import { GenericDataService } from './GenericDataService';
@ -37,7 +37,8 @@ export class MediaService extends GenericDataService<Media> {
episode?: number,
title?: string,
typeId?: number,
progress: ProgressCallback | undefined = undefined) {
progress: ProgressCallback | undefined = undefined,
cancelHandle: RESTAbort | undefined = undefined) {
const formData = {
fileName: file.name,
file,
@ -52,7 +53,10 @@ export class MediaService extends GenericDataService<Media> {
return MediaResource.uploadFile({
restConfig: this.getRestConfig(),
data: formData,
progress
callback: {
progressUpload: progress,
abortHandle: cancelHandle,
}
});
}
@ -110,7 +114,8 @@ export class MediaService extends GenericDataService<Media> {
}
uploadCover(id: number,
file: File,
progress: ProgressCallback | undefined = undefined): Promise<Media> {
progress: ProgressCallback | undefined = undefined,
cancelHandle: RESTAbort | undefined = undefined): Promise<Media> {
let self = this;
return new Promise((resolve, reject) => {
MediaResource.uploadCover({
@ -122,7 +127,10 @@ export class MediaService extends GenericDataService<Media> {
file,
fileName: file.name
},
progress
callback: {
progressUpload: progress,
abortHandle: cancelHandle,
}
}).then((value) => {
self.dataStore.updateValue(value);
resolve(value);

View File

@ -7,7 +7,7 @@
import { Injectable } from '@angular/core';
import { DataStore, SessionService, TypeCheck } from '@kangaroo-and-rabbit/kar-cw';
import { Media, Season, SeasonResource, UUID } from 'app/back-api';
import { ProgressCallback, RESTConfig } from 'app/back-api/rest-tools';
import { ProgressCallback, RESTAbort, RESTConfig } from 'app/back-api/rest-tools';
import { environment } from 'environments/environment';
import { GenericDataService } from './GenericDataService';
import { MediaService } from './media';
@ -141,7 +141,8 @@ export class SeasonService extends GenericDataService<Season> {
}
uploadCover(id: number,
file: File,
progress: ProgressCallback | undefined = undefined): Promise<Season> {
progress: ProgressCallback | undefined = undefined,
cancelHandle: RESTAbort | undefined = undefined): Promise<Season> {
let self = this;
return new Promise((resolve, reject) => {
SeasonResource.uploadCover({
@ -153,7 +154,10 @@ export class SeasonService extends GenericDataService<Season> {
file,
fileName: file.name
},
progress
callback: {
progressUpload: progress,
abortHandle: cancelHandle,
}
}).then((value) => {
self.dataStore.updateValue(value);
resolve(value);

View File

@ -8,7 +8,7 @@ import { Injectable } from '@angular/core';
import { SessionService, DataStore, TypeCheck } from '@kangaroo-and-rabbit/kar-cw';
import { Media, Season, Series, SeriesResource, UUID } from 'app/back-api';
import { ProgressCallback, RESTConfig } from 'app/back-api/rest-tools';
import { ProgressCallback, RESTAbort, RESTConfig } from 'app/back-api/rest-tools';
import { environment } from 'environments/environment';
import { GenericDataService } from './GenericDataService';
import { SeasonService, MediaService } from '.';
@ -196,7 +196,8 @@ export class SeriesService extends GenericDataService<Series> {
}
uploadCover(id: number,
file: File,
progress: ProgressCallback | undefined = undefined): Promise<Media> {
progress: ProgressCallback | undefined = undefined,
cancelHandle: RESTAbort | undefined = undefined): Promise<Media> {
let self = this;
return new Promise((resolve, reject) => {
SeriesResource.uploadCover({
@ -208,7 +209,10 @@ export class SeriesService extends GenericDataService<Series> {
file,
fileName: file.name
},
progress
callback: {
progressUpload: progress,
abortHandle: cancelHandle,
}
}).then((value) => {
self.dataStore.updateValue(value);
resolve(value);