Skip to content

Commit

Permalink
feat(strapi-admin-extensions): enable to import VAC as CSV
Browse files Browse the repository at this point in the history
  • Loading branch information
AliKdhim87 committed Jan 16, 2025
1 parent 481043e commit 399bb87
Show file tree
Hide file tree
Showing 33 changed files with 1,079 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/rare-cows-hug.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@frameless/strapi-admin-extensions": major
---

Maak het mogelijk om VAC als een CSV-bestand te importeren via de API.
2 changes: 2 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ module.exports = {
project: [
'./apps/overige-objecten-api/tsconfig.json',
'./apps/overige-objecten-api/tsconfig.test.json',
'./apps/strapi-admin-extensions/tsconfig.json',
'./apps/strapi-admin-extensions/tsconfig.test.json',
'./apps/kennisbank-dashboard/src/admin/tsconfig.json',
'./apps/kennisbank-dashboard/tsconfig.json',
'./apps/kennisbank-frontend/tsconfig.json',
Expand Down
6 changes: 4 additions & 2 deletions Dockerfile.dev
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ COPY ./apps/vth-dashboard/package.json apps/vth-dashboard/package.json
COPY ./apps/vth-frontend/package.json apps/vth-frontend/package.json
COPY ./apps/kennisbank-dashboard/package.json apps/kennisbank-dashboard/package.json
COPY ./apps/overige-objecten-api/package.json apps/overige-objecten-api/package.json
COPY ./apps/strapi-admin-extensions/package.json apps/strapi-admin-extensions/package.json
COPY ./apps/kennisbank-frontend/package.json apps/kennisbank-frontend/package.json
COPY ./packages/catalogi-data/package.json packages/catalogi-data/package.json
COPY ./packages/preview-button/package.json packages/preview-button/package.json
Expand All @@ -37,7 +38,7 @@ COPY ./packages/strapi-plugin-language/package.json packages/strapi-plugin-langu
FROM build AS dependencies
# Install prod dependencies
COPY ./patches /opt/app/patches
RUN yarn install
RUN yarn install --frozen-lockfile

# Build target builder #
########################
Expand All @@ -55,7 +56,8 @@ RUN npm run build --workspace @frameless/upl && \
npm run build --workspace @frameless/strapi-plugin-uuid-field && \
npm run build --workspace @frameless/strapi-plugin-env-label && \
npm run build --workspace @frameless/strapi-plugin-language && \
npm run build --workspace @frameless/overige-objecten-api
npm run build --workspace @frameless/overige-objecten-api && \
npm run build --workspace @frameless/strapi-admin-extensions

# Build target production #
###########################
Expand Down
53 changes: 53 additions & 0 deletions apps/strapi-admin-extensions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Strapi Admin Extensions

This project contains custom extensions for the Strapi admin panel. It depends on another app called Strapi dashboard.

## Prerequisites

- Ensure `pdc-dashboard` is installed and set up properly before using `strapi-admin-extensions`.

## Installation

1. **Clone the repository:**

```bash
git clone git@github.com:frameless/strapi.git
```

2. **Install dependencies:**
Make sure you are in the project root:

```bash
yarn install
```

## Usage

1. Ensure the `pdc-dashboard` app is running:

```bash
yarn workspace @frameless/pdc-dashboard dev
```

2. Copy the environment configuration file to the `strapi-admin-extensions` folder:

```bash
cp .env.example .env
```

3. Run the development server for `strapi-admin-extensions`:

```bash
yarn workspace @frameless/strapi-admin-extensions dev
```

## Contributing

We welcome contributions! Feel free to:

- Open an issue to report bugs or suggest new features.
- Submit a pull request with improvements or fixes.

## License

This project is licensed under the EUPL-1.2 License.
21 changes: 21 additions & 0 deletions apps/strapi-admin-extensions/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { Config } from 'jest';

const config: Config = {
preset: 'ts-jest',
// to obtain access to the matchers.
moduleFileExtensions: ['ts', 'tsx', 'js', 'json', 'node'],
setupFilesAfterEnv: ['<rootDir>/src/tests/jest.setup.ts'],
modulePaths: ['<rootDir>'],
testEnvironment: 'node',
roots: ['<rootDir>/src'],
transform: {
'^.+\\.(ts)$': [
'ts-jest',
{
tsconfig: 'tsconfig.test.json',
},
],
},
};

export default config;
52 changes: 52 additions & 0 deletions apps/strapi-admin-extensions/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"name": "@frameless/strapi-admin-extensions",
"version": "0.0.0",
"private": true,
"author": "@frameless",
"description": "Strapi Admin Extensions",
"license": "EUPL-1.2",
"keywords": [],
"scripts": {
"prebuild": "yarn clean",
"build": "npm-run-all --parallel build:*",
"build:server": "tsc -p ./tsconfig.json",
"watch": "tsc -p ./tsconfig.json -w",
"start": "NODE_ENV=production node ./dist/src/server.js",
"dev": "NODE_ENV=development nodemon src/server.ts",
"clean": "rimraf dist src/types tmp",
"test": "STRAPI_ADMIN_EXTENSIONS_PORT=3000 jest --coverage --forceExit --verbose",
"test:watch": "STRAPI_ADMIN_EXTENSIONS_PORT=3000 jest --watch"
},
"dependencies": {
"cors": "2.8.5",
"csv-parser": "3.0.0",
"dompurify": "3.2.1",
"dotenv": "16.4.5",
"express": "4.21.0",
"lodash.memoize": "4.1.2",
"p-limit": "3.0.0",
"morgan": "1.10.0",
"js-yaml": "4.1.0"
},
"devDependencies": {
"@types/cors": "2.8.17",
"@types/dompurify": "3.2.0",
"@types/jest": "29.5.12",
"@types/lodash.memoize": "4.1.9",
"@types/supertest": "6.0.2",
"jest": "29.7.0",
"jest-fetch-mock": "3.0.3",
"nodemon": "3.1.7",
"rimraf": "6.0.1",
"supertest": "7.0.0",
"ts-jest": "29.2.3",
"ts-node": "10.9.2",
"typescript": "5.0.4",
"@types/morgan": "1.9.9"
},
"repository": {
"type": "git+ssh",
"url": "git@github.com:frameless/strapi.git",
"directory": "apps/strapi-admin-extensio0s"
}
}
64 changes: 64 additions & 0 deletions apps/strapi-admin-extensions/src/controllers/import/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import type { NextFunction, Request, Response } from 'express';
import fs from 'node:fs';
import pLimit from 'p-limit';
import { CREATE_VAC } from '../../queries';
import { CreateVacResponse } from '../../strapi-product-types';
import { fetchData, processCsvFile } from '../../utils';

const limit = pLimit(5); // Limit the number of concurrent file uploads
export const importController = async (req: Request, res: Response, next: NextFunction) => {
const type = req.body.type;
if (req.file) {
const filePath = req.file.path;
const requiredColumns = ['vraag', 'antwoord'];

try {
// Process the CSV file and sanitize results
const authorizationHeader = req.headers?.authorization || '';
const [authType, authToken] = authorizationHeader.split(/\s+/);
const tokenAuth = authType === 'Token' ? authToken : authorizationHeader;
const graphqlURL = new URL('/graphql', process.env.STRAPI_PRIVATE_URL);
const sanitizedResults = await processCsvFile(filePath, requiredColumns);
const locale = req.query?.locale || 'nl';

if (type === 'vac') {
// Loop through the sanitized results and create entries one by one
const results = await Promise.all(
sanitizedResults.map((entry) =>
limit(async () => {
try {
const { data: responseData } = await fetchData<CreateVacResponse>({
url: graphqlURL.href,
query: CREATE_VAC,
variables: { locale, data: entry },
headers: {
Authorization: `Bearer ${tokenAuth}`,
},
});
return responseData;
} catch (error: any) {
next(error);
// eslint-disable-next-line no-console
console.error('Error processing entry:', error);
return { error: error.message, entry };
}
}),
),
);
res.json({ message: 'CSV converted to JSON', data: results });
// Delete temporary file after processing
await fs.promises.unlink(filePath);
} else {
res.status(400).send('Invalid import type.');
}
} catch (error) {
await fs.promises.unlink(filePath); // Delete the temporary file in case of error
// Forward any errors to the error handler middleware
next(error);
return null;
}
} else {
res.status(400).send('No file uploaded.');
}
return null;
};
2 changes: 2 additions & 0 deletions apps/strapi-admin-extensions/src/controllers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { importController } from './import';
export { openAPIController } from './openapi';
30 changes: 30 additions & 0 deletions apps/strapi-admin-extensions/src/controllers/openapi/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* eslint-disable no-undef */
import type { RequestHandler } from 'express';
import yaml from 'js-yaml';
import fs from 'node:fs';
import path from 'node:path';

export const openAPIController: RequestHandler = async (req, res, next) => {
try {
const serverURL = `${req.protocol}://${req.get('host')}`;
const url = new URL('api/v2', serverURL).href;
const OPEN_API_YAML = fs.readFileSync(path.join(__dirname, '../../docs/openapi.yaml'), 'utf8');

if (!OPEN_API_YAML) throw new Error('openapi.yaml file not found');

const openAPIDocument = yaml.load(OPEN_API_YAML) as any;
// Update server URLs
const openapiServers = (openAPIDocument.servers || []).map((server: any) => ({
url,
description: server.description,
}));

res.setHeader('Content-Type', 'application/json');
res.setHeader('Access-Control-Allow-Origin', '*');
res.status(200);
return res.json({ ...openAPIDocument, servers: openapiServers });
} catch (error) {
next(error);
return null;
}
};
Loading

0 comments on commit 399bb87

Please sign in to comment.