@stemy/backend 2.7.1 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@ import { dirname, basename, join, resolve } from 'path';
2
2
  import { json } from 'body-parser';
3
3
  import { sign, verify } from 'jsonwebtoken';
4
4
  import { injectable, scoped, Lifecycle, injectAll, singleton, inject, isFactoryProvider, container } from 'tsyringe';
5
- import { createParamDecorator, BadRequestError, HttpError, getMetadataArgsStorage, Authorized, Post, UploadedFile, Get, Param, QueryParams, QueryParam, Res, Controller, Body, CurrentUser, Middleware, useContainer, useExpressServer } from 'routing-controllers';
5
+ import { createParamDecorator, BadRequestError, HttpError, getMetadataArgsStorage, Authorized, Post, UploadedFile, Body, Get, Param, QueryParams, QueryParam, Res, Controller, CurrentUser, Middleware, useContainer, useExpressServer } from 'routing-controllers';
6
6
  import { OnMessage, ConnectedSocket, MessageBody, SocketController, Middleware as Middleware$1, useContainer as useContainer$1, useSocketServer } from 'socket-controllers';
7
7
  import { routingControllersToSpec } from 'routing-controllers-openapi';
8
8
  import { defaultMetadataStorage } from 'class-transformer/storage';
@@ -20,6 +20,7 @@ import { ObjectId } from 'bson';
20
20
  import fontKit_ from 'fontkit';
21
21
  import { fromBuffer, fromStream } from 'file-type';
22
22
  import sharp_ from 'sharp';
23
+ import axios from 'axios';
23
24
  import { GridFSBucket } from 'mongodb';
24
25
  import dotenv from 'dotenv';
25
26
  import { Queue, Worker, Scheduler } from 'node-resque';
@@ -32,11 +33,10 @@ import socket_io from 'socket.io';
32
33
  import { v4 } from 'uuid';
33
34
  import { createTransport } from 'nodemailer';
34
35
  import * as Handlebars from 'handlebars';
35
- import axios from 'axios';
36
36
  import { compare } from 'bcrypt';
37
37
  import moment from 'moment';
38
38
 
39
- var __awaiter$u = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
39
+ var __awaiter$v = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
40
40
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
41
41
  return new (P || (P = Promise))(function (resolve, reject) {
42
42
  function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
@@ -238,7 +238,7 @@ function hydratePopulated(modelType, json) {
238
238
  return object;
239
239
  }
240
240
  function paginateAggregations(model, aggregations, params, metaProjection = {}) {
241
- return __awaiter$u(this, void 0, void 0, function* () {
241
+ return __awaiter$v(this, void 0, void 0, function* () {
242
242
  const sortField = !isString(params.sort) || !params.sort ? null : (params.sort.startsWith("-") ? params.sort.substr(1) : params.sort);
243
243
  const sortAggregation = !sortField ? [] : [{
244
244
  $sort: { [sortField]: sortField == params.sort ? 1 : -1 }
@@ -337,7 +337,7 @@ function readFile(path) {
337
337
  });
338
338
  }
339
339
  function readAndDeleteFile(path, timeout = 5000) {
340
- return __awaiter$u(this, void 0, void 0, function* () {
340
+ return __awaiter$v(this, void 0, void 0, function* () {
341
341
  const data = yield readFile(path);
342
342
  setTimeout(() => {
343
343
  unlink(path, () => {
@@ -347,7 +347,7 @@ function readAndDeleteFile(path, timeout = 5000) {
347
347
  });
348
348
  }
349
349
  function writeFile(path, data) {
350
- return __awaiter$u(this, void 0, void 0, function* () {
350
+ return __awaiter$v(this, void 0, void 0, function* () {
351
351
  yield mkdirRecursive(dirname(path));
352
352
  return new Promise((res, rej) => {
353
353
  writeFile$1(path, data, err => {
@@ -426,7 +426,7 @@ function ResolveEntity(model, extraCheck) {
426
426
  const paramName = modelName.toLowerCase();
427
427
  return createParamDecorator({
428
428
  required: false,
429
- value: (action) => __awaiter$u(this, void 0, void 0, function* () {
429
+ value: (action) => __awaiter$v(this, void 0, void 0, function* () {
430
430
  const req = action.request;
431
431
  const token = req.header(`x-${paramName}-token`);
432
432
  const id = req.params[`${paramName}Id`];
@@ -750,7 +750,7 @@ var __decorate$w = (this && this.__decorate) || function (decorators, target, ke
750
750
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
751
751
  return c > 3 && r && Object.defineProperty(target, key, r), r;
752
752
  };
753
- var __awaiter$t = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
753
+ var __awaiter$u = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
754
754
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
755
755
  return new (P || (P = Promise))(function (resolve, reject) {
756
756
  function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
@@ -775,7 +775,7 @@ const fontProps = [
775
775
  ];
776
776
  let AssetProcessor = AssetProcessor_1 = class AssetProcessor {
777
777
  static getMimeType(buffer, mimeType) {
778
- return __awaiter$t(this, void 0, void 0, function* () {
778
+ return __awaiter$u(this, void 0, void 0, function* () {
779
779
  try {
780
780
  mimeType = (yield fromBuffer(buffer)).mime;
781
781
  }
@@ -807,7 +807,7 @@ let AssetProcessor = AssetProcessor_1 = class AssetProcessor {
807
807
  return imageTypes.indexOf(contentType) >= 0;
808
808
  }
809
809
  static copyImageMeta(buffer, metadata) {
810
- return __awaiter$t(this, void 0, void 0, function* () {
810
+ return __awaiter$u(this, void 0, void 0, function* () {
811
811
  const output = yield sharp$3(buffer).rotate().toBuffer({ resolveWithObject: true });
812
812
  Object.assign(metadata, output.info);
813
813
  return output.data;
@@ -824,7 +824,7 @@ let AssetProcessor = AssetProcessor_1 = class AssetProcessor {
824
824
  });
825
825
  }
826
826
  process(buffer, metadata, contentType) {
827
- return __awaiter$t(this, void 0, void 0, function* () {
827
+ return __awaiter$u(this, void 0, void 0, function* () {
828
828
  if (AssetProcessor_1.isImage(contentType)) {
829
829
  buffer = yield AssetProcessor_1.copyImageMeta(buffer, metadata);
830
830
  }
@@ -899,7 +899,7 @@ var __decorate$u = (this && this.__decorate) || function (decorators, target, ke
899
899
  var __metadata$o = (this && this.__metadata) || function (k, v) {
900
900
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
901
901
  };
902
- var __awaiter$s = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
902
+ var __awaiter$t = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
903
903
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
904
904
  return new (P || (P = Promise))(function (resolve, reject) {
905
905
  function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
@@ -925,7 +925,7 @@ let MongoConnector = class MongoConnector {
925
925
  return this.fsBucket;
926
926
  }
927
927
  connect() {
928
- return __awaiter$s(this, void 0, void 0, function* () {
928
+ return __awaiter$t(this, void 0, void 0, function* () {
929
929
  if (this.db)
930
930
  return this.db;
931
931
  this.conn = (yield connect(this.configuration.resolve("mongoUri"), {
@@ -946,6 +946,43 @@ MongoConnector = __decorate$u([
946
946
  __metadata$o("design:paramtypes", [Configuration])
947
947
  ], MongoConnector);
948
948
 
949
+ var __awaiter$s = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
950
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
951
+ return new (P || (P = Promise))(function (resolve, reject) {
952
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
953
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
954
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
955
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
956
+ });
957
+ };
958
+ class BaseEntity {
959
+ constructor(mId, data, collection) {
960
+ this.mId = mId;
961
+ this.data = data;
962
+ this.collection = collection;
963
+ }
964
+ get id() {
965
+ return this.mId.toHexString();
966
+ }
967
+ save() {
968
+ return this.collection.updateOne({ _id: this.mId }, { $set: this.toJSON() });
969
+ }
970
+ load() {
971
+ return __awaiter$s(this, void 0, void 0, function* () {
972
+ const res = yield this.collection.findOne({ _id: this.mId });
973
+ this.deleted = !res;
974
+ this.data = res || {};
975
+ return this;
976
+ });
977
+ }
978
+ toJSON() {
979
+ const ret = Object.assign({}, this.data);
980
+ delete ret._id;
981
+ ret.id = this.id;
982
+ return ret;
983
+ }
984
+ }
985
+
949
986
  var __awaiter$r = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
950
987
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
951
988
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -962,14 +999,10 @@ const cropInterface = {
962
999
  w: "number",
963
1000
  h: "number"
964
1001
  };
965
- class Asset {
966
- constructor(fileId, filename, contentType, metadata, bucket, collection) {
967
- this.fileId = fileId;
968
- this.filename = filename;
969
- this.contentType = contentType;
970
- this.metadata = metadata;
1002
+ class Asset extends BaseEntity {
1003
+ constructor(id, data, collection, bucket) {
1004
+ super(id, data, collection);
971
1005
  this.bucket = bucket;
972
- this.collection = collection;
973
1006
  }
974
1007
  static toCropRegion(cropInfo) {
975
1008
  let crop = cropInfo;
@@ -993,20 +1026,22 @@ class Asset {
993
1026
  static toImage(stream, meta, params) {
994
1027
  return __awaiter$r(this, void 0, void 0, function* () {
995
1028
  params = params || {};
996
- if (Object.keys(params).length == 0)
1029
+ // Get default crop info
1030
+ const crop = Asset.toCropRegion(meta.crop);
1031
+ // Return back the stream if there is no params and no default crop exists
1032
+ if (Object.keys(params).length == 0 && !crop)
997
1033
  return stream;
998
- let buffer = yield streamToBuffer(stream);
999
1034
  // Parse params
1000
1035
  params.rotation = isNaN(params.rotation) ? 0 : Math.round(params.rotation / 90) * 90;
1001
- params.canvasScaleX = isNaN(params.canvasScaleX) ? 1 : params.canvasScaleX;
1002
- params.canvasScaleY = isNaN(params.canvasScaleY) ? 1 : params.canvasScaleY;
1003
- params.scaleX = isNaN(params.scaleX) ? 1 : params.scaleX;
1004
- params.scaleY = isNaN(params.scaleY) ? 1 : params.scaleY;
1005
- params.crop = Boolean(params.crop);
1036
+ params.canvasScaleX = isNaN(params.canvasScaleX) ? 1 : Number(params.canvasScaleX);
1037
+ params.canvasScaleY = isNaN(params.canvasScaleY) ? 1 : Number(params.canvasScaleY);
1038
+ params.scaleX = isNaN(params.scaleX) ? 1 : Number(params.scaleX);
1039
+ params.scaleY = isNaN(params.scaleY) ? 1 : Number(params.scaleY);
1040
+ params.crop = isBoolean(params.crop) ? params.crop : params.crop == "true";
1006
1041
  // Try to modify image
1042
+ let buffer = yield streamToBuffer(stream);
1007
1043
  try {
1008
1044
  // Get crop info
1009
- const crop = Asset.toCropRegion(meta.crop);
1010
1045
  const cropBefore = Asset.toCropRegion(params.cropBefore || (params.crop ? meta.cropBefore : null));
1011
1046
  const cropAfter = Asset.toCropRegion(params.cropAfter || (params.crop ? meta.cropAfter : null));
1012
1047
  // Get metadata
@@ -1018,11 +1053,15 @@ class Asset {
1018
1053
  buffer = yield sharp$2(buffer)
1019
1054
  .extract(cropBefore)
1020
1055
  .toBuffer();
1056
+ width = cropBefore.width;
1057
+ height = cropBefore.height;
1021
1058
  }
1022
1059
  else if (crop) {
1023
1060
  buffer = yield sharp$2(buffer)
1024
1061
  .extract(crop)
1025
1062
  .toBuffer();
1063
+ width = crop.width;
1064
+ height = crop.height;
1026
1065
  }
1027
1066
  // Resize canvas
1028
1067
  if (params.canvasScaleX !== 1 || params.canvasScaleY !== 1) {
@@ -1058,15 +1097,21 @@ class Asset {
1058
1097
  }
1059
1098
  });
1060
1099
  }
1061
- get id() {
1062
- return this.fileId.toHexString();
1100
+ get filename() {
1101
+ return this.data.filename;
1102
+ }
1103
+ get contentType() {
1104
+ return this.data.contentType;
1105
+ }
1106
+ get metadata() {
1107
+ return this.data.metadata;
1063
1108
  }
1064
1109
  get stream() {
1065
- return this.bucket.openDownloadStream(this.fileId);
1110
+ return this.bucket.openDownloadStream(this.mId);
1066
1111
  }
1067
1112
  unlink() {
1068
1113
  return __awaiter$r(this, void 0, void 0, function* () {
1069
- return deleteFromBucket(this.bucket, this.fileId);
1114
+ return deleteFromBucket(this.bucket, this.mId);
1070
1115
  });
1071
1116
  }
1072
1117
  getBuffer() {
@@ -1080,7 +1125,7 @@ class Asset {
1080
1125
  : metadata.downloadCount + 1;
1081
1126
  metadata.firstDownload = metadata.firstDownload || new Date();
1082
1127
  metadata.lastDownload = new Date();
1083
- yield this.collection.updateOne({ _id: this.fileId }, { $set: { metadata } });
1128
+ yield this.collection.updateOne({ _id: this.mId }, { $set: { metadata } });
1084
1129
  return this.stream;
1085
1130
  });
1086
1131
  }
@@ -1094,14 +1139,6 @@ class Asset {
1094
1139
  return Asset.toImage(yield this.download(metadata), this.metadata, params);
1095
1140
  });
1096
1141
  }
1097
- toJSON() {
1098
- return {
1099
- id: this.id,
1100
- filename: this.filename,
1101
- contentType: this.contentType,
1102
- metadata: this.metadata
1103
- };
1104
- }
1105
1142
  }
1106
1143
 
1107
1144
  var __decorate$t = (this && this.__decorate) || function (decorators, target, key, desc) {
@@ -1162,8 +1199,12 @@ let Assets = class Assets {
1162
1199
  reject(error.message || error);
1163
1200
  })
1164
1201
  .on("finish", () => {
1165
- const asset = new Asset(uploaderStream.id, metadata.filename, contentType, metadata, this.bucket, this.collection);
1166
- this.collection.updateOne({ _id: uploaderStream.id }, { $set: asset.toJSON() }).then(() => {
1202
+ const asset = new Asset(uploaderStream.id, {
1203
+ filename: metadata.filename,
1204
+ contentType,
1205
+ metadata
1206
+ }, this.collection, this.bucket);
1207
+ asset.save().then(() => {
1167
1208
  resolve(asset);
1168
1209
  }, error => {
1169
1210
  reject(error.message || error);
@@ -1180,6 +1221,12 @@ let Assets = class Assets {
1180
1221
  return this.write(bufferToStream(buffer), contentType, metadata);
1181
1222
  });
1182
1223
  }
1224
+ writeUrl(url, metadata = null) {
1225
+ return __awaiter$q(this, void 0, void 0, function* () {
1226
+ const buffer = (yield axios({ url, responseType: "arraybuffer" })).data;
1227
+ return this.writeBuffer(buffer, metadata);
1228
+ });
1229
+ }
1183
1230
  read(id) {
1184
1231
  return __awaiter$q(this, void 0, void 0, function* () {
1185
1232
  return this.find({ _id: new ObjectId(id) });
@@ -1188,7 +1235,7 @@ let Assets = class Assets {
1188
1235
  find(where) {
1189
1236
  return __awaiter$q(this, void 0, void 0, function* () {
1190
1237
  const data = yield this.collection.findOne(where);
1191
- return !data ? null : new Asset(data._id, data.filename, data.contentType, data.metadata, this.bucket, this.collection);
1238
+ return !data ? null : new Asset(data._id, data, this.collection, this.bucket);
1192
1239
  });
1193
1240
  }
1194
1241
  unlink(id) {
@@ -1215,52 +1262,61 @@ var __awaiter$p = (this && this.__awaiter) || function (thisArg, _arguments, P,
1215
1262
  step((generator = generator.apply(thisArg, _arguments || [])).next());
1216
1263
  });
1217
1264
  };
1218
- class LazyAsset {
1219
- constructor(lazyId, jobName, jobParams, jobQue, mProgressId, mAssetId, assets, progresses, jobMan, collection) {
1220
- this.lazyId = lazyId;
1221
- this.jobName = jobName;
1222
- this.jobParams = jobParams;
1223
- this.jobQue = jobQue;
1224
- this.mProgressId = mProgressId;
1225
- this.mAssetId = mAssetId;
1265
+ class LazyAsset extends BaseEntity {
1266
+ constructor(id, data, collection, assets, progresses, jobMan) {
1267
+ super(id, data, collection);
1226
1268
  this.assets = assets;
1227
1269
  this.progresses = progresses;
1228
1270
  this.jobMan = jobMan;
1229
- this.collection = collection;
1230
1271
  }
1231
- get id() {
1232
- return this.lazyId.toHexString();
1272
+ get jobName() {
1273
+ return this.data.jobName;
1274
+ }
1275
+ get jobParams() {
1276
+ return this.data.jobParams;
1277
+ }
1278
+ get jobQue() {
1279
+ return this.data.jobQue;
1233
1280
  }
1234
1281
  get progressId() {
1235
- return this.mProgressId;
1282
+ return this.data.progressId;
1236
1283
  }
1237
1284
  get assetId() {
1238
- return this.mAssetId;
1285
+ return this.data.assetId;
1239
1286
  }
1240
1287
  unlink() {
1241
1288
  return __awaiter$p(this, void 0, void 0, function* () {
1242
- yield this.collection.deleteOne({ _id: this.lazyId });
1243
- return deleteFromBucket(this.assets.bucket, new ObjectId(this.mAssetId));
1289
+ yield this.load();
1290
+ if (!this.progressId) {
1291
+ yield this.collection.deleteOne({ _id: this.mId });
1292
+ }
1293
+ return deleteFromBucket(this.assets.bucket, new ObjectId(this.assetId));
1244
1294
  });
1245
1295
  }
1246
1296
  startWorking() {
1247
- if (this.mProgressId)
1248
- return;
1249
- this.startWorkingOnAsset().then(() => {
1250
- console.log(`Started working on lazy asset: ${this.id}`);
1251
- }).catch(reason => {
1252
- console.log(`Can't start working on lazy asset: ${this.id}\nReason: ${reason}`);
1297
+ this.load().then(() => {
1298
+ if (this.deleted)
1299
+ return;
1300
+ const progressPromise = !this.progressId ? Promise.resolve(null) : this.progresses.get(this.progressId).then(p => p.cancel());
1301
+ progressPromise.then(() => {
1302
+ this.startWorkingOnAsset().then(() => {
1303
+ console.log(`Started working on lazy asset: ${this.id}`);
1304
+ }).catch(reason => {
1305
+ console.log(`Can't start working on lazy asset: ${this.id}\nReason: ${reason}`);
1306
+ });
1307
+ });
1253
1308
  });
1254
1309
  }
1255
1310
  loadAsset() {
1256
1311
  return __awaiter$p(this, void 0, void 0, function* () {
1257
- if (this.mAssetId) {
1258
- return this.assets.read(this.mAssetId);
1312
+ yield this.load();
1313
+ if (this.deleted)
1314
+ return null;
1315
+ if (this.assetId) {
1316
+ return this.assets.read(this.assetId);
1259
1317
  }
1260
- if (this.mProgressId) {
1261
- yield this.progresses.waitToFinish(this.mProgressId);
1262
- const data = yield this.collection.findOne({ _id: this.lazyId });
1263
- this.mAssetId = data.assetId;
1318
+ if (this.progressId) {
1319
+ yield this.progresses.waitToFinish(this.progressId);
1264
1320
  return this.loadAsset();
1265
1321
  }
1266
1322
  yield this.startWorkingOnAsset();
@@ -1269,30 +1325,17 @@ class LazyAsset {
1269
1325
  }
1270
1326
  writeAsset(asset) {
1271
1327
  return __awaiter$p(this, void 0, void 0, function* () {
1272
- this.mAssetId = asset.id;
1328
+ this.data.assetId = asset.id;
1273
1329
  yield this.save();
1274
1330
  return asset;
1275
1331
  });
1276
1332
  }
1277
- save() {
1278
- return this.collection.updateOne({ _id: this.lazyId }, { $set: this.toJSON() });
1279
- }
1280
- toJSON() {
1281
- return {
1282
- id: this.id,
1283
- jobName: this.jobName,
1284
- jobParams: this.jobParams,
1285
- jobQue: this.jobQue,
1286
- progressId: this.progressId,
1287
- assetId: this.assetId,
1288
- };
1289
- }
1290
1333
  startWorkingOnAsset() {
1291
1334
  return __awaiter$p(this, void 0, void 0, function* () {
1292
- const progress = yield this.progresses.create();
1293
- this.mProgressId = progress.id;
1335
+ const { id } = yield this.progresses.create();
1336
+ this.data.progressId = id;
1294
1337
  yield this.save();
1295
- yield this.jobMan.enqueueWithName(this.jobName, Object.assign(Object.assign({}, this.jobParams), { lazyId: this.id }));
1338
+ yield this.jobMan.enqueueWithName(this.data.jobName, Object.assign(Object.assign({}, this.data.jobParams), { lazyId: this.id }));
1296
1339
  });
1297
1340
  }
1298
1341
  }
@@ -1501,36 +1544,31 @@ var __awaiter$n = (this && this.__awaiter) || function (thisArg, _arguments, P,
1501
1544
  step((generator = generator.apply(thisArg, _arguments || [])).next());
1502
1545
  });
1503
1546
  };
1504
- class Progress {
1505
- constructor(progressId, mCurrent, mMax, mMessage, mError, client, collection) {
1506
- this.progressId = progressId;
1507
- this.mCurrent = mCurrent;
1508
- this.mMax = mMax;
1509
- this.mMessage = mMessage;
1510
- this.mError = mError;
1547
+ class Progress extends BaseEntity {
1548
+ constructor(id, data, collection, client) {
1549
+ super(id, data, collection);
1511
1550
  this.client = client;
1512
- this.collection = collection;
1513
- }
1514
- get id() {
1515
- return this.progressId.toHexString();
1516
1551
  }
1517
1552
  get current() {
1518
- return this.mCurrent;
1553
+ return this.data.current;
1519
1554
  }
1520
1555
  get max() {
1521
- return this.mMax;
1556
+ return this.data.max;
1522
1557
  }
1523
1558
  get message() {
1524
- return this.mMessage;
1559
+ return this.data.message;
1525
1560
  }
1526
1561
  get error() {
1527
- return this.mError;
1562
+ return this.data.error;
1563
+ }
1564
+ get canceled() {
1565
+ return this.data.canceled;
1528
1566
  }
1529
1567
  get percent() {
1530
- return this.mMax > 0 ? Math.round(this.mCurrent / this.mMax * 100) : 0;
1568
+ return this.max > 0 ? Math.round(this.current / this.max * 100) : 0;
1531
1569
  }
1532
1570
  get remaining() {
1533
- return this.mMax > 0 ? this.mMax - this.mCurrent : 0;
1571
+ return this.max > 0 ? this.max - this.current : 0;
1534
1572
  }
1535
1573
  createSubProgress(progressValue, max, message) {
1536
1574
  return __awaiter$n(this, void 0, void 0, function* () {
@@ -1538,10 +1576,10 @@ class Progress {
1538
1576
  yield this.advance(progressValue);
1539
1577
  }
1540
1578
  if (message !== null) {
1541
- this.mMessage = message;
1579
+ this.data.message = message;
1542
1580
  yield this.save();
1543
1581
  }
1544
- return new SubProgress(this, this.mCurrent, progressValue, Math.max(max, 1));
1582
+ return new SubProgress(this, this.current, progressValue, Math.max(max, 1));
1545
1583
  });
1546
1584
  }
1547
1585
  setMax(max) {
@@ -1549,13 +1587,19 @@ class Progress {
1549
1587
  if (isNaN(max) || max <= 0) {
1550
1588
  throw "Max progress value must be bigger than zero";
1551
1589
  }
1552
- this.mMax = max;
1590
+ this.data.max = max;
1591
+ yield this.save();
1592
+ });
1593
+ }
1594
+ setMessage(message) {
1595
+ return __awaiter$n(this, void 0, void 0, function* () {
1596
+ this.data.message = message;
1553
1597
  yield this.save();
1554
1598
  });
1555
1599
  }
1556
1600
  setError(error) {
1557
1601
  return __awaiter$n(this, void 0, void 0, function* () {
1558
- this.mError = error;
1602
+ this.data.error = error;
1559
1603
  yield this.save();
1560
1604
  });
1561
1605
  }
@@ -1564,63 +1608,60 @@ class Progress {
1564
1608
  if (isNaN(value) || value <= 0) {
1565
1609
  throw "Advance value must be bigger than zero";
1566
1610
  }
1567
- this.mCurrent = Math.min(this.mMax, this.mCurrent + value);
1611
+ yield this.load();
1612
+ if (this.deleted || this.canceled)
1613
+ return null;
1614
+ this.data.current = Math.min(this.max, this.current + value);
1568
1615
  yield this.save();
1569
1616
  if (!this.client)
1570
1617
  return;
1571
1618
  this.client.emit("background-progress", this.id);
1572
1619
  });
1573
1620
  }
1574
- toJSON() {
1575
- return {
1576
- id: this.id,
1577
- current: this.current,
1578
- max: this.max,
1579
- message: this.message,
1580
- error: this.error
1581
- };
1582
- }
1583
- save() {
1584
- return this.collection.updateOne({ _id: this.progressId }, { $set: this.toJSON() });
1621
+ cancel() {
1622
+ return __awaiter$n(this, void 0, void 0, function* () {
1623
+ this.data.canceled = true;
1624
+ yield this.save();
1625
+ });
1585
1626
  }
1586
1627
  }
1587
1628
  class SubProgress {
1588
- constructor(parent, progressFrom, progressValue, max = 100) {
1629
+ constructor(parent, progressFrom, progressValue, mMax = 100) {
1589
1630
  this.parent = parent;
1590
1631
  this.progressFrom = progressFrom;
1591
1632
  this.progressValue = progressValue;
1592
- this.max = max;
1633
+ this.mMax = mMax;
1593
1634
  if (progressFrom < 0) {
1594
1635
  throw "Progress from must be bigger than or zero";
1595
1636
  }
1596
1637
  if (progressValue <= 0) {
1597
1638
  throw "Progress value must be bigger than zero";
1598
1639
  }
1599
- this.currentValue = 0;
1640
+ this.mCurrent = 0;
1600
1641
  }
1601
1642
  get id() {
1602
1643
  return this.parent.id;
1603
1644
  }
1645
+ get current() {
1646
+ return this.mCurrent;
1647
+ }
1648
+ get max() {
1649
+ return this.mMax;
1650
+ }
1604
1651
  get message() {
1605
1652
  return this.parent.message;
1606
1653
  }
1607
- set message(value) {
1608
- this.parent.message = value;
1609
- }
1610
1654
  get error() {
1611
1655
  return this.parent.error;
1612
1656
  }
1613
- set error(value) {
1614
- this.parent.error = value;
1615
- }
1616
1657
  get percent() {
1617
1658
  return this.parent.percent;
1618
1659
  }
1619
- get current() {
1620
- return this.currentValue;
1621
- }
1622
1660
  get remaining() {
1623
- return this.max - this.currentValue;
1661
+ return this.max - this.mCurrent;
1662
+ }
1663
+ get canceled() {
1664
+ return !this.parent || this.parent.canceled;
1624
1665
  }
1625
1666
  createSubProgress(progressValue, max, message) {
1626
1667
  return __awaiter$n(this, void 0, void 0, function* () {
@@ -1628,8 +1669,7 @@ class SubProgress {
1628
1669
  yield this.advance(progressValue);
1629
1670
  }
1630
1671
  if (message !== null) {
1631
- this.message = message;
1632
- yield this.parent.save();
1672
+ yield this.setMessage(message);
1633
1673
  }
1634
1674
  return new SubProgress(this, this.current, progressValue, Math.max(max, 1));
1635
1675
  });
@@ -1639,14 +1679,22 @@ class SubProgress {
1639
1679
  if (isNaN(max) || max <= 0) {
1640
1680
  throw "Max progress value must be bigger than zero";
1641
1681
  }
1642
- this.max = max;
1682
+ this.mMax = max;
1643
1683
  yield this.save();
1644
1684
  });
1645
1685
  }
1686
+ setMessage(message) {
1687
+ return __awaiter$n(this, void 0, void 0, function* () {
1688
+ if (!this.parent)
1689
+ return null;
1690
+ yield this.parent.setMessage(message);
1691
+ });
1692
+ }
1646
1693
  setError(error) {
1647
1694
  return __awaiter$n(this, void 0, void 0, function* () {
1648
- this.error = error || null;
1649
- yield this.save();
1695
+ if (!this.parent)
1696
+ return null;
1697
+ yield this.parent.setError(error);
1650
1698
  });
1651
1699
  }
1652
1700
  advance(value = 1) {
@@ -1654,13 +1702,20 @@ class SubProgress {
1654
1702
  if (isNaN(value) || value <= 0) {
1655
1703
  throw "Advance value must be bigger than zero";
1656
1704
  }
1657
- this.currentValue = Math.min(this.max, this.currentValue + value);
1705
+ this.mCurrent = Math.min(this.max, this.mCurrent + value);
1658
1706
  yield this.save();
1659
1707
  });
1660
1708
  }
1709
+ cancel() {
1710
+ return __awaiter$n(this, void 0, void 0, function* () {
1711
+ if (!this.parent)
1712
+ return null;
1713
+ yield this.parent.cancel();
1714
+ });
1715
+ }
1661
1716
  save() {
1662
1717
  return __awaiter$n(this, void 0, void 0, function* () {
1663
- const ratio = this.max > 0 ? this.currentValue / this.max : 0;
1718
+ const ratio = this.max > 0 ? this.mCurrent / this.max : 0;
1664
1719
  const newProgress = this.progressFrom + Math.round(this.progressValue * ratio);
1665
1720
  const current = this.parent.current;
1666
1721
  if (newProgress <= current)
@@ -1668,6 +1723,11 @@ class SubProgress {
1668
1723
  yield this.parent.advance(newProgress);
1669
1724
  });
1670
1725
  }
1726
+ load() {
1727
+ return __awaiter$n(this, void 0, void 0, function* () {
1728
+ return null;
1729
+ });
1730
+ }
1671
1731
  toJSON() {
1672
1732
  return this.parent.toJSON();
1673
1733
  }
@@ -1728,7 +1788,7 @@ let Progresses = class Progresses {
1728
1788
  find(where) {
1729
1789
  return __awaiter$m(this, void 0, void 0, function* () {
1730
1790
  const data = yield this.collection.findOne(where);
1731
- return !data ? null : new Progress(data._id, data.current, data.max, data.message, data.error, this.client, this.collection);
1791
+ return !data ? null : new Progress(data._id, data, this.collection, this.client);
1732
1792
  });
1733
1793
  }
1734
1794
  create(max = 100) {
@@ -1736,11 +1796,15 @@ let Progresses = class Progresses {
1736
1796
  if (isNaN(max) || max <= 0) {
1737
1797
  throw "Max progress value must be bigger than zero";
1738
1798
  }
1739
- const res = yield this.collection.insertOne({
1799
+ const data = {
1740
1800
  current: 0,
1741
- max
1742
- });
1743
- return new Progress(res.insertedId, 0, max, "", "", this.client, this.collection);
1801
+ max: max,
1802
+ message: "",
1803
+ error: "",
1804
+ canceled: false
1805
+ };
1806
+ const res = yield this.collection.insertOne(data);
1807
+ return new Progress(res.insertedId, data, this.collection, this.client);
1744
1808
  });
1745
1809
  }
1746
1810
  remove(id) {
@@ -1785,12 +1849,16 @@ let LazyAssets = class LazyAssets {
1785
1849
  create(jobType, jobParams = {}, jobQue = "main") {
1786
1850
  return __awaiter$l(this, void 0, void 0, function* () {
1787
1851
  const jobName = this.jobMan.tryResolve(jobType, Object.assign(Object.assign({}, jobParams), { lazyId: "" }));
1788
- const res = yield this.collection.insertOne({
1852
+ const data = {
1789
1853
  jobName,
1790
1854
  jobParams,
1791
1855
  jobQue
1792
- });
1793
- return new LazyAsset(res.insertedId, jobName, jobParams, jobQue, null, null, this.assets, this.progresses, this.jobMan, this.collection);
1856
+ };
1857
+ const existingAsset = yield this.find(data);
1858
+ if (existingAsset)
1859
+ return existingAsset;
1860
+ const res = yield this.collection.insertOne(data);
1861
+ return new LazyAsset(res.insertedId, data, this.collection, this.assets, this.progresses, this.jobMan);
1794
1862
  });
1795
1863
  }
1796
1864
  read(id) {
@@ -1803,7 +1871,7 @@ let LazyAssets = class LazyAssets {
1803
1871
  const data = yield this.collection.findOne(where);
1804
1872
  return !data
1805
1873
  ? null
1806
- : new LazyAsset(data._id, data.jobName, data.jobParams, data.jobQue, data.progressId, data.assetId, this.assets, this.progresses, this.jobMan, this.collection);
1874
+ : new LazyAsset(data._id, data, this.collection, this.assets, this.progresses, this.jobMan);
1807
1875
  });
1808
1876
  }
1809
1877
  unlink(id) {
@@ -2765,6 +2833,18 @@ let AssetsController = class AssetsController {
2765
2833
  }
2766
2834
  });
2767
2835
  }
2836
+ uploadUrl(body) {
2837
+ return __awaiter$7(this, void 0, void 0, function* () {
2838
+ try {
2839
+ const asset = yield this.assets.writeUrl(body.url, body);
2840
+ return asset.toJSON();
2841
+ }
2842
+ catch (e) {
2843
+ const msg = (e === null || e === void 0 ? void 0 : e.message) || e || "Unknown error";
2844
+ throw new HttpError(400, `Asset can't be uploaded.\n${msg}`);
2845
+ }
2846
+ });
2847
+ }
2768
2848
  getImageRotation(id, params, rotation = 0) {
2769
2849
  var _a;
2770
2850
  return __awaiter$7(this, void 0, void 0, function* () {
@@ -2810,6 +2890,14 @@ __decorate$a([
2810
2890
  __metadata$7("design:paramtypes", [Object]),
2811
2891
  __metadata$7("design:returntype", Promise)
2812
2892
  ], AssetsController.prototype, "upload", null);
2893
+ __decorate$a([
2894
+ Authorized(),
2895
+ Post("url"),
2896
+ __param$5(0, Body()),
2897
+ __metadata$7("design:type", Function),
2898
+ __metadata$7("design:paramtypes", [Object]),
2899
+ __metadata$7("design:returntype", Promise)
2900
+ ], AssetsController.prototype, "uploadUrl", null);
2813
2901
  __decorate$a([
2814
2902
  Get("/image/:id/:rotation"),
2815
2903
  __param$5(0, Param("id")), __param$5(1, QueryParams()), __param$5(2, Param("rotation")),
@@ -3495,9 +3583,14 @@ class LazyAssetGenerator {
3495
3583
  process() {
3496
3584
  return __awaiter$1(this, void 0, void 0, function* () {
3497
3585
  const lazyAsset = yield this.lazyAssets.read(this.lazyId);
3498
- const progress = yield this.progresses.get(lazyAsset.progressId);
3586
+ let progress = yield this.progresses.get(lazyAsset.progressId);
3587
+ if (!progress || progress.canceled)
3588
+ return null;
3499
3589
  try {
3500
3590
  const asset = yield this.generate(progress);
3591
+ progress = yield progress.load();
3592
+ if (!progress || progress.canceled)
3593
+ return null;
3501
3594
  yield lazyAsset.writeAsset(asset);
3502
3595
  }
3503
3596
  catch (e) {