diff --git a/.github/workflows/1511661.yml b/.github/workflows/1511661.yml new file mode 100644 index 0000000000..ddeb9491c4 --- /dev/null +++ b/.github/workflows/1511661.yml @@ -0,0 +1,32 @@ +name: 1511661 + +on: + push: + branches: + - f24 + - 'feature/*' + pull_request: + branches: + - main + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Node.js + uses: actions/setup-node@v2 + with: + node-version: '20' + + - name: Install dependencies + run: npm install + + - name: Compile TypeScript + run: npx tsc + + - name: Run tests (opcional) + run: npm test diff --git a/.husky/commit-msg b/.husky/commit-msg old mode 100755 new mode 100644 diff --git a/.husky/pre-commit b/.husky/pre-commit old mode 100755 new mode 100644 diff --git a/install/docker/entrypoint.sh b/install/docker/entrypoint.sh old mode 100755 new mode 100644 diff --git a/nodebb b/nodebb old mode 100755 new mode 100644 diff --git a/src/groups/cover.ts b/src/groups/cover.ts new file mode 100644 index 0000000000..254af7a59c --- /dev/null +++ b/src/groups/cover.ts @@ -0,0 +1,121 @@ +'use strict'; + +import path from 'path'; +import nconf from 'nconf'; +import db from '../database'; // Módulo JS posiblemente sin migrar a TS +import image from '../image'; // Módulo JS posiblemente sin migrar a TS +import file from '../file'; // Módulo JS posiblemente sin migrar a TS + +// Inicializa nconf +nconf.argv().env().file({ file: path.join(__dirname, '../../node_modules/nconf/lib/config.json') }); + +// Tipos de datos necesarios +interface CoverData { + file?: { + path: string; + type: string; + }; + imageData?: string; + position?: string; + groupName: string; +} + +interface UploadData { + url: string; +} + +// Función principal +export default function (Groups: any) { + const allowedTypes = ['image/png', 'image/jpeg', 'image/bmp']; + + // Función para actualizar la posición de la imagen de portada + Groups.updateCoverPosition = async function (groupName: string, position: string): Promise { + if (!groupName) { + throw new Error('[[error:invalid-data]]'); + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + await Groups.setGroupField(groupName, 'cover:position', position); + }; + + // Función para actualizar la imagen de portada + Groups.updateCover = async function (uid: number, data: CoverData): Promise<{ url: string }> { + let tempPath = data.file ? data.file.path : ''; + try { + if (!data.imageData && !data.file && data.position) { + return await Groups.updateCoverPosition(data.groupName, data.position); + } + + // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access + const type = data.file ? data.file.type : image.mimeFromBase64(data.imageData || ''); + if (!type || !allowedTypes.includes(type)) { + throw new Error('[[error:invalid-image]]'); + } + + if (!tempPath) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + tempPath = await image.writeImageDataToTempFile(data.imageData as string); + } + + const filename = `groupCover-${data.groupName}${path.extname(tempPath)}`; + + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + const uploadData: UploadData = await image.uploadImage(filename, 'files', { + path: tempPath, + uid: uid, + name: 'groupCover', + }); + + const { url } = uploadData; + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + await Groups.setGroupField(data.groupName, 'cover:url', url); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + await image.resizeImage({ + path: tempPath, + width: 358, + }); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + const thumbUploadData: UploadData = await image.uploadImage(`groupCoverThumb-${data.groupName}${path.extname(tempPath)}`, 'files', { + path: tempPath, + uid: uid, + name: 'groupCover', + }); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + await Groups.setGroupField(data.groupName, 'cover:thumb:url', thumbUploadData.url); + + if (data.position) { + await Groups.updateCoverPosition(data.groupName, data.position); + } + + return { url: url }; + } finally { + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + file.delete(tempPath); + } + }; + + // Función para eliminar la imagen de portada + Groups.removeCover = async function (data: { groupName: string }): Promise { + const fields = ['cover:url', 'cover:thumb:url']; + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + const values = await Groups.getGroupFields(data.groupName, fields); + + await Promise.all(fields.map((field) => { + if (!values[field] || !values[field].startsWith(`${nconf.get('relative_path')}/assets/uploads/files/`)) { + return; + } + + const filename = values[field].split('/').pop(); + const filePath = path.join(nconf.get('upload_path'), 'files', filename); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + return file.delete(filePath); + })); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + await db.deleteObjectFields(`group:${data.groupName}`, ['cover:url', 'cover:thumb:url', 'cover:position']); + }; +} diff --git a/tsconfig.json b/tsconfig.json index 10aeeef7e6..0e63d152ea 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,17 +1,18 @@ { "compilerOptions": { - "allowJs": false, + "allowJs": true, "target": "es6", "module": "commonjs", "moduleResolution": "node", - "esModuleInterop": true, + "outDir": "./dist", + "rootDir": "./src", + "noImplicitAny": false, + "esModuleInterop": true }, "include": [ "public/src/**/*", "src/**/*", - "test/**/*", + "test/**/*" ], - "exclude":[ - "node_modules", - ] -} \ No newline at end of file + "exclude": ["node_modules"] +}