From 0d96bb6a67d9a3be9133619aa624e74824fdc7a9 Mon Sep 17 00:00:00 2001 From: Henry <14-10373@usb.ve> Date: Thu, 10 Oct 2024 21:49:13 -0400 Subject: [PATCH 1/7] Convertir require a import y eliminar 'use strict' en uploads.ts --- src/user/uploads.ts | 90 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 src/user/uploads.ts diff --git a/src/user/uploads.ts b/src/user/uploads.ts new file mode 100644 index 0000000000..14c7a67b34 --- /dev/null +++ b/src/user/uploads.ts @@ -0,0 +1,90 @@ +'use strict'; + +const path = require('path'); +const nconf = require('nconf'); +const winston = require('winston'); +const crypto = require('crypto'); + +const db = require('../database'); +const posts = require('../posts'); +const file = require('../file'); +const batch = require('../batch'); + +const md5 = filename => crypto.createHash('md5').update(filename).digest('hex'); +const _getFullPath = relativePath => path.resolve(nconf.get('upload_path'), relativePath); +const _validatePath = async (relativePaths) => { + if (typeof relativePaths === 'string') { + relativePaths = [relativePaths]; + } else if (!Array.isArray(relativePaths)) { + throw new Error(`[[error:wrong-parameter-type, relativePaths, ${typeof relativePaths}, array]]`); + } + + const fullPaths = relativePaths.map(path => _getFullPath(path)); + const exists = await Promise.all(fullPaths.map(async fullPath => file.exists(fullPath))); + + if (!fullPaths.every(fullPath => fullPath.startsWith(nconf.get('upload_path'))) || !exists.every(Boolean)) { + throw new Error('[[error:invalid-path]]'); + } +}; + +module.exports = function (User) { + User.associateUpload = async (uid, relativePath) => { + await _validatePath(relativePath); + await Promise.all([ + db.sortedSetAdd(`uid:${uid}:uploads`, Date.now(), relativePath), + db.setObjectField(`upload:${md5(relativePath)}`, 'uid', uid), + ]); + }; + + User.deleteUpload = async function (callerUid, uid, uploadNames) { + if (typeof uploadNames === 'string') { + uploadNames = [uploadNames]; + } else if (!Array.isArray(uploadNames)) { + throw new Error(`[[error:wrong-parameter-type, uploadNames, ${typeof uploadNames}, array]]`); + } + + await _validatePath(uploadNames); + + const [isUsersUpload, isAdminOrGlobalMod] = await Promise.all([ + db.isSortedSetMembers(`uid:${callerUid}:uploads`, uploadNames), + User.isAdminOrGlobalMod(callerUid), + ]); + if (!isAdminOrGlobalMod && !isUsersUpload.every(Boolean)) { + throw new Error('[[error:no-privileges]]'); + } + + await batch.processArray(uploadNames, async (uploadNames) => { + const fullPaths = uploadNames.map(path => _getFullPath(path)); + + await Promise.all(fullPaths.map(async (fullPath, idx) => { + winston.verbose(`[user/deleteUpload] Deleting ${uploadNames[idx]}`); + await Promise.all([ + file.delete(fullPath), + file.delete(file.appendToFileName(fullPath, '-resized')), + ]); + await Promise.all([ + db.sortedSetRemove(`uid:${uid}:uploads`, uploadNames[idx]), + db.delete(`upload:${md5(uploadNames[idx])}`), + ]); + })); + + // Dissociate the upload from pids, if any + const pids = await db.getSortedSetsMembers(uploadNames.map(relativePath => `upload:${md5(relativePath)}:pids`)); + await Promise.all(pids.map(async (pids, idx) => Promise.all( + pids.map(async pid => posts.uploads.dissociate(pid, uploadNames[idx])) + ))); + }, { batch: 50 }); + }; + + User.collateUploads = async function (uid, archive) { + await batch.processSortedSet(`uid:${uid}:uploads`, (files, next) => { + files.forEach((file) => { + archive.file(_getFullPath(file), { + name: path.basename(file), + }); + }); + + setImmediate(next); + }, { batch: 100 }); + }; +}; From 6d6583e9611b66541527e63f3364ac0202ed746a Mon Sep 17 00:00:00 2001 From: Henry <14-10373@usb.ve> Date: Thu, 10 Oct 2024 21:58:32 -0400 Subject: [PATCH 2/7] Agregar tipos a md5, _getFullPath, y _validatePath en uploads.ts --- src/user/uploads.ts | 51 +++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/src/user/uploads.ts b/src/user/uploads.ts index 14c7a67b34..4d0c98d08c 100644 --- a/src/user/uploads.ts +++ b/src/user/uploads.ts @@ -1,30 +1,28 @@ -'use strict'; +import path from 'path'; +import nconf from 'nconf'; +import winston from 'winston'; +import crypto from 'crypto'; -const path = require('path'); -const nconf = require('nconf'); -const winston = require('winston'); -const crypto = require('crypto'); +import db from '../database'; +import posts from '../posts'; +import file from '../file'; +import batch from '../batch'; -const db = require('../database'); -const posts = require('../posts'); -const file = require('../file'); -const batch = require('../batch'); +const md5 = (filename: string): string => crypto.createHash('md5').update(filename).digest('hex'); +const _getFullPath = (relativePath: string): string => path.resolve(nconf.get('upload_path'), relativePath); +const _validatePath = async (relativePaths: string | string[]): Promise => { + if (typeof relativePaths === 'string') { + relativePaths = [relativePaths]; + } else if (!Array.isArray(relativePaths)) { + throw new Error(`[[error:wrong-parameter-type, relativePaths, ${typeof relativePaths}, array]]`); + } -const md5 = filename => crypto.createHash('md5').update(filename).digest('hex'); -const _getFullPath = relativePath => path.resolve(nconf.get('upload_path'), relativePath); -const _validatePath = async (relativePaths) => { - if (typeof relativePaths === 'string') { - relativePaths = [relativePaths]; - } else if (!Array.isArray(relativePaths)) { - throw new Error(`[[error:wrong-parameter-type, relativePaths, ${typeof relativePaths}, array]]`); - } + const fullPaths = relativePaths.map(path => _getFullPath(path)); + const exists = await Promise.all(fullPaths.map(async (fullPath) => file.exists(fullPath))); - const fullPaths = relativePaths.map(path => _getFullPath(path)); - const exists = await Promise.all(fullPaths.map(async fullPath => file.exists(fullPath))); - - if (!fullPaths.every(fullPath => fullPath.startsWith(nconf.get('upload_path'))) || !exists.every(Boolean)) { - throw new Error('[[error:invalid-path]]'); - } + if (!fullPaths.every(fullPath => fullPath.startsWith(nconf.get('upload_path'))) || !exists.every(Boolean)) { + throw new Error('[[error:invalid-path]]'); + } }; module.exports = function (User) { @@ -84,6 +82,13 @@ module.exports = function (User) { }); }); + setImmediate(next); + }, { batch: 100 }); + }; +basename(file), + }); + }); + setImmediate(next); }, { batch: 100 }); }; From 2184895c57c80cdc167bdd9943b4f5cf4ba4e0fd Mon Sep 17 00:00:00 2001 From: Henry <14-10373@usb.ve> Date: Thu, 10 Oct 2024 22:13:22 -0400 Subject: [PATCH 3/7] Agregar tipos a las funciones exportadas en uploads.ts --- src/user/uploads.ts | 111 +++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 59 deletions(-) diff --git a/src/user/uploads.ts b/src/user/uploads.ts index 4d0c98d08c..7855e0dcab 100644 --- a/src/user/uploads.ts +++ b/src/user/uploads.ts @@ -25,71 +25,64 @@ const _validatePath = async (relativePaths: string | string[]): Promise => } }; -module.exports = function (User) { - User.associateUpload = async (uid, relativePath) => { - await _validatePath(relativePath); - await Promise.all([ - db.sortedSetAdd(`uid:${uid}:uploads`, Date.now(), relativePath), - db.setObjectField(`upload:${md5(relativePath)}`, 'uid', uid), - ]); - }; +module.exports = function (User: any) { - User.deleteUpload = async function (callerUid, uid, uploadNames) { - if (typeof uploadNames === 'string') { - uploadNames = [uploadNames]; - } else if (!Array.isArray(uploadNames)) { - throw new Error(`[[error:wrong-parameter-type, uploadNames, ${typeof uploadNames}, array]]`); - } + User.associateUpload = async (uid: number, relativePath: string): Promise => { + await _validatePath(relativePath); + await Promise.all([ + db.sortedSetAdd(`uid:${uid}:uploads`, Date.now(), relativePath), + db.setObjectField(`upload:${md5(relativePath)}`, 'uid', uid), + ]); + }; - await _validatePath(uploadNames); + User.deleteUpload = async function (callerUid: number, uid: number, uploadNames: string | string[]): Promise { + if (typeof uploadNames === 'string') { + uploadNames = [uploadNames]; + } else if (!Array.isArray(uploadNames)) { + throw new Error(`[[error:wrong-parameter-type, uploadNames, ${typeof uploadNames}, array]]`); + } - const [isUsersUpload, isAdminOrGlobalMod] = await Promise.all([ - db.isSortedSetMembers(`uid:${callerUid}:uploads`, uploadNames), - User.isAdminOrGlobalMod(callerUid), - ]); - if (!isAdminOrGlobalMod && !isUsersUpload.every(Boolean)) { - throw new Error('[[error:no-privileges]]'); - } + await _validatePath(uploadNames); - await batch.processArray(uploadNames, async (uploadNames) => { - const fullPaths = uploadNames.map(path => _getFullPath(path)); + const [isUsersUpload, isAdminOrGlobalMod] = await Promise.all([ + db.isSortedSetMembers(`uid:${callerUid}:uploads`, uploadNames), + User.isAdminOrGlobalMod(callerUid), + ]); - await Promise.all(fullPaths.map(async (fullPath, idx) => { - winston.verbose(`[user/deleteUpload] Deleting ${uploadNames[idx]}`); - await Promise.all([ - file.delete(fullPath), - file.delete(file.appendToFileName(fullPath, '-resized')), - ]); - await Promise.all([ - db.sortedSetRemove(`uid:${uid}:uploads`, uploadNames[idx]), - db.delete(`upload:${md5(uploadNames[idx])}`), - ]); - })); + if (!isAdminOrGlobalMod && !isUsersUpload.every(Boolean)) { + throw new Error('[[error:no-privileges]]'); + } - // Dissociate the upload from pids, if any - const pids = await db.getSortedSetsMembers(uploadNames.map(relativePath => `upload:${md5(relativePath)}:pids`)); - await Promise.all(pids.map(async (pids, idx) => Promise.all( - pids.map(async pid => posts.uploads.dissociate(pid, uploadNames[idx])) - ))); - }, { batch: 50 }); - }; + await batch.processArray(uploadNames, async (uploadNames: string[]) => { + const fullPaths = uploadNames.map(path => _getFullPath(path)); - User.collateUploads = async function (uid, archive) { - await batch.processSortedSet(`uid:${uid}:uploads`, (files, next) => { - files.forEach((file) => { - archive.file(_getFullPath(file), { - name: path.basename(file), - }); - }); + await Promise.all(fullPaths.map(async (fullPath, idx) => { + winston.verbose(`[user/deleteUpload] Deleting ${uploadNames[idx]}`); + await Promise.all([ + file.delete(fullPath), + file.delete(file.appendToFileName(fullPath, '-resized')), + ]); + await Promise.all([ + db.sortedSetRemove(`uid:${uid}:uploads`, uploadNames[idx]), + db.delete(`upload:${md5(uploadNames[idx])}`), + ]); + })); - setImmediate(next); - }, { batch: 100 }); - }; -basename(file), - }); - }); + // Dissociate the upload from pids, if any + const pids = await db.getSortedSetsMembers(uploadNames.map(relativePath => `upload:${md5(relativePath)}:pids`)); + await Promise.all(pids.map(async (pids, idx) => + Promise.all(pids.map(async (pid) => posts.uploads.dissociate(pid, uploadNames[idx]))))); + }, { batch: 50 }); + }; - setImmediate(next); - }, { batch: 100 }); - }; -}; + User.collateUploads = async function (uid: number, archive: any): Promise { + await batch.processSortedSet(`uid:${uid}:uploads`, (files: string[], next: Function) => { + files.forEach((file: string) => { + archive.file(_getFullPath(file), { + name: path.basename(file), + }); + }); + setImmediate(next); + }, { batch: 100 }); + }; +}; \ No newline at end of file From d91b912fa1523a8c7db30e9f60d4be929d9deeda Mon Sep 17 00:00:00 2001 From: Henry <14-10373@usb.ve> Date: Thu, 10 Oct 2024 22:22:50 -0400 Subject: [PATCH 4/7] Cambio de setImmediate(next) a setImmediate(() => next()) --- src/user/uploads.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/user/uploads.ts b/src/user/uploads.ts index 7855e0dcab..d825073547 100644 --- a/src/user/uploads.ts +++ b/src/user/uploads.ts @@ -82,7 +82,7 @@ module.exports = function (User: any) { name: path.basename(file), }); }); - setImmediate(next); + setImmediate(() => next()); }, { batch: 100 }); }; }; \ No newline at end of file From c211cf8d3434c1742c56c3d370eacfe7e455837b Mon Sep 17 00:00:00 2001 From: Henry <14-10373@usb.ve> Date: Thu, 10 Oct 2024 22:31:04 -0400 Subject: [PATCH 5/7] Cambio de module.export = function (User:any) a export default function (User: any) --- src/user/uploads.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/user/uploads.ts b/src/user/uploads.ts index d825073547..88fb40f3ed 100644 --- a/src/user/uploads.ts +++ b/src/user/uploads.ts @@ -25,7 +25,7 @@ const _validatePath = async (relativePaths: string | string[]): Promise => } }; -module.exports = function (User: any) { +export default function (User: any) { User.associateUpload = async (uid: number, relativePath: string): Promise => { await _validatePath(relativePath); From bc40277b8b92b4d87459f4930ba695a8611e3ac2 Mon Sep 17 00:00:00 2001 From: Henry <14-10373@usb.ve> Date: Thu, 10 Oct 2024 22:43:04 -0400 Subject: [PATCH 6/7] Problemas de identacion y otros --- src/user/uploads.ts | 121 ++++++++++++++++++++++---------------------- 1 file changed, 61 insertions(+), 60 deletions(-) diff --git a/src/user/uploads.ts b/src/user/uploads.ts index 88fb40f3ed..2df56b1178 100644 --- a/src/user/uploads.ts +++ b/src/user/uploads.ts @@ -10,79 +10,80 @@ import batch from '../batch'; const md5 = (filename: string): string => crypto.createHash('md5').update(filename).digest('hex'); const _getFullPath = (relativePath: string): string => path.resolve(nconf.get('upload_path'), relativePath); + const _validatePath = async (relativePaths: string | string[]): Promise => { - if (typeof relativePaths === 'string') { - relativePaths = [relativePaths]; - } else if (!Array.isArray(relativePaths)) { - throw new Error(`[[error:wrong-parameter-type, relativePaths, ${typeof relativePaths}, array]]`); - } + if (typeof relativePaths === 'string') { + relativePaths = [relativePaths]; + } else if (!Array.isArray(relativePaths)) { + throw new Error(`[[error:wrong-parameter-type, relativePaths, ${typeof relativePaths}, array]]`); + } - const fullPaths = relativePaths.map(path => _getFullPath(path)); - const exists = await Promise.all(fullPaths.map(async (fullPath) => file.exists(fullPath))); + const fullPaths = relativePaths.map(path => _getFullPath(path)); + const exists = await Promise.all(fullPaths.map(async (fullPath) => file.exists(fullPath))); - if (!fullPaths.every(fullPath => fullPath.startsWith(nconf.get('upload_path'))) || !exists.every(Boolean)) { - throw new Error('[[error:invalid-path]]'); - } + if (!fullPaths.every(fullPath => fullPath.startsWith(nconf.get('upload_path'))) || !exists.every(Boolean)) { + throw new Error('[[error:invalid-path]]'); + } }; -export default function (User: any) { +export default function (User: Record) { - User.associateUpload = async (uid: number, relativePath: string): Promise => { - await _validatePath(relativePath); - await Promise.all([ - db.sortedSetAdd(`uid:${uid}:uploads`, Date.now(), relativePath), - db.setObjectField(`upload:${md5(relativePath)}`, 'uid', uid), - ]); - }; + User.associateUpload = async (uid: number, relativePath: string): Promise => { + await _validatePath(relativePath); + await Promise.all([ + db.sortedSetAdd(`uid:${uid}:uploads`, Date.now(), relativePath), + db.setObjectField(`upload:${md5(relativePath)}`, 'uid', uid), + ]); + }; - User.deleteUpload = async function (callerUid: number, uid: number, uploadNames: string | string[]): Promise { - if (typeof uploadNames === 'string') { - uploadNames = [uploadNames]; - } else if (!Array.isArray(uploadNames)) { - throw new Error(`[[error:wrong-parameter-type, uploadNames, ${typeof uploadNames}, array]]`); - } + User.deleteUpload = async function (callerUid: number, uid: number, uploadNames: string | string[]): Promise { + if (typeof uploadNames === 'string') { + uploadNames = [uploadNames]; + } else if (!Array.isArray(uploadNames)) { + throw new Error(`[[error:wrong-parameter-type, uploadNames, ${typeof uploadNames}, array]]`); + } - await _validatePath(uploadNames); + await _validatePath(uploadNames); - const [isUsersUpload, isAdminOrGlobalMod] = await Promise.all([ - db.isSortedSetMembers(`uid:${callerUid}:uploads`, uploadNames), - User.isAdminOrGlobalMod(callerUid), - ]); + const [isUsersUpload, isAdminOrGlobalMod] = await Promise.all([ + db.isSortedSetMembers(`uid:${callerUid}:uploads`, uploadNames), + User.isAdminOrGlobalMod(callerUid), + ]); - if (!isAdminOrGlobalMod && !isUsersUpload.every(Boolean)) { - throw new Error('[[error:no-privileges]]'); - } + if (!isAdminOrGlobalMod && !isUsersUpload.every(Boolean)) { + throw new Error('[[error:no-privileges]]'); + } - await batch.processArray(uploadNames, async (uploadNames: string[]) => { - const fullPaths = uploadNames.map(path => _getFullPath(path)); + await batch.processArray(uploadNames, async (uploadNames: string[]) => { + const fullPaths = uploadNames.map(path => _getFullPath(path)); - await Promise.all(fullPaths.map(async (fullPath, idx) => { - winston.verbose(`[user/deleteUpload] Deleting ${uploadNames[idx]}`); - await Promise.all([ - file.delete(fullPath), - file.delete(file.appendToFileName(fullPath, '-resized')), - ]); - await Promise.all([ - db.sortedSetRemove(`uid:${uid}:uploads`, uploadNames[idx]), - db.delete(`upload:${md5(uploadNames[idx])}`), - ]); - })); + await Promise.all(fullPaths.map(async (fullPath, idx) => { + winston.verbose(`[user/deleteUpload] Deleting ${uploadNames[idx]}`); + await Promise.all([ + file.delete(fullPath), + file.delete(file.appendToFileName(fullPath, '-resized')), + ]); + await Promise.all([ + db.sortedSetRemove(`uid:${uid}:uploads`, uploadNames[idx]), + db.delete(`upload:${md5(uploadNames[idx])}`), + ]); + })); // Dissociate the upload from pids, if any const pids = await db.getSortedSetsMembers(uploadNames.map(relativePath => `upload:${md5(relativePath)}:pids`)); - await Promise.all(pids.map(async (pids, idx) => - Promise.all(pids.map(async (pid) => posts.uploads.dissociate(pid, uploadNames[idx]))))); - }, { batch: 50 }); - }; + await Promise.all(pids.map(async (pids, idx) => + Promise.all(pids.map(async (pid) => posts.uploads.dissociate(pid, uploadNames[idx]))))); + }, { batch: 50 }); + }; - User.collateUploads = async function (uid: number, archive: any): Promise { - await batch.processSortedSet(`uid:${uid}:uploads`, (files: string[], next: Function) => { - files.forEach((file: string) => { - archive.file(_getFullPath(file), { - name: path.basename(file), - }); - }); - setImmediate(() => next()); - }, { batch: 100 }); - }; -}; \ No newline at end of file + User.collateUploads = async function (uid: number, archive: { file: (path: string, options: { name: string }) => void }): Promise { + await batch.processSortedSet(`uid:${uid}:uploads`, (files: string[], next: () => void) => { + files.forEach((file: string) => { + archive.file(_getFullPath(file), { + name: path.basename(file), + }); + }); + setImmediate(() => next()); + }, { batch: 100 }); + }; +} From 5e0026d2ad948638dd83f98c59328e8ed105eec1 Mon Sep 17 00:00:00 2001 From: Henry <14-10373@usb.ve> Date: Thu, 10 Oct 2024 22:52:11 -0400 Subject: [PATCH 7/7] Generar archivo JavaScript desde TypeScript para uploads.js --- src/user/uploads.js | 180 ++++++++++++++++++++++---------------------- 1 file changed, 92 insertions(+), 88 deletions(-) diff --git a/src/user/uploads.js b/src/user/uploads.js index 14c7a67b34..219b8f94b1 100644 --- a/src/user/uploads.js +++ b/src/user/uploads.js @@ -1,90 +1,94 @@ -'use strict'; - -const path = require('path'); -const nconf = require('nconf'); -const winston = require('winston'); -const crypto = require('crypto'); - -const db = require('../database'); -const posts = require('../posts'); -const file = require('../file'); -const batch = require('../batch'); - -const md5 = filename => crypto.createHash('md5').update(filename).digest('hex'); -const _getFullPath = relativePath => path.resolve(nconf.get('upload_path'), relativePath); -const _validatePath = async (relativePaths) => { - if (typeof relativePaths === 'string') { - relativePaths = [relativePaths]; - } else if (!Array.isArray(relativePaths)) { - throw new Error(`[[error:wrong-parameter-type, relativePaths, ${typeof relativePaths}, array]]`); - } - - const fullPaths = relativePaths.map(path => _getFullPath(path)); - const exists = await Promise.all(fullPaths.map(async fullPath => file.exists(fullPath))); - - if (!fullPaths.every(fullPath => fullPath.startsWith(nconf.get('upload_path'))) || !exists.every(Boolean)) { - throw new Error('[[error:invalid-path]]'); - } +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); }; - -module.exports = function (User) { - User.associateUpload = async (uid, relativePath) => { - await _validatePath(relativePath); - await Promise.all([ - db.sortedSetAdd(`uid:${uid}:uploads`, Date.now(), relativePath), - db.setObjectField(`upload:${md5(relativePath)}`, 'uid', uid), - ]); - }; - - User.deleteUpload = async function (callerUid, uid, uploadNames) { - if (typeof uploadNames === 'string') { - uploadNames = [uploadNames]; - } else if (!Array.isArray(uploadNames)) { - throw new Error(`[[error:wrong-parameter-type, uploadNames, ${typeof uploadNames}, array]]`); - } - - await _validatePath(uploadNames); - - const [isUsersUpload, isAdminOrGlobalMod] = await Promise.all([ - db.isSortedSetMembers(`uid:${callerUid}:uploads`, uploadNames), - User.isAdminOrGlobalMod(callerUid), - ]); - if (!isAdminOrGlobalMod && !isUsersUpload.every(Boolean)) { - throw new Error('[[error:no-privileges]]'); - } - - await batch.processArray(uploadNames, async (uploadNames) => { - const fullPaths = uploadNames.map(path => _getFullPath(path)); - - await Promise.all(fullPaths.map(async (fullPath, idx) => { - winston.verbose(`[user/deleteUpload] Deleting ${uploadNames[idx]}`); - await Promise.all([ - file.delete(fullPath), - file.delete(file.appendToFileName(fullPath, '-resized')), - ]); - await Promise.all([ - db.sortedSetRemove(`uid:${uid}:uploads`, uploadNames[idx]), - db.delete(`upload:${md5(uploadNames[idx])}`), - ]); - })); - - // Dissociate the upload from pids, if any - const pids = await db.getSortedSetsMembers(uploadNames.map(relativePath => `upload:${md5(relativePath)}:pids`)); - await Promise.all(pids.map(async (pids, idx) => Promise.all( - pids.map(async pid => posts.uploads.dissociate(pid, uploadNames[idx])) - ))); - }, { batch: 50 }); - }; - - User.collateUploads = async function (uid, archive) { - await batch.processSortedSet(`uid:${uid}:uploads`, (files, next) => { - files.forEach((file) => { - archive.file(_getFullPath(file), { - name: path.basename(file), - }); - }); - - setImmediate(next); - }, { batch: 100 }); - }; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; }; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.default = default_1; +const path_1 = __importDefault(require("path")); +const nconf_1 = __importDefault(require("nconf")); +const winston_1 = __importDefault(require("winston")); +const crypto_1 = __importDefault(require("crypto")); +const database_1 = __importDefault(require("../database")); +const posts_1 = __importDefault(require("../posts")); +const file_1 = __importDefault(require("../file")); +const batch_1 = __importDefault(require("../batch")); +const md5 = (filename) => crypto_1.default.createHash('md5').update(filename).digest('hex'); +const _getFullPath = (relativePath) => path_1.default.resolve(nconf_1.default.get('upload_path'), relativePath); +const _validatePath = (relativePaths) => __awaiter(void 0, void 0, void 0, function* () { + if (typeof relativePaths === 'string') { + relativePaths = [relativePaths]; + } + else if (!Array.isArray(relativePaths)) { + throw new Error(`[[error:wrong-parameter-type, relativePaths, ${typeof relativePaths}, array]]`); + } + const fullPaths = relativePaths.map(path => _getFullPath(path)); + const exists = yield Promise.all(fullPaths.map((fullPath) => __awaiter(void 0, void 0, void 0, function* () { return file_1.default.exists(fullPath); }))); + if (!fullPaths.every(fullPath => fullPath.startsWith(nconf_1.default.get('upload_path'))) || !exists.every(Boolean)) { + throw new Error('[[error:invalid-path]]'); + } +}); +function default_1(User) { + User.associateUpload = (uid, relativePath) => __awaiter(this, void 0, void 0, function* () { + yield _validatePath(relativePath); + yield Promise.all([ + database_1.default.sortedSetAdd(`uid:${uid}:uploads`, Date.now(), relativePath), + database_1.default.setObjectField(`upload:${md5(relativePath)}`, 'uid', uid), + ]); + }); + User.deleteUpload = function (callerUid, uid, uploadNames) { + return __awaiter(this, void 0, void 0, function* () { + if (typeof uploadNames === 'string') { + uploadNames = [uploadNames]; + } + else if (!Array.isArray(uploadNames)) { + throw new Error(`[[error:wrong-parameter-type, uploadNames, ${typeof uploadNames}, array]]`); + } + yield _validatePath(uploadNames); + const [isUsersUpload, isAdminOrGlobalMod] = yield Promise.all([ + database_1.default.isSortedSetMembers(`uid:${callerUid}:uploads`, uploadNames), + User.isAdminOrGlobalMod(callerUid), + ]); + if (!isAdminOrGlobalMod && !isUsersUpload.every(Boolean)) { + throw new Error('[[error:no-privileges]]'); + } + yield batch_1.default.processArray(uploadNames, (uploadNames) => __awaiter(this, void 0, void 0, function* () { + const fullPaths = uploadNames.map(path => _getFullPath(path)); + yield Promise.all(fullPaths.map((fullPath, idx) => __awaiter(this, void 0, void 0, function* () { + winston_1.default.verbose(`[user/deleteUpload] Deleting ${uploadNames[idx]}`); + yield Promise.all([ + file_1.default.delete(fullPath), + file_1.default.delete(file_1.default.appendToFileName(fullPath, '-resized')), + ]); + yield Promise.all([ + database_1.default.sortedSetRemove(`uid:${uid}:uploads`, uploadNames[idx]), + database_1.default.delete(`upload:${md5(uploadNames[idx])}`), + ]); + }))); + // Dissociate the upload from pids, if any + const pids = yield database_1.default.getSortedSetsMembers(uploadNames.map(relativePath => `upload:${md5(relativePath)}:pids`)); + yield Promise.all(pids.map((pids, idx) => __awaiter(this, void 0, void 0, function* () { return Promise.all(pids.map((pid) => __awaiter(this, void 0, void 0, function* () { return posts_1.default.uploads.dissociate(pid, uploadNames[idx]); }))); }))); + }), { batch: 50 }); + }); + }; + User.collateUploads = function (uid, archive) { + return __awaiter(this, void 0, void 0, function* () { + yield batch_1.default.processSortedSet(`uid:${uid}:uploads`, (files, next) => { + files.forEach((file) => { + archive.file(_getFullPath(file), { + name: path_1.default.basename(file), + }); + }); + setImmediate(() => next()); + }, { batch: 100 }); + }); + }; +}