From f9f2c520f7876962a6bc291365bec5e4b394eed1 Mon Sep 17 00:00:00 2001 From: mpavlovicbb <58938959+mpavlovicbb@users.noreply.github.com> Date: Thu, 22 Aug 2024 16:53:21 +0200 Subject: [PATCH 01/20] Update merge.yaml --- .github/workflows/merge.yaml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/merge.yaml b/.github/workflows/merge.yaml index 58150939..4c5025cf 100644 --- a/.github/workflows/merge.yaml +++ b/.github/workflows/merge.yaml @@ -5,7 +5,8 @@ on: branches: - develop - staging - - main + - beta + - master permissions: contents: write @@ -127,9 +128,9 @@ jobs: cache-from: type=local,src=/tmp/.buildx-cache cache-to: type=local,dest=/tmp/.buildx-cache build-args: | - NEXT_PUBLIC_API_URL=${{ secrets.DEV_NEXT_PUBLIC_API_URL }} - NEXT_PUBLIC_USERSNAP_GLOBAL_API_KEY=${{ secrets.DEV_NEXT_PUBLIC_USERSNAP_GLOBAL_API_KEY }} - NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY={{ secrets.DEV_NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY }} + NEXT_PUBLIC_API_URL=${{ secrets.PROD_NEXT_PUBLIC_API_URL }} + NEXT_PUBLIC_USERSNAP_GLOBAL_API_KEY=${{ secrets.PROD_NEXT_PUBLIC_USERSNAP_GLOBAL_API_KEY }} + NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY={{ secrets.PROD_NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY }} - name: Login to GHCR uses: docker/login-action@v2 @@ -156,6 +157,7 @@ jobs: docker push ${{ steps.image_lowercase.outputs.lowercase }}:${{ env.TAG }} - name: Deploy with Qovery + if: github.ref == 'refs/heads/develop' env: QOVERY_CLI_ACCESS_TOKEN: ${{secrets.QOVERY_CLI_ACCESS_TOKEN }} run: | From 4ae4ecd60d1170a0e3bb701d766b958a38fcbd6e Mon Sep 17 00:00:00 2001 From: Milos <161627443+BEdev24@users.noreply.github.com> Date: Mon, 26 Aug 2024 10:36:57 +0200 Subject: [PATCH 02/20] feat: readme-master (#291) * feature/readme-master: added readme * feature/readme-master: added docker-compose.yaml --- README.md | 249 +++++++++++++++++-------- backend/example.env | 33 ++-- docker-compose.yaml | 48 ++--- frontend/{.env.example => example.env} | 0 ipfs-service/example.env | 13 +- worker-service/example.env | 12 +- 6 files changed, 211 insertions(+), 144 deletions(-) rename frontend/{.env.example => example.env} (100%) diff --git a/README.md b/README.md index a3b66f6d..5c1dba1c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ -# 🚀 Web-App Boilerplate 🚀 +# Constitution Committee Portal -Welcome to the official repository for the Web App Boilerplate. +Welcome to the official repository for the Constitution Committee Portal. + +The primary purpose of the solution is to host the Cardano Constitution and allow anyone to get familiar with it and follow its evolution over time. It also serves as the single point of truth for the Cardano Community members to see how Constitutional Committee members voted on a specific Governance Action, with the inclusion of their rationale. For members of the Constitutional Committee, it serves as a portal to add reasoning to their votes and prepare it as an off-chain resource to be attached to on-chain governance actions. ## Table of content: @@ -8,42 +10,59 @@ Welcome to the official repository for the Web App Boilerplate. - [Prerequisites](#prerequisites) - [Tech stack](#tech-stack) - [Getting started](#getting-started) -- [Running locally](#running-locally) -- [Running using docker compose](#running-using-docker-compose) +- [Usage](#usage) +- [Environment Variables](#environment-variables) +- [API Documentation](#api-documentation) +- [License](#license) ## Introduction -This document serves as a comprehensive guide for setting up the full stack of our application, which includes the backend, frontend, and database components. +This document serves as a comprehensive guide for setting up the full stack of our application, which includes the Frontend, Backend, Database, Caching, Worker and IPFS components. ## Prerequisites - Node.js installed - [Download link](https://nodejs.org/en/download/). -- PostgreSQL installed (if running locally without Docker) - [Download link](https://www.postgresql.org/). -- Docker and Docker Compose installed (for Docker environment) - [Download link](https://docs.docker.com/get-started/) +- Docker and Docker Compose installed - [Download link](https://docs.docker.com/get-started/) ## Tech stack: -**Server:** [Node](https://nodejs.org/en/about/), [Strapi](https://docs.strapi.io/developer-docs/latest/getting-started/introduction.html) +**Frontend:** [Next.js](https://nextjs.org/) + +**Backend:** [Node](https://nodejs.org/en/about/), [Nest.js](https://nestjs.com/) **Database:** [PostgreSQL](https://www.postgresql.org/) -**Frontend:** [Next.js](https://nextjs.org/) +**Caching service:** [Redis](https://redis.io/docs) + +**Worker service:** [Nest.js](https://nestjs.com/) + +**Helia IPFS/IPNS node:** [Helia](https://github.com/ipfs/helia), [Nest.js](https://nestjs.com/) -**Container:** [Docker](https://docs.docker.com/get-started/) +### Frontend + +The Frontend is developed with Next.js, a React framework that allows for server-side rendering and static site generation. This choice enables us to create fast, SEO-friendly web pages that integrate seamlessly with our Nest.js backend. + +The instructions that follow will guide you through setting up each component of our application stack, ensuring a cohesive development and deployment process. ### Backend -Our backend is powered by Strapi, a versatile headless CMS built on Node.js. It offers an intuitive admin panel, coupled with extensive RESTful and GraphQL API support, enabling efficient content management and API development. +Our Backend is powered by Nest.js on Node.js. It offers REST APIs with a publicly available OpenAPI specification. IIt handles all requests coming from the Frontend. ### Database -For data persistence, we utilize PostgreSQL, known for its robustness, scalability, and reliability. This choice ensures that our application's data layer is secure, efficient, and capable of handling growth. +For data persistence, we utilize PostgreSQL, known for its robustness, scalability, and reliability. This choice ensures that our application's data layer is secure, efficient, and capable of handling growth. It contains the main object data required for operation such as CC members (users), Governance Action Proposals and voting data. -### Frontend +### Caching service -The frontend is developed with Next.js, a React framework that allows for server-side rendering and static site generation. This choice enables us to create fast, SEO-friendly web pages that integrate seamlessly with our Strapi backend. +We utilize Redis service to reduce the load on a Backend database by caching responses for quick retrieval. -The instructions that follow will guide you through setting up each component of our application stack, ensuring a cohesive development and deployment process. +### Worker service + +The Worker service is powered by Nest.js on Node.js. It is used to synchronize with on-chain data changes, specifically governance actions. It is also used to monitor CC members' voting activity on governance actions. It is used to keep track of reasoning URLs that are attached to the CC vote to synchronize the information with the blockchain. + +### IPFS/IPNS Helia node + +The IPFS node is powered by Nest.js with Helia JS library. This service is used to store the Constitution. IPFS relies on hashes of the document to generate URLs, so each revision has a unique hash by default, while IPNS always points to the hash of the latest revision and acts as a regular web domain. The Constitution Page contains a cached version of what is on IPFS as IPFS is good as an immutable store of data but slow for a high number of concurrent users. ## Getting started @@ -55,84 +74,152 @@ Before you begin setting up the application, you'll need to clone the repository - Navigate to the directory where you want to store the project. - Run the following command to clone the repository: ``` - git clone https://github.com/IntersectMBO/web-app-boilerplate.git + git clone https://github.com/IntersectMBO/cc-portal.git ``` 2. **Navigate to the Project Directory:** + - After cloning, change into the project's root directory: ``` - cd web-app-boilerplate + cd cc-portal ``` - This directory contains all the files you need to set up the application, including the Docker Compose files and the separate directories for the backend and frontend components. - -By cloning the repository, you ensure that you have the latest version of the code and all the necessary files to get started with the application setup. - -## Running locally - -To run the application locally, you need to have Node.js installed for the backend and frontend parts, as well as the necessary databases. Follow these steps: - -### Backend setup - -1. **Navigate to the `backend` directory** of the project. -2. **Install dependencies** by running `npm install`. -3. **Configure environment variables** by creating a `.env` file in the backend directory, following the `.env.example` template if available. -4. **Start the Strapi server** in development mode with `npm run develop`, allowing for real-time updates and access to the admin panel. - -### Database configuration - -1. **Install PostgreSQL** if not already installed and ensure it is running. -2. **Create a new database** for the project, noting down the credentials. -3. **Update the `.env` file** in the backend directory with your database credentials (host, port, username, database name, and password). + This directory contains all the files you need to set up the application, including the Docker Compose file and the separate directories for the frontend, backend, ipfs and worker components. -### Frontend setup +3. **Configure Environment Variables:** -1. **Navigate to the `frontend` directory** of the project. -2. **Install dependencies** by running `npm install`. -3. **Configure Environment Variables:** Create or edit a `.env` file in the frontend directory to include environment variables specific to your Next.js application. For seamless integration with the Strapi backend, add the following line to specify the backend API URL: `NEXT_PUBLIC_API_URL=http://localhost:1337` - -4. **Start the Next.js server** with `npm run dev` for development mode. This command serves your frontend application and hot-reloads for any changes. - -By following these detailed steps for each part of the stack, you will have a fully functional full-stack application ready for further development and eventual deployment. - -### Additional Information - -For more detailed information about setting up and running each part of the application, please refer to the README files located in the respective directories: - -- [Backend setup](./backend/README.md) - Detailed instructions for setting up the backend part of the application. -- [Frontend setup](./frontend/README.md) - Detailed instructions for setting up the frontend part of the application. - -## Running using docker compose - -Leverage Docker Compose to simplify the process of deploying the full stack of our application, which includes the backend, frontend, and database. Follow these steps to get everything up and running smoothly: - -1. **Prerequisites:** - - - Confirm that Docker and Docker Compose are installed on your machine. These tools are essential for creating and managing multi-container Docker applications. - -2. **Navigate to your project's root directory:** - - - Open a terminal and change your directory to the root of your project where the `docker-compose.yaml` file is located. This file contains the configuration for all the services that make up your application. - -3. **Start services with docker compose:** - - - Execute the following command to start up all the services as defined in your `docker-compose.yaml` file. The `--build` flag ensures that Docker builds fresh images for your services, reflecting any recent changes you might have made. + - Navigate to the `backend` directory and run the following command: ``` - docker-compose up --build + cp example.env .env ``` - - This command will spin up the backend, frontend, and database containers, linking them together based on your configurations. - -4. **Accessing the application:** - - With all services running, your application components should be accessible at the following URLs: - - **Backend:** `http://localhost:1337` – This is where your Strapi CMS will be accessible for managing content and accessing the API. - - **Frontend:** `http://localhost:3000` – Your Next.js frontend application will be available here, ready to serve your site's visitors. - - **Database:** While the database itself won't be directly accessible via a simple URL (since it's meant to be accessed by your backend service), it's running on a mapped port `4321` on your host machine. This setup is specified in your `docker-compose.yaml` file, allowing secure and straightforward connections from your backend service. + Edit the .env file to reflect your local settings. Env variables description can be found [below](#environment-variables). + - Run this command within folders: `frontend`, `worker-service`, `ipfs-service` to configure environment variables for all these services. Edit every .env file to reflect your local settings. + Important: for `worker-service` environment variables ensure the right credentials for connection to DB-SYNC Database -### Overview of services in docker compose: +4. **Docker Setup:** -- **Backend service:** Configured to run Strapi on port `1337`, this service automatically connects to the PostgreSQL database, ensuring your CMS has all the data it needs to operate. + - Change your directory to the root of your project where the `docker-compose.yaml` file is located. + - Execute the following command to start up all the services as defined in your `docker-compose.yaml` file. + ``` + docker-compose up --build -d + ``` -- **Database service:** This service runs PostgreSQL and is set to be accessible on port `4321` from the host machine. It's crucial for storing all your application's data securely and efficiently. +5. **Database migration:** -- **Frontend service:** Your Next.js application will be served on port `3000`, connecting to the Strapi backend to fetch content and data. This setup provides a seamless experience for developers and users alike. + - Run the following commands: + 1. Navigate to the backend docker container + ``` + docker container exec -it backend bash + ``` + 2. Run script for migrations + ``` + npm run typeorm:run-migrations + ``` + 3. Exit from the backend docker container + ``` + exit + ``` -By following these steps, you can quickly get your full-stack application running using Docker Compose, ensuring each component is correctly configured and interconnected for optimal performance. +6. **Create Super Admin** + + A Super Admin should be created manually. To do that, run the following SQL queries on the Backend PostgreSQL database: + 1. Create super admin user with valid email address + ``` + INSERT INTO users (email, status, role_id) VALUES ('your@email.com', 'active', (SELECT r.id FROM roles r WHERE r.code='super_admin')); + ``` + 2. Add permissions to super admin + ``` + INSERT INTO user_permissions(user_id, permission_id) + SELECT users.id, permissions.id + FROM permissions + INNER join users on users.email + IN ('your@email.com') + WHERE code IN ('manage_admins', 'manage_cc_members', 'add_constitution_version'); + ``` + +## Usage + +If the installation process passes successfully, the CC Portal is ready to use. + - Frontend should be available on the URL: `http://localhost:3000`. + - Backend shoul be available on the URL: `http://localhost:1337`. + +## Environment Variables + +Below is a description of the environment variables used in the `.env` file: + +1. **Frontend:** + + - `NEXT_PUBLIC_API_URL`: Url of the Backend service. Example: `http://localhost:1337`. + +2. **Backend:** + + - `POSTGRES_DB`: The name of the PostgreSQL database. Example: `cc-portal`. + - `POSTGRES_HOST`: The hostname for the PostgreSQL database. Example: `postgres` + - `POSTGRES_PORT`: The port number for the PostgreSQL database. Example: `5432`. + - `POSTGRES_USERNAME`: Username for accessing the PostgreSQL database. Example: `postgres`. + - `POSTGRES_PASSWORD`: Password for the PostgreSQL database user. Example: `postgres`. + - `ENVIRONMENT`: Defines the environment. Example: `local`, `dev`, `stage`, `prod`. + - `DISPLAY_SWAGGER_API`: Defines whether Swagger will be displayed. Example: `true`, `false`. + - `BASE_URL`: Domain of the Backend service. Example: `http://locahost:1337`. + - `MAGIC_LOGIN_SECRET`: Secret key for Magic Login link. + - `MAGIC_LOGIN_LINK_EXPIRES_IN`: Expiration time for Magic Login link. Example: `5m`. + - `MAGIC_REGISTER_SECRET`: Secret key for Magic Register link. + - `MAGIC_REGISTER_LINK_EXPIRES_IN`: Expiration time for Magic Register link. Example: `7d` + - `ACCESS_SECRET`: Secret key for access tokens. + - `REFRESH_SECRET`: Secret key for refresh tokens. + - `JWT_ACCESS_TOKEN_EXPIRES_IN`: Expiration time for JWT access tokens. Example: `15m`. + - `JWT_REFRESH_TOKEN_EXPIRES_IN`: Expiration time for JWT refresh tokens. Example: `7d`. + - `REDIS_HOST`: Hostname for Redis. Example `cache`. + - `REDIS_PORT`: Port number for Redis. Example `6379`. + - `REDIS_PASSWORD`: Password for Redis. Example `password`. + - `AWS_ACCESS_KEY_ID`: AWS SES access key id. + - `AWS_SECRET_ACCESS_KEY`: AWS SES secret access key. + - `AWS_REGION`: AWS SES region. + - `EMAIL_FROM`: Email of sender. + - `NAME_FROM`: Name of sender. + - `MINIO_ENDPOINT`: Endpoint for Minio. Example: `localhost`. + - `MINIO_PORT`: Port number for Minio. Example: `9000`. + - `MINIO_ACCESS_KEY`: Access key for Minio. + - `MINIO_SECRET_KEY`: Secret key for Minio. + - `MINIO_USE_SSL`: Dedines whether Minio use SSL. Example `true`, `false`. + - `MINIO_BUCKET`: Bucket name for Minio. + - `IPFS_SERVICE_URL`: URL of the IPFS service.Example `http://localhost:3001`. + - `FE_LOGIN_CALLBACK_URL`: Frontend login callback URL. Example `http://localhost:3000/en/verify/login`. + - `FE_REGISTER_CALLBACK_URL`: Frontend register callback URL. Example `http://localhost:3000/en/verify/register`. + +3. **IPFS service** + + - `LISTEN_TCP_ADDRESS`: Define where the IPFS node should expect and accept connections from other peers over TCP protocol. + - `LISTEN_WS_ADDRESS`: WebSocket address over TCP protocol. + - `LISTEN_QUIC_ADDRESS`: Quic-v1 address over UDP protocol. + - `IPFS_PUBLIC_URL`: The base of public IPFS URL. + - `IPNS_PUBLIC_URL`: The base of public IPNS URL. + - `IPNS_CONSTITUTION_KEY_NAME`: Key name used to generate IPNS peer ID. Example `some-random-string`. + +4. **Worker service** + + - `BE_POSTGRES_DB`: The name of the Backend PostgreSQL database. Example: `cc-portal`. + - `BE_POSTGRES_HOST`: The hostname for the Backend PostgreSQL database. Example: `postgres` + - `BE_POSTGRES_PORT`: The port number for the Backend PostgreSQL database. Example: `5432`. + - `BE_POSTGRES_USERNAME`: Username for the Backend PostgreSQL database. Example: `postgres`. + - `BE_POSTGRES_PASSWORD`: Password for the Backend PostgreSQL database user. Example: `postgres`. + - `DB_SYNC_POSTGRES_DB`: The name of the Backend PostgreSQL database. Example: `db-sync`. + - `DB_SYNC_POSTGRES_SCHEMA`: The schema of the DB-Sync PostgreSQL database. Example: `public` + - `DB_SYNC_POSTGRES_HOST`: The hostname for the DB-Sync PostgreSQL database. Example: `localhost` + - `DB_SYNC_POSTGRES_PORT`: The port number for the DB-Sync PostgreSQL database. Example: `5432`. + - `DB_SYNC_POSTGRES_USERNAME`: Username for the DB-Sync PostgreSQL database. Example: `db-sync-user`. + - `DB_SYNC_POSTGRES_PASSWORD`: Password for the DB-Sync PostgreSQL database user. Example: `db-sync-password`. + - `REDIS_HOST`: Hostname for Redis. Example `cache`. + - `REDIS_PORT`: Port number for Redis. Example `6379`. + - `REDIS_PASSWORD`: Password for Redis. Example `password`. + - `HOT_ADDRESSES_PER_PAGE`: Password for the DB-Sync PostgreSQL database user. Example: `10`. + - `GOV_ACTION_PROPOSALS_PER_PAGE`: Password for the DB-Sync PostgreSQL database user. Example: `10`. + - `VOTES_JOB_FREQUENCY`: Frequency of the job that retrieves votes. Example: `*/30 * * * * *`. + - `GOV_ACTION_PROPOSALS_JOB_FREQUENCY`: Frequency of the job that retrieves Governance Action Proposals. Example: `0 * * * * *`. + +## API Documentation + +Access the API documentation at: [http://localhost:1337/api-docs](http://localhost:1337/api-docs). + +## License + +This project is licensed under the MIT License. \ No newline at end of file diff --git a/backend/example.env b/backend/example.env index d2baa950..d2ec7064 100644 --- a/backend/example.env +++ b/backend/example.env @@ -1,5 +1,5 @@ POSTGRES_DB=cc-portal -POSTGRES_HOST=localhost +POSTGRES_HOST=postgres POSTGRES_PORT=5432 POSTGRES_USERNAME=postgres POSTGRES_PASSWORD=postgres @@ -19,31 +19,28 @@ JWT_ACCESS_TOKEN_EXPIRES_IN=30m JWT_REFRESH_TOKEN_EXPIRES_IN=7d # Redis -REDIS_HOST=localhost +REDIS_HOST=cache REDIS_PORT=6379 REDIS_PASSWORD=password -#Scheduler -SCHEDULER_JOBS_SYNC_ALL_USERS_FOR_SEARCH_FREQUENCY=0 0-23/1 * * * - -# Sendgrid -SENDGRID_HOST=smtp.sendgrid.net -SENDGRID_PORT=587 -SENDGRID_USER=apikey -SENDGRID_API_KEY=your_api_key -SENDGRID_EMAIL_FROM=email_from -SENDGRID_EMAIL_NAME=CC Portal +# AWS SES +AWS_ACCESS_KEY_ID=your_access_key_id +AWS_SECRET_ACCESS_KEY=your_secret_access_key +AWS_REGION=your_region +EMAIL_FROM=example@email.from +NAME_FROM=Example Name From #minio -MINIO_ENDPOINT='localhost' +MINIO_ENDPOINT=minio MINIO_PORT=9000 -MINIO_ACCESS_KEY=bloxico -MINIO_SECRET_KEY=bloxico2 +MINIO_ACCESS_KEY=minio +MINIO_SECRET_KEY=minio123 MINIO_USE_SSL=false MINIO_BUCKET=cc-portal + # IPFS Service -IPFS_SERVICE_URL=http://localhost:3001 +IPFS_SERVICE_URL=http://ipfs-service:3001 # FE Callback Url -FE_LOGIN_CALLBACK_URL= http://localhost:3000/en/verify/login -FE_REGISTER_CALLBACK_URL = http://localhost:3000/en/verify/register +FE_LOGIN_CALLBACK_URL=http://localhost:3000/en/verify/login +FE_REGISTER_CALLBACK_URL=http://localhost:3000/en/verify/register diff --git a/docker-compose.yaml b/docker-compose.yaml index 6f6b3ecd..eff59fbc 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -8,7 +8,7 @@ services: ports: - "1337:1337" networks: - - bloxico_local + - cc depends_on: - psql - cache @@ -22,24 +22,17 @@ services: container_name: worker restart: unless-stopped networks: - - bloxico_local + - cc ipfs: build: context: ./ipfs-service dockerfile: Dockerfile container_name: ipfs-service - ports: - - "3001:3001" - - "4001:4001" - - "4002:4002" - - "4003:4003" - - "5001:5001" - - "8080:8080" volumes: - - ipfs_data:/ipfs/ + - ipfs_data:/app/ networks: - - bloxico_local + - cc extra_hosts: - "host.docker.internal:host-gateway" depends_on: @@ -51,8 +44,8 @@ services: container_name: postgres environment: POSTGRES_DB: cc-portal - POSTGRES_USER: BEdev24 - POSTGRES_PASSWORD: bedev.bloxico24 + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres volumes: - "psql-data:/var/lib/postgresql/data/" ports: @@ -65,22 +58,22 @@ services: while ! pg_isready -q -h postgres -p 5432; do sleep 1; done; - PGUSER=BEdev24 PGPASSWORD=bedev.bloxico24 psql -U BEdev24 -d cc-portal -c "CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";"; + PGUSER=postgres PGPASSWORD=postgres psql -U postgres -d cc-portal -c "CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";"; wait $pid ' networks: - - bloxico_local + - cc cache: image: redis/redis-stack:latest container_name: cache restart: always ports: - - "6379:6379" + - '6379:6379' volumes: - cache:/data networks: - - bloxico_local + - cc s3: image: minio/minio @@ -89,32 +82,23 @@ services: - "9000:9000" - "9001:9001" environment: - MINIO_ROOT_USER: bloxico - MINIO_ROOT_PASSWORD: bloxico2 + MINIO_ROOT_USER: minio + MINIO_ROOT_PASSWORD: minio123 command: ["server", "/data", "--console-address", ":9001"] volumes: - s3_data:/data networks: - - bloxico_local + - cc frontend: build: context: ./frontend dockerfile: Dockerfile container_name: frontend - networks: - - bloxico_local - - proxy: - build: - context: ./proxy - dockerfile: Dockerfile - container_name: proxy ports: - - "80:80" - - "443:443" + - "3000:3000" networks: - - bloxico_local + - cc volumes: cache: @@ -122,4 +106,4 @@ volumes: ipfs_data: psql-data: networks: - bloxico_local: + cc: \ No newline at end of file diff --git a/frontend/.env.example b/frontend/example.env similarity index 100% rename from frontend/.env.example rename to frontend/example.env diff --git a/ipfs-service/example.env b/ipfs-service/example.env index 1fffecd0..62a72fb3 100644 --- a/ipfs-service/example.env +++ b/ipfs-service/example.env @@ -1,9 +1,8 @@ -LISTEN_TCP_ADDRESS='/ip4/0.0.0.0/tcp/4001' -LISTEN_WS_ADDRESS='/ip4/0.0.0.0/tcp/4003/ws' -LISTEN_QUIC_ADDRESS='/ip4/0.0.0.0/udp/4001/quic' - -ANNOUNCE_TCP_ADDRESS='/ip4//tcp/4001' -ANNOUNCE_WS_ADDRESS='/ip4//tcp/4003/ws' +LISTEN_TCP_ADDRESS='/ip4/0.0.0.0/tcp/0' +LISTEN_WS_ADDRESS='/ip4/0.0.0.0/tcp/0/ws' +LISTEN_QUIC_ADDRESS='/ip4/0.0.0.0/udp/0/quic-v1' IPFS_PUBLIC_URL='https://ipfs.io/ipfs/' -IPNS_PUBLIC_URL='https://ipfs.io/ipns/' \ No newline at end of file +IPNS_PUBLIC_URL='https://ipfs.io/ipns/' + +IPNS_CONSTITUTION_KEY_NAME='some-key-name' \ No newline at end of file diff --git a/worker-service/example.env b/worker-service/example.env index f734c4e6..f15d8584 100644 --- a/worker-service/example.env +++ b/worker-service/example.env @@ -1,20 +1,20 @@ # Backend Database BE_POSTGRES_DB=cc-portal -BE_POSTGRES_HOST=localhost +BE_POSTGRES_HOST=postgres BE_POSTGRES_PORT=5432 BE_POSTGRES_USERNAME=postgres BE_POSTGRES_PASSWORD=postgres # DB-SYNC Database -DB_SYNC_POSTGRES_DB=bloxico_sync +DB_SYNC_POSTGRES_DB=name_of_db_sync DB_SYNC_POSTGRES_SCHEMA=public -DB_SYNC_POSTGRES_HOST=134.209.252.118 +DB_SYNC_POSTGRES_HOST=host_of_db_sync DB_SYNC_POSTGRES_PORT=5432 -DB_SYNC_POSTGRES_USERNAME=BEdev24 -DB_SYNC_POSTGRES_PASSWORD=bedev.bloxico24 +DB_SYNC_POSTGRES_USERNAME=username +DB_SYNC_POSTGRES_PASSWORD=password # Redis -REDIS_HOST=localhost +REDIS_HOST=cache REDIS_PORT=6379 REDIS_PASSWORD=password From 1deaeb35aa8fdec7d4313763d18ad705e66a691b Mon Sep 17 00:00:00 2001 From: Ryan <44342099+Ryun1@users.noreply.github.com> Date: Mon, 26 Aug 2024 10:07:29 +0100 Subject: [PATCH 03/20] docs: add and refactor Intersect boilerplate docs (#292) --- .github/ISSUE_TEMPLATE/bug_report.md | 25 -------- .github/ISSUE_TEMPLATE/bug_report.yml | 68 +++++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 6 +- .github/ISSUE_TEMPLATE/feature_idea.yml | 67 +++++++++++++++------ .github/pull_request_template.md | 4 +- .github/workflows/label-feature-idea.yml | 61 +++++++++++++++++++ CHANGELOG.md | 4 +- CODE-OF-CONDUCT.md | 2 +- CODEOWNERS | 2 +- CONTRIBUTING.md | 75 +++++++----------------- SECURITY.md | 2 +- SUPPORT.md | 4 +- 12 files changed, 209 insertions(+), 111 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/workflows/label-feature-idea.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 1c9509c9..00000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -name: Bug report -about: You might have found a bug and decide to report it -title: '' -labels: 'bug :bug:' -assignees: '' ---- - -## Context & versions - - -## Steps to reproduce - - -## Actual behavior - - -## Expected behavior - \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000..f2dbf1ff --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,68 @@ +name: 🐛 Bug report +description: You found a bug! +title: '🐛 ' +labels: ["🐛 Bug"] +projects: [ ] +body: + - type: markdown + attributes: + value: | + ## 🌟 **Thank you for contributing to Constitutional Committee Portal!** + - type: markdown + attributes: + value: | + Before submitting a new issue please check the [existing issues](https://github.com/IntersectMBO/cc-portal/issues) to avoid duplication. + + - type: dropdown + id: domain + attributes: + label: Domain + description: Which CC Portal instance were you connected to? + options: + - constitution.gov.tools + - sancho.constitution.gov.tools + - other + validations: + required: true + + - type: textarea + id: context + attributes: + label: Context + description: Please give the context to what you were trying to achieve + placeholder: | + I was trying to see the latest CC member updates... + validations: + required: true + + - type: textarea + id: reproduce + attributes: + label: Steps to reproduce + description: Explain the steps to reproduce + placeholder: | + 1. Navigate to view constitution + 2. Scroll to appendix + 3. ... + validations: + required: true + + - type: textarea + id: actual-behavior + attributes: + label: Actual behavior + description: A description of the erroneous outcome + placeholder: | + A error came up on the screen stating... + validations: + required: true + + - type: textarea + id: expected-behavior + attributes: + label: Expected behavior + description: A description of what you expect to happen instead + placeholder: | + The constitution appendix is legible and accessible... + validations: + required: true \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 51874e6e..d4800fce 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,13 +1,13 @@ blank_issues_enabled: true contact_links: - name: Contributing guidelines - url: https://github.com/IntersectMBO/xxxx/blob/master/CONTRIBUTING.md + url: https://github.com/IntersectMBO/cc-portal/blob/master/CONTRIBUTING.md about: Some rules & processes we honor. - name: Feature ideas - url: https://github.com/IntersectMBO/xxxx/discussions/categories/ideas + url: https://github.com/IntersectMBO/cc-portal/discussions/categories/ideas about: Maybe someone else had the same or a similar idea already? - name: All issues - url: https://github.com/IntersectMBO/xxxx/issues + url: https://github.com/IntersectMBO/cc-portal/issues about: Check whether your issue is not already covered here. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_idea.yml b/.github/ISSUE_TEMPLATE/feature_idea.yml index c5542fa5..9fe8d7ae 100644 --- a/.github/ISSUE_TEMPLATE/feature_idea.yml +++ b/.github/ISSUE_TEMPLATE/feature_idea.yml @@ -1,44 +1,73 @@ -name: Feature idea -description: Idea or request for some feature on the xxxx roadmap -labels: [':thought_balloon: idea'] +name: 💡 Feature idea +description: Idea or request for some feature on the CC Portal roadmap +title: "💡 " +labels: ["💡 Feature idea"] +projects: [ ] body: - type: markdown attributes: - value: value: | - **Thank you for contributing to our project!** :green_heart: + ## 🌟 **Thank you for contributing to Constitutional Committee Portal!** + - type: markdown + attributes: + value: | + Before submitting a new issue consider [starting a new discussion](https://github.com/IntersectMBO/cc-portal/discussions/new?category=ideas). - Instead of opening this issue, consider [starting a new idea discussion](https://github.com/IntersectMBO/xxxx/discussions/new?category=ideas). - That way, we can discuss & refine your idea together, before we adopt it as a feature into the roadmap. + - type: dropdown + id: design-needed + attributes: + label: Is there new design needed? + description: Will this feature require new or edit to existing frontend designs? + options: + - 'Yes' + - 'No' + - Not sure + validations: + required: true - type: textarea - id: why + id: what attributes: - label: Why - description: Why do we need or want this feature + label: What? + description: What is this feature? placeholder: | - Give context and describe the problem, challenge or opportunity you see + For example describe a new API endpoint, a change in wording, + a new configuration option, ... validations: required: true - type: textarea - id: what + id: why attributes: - label: What - description: What is this feature roughly about + label: Why? + description: Why do we need or want this feature? placeholder: | - For example describe a new API endpoint, a change in messaging formats, - a new configuration option, ... + Give context and describe the problem the idea solves validations: required: true - type: textarea id: how attributes: - label: How - description: How could we realize this feature + label: How? + description: How can we realize this feature? placeholder: | Which technical solutions, libraries or systems should be used, which components need to change, steps how to implement this, ... validations: - required: true \ No newline at end of file + required: true + + - type: markdown + attributes: + value: | + --- + + - type: textarea + id: user-story + attributes: + label: (Optional) User Story with acceptance criteria + description: See examples [here](https://github.com/IntersectMBO/cardano-test-plans/blob/main/userStoryInventoryChangHF.md#2g-delegate-to-self-for-registered-dreps). + placeholder: | + As a [ada holder | DRep | Direct voter], I want [some goal] so that [some reason]. + validations: + required: false \ No newline at end of file diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 283f57ae..ce0073e2 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -4,8 +4,8 @@ ## Checklist -- [related issue](https://github.com/IntersectMBO/xxxx/issues/) +- [related issue](https://github.com/IntersectMBO/cc-portal/issues/) - [ ] My changes generate no new warnings -- [ ] My code follows the [style guidelines](https://github.com/IntersectMBO/xxxx/tree/main/docs/style-guides) of this project +- [ ] My code follows the [style guidelines](https://github.com/IntersectMBO/cc-portal/tree/main/docs/style-guides) of this project - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have added tests that prove my fix is effective or that my feature works diff --git a/.github/workflows/label-feature-idea.yml b/.github/workflows/label-feature-idea.yml new file mode 100644 index 00000000..a46751e5 --- /dev/null +++ b/.github/workflows/label-feature-idea.yml @@ -0,0 +1,61 @@ +name: Add labels to 💡 Feature idea issues + +on: + issues: + types: [opened, edited] + +permissions: + issues: write + contents: read + +jobs: + apply-labels: + runs-on: ubuntu-latest + steps: + - name: Check if issue is a "💡 Feature idea" + id: check_is_feature_idea + run: | + echo "## Checking if issue is a 'Feature idea'..." + if [[ "${{ github.event.issue.title }}" == "💡 "* ]]; then + echo "is_feature_idea=true" >> $GITHUB_ENV + else + echo "is_feature_idea=false" >> $GITHUB_ENV + fi + + - name: Apply "🎨 Design Needed" label if design needed is "Yes" + if: ${{ env.is_feature_idea == 'true' }} + uses: actions/github-script@v6 + with: + script: | + const issueBody = context.payload.issue.body; + + // Match the "Yes" selection under the "### Is there new design needed?" header + const designNeededMatch = issueBody.match(/### Is there new design needed\?\s*\n\s*Yes\s*\n/); + + if (designNeededMatch) { + await github.rest.issues.addLabels({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + labels: ["🎨 Design Needed"], + }); + } + + - name: Apply "User Story Needed" label if user story not provided + if: ${{ env.is_feature_idea == 'true' }} + uses: actions/github-script@v6 + with: + script: | + const issueBody = context.payload.issue.body; + + const userStoryPattern = /### \(Optional\) User Story with acceptance criteria\s*\n\s*_No response_/; + const userStoryMissing = userStoryPattern.test(issueBody); + + if (userStoryMissing) { + await github.rest.issues.addLabels({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + labels: ["User Story Needed"], + }); + } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index c02a8b13..cd4abd54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# xxxx Changelog +# Constitutional Committee Portal Changelog All notable changes to this project will be documented in this file. @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 As a minor extension, we also keep a semantic version for the `UNRELEASED` changes. -## [tag-xxxx](https://github.com/IntersectMBO/xxxx/releases/tag/xxxx) 2024-xx-xx +## [tag-xxxx](https://github.com/IntersectMBO/cc-portal/releases/tag/xxxx) 2024-xx-xx ### Added - diff --git a/CODE-OF-CONDUCT.md b/CODE-OF-CONDUCT.md index 279206db..7be7b84a 100644 --- a/CODE-OF-CONDUCT.md +++ b/CODE-OF-CONDUCT.md @@ -60,7 +60,7 @@ representative at an online or offline event. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at -[XXXX@intersectmbo.org](XXXX@intersectmbo.org). +[oso@intersectmbo.org](oso@intersectmbo.org). All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the diff --git a/CODEOWNERS b/CODEOWNERS index dee7e04c..1108c039 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,4 +1,4 @@ -# xxxx Project Codeowners +# Constitutional Committee Project Codeowners # These owners will be the default owners for everything in the repository. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 96ff3232..4534399f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,14 +1,21 @@ -# Contributing to the `xxxx` project +# Contributing to the `CC Portal` project -Thanks for considering contributing and helping us on creating xxxx! 😎 +⚠️ This is a work in progress document, more instruction on how-to contribute to come! + +Contributing todo: + +- [ ] Refactor to reflect reality +- [ ] Make more friendly to open source contributors + +Thanks for considering contributing and helping us on creating CC Portal! 😎 The best way to contribute right now is to try things out and provide feedback, but we also accept contributions to the documentation and the obviously to the code itself. -This document contains guidelines to help you get started and how to make sure your contribution gets accepted, making you our newest xxxx contributor! +This document contains guidelines to help you get started and how to make sure your contribution gets accepted, making you our newest CC Portal contributor! ## Table of Contents -- [Contributing to the `xxxx` project](#contributing-to-the-xxxx-project) +- [Contributing to the `CC Portal` project](#contributing-to-the-cc-portal-project) - [Table of Contents](#table-of-contents) - [Code of Conduct](#code-of-conduct) - [Ask for Help](#ask-for-help) @@ -30,12 +37,6 @@ This document contains guidelines to help you get started and how to make sure y - [React](#react) - [CSS in Javascript](#css-in-javascript) - [CSS / SASS](#css--sass) - - [Haskell](#haskell) - - [Development Processes](#development-processes) - - [Developer workflow](#developer-workflow) - - [QA Workflow](#qa-workflow) - - [PO Workflow](#po-workflow) - - [Tech Lead Workflow](#tech-lead-workflow) ## Code of Conduct @@ -77,11 +78,11 @@ Please complete the following steps in advance to help us fix any potential bug We use GitHub issues to track bugs and errors. If you run into an issue with the project: -- Open an [Issue](https://github.com/IntersectMBO/xxxx/issues/new). +- Open an [Issue](https://github.com/IntersectMBO/cc-portal/issues/new). (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.) - Explain the behavior you would expect and the actual behavior. - Please provide as much context as possible. - Describe the *reproduction steps* that someone else can follow to recreate the issue on their own. + Describe the _reproduction steps_ that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case. - Provide the information you collected in the previous section. @@ -108,6 +109,7 @@ TODO Thank you for contributing your changes by opening a pull requests! To get something merged we usually require: + - Follow the Pull Request template - Description of the changes - if your commit messages are great, this is less important - Quality of changes is ensured - through new or updated automated tests @@ -124,6 +126,7 @@ Please reuse the branch naming for the pull request naming. - Using the related issue number after the prefix is required. Examples: + - `feat/123-added-ability-for-dreps-to-change-drep-id` - `fix/312-fixed-drep-ids-being-reversed` - `chore/567-bumped-cardano-node-version-to-9` @@ -131,7 +134,7 @@ Examples: ### Commit Messages -Please make informative commit messages! +Please make informative commit messages! It makes it much easier to work out why things are the way they are when you’re debugging things later. A commit message is communication, so as usual, put yourself in the position of the reader: what does a reviewer, or someone reading the commit message later need to do their job? @@ -142,6 +145,7 @@ Also, include any relevant meta-information, such as issue numbers. If a commit completely addresses a issue, you can put that in the headline if you want, but it’s fine to just put it in the body. Here are seven rules for great git commit messages: + 1. Separate subject from body with a blank line 2. Limit the subject line to 50 characters (soft limit) 3. Capitalize the subject line @@ -165,6 +169,7 @@ Try to keep branches up-to-date with main (not strict requirement though). Once merged to main, please delete the branch. **Tip:** Use Github's merge button in PRs to merge with commit. +This strategy helps us operate on the commits you've delivered: it's easier to [cherry-pick a merge commit](https://git-scm.com/docs/git-cherry-pick#Documentation/git-cherry-pick.txt--mltparent-numbergt) than a series of commits, and it's also easier to [revert changes using a merge commit](https://git-scm.com/docs/git-revert#Documentation/git-revert.txt--mparent-number) instead of a series of reverts. If a branch is outdated, use the rebase button in PRs to rebase feature branches (NOT update via merge). #### Rationale @@ -172,7 +177,7 @@ If a branch is outdated, use the rebase button in PRs to rebase feature branches Keeping branches ahead of main not only make the git history a lot nicer to process, it also makes conflict resolutions easier. Merging main into a branch repeatedly is a good recipe to introduce invalid conflict resolutions and loose track of the actual changes brought by a the branch. -### Versioning +### Versioning Not all releases are declared stable. Releases that aren't stable will be released as pre-releases and will append a -pre tag indicating it is not ready for running on production networks. @@ -180,6 +185,7 @@ Releases that aren't stable will be released as pre-releases and will append a - ### Changelog During development, on every PR; + - Make sure `CHANGELOG.md` is kept up-to-date with high-level, technical, but user-focused list of changes according to [keepachangelog](https://keepachangelog.com/en/1.0.0/). - Bump `UNRELEASED` version in `CHANGELOG.md` according to [semver](https://semver.org/). @@ -196,44 +202,3 @@ Please see [CSS in Javascript Style Guide](./docs/style-guides/css-in-js/). #### CSS / SASS Please see [CSS / SASS Style Guide](./docs/style-guides/css-sass/). - -#### Haskell - -TODO - -## Development Processes - -### Developer workflow - - - -- Choose ticket/issue to work on from the project, move ticket from `todo` to `in progress`. -- Create [well named](#branch-naming) branch from `develop` add changes, then make a pull request back to the `develop` branch. -- If the changes are not ready for review then feel free to create a draft PR, and link this to the ticket/issue. -- Developers should review each other's pull requests, and should be requested via [CODEOWNERS](./CODEOWNERS). -- Unit tests are run on each pull request to `develop`. -- Once tests pass and peer review is done the branch can be merged into `develop` by author and then deployed to the dev environment (manually for now). -- The ticket status can then be moved ticket to `in QA` making sure that the PR/branch has been added to the ticket/issue as a comment. - -### QA Workflow - -- Choose ticket from `in QA`. -- Merge in the ticket's changes from `develop` branch into `test` branch. -- Deploy to test environment (manually for now). -- The QA tests the deployed test environment against the ticket. -- If QA agrees that the code is good, they can make a PR from `test` branch to `staging` branch where end-to-end and performance tests are run. -- If tests pass, then QA or tech lead can merge and deploy to staging environment (manually for now). -- Moving ticket to `staging` status this ready for PO check. - -### PO Workflow - -- Choose ticket from `staging` status. -- Compare the deployment on staging environment to the contents of the ticket. -- If the deployment has been satisfied via the staging environment, PO comments on the ticket to be included in next release. - -### Tech Lead Workflow - -- Bundle the staging status tickets together into a new tag. -- Merge `staging` branch into the `main` branch. -- Deploy tagged build to `beta` environment. -- Move tickets from staging status to done status. diff --git a/SECURITY.md b/SECURITY.md index d7856a7f..2e7800b1 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,7 +2,7 @@ ## Reporting a Vulnerability -Please report (suspected) security vulnerabilities to [XXXX@intersectmbo.org](XXXX@intersectmbo.org). +Please report (suspected) security vulnerabilities to [security@intersectmbo.org](security@intersectmbo.org). You will receive a response from us within 48 hours. If the issue is confirmed, we will release a patch as soon as possible. diff --git a/SUPPORT.md b/SUPPORT.md index 2722f187..ad9d7e34 100644 --- a/SUPPORT.md +++ b/SUPPORT.md @@ -1,8 +1,8 @@ # Ask for help -Should you have any questions or need some help in getting set up, you can use these communication channels to reach the xxxx team and get answers in a way where others can benefit from it as well: +Should you have any questions or need some help in getting set up, you can use these communication channels to reach the CC portal team and get answers in a way where others can benefit from it as well: -- Github [Discussions](https://github.com/IntersectMBO/xxxx) +- Github [Discussions](https://github.com/IntersectMBO/cc-portal/discussions) # Reporting a Vulnerability From 3fd77dac01b970ca6e595b1b04b9aff40178244b Mon Sep 17 00:00:00 2001 From: Ryan <44342099+Ryun1@users.noreply.github.com> Date: Mon, 26 Aug 2024 12:07:07 +0100 Subject: [PATCH 04/20] docs: add license file and tweak base readme (#306) --- LICENSE | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 47 +++++++++---- 2 files changed, 236 insertions(+), 12 deletions(-) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..b9e73469 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright © 2018-2021 IOHK + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 5c1dba1c..b841034c 100644 --- a/README.md +++ b/README.md @@ -2,22 +2,43 @@ Welcome to the official repository for the Constitution Committee Portal. +## Navigation + +- [Constitution Committee Portal](#constitution-committee-portal) + - [Navigation](#navigation) + - [Introduction](#introduction) + - [Instances](#instances) + - [Mainnet (beta)](#mainnet-beta) + - [SanchoNet](#sanchonet) + - [Prerequisites](#prerequisites) + - [Tech stack:](#tech-stack) + - [Frontend](#frontend) + - [Backend](#backend) + - [Database](#database) + - [Caching service](#caching-service) + - [Worker service](#worker-service) + - [IPFS/IPNS Helia node](#ipfsipns-helia-node) + - [Getting started](#getting-started) + - [Usage](#usage) + - [Environment Variables](#environment-variables) + - [API Documentation](#api-documentation) + - [License](#license) + +## Introduction + The primary purpose of the solution is to host the Cardano Constitution and allow anyone to get familiar with it and follow its evolution over time. It also serves as the single point of truth for the Cardano Community members to see how Constitutional Committee members voted on a specific Governance Action, with the inclusion of their rationale. For members of the Constitutional Committee, it serves as a portal to add reasoning to their votes and prepare it as an off-chain resource to be attached to on-chain governance actions. -## Table of content: +This document serves as a comprehensive guide for setting up the full stack of our application, which includes the Frontend, Backend, Database, Caching, Worker and IPFS components. -- [Introduction](#introduction) -- [Prerequisites](#prerequisites) -- [Tech stack](#tech-stack) -- [Getting started](#getting-started) -- [Usage](#usage) -- [Environment Variables](#environment-variables) -- [API Documentation](#api-documentation) -- [License](#license) +## Instances -## Introduction +### Mainnet (beta) -This document serves as a comprehensive guide for setting up the full stack of our application, which includes the Frontend, Backend, Database, Caching, Worker and IPFS components. +- [constitution.gov.tools](https://constitution.gov.tools/) + +### SanchoNet + +- [sancho.constitution.gov.tools](https://sancho.constitution.gov.tools/) ## Prerequisites @@ -222,4 +243,6 @@ Access the API documentation at: [http://localhost:1337/api-docs](http://localho ## License -This project is licensed under the MIT License. \ No newline at end of file +This project is licensed under the Apache 2.0. + +See [License file](./LICENSE). \ No newline at end of file From a4406fdae27c0a77e1ae496cf60cb93b72e9dc77 Mon Sep 17 00:00:00 2001 From: Baja-KS Date: Tue, 27 Aug 2024 11:57:53 +0200 Subject: [PATCH 05/20] ci --- .github/workflows/merge.yaml | 32 +++++++++++++++++++------------- .github/workflows/pr.yaml | 18 ++++++++++++------ 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/.github/workflows/merge.yaml b/.github/workflows/merge.yaml index 4c5025cf..cff7f473 100644 --- a/.github/workflows/merge.yaml +++ b/.github/workflows/merge.yaml @@ -14,7 +14,7 @@ permissions: packages: write env: - ENVIRONMENT: ${{ (github.ref_name == 'main' && 'prod-cc-portal') || (github.ref_name == 'staging' && 'pre-prod-cc-portal') || (github.ref_name == 'staging' && 'qa-cc-portal') || (github.ref_name == 'develop' && 'dev-cc-portal') }} + ENVIRONMENT: ${{ (github.ref_name == 'master' && 'prod-cc-portal') || (github.ref_name == 'beta' && 'pre-prod-cc-portal') || (github.ref_name == 'staging' && 'qa-cc-portal') || (github.ref_name == 'develop' && 'dev-cc-portal') }} jobs: check-build-deploy: @@ -124,38 +124,44 @@ jobs: context: ${{ matrix.workdir }} file: ${{ matrix.dockerfile }} tags: ${{ steps.image_lowercase.outputs.lowercase }}:${{ env.TAG }} - load: true + load: false cache-from: type=local,src=/tmp/.buildx-cache cache-to: type=local,dest=/tmp/.buildx-cache + outputs: type=docker,dest=/tmp/image-${{ matrix.name }}-${{ env.ENVIRONMENT }}.tar build-args: | NEXT_PUBLIC_API_URL=${{ secrets.PROD_NEXT_PUBLIC_API_URL }} NEXT_PUBLIC_USERSNAP_GLOBAL_API_KEY=${{ secrets.PROD_NEXT_PUBLIC_USERSNAP_GLOBAL_API_KEY }} - NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY={{ secrets.PROD_NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY }} - - - name: Login to GHCR - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY=${{ secrets.PROD_NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY }} - name: Scan Docker image with Dockle id: dockle run: | - wget https://github.com/goodwithtech/dockle/releases/download/v0.4.14/dockle_0.4.14_Linux-64bit.tar.gz - tar zxvf dockle_0.4.14_Linux-64bit.tar.gz + wget -q https://github.com/goodwithtech/dockle/releases/download/v0.4.14/dockle_0.4.14_Linux-64bit.tar.gz + tar zxf dockle_0.4.14_Linux-64bit.tar.gz sudo mv dockle /usr/local/bin - dockle --exit-level fatal --format json --output ${{ matrix.workdir }}/dockle_scan_output.json ${{ steps.image_lowercase.outputs.lowercase }}:${{ env.TAG }} + dockle --exit-code 1 --exit-level fatal --format json --input '/tmp/image-${{ matrix.name }}-${{ env.ENVIRONMENT }}.tar' --output ${{ matrix.workdir }}/dockle_scan_output.json echo " dockle exited w/ $?" cat ${{ matrix.workdir }}/dockle_scan_output.json echo "outcome=success" >> $GITHUB_OUTPUT + + - name: Login to GHCR + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Push Docker image to GHCR run: | + docker load -i '/tmp/image-${{ matrix.name }}-${{ env.ENVIRONMENT }}.tar' + rm -rf '/tmp/image-${{ matrix.name }}-${{ env.ENVIRONMENT }}.tar' docker push ${{ steps.image_lowercase.outputs.lowercase }}:${{ env.TAG }} + - name: Deploy with Qovery if: github.ref == 'refs/heads/develop' env: diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 15eeb42e..2e8dc10c 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -5,7 +5,8 @@ on: branches: - develop - staging - - main + - beta + - master permissions: contents: read @@ -111,19 +112,24 @@ jobs: context: ${{ matrix.workdir }} file: ${{ matrix.dockerfile }} tags: ${{ steps.image_lowercase.outputs.lowercase }}:${{ github.sha }} - load: true + load: false cache-from: type=local,src=/tmp/.buildx-cache cache-to: type=local,dest=/tmp/.buildx-cache + outputs: type=docker,dest=/tmp/image-${{ matrix.name }}-${{ github.sha }}-pr.tar + build-args: | + NEXT_PUBLIC_API_URL=${{ secrets.PROD_NEXT_PUBLIC_API_URL }} + NEXT_PUBLIC_USERSNAP_GLOBAL_API_KEY=${{ secrets.PROD_NEXT_PUBLIC_USERSNAP_GLOBAL_API_KEY }} + NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY=${{ secrets.PROD_NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY }} - name: Scan Docker image with Dockle id: dockle run: | - wget https://github.com/goodwithtech/dockle/releases/download/v0.4.14/dockle_0.4.14_Linux-64bit.tar.gz - tar zxvf dockle_0.4.14_Linux-64bit.tar.gz + wget -q https://github.com/goodwithtech/dockle/releases/download/v0.4.14/dockle_0.4.14_Linux-64bit.tar.gz + tar zxf dockle_0.4.14_Linux-64bit.tar.gz sudo mv dockle /usr/local/bin - dockle --exit-level fatal --format json --output ${{ matrix.workdir }}/dockle_scan_output.json ${{ steps.image_lowercase.outputs.lowercase }}:${{ github.sha }} - echo " dockle exited w/ $?" + dockle --exit-code 1 --exit-level fatal --format json --input '/tmp/image-${{ matrix.name }}-${{ github.sha }}-pr.tar' --output ${{ matrix.workdir }}/dockle_scan_output.json + rm -rf '/tmp/image-${{ matrix.name }}-${{ github.sha }}-pr.tar' cat ${{ matrix.workdir }}/dockle_scan_output.json echo "outcome=success" >> $GITHUB_OUTPUT From 4eedec1319e0d50336c0cf58770b96076ae3c320 Mon Sep 17 00:00:00 2001 From: Milos <161627443+BEdev24@users.noreply.github.com> Date: Thu, 29 Aug 2024 16:06:12 +0200 Subject: [PATCH 06/20] feat: staging to master (#320) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feature: Latest revisions-add IPFS url link * feature: Display tooltip if text is too long to be fully displayed * add pipelines * modify pipelines * modify pipelines to include env vars for frontend * staging change * staging fix * staging fix * Update de.json (POEditor.com) * Update de.json (POEditor.com) * fix: ipfs volume change * fix: ipfs volume change * Revert "Revert "feat: modify-constitution-response-fields - added new fields …" (#257) This reverts commit 458c02f1a191233a32d576de968d9680d25792d0. * fix/redis-connection: added password to bullmq connect to redis (#274) * fix/redis-bullmq-pass: added password for redis connection (#275) * feat: ipns url (#272) * feature/ipns-url: Returns IPNS url for uloaded constitution * feature/ipns-url: minor cahnges * feature/ipns-url: changed env variable * feature/ipns-url: disabled open api for uploading the constitution file * feature: Add ipfs link on Constitution versions * fix: Remove unused import and translations * fix: Remove unused import and translations * fix: Equal latest revisions flex item with * fix: Latest revisions align utems * fix: Remove duplicate type definition * fix: User Profile button overlaps background behind * fix: Close Constitution sidebar initially for mobile * fix/worker-service: check if dbData exists (#278) * fix: worker service (#279) * fix/worker-service: check if dbData exists * fix/worker-service: check if dbData exists * fix: worker service (#280) * fix/worker-service: check if dbData exists * fix/worker-service: check if dbData exists * fix/worker-service: minor changes * fix: worker service (#281) * fix/worker-service: check if dbData exists * fix/worker-service: check if dbData exists * fix/worker-service: minor changes * fix/worker: try catch get votes * fix/worker: removed console log (#282) * Merge develop (#283) * feature: Latest revisions-add IPFS url link * feature: Display tooltip if text is too long to be fully displayed * Update de.json (POEditor.com) * Update de.json (POEditor.com) * fix: ipfs volume change * Revert "Revert "feat: modify-constitution-response-fields - added new fields …" (#257) This reverts commit 458c02f1a191233a32d576de968d9680d25792d0. * fix/redis-connection: added password to bullmq connect to redis (#274) * feat: ipns url (#272) * feature/ipns-url: Returns IPNS url for uloaded constitution * feature/ipns-url: minor cahnges * feature/ipns-url: changed env variable * feature/ipns-url: disabled open api for uploading the constitution file * feature: Add ipfs link on Constitution versions * fix: Remove unused import and translations * fix: Remove unused import and translations * fix: Equal latest revisions flex item with * fix: Latest revisions align utems * fix: Remove duplicate type definition * fix: User Profile button overlaps background behind * fix: Close Constitution sidebar initially for mobile * fix/worker-service: check if dbData exists (#278) * fix: worker service (#279) * fix/worker-service: check if dbData exists * fix/worker-service: check if dbData exists * fix: worker service (#280) * fix/worker-service: check if dbData exists * fix/worker-service: check if dbData exists * fix/worker-service: minor changes * fix: worker service (#281) * fix/worker-service: check if dbData exists * fix/worker-service: check if dbData exists * fix/worker-service: minor changes * fix/worker: try catch get votes * fix/worker: removed console log (#282) --------- Co-authored-by: Kristina Co-authored-by: Programmerassist Co-authored-by: nike-getto Co-authored-by: Kristina <42462482+Kristina2103@users.noreply.github.com> * fix: Dissplay onnchain rationale on latest updates page * Merge 'develop' into staging (#285) * feature: Latest revisions-add IPFS url link * feature: Display tooltip if text is too long to be fully displayed * Update de.json (POEditor.com) * Update de.json (POEditor.com) * fix: ipfs volume change * Revert "Revert "feat: modify-constitution-response-fields - added new fields …" (#257) This reverts commit 458c02f1a191233a32d576de968d9680d25792d0. * fix/redis-connection: added password to bullmq connect to redis (#274) * feat: ipns url (#272) * feature/ipns-url: Returns IPNS url for uloaded constitution * feature/ipns-url: minor cahnges * feature/ipns-url: changed env variable * feature/ipns-url: disabled open api for uploading the constitution file * feature: Add ipfs link on Constitution versions * fix: Remove unused import and translations * fix: Remove unused import and translations * fix: Equal latest revisions flex item with * fix: Latest revisions align utems * fix: Remove duplicate type definition * fix: User Profile button overlaps background behind * fix: Close Constitution sidebar initially for mobile * fix/worker-service: check if dbData exists (#278) * fix: worker service (#279) * fix/worker-service: check if dbData exists * fix/worker-service: check if dbData exists * fix: worker service (#280) * fix/worker-service: check if dbData exists * fix/worker-service: check if dbData exists * fix/worker-service: minor changes * fix: worker service (#281) * fix/worker-service: check if dbData exists * fix/worker-service: check if dbData exists * fix/worker-service: minor changes * fix/worker: try catch get votes * fix/worker: removed console log (#282) * fix: Dissplay onnchain rationale on latest updates page --------- Co-authored-by: Kristina Co-authored-by: Programmerassist Co-authored-by: nike-getto Co-authored-by: Kristina <42462482+Kristina2103@users.noreply.github.com> * Update merge.yaml * Update merge.yaml * Update merge.yaml * refactor: email module (#289) * refactor/email-module: refactoring the email module to work with AWS * refactor/email-module: changed example.env file * feat: readme (#290) * feature/readme: added readme and some changes in example.env files * feature/readme: minor changes * feature/readme: correction in docker-compose file * feature/readme: added psql ports in docker-compose * feature/readme: changes in example.env files * feature/readme: minor changes * feature/readme: minor changes * feature/readme: minor changes * fix: fixing develop instance * Fix/beta responsive adjustments (#293) * feat: Add close button prop for modal * feat: Decrease Constitution mobile font size * feat: Remove Constitution card box view for mobile * feat: Constitution page sidebar refactoring * feat: Add isActive label on Constitution revision card * feat: Custom TOCLink component and handler * feat: Remove logo from mobile menu drawer * feat: Rename Memebers page title * fix: Responsive Hero section * fix: Responsive Footer adjustments * fix: Decrese modal image for mobile * feat: ipfs node ver change * fix/increase-max-event-listenrs: incresed to 50 (#307) * update ci * [no ci] add beta branch to pr checks * declutter dockle output --------- Co-authored-by: Kristina Co-authored-by: mpavlovicbb Co-authored-by: mpavlovicbb <58938959+mpavlovicbb@users.noreply.github.com> Co-authored-by: nike-getto Co-authored-by: Programmerassist Co-authored-by: Kristina <42462482+Kristina2103@users.noreply.github.com> Co-authored-by: Baja-KS --- .github/workflows/merge.yaml | 1 - .github/workflows/pr.yaml | 2 +- backend/package-lock.json | 3003 +++++++++++++++-- backend/package.json | 8 +- .../CC Portal develop.postman_collection.json | 30 +- .../src/common/constants/ipfs.constants.ts | 1 + .../api/constitution.controller.ts | 20 + .../response/constitutio-ipns-url.response.ts | 12 + .../constitution-metadata.response.ts | 15 + .../api/response/constitution.response.ts | 15 + .../facade/constitution.facade.ts | 6 + .../mapper/constitution.mapper.ts | 12 + backend/src/email/email.module.ts | 19 +- backend/src/ipfs/services/ipfs.service.ts | 15 + frontend/Dockerfile | 2 +- frontend/messages/de.json | 16 +- frontend/messages/en.json | 4 +- frontend/public/icons/Close.svg | 6 +- frontend/public/icons/ExternalLink.svg | 4 + frontend/src/components/atoms/Typography.tsx | 21 +- .../components/atoms/modal/ModalWrapper.tsx | 32 +- .../molecules/ConditionalWrapper.tsx | 15 + .../molecules/UserCard/UserBasicInfo.tsx | 24 +- .../molecules/UserProfileButton.tsx | 2 +- frontend/src/components/molecules/index.ts | 1 + .../organisms/Constitution/Constitution.tsx | 181 +- .../Constitution/ConstitutionSidebar.tsx | 124 + .../organisms/Constitution/MDXComponents.tsx | 149 +- .../organisms/Constitution/TOCLink.tsx | 71 + .../components/organisms/Footer/Footer.tsx | 6 +- .../src/components/organisms/Hero/Hero.tsx | 1 + .../components/organisms/LatestUpdates.tsx | 2 + .../Modals/CompareConstitutionModal.tsx | 1 + .../organisms/Modals/GovActionModal.tsx | 4 +- .../Modals/PreviewReasoningModal.tsx | 22 +- .../organisms/TopNavigation/DrawerMobile.tsx | 25 +- frontend/src/components/organisms/types.ts | 9 +- frontend/src/constants/icons.ts | 1 + frontend/src/lib/requests/types.ts | 6 +- ipfs-service/Dockerfile | 4 +- ipfs-service/src/app.controller.ts | 5 + ipfs-service/src/app.service.ts | 10 +- ipfs-service/src/main.ts | 4 + worker-service/src/bullmq/bullmq.module.ts | 1 + .../src/governance/services/vote.service.ts | 27 +- 45 files changed, 3484 insertions(+), 455 deletions(-) create mode 100644 backend/src/common/constants/ipfs.constants.ts create mode 100644 backend/src/constitution/api/response/constitutio-ipns-url.response.ts create mode 100644 frontend/public/icons/ExternalLink.svg create mode 100644 frontend/src/components/molecules/ConditionalWrapper.tsx create mode 100644 frontend/src/components/organisms/Constitution/ConstitutionSidebar.tsx create mode 100644 frontend/src/components/organisms/Constitution/TOCLink.tsx diff --git a/.github/workflows/merge.yaml b/.github/workflows/merge.yaml index cff7f473..d0c83e60 100644 --- a/.github/workflows/merge.yaml +++ b/.github/workflows/merge.yaml @@ -141,7 +141,6 @@ jobs: sudo mv dockle /usr/local/bin dockle --exit-code 1 --exit-level fatal --format json --input '/tmp/image-${{ matrix.name }}-${{ env.ENVIRONMENT }}.tar' --output ${{ matrix.workdir }}/dockle_scan_output.json - echo " dockle exited w/ $?" cat ${{ matrix.workdir }}/dockle_scan_output.json echo "outcome=success" >> $GITHUB_OUTPUT diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 2e8dc10c..8ce17a97 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -119,7 +119,7 @@ jobs: build-args: | NEXT_PUBLIC_API_URL=${{ secrets.PROD_NEXT_PUBLIC_API_URL }} NEXT_PUBLIC_USERSNAP_GLOBAL_API_KEY=${{ secrets.PROD_NEXT_PUBLIC_USERSNAP_GLOBAL_API_KEY }} - NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY=${{ secrets.PROD_NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY }} + NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY=${{ secrets.PROD_NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY }}r - name: Scan Docker image with Dockle id: dockle diff --git a/backend/package-lock.json b/backend/package-lock.json index 28c9a920..e3d8a7da 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -10,8 +10,9 @@ "license": "UNLICENSED", "dependencies": { "@aws-sdk/client-s3": "^3.552.0", + "@aws-sdk/client-ses": "^3.621.0", "@helia/unixfs": "^3.0.2", - "@nestjs-modules/mailer": "^1.11.2", + "@nestjs-modules/mailer": "^2.0.2", "@nestjs/class-transformer": "^0.4.0", "@nestjs/common": "^10.0.0", "@nestjs/config": "^3.2.0", @@ -29,7 +30,6 @@ "@types/morgan": "^1.9.7", "@types/multer": "^1.4.11", "axios": "^1.6.8", - "blake2": "^5.0.0", "blake2b": "^2.1.4", "blakejs": "^1.2.1", "blockstore-s3": "^1.0.15", @@ -51,7 +51,7 @@ "multiformats": "^13.1.0", "nest-winston": "^1.9.4", "nestjs-paginate": "^8.6.2", - "nodemailer": "^6.9.13", + "nodemailer": "^6.9.14", "passport": "^0.7.0", "passport-jwt": "^4.0.1", "passport-magic-login": "^1.2.2", @@ -509,6 +509,1155 @@ "node": ">=14.0.0" } }, + "node_modules/@aws-sdk/client-ses": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-ses/-/client-ses-3.621.0.tgz", + "integrity": "sha512-dzqIiT12wd5NCDhwofQizV2rr8Ihsxn/13dvIwha+egAXiVo09dM6zVBW1atdHYS0vP/D5i/UB76+xk6JhCasw==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.1", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "@smithy/util-waiter": "^3.1.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "dependencies": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/client-sso": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", + "integrity": "sha512-xpKfikN4u0BaUYZA9FGUMkkDmfoIP0Q03+A86WjqDWhcOoqNA1DkHsE4kZ+r064ifkPUfcNuUvlkVTEoBZoFjA==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.1", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/client-sso-oidc": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.621.0.tgz", + "integrity": "sha512-mMjk3mFUwV2Y68POf1BQMTF+F6qxt5tPu6daEUCNGC9Cenk3h2YXQQoS4/eSyYzuBiYk3vx49VgleRvdvkg8rg==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.1", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.621.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/client-sts": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.621.0.tgz", + "integrity": "sha512-707uiuReSt+nAx6d0c21xLjLm2lxeKc7padxjv92CIrIocnQSlJPxSCM7r5zBhwiahJA6MNQwmTl2xznU67KgA==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.1", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/core": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.621.0.tgz", + "integrity": "sha512-CtOwWmDdEiINkGXD93iGfXjN0WmCp9l45cDWHHGa8lRgEDyhuL7bwd/pH5aSzj0j8SiQBG2k0S7DHbd5RaqvbQ==", + "dependencies": { + "@smithy/core": "^2.3.1", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/signature-v4": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.620.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.620.1.tgz", + "integrity": "sha512-ExuILJ2qLW5ZO+rgkNRj0xiAipKT16Rk77buvPP8csR7kkCflT/gXTyzRe/uzIiETTxM7tr8xuO9MP/DQXqkfg==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.621.0.tgz", + "integrity": "sha512-/jc2tEsdkT1QQAI5Dvoci50DbSxtJrevemwFsm0B73pwCcOQZ5ZwwSdVqGsPutzYzUVx3bcXg3LRL7jLACqRIg==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/util-stream": "^3.1.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.621.0.tgz", + "integrity": "sha512-0EWVnSc+JQn5HLnF5Xv405M8n4zfdx9gyGdpnCmAmFqEDHA8LmBdxJdpUk1Ovp/I5oPANhjojxabIW5f1uU0RA==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.620.1", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-process": "3.620.1", + "@aws-sdk/credential-provider-sso": "3.621.0", + "@aws-sdk/credential-provider-web-identity": "3.621.0", + "@aws-sdk/types": "3.609.0", + "@smithy/credential-provider-imds": "^3.2.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.621.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.621.0.tgz", + "integrity": "sha512-4JqpccUgz5Snanpt2+53hbOBbJQrSFq7E1sAAbgY6BKVQUsW5qyXqnjvSF32kDeKa5JpBl3bBWLZl04IadcPHw==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.620.1", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-ini": "3.621.0", + "@aws-sdk/credential-provider-process": "3.620.1", + "@aws-sdk/credential-provider-sso": "3.621.0", + "@aws-sdk/credential-provider-web-identity": "3.621.0", + "@aws-sdk/types": "3.609.0", + "@smithy/credential-provider-imds": "^3.2.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.620.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.620.1.tgz", + "integrity": "sha512-hWqFMidqLAkaV9G460+1at6qa9vySbjQKKc04p59OT7lZ5cO5VH5S4aI05e+m4j364MBROjjk2ugNvfNf/8ILg==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.621.0.tgz", + "integrity": "sha512-Kza0jcFeA/GEL6xJlzR2KFf1PfZKMFnxfGzJzl5yN7EjoGdMijl34KaRyVnfRjnCWcsUpBWKNIDk9WZVMY9yiw==", + "dependencies": { + "@aws-sdk/client-sso": "3.621.0", + "@aws-sdk/token-providers": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.621.0.tgz", + "integrity": "sha512-w7ASSyfNvcx7+bYGep3VBgC3K6vEdLmlpjT7nSIHxxQf+WSdvy+HynwJosrpZax0sK5q0D1Jpn/5q+r5lwwW6w==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.621.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.620.0.tgz", + "integrity": "sha512-VMtPEZwqYrII/oUkffYsNWY9PZ9xpNJpMgmyU0rlDQ25O1c0Hk3fJmZRe6pEkAJ0omD7kLrqGl1DUjQVxpd/Rg==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/middleware-logger": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.609.0.tgz", + "integrity": "sha512-S62U2dy4jMDhDFDK5gZ4VxFdWzCtLzwbYyFZx2uvPYTECkepLUfzLic2BHg2Qvtu4QjX+oGE3P/7fwaGIsGNuQ==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.620.0.tgz", + "integrity": "sha512-nh91S7aGK3e/o1ck64sA/CyoFw+gAYj2BDOnoNa6ouyCrVJED96ZXWbhye/fz9SgmNUZR2g7GdVpiLpMKZoI5w==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.620.0.tgz", + "integrity": "sha512-bvS6etn+KsuL32ubY5D3xNof1qkenpbJXf/ugGXbg0n98DvDFQ/F+SMLxHgbnER5dsKYchNnhmtI6/FC3HFu/A==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.614.0.tgz", + "integrity": "sha512-vDCeMXvic/LU0KFIUjpC3RiSTIkkvESsEfbVHiHH0YINfl8HnEqR5rj+L8+phsCeVg2+LmYwYxd5NRz4PHxt5g==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/token-providers": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.614.0.tgz", + "integrity": "sha512-okItqyY6L9IHdxqs+Z116y5/nda7rHxLvROxtAJdLavWTYDydxrZstImNgGWTeVdmc0xX2gJCI77UYUTQWnhRw==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sso-oidc": "^3.614.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/types": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", + "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/util-endpoints": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.614.0.tgz", + "integrity": "sha512-wK2cdrXHH4oz4IomV/yrGkftU9A+ITB6nFL+rxxyO78is2ifHJpFdV4aqk4LSkXYPi6CXWNru/Dqc7yiKXgJPw==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "@smithy/util-endpoints": "^2.0.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.609.0.tgz", + "integrity": "sha512-fojPU+mNahzQ0YHYBsx0ZIhmMA96H+ZIZ665ObU9tl+SGdbLneVZVikGve+NmHTQwHzwkFsZYYnVKAkreJLAtA==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.614.0.tgz", + "integrity": "sha512-15ElZT88peoHnq5TEoEtZwoXTXRxNrk60TZNdpl/TUBJ5oNJ9Dqb5Z4ryb8ofN6nm9aFf59GVAerFDz8iUoHBA==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", + "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/config-resolver": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.5.tgz", + "integrity": "sha512-SkW5LxfkSI1bUC74OtfBbdz+grQXYiPYolyu8VfpLIjEoN/sHVBlLeGXMQ1vX4ejkgfv6sxVbQJ32yF2cl1veA==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/core": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.1.tgz", + "integrity": "sha512-BC7VMXx/1BCmRPCVzzn4HGWAtsrb7/0758EtwOGFJQrlSwJBEjCcDLNZLFoL/68JexYa2s+KmgL/UfmXdG6v1w==", + "dependencies": { + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/credential-provider-imds": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.0.tgz", + "integrity": "sha512-0SCIzgd8LYZ9EJxUjLXBmEKSZR/P/w6l7Rz/pab9culE/RWuqelAKGJvn5qUOl8BgX8Yj5HWM50A5hiB/RzsgA==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/fetch-http-handler": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.4.tgz", + "integrity": "sha512-kBprh5Gs5h7ug4nBWZi1FZthdqSM+T7zMmsZxx0IBvWUn7dK3diz2SHn7Bs4dQGFDk8plDv375gzenDoNwrXjg==", + "dependencies": { + "@smithy/protocol-http": "^4.1.0", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "@smithy/util-base64": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/hash-node": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.3.tgz", + "integrity": "sha512-2ctBXpPMG+B3BtWSGNnKELJ7SH9e4TNefJS0cd2eSkOOROeBnnVBnAy9LtJ8tY4vUEoe55N4CNPxzbWvR39iBw==", + "dependencies": { + "@smithy/types": "^3.3.0", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/hash-node/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/invalid-dependency": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.3.tgz", + "integrity": "sha512-ID1eL/zpDULmHJbflb864k72/SNOZCADRc9i7Exq3RUNJw6raWUSlFEQ+3PX3EYs++bTxZB2dE9mEHTQLv61tw==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/middleware-content-length": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.5.tgz", + "integrity": "sha512-ILEzC2eyxx6ncej3zZSwMpB5RJ0zuqH7eMptxC4KN3f+v9bqT8ohssKbhNR78k/2tWW+KS5Spw+tbPF4Ejyqvw==", + "dependencies": { + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/middleware-endpoint": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.1.0.tgz", + "integrity": "sha512-5y5aiKCEwg9TDPB4yFE7H6tYvGFf1OJHNczeY10/EFF8Ir8jZbNntQJxMWNfeQjC1mxPsaQ6mR9cvQbf+0YeMw==", + "dependencies": { + "@smithy/middleware-serde": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/middleware-retry": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.13.tgz", + "integrity": "sha512-zvCLfaRYCaUmjbF2yxShGZdolSHft7NNCTA28HVN9hKcEbOH+g5irr1X9s+in8EpambclGnevZY4A3lYpvDCFw==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/service-error-classification": "^3.0.3", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/middleware-serde": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.3.tgz", + "integrity": "sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/middleware-stack": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.3.tgz", + "integrity": "sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/node-config-provider": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.4.tgz", + "integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==", + "dependencies": { + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/node-http-handler": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.4.tgz", + "integrity": "sha512-+UmxgixgOr/yLsUxcEKGH0fMNVteJFGkmRltYFHnBMlogyFdpzn2CwqWmxOrfJELhV34v0WSlaqG1UtE1uXlJg==", + "dependencies": { + "@smithy/abort-controller": "^3.1.1", + "@smithy/protocol-http": "^4.1.0", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/property-provider": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", + "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/querystring-builder": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", + "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", + "dependencies": { + "@smithy/types": "^3.3.0", + "@smithy/util-uri-escape": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/querystring-parser": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.3.tgz", + "integrity": "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/service-error-classification": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.3.tgz", + "integrity": "sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ==", + "dependencies": { + "@smithy/types": "^3.3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/shared-ini-file-loader": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.4.tgz", + "integrity": "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/signature-v4": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.1.0.tgz", + "integrity": "sha512-aRryp2XNZeRcOtuJoxjydO6QTaVhxx/vjaR+gx7ZjaFgrgPRyZ3HCTbfwqYj6ZWEBHkCSUfcaymKPURaByukag==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-uri-escape": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/smithy-client": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", + "dependencies": { + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "@smithy/util-stream": "^3.1.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/url-parser": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.3.tgz", + "integrity": "sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A==", + "dependencies": { + "@smithy/querystring-parser": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-base64": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", + "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-base64/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-body-length-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-3.0.0.tgz", + "integrity": "sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-body-length-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", + "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-config-provider": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", + "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-defaults-mode-browser": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.13.tgz", + "integrity": "sha512-ZIRSUsnnMRStOP6OKtW+gCSiVFkwnfQF2xtf32QKAbHR6ACjhbAybDvry+3L5qQYdh3H6+7yD/AiUE45n8mTTw==", + "dependencies": { + "@smithy/property-provider": "^3.1.3", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-defaults-mode-node": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.13.tgz", + "integrity": "sha512-voUa8TFJGfD+U12tlNNLCDlXibt9vRdNzRX45Onk/WxZe7TS+hTOZouEZRa7oARGicdgeXvt1A0W45qLGYdy+g==", + "dependencies": { + "@smithy/config-resolver": "^3.0.5", + "@smithy/credential-provider-imds": "^3.2.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-endpoints": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.0.5.tgz", + "integrity": "sha512-ReQP0BWihIE68OAblC/WQmDD40Gx+QY1Ez8mTdFMXpmjfxSyz2fVQu3A4zXRfQU9sZXtewk3GmhfOHswvX+eNg==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-hex-encoding": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", + "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-middleware": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.3.tgz", + "integrity": "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-retry": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.3.tgz", + "integrity": "sha512-AFw+hjpbtVApzpNDhbjNG5NA3kyoMs7vx0gsgmlJF4s+yz1Zlepde7J58zpIRIsdjc+emhpAITxA88qLkPF26w==", + "dependencies": { + "@smithy/service-error-classification": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-stream": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.1.3.tgz", + "integrity": "sha512-FIv/bRhIlAxC0U7xM1BCnF2aDRPq0UaelqBHkM2lsCp26mcBbgI0tCVTv+jGdsQLUmAMybua/bjDsSu8RQHbmw==", + "dependencies": { + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-stream/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-uri-escape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", + "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-utf8/node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/@smithy/util-waiter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-3.1.2.tgz", + "integrity": "sha512-4pP0EV3iTsexDx+8PPGAKCQpd/6hsQBaQhqWzU4hqKPHN5epPsxKbvUTIiYIHTxaKt6/kEaqPBpu/ufvfbrRzw==", + "dependencies": { + "@smithy/abort-controller": "^3.1.1", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-ses/node_modules/fast-xml-parser": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", + "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + }, + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + } + ], + "dependencies": { + "strnum": "^1.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, "node_modules/@aws-sdk/client-sso": { "version": "3.556.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.556.0.tgz", @@ -3396,27 +4545,59 @@ } }, "node_modules/@css-inline/css-inline": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline/-/css-inline-0.13.0.tgz", - "integrity": "sha512-ZozAXBiW1I8hf6eW5eTNqhxUdNOBxrNNxxUnQRiKQpWcs5ORuGaiWwV5focMBTJ5WXGN+Z8VLP93BOwWFPzCJw==", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline/-/css-inline-0.14.1.tgz", + "integrity": "sha512-u4eku+hnPqqHIGq/ZUQcaP0TrCbYeLIYBaK7qClNRGZbnh8RC4gVxLEIo8Pceo1nOK9E5G4Lxzlw5KnXcvflfA==", "engines": { "node": ">= 10" }, "optionalDependencies": { - "@css-inline/css-inline-darwin-arm64": "0.13.0", - "@css-inline/css-inline-darwin-x64": "0.13.0", - "@css-inline/css-inline-linux-arm-gnueabihf": "0.13.0", - "@css-inline/css-inline-linux-arm64-gnu": "0.13.0", - "@css-inline/css-inline-linux-arm64-musl": "0.13.0", - "@css-inline/css-inline-linux-x64-gnu": "0.13.0", - "@css-inline/css-inline-linux-x64-musl": "0.13.0", - "@css-inline/css-inline-win32-x64-msvc": "0.13.0" + "@css-inline/css-inline-android-arm-eabi": "0.14.1", + "@css-inline/css-inline-android-arm64": "0.14.1", + "@css-inline/css-inline-darwin-arm64": "0.14.1", + "@css-inline/css-inline-darwin-x64": "0.14.1", + "@css-inline/css-inline-linux-arm-gnueabihf": "0.14.1", + "@css-inline/css-inline-linux-arm64-gnu": "0.14.1", + "@css-inline/css-inline-linux-arm64-musl": "0.14.1", + "@css-inline/css-inline-linux-x64-gnu": "0.14.1", + "@css-inline/css-inline-linux-x64-musl": "0.14.1", + "@css-inline/css-inline-win32-x64-msvc": "0.14.1" + } + }, + "node_modules/@css-inline/css-inline-android-arm-eabi": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-android-arm-eabi/-/css-inline-android-arm-eabi-0.14.1.tgz", + "integrity": "sha512-LNUR8TY4ldfYi0mi/d4UNuHJ+3o8yLQH9r2Nt6i4qeg1i7xswfL3n/LDLRXvGjBYqeEYNlhlBQzbPwMX1qrU6A==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@css-inline/css-inline-android-arm64": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-android-arm64/-/css-inline-android-arm64-0.14.1.tgz", + "integrity": "sha512-tH5us0NYGoTNBHOUHVV7j9KfJ4DtFOeTLA3cM0XNoMtArNu2pmaaBMFJPqECzavfXkLc7x5Z22UPZYjoyHfvCA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" } }, "node_modules/@css-inline/css-inline-darwin-arm64": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-darwin-arm64/-/css-inline-darwin-arm64-0.13.0.tgz", - "integrity": "sha512-A4QvlZdhp8v+3IHKF/UftRf5GrAVUMEHCGRuk2Dx594xn/UR4ieh+B70aMm5rfONh2hv5mlR9UcoYAkVpEQ99g==", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-darwin-arm64/-/css-inline-darwin-arm64-0.14.1.tgz", + "integrity": "sha512-QE5W1YRIfRayFrtrcK/wqEaxNaqLULPI0gZB4ArbFRd3d56IycvgBasDTHPre5qL2cXCO3VyPx+80XyHOaVkag==", "cpu": [ "arm64" ], @@ -3429,9 +4610,9 @@ } }, "node_modules/@css-inline/css-inline-darwin-x64": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-darwin-x64/-/css-inline-darwin-x64-0.13.0.tgz", - "integrity": "sha512-px9z4ypzeECMyBEtlrNzTMpA1tnw5MmMIiMkBRhb8UGRr2pOBZY3yd/eEIxWzVVSPt0aIjVDwUOJ3+d0Z+BskA==", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-darwin-x64/-/css-inline-darwin-x64-0.14.1.tgz", + "integrity": "sha512-mAvv2sN8awNFsbvBzlFkZPbCNZ6GCWY5/YcIz7V5dPYw+bHHRbjnlkNTEZq5BsDxErVrMIGvz05PGgzuNvZvdQ==", "cpu": [ "x64" ], @@ -3444,9 +4625,9 @@ } }, "node_modules/@css-inline/css-inline-linux-arm-gnueabihf": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-arm-gnueabihf/-/css-inline-linux-arm-gnueabihf-0.13.0.tgz", - "integrity": "sha512-+uo0coLQNgk/AKeOB8mXSRd8VIlUg38zRSB9B9q0ior9oBCDPtEdn1HuCSvWxHoOSJ8QNNk+uwbz0zW4CETzFw==", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-arm-gnueabihf/-/css-inline-linux-arm-gnueabihf-0.14.1.tgz", + "integrity": "sha512-AWC44xL0X7BgKvrWEqfSqkT2tJA5kwSGrAGT+m0gt11wnTYySvQ6YpX0fTY9i3ppYGu4bEdXFjyK2uY1DTQMHA==", "cpu": [ "arm" ], @@ -3459,9 +4640,9 @@ } }, "node_modules/@css-inline/css-inline-linux-arm64-gnu": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-arm64-gnu/-/css-inline-linux-arm64-gnu-0.13.0.tgz", - "integrity": "sha512-GVrsFbY5l0Hxyzxsm5S5JPGObvHm/Ybf2wZgnWBsQigxqGtr1FL535HaTwEnq6aHOpH3f08gR5Vx33gB7jG4pw==", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-arm64-gnu/-/css-inline-linux-arm64-gnu-0.14.1.tgz", + "integrity": "sha512-drj0ciiJgdP3xKXvNAt4W+FH4KKMs8vB5iKLJ3HcH07sNZj58Sx++2GxFRS1el3p+GFp9OoYA6dgouJsGEqt0Q==", "cpu": [ "arm64" ], @@ -3474,9 +4655,9 @@ } }, "node_modules/@css-inline/css-inline-linux-arm64-musl": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-arm64-musl/-/css-inline-linux-arm64-musl-0.13.0.tgz", - "integrity": "sha512-V5h5+CRnE01EgoafI/kyjEcM8zvN+sKLnp17Aq9LqQfsut7mO3i72d8g/xeVC37DCLoGQFLvDCzbze2NbF2dIQ==", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-arm64-musl/-/css-inline-linux-arm64-musl-0.14.1.tgz", + "integrity": "sha512-FzknI+st8eA8YQSdEJU9ykcM0LZjjigBuynVF5/p7hiMm9OMP8aNhWbhZ8LKJpKbZrQsxSGS4g9Vnr6n6FiSdQ==", "cpu": [ "arm64" ], @@ -3489,9 +4670,9 @@ } }, "node_modules/@css-inline/css-inline-linux-x64-gnu": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-x64-gnu/-/css-inline-linux-x64-gnu-0.13.0.tgz", - "integrity": "sha512-vbRV++73MW7dvz/AIbozkv4R68/k/sEp57hno/L6lx034VYxpCwdfqtGN4D0W1TOTzdr2b6qBOGNZ1oLKQZOQQ==", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-x64-gnu/-/css-inline-linux-x64-gnu-0.14.1.tgz", + "integrity": "sha512-yubbEye+daDY/4vXnyASAxH88s256pPati1DfVoZpU1V0+KP0BZ1dByZOU1ktExurbPH3gZOWisAnBE9xon0Uw==", "cpu": [ "x64" ], @@ -3504,9 +4685,9 @@ } }, "node_modules/@css-inline/css-inline-linux-x64-musl": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-x64-musl/-/css-inline-linux-x64-musl-0.13.0.tgz", - "integrity": "sha512-2tCnwU23W/yMs9cGc2/i2jd9y2pjuntx0a5OytqX7s9fvUtmI3nc0Od6wuf51LnmdU+XAU8HLT9pZppsQiwPfQ==", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-x64-musl/-/css-inline-linux-x64-musl-0.14.1.tgz", + "integrity": "sha512-6CRAZzoy1dMLPC/tns2rTt1ZwPo0nL/jYBEIAsYTCWhfAnNnpoLKVh5Nm+fSU3OOwTTqU87UkGrFJhObD/wobQ==", "cpu": [ "x64" ], @@ -3519,9 +4700,9 @@ } }, "node_modules/@css-inline/css-inline-win32-x64-msvc": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-win32-x64-msvc/-/css-inline-win32-x64-msvc-0.13.0.tgz", - "integrity": "sha512-6VFhFSXp4FH+NzJhLd6fFi7jKCPvIRW+vq0tV+CPuiQ3zPzMfC9nIk8sB/1VJR8EcvBAjMV53YnacuDjRFRT9g==", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-win32-x64-msvc/-/css-inline-win32-x64-msvc-0.14.1.tgz", + "integrity": "sha512-nzotGiaiuiQW78EzsiwsHZXbxEt6DiMUFcDJ6dhiliomXxnlaPyBfZb6/FMBgRJOf6sknDt/5695OttNmbMYzg==", "cpu": [ "x64" ], @@ -5085,33 +6266,60 @@ } }, "node_modules/@nestjs-modules/mailer": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/@nestjs-modules/mailer/-/mailer-1.11.2.tgz", - "integrity": "sha512-k07wyKbtCzxWMm6IqGwcGIisnXD/6sneGvUR8rBBZbxtLn1HE1FLGyiaXBrPui/0K7W41aS9x9jAIhfTawtlUg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@nestjs-modules/mailer/-/mailer-2.0.2.tgz", + "integrity": "sha512-+z4mADQasg0H1ZaGu4zZTuKv2pu+XdErqx99PLFPzCDNTN/q9U59WPgkxVaHnsvKHNopLj5Xap7G4ZpptduoYw==", "dependencies": { - "@css-inline/css-inline": "0.13.0", - "glob": "10.3.10", - "mjml": "4.15.3", - "preview-email": "3.0.19" + "@css-inline/css-inline": "0.14.1", + "glob": "10.3.12" }, "optionalDependencies": { "@types/ejs": "^3.1.5", + "@types/mjml": "^4.7.4", "@types/pug": "^2.0.10", - "ejs": "^3.1.9", + "ejs": "^3.1.10", "handlebars": "^4.7.8", + "liquidjs": "^10.11.1", + "mjml": "^4.15.3", + "preview-email": "^3.0.19", "pug": "^3.0.2" }, "peerDependencies": { "@nestjs/common": ">=7.0.9", "@nestjs/core": ">=7.0.9", "@types/ejs": ">=3.0.3", + "@types/mjml": ">=4.7.4", "@types/pug": ">=2.0.6", "ejs": ">=3.1.2", "handlebars": ">=4.7.6", + "liquidjs": ">=10.8.2", + "mjml": ">=4.15.3", "nodemailer": ">=6.4.6", + "preview-email": ">=3.0.19", "pug": ">=3.0.1" } }, + "node_modules/@nestjs-modules/mailer/node_modules/glob": { + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.6", + "minimatch": "^9.0.1", + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@nestjs/class-transformer": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/@nestjs/class-transformer/-/class-transformer-0.4.0.tgz", @@ -5610,7 +6818,8 @@ "node_modules/@one-ini/wasm": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz", - "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==" + "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", + "optional": true }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", @@ -7254,6 +8463,7 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz", "integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==", + "optional": true, "dependencies": { "domhandler": "^5.0.3", "selderee": "^0.11.0" @@ -8230,6 +9440,21 @@ "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", "dev": true }, + "node_modules/@types/mjml": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/@types/mjml/-/mjml-4.7.4.tgz", + "integrity": "sha512-vyi1vzWgMzFMwZY7GSZYX0GU0dmtC8vLHwpgk+NWmwbwRSrlieVyJ9sn5elodwUfklJM7yGl0zQeet1brKTWaQ==", + "optional": true, + "dependencies": { + "@types/mjml-core": "*" + } + }, + "node_modules/@types/mjml-core": { + "version": "4.15.0", + "resolved": "https://registry.npmjs.org/@types/mjml-core/-/mjml-core-4.15.0.tgz", + "integrity": "sha512-jSRWTOpwRS/uHIBfGdvLl0a7MaoBZZYHKI+HhsFYChrUOKVJTnjSYsuV6wx0snv6ZaX3TUo5OP/gNsz/uzZz1A==", + "optional": true + }, "node_modules/@types/morgan": { "version": "1.9.9", "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.9.tgz", @@ -8762,6 +9987,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "optional": true, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -8886,6 +10112,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/alce/-/alce-1.2.0.tgz", "integrity": "sha512-XppPf2S42nO2WhvKzlwzlfcApcXHzjlod30pKmcWjRgLOtqoe5DMuqdiYoM6AgyXksc6A6pV4v1L/WW217e57w==", + "optional": true, "dependencies": { "esprima": "^1.2.0", "estraverse": "^1.5.0" @@ -8898,6 +10125,7 @@ "version": "1.2.5", "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz", "integrity": "sha512-S9VbPDU0adFErpDai3qDkjq8+G05ONtKzcyNrPKg/ZKa+tf879nX2KexNU95b31UoTJjRLInNBHHHjFPoCd7lQ==", + "optional": true, "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -8910,6 +10138,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==", + "optional": true, "engines": { "node": ">=0.10.0" } @@ -8924,6 +10153,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "devOptional": true, "engines": { "node": ">=6" } @@ -9117,7 +10347,8 @@ "node_modules/assert-never": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.2.1.tgz", - "integrity": "sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==" + "integrity": "sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==", + "optional": true }, "node_modules/ast-types": { "version": "0.15.2", @@ -9391,6 +10622,7 @@ "version": "3.0.0-canary-5", "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==", + "optional": true, "dependencies": { "@babel/types": "^7.9.6" }, @@ -9442,6 +10674,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "devOptional": true, "engines": { "node": ">=8" }, @@ -9482,18 +10715,6 @@ "ieee754": "^1.1.13" } }, - "node_modules/blake2": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/blake2/-/blake2-5.0.0.tgz", - "integrity": "sha512-MLpq1DwBB9rC0IHuRc2gXLEAeNNTTYHEtvYCA5lK4RmoUPRmQLSLQrwgJvou62BvH9KP7whe8n+xxw45++fnYg==", - "hasInstallScript": true, - "dependencies": { - "nan": "^2.17.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, "node_modules/blake2b": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/blake2b/-/blake2b-2.1.4.tgz", @@ -9611,7 +10832,8 @@ "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "optional": true }, "node_modules/bowser": { "version": "2.11.0", @@ -9835,6 +11057,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==", + "optional": true, "dependencies": { "no-case": "^2.2.0", "upper-case": "^1.1.1" @@ -9911,6 +11134,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", "integrity": "sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==", + "optional": true, "dependencies": { "is-regex": "^1.0.3" } @@ -9925,6 +11149,7 @@ "version": "1.0.0-rc.12", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "optional": true, "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", @@ -9945,6 +11170,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "optional": true, "dependencies": { "boolbase": "^1.0.0", "css-select": "^5.1.0", @@ -9961,6 +11187,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "devOptional": true, "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -10150,6 +11377,7 @@ "version": "4.2.4", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", + "optional": true, "dependencies": { "source-map": "~0.6.0" }, @@ -10161,6 +11389,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true, "engines": { "node": ">=0.10.0" } @@ -10604,6 +11833,7 @@ "version": "1.1.13", "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "optional": true, "dependencies": { "ini": "^1.3.4", "proto-list": "~1.2.1" @@ -10687,6 +11917,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==", + "optional": true, "dependencies": { "@babel/parser": "^7.6.0", "@babel/types": "^7.6.1" @@ -10856,6 +12087,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "optional": true, "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", @@ -10871,6 +12103,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "optional": true, "engines": { "node": ">= 6" }, @@ -11134,6 +12367,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "optional": true, "engines": { "node": ">=8" } @@ -11150,6 +12384,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "devOptional": true, "engines": { "node": ">=8" } @@ -11157,7 +12392,8 @@ "node_modules/detect-node": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "optional": true }, "node_modules/dezalgo": { "version": "1.0.4", @@ -11202,6 +12438,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/display-notification/-/display-notification-2.0.0.tgz", "integrity": "sha512-TdmtlAcdqy1NU+j7zlkDdMnCL878zriLaBmoD9quOoq1ySSSGv03l0hXK5CvIFZlIfFI/hizqdQuW+Num7xuhw==", + "optional": true, "dependencies": { "escape-string-applescript": "^1.0.0", "run-applescript": "^3.0.0" @@ -11236,12 +12473,14 @@ "node_modules/doctypes": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", - "integrity": "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==" + "integrity": "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==", + "optional": true }, "node_modules/dom-serializer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "optional": true, "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -11260,12 +12499,14 @@ "type": "github", "url": "https://github.com/sponsors/fb55" } - ] + ], + "optional": true }, "node_modules/domhandler": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "optional": true, "dependencies": { "domelementtype": "^2.3.0" }, @@ -11280,6 +12521,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "optional": true, "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", @@ -11325,6 +12567,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", + "optional": true, "dependencies": { "@one-ini/wasm": "0.1.1", "commander": "^10.0.0", @@ -11342,6 +12585,7 @@ "version": "10.0.1", "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "optional": true, "engines": { "node": ">=14" } @@ -11350,6 +12594,7 @@ "version": "9.0.1", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "optional": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -11419,6 +12664,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/encoding-japanese/-/encoding-japanese-2.0.0.tgz", "integrity": "sha512-++P0RhebUC8MJAwJOsT93dT+5oc5oPImp1HubZpAuCZ5kTLnhuuBhKHj2jJeO/Gj93idPBWmIuQ9QWMe5rX3pQ==", + "optional": true, "engines": { "node": ">=8.10.0" } @@ -11448,6 +12694,7 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "optional": true, "engines": { "node": ">=0.12" }, @@ -11539,6 +12786,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-3.0.0.tgz", "integrity": "sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==", + "optional": true, "engines": { "node": ">=10" }, @@ -11555,6 +12803,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/escape-string-applescript/-/escape-string-applescript-1.0.0.tgz", "integrity": "sha512-4/hFwoYaC6TkpDn9A3pTC52zQPArFeXuIfhUtCGYdauTzXVP9H3BDr3oO/QzQehMpLDC7srvYgfwvImPFGfvBA==", + "optional": true, "engines": { "node": ">=0.10.0" } @@ -11991,7 +13240,8 @@ "node_modules/extend-object": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/extend-object/-/extend-object-1.0.0.tgz", - "integrity": "sha512-0dHDIXC7y7LDmCh/lp1oYkmv73K25AMugQI07r8eFopkW6f7Ufn1q+ETMsJjnV9Am14SlElkqy3O92r6xEaxPw==" + "integrity": "sha512-0dHDIXC7y7LDmCh/lp1oYkmv73K25AMugQI07r8eFopkW6f7Ufn1q+ETMsJjnV9Am14SlElkqy3O92r6xEaxPw==", + "optional": true }, "node_modules/external-editor": { "version": "3.1.0", @@ -12458,6 +13708,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/fixpack/-/fixpack-4.0.0.tgz", "integrity": "sha512-5SM1+H2CcuJ3gGEwTiVo/+nd/hYpNj9Ch3iMDOQ58ndY+VGQ2QdvaUTkd3otjZvYnd/8LF/HkJ5cx7PBq0orCQ==", + "optional": true, "dependencies": { "alce": "1.2.0", "chalk": "^3.0.0", @@ -12474,6 +13725,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "optional": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -12828,6 +14080,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "optional": true, "engines": { "node": ">=8" }, @@ -12876,6 +14129,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "devOptional": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -13037,6 +14291,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "devOptional": true, "dependencies": { "has-symbols": "^1.0.3" }, @@ -13067,6 +14322,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "optional": true, "bin": { "he": "bin/he" } @@ -13164,6 +14420,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz", "integrity": "sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==", + "optional": true, "dependencies": { "camel-case": "^3.0.0", "clean-css": "^4.2.1", @@ -13183,12 +14440,14 @@ "node_modules/html-minifier/node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "optional": true }, "node_modules/html-to-text": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz", "integrity": "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==", + "optional": true, "dependencies": { "@selderee/plugin-htmlparser2": "^0.11.0", "deepmerge": "^4.3.1", @@ -13211,6 +14470,7 @@ "url": "https://github.com/sponsors/fb55" } ], + "optional": true, "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", @@ -13562,6 +14822,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "devOptional": true, "dependencies": { "binary-extensions": "^2.0.0" }, @@ -13646,6 +14907,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", + "optional": true, "dependencies": { "acorn": "^7.1.1", "object-assign": "^4.1.1" @@ -13655,6 +14917,7 @@ "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "optional": true, "bin": { "acorn": "bin/acorn" }, @@ -13666,6 +14929,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "devOptional": true, "engines": { "node": ">=0.10.0" } @@ -13707,6 +14971,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "devOptional": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -13778,12 +15043,14 @@ "node_modules/is-promise": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "optional": true }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "optional": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -15014,6 +16281,7 @@ "version": "1.15.1", "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.1.tgz", "integrity": "sha512-ESjNzSlt/sWE8sciZH8kBF8BPlwXPwhR6pWKAw8bw4Bwj+iZcnKW6ONWUutJ7eObuBZQpiIb8S7OYspWrKt7rA==", + "optional": true, "dependencies": { "config-chain": "^1.1.13", "editorconfig": "^1.0.4", @@ -15034,6 +16302,7 @@ "version": "3.0.5", "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "optional": true, "engines": { "node": ">=14" } @@ -15041,7 +16310,8 @@ "node_modules/js-stringify": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", - "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==" + "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==", + "optional": true }, "node_modules/js-tokens": { "version": "4.0.0", @@ -15230,6 +16500,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", "integrity": "sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==", + "optional": true, "dependencies": { "is-promise": "^2.0.0", "promise": "^7.0.1" @@ -15239,6 +16510,7 @@ "version": "10.0.0", "resolved": "https://registry.npmjs.org/juice/-/juice-10.0.0.tgz", "integrity": "sha512-9f68xmhGrnIi6DBkiiP3rUrQN33SEuaKu1+njX6VgMP+jwZAsnT33WIzlrWICL9matkhYu3OyrqSUP55YTIdGg==", + "optional": true, "dependencies": { "cheerio": "^1.0.0-rc.12", "commander": "^6.1.0", @@ -15257,6 +16529,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "optional": true, "engines": { "node": ">= 6" } @@ -15315,6 +16588,7 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz", "integrity": "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==", + "optional": true, "funding": { "url": "https://ko-fi.com/killymxi" } @@ -15380,12 +16654,14 @@ "node_modules/libbase64": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-1.3.0.tgz", - "integrity": "sha512-GgOXd0Eo6phYgh0DJtjQ2tO8dc0IVINtZJeARPeiIJqge+HdsWSuaDTe8ztQ7j/cONByDZ3zeB325AHiv5O0dg==" + "integrity": "sha512-GgOXd0Eo6phYgh0DJtjQ2tO8dc0IVINtZJeARPeiIJqge+HdsWSuaDTe8ztQ7j/cONByDZ3zeB325AHiv5O0dg==", + "optional": true }, "node_modules/libmime": { "version": "5.3.4", "resolved": "https://registry.npmjs.org/libmime/-/libmime-5.3.4.tgz", "integrity": "sha512-TsqPdercr6DHrnoQx1F0nS2Y4yPT+fWuOjEP2rqzvV77hMYWomTe/rpm0u9JORQ/FavEXybAGcBJsQbLr9+hjA==", + "optional": true, "dependencies": { "encoding-japanese": "2.0.0", "iconv-lite": "0.6.3", @@ -15397,6 +16673,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -15440,7 +16717,8 @@ "node_modules/libqp": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/libqp/-/libqp-2.1.0.tgz", - "integrity": "sha512-O6O6/fsG5jiUVbvdgT7YX3xY3uIadR6wEZ7+vy9u7PKHAlSEB6blvC1o5pHBjgsi95Uo0aiBBdkyFecj6jtb7A==" + "integrity": "sha512-O6O6/fsG5jiUVbvdgT7YX3xY3uIadR6wEZ7+vy9u7PKHAlSEB6blvC1o5pHBjgsi95Uo0aiBBdkyFecj6jtb7A==", + "optional": true }, "node_modules/light-my-request": { "version": "5.13.0", @@ -15497,10 +16775,40 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "optional": true, "dependencies": { "uc.micro": "^2.0.0" } }, + "node_modules/liquidjs": { + "version": "10.16.1", + "resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-10.16.1.tgz", + "integrity": "sha512-1JFL/Y7ONoajrfwav37yuz5yQHU3+Pgz1XWsg9E/2T8Fp65KalNfMF8QZ3+tNETqGUIB66waOSLOi64niYZE9A==", + "optional": true, + "dependencies": { + "commander": "^10.0.0" + }, + "bin": { + "liquid": "bin/liquid.js", + "liquidjs": "bin/liquid.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/liquidjs" + } + }, + "node_modules/liquidjs/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", @@ -15770,7 +17078,8 @@ "node_modules/lower-case": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", - "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==" + "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==", + "optional": true }, "node_modules/lru-cache": { "version": "5.1.1", @@ -15804,6 +17113,7 @@ "version": "3.7.0", "resolved": "https://registry.npmjs.org/mailparser/-/mailparser-3.7.0.tgz", "integrity": "sha512-yFo1+4r3gHhTcazVGCv3D/uX5VJyyrx4iWkzKtJh8mujYIUm92kpG5BjKpZIJgEoKcKxbJVd4CPs+IImE1sKlQ==", + "optional": true, "dependencies": { "encoding-japanese": "2.0.0", "he": "1.2.0", @@ -15821,6 +17131,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -15832,6 +17143,7 @@ "version": "6.9.11", "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.11.tgz", "integrity": "sha512-UiAkgiERuG94kl/3bKfE8o10epvDnl0vokNEtZDPTq9BWzIl6EFT9336SbIT4oaTBD8NmmUTLsQyXHV82eXSWg==", + "optional": true, "engines": { "node": ">=6.0.0" } @@ -15840,6 +17152,7 @@ "version": "5.4.0", "resolved": "https://registry.npmjs.org/mailsplit/-/mailsplit-5.4.0.tgz", "integrity": "sha512-wnYxX5D5qymGIPYLwnp6h8n1+6P6vz/MJn5AzGjZ8pwICWssL+CCQjWBIToOVHASmATot4ktvlLo6CyLfOXWYA==", + "optional": true, "dependencies": { "libbase64": "1.2.1", "libmime": "5.2.0", @@ -15850,6 +17163,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -15860,12 +17174,14 @@ "node_modules/mailsplit/node_modules/libbase64": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-1.2.1.tgz", - "integrity": "sha512-l+nePcPbIG1fNlqMzrh68MLkX/gTxk/+vdvAb388Ssi7UuUN31MI44w4Yf33mM3Cm4xDfw48mdf3rkdHszLNew==" + "integrity": "sha512-l+nePcPbIG1fNlqMzrh68MLkX/gTxk/+vdvAb388Ssi7UuUN31MI44w4Yf33mM3Cm4xDfw48mdf3rkdHszLNew==", + "optional": true }, "node_modules/mailsplit/node_modules/libmime": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/libmime/-/libmime-5.2.0.tgz", "integrity": "sha512-X2U5Wx0YmK0rXFbk67ASMeqYIkZ6E5vY7pNWRKtnNzqjvdYYG8xtPDpCnuUEnPU9vlgNev+JoSrcaKSUaNvfsw==", + "optional": true, "dependencies": { "encoding-japanese": "2.0.0", "iconv-lite": "0.6.3", @@ -15876,7 +17192,8 @@ "node_modules/mailsplit/node_modules/libqp": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/libqp/-/libqp-2.0.1.tgz", - "integrity": "sha512-Ka0eC5LkF3IPNQHJmYBWljJsw0UvM6j+QdKRbWyCdTmYwvIDE6a7bCm0UkTAL/K+3KXK5qXT/ClcInU01OpdLg==" + "integrity": "sha512-Ka0eC5LkF3IPNQHJmYBWljJsw0UvM6j+QdKRbWyCdTmYwvIDE6a7bCm0UkTAL/K+3KXK5qXT/ClcInU01OpdLg==", + "optional": true }, "node_modules/make-dir": { "version": "4.0.0", @@ -15942,7 +17259,8 @@ "node_modules/mensch": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/mensch/-/mensch-0.3.4.tgz", - "integrity": "sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==" + "integrity": "sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==", + "optional": true }, "node_modules/merge-descriptors": { "version": "1.0.1", @@ -16728,6 +18046,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml/-/mjml-4.15.3.tgz", "integrity": "sha512-bW2WpJxm6HS+S3Yu6tq1DUPFoTxU9sPviUSmnL7Ua+oVO3WA5ILFWqvujUlz+oeuM+HCwEyMiP5xvKNPENVjYA==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "mjml-cli": "4.15.3", @@ -16744,6 +18063,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-accordion/-/mjml-accordion-4.15.3.tgz", "integrity": "sha512-LPNVSj1LyUVYT9G1gWwSw3GSuDzDsQCu0tPB2uDsq4VesYNnU6v3iLCQidMiR6azmIt13OEozG700ygAUuA6Ng==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -16754,6 +18074,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-body/-/mjml-body-4.15.3.tgz", "integrity": "sha512-7pfUOVPtmb0wC+oUOn4xBsAw4eT5DyD6xqaxj/kssu6RrFXOXgJaVnDPAI9AzIvXJ/5as9QrqRGYAddehwWpHQ==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -16764,6 +18085,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-button/-/mjml-button-4.15.3.tgz", "integrity": "sha512-79qwn9AgdGjJR1vLnrcm2rq2AsAZkKC5JPwffTMG+Nja6zGYpTDZFZ56ekHWr/r1b5WxkukcPj2PdevUug8c+Q==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -16774,6 +18096,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-carousel/-/mjml-carousel-4.15.3.tgz", "integrity": "sha512-3ju6I4l7uUhPRrJfN3yK9AMsfHvrYbRkcJ1GRphFHzUj37B2J6qJOQUpzA547Y4aeh69TSb7HFVf1t12ejQxVw==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -16784,6 +18107,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-cli/-/mjml-cli-4.15.3.tgz", "integrity": "sha512-+V2TDw3tXUVEptFvLSerz125C2ogYl8klIBRY1m5BHd4JvGVf3yhx8N3PngByCzA6PGcv/eydGQN+wy34SHf0Q==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "chokidar": "^3.0.0", @@ -16806,6 +18130,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-column/-/mjml-column-4.15.3.tgz", "integrity": "sha512-hYdEFdJGHPbZJSEysykrevEbB07yhJGSwfDZEYDSbhQQFjV2tXrEgYcFD5EneMaowjb55e3divSJxU4c5q4Qgw==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -16816,6 +18141,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-core/-/mjml-core-4.15.3.tgz", "integrity": "sha512-Dmwk+2cgSD9L9GmTbEUNd8QxkTZtW9P7FN/ROZW/fGZD6Hq6/4TB0zEspg2Ow9eYjZXO2ofOJ3PaQEEShKV0kQ==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "cheerio": "1.0.0-rc.12", @@ -16833,6 +18159,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-divider/-/mjml-divider-4.15.3.tgz", "integrity": "sha512-vh27LQ9FG/01y0b9ntfqm+GT5AjJnDSDY9hilss2ixIUh0FemvfGRfsGVeV5UBVPBKK7Ffhvfqc7Rciob9Spzw==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -16843,6 +18170,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-group/-/mjml-group-4.15.3.tgz", "integrity": "sha512-HSu/rKnGZVKFq3ciT46vi1EOy+9mkB0HewO4+P6dP/Y0UerWkN6S3UK11Cxsj0cAp0vFwkPDCdOeEzRdpFEkzA==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -16853,6 +18181,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-head/-/mjml-head-4.15.3.tgz", "integrity": "sha512-o3mRuuP/MB5fZycjD3KH/uXsnaPl7Oo8GtdbJTKtH1+O/3pz8GzGMkscTKa97l03DAG2EhGrzzLcU2A6eshwFw==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -16863,6 +18192,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-head-attributes/-/mjml-head-attributes-4.15.3.tgz", "integrity": "sha512-2ISo0r5ZKwkrvJgDou9xVPxxtXMaETe2AsAA02L89LnbB2KC0N5myNsHV0sEysTw9+CfCmgjAb0GAI5QGpxKkQ==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -16873,6 +18203,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-head-breakpoint/-/mjml-head-breakpoint-4.15.3.tgz", "integrity": "sha512-Eo56FA5C2v6ucmWQL/JBJ2z641pLOom4k0wP6CMZI2utfyiJ+e2Uuinj1KTrgDcEvW4EtU9HrfAqLK9UosLZlg==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -16883,6 +18214,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-head-font/-/mjml-head-font-4.15.3.tgz", "integrity": "sha512-CzV2aDPpiNIIgGPHNcBhgyedKY4SX3BJoTwOobSwZVIlEA6TAWB4Z9WwFUmQqZOgo1AkkiTHPZQvGcEhFFXH6g==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -16893,6 +18225,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-head-html-attributes/-/mjml-head-html-attributes-4.15.3.tgz", "integrity": "sha512-MDNDPMBOgXUZYdxhosyrA2kudiGO8aogT0/cODyi2Ed9o/1S7W+je11JUYskQbncqhWKGxNyaP4VWa+6+vUC/g==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -16903,6 +18236,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-head-preview/-/mjml-head-preview-4.15.3.tgz", "integrity": "sha512-J2PxCefUVeFwsAExhrKo4lwxDevc5aKj888HBl/wN4EuWOoOg06iOGCxz4Omd8dqyFsrqvbBuPqRzQ+VycGmaA==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -16913,6 +18247,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-head-style/-/mjml-head-style-4.15.3.tgz", "integrity": "sha512-9J+JuH+mKrQU65CaJ4KZegACUgNIlYmWQYx3VOBR/tyz+8kDYX7xBhKJCjQ1I4wj2Tvga3bykd89Oc2kFZ5WOw==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -16923,6 +18258,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-head-title/-/mjml-head-title-4.15.3.tgz", "integrity": "sha512-IM59xRtsxID4DubQ0iLmoCGXguEe+9BFG4z6y2xQDrscIa4QY3KlfqgKGT69ojW+AVbXXJPEVqrAi4/eCsLItQ==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -16933,6 +18269,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-hero/-/mjml-hero-4.15.3.tgz", "integrity": "sha512-9cLAPuc69yiuzNrMZIN58j+HMK1UWPaq2i3/Fg2ZpimfcGFKRcPGCbEVh0v+Pb6/J0+kf8yIO0leH20opu3AyQ==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -16943,6 +18280,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-image/-/mjml-image-4.15.3.tgz", "integrity": "sha512-g1OhSdofIytE9qaOGdTPmRIp7JsCtgO0zbsn1Fk6wQh2gEL55Z40j/VoghslWAWTgT2OHFdBKnMvWtN6U5+d2Q==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -16953,6 +18291,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-migrate/-/mjml-migrate-4.15.3.tgz", "integrity": "sha512-sr/+35RdxZroNQVegjpfRHJ5hda9XCgaS4mK2FGO+Mb1IUevKfeEPII3F/cHDpNwFeYH3kAgyqQ22ClhGLWNBA==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "js-beautify": "^1.6.14", @@ -16969,6 +18308,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-navbar/-/mjml-navbar-4.15.3.tgz", "integrity": "sha512-VsKH/Jdlf8Yu3y7GpzQV5n7JMdpqvZvTSpF6UQXL0PWOm7k6+LX+sCZimOfpHJ+wCaaybpxokjWZ71mxOoCWoA==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -16979,6 +18319,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-parser-xml/-/mjml-parser-xml-4.15.3.tgz", "integrity": "sha512-Tz0UX8/JVYICLjT+U8J1f/TFxIYVYjzZHeh4/Oyta0pLpRLeZlxEd71f3u3kdnulCKMP4i37pFRDmyLXAlEuLw==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "detect-node": "2.1.0", @@ -16997,6 +18338,7 @@ "url": "https://github.com/sponsors/fb55" } ], + "optional": true, "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", @@ -17008,6 +18350,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-preset-core/-/mjml-preset-core-4.15.3.tgz", "integrity": "sha512-1zZS8P4O0KweWUqNS655+oNnVMPQ1Rq1GaZq5S9JfwT1Vh/m516lSmiTW9oko6gGHytt5s6Yj6oOeu5Zm8FoLw==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "mjml-accordion": "4.15.3", @@ -17041,6 +18384,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-raw/-/mjml-raw-4.15.3.tgz", "integrity": "sha512-IGyHheOYyRchBLiAEgw3UM11kFNmBSMupu2BDdejC6ZiDhEAdG+tyERlsCwDPYtXanvFpGWULIu3XlsUPc+RZw==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -17051,6 +18395,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-section/-/mjml-section-4.15.3.tgz", "integrity": "sha512-JfVPRXH++Hd933gmQfG8JXXCBCR6fIzC3DwiYycvanL/aW1cEQ2EnebUfQkt5QzlYjOkJEH+JpccAsq3ln6FZQ==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -17061,6 +18406,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-social/-/mjml-social-4.15.3.tgz", "integrity": "sha512-7sD5FXrESOxpT9Z4Oh36bS6u/geuUrMP1aCg2sjyAwbPcF1aWa2k9OcatQfpRf6pJEhUZ18y6/WBBXmMVmSzXg==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -17071,6 +18417,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-spacer/-/mjml-spacer-4.15.3.tgz", "integrity": "sha512-3B7Qj+17EgDdAtZ3NAdMyOwLTX1jfmJuY7gjyhS2HtcZAmppW+cxqHUBwCKfvSRgTQiccmEvtNxaQK+tfyrZqA==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -17081,6 +18428,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-table/-/mjml-table-4.15.3.tgz", "integrity": "sha512-FLx7DcRKTdKdcOCbMyBaeudeHaHpwPveRrBm6WyQe3LXx6FfdmOh59i71/16LFQMgBOD3N4/UJkzxLzlTJzMqQ==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -17091,6 +18439,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-text/-/mjml-text-4.15.3.tgz", "integrity": "sha512-+C0hxCmw9kg0XzT6vhE5mFkK6y225nC8UEQcN94K0fBCjPKkM+HqZMwGX205fzdGRi+Bxa55b/VhrIVwdv+8vw==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -17101,6 +18450,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-validator/-/mjml-validator-4.15.3.tgz", "integrity": "sha512-Xb72KdqRwjv/qM2rJpV22syyP2N3cRQ9VVDrN6u2FSzLq02buFNxmSPJ7CKhat3PrUNdVHU75KZwOf/tz4UEhA==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9" } @@ -17109,6 +18459,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-wrapper/-/mjml-wrapper-4.15.3.tgz", "integrity": "sha512-ditsCijeHJrmBmObtJmQ18ddLxv5oPyMTdPU8Di8APOnD2zPk7Z4UAuJSl7HXB45oFiivr3MJf4koFzMUSZ6Gg==", + "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -17300,11 +18651,6 @@ "thenify-all": "^1.0.0" } }, - "node_modules/nan": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz", - "integrity": "sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==" - }, "node_modules/nanoassert": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-2.0.0.tgz", @@ -17377,12 +18723,14 @@ "node_modules/nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "optional": true }, "node_modules/no-case": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "optional": true, "dependencies": { "lower-case": "^1.1.1" } @@ -17540,9 +18888,9 @@ } }, "node_modules/nodemailer": { - "version": "6.9.13", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.13.tgz", - "integrity": "sha512-7o38Yogx6krdoBf3jCAqnIN4oSQFx+fMa0I7dK1D+me9kBxx12D+/33wSb+fhOCtIxvYJ+4x4IMEhmhCKfAiOA==", + "version": "6.9.14", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.14.tgz", + "integrity": "sha512-Dobp/ebDKBvz91sbtRKhcznLThrKxKt97GI2FAlAyy+fk19j73Uz3sBXolVtmcXjaorivqsbbbjDY+Jkt4/bQA==", "engines": { "node": ">=6.0.0" } @@ -17551,6 +18899,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz", "integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==", + "optional": true, "dependencies": { "abbrev": "^2.0.0" }, @@ -17598,6 +18947,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "optional": true, "dependencies": { "boolbase": "^1.0.0" }, @@ -17803,6 +19153,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "optional": true, "engines": { "node": ">=4" } @@ -17889,6 +19240,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/p-wait-for/-/p-wait-for-3.2.0.tgz", "integrity": "sha512-wpgERjNkLrBiFmkMEjuZJEWKKDrNfHCKA1OhyN1wg1FrLkULbviEy6py1AyJUgZ72YWFbZ38FIpnqvVqAlDUwA==", + "optional": true, "dependencies": { "p-timeout": "^3.0.0" }, @@ -17903,6 +19255,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "optional": true, "dependencies": { "p-finally": "^1.0.0" }, @@ -17914,6 +19267,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", "integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==", + "optional": true, "dependencies": { "no-case": "^2.2.0" } @@ -17952,6 +19306,7 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "optional": true, "dependencies": { "entities": "^4.4.0" }, @@ -17963,6 +19318,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "optional": true, "dependencies": { "domhandler": "^5.0.2", "parse5": "^7.0.0" @@ -17975,6 +19331,7 @@ "version": "0.12.1", "resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz", "integrity": "sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==", + "optional": true, "dependencies": { "leac": "^0.6.0", "peberminta": "^0.9.0" @@ -18117,6 +19474,7 @@ "version": "0.9.0", "resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz", "integrity": "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==", + "optional": true, "funding": { "url": "https://ko-fi.com/killymxi" } @@ -18496,6 +19854,7 @@ "version": "3.0.19", "resolved": "https://registry.npmjs.org/preview-email/-/preview-email-3.0.19.tgz", "integrity": "sha512-DBS3Nir18YtKc8loYCCOGitmiaQ0vTdahPoiXxwNweJDpmVZo+w3tppufOhoK0m8skpRxT56llYLs3VrORnmNQ==", + "optional": true, "dependencies": { "ci-info": "^3.8.0", "display-notification": "2.0.0", @@ -18517,6 +19876,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", + "optional": true, "dependencies": { "p-timeout": "^3.1.0" }, @@ -18531,6 +19891,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "optional": true, "dependencies": { "p-finally": "^1.0.0" }, @@ -18571,6 +19932,7 @@ "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "optional": true, "dependencies": { "asap": "~2.0.3" } @@ -18607,7 +19969,8 @@ "node_modules/proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==" + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "optional": true }, "node_modules/protons-runtime": { "version": "5.4.0", @@ -18648,6 +20011,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.2.tgz", "integrity": "sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw==", + "optional": true, "dependencies": { "pug-code-gen": "^3.0.2", "pug-filters": "^4.0.0", @@ -18663,6 +20027,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz", "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==", + "optional": true, "dependencies": { "constantinople": "^4.0.1", "js-stringify": "^1.0.2", @@ -18673,6 +20038,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.2.tgz", "integrity": "sha512-nJMhW16MbiGRiyR4miDTQMRWDgKplnHyeLvioEJYbk1RsPI3FuA3saEP8uwnTb2nTJEKBU90NFVWJBk4OU5qyg==", + "optional": true, "dependencies": { "constantinople": "^4.0.1", "doctypes": "^1.1.0", @@ -18687,12 +20053,14 @@ "node_modules/pug-error": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.0.0.tgz", - "integrity": "sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ==" + "integrity": "sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ==", + "optional": true }, "node_modules/pug-filters": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz", "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==", + "optional": true, "dependencies": { "constantinople": "^4.0.1", "jstransformer": "1.0.0", @@ -18705,6 +20073,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz", "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==", + "optional": true, "dependencies": { "character-parser": "^2.2.0", "is-expression": "^4.0.0", @@ -18715,6 +20084,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz", "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==", + "optional": true, "dependencies": { "pug-error": "^2.0.0", "pug-walk": "^2.0.0" @@ -18724,6 +20094,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz", "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==", + "optional": true, "dependencies": { "object-assign": "^4.1.1", "pug-walk": "^2.0.0" @@ -18733,6 +20104,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz", "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==", + "optional": true, "dependencies": { "pug-error": "^2.0.0", "token-stream": "1.0.0" @@ -18741,12 +20113,14 @@ "node_modules/pug-runtime": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz", - "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==" + "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==", + "optional": true }, "node_modules/pug-strip-comments": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz", "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==", + "optional": true, "dependencies": { "pug-error": "^2.0.0" } @@ -18754,7 +20128,8 @@ "node_modules/pug-walk": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz", - "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==" + "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==", + "optional": true }, "node_modules/pump": { "version": "3.0.0", @@ -19196,6 +20571,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "devOptional": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -19207,6 +20583,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "devOptional": true, "engines": { "node": ">=8.6" }, @@ -19363,6 +20740,7 @@ "version": "0.2.7", "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "optional": true, "engines": { "node": ">= 0.10" } @@ -19622,6 +21000,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-3.2.0.tgz", "integrity": "sha512-Ep0RsvAjnRcBX1p5vogbaBdAGu/8j/ewpvGqnQYunnLd9SM0vWcPJewPKNnWFggf0hF0pwIgwV5XK7qQ7UZ8Qg==", + "optional": true, "dependencies": { "execa": "^0.10.0" }, @@ -19633,6 +21012,7 @@ "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "optional": true, "dependencies": { "nice-try": "^1.0.4", "path-key": "^2.0.1", @@ -19648,6 +21028,7 @@ "version": "0.10.0", "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", + "optional": true, "dependencies": { "cross-spawn": "^6.0.0", "get-stream": "^3.0.0", @@ -19665,6 +21046,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", + "optional": true, "engines": { "node": ">=4" } @@ -19673,6 +21055,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "optional": true, "engines": { "node": ">=0.10.0" } @@ -19681,6 +21064,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "optional": true, "dependencies": { "path-key": "^2.0.0" }, @@ -19692,6 +21076,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "optional": true, "engines": { "node": ">=4" } @@ -19700,6 +21085,7 @@ "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "optional": true, "bin": { "semver": "bin/semver" } @@ -19708,6 +21094,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "optional": true, "dependencies": { "shebang-regex": "^1.0.0" }, @@ -19719,6 +21106,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "optional": true, "engines": { "node": ">=0.10.0" } @@ -19726,12 +21114,14 @@ "node_modules/run-applescript/node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "optional": true }, "node_modules/run-applescript/node_modules/which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "optional": true, "dependencies": { "isexe": "^2.0.0" }, @@ -19923,6 +21313,7 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz", "integrity": "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==", + "optional": true, "dependencies": { "parseley": "^0.12.0" }, @@ -20330,6 +21721,7 @@ "version": "1.12.2", "resolved": "https://registry.npmjs.org/slick/-/slick-1.12.2.tgz", "integrity": "sha512-4qdtOGcBjral6YIBCWJ0ljFSKNLz9KkhbWtuGvUyRowl1kxfuE1x/Z/aJcaiilpb3do9bl5K7/1h9XC5wWpY/A==", + "optional": true, "engines": { "node": "*" } @@ -20587,6 +21979,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", + "optional": true, "engines": { "node": ">=0.10.0" } @@ -21039,6 +22432,7 @@ "version": "1.250.0", "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.250.0.tgz", "integrity": "sha512-rWsBfFCWKrjM/o2Q1TTUeYQv6tHSd/umUutDjVs6taTuEgRDIreVYIBgWRWW4ot7jp6n0UVUuxhTLWBtUmPu/w==", + "optional": true, "bin": { "tlds": "bin.js" } @@ -21099,7 +22493,8 @@ "node_modules/token-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz", - "integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==" + "integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==", + "optional": true }, "node_modules/tr46": { "version": "0.0.3", @@ -21500,12 +22895,14 @@ "node_modules/uc.micro": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", - "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==" + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "optional": true }, "node_modules/uglify-js": { "version": "3.17.4", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "optional": true, "bin": { "uglifyjs": "bin/uglifyjs" }, @@ -21643,7 +23040,8 @@ "node_modules/upper-case": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", - "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==" + "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==", + "optional": true }, "node_modules/uri-js": { "version": "4.4.1", @@ -21720,6 +23118,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-3.0.1.tgz", "integrity": "sha512-jOWVmzVceKlVVdwjNSenT4PbGghU0SBIizAev8ofZVgivk/TVHXSbNL8LP6M3spZvkR9/QolkyJavGSX5Cs0UA==", + "optional": true, "engines": { "node": ">=10" } @@ -21755,6 +23154,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "optional": true, "engines": { "node": ">=0.10.0" } @@ -21804,6 +23204,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/web-resource-inliner/-/web-resource-inliner-6.0.1.tgz", "integrity": "sha512-kfqDxt5dTB1JhqsCUQVFDj0rmY+4HLwGQIsLPbyrsN9y9WV/1oFDSx3BQ4GfCv9X+jVeQ7rouTqwK53rA/7t8A==", + "optional": true, "dependencies": { "ansi-colors": "^4.1.1", "escape-goat": "^3.0.0", @@ -21820,6 +23221,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "optional": true, "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", @@ -21833,6 +23235,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "optional": true, "dependencies": { "domelementtype": "^2.2.0" }, @@ -21847,6 +23250,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", + "optional": true, "dependencies": { "domelementtype": "^2.0.1" }, @@ -21861,6 +23265,7 @@ "version": "2.8.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "optional": true, "dependencies": { "dom-serializer": "^1.0.1", "domelementtype": "^2.2.0", @@ -21874,6 +23279,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "optional": true, "dependencies": { "domelementtype": "^2.2.0" }, @@ -21888,6 +23294,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "optional": true, "funding": { "url": "https://github.com/fb55/entities?sponsor=1" } @@ -21896,6 +23303,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-5.0.1.tgz", "integrity": "sha512-vKZZra6CSe9qsJzh0BjBGXo8dvzNsq/oGvsjfRdOrrryfeD9UOBEEQdeoqCRmKZchF5h2zOBMQ6YuQ0uRUmdbQ==", + "optional": true, "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^3.3.0", @@ -22138,6 +23546,7 @@ "version": "7.0.2", "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==", + "optional": true, "dependencies": { "@babel/parser": "^7.9.6", "@babel/types": "^7.9.6", @@ -22696,6 +24105,947 @@ "tslib": "^2.6.2" } }, + "@aws-sdk/client-ses": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-ses/-/client-ses-3.621.0.tgz", + "integrity": "sha512-dzqIiT12wd5NCDhwofQizV2rr8Ihsxn/13dvIwha+egAXiVo09dM6zVBW1atdHYS0vP/D5i/UB76+xk6JhCasw==", + "requires": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.1", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "@smithy/util-waiter": "^3.1.2", + "tslib": "^2.6.2" + }, + "dependencies": { + "@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "requires": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "requires": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + } + } + } + }, + "@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "requires": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + } + }, + "@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "requires": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "requires": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + } + } + } + }, + "@aws-sdk/client-sso": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", + "integrity": "sha512-xpKfikN4u0BaUYZA9FGUMkkDmfoIP0Q03+A86WjqDWhcOoqNA1DkHsE4kZ+r064ifkPUfcNuUvlkVTEoBZoFjA==", + "requires": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.1", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/client-sso-oidc": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.621.0.tgz", + "integrity": "sha512-mMjk3mFUwV2Y68POf1BQMTF+F6qxt5tPu6daEUCNGC9Cenk3h2YXQQoS4/eSyYzuBiYk3vx49VgleRvdvkg8rg==", + "requires": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.1", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/client-sts": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.621.0.tgz", + "integrity": "sha512-707uiuReSt+nAx6d0c21xLjLm2lxeKc7padxjv92CIrIocnQSlJPxSCM7r5zBhwiahJA6MNQwmTl2xznU67KgA==", + "requires": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.1", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/core": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.621.0.tgz", + "integrity": "sha512-CtOwWmDdEiINkGXD93iGfXjN0WmCp9l45cDWHHGa8lRgEDyhuL7bwd/pH5aSzj0j8SiQBG2k0S7DHbd5RaqvbQ==", + "requires": { + "@smithy/core": "^2.3.1", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/signature-v4": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/credential-provider-env": { + "version": "3.620.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.620.1.tgz", + "integrity": "sha512-ExuILJ2qLW5ZO+rgkNRj0xiAipKT16Rk77buvPP8csR7kkCflT/gXTyzRe/uzIiETTxM7tr8xuO9MP/DQXqkfg==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/credential-provider-http": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.621.0.tgz", + "integrity": "sha512-/jc2tEsdkT1QQAI5Dvoci50DbSxtJrevemwFsm0B73pwCcOQZ5ZwwSdVqGsPutzYzUVx3bcXg3LRL7jLACqRIg==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/util-stream": "^3.1.3", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/credential-provider-ini": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.621.0.tgz", + "integrity": "sha512-0EWVnSc+JQn5HLnF5Xv405M8n4zfdx9gyGdpnCmAmFqEDHA8LmBdxJdpUk1Ovp/I5oPANhjojxabIW5f1uU0RA==", + "requires": { + "@aws-sdk/credential-provider-env": "3.620.1", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-process": "3.620.1", + "@aws-sdk/credential-provider-sso": "3.621.0", + "@aws-sdk/credential-provider-web-identity": "3.621.0", + "@aws-sdk/types": "3.609.0", + "@smithy/credential-provider-imds": "^3.2.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/credential-provider-node": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.621.0.tgz", + "integrity": "sha512-4JqpccUgz5Snanpt2+53hbOBbJQrSFq7E1sAAbgY6BKVQUsW5qyXqnjvSF32kDeKa5JpBl3bBWLZl04IadcPHw==", + "requires": { + "@aws-sdk/credential-provider-env": "3.620.1", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-ini": "3.621.0", + "@aws-sdk/credential-provider-process": "3.620.1", + "@aws-sdk/credential-provider-sso": "3.621.0", + "@aws-sdk/credential-provider-web-identity": "3.621.0", + "@aws-sdk/types": "3.609.0", + "@smithy/credential-provider-imds": "^3.2.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/credential-provider-process": { + "version": "3.620.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.620.1.tgz", + "integrity": "sha512-hWqFMidqLAkaV9G460+1at6qa9vySbjQKKc04p59OT7lZ5cO5VH5S4aI05e+m4j364MBROjjk2ugNvfNf/8ILg==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/credential-provider-sso": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.621.0.tgz", + "integrity": "sha512-Kza0jcFeA/GEL6xJlzR2KFf1PfZKMFnxfGzJzl5yN7EjoGdMijl34KaRyVnfRjnCWcsUpBWKNIDk9WZVMY9yiw==", + "requires": { + "@aws-sdk/client-sso": "3.621.0", + "@aws-sdk/token-providers": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/credential-provider-web-identity": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.621.0.tgz", + "integrity": "sha512-w7ASSyfNvcx7+bYGep3VBgC3K6vEdLmlpjT7nSIHxxQf+WSdvy+HynwJosrpZax0sK5q0D1Jpn/5q+r5lwwW6w==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/middleware-host-header": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.620.0.tgz", + "integrity": "sha512-VMtPEZwqYrII/oUkffYsNWY9PZ9xpNJpMgmyU0rlDQ25O1c0Hk3fJmZRe6pEkAJ0omD7kLrqGl1DUjQVxpd/Rg==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/middleware-logger": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.609.0.tgz", + "integrity": "sha512-S62U2dy4jMDhDFDK5gZ4VxFdWzCtLzwbYyFZx2uvPYTECkepLUfzLic2BHg2Qvtu4QjX+oGE3P/7fwaGIsGNuQ==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/middleware-recursion-detection": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.620.0.tgz", + "integrity": "sha512-nh91S7aGK3e/o1ck64sA/CyoFw+gAYj2BDOnoNa6ouyCrVJED96ZXWbhye/fz9SgmNUZR2g7GdVpiLpMKZoI5w==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/middleware-user-agent": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.620.0.tgz", + "integrity": "sha512-bvS6etn+KsuL32ubY5D3xNof1qkenpbJXf/ugGXbg0n98DvDFQ/F+SMLxHgbnER5dsKYchNnhmtI6/FC3HFu/A==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/region-config-resolver": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.614.0.tgz", + "integrity": "sha512-vDCeMXvic/LU0KFIUjpC3RiSTIkkvESsEfbVHiHH0YINfl8HnEqR5rj+L8+phsCeVg2+LmYwYxd5NRz4PHxt5g==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/token-providers": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.614.0.tgz", + "integrity": "sha512-okItqyY6L9IHdxqs+Z116y5/nda7rHxLvROxtAJdLavWTYDydxrZstImNgGWTeVdmc0xX2gJCI77UYUTQWnhRw==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/types": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", + "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/util-endpoints": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.614.0.tgz", + "integrity": "sha512-wK2cdrXHH4oz4IomV/yrGkftU9A+ITB6nFL+rxxyO78is2ifHJpFdV4aqk4LSkXYPi6CXWNru/Dqc7yiKXgJPw==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "@smithy/util-endpoints": "^2.0.5", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/util-user-agent-browser": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.609.0.tgz", + "integrity": "sha512-fojPU+mNahzQ0YHYBsx0ZIhmMA96H+ZIZ665ObU9tl+SGdbLneVZVikGve+NmHTQwHzwkFsZYYnVKAkreJLAtA==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "@aws-sdk/util-user-agent-node": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.614.0.tgz", + "integrity": "sha512-15ElZT88peoHnq5TEoEtZwoXTXRxNrk60TZNdpl/TUBJ5oNJ9Dqb5Z4ryb8ofN6nm9aFf59GVAerFDz8iUoHBA==", + "requires": { + "@aws-sdk/types": "3.609.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", + "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/config-resolver": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.5.tgz", + "integrity": "sha512-SkW5LxfkSI1bUC74OtfBbdz+grQXYiPYolyu8VfpLIjEoN/sHVBlLeGXMQ1vX4ejkgfv6sxVbQJ32yF2cl1veA==", + "requires": { + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + } + }, + "@smithy/core": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.1.tgz", + "integrity": "sha512-BC7VMXx/1BCmRPCVzzn4HGWAtsrb7/0758EtwOGFJQrlSwJBEjCcDLNZLFoL/68JexYa2s+KmgL/UfmXdG6v1w==", + "requires": { + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + } + }, + "@smithy/credential-provider-imds": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.0.tgz", + "integrity": "sha512-0SCIzgd8LYZ9EJxUjLXBmEKSZR/P/w6l7Rz/pab9culE/RWuqelAKGJvn5qUOl8BgX8Yj5HWM50A5hiB/RzsgA==", + "requires": { + "@smithy/node-config-provider": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "tslib": "^2.6.2" + } + }, + "@smithy/fetch-http-handler": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.4.tgz", + "integrity": "sha512-kBprh5Gs5h7ug4nBWZi1FZthdqSM+T7zMmsZxx0IBvWUn7dK3diz2SHn7Bs4dQGFDk8plDv375gzenDoNwrXjg==", + "requires": { + "@smithy/protocol-http": "^4.1.0", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "@smithy/util-base64": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@smithy/hash-node": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.3.tgz", + "integrity": "sha512-2ctBXpPMG+B3BtWSGNnKELJ7SH9e4TNefJS0cd2eSkOOROeBnnVBnAy9LtJ8tY4vUEoe55N4CNPxzbWvR39iBw==", + "requires": { + "@smithy/types": "^3.3.0", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "requires": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + } + } + } + }, + "@smithy/invalid-dependency": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.3.tgz", + "integrity": "sha512-ID1eL/zpDULmHJbflb864k72/SNOZCADRc9i7Exq3RUNJw6raWUSlFEQ+3PX3EYs++bTxZB2dE9mEHTQLv61tw==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/middleware-content-length": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.5.tgz", + "integrity": "sha512-ILEzC2eyxx6ncej3zZSwMpB5RJ0zuqH7eMptxC4KN3f+v9bqT8ohssKbhNR78k/2tWW+KS5Spw+tbPF4Ejyqvw==", + "requires": { + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/middleware-endpoint": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.1.0.tgz", + "integrity": "sha512-5y5aiKCEwg9TDPB4yFE7H6tYvGFf1OJHNczeY10/EFF8Ir8jZbNntQJxMWNfeQjC1mxPsaQ6mR9cvQbf+0YeMw==", + "requires": { + "@smithy/middleware-serde": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + } + }, + "@smithy/middleware-retry": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.13.tgz", + "integrity": "sha512-zvCLfaRYCaUmjbF2yxShGZdolSHft7NNCTA28HVN9hKcEbOH+g5irr1X9s+in8EpambclGnevZY4A3lYpvDCFw==", + "requires": { + "@smithy/node-config-provider": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/service-error-classification": "^3.0.3", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "tslib": "^2.6.2", + "uuid": "^9.0.1" + } + }, + "@smithy/middleware-serde": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.3.tgz", + "integrity": "sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/middleware-stack": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.3.tgz", + "integrity": "sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/node-config-provider": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.4.tgz", + "integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==", + "requires": { + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/node-http-handler": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.4.tgz", + "integrity": "sha512-+UmxgixgOr/yLsUxcEKGH0fMNVteJFGkmRltYFHnBMlogyFdpzn2CwqWmxOrfJELhV34v0WSlaqG1UtE1uXlJg==", + "requires": { + "@smithy/abort-controller": "^3.1.1", + "@smithy/protocol-http": "^4.1.0", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/property-provider": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", + "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/querystring-builder": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", + "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", + "requires": { + "@smithy/types": "^3.3.0", + "@smithy/util-uri-escape": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@smithy/querystring-parser": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.3.tgz", + "integrity": "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/service-error-classification": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.3.tgz", + "integrity": "sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ==", + "requires": { + "@smithy/types": "^3.3.0" + } + }, + "@smithy/shared-ini-file-loader": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.4.tgz", + "integrity": "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/signature-v4": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.1.0.tgz", + "integrity": "sha512-aRryp2XNZeRcOtuJoxjydO6QTaVhxx/vjaR+gx7ZjaFgrgPRyZ3HCTbfwqYj6ZWEBHkCSUfcaymKPURaByukag==", + "requires": { + "@smithy/is-array-buffer": "^3.0.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-uri-escape": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + } + }, + "@smithy/smithy-client": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", + "requires": { + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "@smithy/util-stream": "^3.1.3", + "tslib": "^2.6.2" + } + }, + "@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/url-parser": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.3.tgz", + "integrity": "sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A==", + "requires": { + "@smithy/querystring-parser": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-base64": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", + "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", + "requires": { + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "requires": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + } + } + } + }, + "@smithy/util-body-length-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-3.0.0.tgz", + "integrity": "sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-body-length-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", + "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-config-provider": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", + "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-defaults-mode-browser": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.13.tgz", + "integrity": "sha512-ZIRSUsnnMRStOP6OKtW+gCSiVFkwnfQF2xtf32QKAbHR6ACjhbAybDvry+3L5qQYdh3H6+7yD/AiUE45n8mTTw==", + "requires": { + "@smithy/property-provider": "^3.1.3", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-defaults-mode-node": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.13.tgz", + "integrity": "sha512-voUa8TFJGfD+U12tlNNLCDlXibt9vRdNzRX45Onk/WxZe7TS+hTOZouEZRa7oARGicdgeXvt1A0W45qLGYdy+g==", + "requires": { + "@smithy/config-resolver": "^3.0.5", + "@smithy/credential-provider-imds": "^3.2.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-endpoints": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.0.5.tgz", + "integrity": "sha512-ReQP0BWihIE68OAblC/WQmDD40Gx+QY1Ez8mTdFMXpmjfxSyz2fVQu3A4zXRfQU9sZXtewk3GmhfOHswvX+eNg==", + "requires": { + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-hex-encoding": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", + "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-middleware": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.3.tgz", + "integrity": "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==", + "requires": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-retry": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.3.tgz", + "integrity": "sha512-AFw+hjpbtVApzpNDhbjNG5NA3kyoMs7vx0gsgmlJF4s+yz1Zlepde7J58zpIRIsdjc+emhpAITxA88qLkPF26w==", + "requires": { + "@smithy/service-error-classification": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "@smithy/util-stream": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.1.3.tgz", + "integrity": "sha512-FIv/bRhIlAxC0U7xM1BCnF2aDRPq0UaelqBHkM2lsCp26mcBbgI0tCVTv+jGdsQLUmAMybua/bjDsSu8RQHbmw==", + "requires": { + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "requires": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + } + } + } + }, + "@smithy/util-uri-escape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", + "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "requires": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "requires": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + } + } + } + }, + "@smithy/util-waiter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-3.1.2.tgz", + "integrity": "sha512-4pP0EV3iTsexDx+8PPGAKCQpd/6hsQBaQhqWzU4hqKPHN5epPsxKbvUTIiYIHTxaKt6/kEaqPBpu/ufvfbrRzw==", + "requires": { + "@smithy/abort-controller": "^3.1.1", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + } + }, + "fast-xml-parser": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", + "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", + "requires": { + "strnum": "^1.0.5" + } + } + } + }, "@aws-sdk/client-sso": { "version": "3.556.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.556.0.tgz", @@ -24779,66 +27129,80 @@ } }, "@css-inline/css-inline": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline/-/css-inline-0.13.0.tgz", - "integrity": "sha512-ZozAXBiW1I8hf6eW5eTNqhxUdNOBxrNNxxUnQRiKQpWcs5ORuGaiWwV5focMBTJ5WXGN+Z8VLP93BOwWFPzCJw==", - "requires": { - "@css-inline/css-inline-darwin-arm64": "0.13.0", - "@css-inline/css-inline-darwin-x64": "0.13.0", - "@css-inline/css-inline-linux-arm-gnueabihf": "0.13.0", - "@css-inline/css-inline-linux-arm64-gnu": "0.13.0", - "@css-inline/css-inline-linux-arm64-musl": "0.13.0", - "@css-inline/css-inline-linux-x64-gnu": "0.13.0", - "@css-inline/css-inline-linux-x64-musl": "0.13.0", - "@css-inline/css-inline-win32-x64-msvc": "0.13.0" - } + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline/-/css-inline-0.14.1.tgz", + "integrity": "sha512-u4eku+hnPqqHIGq/ZUQcaP0TrCbYeLIYBaK7qClNRGZbnh8RC4gVxLEIo8Pceo1nOK9E5G4Lxzlw5KnXcvflfA==", + "requires": { + "@css-inline/css-inline-android-arm-eabi": "0.14.1", + "@css-inline/css-inline-android-arm64": "0.14.1", + "@css-inline/css-inline-darwin-arm64": "0.14.1", + "@css-inline/css-inline-darwin-x64": "0.14.1", + "@css-inline/css-inline-linux-arm-gnueabihf": "0.14.1", + "@css-inline/css-inline-linux-arm64-gnu": "0.14.1", + "@css-inline/css-inline-linux-arm64-musl": "0.14.1", + "@css-inline/css-inline-linux-x64-gnu": "0.14.1", + "@css-inline/css-inline-linux-x64-musl": "0.14.1", + "@css-inline/css-inline-win32-x64-msvc": "0.14.1" + } + }, + "@css-inline/css-inline-android-arm-eabi": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-android-arm-eabi/-/css-inline-android-arm-eabi-0.14.1.tgz", + "integrity": "sha512-LNUR8TY4ldfYi0mi/d4UNuHJ+3o8yLQH9r2Nt6i4qeg1i7xswfL3n/LDLRXvGjBYqeEYNlhlBQzbPwMX1qrU6A==", + "optional": true + }, + "@css-inline/css-inline-android-arm64": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-android-arm64/-/css-inline-android-arm64-0.14.1.tgz", + "integrity": "sha512-tH5us0NYGoTNBHOUHVV7j9KfJ4DtFOeTLA3cM0XNoMtArNu2pmaaBMFJPqECzavfXkLc7x5Z22UPZYjoyHfvCA==", + "optional": true }, "@css-inline/css-inline-darwin-arm64": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-darwin-arm64/-/css-inline-darwin-arm64-0.13.0.tgz", - "integrity": "sha512-A4QvlZdhp8v+3IHKF/UftRf5GrAVUMEHCGRuk2Dx594xn/UR4ieh+B70aMm5rfONh2hv5mlR9UcoYAkVpEQ99g==", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-darwin-arm64/-/css-inline-darwin-arm64-0.14.1.tgz", + "integrity": "sha512-QE5W1YRIfRayFrtrcK/wqEaxNaqLULPI0gZB4ArbFRd3d56IycvgBasDTHPre5qL2cXCO3VyPx+80XyHOaVkag==", "optional": true }, "@css-inline/css-inline-darwin-x64": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-darwin-x64/-/css-inline-darwin-x64-0.13.0.tgz", - "integrity": "sha512-px9z4ypzeECMyBEtlrNzTMpA1tnw5MmMIiMkBRhb8UGRr2pOBZY3yd/eEIxWzVVSPt0aIjVDwUOJ3+d0Z+BskA==", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-darwin-x64/-/css-inline-darwin-x64-0.14.1.tgz", + "integrity": "sha512-mAvv2sN8awNFsbvBzlFkZPbCNZ6GCWY5/YcIz7V5dPYw+bHHRbjnlkNTEZq5BsDxErVrMIGvz05PGgzuNvZvdQ==", "optional": true }, "@css-inline/css-inline-linux-arm-gnueabihf": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-arm-gnueabihf/-/css-inline-linux-arm-gnueabihf-0.13.0.tgz", - "integrity": "sha512-+uo0coLQNgk/AKeOB8mXSRd8VIlUg38zRSB9B9q0ior9oBCDPtEdn1HuCSvWxHoOSJ8QNNk+uwbz0zW4CETzFw==", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-arm-gnueabihf/-/css-inline-linux-arm-gnueabihf-0.14.1.tgz", + "integrity": "sha512-AWC44xL0X7BgKvrWEqfSqkT2tJA5kwSGrAGT+m0gt11wnTYySvQ6YpX0fTY9i3ppYGu4bEdXFjyK2uY1DTQMHA==", "optional": true }, "@css-inline/css-inline-linux-arm64-gnu": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-arm64-gnu/-/css-inline-linux-arm64-gnu-0.13.0.tgz", - "integrity": "sha512-GVrsFbY5l0Hxyzxsm5S5JPGObvHm/Ybf2wZgnWBsQigxqGtr1FL535HaTwEnq6aHOpH3f08gR5Vx33gB7jG4pw==", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-arm64-gnu/-/css-inline-linux-arm64-gnu-0.14.1.tgz", + "integrity": "sha512-drj0ciiJgdP3xKXvNAt4W+FH4KKMs8vB5iKLJ3HcH07sNZj58Sx++2GxFRS1el3p+GFp9OoYA6dgouJsGEqt0Q==", "optional": true }, "@css-inline/css-inline-linux-arm64-musl": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-arm64-musl/-/css-inline-linux-arm64-musl-0.13.0.tgz", - "integrity": "sha512-V5h5+CRnE01EgoafI/kyjEcM8zvN+sKLnp17Aq9LqQfsut7mO3i72d8g/xeVC37DCLoGQFLvDCzbze2NbF2dIQ==", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-arm64-musl/-/css-inline-linux-arm64-musl-0.14.1.tgz", + "integrity": "sha512-FzknI+st8eA8YQSdEJU9ykcM0LZjjigBuynVF5/p7hiMm9OMP8aNhWbhZ8LKJpKbZrQsxSGS4g9Vnr6n6FiSdQ==", "optional": true }, "@css-inline/css-inline-linux-x64-gnu": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-x64-gnu/-/css-inline-linux-x64-gnu-0.13.0.tgz", - "integrity": "sha512-vbRV++73MW7dvz/AIbozkv4R68/k/sEp57hno/L6lx034VYxpCwdfqtGN4D0W1TOTzdr2b6qBOGNZ1oLKQZOQQ==", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-x64-gnu/-/css-inline-linux-x64-gnu-0.14.1.tgz", + "integrity": "sha512-yubbEye+daDY/4vXnyASAxH88s256pPati1DfVoZpU1V0+KP0BZ1dByZOU1ktExurbPH3gZOWisAnBE9xon0Uw==", "optional": true }, "@css-inline/css-inline-linux-x64-musl": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-x64-musl/-/css-inline-linux-x64-musl-0.13.0.tgz", - "integrity": "sha512-2tCnwU23W/yMs9cGc2/i2jd9y2pjuntx0a5OytqX7s9fvUtmI3nc0Od6wuf51LnmdU+XAU8HLT9pZppsQiwPfQ==", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-x64-musl/-/css-inline-linux-x64-musl-0.14.1.tgz", + "integrity": "sha512-6CRAZzoy1dMLPC/tns2rTt1ZwPo0nL/jYBEIAsYTCWhfAnNnpoLKVh5Nm+fSU3OOwTTqU87UkGrFJhObD/wobQ==", "optional": true }, "@css-inline/css-inline-win32-x64-msvc": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-win32-x64-msvc/-/css-inline-win32-x64-msvc-0.13.0.tgz", - "integrity": "sha512-6VFhFSXp4FH+NzJhLd6fFi7jKCPvIRW+vq0tV+CPuiQ3zPzMfC9nIk8sB/1VJR8EcvBAjMV53YnacuDjRFRT9g==", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-win32-x64-msvc/-/css-inline-win32-x64-msvc-0.14.1.tgz", + "integrity": "sha512-nzotGiaiuiQW78EzsiwsHZXbxEt6DiMUFcDJ6dhiliomXxnlaPyBfZb6/FMBgRJOf6sknDt/5695OttNmbMYzg==", "optional": true }, "@dabh/diagnostics": { @@ -26201,19 +28565,35 @@ } }, "@nestjs-modules/mailer": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/@nestjs-modules/mailer/-/mailer-1.11.2.tgz", - "integrity": "sha512-k07wyKbtCzxWMm6IqGwcGIisnXD/6sneGvUR8rBBZbxtLn1HE1FLGyiaXBrPui/0K7W41aS9x9jAIhfTawtlUg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@nestjs-modules/mailer/-/mailer-2.0.2.tgz", + "integrity": "sha512-+z4mADQasg0H1ZaGu4zZTuKv2pu+XdErqx99PLFPzCDNTN/q9U59WPgkxVaHnsvKHNopLj5Xap7G4ZpptduoYw==", "requires": { - "@css-inline/css-inline": "0.13.0", + "@css-inline/css-inline": "0.14.1", "@types/ejs": "^3.1.5", + "@types/mjml": "^4.7.4", "@types/pug": "^2.0.10", - "ejs": "^3.1.9", - "glob": "10.3.10", + "ejs": "^3.1.10", + "glob": "10.3.12", "handlebars": "^4.7.8", - "mjml": "4.15.3", - "preview-email": "3.0.19", + "liquidjs": "^10.11.1", + "mjml": "^4.15.3", + "preview-email": "^3.0.19", "pug": "^3.0.2" + }, + "dependencies": { + "glob": { + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", + "requires": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.6", + "minimatch": "^9.0.1", + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" + } + } } }, "@nestjs/class-transformer": { @@ -26515,7 +28895,8 @@ "@one-ini/wasm": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz", - "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==" + "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", + "optional": true }, "@pkgjs/parseargs": { "version": "0.11.0", @@ -27738,6 +30119,7 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz", "integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==", + "optional": true, "requires": { "domhandler": "^5.0.3", "selderee": "^0.11.0" @@ -28579,6 +30961,21 @@ "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", "dev": true }, + "@types/mjml": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/@types/mjml/-/mjml-4.7.4.tgz", + "integrity": "sha512-vyi1vzWgMzFMwZY7GSZYX0GU0dmtC8vLHwpgk+NWmwbwRSrlieVyJ9sn5elodwUfklJM7yGl0zQeet1brKTWaQ==", + "optional": true, + "requires": { + "@types/mjml-core": "*" + } + }, + "@types/mjml-core": { + "version": "4.15.0", + "resolved": "https://registry.npmjs.org/@types/mjml-core/-/mjml-core-4.15.0.tgz", + "integrity": "sha512-jSRWTOpwRS/uHIBfGdvLl0a7MaoBZZYHKI+HhsFYChrUOKVJTnjSYsuV6wx0snv6ZaX3TUo5OP/gNsz/uzZz1A==", + "optional": true + }, "@types/morgan": { "version": "1.9.9", "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.9.tgz", @@ -29021,7 +31418,8 @@ "abbrev": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", - "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==" + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "optional": true }, "abort-controller": { "version": "3.0.0", @@ -29109,6 +31507,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/alce/-/alce-1.2.0.tgz", "integrity": "sha512-XppPf2S42nO2WhvKzlwzlfcApcXHzjlod30pKmcWjRgLOtqoe5DMuqdiYoM6AgyXksc6A6pV4v1L/WW217e57w==", + "optional": true, "requires": { "esprima": "^1.2.0", "estraverse": "^1.5.0" @@ -29117,12 +31516,14 @@ "esprima": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz", - "integrity": "sha512-S9VbPDU0adFErpDai3qDkjq8+G05ONtKzcyNrPKg/ZKa+tf879nX2KexNU95b31UoTJjRLInNBHHHjFPoCd7lQ==" + "integrity": "sha512-S9VbPDU0adFErpDai3qDkjq8+G05ONtKzcyNrPKg/ZKa+tf879nX2KexNU95b31UoTJjRLInNBHHHjFPoCd7lQ==", + "optional": true }, "estraverse": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", - "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==" + "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==", + "optional": true } } }, @@ -29135,7 +31536,8 @@ "ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==" + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "devOptional": true }, "ansi-escapes": { "version": "4.3.2", @@ -29283,7 +31685,8 @@ "assert-never": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.2.1.tgz", - "integrity": "sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==" + "integrity": "sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==", + "optional": true }, "ast-types": { "version": "0.15.2", @@ -29505,6 +31908,7 @@ "version": "3.0.0-canary-5", "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==", + "optional": true, "requires": { "@babel/types": "^7.9.6" } @@ -29537,7 +31941,8 @@ "binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==" + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "devOptional": true }, "bl": { "version": "4.1.0", @@ -29560,14 +31965,6 @@ } } }, - "blake2": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/blake2/-/blake2-5.0.0.tgz", - "integrity": "sha512-MLpq1DwBB9rC0IHuRc2gXLEAeNNTTYHEtvYCA5lK4RmoUPRmQLSLQrwgJvou62BvH9KP7whe8n+xxw45++fnYg==", - "requires": { - "nan": "^2.17.0" - } - }, "blake2b": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/blake2b/-/blake2b-2.1.4.tgz", @@ -29683,7 +32080,8 @@ "boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "optional": true }, "bowser": { "version": "2.11.0", @@ -29842,6 +32240,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==", + "optional": true, "requires": { "no-case": "^2.2.0", "upper-case": "^1.1.1" @@ -29886,6 +32285,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", "integrity": "sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==", + "optional": true, "requires": { "is-regex": "^1.0.3" } @@ -29900,6 +32300,7 @@ "version": "1.0.0-rc.12", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "optional": true, "requires": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", @@ -29914,6 +32315,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "optional": true, "requires": { "boolbase": "^1.0.0", "css-select": "^5.1.0", @@ -29927,6 +32329,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "devOptional": true, "requires": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -30067,6 +32470,7 @@ "version": "4.2.4", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", + "optional": true, "requires": { "source-map": "~0.6.0" }, @@ -30074,7 +32478,8 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true } } }, @@ -30444,6 +32849,7 @@ "version": "1.1.13", "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "optional": true, "requires": { "ini": "^1.3.4", "proto-list": "~1.2.1" @@ -30517,6 +32923,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==", + "optional": true, "requires": { "@babel/parser": "^7.6.0", "@babel/types": "^7.6.1" @@ -30644,6 +33051,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "optional": true, "requires": { "boolbase": "^1.0.0", "css-what": "^6.1.0", @@ -30655,7 +33063,8 @@ "css-what": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==" + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "optional": true }, "datastore-core": { "version": "9.2.9", @@ -30841,7 +33250,8 @@ "detect-indent": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", - "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==" + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "optional": true }, "detect-libc": { "version": "2.0.3", @@ -30851,12 +33261,14 @@ "detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==" + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "devOptional": true }, "detect-node": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "optional": true }, "dezalgo": { "version": "1.0.4", @@ -30892,6 +33304,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/display-notification/-/display-notification-2.0.0.tgz", "integrity": "sha512-TdmtlAcdqy1NU+j7zlkDdMnCL878zriLaBmoD9quOoq1ySSSGv03l0hXK5CvIFZlIfFI/hizqdQuW+Num7xuhw==", + "optional": true, "requires": { "escape-string-applescript": "^1.0.0", "run-applescript": "^3.0.0" @@ -30917,12 +33330,14 @@ "doctypes": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", - "integrity": "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==" + "integrity": "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==", + "optional": true }, "dom-serializer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "optional": true, "requires": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -30932,12 +33347,14 @@ "domelementtype": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "optional": true }, "domhandler": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "optional": true, "requires": { "domelementtype": "^2.3.0" } @@ -30946,6 +33363,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "optional": true, "requires": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", @@ -30979,6 +33397,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", + "optional": true, "requires": { "@one-ini/wasm": "0.1.1", "commander": "^10.0.0", @@ -30989,12 +33408,14 @@ "commander": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==" + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "optional": true }, "minimatch": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "optional": true, "requires": { "brace-expansion": "^2.0.1" } @@ -31044,7 +33465,8 @@ "encoding-japanese": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encoding-japanese/-/encoding-japanese-2.0.0.tgz", - "integrity": "sha512-++P0RhebUC8MJAwJOsT93dT+5oc5oPImp1HubZpAuCZ5kTLnhuuBhKHj2jJeO/Gj93idPBWmIuQ9QWMe5rX3pQ==" + "integrity": "sha512-++P0RhebUC8MJAwJOsT93dT+5oc5oPImp1HubZpAuCZ5kTLnhuuBhKHj2jJeO/Gj93idPBWmIuQ9QWMe5rX3pQ==", + "optional": true }, "end-of-stream": { "version": "1.4.4", @@ -31067,7 +33489,8 @@ "entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "optional": true }, "envinfo": { "version": "7.12.0", @@ -31134,7 +33557,8 @@ "escape-goat": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-3.0.0.tgz", - "integrity": "sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==" + "integrity": "sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==", + "optional": true }, "escape-html": { "version": "1.0.3", @@ -31144,7 +33568,8 @@ "escape-string-applescript": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/escape-string-applescript/-/escape-string-applescript-1.0.0.tgz", - "integrity": "sha512-4/hFwoYaC6TkpDn9A3pTC52zQPArFeXuIfhUtCGYdauTzXVP9H3BDr3oO/QzQehMpLDC7srvYgfwvImPFGfvBA==" + "integrity": "sha512-4/hFwoYaC6TkpDn9A3pTC52zQPArFeXuIfhUtCGYdauTzXVP9H3BDr3oO/QzQehMpLDC7srvYgfwvImPFGfvBA==", + "optional": true }, "escape-string-regexp": { "version": "4.0.0", @@ -31467,7 +33892,8 @@ "extend-object": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/extend-object/-/extend-object-1.0.0.tgz", - "integrity": "sha512-0dHDIXC7y7LDmCh/lp1oYkmv73K25AMugQI07r8eFopkW6f7Ufn1q+ETMsJjnV9Am14SlElkqy3O92r6xEaxPw==" + "integrity": "sha512-0dHDIXC7y7LDmCh/lp1oYkmv73K25AMugQI07r8eFopkW6f7Ufn1q+ETMsJjnV9Am14SlElkqy3O92r6xEaxPw==", + "optional": true }, "external-editor": { "version": "3.1.0", @@ -31841,6 +34267,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/fixpack/-/fixpack-4.0.0.tgz", "integrity": "sha512-5SM1+H2CcuJ3gGEwTiVo/+nd/hYpNj9Ch3iMDOQ58ndY+VGQ2QdvaUTkd3otjZvYnd/8LF/HkJ5cx7PBq0orCQ==", + "optional": true, "requires": { "alce": "1.2.0", "chalk": "^3.0.0", @@ -31854,6 +34281,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "optional": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -32114,7 +34542,8 @@ "get-port": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", - "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==" + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "optional": true }, "get-stream": { "version": "6.0.1", @@ -32142,6 +34571,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "devOptional": true, "requires": { "is-glob": "^4.0.1" } @@ -32255,6 +34685,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "devOptional": true, "requires": { "has-symbols": "^1.0.3" } @@ -32275,7 +34706,8 @@ "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "optional": true }, "helia": { "version": "4.1.1", @@ -32361,6 +34793,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz", "integrity": "sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==", + "optional": true, "requires": { "camel-case": "^3.0.0", "clean-css": "^4.2.1", @@ -32374,7 +34807,8 @@ "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "optional": true } } }, @@ -32382,6 +34816,7 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz", "integrity": "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==", + "optional": true, "requires": { "@selderee/plugin-htmlparser2": "^0.11.0", "deepmerge": "^4.3.1", @@ -32394,6 +34829,7 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "optional": true, "requires": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", @@ -32673,6 +35109,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "devOptional": true, "requires": { "binary-extensions": "^2.0.0" } @@ -32716,6 +35153,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", + "optional": true, "requires": { "acorn": "^7.1.1", "object-assign": "^4.1.1" @@ -32724,14 +35162,16 @@ "acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "optional": true } } }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "devOptional": true }, "is-fullwidth-code-point": { "version": "2.0.0", @@ -32758,6 +35198,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "devOptional": true, "requires": { "is-extglob": "^2.1.1" } @@ -32805,12 +35246,14 @@ "is-promise": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "optional": true }, "is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "optional": true, "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -33777,6 +36220,7 @@ "version": "1.15.1", "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.1.tgz", "integrity": "sha512-ESjNzSlt/sWE8sciZH8kBF8BPlwXPwhR6pWKAw8bw4Bwj+iZcnKW6ONWUutJ7eObuBZQpiIb8S7OYspWrKt7rA==", + "optional": true, "requires": { "config-chain": "^1.1.13", "editorconfig": "^1.0.4", @@ -33788,12 +36232,14 @@ "js-cookie": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", - "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==" + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "optional": true }, "js-stringify": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", - "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==" + "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==", + "optional": true }, "js-tokens": { "version": "4.0.0", @@ -33957,6 +36403,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", "integrity": "sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==", + "optional": true, "requires": { "is-promise": "^2.0.0", "promise": "^7.0.1" @@ -33966,6 +36413,7 @@ "version": "10.0.0", "resolved": "https://registry.npmjs.org/juice/-/juice-10.0.0.tgz", "integrity": "sha512-9f68xmhGrnIi6DBkiiP3rUrQN33SEuaKu1+njX6VgMP+jwZAsnT33WIzlrWICL9matkhYu3OyrqSUP55YTIdGg==", + "optional": true, "requires": { "cheerio": "^1.0.0-rc.12", "commander": "^6.1.0", @@ -33977,7 +36425,8 @@ "commander": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==" + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "optional": true } } }, @@ -34028,7 +36477,8 @@ "leac": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz", - "integrity": "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==" + "integrity": "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==", + "optional": true }, "level": { "version": "8.0.1", @@ -34072,12 +36522,14 @@ "libbase64": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-1.3.0.tgz", - "integrity": "sha512-GgOXd0Eo6phYgh0DJtjQ2tO8dc0IVINtZJeARPeiIJqge+HdsWSuaDTe8ztQ7j/cONByDZ3zeB325AHiv5O0dg==" + "integrity": "sha512-GgOXd0Eo6phYgh0DJtjQ2tO8dc0IVINtZJeARPeiIJqge+HdsWSuaDTe8ztQ7j/cONByDZ3zeB325AHiv5O0dg==", + "optional": true }, "libmime": { "version": "5.3.4", "resolved": "https://registry.npmjs.org/libmime/-/libmime-5.3.4.tgz", "integrity": "sha512-TsqPdercr6DHrnoQx1F0nS2Y4yPT+fWuOjEP2rqzvV77hMYWomTe/rpm0u9JORQ/FavEXybAGcBJsQbLr9+hjA==", + "optional": true, "requires": { "encoding-japanese": "2.0.0", "iconv-lite": "0.6.3", @@ -34089,6 +36541,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, "requires": { "safer-buffer": ">= 2.1.2 < 3.0.0" } @@ -34131,7 +36584,8 @@ "libqp": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/libqp/-/libqp-2.1.0.tgz", - "integrity": "sha512-O6O6/fsG5jiUVbvdgT7YX3xY3uIadR6wEZ7+vy9u7PKHAlSEB6blvC1o5pHBjgsi95Uo0aiBBdkyFecj6jtb7A==" + "integrity": "sha512-O6O6/fsG5jiUVbvdgT7YX3xY3uIadR6wEZ7+vy9u7PKHAlSEB6blvC1o5pHBjgsi95Uo0aiBBdkyFecj6jtb7A==", + "optional": true }, "light-my-request": { "version": "5.13.0", @@ -34189,10 +36643,28 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "optional": true, "requires": { "uc.micro": "^2.0.0" } }, + "liquidjs": { + "version": "10.16.1", + "resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-10.16.1.tgz", + "integrity": "sha512-1JFL/Y7ONoajrfwav37yuz5yQHU3+Pgz1XWsg9E/2T8Fp65KalNfMF8QZ3+tNETqGUIB66waOSLOi64niYZE9A==", + "optional": true, + "requires": { + "commander": "^10.0.0" + }, + "dependencies": { + "commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "optional": true + } + } + }, "loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", @@ -34418,7 +36890,8 @@ "lower-case": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", - "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==" + "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==", + "optional": true }, "lru-cache": { "version": "5.1.1", @@ -34446,6 +36919,7 @@ "version": "3.7.0", "resolved": "https://registry.npmjs.org/mailparser/-/mailparser-3.7.0.tgz", "integrity": "sha512-yFo1+4r3gHhTcazVGCv3D/uX5VJyyrx4iWkzKtJh8mujYIUm92kpG5BjKpZIJgEoKcKxbJVd4CPs+IImE1sKlQ==", + "optional": true, "requires": { "encoding-japanese": "2.0.0", "he": "1.2.0", @@ -34463,6 +36937,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, "requires": { "safer-buffer": ">= 2.1.2 < 3.0.0" } @@ -34470,7 +36945,8 @@ "nodemailer": { "version": "6.9.11", "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.11.tgz", - "integrity": "sha512-UiAkgiERuG94kl/3bKfE8o10epvDnl0vokNEtZDPTq9BWzIl6EFT9336SbIT4oaTBD8NmmUTLsQyXHV82eXSWg==" + "integrity": "sha512-UiAkgiERuG94kl/3bKfE8o10epvDnl0vokNEtZDPTq9BWzIl6EFT9336SbIT4oaTBD8NmmUTLsQyXHV82eXSWg==", + "optional": true } } }, @@ -34478,6 +36954,7 @@ "version": "5.4.0", "resolved": "https://registry.npmjs.org/mailsplit/-/mailsplit-5.4.0.tgz", "integrity": "sha512-wnYxX5D5qymGIPYLwnp6h8n1+6P6vz/MJn5AzGjZ8pwICWssL+CCQjWBIToOVHASmATot4ktvlLo6CyLfOXWYA==", + "optional": true, "requires": { "libbase64": "1.2.1", "libmime": "5.2.0", @@ -34488,6 +36965,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, "requires": { "safer-buffer": ">= 2.1.2 < 3.0.0" } @@ -34495,12 +36973,14 @@ "libbase64": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-1.2.1.tgz", - "integrity": "sha512-l+nePcPbIG1fNlqMzrh68MLkX/gTxk/+vdvAb388Ssi7UuUN31MI44w4Yf33mM3Cm4xDfw48mdf3rkdHszLNew==" + "integrity": "sha512-l+nePcPbIG1fNlqMzrh68MLkX/gTxk/+vdvAb388Ssi7UuUN31MI44w4Yf33mM3Cm4xDfw48mdf3rkdHszLNew==", + "optional": true }, "libmime": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/libmime/-/libmime-5.2.0.tgz", "integrity": "sha512-X2U5Wx0YmK0rXFbk67ASMeqYIkZ6E5vY7pNWRKtnNzqjvdYYG8xtPDpCnuUEnPU9vlgNev+JoSrcaKSUaNvfsw==", + "optional": true, "requires": { "encoding-japanese": "2.0.0", "iconv-lite": "0.6.3", @@ -34511,7 +36991,8 @@ "libqp": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/libqp/-/libqp-2.0.1.tgz", - "integrity": "sha512-Ka0eC5LkF3IPNQHJmYBWljJsw0UvM6j+QdKRbWyCdTmYwvIDE6a7bCm0UkTAL/K+3KXK5qXT/ClcInU01OpdLg==" + "integrity": "sha512-Ka0eC5LkF3IPNQHJmYBWljJsw0UvM6j+QdKRbWyCdTmYwvIDE6a7bCm0UkTAL/K+3KXK5qXT/ClcInU01OpdLg==", + "optional": true } } }, @@ -34567,7 +37048,8 @@ "mensch": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/mensch/-/mensch-0.3.4.tgz", - "integrity": "sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==" + "integrity": "sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==", + "optional": true }, "merge-descriptors": { "version": "1.0.1", @@ -35193,6 +37675,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml/-/mjml-4.15.3.tgz", "integrity": "sha512-bW2WpJxm6HS+S3Yu6tq1DUPFoTxU9sPviUSmnL7Ua+oVO3WA5ILFWqvujUlz+oeuM+HCwEyMiP5xvKNPENVjYA==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "mjml-cli": "4.15.3", @@ -35206,6 +37689,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-accordion/-/mjml-accordion-4.15.3.tgz", "integrity": "sha512-LPNVSj1LyUVYT9G1gWwSw3GSuDzDsQCu0tPB2uDsq4VesYNnU6v3iLCQidMiR6azmIt13OEozG700ygAUuA6Ng==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -35216,6 +37700,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-body/-/mjml-body-4.15.3.tgz", "integrity": "sha512-7pfUOVPtmb0wC+oUOn4xBsAw4eT5DyD6xqaxj/kssu6RrFXOXgJaVnDPAI9AzIvXJ/5as9QrqRGYAddehwWpHQ==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -35226,6 +37711,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-button/-/mjml-button-4.15.3.tgz", "integrity": "sha512-79qwn9AgdGjJR1vLnrcm2rq2AsAZkKC5JPwffTMG+Nja6zGYpTDZFZ56ekHWr/r1b5WxkukcPj2PdevUug8c+Q==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -35236,6 +37722,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-carousel/-/mjml-carousel-4.15.3.tgz", "integrity": "sha512-3ju6I4l7uUhPRrJfN3yK9AMsfHvrYbRkcJ1GRphFHzUj37B2J6qJOQUpzA547Y4aeh69TSb7HFVf1t12ejQxVw==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -35246,6 +37733,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-cli/-/mjml-cli-4.15.3.tgz", "integrity": "sha512-+V2TDw3tXUVEptFvLSerz125C2ogYl8klIBRY1m5BHd4JvGVf3yhx8N3PngByCzA6PGcv/eydGQN+wy34SHf0Q==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "chokidar": "^3.0.0", @@ -35265,6 +37753,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-column/-/mjml-column-4.15.3.tgz", "integrity": "sha512-hYdEFdJGHPbZJSEysykrevEbB07yhJGSwfDZEYDSbhQQFjV2tXrEgYcFD5EneMaowjb55e3divSJxU4c5q4Qgw==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -35275,6 +37764,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-core/-/mjml-core-4.15.3.tgz", "integrity": "sha512-Dmwk+2cgSD9L9GmTbEUNd8QxkTZtW9P7FN/ROZW/fGZD6Hq6/4TB0zEspg2Ow9eYjZXO2ofOJ3PaQEEShKV0kQ==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "cheerio": "1.0.0-rc.12", @@ -35292,6 +37782,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-divider/-/mjml-divider-4.15.3.tgz", "integrity": "sha512-vh27LQ9FG/01y0b9ntfqm+GT5AjJnDSDY9hilss2ixIUh0FemvfGRfsGVeV5UBVPBKK7Ffhvfqc7Rciob9Spzw==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -35302,6 +37793,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-group/-/mjml-group-4.15.3.tgz", "integrity": "sha512-HSu/rKnGZVKFq3ciT46vi1EOy+9mkB0HewO4+P6dP/Y0UerWkN6S3UK11Cxsj0cAp0vFwkPDCdOeEzRdpFEkzA==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -35312,6 +37804,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-head/-/mjml-head-4.15.3.tgz", "integrity": "sha512-o3mRuuP/MB5fZycjD3KH/uXsnaPl7Oo8GtdbJTKtH1+O/3pz8GzGMkscTKa97l03DAG2EhGrzzLcU2A6eshwFw==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -35322,6 +37815,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-head-attributes/-/mjml-head-attributes-4.15.3.tgz", "integrity": "sha512-2ISo0r5ZKwkrvJgDou9xVPxxtXMaETe2AsAA02L89LnbB2KC0N5myNsHV0sEysTw9+CfCmgjAb0GAI5QGpxKkQ==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -35332,6 +37826,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-head-breakpoint/-/mjml-head-breakpoint-4.15.3.tgz", "integrity": "sha512-Eo56FA5C2v6ucmWQL/JBJ2z641pLOom4k0wP6CMZI2utfyiJ+e2Uuinj1KTrgDcEvW4EtU9HrfAqLK9UosLZlg==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -35342,6 +37837,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-head-font/-/mjml-head-font-4.15.3.tgz", "integrity": "sha512-CzV2aDPpiNIIgGPHNcBhgyedKY4SX3BJoTwOobSwZVIlEA6TAWB4Z9WwFUmQqZOgo1AkkiTHPZQvGcEhFFXH6g==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -35352,6 +37848,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-head-html-attributes/-/mjml-head-html-attributes-4.15.3.tgz", "integrity": "sha512-MDNDPMBOgXUZYdxhosyrA2kudiGO8aogT0/cODyi2Ed9o/1S7W+je11JUYskQbncqhWKGxNyaP4VWa+6+vUC/g==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -35362,6 +37859,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-head-preview/-/mjml-head-preview-4.15.3.tgz", "integrity": "sha512-J2PxCefUVeFwsAExhrKo4lwxDevc5aKj888HBl/wN4EuWOoOg06iOGCxz4Omd8dqyFsrqvbBuPqRzQ+VycGmaA==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -35372,6 +37870,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-head-style/-/mjml-head-style-4.15.3.tgz", "integrity": "sha512-9J+JuH+mKrQU65CaJ4KZegACUgNIlYmWQYx3VOBR/tyz+8kDYX7xBhKJCjQ1I4wj2Tvga3bykd89Oc2kFZ5WOw==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -35382,6 +37881,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-head-title/-/mjml-head-title-4.15.3.tgz", "integrity": "sha512-IM59xRtsxID4DubQ0iLmoCGXguEe+9BFG4z6y2xQDrscIa4QY3KlfqgKGT69ojW+AVbXXJPEVqrAi4/eCsLItQ==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -35392,6 +37892,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-hero/-/mjml-hero-4.15.3.tgz", "integrity": "sha512-9cLAPuc69yiuzNrMZIN58j+HMK1UWPaq2i3/Fg2ZpimfcGFKRcPGCbEVh0v+Pb6/J0+kf8yIO0leH20opu3AyQ==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -35402,6 +37903,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-image/-/mjml-image-4.15.3.tgz", "integrity": "sha512-g1OhSdofIytE9qaOGdTPmRIp7JsCtgO0zbsn1Fk6wQh2gEL55Z40j/VoghslWAWTgT2OHFdBKnMvWtN6U5+d2Q==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -35412,6 +37914,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-migrate/-/mjml-migrate-4.15.3.tgz", "integrity": "sha512-sr/+35RdxZroNQVegjpfRHJ5hda9XCgaS4mK2FGO+Mb1IUevKfeEPII3F/cHDpNwFeYH3kAgyqQ22ClhGLWNBA==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "js-beautify": "^1.6.14", @@ -35425,6 +37928,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-navbar/-/mjml-navbar-4.15.3.tgz", "integrity": "sha512-VsKH/Jdlf8Yu3y7GpzQV5n7JMdpqvZvTSpF6UQXL0PWOm7k6+LX+sCZimOfpHJ+wCaaybpxokjWZ71mxOoCWoA==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -35435,6 +37939,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-parser-xml/-/mjml-parser-xml-4.15.3.tgz", "integrity": "sha512-Tz0UX8/JVYICLjT+U8J1f/TFxIYVYjzZHeh4/Oyta0pLpRLeZlxEd71f3u3kdnulCKMP4i37pFRDmyLXAlEuLw==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "detect-node": "2.1.0", @@ -35446,6 +37951,7 @@ "version": "9.1.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==", + "optional": true, "requires": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", @@ -35459,6 +37965,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-preset-core/-/mjml-preset-core-4.15.3.tgz", "integrity": "sha512-1zZS8P4O0KweWUqNS655+oNnVMPQ1Rq1GaZq5S9JfwT1Vh/m516lSmiTW9oko6gGHytt5s6Yj6oOeu5Zm8FoLw==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "mjml-accordion": "4.15.3", @@ -35492,6 +37999,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-raw/-/mjml-raw-4.15.3.tgz", "integrity": "sha512-IGyHheOYyRchBLiAEgw3UM11kFNmBSMupu2BDdejC6ZiDhEAdG+tyERlsCwDPYtXanvFpGWULIu3XlsUPc+RZw==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -35502,6 +38010,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-section/-/mjml-section-4.15.3.tgz", "integrity": "sha512-JfVPRXH++Hd933gmQfG8JXXCBCR6fIzC3DwiYycvanL/aW1cEQ2EnebUfQkt5QzlYjOkJEH+JpccAsq3ln6FZQ==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -35512,6 +38021,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-social/-/mjml-social-4.15.3.tgz", "integrity": "sha512-7sD5FXrESOxpT9Z4Oh36bS6u/geuUrMP1aCg2sjyAwbPcF1aWa2k9OcatQfpRf6pJEhUZ18y6/WBBXmMVmSzXg==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -35522,6 +38032,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-spacer/-/mjml-spacer-4.15.3.tgz", "integrity": "sha512-3B7Qj+17EgDdAtZ3NAdMyOwLTX1jfmJuY7gjyhS2HtcZAmppW+cxqHUBwCKfvSRgTQiccmEvtNxaQK+tfyrZqA==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -35532,6 +38043,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-table/-/mjml-table-4.15.3.tgz", "integrity": "sha512-FLx7DcRKTdKdcOCbMyBaeudeHaHpwPveRrBm6WyQe3LXx6FfdmOh59i71/16LFQMgBOD3N4/UJkzxLzlTJzMqQ==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -35542,6 +38054,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-text/-/mjml-text-4.15.3.tgz", "integrity": "sha512-+C0hxCmw9kg0XzT6vhE5mFkK6y225nC8UEQcN94K0fBCjPKkM+HqZMwGX205fzdGRi+Bxa55b/VhrIVwdv+8vw==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -35552,6 +38065,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-validator/-/mjml-validator-4.15.3.tgz", "integrity": "sha512-Xb72KdqRwjv/qM2rJpV22syyP2N3cRQ9VVDrN6u2FSzLq02buFNxmSPJ7CKhat3PrUNdVHU75KZwOf/tz4UEhA==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9" } @@ -35560,6 +38074,7 @@ "version": "4.15.3", "resolved": "https://registry.npmjs.org/mjml-wrapper/-/mjml-wrapper-4.15.3.tgz", "integrity": "sha512-ditsCijeHJrmBmObtJmQ18ddLxv5oPyMTdPU8Di8APOnD2zPk7Z4UAuJSl7HXB45oFiivr3MJf4koFzMUSZ6Gg==", + "optional": true, "requires": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -35722,11 +38237,6 @@ "thenify-all": "^1.0.0" } }, - "nan": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz", - "integrity": "sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==" - }, "nanoassert": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-2.0.0.tgz", @@ -35782,12 +38292,14 @@ "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "optional": true }, "no-case": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "optional": true, "requires": { "lower-case": "^1.1.1" } @@ -35895,14 +38407,15 @@ "peer": true }, "nodemailer": { - "version": "6.9.13", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.13.tgz", - "integrity": "sha512-7o38Yogx6krdoBf3jCAqnIN4oSQFx+fMa0I7dK1D+me9kBxx12D+/33wSb+fhOCtIxvYJ+4x4IMEhmhCKfAiOA==" + "version": "6.9.14", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.14.tgz", + "integrity": "sha512-Dobp/ebDKBvz91sbtRKhcznLThrKxKt97GI2FAlAyy+fk19j73Uz3sBXolVtmcXjaorivqsbbbjDY+Jkt4/bQA==" }, "nopt": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz", "integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==", + "optional": true, "requires": { "abbrev": "^2.0.0" } @@ -35931,6 +38444,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "optional": true, "requires": { "boolbase": "^1.0.0" } @@ -36071,7 +38585,8 @@ "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==" + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "optional": true }, "p-limit": { "version": "3.1.0", @@ -36122,6 +38637,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/p-wait-for/-/p-wait-for-3.2.0.tgz", "integrity": "sha512-wpgERjNkLrBiFmkMEjuZJEWKKDrNfHCKA1OhyN1wg1FrLkULbviEy6py1AyJUgZ72YWFbZ38FIpnqvVqAlDUwA==", + "optional": true, "requires": { "p-timeout": "^3.0.0" }, @@ -36130,6 +38646,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "optional": true, "requires": { "p-finally": "^1.0.0" } @@ -36140,6 +38657,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", "integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==", + "optional": true, "requires": { "no-case": "^2.2.0" } @@ -36169,6 +38687,7 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "optional": true, "requires": { "entities": "^4.4.0" } @@ -36177,6 +38696,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "optional": true, "requires": { "domhandler": "^5.0.2", "parse5": "^7.0.0" @@ -36186,6 +38706,7 @@ "version": "0.12.1", "resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz", "integrity": "sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==", + "optional": true, "requires": { "leac": "^0.6.0", "peberminta": "^0.9.0" @@ -36291,7 +38812,8 @@ "peberminta": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz", - "integrity": "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==" + "integrity": "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==", + "optional": true }, "pg": { "version": "8.11.5", @@ -36569,6 +39091,7 @@ "version": "3.0.19", "resolved": "https://registry.npmjs.org/preview-email/-/preview-email-3.0.19.tgz", "integrity": "sha512-DBS3Nir18YtKc8loYCCOGitmiaQ0vTdahPoiXxwNweJDpmVZo+w3tppufOhoK0m8skpRxT56llYLs3VrORnmNQ==", + "optional": true, "requires": { "ci-info": "^3.8.0", "display-notification": "2.0.0", @@ -36587,6 +39110,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", + "optional": true, "requires": { "p-timeout": "^3.1.0" } @@ -36595,6 +39119,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "optional": true, "requires": { "p-finally": "^1.0.0" } @@ -36627,6 +39152,7 @@ "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "optional": true, "requires": { "asap": "~2.0.3" } @@ -36662,7 +39188,8 @@ "proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==" + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "optional": true }, "protons-runtime": { "version": "5.4.0", @@ -36699,6 +39226,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.2.tgz", "integrity": "sha512-bp0I/hiK1D1vChHh6EfDxtndHji55XP/ZJKwsRqrz6lRia6ZC2OZbdAymlxdVFwd1L70ebrVJw4/eZ79skrIaw==", + "optional": true, "requires": { "pug-code-gen": "^3.0.2", "pug-filters": "^4.0.0", @@ -36714,6 +39242,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz", "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==", + "optional": true, "requires": { "constantinople": "^4.0.1", "js-stringify": "^1.0.2", @@ -36724,6 +39253,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.2.tgz", "integrity": "sha512-nJMhW16MbiGRiyR4miDTQMRWDgKplnHyeLvioEJYbk1RsPI3FuA3saEP8uwnTb2nTJEKBU90NFVWJBk4OU5qyg==", + "optional": true, "requires": { "constantinople": "^4.0.1", "doctypes": "^1.1.0", @@ -36738,12 +39268,14 @@ "pug-error": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.0.0.tgz", - "integrity": "sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ==" + "integrity": "sha512-sjiUsi9M4RAGHktC1drQfCr5C5eriu24Lfbt4s+7SykztEOwVZtbFk1RRq0tzLxcMxMYTBR+zMQaG07J/btayQ==", + "optional": true }, "pug-filters": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz", "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==", + "optional": true, "requires": { "constantinople": "^4.0.1", "jstransformer": "1.0.0", @@ -36756,6 +39288,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz", "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==", + "optional": true, "requires": { "character-parser": "^2.2.0", "is-expression": "^4.0.0", @@ -36766,6 +39299,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz", "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==", + "optional": true, "requires": { "pug-error": "^2.0.0", "pug-walk": "^2.0.0" @@ -36775,6 +39309,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz", "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==", + "optional": true, "requires": { "object-assign": "^4.1.1", "pug-walk": "^2.0.0" @@ -36784,6 +39319,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz", "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==", + "optional": true, "requires": { "pug-error": "^2.0.0", "token-stream": "1.0.0" @@ -36792,12 +39328,14 @@ "pug-runtime": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz", - "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==" + "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==", + "optional": true }, "pug-strip-comments": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz", "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==", + "optional": true, "requires": { "pug-error": "^2.0.0" } @@ -36805,7 +39343,8 @@ "pug-walk": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz", - "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==" + "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==", + "optional": true }, "pump": { "version": "3.0.0", @@ -37150,6 +39689,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "devOptional": true, "requires": { "picomatch": "^2.2.1" }, @@ -37157,7 +39697,8 @@ "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "devOptional": true } } }, @@ -37283,7 +39824,8 @@ "relateurl": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==" + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "optional": true }, "repeat-string": { "version": "1.6.1", @@ -37464,6 +40006,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-3.2.0.tgz", "integrity": "sha512-Ep0RsvAjnRcBX1p5vogbaBdAGu/8j/ewpvGqnQYunnLd9SM0vWcPJewPKNnWFggf0hF0pwIgwV5XK7qQ7UZ8Qg==", + "optional": true, "requires": { "execa": "^0.10.0" }, @@ -37472,6 +40015,7 @@ "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "optional": true, "requires": { "nice-try": "^1.0.4", "path-key": "^2.0.1", @@ -37484,6 +40028,7 @@ "version": "0.10.0", "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", + "optional": true, "requires": { "cross-spawn": "^6.0.0", "get-stream": "^3.0.0", @@ -37497,17 +40042,20 @@ "get-stream": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==" + "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", + "optional": true }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==" + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "optional": true }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "optional": true, "requires": { "path-key": "^2.0.0" } @@ -37515,17 +40063,20 @@ "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==" + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "optional": true }, "semver": { "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "optional": true }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "optional": true, "requires": { "shebang-regex": "^1.0.0" } @@ -37533,17 +40084,20 @@ "shebang-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==" + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "optional": true }, "signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "optional": true }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "optional": true, "requires": { "isexe": "^2.0.0" } @@ -37675,6 +40229,7 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz", "integrity": "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==", + "optional": true, "requires": { "parseley": "^0.12.0" } @@ -37984,7 +40539,8 @@ "slick": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/slick/-/slick-1.12.2.tgz", - "integrity": "sha512-4qdtOGcBjral6YIBCWJ0ljFSKNLz9KkhbWtuGvUyRowl1kxfuE1x/Z/aJcaiilpb3do9bl5K7/1h9XC5wWpY/A==" + "integrity": "sha512-4qdtOGcBjral6YIBCWJ0ljFSKNLz9KkhbWtuGvUyRowl1kxfuE1x/Z/aJcaiilpb3do9bl5K7/1h9XC5wWpY/A==", + "optional": true }, "sonic-boom": { "version": "4.0.1", @@ -38186,7 +40742,8 @@ "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==" + "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", + "optional": true }, "strip-final-newline": { "version": "3.0.0", @@ -38529,7 +41086,8 @@ "tlds": { "version": "1.250.0", "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.250.0.tgz", - "integrity": "sha512-rWsBfFCWKrjM/o2Q1TTUeYQv6tHSd/umUutDjVs6taTuEgRDIreVYIBgWRWW4ot7jp6n0UVUuxhTLWBtUmPu/w==" + "integrity": "sha512-rWsBfFCWKrjM/o2Q1TTUeYQv6tHSd/umUutDjVs6taTuEgRDIreVYIBgWRWW4ot7jp6n0UVUuxhTLWBtUmPu/w==", + "optional": true }, "tmp": { "version": "0.0.33", @@ -38572,7 +41130,8 @@ "token-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz", - "integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==" + "integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==", + "optional": true }, "tr46": { "version": "0.0.3", @@ -38783,12 +41342,14 @@ "uc.micro": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", - "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==" + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "optional": true }, "uglify-js": { "version": "3.17.4", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==" + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "optional": true }, "uid": { "version": "2.0.2", @@ -38879,7 +41440,8 @@ "upper-case": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", - "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==" + "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==", + "optional": true }, "uri-js": { "version": "4.4.1", @@ -38942,7 +41504,8 @@ "valid-data-url": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-3.0.1.tgz", - "integrity": "sha512-jOWVmzVceKlVVdwjNSenT4PbGghU0SBIizAev8ofZVgivk/TVHXSbNL8LP6M3spZvkR9/QolkyJavGSX5Cs0UA==" + "integrity": "sha512-jOWVmzVceKlVVdwjNSenT4PbGghU0SBIizAev8ofZVgivk/TVHXSbNL8LP6M3spZvkR9/QolkyJavGSX5Cs0UA==", + "optional": true }, "validator": { "version": "13.11.0", @@ -38968,7 +41531,8 @@ "void-elements": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", - "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==" + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "optional": true }, "walker": { "version": "1.0.8", @@ -39010,6 +41574,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/web-resource-inliner/-/web-resource-inliner-6.0.1.tgz", "integrity": "sha512-kfqDxt5dTB1JhqsCUQVFDj0rmY+4HLwGQIsLPbyrsN9y9WV/1oFDSx3BQ4GfCv9X+jVeQ7rouTqwK53rA/7t8A==", + "optional": true, "requires": { "ansi-colors": "^4.1.1", "escape-goat": "^3.0.0", @@ -39023,6 +41588,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "optional": true, "requires": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", @@ -39033,6 +41599,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "optional": true, "requires": { "domelementtype": "^2.2.0" } @@ -39043,6 +41610,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", + "optional": true, "requires": { "domelementtype": "^2.0.1" } @@ -39051,6 +41619,7 @@ "version": "2.8.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "optional": true, "requires": { "dom-serializer": "^1.0.1", "domelementtype": "^2.2.0", @@ -39061,6 +41630,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "optional": true, "requires": { "domelementtype": "^2.2.0" } @@ -39070,12 +41640,14 @@ "entities": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "optional": true }, "htmlparser2": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-5.0.1.tgz", "integrity": "sha512-vKZZra6CSe9qsJzh0BjBGXo8dvzNsq/oGvsjfRdOrrryfeD9UOBEEQdeoqCRmKZchF5h2zOBMQ6YuQ0uRUmdbQ==", + "optional": true, "requires": { "domelementtype": "^2.0.1", "domhandler": "^3.3.0", @@ -39257,6 +41829,7 @@ "version": "7.0.2", "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==", + "optional": true, "requires": { "@babel/parser": "^7.9.6", "@babel/types": "^7.9.6", diff --git a/backend/package.json b/backend/package.json index b3329cb7..27655de1 100644 --- a/backend/package.json +++ b/backend/package.json @@ -26,8 +26,9 @@ }, "dependencies": { "@aws-sdk/client-s3": "^3.552.0", + "@aws-sdk/client-ses": "^3.621.0", "@helia/unixfs": "^3.0.2", - "@nestjs-modules/mailer": "^1.11.2", + "@nestjs-modules/mailer": "^2.0.2", "@nestjs/class-transformer": "^0.4.0", "@nestjs/common": "^10.0.0", "@nestjs/config": "^3.2.0", @@ -41,11 +42,10 @@ "@nestjs/typeorm": "^10.0.2", "@sendgrid/mail": "^8.1.1", "@types/diff": "^5.0.9", - "@types/morgan": "^1.9.7", "@types/humps": "^2.0.6", + "@types/morgan": "^1.9.7", "@types/multer": "^1.4.11", "axios": "^1.6.8", - "blake2": "^5.0.0", "blake2b": "^2.1.4", "blakejs": "^1.2.1", "blockstore-s3": "^1.0.15", @@ -67,7 +67,7 @@ "multiformats": "^13.1.0", "nest-winston": "^1.9.4", "nestjs-paginate": "^8.6.2", - "nodemailer": "^6.9.13", + "nodemailer": "^6.9.14", "passport": "^0.7.0", "passport-jwt": "^4.0.1", "passport-magic-login": "^1.2.2", diff --git a/backend/postman/CC Portal develop.postman_collection.json b/backend/postman/CC Portal develop.postman_collection.json index a7986dfe..10d6daba 100644 --- a/backend/postman/CC Portal develop.postman_collection.json +++ b/backend/postman/CC Portal develop.postman_collection.json @@ -1,7 +1,7 @@ { "info": { - "_postman_id": "374f247a-1ea9-4c6a-8a4f-5b5eaa052036", - "name": "CC Portal develop", + "_postman_id": "e842d76b-56e2-476d-b31d-bbeffd0853bc", + "name": "CC Portal develop Copy", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", "_exporter_id": "20133713" }, @@ -623,6 +623,32 @@ } }, "response": [] + }, + { + "name": "Get IPNS URL", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "{{accessToken}}", + "type": "text" + } + ], + "url": { + "raw": "{{base-url}}/api/constitution/ipns/url", + "host": [ + "{{base-url}}" + ], + "path": [ + "api", + "constitution", + "ipns", + "url" + ] + } + }, + "response": [] } ] }, diff --git a/backend/src/common/constants/ipfs.constants.ts b/backend/src/common/constants/ipfs.constants.ts new file mode 100644 index 00000000..be4c867a --- /dev/null +++ b/backend/src/common/constants/ipfs.constants.ts @@ -0,0 +1 @@ +export const IPFS_PUBLIC_URL: string = 'https://ipfs.io/ipfs/'; diff --git a/backend/src/constitution/api/constitution.controller.ts b/backend/src/constitution/api/constitution.controller.ts index cfaba99a..9bef1f28 100644 --- a/backend/src/constitution/api/constitution.controller.ts +++ b/backend/src/constitution/api/constitution.controller.ts @@ -10,6 +10,7 @@ import { HttpStatus, } from '@nestjs/common'; import { + ApiBearerAuth, ApiBody, ApiConsumes, ApiOperation, @@ -25,6 +26,7 @@ import { PermissionGuard } from 'src/auth/guard/permission.guard'; import { FileInterceptor } from '@nestjs/platform-express'; import { ConstitutionMetadataResponse } from './response/constitution-metadata.response'; import { getFileValidator } from '../pipe/fileValidatorPipe'; +import { ApiConditionalExcludeEndpoint } from 'src/common/decorators/api-conditional-exclude-endpoint.decorator'; @ApiTags('Constitution') @Controller('constitution') @@ -60,6 +62,7 @@ export class ConstitutionController { return await this.constitutionFacade.getConstitutionFileByCid(cid); } + @ApiConditionalExcludeEndpoint() @ApiOperation({ summary: 'Store constitution file' }) @ApiBody({ schema: { @@ -125,4 +128,21 @@ export class ConstitutionController { async getAllConstitutionMetadata(): Promise { return this.constitutionFacade.getAllConstitutionMetadata(); } + + @ApiConditionalExcludeEndpoint() + @ApiOperation({ + summary: 'Get IPNS URL for constitution', + }) + @ApiBearerAuth('JWT-auth') + @ApiResponse({ + status: 200, + description: 'Returns a IPNS URL', + type: ConstitutionMetadataResponse, + }) + @Permissions(PermissionEnum.ADD_CONSTITUTION) + @UseGuards(JwtAuthGuard, PermissionGuard) + @Get('ipns/url') + async getIpnsUrl() { + return await this.constitutionFacade.getIpnsUrl(); + } } diff --git a/backend/src/constitution/api/response/constitutio-ipns-url.response.ts b/backend/src/constitution/api/response/constitutio-ipns-url.response.ts new file mode 100644 index 00000000..74242502 --- /dev/null +++ b/backend/src/constitution/api/response/constitutio-ipns-url.response.ts @@ -0,0 +1,12 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Expose } from 'class-transformer'; + +export class ConstitutionIpnsUrlResponse { + @ApiProperty({ + description: 'IPNS URL related to a deployed Constitution', + example: + 'https://ipfs.io/ipns/QmVcVq1zssBLdcuw8nM19VYiLWjt9cMQSUrHSwVd5oY4s2', + }) + @Expose({ name: 'ipns_url' }) + ipnsUrl: string; +} diff --git a/backend/src/constitution/api/response/constitution-metadata.response.ts b/backend/src/constitution/api/response/constitution-metadata.response.ts index a9d82b86..b7a9945b 100644 --- a/backend/src/constitution/api/response/constitution-metadata.response.ts +++ b/backend/src/constitution/api/response/constitution-metadata.response.ts @@ -9,6 +9,21 @@ export class ConstitutionMetadataResponse { @Expose({ name: 'cid' }) cid: string; + @ApiProperty({ + description: 'Blake2b hash related to a deployed Constitution', + example: 'd9eeada848e4ffcbbb1be73421b47a960885954548aa44b2d46b2d84fb99141c', + }) + @Expose({ name: 'blake2b' }) + blake2b: string; + + @ApiProperty({ + description: 'Ipfs URL of the document', + example: + 'https://ipfs.io/ipfs/QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n', + }) + @Expose({ name: 'url' }) + url: string; + @ApiProperty({ description: 'Title of the document', example: 'Revision 1', diff --git a/backend/src/constitution/api/response/constitution.response.ts b/backend/src/constitution/api/response/constitution.response.ts index 7661522a..9d63fcb0 100644 --- a/backend/src/constitution/api/response/constitution.response.ts +++ b/backend/src/constitution/api/response/constitution.response.ts @@ -9,6 +9,21 @@ export class ConstitutionResponse { @Expose({ name: 'cid' }) cid: string; + @ApiProperty({ + description: 'Blake2b hash related to a deployed Constitution', + example: 'd9eeada848e4ffcbbb1be73421b47a960885954548aa44b2d46b2d84fb99141c', + }) + @Expose({ name: 'blake2b' }) + blake2b: string; + + @ApiProperty({ + description: 'Ipfs URL of the document', + example: + 'https://ipfs.io/ipfs/QmdfTbBqBPQ7VNxZEYEj14VmRuZBkqFbiwReogJgS1zR1n', + }) + @Expose({ name: 'url' }) + url: string; + @ApiProperty({ description: 'Version of the document', example: '1713153716', diff --git a/backend/src/constitution/facade/constitution.facade.ts b/backend/src/constitution/facade/constitution.facade.ts index 281390c6..91892be8 100644 --- a/backend/src/constitution/facade/constitution.facade.ts +++ b/backend/src/constitution/facade/constitution.facade.ts @@ -6,6 +6,7 @@ import { ConstitutionDto } from 'src/redis/dto/constitution.dto'; import { ConstitutionService } from '../services/constitution.service'; import { IpfsService } from 'src/ipfs/services/ipfs.service'; import { ConstitutionMetadataResponse } from '../api/response/constitution-metadata.response'; +import { ConstitutionIpnsUrlResponse } from '../api/response/constitutio-ipns-url.response'; @Injectable() export class ConstitutionFacade { @@ -63,4 +64,9 @@ export class ConstitutionFacade { ConstitutionMapper.ipfsMetadataDtoToConstitutionResponse(metadataDto), ); } + + async getIpnsUrl(): Promise { + const ipnsUrl = await this.ipfsService.getIpnsUrl(); + return ConstitutionMapper.ipnsUrlToResponse(ipnsUrl); + } } diff --git a/backend/src/constitution/mapper/constitution.mapper.ts b/backend/src/constitution/mapper/constitution.mapper.ts index c3878ecb..4ddf0582 100644 --- a/backend/src/constitution/mapper/constitution.mapper.ts +++ b/backend/src/constitution/mapper/constitution.mapper.ts @@ -5,11 +5,15 @@ import { CreateConstitutionDto } from '../dto/create-constitution.dto'; import { IpfsContentDto } from 'src/ipfs/dto/ipfs-content.dto'; import { IpfsMetadataDto } from 'src/ipfs/dto/ipfs-metadata.dto'; import { ConstitutionMetadataResponse } from '../api/response/constitution-metadata.response'; +import { ConstitutionIpnsUrlResponse } from '../api/response/constitutio-ipns-url.response'; +import { IPFS_PUBLIC_URL } from 'src/common/constants/ipfs.constants'; export class ConstitutionMapper { static dtoToResponse(dto: ConstitutionDto): ConstitutionResponse { const response = new ConstitutionResponse(); response.cid = dto.cid; + response.blake2b = dto.blake2b; + response.url = IPFS_PUBLIC_URL + dto.cid; response.version = dto.version; response.contents = dto.contents; return response; @@ -37,10 +41,18 @@ export class ConstitutionMapper { ): ConstitutionMetadataResponse { const constitutionResponse = new ConstitutionMetadataResponse(); constitutionResponse.cid = ipfsMetadataDto.cid; + constitutionResponse.blake2b = ipfsMetadataDto.blake2b; + constitutionResponse.url = IPFS_PUBLIC_URL + ipfsMetadataDto.cid; constitutionResponse.title = ipfsMetadataDto.title; constitutionResponse.version = ipfsMetadataDto.version; constitutionResponse.createdDate = ipfsMetadataDto.createdDate; return constitutionResponse; } + + static ipnsUrlToResponse(ipnsUrl: string): ConstitutionIpnsUrlResponse { + const constitutionIpnsUrlResponse = new ConstitutionIpnsUrlResponse(); + constitutionIpnsUrlResponse.ipnsUrl = ipnsUrl; + return constitutionIpnsUrlResponse; + } } diff --git a/backend/src/email/email.module.ts b/backend/src/email/email.module.ts index 77f91450..7f96b73d 100644 --- a/backend/src/email/email.module.ts +++ b/backend/src/email/email.module.ts @@ -4,21 +4,28 @@ import { MailerModule } from '@nestjs-modules/mailer'; import { HandlebarsAdapter } from '@nestjs-modules/mailer/dist/adapters/handlebars.adapter'; import { join } from 'path'; import { ConfigService } from '@nestjs/config'; +import * as aws from '@aws-sdk/client-ses'; @Module({ imports: [ MailerModule.forRootAsync({ useFactory: async (configService: ConfigService) => ({ transport: { - host: configService.getOrThrow('SENDGRID_HOST'), - port: configService.getOrThrow('SENDGRID_PORT'), - auth: { - user: configService.getOrThrow('SENDGRID_USER'), - pass: configService.getOrThrow('SENDGRID_API_KEY'), + SES: { + ses: new aws.SES({ + region: configService.getOrThrow('AWS_REGION'), + credentials: { + accessKeyId: configService.getOrThrow('AWS_ACCESS_KEY_ID'), + secretAccessKey: configService.getOrThrow( + 'AWS_SECRET_ACCESS_KEY', + ), + }, + }), + aws, }, }, defaults: { - from: `${configService.getOrThrow('SENDGRID_EMAIL_NAME')} <${configService.getOrThrow('SENDGRID_EMAIL_FROM')}>`, + from: `${configService.getOrThrow('NAME_FROM')} <${configService.getOrThrow('EMAIL_FROM')}>`, }, template: { dir: join(__dirname, './templates'), diff --git a/backend/src/ipfs/services/ipfs.service.ts b/backend/src/ipfs/services/ipfs.service.ts index 18367efe..30054ab2 100644 --- a/backend/src/ipfs/services/ipfs.service.ts +++ b/backend/src/ipfs/services/ipfs.service.ts @@ -176,4 +176,19 @@ export class IpfsService { contents: content, }; } + + async getIpnsUrl(): Promise { + const apiLink = + this.configService.getOrThrow('IPFS_SERVICE_URL') + '/ipfs/ipns/url'; + try { + const response = await axios.get(apiLink); + const ipnsUrl = response.data; + return ipnsUrl; + } catch (error) { + this.logger.error(`Error when getting IPNS URL from IPFS: ${error}`); + throw new InternalServerErrorException( + `Error when getting IPNS URL from IPFS service`, + ); + } + } } diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 95ab907e..60afa292 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -77,4 +77,4 @@ ENV PORT 3000 ENV HOSTNAME "0.0.0.0" # server.js is created by next build from the standalone output -CMD ["node", "server.js"] \ No newline at end of file +CMD ["node", "server.js"] diff --git a/frontend/messages/de.json b/frontend/messages/de.json index 31b2ad14..07970556 100644 --- a/frontend/messages/de.json +++ b/frontend/messages/de.json @@ -2,24 +2,24 @@ "Index": { "title": "Web App Boilerplate", "hero": { - "headline": "Championing Cardano's community-led governance", - "description": "Until a final Cardano Constitution has been developed and ratified by the community - a programme of consultation taking place throughout 2024 - a set of interim rules is required to support the transition.", - "seeConstitution": "Read the Interim Constitution", - "signIn": "Sign In", - "constitutionalCommitteePortal": "Constitutional Committee Portal" + "headline": "Wir setzen uns für die von der Community geführte Governance von Cardano ein", + "description": "Bis eine endgültige Cardano-Verfassung entwickelt und von der Community ratifiziert wurde – ein Konsultationsprogramm, das das ganze Jahr 2024 über läuft – ist eine Reihe von Übergangsregeln erforderlich, um den Übergang zu unterstützen.", + "seeConstitution": "Lesen Sie die Interimsverfassung", + "signIn": "Anmelden", + "constitutionalCommitteePortal": "Portal des Verfassungsausschusses" } }, "Constitution": { - "title": "Cardano Constituition", + "title": "Cardano-Verfassung", "drawer": { - "compare": "Compare", + "compare": "Vergleichen", "latestRevisions": "Latest Revisions", "tableOfContents": "Content", "latest": "Latest" } }, "Members": { - "title": "Active Members", + "title": "Members", "card": { "joined": "Joined", "latestUpdates": "Latest updates" diff --git a/frontend/messages/en.json b/frontend/messages/en.json index 31b2ad14..6ec76645 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -10,7 +10,7 @@ } }, "Constitution": { - "title": "Cardano Constituition", + "title": "Interim Constitution", "drawer": { "compare": "Compare", "latestRevisions": "Latest Revisions", @@ -19,7 +19,7 @@ } }, "Members": { - "title": "Active Members", + "title": "Members", "card": { "joined": "Joined", "latestUpdates": "Latest updates" diff --git a/frontend/public/icons/Close.svg b/frontend/public/icons/Close.svg index 82aee03c..91674486 100644 --- a/frontend/public/icons/Close.svg +++ b/frontend/public/icons/Close.svg @@ -1,4 +1,4 @@ - - - + + + diff --git a/frontend/public/icons/ExternalLink.svg b/frontend/public/icons/ExternalLink.svg new file mode 100644 index 00000000..a734f31b --- /dev/null +++ b/frontend/public/icons/ExternalLink.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/components/atoms/Typography.tsx b/frontend/src/components/atoms/Typography.tsx index c4da119d..6dfcacd2 100644 --- a/frontend/src/components/atoms/Typography.tsx +++ b/frontend/src/components/atoms/Typography.tsx @@ -22,9 +22,9 @@ export const Typography = ({ }[variant]; const fontSizeXS = { - headline1: 46, - headline2: 46, - headline3: 36, + headline1: 42, + headline2: 32, + headline3: 26, headline4: 24, headline5: 20, title1: 20, @@ -60,12 +60,25 @@ export const Typography = ({ caption: "16px", }[variant]; + const lineHeightXS = { + headline1: "57px", + headline2: "47px", + headline3: "40px", + headline4: "40px", + headline5: "36px", + title1: "32px", + title2: "28px", + body1: "24px", + body2: "20px", + caption: "16px", + }[variant]; + return ( {props.children} diff --git a/frontend/src/components/atoms/modal/ModalWrapper.tsx b/frontend/src/components/atoms/modal/ModalWrapper.tsx index bc8068cf..eb39bd05 100644 --- a/frontend/src/components/atoms/modal/ModalWrapper.tsx +++ b/frontend/src/components/atoms/modal/ModalWrapper.tsx @@ -2,13 +2,17 @@ import { SxProps, styled } from "@mui/material/styles"; -import { customPalette } from "@consts"; +import { customPalette, ICONS } from "@consts"; +import { callAll } from "@utils"; +import { useModal } from "@/context"; +import { useScreenDimension } from "@/lib/hooks"; type ModalVariant = "modal" | "popup" | "wide"; interface Props { variant?: ModalVariant; onClose?: () => void; children: React.ReactNode; + hideCloseButton?: boolean; dataTestId?: string; sx?: SxProps; icon?: string; @@ -22,7 +26,11 @@ export const ModalWrapper = ({ sx, icon, scrollable, + hideCloseButton = true, + onClose, }: Props) => { + const { closeModal } = useModal(); + const { isMobile } = useScreenDimension(); return ( {variant !== "popup" && icon && ( - icon + icon + )} + {variant !== "popup" && !hideCloseButton && ( + )} {children} @@ -85,3 +106,10 @@ export const BaseWrapper = styled("div")<{ } }} `; + +export const CloseButton = styled("img")` + cursor: pointer; + position: absolute; + top: 24px; + right: 24px; +`; diff --git a/frontend/src/components/molecules/ConditionalWrapper.tsx b/frontend/src/components/molecules/ConditionalWrapper.tsx new file mode 100644 index 00000000..290a6972 --- /dev/null +++ b/frontend/src/components/molecules/ConditionalWrapper.tsx @@ -0,0 +1,15 @@ +import React from "react"; + +type Props = { + children: React.ReactNode; + wrapper: any; + condition: boolean; +}; + +const ConditionalWrapper: React.FC = ({ + condition, + wrapper, + children, +}: Props): JSX.Element => (condition ? wrapper(children) : children); + +export default ConditionalWrapper; diff --git a/frontend/src/components/molecules/UserCard/UserBasicInfo.tsx b/frontend/src/components/molecules/UserCard/UserBasicInfo.tsx index 48780637..6f84430d 100644 --- a/frontend/src/components/molecules/UserCard/UserBasicInfo.tsx +++ b/frontend/src/components/molecules/UserCard/UserBasicInfo.tsx @@ -1,8 +1,9 @@ import { IMAGES } from "@consts"; -import { Typography } from "@atoms"; +import { Typography, Tooltip } from "@atoms"; import { Grid } from "@mui/material"; -import { getShortenedGovActionId } from "@utils"; +import { getShortenedGovActionId, truncateText } from "@utils"; import { CopyPill } from "../CopyPill"; +import ConditionalWrapper from "../ConditionalWrapper"; export const UserBasicInfo = ({ name, @@ -35,12 +36,19 @@ export const UserBasicInfo = ({ {name} {email && ( - - - - {email} - - + 20} + wrapper={(children) => ( + {children} + )} + > + + + + {truncateText(email, 20)} + + + )} {hotAddress && ( ) => { - openModal({ - type: "compareConstitutionModal", - state: { - base: metadata[0], - target, - }, - }); + useEffect(() => { + if (isMobile) { + setIsOpen(false); + } + }, [isMobile]); + + const onTOCLinkClick = () => { + if (isMobile) { + setIsOpen(false); + } }; + const MDXComponents = { - nav: ({ children }) => ( - setIsOpen(!isOpen)} - top={{ xxs: 75, md: 90 }} - left={0} - > - + isMobile ? ( + - - setTab(tab.value)} - tabs={CONSTITUTION_SIDEBAR_TABS} - selectedValue={tab} - sx={{ fontSize: { xxs: 16 } }} - /> - - - - - - + + ) : ( + setIsOpen(!isOpen)} + top={{ xxs: 0, md: 90 }} + left={0} > - {tab === "revisions" ? ( - - {metadata ? ( - metadata.map(({ title, created_date, cid }) => { - return ( - { - metadata[0].cid === cid - ? null - : onCompare({ title, created_date, cid }); - }} - hash={cid} - title={title} - description={created_date} - buttonLabel={ - metadata[0].cid === cid - ? t("drawer.latest") - : t("drawer.compare") - } - key={cid} - /> - ); - }) - ) : ( - - )} - - ) : ( - - {children} - - )} - - - ), + + + ), h1: Heading1, h2: Heading2, h3: Heading3, p: Paragraph, li: ListItem, code: Code, + a: (props) => { + if (props.href && props.href.startsWith("#")) { + return ; + } + return ; + }, }; return ( @@ -140,13 +82,32 @@ export function Constitution({ constitution, metadata }: ConstitutionProps) { data-testid="constitution-page-wrapper" container position="relative" - justifyContent="flex-end" + justifyContent={{ xxs: "flex-start", md: "flex-end" }} flex={1} > - + - + + + {t("title")} + setIsOpen(true)} + sx={{ + bgcolor: customPalette.arcticWhite, + display: { xxs: "flex", md: "none" }, + justifyContent: "center", + }} + > + + + @@ -157,4 +118,4 @@ export function Constitution({ constitution, metadata }: ConstitutionProps) { ); -} +} \ No newline at end of file diff --git a/frontend/src/components/organisms/Constitution/ConstitutionSidebar.tsx b/frontend/src/components/organisms/Constitution/ConstitutionSidebar.tsx new file mode 100644 index 00000000..d99bd2eb --- /dev/null +++ b/frontend/src/components/organisms/Constitution/ConstitutionSidebar.tsx @@ -0,0 +1,124 @@ +"use client"; +import { CONSTITUTION_SIDEBAR_TABS, customPalette } from "@/constants"; +import { Divider, Grid } from "@mui/material"; +import { NotFound } from "../NotFound"; +import { PageTitleTabs } from "../PageTitleTabs"; +import { ConstitutionMetadata } from "../types"; +import { isAnyAdminRole } from "@utils"; +import { useAppContext, useModal } from "@/context"; +import { NavCard } from "./MDXComponents"; +import { useState } from "react"; +import { useTranslations } from "next-intl"; + +export const ConstitutionSidebar = ({ tableOfContents, metadata }) => { + const { openModal } = useModal(); + const { userSession } = useAppContext(); + const [tab, setTab] = useState("revisions"); + const t = useTranslations("Constitution"); + + const onCompare = ( + target: Omit + ) => { + openModal({ + type: "compareConstitutionModal", + state: { + base: metadata[0], + target, + }, + }); + }; + + return ( + <> + + + setTab(tab.value)} + tabs={CONSTITUTION_SIDEBAR_TABS} + selectedValue={tab} + sx={{ fontSize: { xxs: 16 } }} + /> + + + + + + + {tab === "revisions" ? ( + + {metadata ? ( + metadata.map(({ title, created_date, cid, blake2b, url }) => { + return ( + { + metadata[0].cid === cid + ? null + : onCompare({ title, created_date, cid }); + }} + hash={blake2b} + title={title} + description={created_date} + buttonLabel={metadata[0].cid !== cid && t("drawer.compare")} + isActiveLabel={ + metadata[0].cid === cid && t("drawer.latest") + } + url={ + userSession && + isAnyAdminRole(userSession?.role) && + userSession?.permissions.includes( + "add_constitution_version" + ) + ? url + : null + } + key={cid} + /> + ); + }) + ) : ( + + )} + + ) : ( + + {tableOfContents} + + )} + + + ); +}; diff --git a/frontend/src/components/organisms/Constitution/MDXComponents.tsx b/frontend/src/components/organisms/Constitution/MDXComponents.tsx index 481308f8..7e5cf3da 100644 --- a/frontend/src/components/organisms/Constitution/MDXComponents.tsx +++ b/frontend/src/components/organisms/Constitution/MDXComponents.tsx @@ -1,9 +1,11 @@ -import { Card } from "@/components/molecules"; -import { customPalette, ICONS } from "@/constants"; +import { Card } from "@molecules"; +import { customPalette, ICONS, orange } from "@consts"; import { getShortenedGovActionId } from "@utils"; import { Button, CopyButton, Typography } from "@atoms"; import { Box, Collapse, Grid } from "@mui/material"; import React, { ReactNode } from "react"; +import Image from "next/image"; +import Link from "next/link"; const Anchor = ({ id, offset = "-20vh " }) => { return ( @@ -33,7 +35,7 @@ export const Heading1 = ({ children, id }) => ( marginTop: "24px", marginBottom: "16px", lineHeight: "1.25em", - fontSize: "2em", + fontSize: { xxs: 20, md: 32 }, }} variant="headline4" > @@ -50,7 +52,8 @@ export const Heading2 = ({ children, id }) => ( marginTop: "24px", marginBottom: "16px", fontWeight: 600, - fontSize: 20, + fontSize: { xxs: 16, md: 20 }, + lineHeight: "1.25em", }} > @@ -67,7 +70,7 @@ export const Heading3 = ({ children, id }) => ( marginTop: "24px", marginBottom: "16px", fontWeight: 600, - fontSize: 18, + fontSize: { xxs: 14, md: 18 }, lineHeight: "1.25em", }} > @@ -117,7 +120,38 @@ export const Code = ({ children }) => ( ); -export const NavDrawer = ({ +export const TABLE_OF_CONTENTS_WRAPPER_STYLE_PROPS = { + backgroundColor: customPalette.arcticWhite, + "& ol.toc-level": { + margin: 0, + }, + "& ol.toc-level-1": { + paddingInlineStart: "20px", + + "& li": { + listStyle: "outside !important", + "& a.toc-link-h1": { + fontWeight: 600, + }, + }, + }, + "& ol.toc-level-2": { + margin: "10px 0px 10px 0px", + }, + "& li": { + marginBottom: "3px !important", + "& a": { + textDecoration: "none", + textAlign: "left", + fontSize: 14, + fontWeight: 500, + lineHeight: "24px", + color: customPalette.textBlack, + }, + }, +}; + +export const NavDrawerDesktop = ({ children, onClick, isOpen, @@ -132,6 +166,7 @@ export const NavDrawer = ({ }) => { return ( ( +export const NavCard = ({ + onClick, + title, + description, + buttonLabel, + hash, + url, + isActiveLabel, +}) => ( ( justifyContent="space-between" alignItems={{ lg: "center" }} > - - {title} + + + {title} + {description} - + ( display="flex" flexWrap="nowrap" gap={1} + width="100%" > @@ -238,15 +260,50 @@ export const NavCard = ({ onClick, title, description, buttonLabel, hash }) => ( - - + + ipfs link + + + )} + + + {buttonLabel && ( + + )} + {isActiveLabel && ( + + {isActiveLabel} + + )} diff --git a/frontend/src/components/organisms/Constitution/TOCLink.tsx b/frontend/src/components/organisms/Constitution/TOCLink.tsx new file mode 100644 index 00000000..f9067a72 --- /dev/null +++ b/frontend/src/components/organisms/Constitution/TOCLink.tsx @@ -0,0 +1,71 @@ +import { orange } from "@/constants"; +import { useEffect, useState } from "react"; + +interface Props { + href: string; + children: React.ReactNode; + callback: () => void; +} +/** + * TOCLink Component + * + * This component represents a link in a Table of Contents (TOC) that scrolls smoothly to the + * corresponding section on the page when clicked. The link highlights itself when active + * and resets other links. + * + * @param {string} props.href - The hash URL that the link points to (e.g., "#section1"). + * @param {React.ReactNode} props.children - The content inside the link (e.g., link text). + * @param {Function} props.callback - A callback function to be executed after the link is clicked. + */ + +const TOCLink = ({ href, children, callback }: Props) => { + const [isActive, setIsActive] = useState(false); + + const handleClick = (e) => { + e.preventDefault(); + // Extract the target element's ID from the href (e.g., "#section1" => "section1") + const targetId = href.substring(1); + const target = document.getElementById(targetId); + + if (target) { + target.scrollIntoView({ behavior: "smooth" }); + window.history.pushState(null, null, href); + + // Dispatch a custom event to notify other TOC links to reset their active state + window.dispatchEvent(new CustomEvent("toc-link-click", { detail: href })); + + setIsActive(true); + } + callback(); + }; + + /** + * Listens for the custom "toc-link-click" event and resets this link's active state + * if the clicked link's href does not match this link's href. + */ + useEffect(() => { + const handleTocLinkClick = (event) => { + if (event.detail !== href) { + setIsActive(false); // Reset the active state if another link is clicked + } + }; + + window.addEventListener("toc-link-click", handleTocLinkClick); + + return () => { + window.removeEventListener("toc-link-click", handleTocLinkClick); + }; + }, [href]); + + return ( + + {children} + + ); +}; + +export default TOCLink; diff --git a/frontend/src/components/organisms/Footer/Footer.tsx b/frontend/src/components/organisms/Footer/Footer.tsx index 1f1ef8e2..7ca293e7 100644 --- a/frontend/src/components/organisms/Footer/Footer.tsx +++ b/frontend/src/components/organisms/Footer/Footer.tsx @@ -52,9 +52,9 @@ export const Footer = ({ {t("privacyPolicy")} @@ -70,7 +70,7 @@ export const Footer = ({ component="span" fontSize="12px" lineHeight="16px" - sx={{ cursor: "pointer", ml: { xxs: 0, md: 1 } }} + sx={{ cursor: "pointer", ml: 1 }} fontWeight={500} variant="caption" onClick={() => { diff --git a/frontend/src/components/organisms/Hero/Hero.tsx b/frontend/src/components/organisms/Hero/Hero.tsx index 86827268..da873da4 100644 --- a/frontend/src/components/organisms/Hero/Hero.tsx +++ b/frontend/src/components/organisms/Hero/Hero.tsx @@ -21,6 +21,7 @@ export const Hero = ({ children }: HeroProps) => { position="relative" px={{ xxs: 2, sm: 5, md: 10 }} sx={{ backgroundColor: customPalette.arcticWhite }} + minHeight={{ xxs: "90vh", md: "auto" }} > diff --git a/frontend/src/components/organisms/LatestUpdates.tsx b/frontend/src/components/organisms/LatestUpdates.tsx index 58eefd71..81152e76 100644 --- a/frontend/src/components/organisms/LatestUpdates.tsx +++ b/frontend/src/components/organisms/LatestUpdates.tsx @@ -46,6 +46,8 @@ export const LatestUpdates = ({ submit_time: null, //todo, update BE response end_time: action.gov_action_proposal_end_time, vote: action.value, + reasoning_title: action.reasoning_title, + reasoning_comment: action.reasoning_comment, }, }, }); diff --git a/frontend/src/components/organisms/Modals/CompareConstitutionModal.tsx b/frontend/src/components/organisms/Modals/CompareConstitutionModal.tsx index 41e893b3..077465e8 100644 --- a/frontend/src/components/organisms/Modals/CompareConstitutionModal.tsx +++ b/frontend/src/components/organisms/Modals/CompareConstitutionModal.tsx @@ -63,6 +63,7 @@ export const CompareConstitutionModal = () => { { const t = useTranslations("Modals"); const { closeModal, state } = useModal(); const [govAction, setGovAction] = useState(); const { addErrorAlert } = useSnackbar(); + const { isMobile } = useScreenDimension(); const onClick = () => { closeModal(); @@ -61,7 +63,7 @@ export const GovActionModal = () => { icon { - contents: ReasoningContentsI; + comment: string; } export const PreviewReasoningModal = () => { const t = useTranslations("Modals"); @@ -49,16 +49,22 @@ export const PreviewReasoningModal = () => { async function fetchData(id: string) { const response = await getReasoningData(id); if (isResponseErrorI(response)) { - if (response.statusCode !== 404) { + if (response.statusCode !== 404 && response.statusCode !== 401) { addErrorAlert(response.error); closeModal(); } } else { - setReasoning({ ...response, contents: JSON.parse(response.contents) }); + const contents = JSON.parse(response.contents); + setReasoning({ ...response, comment: contents.body.comment }); } } - if (govAction?.id) { + if (govAction.reasoning_title && govAction.reasoning_comment) { + setReasoning({ + comment: govAction.reasoning_comment, + title: govAction.reasoning_title, + }); + } else if (govAction?.id) { fetchData(govAction.id); } }, [govAction?.id]); @@ -111,9 +117,9 @@ export const PreviewReasoningModal = () => { return ( - + icon { > diff --git a/frontend/src/components/organisms/TopNavigation/DrawerMobile.tsx b/frontend/src/components/organisms/TopNavigation/DrawerMobile.tsx index db014219..a2dfcfce 100644 --- a/frontend/src/components/organisms/TopNavigation/DrawerMobile.tsx +++ b/frontend/src/components/organisms/TopNavigation/DrawerMobile.tsx @@ -3,9 +3,15 @@ import React from "react"; import { Box, Grid, IconButton, SwipeableDrawer } from "@mui/material"; -import { ICONS, IMAGES } from "@consts"; +import { ICONS } from "@consts"; -export const DrawerMobile = ({ isDrawerOpen, setIsDrawerOpen, children }) => { +export const DrawerMobile = ({ + isDrawerOpen, + setIsDrawerOpen, + children, + sx = {}, + rowGap = 4, +}) => { return ( { onOpen={() => setIsDrawerOpen(true)} open={isDrawerOpen} PaperProps={{ - sx: { width: "100%" }, + sx: { width: "100%", ...sx }, }} > { - - setIsDrawerOpen(false)} - > + setIsDrawerOpen(false)}> - + {children} diff --git a/frontend/src/components/organisms/types.ts b/frontend/src/components/organisms/types.ts index f9c1524b..02bc738a 100644 --- a/frontend/src/components/organisms/types.ts +++ b/frontend/src/components/organisms/types.ts @@ -11,6 +11,8 @@ import { Vote } from "../atoms"; export interface ConstitutionMetadata { cid: string; + url: string; + blake2b: string; title: string; version: string; created_date: string; @@ -87,7 +89,12 @@ export interface OpenPreviewReasoningModal { govAction: Pick< GovernanceActionTableI, "id" | "type" | "submit_time" | "end_time" | "tx_hash" - > & { vote?: Vote; vote_submit_time?: string }; + > & { + vote?: Vote; + vote_submit_time?: string; + reasoning_title?: string; + reasoning_comment?: string; + }; onActionClick?: (id: string) => void; actionTitle?: string; } diff --git a/frontend/src/constants/icons.ts b/frontend/src/constants/icons.ts index 68aa87df..1736aab2 100644 --- a/frontend/src/constants/icons.ts +++ b/frontend/src/constants/icons.ts @@ -21,4 +21,5 @@ export const ICONS = { sortActive: "/icons/SortActive.svg", sortWhite: "/icons/SortWhite.svg", govAction: "/icons/GovAction.svg", + externalLink: "/icons/ExternalLink.svg", }; diff --git a/frontend/src/lib/requests/types.ts b/frontend/src/lib/requests/types.ts index c77d192c..e063ad83 100644 --- a/frontend/src/lib/requests/types.ts +++ b/frontend/src/lib/requests/types.ts @@ -175,9 +175,9 @@ export interface ReasoningContentsI { } export interface ReasoningResponseI { - cid: string; - url: string; - blake2b: string; + cid?: string; + url?: string; + blake2b?: string; contents: string; title: string; } diff --git a/ipfs-service/Dockerfile b/ipfs-service/Dockerfile index ed901730..dab0c7c2 100644 --- a/ipfs-service/Dockerfile +++ b/ipfs-service/Dockerfile @@ -1,5 +1,5 @@ -# Use the official Node.js 20 image as the base image -FROM node:20 +# Use the official Node.js 22 image as the base image +FROM node:22 # Install build dependencies for native modules RUN apt-get update && \ diff --git a/ipfs-service/src/app.controller.ts b/ipfs-service/src/app.controller.ts index 7b018d00..666c95c9 100644 --- a/ipfs-service/src/app.controller.ts +++ b/ipfs-service/src/app.controller.ts @@ -40,4 +40,9 @@ export class AppController { } return doc } + + @Get('ipns/url') + async getIpnsUrl(): Promise { + return await this.appService.getIpnsUrl(); + } } diff --git a/ipfs-service/src/app.service.ts b/ipfs-service/src/app.service.ts index a4852797..94a04430 100644 --- a/ipfs-service/src/app.service.ts +++ b/ipfs-service/src/app.service.ts @@ -148,7 +148,7 @@ export class AppService implements OnModuleInit { async getIpns() { this.ipns = ipns(this.helia); - const keyName = 'my-key11'; + const keyName = process.env.IPNS_CONSTITUTION_KEY_NAME; const existingKeys = await this.helia.libp2p.services.keychain.listKeys(); // if keyName already exists if (existingKeys.some((x) => x.name === keyName)) { @@ -264,4 +264,12 @@ export class AppService implements OnModuleInit { attemptToProvide(); } + + async getIpnsUrl(): Promise { + if (!this.ipnsPeerId) { + throw new InternalServerErrorException(`IPNS Peer Id not exists`); + } + const ipnsUrl = process.env.IPNS_PUBLIC_URL + this.ipnsPeerId.toString() + return ipnsUrl; + } } diff --git a/ipfs-service/src/main.ts b/ipfs-service/src/main.ts index 3a13dd2f..c589b826 100644 --- a/ipfs-service/src/main.ts +++ b/ipfs-service/src/main.ts @@ -1,7 +1,11 @@ import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module.js'; +import { EventEmitter } from 'events'; async function bootstrap() { + // Increase the max listeners for EventEmitters + EventEmitter.defaultMaxListeners = 50; // Set this to the desired number + const app = await NestFactory.create(AppModule); await app.listen(3001); } diff --git a/worker-service/src/bullmq/bullmq.module.ts b/worker-service/src/bullmq/bullmq.module.ts index 4b4d1867..0b0cbb58 100644 --- a/worker-service/src/bullmq/bullmq.module.ts +++ b/worker-service/src/bullmq/bullmq.module.ts @@ -16,6 +16,7 @@ import { ExpressAdapter } from '@bull-board/express'; connection: { host: configService.getOrThrow('REDIS_HOST'), port: configService.getOrThrow('REDIS_PORT'), + password: configService.getOrThrow('REDIS_PASSWORD'), }, }), inject: [ConfigService], diff --git a/worker-service/src/governance/services/vote.service.ts b/worker-service/src/governance/services/vote.service.ts index 715e1f35..b7df82b1 100644 --- a/worker-service/src/governance/services/vote.service.ts +++ b/worker-service/src/governance/services/vote.service.ts @@ -159,17 +159,22 @@ export class VoteService extends CommonService { async getVoteDataFromDbSync( mapHotAddresses: Map, ): Promise { - const prefix = '\\x'; // prefix for each hot address - const addresses = [...mapHotAddresses.keys()].map((key) => prefix + key); - const dbData = await this.getDataFromSqlFile( - SQL_FILE_PATH.GET_VOTES, - addresses, - ); - const results: VoteRequest[] = []; - dbData.forEach((vote) => { - results.push(VoteMapper.dbSyncToVoteRequest(vote, mapHotAddresses)); - }); - return results; + try { + const prefix = '\\x'; // prefix for each hot address + const addresses = [...mapHotAddresses.keys()].map((key) => prefix + key); + const dbData = await this.getDataFromSqlFile( + SQL_FILE_PATH.GET_VOTES, + addresses, + ); + const results: VoteRequest[] = []; + dbData.forEach((vote) => { + results.push(VoteMapper.dbSyncToVoteRequest(vote, mapHotAddresses)); + }); + return results; + } catch (error) { + this.logger.log(`Error when getting votes from db_sync: ${error}`); + throw new InternalServerErrorException(error); + } } async countHotAddressPages(): Promise { From 7735d4f5c13d4eac9613d22a69cc5b4e4c976474 Mon Sep 17 00:00:00 2001 From: mpavlovicbb <58938959+mpavlovicbb@users.noreply.github.com> Date: Mon, 2 Sep 2024 14:25:58 +0200 Subject: [PATCH 07/20] ci pipeline test (#321) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b841034c..862c33e2 100644 --- a/README.md +++ b/README.md @@ -245,4 +245,4 @@ Access the API documentation at: [http://localhost:1337/api-docs](http://localho This project is licensed under the Apache 2.0. -See [License file](./LICENSE). \ No newline at end of file +See [License file](./LICENSE). From dbc1b5eb7fd0d641832c5b1c996357483d48b598 Mon Sep 17 00:00:00 2001 From: nike-getto Date: Mon, 2 Sep 2024 18:08:56 +0200 Subject: [PATCH 08/20] fix: AWS default region --- backend/src/s3/client/s3client.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/src/s3/client/s3client.ts b/backend/src/s3/client/s3client.ts index 6908ad2f..0a4c290f 100644 --- a/backend/src/s3/client/s3client.ts +++ b/backend/src/s3/client/s3client.ts @@ -12,6 +12,7 @@ export const s3ClientFactory: FactoryProvider = { useSSL: configService.get('MINIO_USE_SSL') === 'true', accessKey: configService.get('MINIO_ACCESS_KEY'), secretKey: configService.get('MINIO_SECRET_KEY'), + region: configService.get('MINIO_REGION', 'us-east-1'), }); const bucketName = configService.get('MINIO_BUCKET'); From ae3fbfa9bf765eb44ad006107f93bef39371248f Mon Sep 17 00:00:00 2001 From: Milos <161627443+BEdev24@users.noreply.github.com> Date: Fri, 13 Sep 2024 21:43:57 +0200 Subject: [PATCH 09/20] refactor: .env vars (#355) --- .github/workflows/pr.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 09c888ff..1da5163a 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -119,8 +119,10 @@ jobs: outputs: type=docker,dest=/tmp/image-${{ matrix.name }}-${{ github.sha }}-pr.tar build-args: | NEXT_PUBLIC_API_URL=${{ secrets.PROD_NEXT_PUBLIC_API_URL }} - NEXT_PUBLIC_USERSNAP_GLOBAL_API_KEY=${{ secrets.PROD_NEXT_PUBLIC_USERSNAP_GLOBAL_API_KEY }} - NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY=${{ secrets.PROD_NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY }}r + NEXT_PUBLIC_USERSNAP_SPACE_API_KEY=${{ secrets.PROD_NEXT_PUBLIC_USERSNAP_SPACE_API_KEY }} + NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY=${{ secrets.PROD_NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY }} + NEXT_PUBLIC_HIDDEN_USERSNAP_PROJECT_IDS=${{ secrets.PROD_NEXT_PUBLIC_HIDDEN_USERSNAP_PROJECT_IDS }} + NEXT_PUBLIC_IS_MAINNET=${{ secrets.PROD_NEXT_PUBLIC_IS_MAINNET }} - name: Scan Docker image with Dockle id: dockle From d421ea3379f14294c7a2fdf8c55de206b08507f0 Mon Sep 17 00:00:00 2001 From: Milos <161627443+BEdev24@users.noreply.github.com> Date: Fri, 13 Sep 2024 21:44:05 +0200 Subject: [PATCH 10/20] fix: add correct env vars (#353) (#354) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix dockle scan on ci * fix registry login * debug imgs * scan tar imgs * test * add tar cleanup * test * pr workflow fix * declutter dockle * add comment * add microservice in pr comment * test w/ individual service failing * fix dockerfile * fix: vote table row responsiveness * Refactor/change logic for file upload to S3 (#328) * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * feat: dht-queue (#336) Added persistent dht-queue which will be responsible for publishing cid to dht * refactor: image upload to S3 (#337) * fitx/rationale-governance-format Rationale - Removed body.references since it will be empty until CC-portal enables that feature GAP title and abstract is now parsing in compatibility with CIP-0108 (body.title, body.abstract) * chore: change guides btn link * fix: rm-gap-title-abstract-len-constraint Remove len constraints for gap.title and gap.abstract (was 80 and 2500 char length) fixed error if db data is undefined when fetching from db sync * refactor: add redis username Added username env variable within backend/worker-service/ipfs-service * Fix add redis creds (#343) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args --------- * Fix add redis creds (#344) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args * refactor: cache docker-compose --------- * fix: typo * fix: typo * refactor: cache service * refactor/redis-auth (#345) * fix: plural grammar corrections * refactor: pruning worker processors (#346) * fix: latest updates content overlaping * refactor: ipfs service path and minor refactoring * fix: usersnap remove other buttons (#323) * fix: Overlapping on tables * fix: don't show top banner on mainnet * fix: show more btn not loading more content, update env example * refactor: renamed migration name for gap len constraint removal * refactor: ipfs volume * add correct vars (#352) --------- Co-authored-by: Baja-KS Co-authored-by: Lazar Lukić <57199246+Baja-KS@users.noreply.github.com> Co-authored-by: Vojimirovich Co-authored-by: Vojimirovich <85948457+Vojimirovich@users.noreply.github.com> Co-authored-by: nike-getto Co-authored-by: BEDev24 Co-authored-by: kubet --- example.env | 1 + frontend/Dockerfile | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 example.env diff --git a/example.env b/example.env new file mode 100644 index 00000000..dfbd622f --- /dev/null +++ b/example.env @@ -0,0 +1 @@ +REDIS_PASSWORD=password \ No newline at end of file diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 60afa292..6768131f 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -28,13 +28,17 @@ ENV NEXT_TELEMETRY_DISABLED 1 # Define build arguments for environment variables ARG NEXT_PUBLIC_API_URL -ARG NEXT_PUBLIC_USERSNAP_GLOBAL_API_KEY +ARG NEXT_PUBLIC_USERSNAP_SPACE_API_KEY ARG NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY +ARG NEXT_PUBLIC_HIDDEN_USERSNAP_PROJECT_IDS +ARG NEXT_PUBLIC_IS_MAINNET # Set the environment variables inside the container ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL} -ENV NEXT_PUBLIC_USERSNAP_GLOBAL_API_KEY=${NEXT_PUBLIC_USERSNAP_GLOBAL_API_KEY} +ENV NEXT_PUBLIC_USERSNAP_SPACE_API_KEY=${NEXT_PUBLIC_USERSNAP_SPACE_API_KEY} ENV NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY=${NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY} +ENV NEXT_PUBLIC_HIDDEN_USERSNAP_PROJECT_IDS=${NEXT_PUBLIC_HIDDEN_USERSNAP_PROJECT_IDS} +ENV NEXT_PUBLIC_IS_MAINNET=${NEXT_PUBLIC_IS_MAINNET} RUN \ if [ -f yarn.lock ]; then yarn run build; \ @@ -52,8 +56,10 @@ ENV NODE_ENV production # Disabled telemetry during runtime. ENV NEXT_TELEMETRY_DISABLED 1 ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL} -ENV NEXT_PUBLIC_USERSNAP_GLOBAL_API_KEY=${NEXT_PUBLIC_USERSNAP_GLOBAL_API_KEY} +ENV NEXT_PUBLIC_USERSNAP_SPACE_API_KEY=${NEXT_PUBLIC_USERSNAP_SPACE_API_KEY} ENV NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY=${NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY} +ENV NEXT_PUBLIC_HIDDEN_USERSNAP_PROJECT_IDS=${NEXT_PUBLIC_HIDDEN_USERSNAP_PROJECT_IDS} +ENV NEXT_PUBLIC_IS_MAINNET=${NEXT_PUBLIC_IS_MAINNET} RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs From a7d48d7290497c7656116bfa65de46daf6755b5d Mon Sep 17 00:00:00 2001 From: Milos <161627443+BEdev24@users.noreply.github.com> Date: Sat, 14 Sep 2024 21:15:33 +0200 Subject: [PATCH 11/20] refactor/fe-deployment (#357) Co-authored-by: nike-getto --- .github/workflows/merge.yaml | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/.github/workflows/merge.yaml b/.github/workflows/merge.yaml index 45bb15e2..9ba8b3b7 100644 --- a/.github/workflows/merge.yaml +++ b/.github/workflows/merge.yaml @@ -91,7 +91,6 @@ jobs: set -o pipefail sudo chmod +x lint.sh && ./lint.sh 2>&1 | tee code_lint_output.txt - - name: Unit tests id: unit_tests run: | @@ -131,21 +130,22 @@ jobs: outputs: type=docker,dest=/tmp/image-${{ matrix.name }}-${{ env.ENVIRONMENT }}.tar build-args: | NEXT_PUBLIC_API_URL=${{ secrets.PROD_NEXT_PUBLIC_API_URL }} - NEXT_PUBLIC_USERSNAP_GLOBAL_API_KEY=${{ secrets.PROD_NEXT_PUBLIC_USERSNAP_GLOBAL_API_KEY }} + NEXT_PUBLIC_USERSNAP_SPACE_API_KEY=${{ secrets.PROD_NEXT_PUBLIC_USERSNAP_SPACE_API_KEY }} NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY=${{ secrets.PROD_NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY }} + NEXT_PUBLIC_HIDDEN_USERSNAP_PROJECT_IDS=${{ secrets.PROD_NEXT_PUBLIC_HIDDEN_USERSNAP_PROJECT_IDS }} + NEXT_PUBLIC_IS_MAINNET=${{ secrets.PROD_NEXT_PUBLIC_IS_MAINNET }} - name: Scan Docker image with Dockle id: dockle run: | - wget -q https://github.com/goodwithtech/dockle/releases/download/v0.4.14/dockle_0.4.14_Linux-64bit.tar.gz - tar zxf dockle_0.4.14_Linux-64bit.tar.gz - sudo mv dockle /usr/local/bin - - dockle --exit-code 1 --exit-level fatal --format json --input '/tmp/image-${{ matrix.name }}-${{ env.ENVIRONMENT }}.tar' --output ${{ matrix.workdir }}/dockle_scan_output.json - cat ${{ matrix.workdir }}/dockle_scan_output.json + wget -q https://github.com/goodwithtech/dockle/releases/download/v0.4.14/dockle_0.4.14_Linux-64bit.tar.gz + tar zxf dockle_0.4.14_Linux-64bit.tar.gz + sudo mv dockle /usr/local/bin - echo "outcome=success" >> $GITHUB_OUTPUT + dockle --exit-code 1 --exit-level fatal --format json --input '/tmp/image-${{ matrix.name }}-${{ env.ENVIRONMENT }}.tar' --output ${{ matrix.workdir }}/dockle_scan_output.json + cat ${{ matrix.workdir }}/dockle_scan_output.json + echo "outcome=success" >> $GITHUB_OUTPUT - name: Login to GHCR uses: docker/login-action@v2 @@ -154,16 +154,14 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Push Docker image to GHCR run: | docker load -i '/tmp/image-${{ matrix.name }}-${{ env.ENVIRONMENT }}.tar' rm -rf '/tmp/image-${{ matrix.name }}-${{ env.ENVIRONMENT }}.tar' docker push ${{ steps.image_lowercase.outputs.lowercase }}:${{ env.TAG }} - - name: Deploy with Qovery - if: github.ref == 'refs/heads/develop' + if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master' env: QOVERY_CLI_ACCESS_TOKEN: ${{secrets.QOVERY_CLI_ACCESS_TOKEN }} run: | From aa8800b961089b8f8d2a2673749a839b05b54454 Mon Sep 17 00:00:00 2001 From: Milos <161627443+BEdev24@users.noreply.github.com> Date: Tue, 17 Sep 2024 20:51:18 +0200 Subject: [PATCH 12/20] fix:redis-tls (#362) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: add correct env vars (#353) * fix dockle scan on ci * fix registry login * debug imgs * scan tar imgs * test * add tar cleanup * test * pr workflow fix * declutter dockle * add comment * add microservice in pr comment * test w/ individual service failing * fix dockerfile * fix: vote table row responsiveness * Refactor/change logic for file upload to S3 (#328) * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * feat: dht-queue (#336) Added persistent dht-queue which will be responsible for publishing cid to dht * refactor: image upload to S3 (#337) * fitx/rationale-governance-format Rationale - Removed body.references since it will be empty until CC-portal enables that feature GAP title and abstract is now parsing in compatibility with CIP-0108 (body.title, body.abstract) * chore: change guides btn link * fix: rm-gap-title-abstract-len-constraint Remove len constraints for gap.title and gap.abstract (was 80 and 2500 char length) fixed error if db data is undefined when fetching from db sync * refactor: add redis username Added username env variable within backend/worker-service/ipfs-service * Fix add redis creds (#343) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args --------- Co-authored-by: nike-getto Co-authored-by: BEDev24 * Fix add redis creds (#344) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args * refactor: cache docker-compose --------- Co-authored-by: nike-getto Co-authored-by: BEDev24 * fix: typo * fix: typo * refactor: cache service * refactor/redis-auth (#345) * fix: plural grammar corrections * refactor: pruning worker processors (#346) * fix: latest updates content overlaping * refactor: ipfs service path and minor refactoring * fix: usersnap remove other buttons (#323) * fix: Overlapping on tables * fix: don't show top banner on mainnet * fix: show more btn not loading more content, update env example * refactor: renamed migration name for gap len constraint removal * refactor: ipfs volume * add correct vars (#352) Co-authored-by: nike-getto --------- Co-authored-by: Baja-KS Co-authored-by: Lazar Lukić <57199246+Baja-KS@users.noreply.github.com> Co-authored-by: Vojimirovich Co-authored-by: Vojimirovich <85948457+Vojimirovich@users.noreply.github.com> Co-authored-by: nike-getto Co-authored-by: BEDev24 Co-authored-by: kubet * fix:redis-tls (#361) * fix dockle scan on ci * fix registry login * debug imgs * scan tar imgs * test * add tar cleanup * test * pr workflow fix * declutter dockle * add comment * add microservice in pr comment * test w/ individual service failing * fix dockerfile * fix: vote table row responsiveness * Refactor/change logic for file upload to S3 (#328) * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * feat: dht-queue (#336) Added persistent dht-queue which will be responsible for publishing cid to dht * refactor: image upload to S3 (#337) * fitx/rationale-governance-format Rationale - Removed body.references since it will be empty until CC-portal enables that feature GAP title and abstract is now parsing in compatibility with CIP-0108 (body.title, body.abstract) * chore: change guides btn link * fix: rm-gap-title-abstract-len-constraint Remove len constraints for gap.title and gap.abstract (was 80 and 2500 char length) fixed error if db data is undefined when fetching from db sync * refactor: add redis username Added username env variable within backend/worker-service/ipfs-service * Fix add redis creds (#343) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args --------- Co-authored-by: nike-getto Co-authored-by: BEDev24 * Fix add redis creds (#344) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args * refactor: cache docker-compose --------- Co-authored-by: nike-getto Co-authored-by: BEDev24 * fix: typo * fix: typo * refactor: cache service * refactor/redis-auth (#345) * fix: plural grammar corrections * refactor: pruning worker processors (#346) * fix: latest updates content overlaping * refactor: ipfs service path and minor refactoring * fix: usersnap remove other buttons (#323) * fix: Overlapping on tables * fix: don't show top banner on mainnet * fix: show more btn not loading more content, update env example * refactor: renamed migration name for gap len constraint removal * refactor: ipfs volume * add correct vars (#352) Co-authored-by: nike-getto * fix: ipfs-redis-service (#360) * fix/ipfs-redis-service: tls connection to redis * fix/ipfs-redis-service: tls connection to redis --------- Co-authored-by: Baja-KS Co-authored-by: Lazar Lukić <57199246+Baja-KS@users.noreply.github.com> Co-authored-by: Vojimirovich Co-authored-by: Vojimirovich <85948457+Vojimirovich@users.noreply.github.com> Co-authored-by: nike-getto Co-authored-by: BEDev24 Co-authored-by: kubet --------- Co-authored-by: Baja-KS Co-authored-by: Lazar Lukić <57199246+Baja-KS@users.noreply.github.com> Co-authored-by: Vojimirovich Co-authored-by: Vojimirovich <85948457+Vojimirovich@users.noreply.github.com> Co-authored-by: nike-getto Co-authored-by: BEDev24 Co-authored-by: kubet --- backend/example.env | 1 + backend/src/redis/client/redis-client.ts | 1 + ipfs-service/example.env | 1 + ipfs-service/src/bullmq/bullmq.module.ts | 1 + worker-service/example.env | 1 + worker-service/src/bullmq/bullmq.module.ts | 1 + 6 files changed, 6 insertions(+) diff --git a/backend/example.env b/backend/example.env index d15953a9..1c9e1497 100644 --- a/backend/example.env +++ b/backend/example.env @@ -22,6 +22,7 @@ JWT_REFRESH_TOKEN_EXPIRES_IN=7d REDIS_HOST=cache REDIS_PORT=6379 REDIS_PASSWORD=password +REDIS_TLS=false # AWS SES AWS_ACCESS_KEY_ID=your_access_key_id diff --git a/backend/src/redis/client/redis-client.ts b/backend/src/redis/client/redis-client.ts index f11a65a3..763d9d5f 100644 --- a/backend/src/redis/client/redis-client.ts +++ b/backend/src/redis/client/redis-client.ts @@ -10,6 +10,7 @@ export const redisClientFactory: FactoryProvider = { host: configService.getOrThrow('REDIS_HOST'), port: configService.getOrThrow('REDIS_PORT'), password: configService.getOrThrow('REDIS_PASSWORD'), + ...(configService.get('REDIS_TLS') === 'false' ? {} : { tls: {} }), }); redisInstance.on('error', (e) => { diff --git a/ipfs-service/example.env b/ipfs-service/example.env index 0678ec6d..e7a58cce 100644 --- a/ipfs-service/example.env +++ b/ipfs-service/example.env @@ -11,6 +11,7 @@ IPNS_CONSTITUTION_KEY_NAME='some-key-name' REDIS_HOST=localhost REDIS_PORT=6379 REDIS_PASSWORD=password +REDIS_TLS=false ## DHT QUEUE ## # Attempts diff --git a/ipfs-service/src/bullmq/bullmq.module.ts b/ipfs-service/src/bullmq/bullmq.module.ts index 8dd4d1fd..a616bf14 100644 --- a/ipfs-service/src/bullmq/bullmq.module.ts +++ b/ipfs-service/src/bullmq/bullmq.module.ts @@ -14,6 +14,7 @@ import { ExpressAdapter } from "@bull-board/express"; host: configService.getOrThrow("REDIS_HOST"), port: configService.getOrThrow("REDIS_PORT"), password: configService.getOrThrow("REDIS_PASSWORD"), + ...(configService.get('REDIS_TLS') === 'false' ? {} : { tls: {} }), }, }), inject: [ConfigService], diff --git a/worker-service/example.env b/worker-service/example.env index f15d8584..1265c48c 100644 --- a/worker-service/example.env +++ b/worker-service/example.env @@ -17,6 +17,7 @@ DB_SYNC_POSTGRES_PASSWORD=password REDIS_HOST=cache REDIS_PORT=6379 REDIS_PASSWORD=password +REDIS_TLS=false # PAGINATION HOT_ADDRESSES_PER_PAGE=10 diff --git a/worker-service/src/bullmq/bullmq.module.ts b/worker-service/src/bullmq/bullmq.module.ts index 0b0cbb58..68523009 100644 --- a/worker-service/src/bullmq/bullmq.module.ts +++ b/worker-service/src/bullmq/bullmq.module.ts @@ -17,6 +17,7 @@ import { ExpressAdapter } from '@bull-board/express'; host: configService.getOrThrow('REDIS_HOST'), port: configService.getOrThrow('REDIS_PORT'), password: configService.getOrThrow('REDIS_PASSWORD'), + ...(configService.get('REDIS_TLS') === 'false' ? {} : { tls: {} }), }, }), inject: [ConfigService], From 9ddacb89af3562b839548e314c32ae2eafced090 Mon Sep 17 00:00:00 2001 From: Dzon <84495632+nikolajovancevic@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:54:16 +0200 Subject: [PATCH 13/20] fix/add-update-rationale-button (#366) --- .../governance/dto/gov-action-proposal-dto.ts | 11 ++++ .../governance/facade/governance.facade.ts | 9 ++- .../governance/mapper/governance-mapper.ts | 59 +++++++++++-------- .../governance/services/governance.service.ts | 24 +------- 4 files changed, 54 insertions(+), 49 deletions(-) diff --git a/backend/src/governance/dto/gov-action-proposal-dto.ts b/backend/src/governance/dto/gov-action-proposal-dto.ts index 4a1d750c..91d7b6e9 100644 --- a/backend/src/governance/dto/gov-action-proposal-dto.ts +++ b/backend/src/governance/dto/gov-action-proposal-dto.ts @@ -11,6 +11,17 @@ export class GovActionProposalDto { status: GovActionProposalStatus; voteStatus: VoteStatus; hasRationale: boolean; + votedBy: string[]; + rationaleBy: string[]; submitTime: Date; endTime: Date; } + +export class VoteStatusRationaleInfoDto { + constructor(voteStatus: VoteStatus, hasRationale: boolean) { + this.voteStatus = voteStatus; + this.hasRationale = hasRationale; + } + voteStatus: VoteStatus; + hasRationale: boolean; +} diff --git a/backend/src/governance/facade/governance.facade.ts b/backend/src/governance/facade/governance.facade.ts index f0f2f38b..29ba4777 100644 --- a/backend/src/governance/facade/governance.facade.ts +++ b/backend/src/governance/facade/governance.facade.ts @@ -139,7 +139,14 @@ export class GovernanceFacade { userId: string, ): Promise> { const gapPaginatedDto = - await this.governanceService.searchGovActionProposals(query, userId); + await this.governanceService.searchGovActionProposals(query); + + gapPaginatedDto.items.forEach((gap) => { + const userVotesRationaleInfo = + GovernanceMapper.returnUserVoteRationaleInfo(gap, userId); + gap.voteStatus = userVotesRationaleInfo.voteStatus; + gap.hasRationale = userVotesRationaleInfo.hasRationale; + }); return new PaginationDtoMapper< GovActionProposalDto, diff --git a/backend/src/governance/mapper/governance-mapper.ts b/backend/src/governance/mapper/governance-mapper.ts index 44b867d7..f13a3c99 100644 --- a/backend/src/governance/mapper/governance-mapper.ts +++ b/backend/src/governance/mapper/governance-mapper.ts @@ -1,7 +1,10 @@ import { IpfsContentDto } from 'src/ipfs/dto/ipfs-content.dto'; import { GovernanceActionProposalResponse } from '../api/response/gov-action-proposal.response'; import { VoteResponse } from '../api/response/vote.response'; -import { GovActionProposalDto } from '../dto/gov-action-proposal-dto'; +import { + GovActionProposalDto, + VoteStatusRationaleInfoDto as UserVoteStatusRationaleDto, +} from '../dto/gov-action-proposal-dto'; import { VoteDto } from '../dto/vote.dto'; import { GovActionProposal } from '../entities/gov-action-proposal.entity'; import { Vote } from '../entities/vote.entity'; @@ -65,39 +68,45 @@ export class GovernanceMapper { govActionProposalDto.type = govActionProposal.govActionType; govActionProposalDto.status = GovActionProposalStatus[govActionProposal.status]; - govActionProposalDto.voteStatus = - GovernanceMapper.returnVoteStatusForGovActionProposal(govActionProposal); - govActionProposalDto.hasRationale = !GovernanceMapper.emptyArray( - govActionProposal.rationales, - ); govActionProposalDto.submitTime = govActionProposal.submitTime; govActionProposalDto.endTime = govActionProposal.endTime; + govActionProposalDto.votedBy = govActionProposal.votes?.map( + (vote) => vote.userId, + ); + govActionProposalDto.rationaleBy = govActionProposal.rationales?.map( + (rationale) => rationale.userId, + ); return govActionProposalDto; } - private static returnVoteStatusForGovActionProposal( - govActionProposal: GovActionProposal, - ): VoteStatus { - if ( - GovernanceMapper.emptyArray(govActionProposal.votes) && - GovernanceMapper.emptyArray(govActionProposal.rationales) - ) { - return VoteStatus.Unvoted; - } else if ( - GovernanceMapper.emptyArray(govActionProposal.votes) && - !GovernanceMapper.emptyArray(govActionProposal.rationales) - ) { - return VoteStatus.Pending; + static returnUserVoteRationaleInfo( + gapDto: GovActionProposalDto, + userId: string, + ): UserVoteStatusRationaleDto { + const userHasVote = GovernanceMapper.userHasVote(gapDto.votedBy, userId); + const userHasRationale = GovernanceMapper.userHasRationale( + gapDto.rationaleBy, + userId, + ); + let voteStatus: VoteStatus; + if (!userHasVote && !userHasRationale) { + voteStatus = VoteStatus.Unvoted; + } else if (!userHasVote && userHasRationale) { + voteStatus = VoteStatus.Pending; + } else { + voteStatus = VoteStatus.Voted; } - return VoteStatus.Voted; + + return new UserVoteStatusRationaleDto(voteStatus, userHasRationale); } - private static emptyArray(array: any[]): boolean { - if (Array.isArray(array) && array.length) { - return false; - } - return true; + private static userHasVote(votedBy: string[], userId: string): boolean { + return votedBy?.some((vote) => vote === userId); + } + + static userHasRationale(rationaleBy: string[], userId: string): boolean { + return rationaleBy?.some((rationale) => rationale === userId); } static govActionProposalDtoToResponse( diff --git a/backend/src/governance/services/governance.service.ts b/backend/src/governance/services/governance.service.ts index 80ce9941..57709e58 100644 --- a/backend/src/governance/services/governance.service.ts +++ b/backend/src/governance/services/governance.service.ts @@ -79,13 +79,10 @@ export class GovernanceService { async searchGovActionProposals( query: PaginateQuery, - userId?: string, ): Promise> { - const customQuery = this.returnGapQuery(userId); - const result = await this.paginator.paginate( query, - customQuery, + this.govActionMetadataRepository, GOVERNANCE_ACTION_PROPOSAL_CONFIG, ); @@ -95,25 +92,6 @@ export class GovernanceService { >().paginatedToDto(result, GovernanceMapper.govActionProposalToDto); } - private returnGapQuery( - userId: string, - ): SelectQueryBuilder { - return this.govActionMetadataRepository - .createQueryBuilder('governanceActionProposals') - .leftJoinAndSelect( - 'governanceActionProposals.votes', - 'vote', - 'vote.userId = :userId', - { userId: userId }, - ) - .leftJoinAndSelect( - 'governanceActionProposals.rationales', - 'rationale', - 'rationale.userId = :userId', - { userId: userId }, - ); - } - async addRationale(rationaleDto: RationaleDto): Promise { const rationale = this.rationaleRepository.create(rationaleDto); const savedRationale = await this.rationaleRepository.save(rationale); From be6e134e312e0811fbd267b26676db7585174db7 Mon Sep 17 00:00:00 2001 From: Milos <161627443+BEdev24@users.noreply.github.com> Date: Fri, 20 Sep 2024 12:23:42 +0200 Subject: [PATCH 14/20] Update README.md (#369) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1b932512..60706f28 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Welcome to the official repository for the Constitution Committee Portal. -The primary purpose of the solution is to host the Cardano Constitution and allow anyone to get familiar with it and follow its evolution over time. It also serves as the single point of truth for the Cardano Community members to see how Constitutional Committee members voted on a specific Governance Action, with the inclusion of their rationale. For members of the Constitutional Committee, it serves as a portal to add reasoning to their votes and prepare it as an off-chain resource to be attached to on-chain governance actions. +The primary purpose of this solution is to host the Cardano Constitution and allow anyone to get familiar with it and follow its evolution over time. It also serves as the single point of truth for the Cardano Community members to see how Constitutional Committee members voted on a specific Governance Action, with the inclusion of their rationale. For members of the Constitutional Committee, it serves as a portal to add reasoning to their votes and prepare it as an off-chain resource to be attached to on-chain governance actions. ## Navigation From 6195c1187cb5f1f209c8af015b3d5f8543b21c76 Mon Sep 17 00:00:00 2001 From: Milos <161627443+BEdev24@users.noreply.github.com> Date: Wed, 25 Sep 2024 10:52:20 +0200 Subject: [PATCH 15/20] fix/multiple-usersnap-buttons (#385) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: add correct env vars (#353) * fix dockle scan on ci * fix registry login * debug imgs * scan tar imgs * test * add tar cleanup * test * pr workflow fix * declutter dockle * add comment * add microservice in pr comment * test w/ individual service failing * fix dockerfile * fix: vote table row responsiveness * Refactor/change logic for file upload to S3 (#328) * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * feat: dht-queue (#336) Added persistent dht-queue which will be responsible for publishing cid to dht * refactor: image upload to S3 (#337) * fitx/rationale-governance-format Rationale - Removed body.references since it will be empty until CC-portal enables that feature GAP title and abstract is now parsing in compatibility with CIP-0108 (body.title, body.abstract) * chore: change guides btn link * fix: rm-gap-title-abstract-len-constraint Remove len constraints for gap.title and gap.abstract (was 80 and 2500 char length) fixed error if db data is undefined when fetching from db sync * refactor: add redis username Added username env variable within backend/worker-service/ipfs-service * Fix add redis creds (#343) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args --------- Co-authored-by: nike-getto Co-authored-by: BEDev24 * Fix add redis creds (#344) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args * refactor: cache docker-compose --------- Co-authored-by: nike-getto Co-authored-by: BEDev24 * fix: typo * fix: typo * refactor: cache service * refactor/redis-auth (#345) * fix: plural grammar corrections * refactor: pruning worker processors (#346) * fix: latest updates content overlaping * refactor: ipfs service path and minor refactoring * fix: usersnap remove other buttons (#323) * fix: Overlapping on tables * fix: don't show top banner on mainnet * fix: show more btn not loading more content, update env example * refactor: renamed migration name for gap len constraint removal * refactor: ipfs volume * add correct vars (#352) Co-authored-by: nike-getto --------- Co-authored-by: Baja-KS Co-authored-by: Lazar Lukić <57199246+Baja-KS@users.noreply.github.com> Co-authored-by: Vojimirovich Co-authored-by: Vojimirovich <85948457+Vojimirovich@users.noreply.github.com> Co-authored-by: nike-getto Co-authored-by: BEDev24 Co-authored-by: kubet * fix:redis-tls (#361) * fix dockle scan on ci * fix registry login * debug imgs * scan tar imgs * test * add tar cleanup * test * pr workflow fix * declutter dockle * add comment * add microservice in pr comment * test w/ individual service failing * fix dockerfile * fix: vote table row responsiveness * Refactor/change logic for file upload to S3 (#328) * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * feat: dht-queue (#336) Added persistent dht-queue which will be responsible for publishing cid to dht * refactor: image upload to S3 (#337) * fitx/rationale-governance-format Rationale - Removed body.references since it will be empty until CC-portal enables that feature GAP title and abstract is now parsing in compatibility with CIP-0108 (body.title, body.abstract) * chore: change guides btn link * fix: rm-gap-title-abstract-len-constraint Remove len constraints for gap.title and gap.abstract (was 80 and 2500 char length) fixed error if db data is undefined when fetching from db sync * refactor: add redis username Added username env variable within backend/worker-service/ipfs-service * Fix add redis creds (#343) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args --------- Co-authored-by: nike-getto Co-authored-by: BEDev24 * Fix add redis creds (#344) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args * refactor: cache docker-compose --------- Co-authored-by: nike-getto Co-authored-by: BEDev24 * fix: typo * fix: typo * refactor: cache service * refactor/redis-auth (#345) * fix: plural grammar corrections * refactor: pruning worker processors (#346) * fix: latest updates content overlaping * refactor: ipfs service path and minor refactoring * fix: usersnap remove other buttons (#323) * fix: Overlapping on tables * fix: don't show top banner on mainnet * fix: show more btn not loading more content, update env example * refactor: renamed migration name for gap len constraint removal * refactor: ipfs volume * add correct vars (#352) Co-authored-by: nike-getto * fix: ipfs-redis-service (#360) * fix/ipfs-redis-service: tls connection to redis * fix/ipfs-redis-service: tls connection to redis --------- Co-authored-by: Baja-KS Co-authored-by: Lazar Lukić <57199246+Baja-KS@users.noreply.github.com> Co-authored-by: Vojimirovich Co-authored-by: Vojimirovich <85948457+Vojimirovich@users.noreply.github.com> Co-authored-by: nike-getto Co-authored-by: BEDev24 Co-authored-by: kubet * fix:add-update-rationale-button (#364) * fix dockle scan on ci * fix registry login * debug imgs * scan tar imgs * test * add tar cleanup * test * pr workflow fix * declutter dockle * add comment * add microservice in pr comment * test w/ individual service failing * fix dockerfile * fix: vote table row responsiveness * Refactor/change logic for file upload to S3 (#328) * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * feat: dht-queue (#336) Added persistent dht-queue which will be responsible for publishing cid to dht * refactor: image upload to S3 (#337) * fitx/rationale-governance-format Rationale - Removed body.references since it will be empty until CC-portal enables that feature GAP title and abstract is now parsing in compatibility with CIP-0108 (body.title, body.abstract) * chore: change guides btn link * fix: rm-gap-title-abstract-len-constraint Remove len constraints for gap.title and gap.abstract (was 80 and 2500 char length) fixed error if db data is undefined when fetching from db sync * refactor: add redis username Added username env variable within backend/worker-service/ipfs-service * Fix add redis creds (#343) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args --------- Co-authored-by: nike-getto Co-authored-by: BEDev24 * Fix add redis creds (#344) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args * refactor: cache docker-compose --------- Co-authored-by: nike-getto Co-authored-by: BEDev24 * fix: typo * fix: typo * refactor: cache service * refactor/redis-auth (#345) * fix: plural grammar corrections * refactor: pruning worker processors (#346) * fix: latest updates content overlaping * refactor: ipfs service path and minor refactoring * fix: usersnap remove other buttons (#323) * fix: Overlapping on tables * fix: don't show top banner on mainnet * fix: show more btn not loading more content, update env example * refactor: renamed migration name for gap len constraint removal * refactor: ipfs volume * add correct vars (#352) Co-authored-by: nike-getto * fix: ipfs-redis-service (#360) * fix/ipfs-redis-service: tls connection to redis * fix/ipfs-redis-service: tls connection to redis * fix/gov-search-rationale-votes: user votes and rationale are being checked when data is fetched (#359) Co-authored-by: BEDev24 --------- Co-authored-by: Baja-KS Co-authored-by: Lazar Lukić <57199246+Baja-KS@users.noreply.github.com> Co-authored-by: Vojimirovich Co-authored-by: Vojimirovich <85948457+Vojimirovich@users.noreply.github.com> Co-authored-by: nike-getto Co-authored-by: BEDev24 Co-authored-by: kubet * refactor/staging-deploy (#380) * Update merge.yaml * refactor: pr pipeline * merge develop-staging (#381) * feat: added new selectors * feat: Upload button selector ids * feat: Input and Select selector ids * feat: User List table selector ids * fix: MultipleSelect rename selector ids * fix: Rename Upload component selctor ids * feat: Modal action buttons selector ids-Add member and Upload constitution * feat: AdminTopNav Search component selector id * feat: Admin signout & modal selector ids * feat: AdminTopNav buttons selector ids * feat: Navigation links selector ids * Feat: Footer selector ids * feat: Constitution page selector ids * feat: Latest updates and votes selector ids * feat: GA table selector ids * fix dockle scan on ci * fix registry login * debug imgs * scan tar imgs * test * add tar cleanup * test * pr workflow fix * declutter dockle * add comment * add microservice in pr comment * test w/ individual service failing * fix dockerfile * fix: vote table row responsiveness * Refactor/change logic for file upload to S3 (#328) * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * feat: dht-queue (#336) Added persistent dht-queue which will be responsible for publishing cid to dht * refactor: image upload to S3 (#337) * fitx/rationale-governance-format Rationale - Removed body.references since it will be empty until CC-portal enables that feature GAP title and abstract is now parsing in compatibility with CIP-0108 (body.title, body.abstract) * chore: change guides btn link * fix: rm-gap-title-abstract-len-constraint Remove len constraints for gap.title and gap.abstract (was 80 and 2500 char length) fixed error if db data is undefined when fetching from db sync * refactor: add redis username Added username env variable within backend/worker-service/ipfs-service * Fix add redis creds (#343) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args --------- Co-authored-by: nike-getto Co-authored-by: BEDev24 * Fix add redis creds (#344) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args * refactor: cache docker-compose --------- Co-authored-by: nike-getto Co-authored-by: BEDev24 * fix: typo * fix: typo * refactor: cache service * refactor/redis-auth (#345) * fix: plural grammar corrections * refactor: pruning worker processors (#346) * fix: latest updates content overlaping * refactor: ipfs service path and minor refactoring * fix: usersnap remove other buttons (#323) * fix: Overlapping on tables * fix: don't show top banner on mainnet * fix: show more btn not loading more content, update env example * refactor: renamed migration name for gap len constraint removal * refactor: ipfs volume * add correct vars (#352) Co-authored-by: nike-getto * fix: ipfs-redis-service (#360) * fix/ipfs-redis-service: tls connection to redis * fix/ipfs-redis-service: tls connection to redis * fix/gov-search-rationale-votes: user votes and rationale are being checked when data is fetched (#359) Co-authored-by: BEDev24 * fix: usersnap showing all on path change * fix: Remove comments for selector ids * fix: Usersnap query params issue --------- Co-authored-by: nikolajovancevic Co-authored-by: Kristina Co-authored-by: Baja-KS Co-authored-by: Lazar Lukić <57199246+Baja-KS@users.noreply.github.com> Co-authored-by: Vojimirovich Co-authored-by: Vojimirovich <85948457+Vojimirovich@users.noreply.github.com> Co-authored-by: nike-getto Co-authored-by: BEDev24 Co-authored-by: kubet Co-authored-by: Kristina <42462482+Kristina2103@users.noreply.github.com> * refactor:staging-branch (#382) --------- Co-authored-by: Baja-KS Co-authored-by: Lazar Lukić <57199246+Baja-KS@users.noreply.github.com> Co-authored-by: Vojimirovich Co-authored-by: Vojimirovich <85948457+Vojimirovich@users.noreply.github.com> Co-authored-by: nike-getto Co-authored-by: BEDev24 Co-authored-by: kubet Co-authored-by: nikolajovancevic Co-authored-by: Kristina Co-authored-by: Kristina <42462482+Kristina2103@users.noreply.github.com> --- .github/workflows/pr.yaml | 2 +- frontend/src/components/atoms/Button.tsx | 2 + frontend/src/components/atoms/Chip/Chip.tsx | 10 ++++- .../src/components/atoms/Chip/ChipList.tsx | 3 ++ frontend/src/components/atoms/CopyButton.tsx | 11 ++++- .../components/atoms/GovActionStatusPill.tsx | 1 + .../src/components/atoms/MultipleSelect.tsx | 23 ++++++++-- .../src/components/atoms/ShowMoreButton.tsx | 2 +- frontend/src/components/atoms/StatusPill.tsx | 1 + frontend/src/components/atoms/Typography.tsx | 1 + .../src/components/atoms/UploadFileButton.tsx | 4 ++ frontend/src/components/atoms/VotePill.tsx | 1 + .../components/atoms/modal/ModalActions.tsx | 14 +++++- frontend/src/components/atoms/types.ts | 2 + frontend/src/components/molecules/Card.tsx | 3 ++ .../src/components/molecules/CopyCard.tsx | 4 +- .../src/components/molecules/CopyPill.tsx | 4 +- .../molecules/Field/MultipleSelect.tsx | 3 ++ .../src/components/molecules/Field/types.ts | 1 + .../molecules/GovernanceActionsFilters.tsx | 2 +- .../molecules/GovernanceActionsSorting.tsx | 4 +- .../src/components/molecules/Reasoning.tsx | 7 ++- frontend/src/components/molecules/Search.tsx | 9 +++- .../molecules/UserCard/UserBasicInfo.tsx | 7 ++- .../molecules/UserCard/UserRole.tsx | 1 + .../molecules/UserProfileButton.tsx | 3 ++ .../organisms/Constitution/Constitution.tsx | 5 ++- .../organisms/Constitution/MDXComponents.tsx | 8 +++- .../organisms/ControlledField/Upload.tsx | 10 +---- .../organisms/ControlledField/types.ts | 1 + .../organisms/Footer/AdminFooter.tsx | 1 + .../components/organisms/Footer/Footer.tsx | 22 ++++++++-- .../GovActionTable/GovActionTableRow.tsx | 44 ++++++++++++------- .../src/components/organisms/Hero/Hero.tsx | 9 +++- .../components/organisms/Hero/HeroActions.tsx | 8 +++- .../components/organisms/Modals/AddMember.tsx | 5 ++- .../Modals/CompareConstitutionModal.tsx | 6 ++- .../organisms/Modals/GovActionModal.tsx | 24 ++++++++-- .../Modals/PreviewReasoningModal.tsx | 27 +++++++++--- .../organisms/Modals/SignInModal.tsx | 13 +++++- .../organisms/Modals/SignOutModal.tsx | 14 ++++-- .../organisms/Modals/SignUpModal.tsx | 2 + .../organisms/Modals/UploadConstitution.tsx | 6 ++- .../src/components/organisms/NotFound.tsx | 4 +- .../components/organisms/PageTitleTabs.tsx | 1 + .../organisms/TopNavigation/AdminTopNav.tsx | 25 +++++++++-- .../organisms/TopNavigation/TopNav.tsx | 3 +- .../organisms/VotesTable/VotesTableRow.tsx | 25 ++++++----- frontend/src/context/usersnap.tsx | 41 ++++++++++++----- 49 files changed, 330 insertions(+), 99 deletions(-) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 1da5163a..a095c0bb 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -123,7 +123,7 @@ jobs: NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY=${{ secrets.PROD_NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY }} NEXT_PUBLIC_HIDDEN_USERSNAP_PROJECT_IDS=${{ secrets.PROD_NEXT_PUBLIC_HIDDEN_USERSNAP_PROJECT_IDS }} NEXT_PUBLIC_IS_MAINNET=${{ secrets.PROD_NEXT_PUBLIC_IS_MAINNET }} - + - name: Scan Docker image with Dockle id: dockle run: | diff --git a/frontend/src/components/atoms/Button.tsx b/frontend/src/components/atoms/Button.tsx index ea877d75..67f6ef2f 100644 --- a/frontend/src/components/atoms/Button.tsx +++ b/frontend/src/components/atoms/Button.tsx @@ -7,6 +7,7 @@ export const Button = ({ size = "large", variant = "contained", sx, + dataTestId, ...props }: ButtonProps) => { const buttonHeight = { @@ -24,6 +25,7 @@ export const Button = ({ ...sx, }} variant={variant} + data-testid={dataTestId} {...props} > {props.children} diff --git a/frontend/src/components/atoms/Chip/Chip.tsx b/frontend/src/components/atoms/Chip/Chip.tsx index 9e6a6c2b..bc597598 100644 --- a/frontend/src/components/atoms/Chip/Chip.tsx +++ b/frontend/src/components/atoms/Chip/Chip.tsx @@ -6,11 +6,13 @@ interface ChipProps { label: string; showCloseButton?: boolean; onClick?: () => void; + dataTestId?: string; } export const Chip = ({ label, showCloseButton = false, onClick, + dataTestId, }: ChipProps) => ( - + {label} {showCloseButton && ( - + )} diff --git a/frontend/src/components/atoms/Chip/ChipList.tsx b/frontend/src/components/atoms/Chip/ChipList.tsx index 81547886..5cc3263a 100644 --- a/frontend/src/components/atoms/Chip/ChipList.tsx +++ b/frontend/src/components/atoms/Chip/ChipList.tsx @@ -5,10 +5,12 @@ export const ChipList = ({ list, showCloseButton, onClick, + dataTestId, }: { list: string[]; showCloseButton?: boolean; onClick?: () => void; + dataTestId?: string; }) => ( {list.map((item) => ( @@ -17,6 +19,7 @@ export const ChipList = ({ onClick={onClick} showCloseButton={showCloseButton} label={item} + dataTestId={dataTestId} /> ))} diff --git a/frontend/src/components/atoms/CopyButton.tsx b/frontend/src/components/atoms/CopyButton.tsx index c020ce1d..d9da8988 100644 --- a/frontend/src/components/atoms/CopyButton.tsx +++ b/frontend/src/components/atoms/CopyButton.tsx @@ -11,9 +11,16 @@ interface Props { text: string; variant?: string; size?: number; + dataTestId?: string; } -export const CopyButton = ({ isChecked, text, variant, size = 24 }: Props) => { +export const CopyButton = ({ + isChecked, + text, + variant, + size = 24, + dataTestId = "copy-button", +}: Props) => { const { addSuccessAlert } = useSnackbar(); const t = useTranslations("Snackbar"); @@ -31,7 +38,7 @@ export const CopyButton = ({ isChecked, text, variant, size = 24 }: Props) => { return ( copy { navigator.clipboard.writeText(text); diff --git a/frontend/src/components/atoms/GovActionStatusPill.tsx b/frontend/src/components/atoms/GovActionStatusPill.tsx index d5edf738..707295c9 100644 --- a/frontend/src/components/atoms/GovActionStatusPill.tsx +++ b/frontend/src/components/atoms/GovActionStatusPill.tsx @@ -41,6 +41,7 @@ export const GovActionStatusPill = ({ fontSize={12} fontWeight={400} lineHeight="16px" + data-testid="ga-table-vote-status-text" > {status} diff --git a/frontend/src/components/atoms/MultipleSelect.tsx b/frontend/src/components/atoms/MultipleSelect.tsx index 66a843d0..9f134384 100644 --- a/frontend/src/components/atoms/MultipleSelect.tsx +++ b/frontend/src/components/atoms/MultipleSelect.tsx @@ -40,6 +40,7 @@ export function MultipleSelect({ multiple = true, required, name, + dataTestId, }: MultipleSelectProps) { const theme = useTheme(); const [selectedValue, setSelectedValue] = React.useState([]); @@ -70,7 +71,14 @@ export function MultipleSelect({ (item) => item.value === selectedValue[0] ); if (selectedOption) { - return {selectedOption.label}; + return ( + + {selectedOption.label} + + ); } } return ( @@ -101,6 +109,7 @@ export function MultipleSelect({ renderValue={renderValue} MenuProps={MenuProps} required={required} + data-testid={`${dataTestId}--dropdown`} > {placeholder} @@ -112,9 +121,17 @@ export function MultipleSelect({ style={getStyles(item.value, selectedValue, theme)} > {multiple && ( - -1} /> + -1} + /> )} - {item.label} + + {item.label} + ))} diff --git a/frontend/src/components/atoms/ShowMoreButton.tsx b/frontend/src/components/atoms/ShowMoreButton.tsx index e6fa7bd4..7dfed1d2 100644 --- a/frontend/src/components/atoms/ShowMoreButton.tsx +++ b/frontend/src/components/atoms/ShowMoreButton.tsx @@ -15,7 +15,7 @@ export const ShowMoreButton = ({ isLoading, hasNextPage, callBack }: Props) => { ) : ( hasNextPage && ( - diff --git a/frontend/src/components/atoms/StatusPill.tsx b/frontend/src/components/atoms/StatusPill.tsx index 0a4863e0..175439e6 100644 --- a/frontend/src/components/atoms/StatusPill.tsx +++ b/frontend/src/components/atoms/StatusPill.tsx @@ -41,6 +41,7 @@ export const StatusPill = ({ fontSize={12} fontWeight={400} lineHeight="16px" + data-testid="user-status-text" > {status} diff --git a/frontend/src/components/atoms/Typography.tsx b/frontend/src/components/atoms/Typography.tsx index 6dfcacd2..5df6a9fa 100644 --- a/frontend/src/components/atoms/Typography.tsx +++ b/frontend/src/components/atoms/Typography.tsx @@ -6,6 +6,7 @@ import { TypographyProps } from "./types"; export const Typography = ({ color, variant = "body1", + dataTestId, ...props }: TypographyProps) => { const fontSize = { diff --git a/frontend/src/components/atoms/UploadFileButton.tsx b/frontend/src/components/atoms/UploadFileButton.tsx index 25007a35..9d105600 100644 --- a/frontend/src/components/atoms/UploadFileButton.tsx +++ b/frontend/src/components/atoms/UploadFileButton.tsx @@ -8,6 +8,7 @@ import { ButtonProps, FormErrorMessageProps } from "./types"; interface UploadFileButtonProps extends Omit { onChange: (file: File) => void; accept?: string; + dataTestId?: string; } export const UploadFileButton = ({ @@ -17,6 +18,7 @@ export const UploadFileButton = ({ errorStyles, name, accept = "image/jpeg", + dataTestId, ...buttonProps }: UploadFileButtonProps & FormErrorMessageProps) => { const [selectedFile, setSelectedFile] = useState(null); @@ -39,10 +41,12 @@ export const UploadFileButton = ({ style={{ display: "none" }} type="file" onChange={fileChange} + data-testid={`${dataTestId}-input`} /> - diff --git a/frontend/src/components/atoms/types.ts b/frontend/src/components/atoms/types.ts index 45aba4d6..3f14181e 100644 --- a/frontend/src/components/atoms/types.ts +++ b/frontend/src/components/atoms/types.ts @@ -10,6 +10,7 @@ import { ButtonProps as MUIButtonProps } from "@mui/material/Button"; export type ButtonProps = Omit & { size?: "small" | "medium" | "large" | "extraLarge"; + dataTestId?: string; }; export type TypographyProps = Pick< @@ -30,6 +31,7 @@ export type TypographyProps = Pick< | "body1" | "body2" | "caption"; + dataTestId?: string; }; export type InputProps = InputBaseProps & { diff --git a/frontend/src/components/molecules/Card.tsx b/frontend/src/components/molecules/Card.tsx index f13818a9..443e7cbd 100644 --- a/frontend/src/components/molecules/Card.tsx +++ b/frontend/src/components/molecules/Card.tsx @@ -16,6 +16,7 @@ type CardProps = PropsWithChildren & { label?: string; sx?: SxProps; variant?: "default" | "error" | "primary" | "success" | "warning"; + dataTestId?: string; }; export const Card = ({ @@ -25,6 +26,7 @@ export const Card = ({ elevation = 4, label, sx, + dataTestId = "card", }: CardProps) => { const colors = COLORS[variant]; @@ -40,6 +42,7 @@ export const Card = ({ position: "relative", ...sx, }} + data-testid={dataTestId} > {label && ( {title} - {copyText} + + {copyText} + diff --git a/frontend/src/components/molecules/CopyPill.tsx b/frontend/src/components/molecules/CopyPill.tsx index 92941fc5..58ee4102 100644 --- a/frontend/src/components/molecules/CopyPill.tsx +++ b/frontend/src/components/molecules/CopyPill.tsx @@ -23,7 +23,9 @@ export const CopyPill = ({ copyText, copyValue, iconSize = 14, sx }: Props) => { sx={sx} > - {copyText} + + {copyText} + ); }; diff --git a/frontend/src/components/molecules/Field/MultipleSelect.tsx b/frontend/src/components/molecules/Field/MultipleSelect.tsx index 8220d6dd..c4245239 100644 --- a/frontend/src/components/molecules/Field/MultipleSelect.tsx +++ b/frontend/src/components/molecules/Field/MultipleSelect.tsx @@ -21,6 +21,7 @@ export const MultipleSelect = ({ multiple, required, name, + dataTestId, ...rest }: MultipleSelectProps) => { return ( @@ -31,6 +32,7 @@ export const MultipleSelect = ({ sx={{ mb: 0.5 }} variant="body2" {...labelStyles} + dataTestId={`${dataTestId}-text`} > {label} @@ -42,6 +44,7 @@ export const MultipleSelect = ({ multiple={multiple} required={required} name={name} + dataTestId={dataTestId} /> { items: SeletItem[]; onChange: (...event: any[]) => void; multiple?: boolean; + dataTestId?: string; } diff --git a/frontend/src/components/molecules/GovernanceActionsFilters.tsx b/frontend/src/components/molecules/GovernanceActionsFilters.tsx index 2d4b930a..4f8d19df 100644 --- a/frontend/src/components/molecules/GovernanceActionsFilters.tsx +++ b/frontend/src/components/molecules/GovernanceActionsFilters.tsx @@ -104,7 +104,7 @@ export const GovernanceActionsFilters = ({ /> } label={ - + {item.label} } diff --git a/frontend/src/components/molecules/GovernanceActionsSorting.tsx b/frontend/src/components/molecules/GovernanceActionsSorting.tsx index eca84d2e..ec177609 100644 --- a/frontend/src/components/molecules/GovernanceActionsSorting.tsx +++ b/frontend/src/components/molecules/GovernanceActionsSorting.tsx @@ -73,7 +73,9 @@ export const GovernanceActionsSorting = ({ key={item.key} value={item.key} control={} - label={item.label} + label={ + {item.label} + } /> ))} diff --git a/frontend/src/components/molecules/Reasoning.tsx b/frontend/src/components/molecules/Reasoning.tsx index 47b04f15..6a9e396a 100644 --- a/frontend/src/components/molecules/Reasoning.tsx +++ b/frontend/src/components/molecules/Reasoning.tsx @@ -14,13 +14,18 @@ export const Reasoning = ({ title, description, link, hash }: ReasoningI) => { return ( - + {title} {description} diff --git a/frontend/src/components/molecules/Search.tsx b/frontend/src/components/molecules/Search.tsx index 91eec640..b8d99c3c 100644 --- a/frontend/src/components/molecules/Search.tsx +++ b/frontend/src/components/molecules/Search.tsx @@ -9,9 +9,14 @@ import { useEffect, useState } from "react"; interface Props { setSearchText: (value) => void; delay?: number; + dataTestId?: string; } -export const Search = ({ setSearchText, delay = 500 }: Props) => { +export const Search = ({ + setSearchText, + delay = 500, + dataTestId = "search-input", +}: Props) => { const [searchInput, setSearchInput] = useState(""); const debouncedSearchInput = useDebounce(searchInput, delay); @@ -21,7 +26,7 @@ export const Search = ({ setSearchText, delay = 500 }: Props) => { return ( setSearchInput(e.target.value)} placeholder="Search..." value={searchInput} diff --git a/frontend/src/components/molecules/UserCard/UserBasicInfo.tsx b/frontend/src/components/molecules/UserCard/UserBasicInfo.tsx index 6f84430d..febeef44 100644 --- a/frontend/src/components/molecules/UserCard/UserBasicInfo.tsx +++ b/frontend/src/components/molecules/UserCard/UserBasicInfo.tsx @@ -31,6 +31,7 @@ export const UserBasicInfo = ({ minHeight: 24, width: "100%", }} + dataTestId="user-info-username-text" variant="body1" > {name} @@ -44,7 +45,11 @@ export const UserBasicInfo = ({ > - + {truncateText(email, 20)} diff --git a/frontend/src/components/molecules/UserCard/UserRole.tsx b/frontend/src/components/molecules/UserCard/UserRole.tsx index 97dcbe46..7ab2dde9 100644 --- a/frontend/src/components/molecules/UserCard/UserRole.tsx +++ b/frontend/src/components/molecules/UserCard/UserRole.tsx @@ -34,6 +34,7 @@ export const UserRole = ({ showCloseButton={showCloseButton} onClick={onClick} list={formattedRoleList} + dataTestId="user-role" /> ); diff --git a/frontend/src/components/molecules/UserProfileButton.tsx b/frontend/src/components/molecules/UserProfileButton.tsx index f7d555e8..80514c43 100644 --- a/frontend/src/components/molecules/UserProfileButton.tsx +++ b/frontend/src/components/molecules/UserProfileButton.tsx @@ -65,6 +65,7 @@ export default function UserProfileButton({ /> } endIcon={} + dataTestId="user-profile-menu-button" > {user?.name || "User"} @@ -92,6 +93,7 @@ export default function UserProfileButton({ variant="outlined" onClick={editProfile} startIcon={} + data-testid="edit-profile-button" > {t("Navigation.editProfile")} @@ -100,6 +102,7 @@ export default function UserProfileButton({ variant="outlined" onClick={signOut} startIcon={} + data-testid="sign-out-button" > {t("Navigation.signOut")} diff --git a/frontend/src/components/organisms/Constitution/Constitution.tsx b/frontend/src/components/organisms/Constitution/Constitution.tsx index 546ad0c9..879d5538 100644 --- a/frontend/src/components/organisms/Constitution/Constitution.tsx +++ b/frontend/src/components/organisms/Constitution/Constitution.tsx @@ -108,7 +108,10 @@ export function Constitution({ constitution, metadata }: ConstitutionProps) { - + diff --git a/frontend/src/components/organisms/Constitution/MDXComponents.tsx b/frontend/src/components/organisms/Constitution/MDXComponents.tsx index 7e5cf3da..2ef9a7eb 100644 --- a/frontend/src/components/organisms/Constitution/MDXComponents.tsx +++ b/frontend/src/components/organisms/Constitution/MDXComponents.tsx @@ -157,15 +157,18 @@ export const NavDrawerDesktop = ({ isOpen, left = 0, top = { xxs: 75, md: 90 }, + dataTestId, }: { children: ReactNode; onClick: () => void; isOpen: boolean; left: number; top: { xxs: number; md: number }; + dataTestId?: string; }) => { return ( ( - + {buttonLabel} diff --git a/frontend/src/components/organisms/ControlledField/Upload.tsx b/frontend/src/components/organisms/ControlledField/Upload.tsx index efd202bf..6d3ef213 100644 --- a/frontend/src/components/organisms/ControlledField/Upload.tsx +++ b/frontend/src/components/organisms/ControlledField/Upload.tsx @@ -3,14 +3,8 @@ import { useCallback } from "react"; import { Controller, get } from "react-hook-form"; -import { Field } from "@molecules"; - -import { - ControlledCheckboxProps, - ControlledUploadProps, - RenderInputProps, -} from "./types"; -import { ButtonProps, UploadFileButton } from "@atoms"; +import { ControlledUploadProps, RenderInputProps } from "./types"; +import { UploadFileButton } from "@atoms"; export const Upload = ({ control, diff --git a/frontend/src/components/organisms/ControlledField/types.ts b/frontend/src/components/organisms/ControlledField/types.ts index a1af05a2..fe673bb6 100644 --- a/frontend/src/components/organisms/ControlledField/types.ts +++ b/frontend/src/components/organisms/ControlledField/types.ts @@ -26,6 +26,7 @@ interface ControlledGenericProps { errors: FieldErrors; name: Path; rules?: Omit; + dataTestId?: string; } export type ControlledCheckboxProps = Omit< diff --git a/frontend/src/components/organisms/Footer/AdminFooter.tsx b/frontend/src/components/organisms/Footer/AdminFooter.tsx index 97f8994c..60e27ea3 100644 --- a/frontend/src/components/organisms/Footer/AdminFooter.tsx +++ b/frontend/src/components/organisms/Footer/AdminFooter.tsx @@ -38,6 +38,7 @@ export const AdminFooter = () => { } variant="outlined" size="medium" + data-testid="admin-signout-button" > {t("signOut")} diff --git a/frontend/src/components/organisms/Footer/Footer.tsx b/frontend/src/components/organisms/Footer/Footer.tsx index 7ca293e7..ec1a4535 100644 --- a/frontend/src/components/organisms/Footer/Footer.tsx +++ b/frontend/src/components/organisms/Footer/Footer.tsx @@ -44,7 +44,11 @@ export const Footer = ({ > - + {t("copyright")} @@ -56,10 +60,18 @@ export const Footer = ({ alignItems="center" justifyContent="space-between" > - + {t("privacyPolicy")} - + {t("termsOfService")} @@ -73,13 +85,14 @@ export const Footer = ({ sx={{ cursor: "pointer", ml: 1 }} fontWeight={500} variant="caption" + data-testid="footer-sign-in-button" onClick={() => { openModal({ type: "signIn", }); }} > - {t("signIn")} + {t("signIn")} )} @@ -89,6 +102,7 @@ export const Footer = ({ href={EXTERNAL_LINKS.guides} startIcon={} variant="text" + data-testid="footer-guides-button" > {t("guides")} diff --git a/frontend/src/components/organisms/GovActionTable/GovActionTableRow.tsx b/frontend/src/components/organisms/GovActionTable/GovActionTableRow.tsx index 38ac53f7..1edfd0b5 100644 --- a/frontend/src/components/organisms/GovActionTable/GovActionTableRow.tsx +++ b/frontend/src/components/organisms/GovActionTable/GovActionTableRow.tsx @@ -5,7 +5,7 @@ import { Button, GovActionStatusPill, OutlinedLightButton, - Typography + Typography, } from "@atoms"; import { customPalette, ICONS, PATHS } from "@consts"; import { useModal } from "@context"; @@ -19,7 +19,7 @@ import { GovActionModalState, OpenAddReasoningModalState, OpenPreviewReasoningModal, - OpenReasoningLinkModalState + OpenReasoningLinkModalState, } from "../types"; interface Props { @@ -47,8 +47,8 @@ export const GovActionTableRow = ({ govActions }: Props) => { govActionModal.openModal({ type: "govActionModal", state: { - id - } + id, + }, }); }; const openUpdateReasoningCallback = () => { @@ -61,8 +61,8 @@ export const GovActionTableRow = ({ govActions }: Props) => { state: { govAction: govActions, actionTitle: t("updateRationale"), - onActionClick: openUpdateReasoningCallback - } + onActionClick: openUpdateReasoningCallback, + }, }); }; @@ -71,8 +71,8 @@ export const GovActionTableRow = ({ govActions }: Props) => { type: "reasoningLinkModal", state: { hash, - link - } + link, + }, }); }; @@ -88,8 +88,8 @@ export const GovActionTableRow = ({ govActions }: Props) => { state: { id, callback: (response: ReasoningResponseI) => - addReasoningCallback(response) - } + addReasoningCallback(response), + }, }); }; @@ -98,7 +98,7 @@ export const GovActionTableRow = ({ govActions }: Props) => { item mb={3} sx={{ - opacity: isDisabled ? 0.5 : 1 + opacity: isDisabled ? 0.5 : 1, }} > @@ -112,7 +112,7 @@ export const GovActionTableRow = ({ govActions }: Props) => { xxs: "column", md: "row", lg: "row", - xl: "row" + xl: "row", }} > { height={12} src={ICONS.informationCircle} style={{ - opacity: title ? 1 : 0.5 + opacity: title ? 1 : 0.5, }} /> } + data-testid="ga-table-title-modal" > - {title ? title : t("notAvailable")} + + {title ? title : t("notAvailable")} + @@ -186,7 +189,10 @@ export const GovActionTableRow = ({ govActions }: Props) => { > {t("govActionCategoryShort")} - + {getProposalTypeLabel(type)} @@ -234,7 +240,10 @@ export const GovActionTableRow = ({ govActions }: Props) => { > {t("gaStatus")} - + {status} @@ -276,6 +285,7 @@ export const GovActionTableRow = ({ govActions }: Props) => { : openUpdateReasoningModal() } variant="outlined" + data-testid="ga-table-rationale-button" > {canAddReasoning ? t("addRationale") : t("updateRationale")} @@ -286,4 +296,4 @@ export const GovActionTableRow = ({ govActions }: Props) => { ); -}; +}; \ No newline at end of file diff --git a/frontend/src/components/organisms/Hero/Hero.tsx b/frontend/src/components/organisms/Hero/Hero.tsx index da873da4..d051f74b 100644 --- a/frontend/src/components/organisms/Hero/Hero.tsx +++ b/frontend/src/components/organisms/Hero/Hero.tsx @@ -24,7 +24,11 @@ export const Hero = ({ children }: HeroProps) => { minHeight={{ xxs: "90vh", md: "auto" }} > - + {t("hero.headline")} { maxWidth: 630, my: { xxs: 2, md: 5 }, whiteSpace: "pre-line", - }} + }} + data-testid="hero-section-description-text" > {t("hero.description")} diff --git a/frontend/src/components/organisms/Hero/HeroActions.tsx b/frontend/src/components/organisms/Hero/HeroActions.tsx index 991ba4b8..37d0a1fd 100644 --- a/frontend/src/components/organisms/Hero/HeroActions.tsx +++ b/frontend/src/components/organisms/Hero/HeroActions.tsx @@ -24,6 +24,7 @@ export function HeroActions({ role }: HeroActionsProps) { type: "signIn", }); }} + data-testid="admin-hero-sign-in-button" > {t("hero.signIn")} @@ -34,6 +35,7 @@ export function HeroActions({ role }: HeroActionsProps) { variant="outlined" size="large" startIcon={} + data-testid="admin-hero-const-comitee-portal-button" > {t("hero.constitutionalCommitteePortal")} @@ -43,7 +45,11 @@ export function HeroActions({ role }: HeroActionsProps) { ) : ( - diff --git a/frontend/src/components/organisms/Modals/AddMember.tsx b/frontend/src/components/organisms/Modals/AddMember.tsx index 78a89a2e..1910dbea 100644 --- a/frontend/src/components/organisms/Modals/AddMember.tsx +++ b/frontend/src/components/organisms/Modals/AddMember.tsx @@ -63,6 +63,7 @@ export const AddMemberModal = () => { control={control} {...register("email", { required: "Email is required" })} type="email" + dataTestId="add-member-email" /> { control={control} errors={errors} multiple={false} + dataTestId="add-member-role" {...register("role", { required: "Role is required" })} /> {isAdminRole(role) && ( @@ -80,13 +82,14 @@ export const AddMemberModal = () => { items={permissionsList} control={control} errors={errors} + dataTestId="add-member-permission" {...register("permissions", { required: "Permission is required", })} /> )} - + diff --git a/frontend/src/components/organisms/Modals/CompareConstitutionModal.tsx b/frontend/src/components/organisms/Modals/CompareConstitutionModal.tsx index 077465e8..aa160be4 100644 --- a/frontend/src/components/organisms/Modals/CompareConstitutionModal.tsx +++ b/frontend/src/components/organisms/Modals/CompareConstitutionModal.tsx @@ -112,7 +112,11 @@ export const CompareConstitutionModal = () => { ) : ( )} - diff --git a/frontend/src/components/organisms/Modals/GovActionModal.tsx b/frontend/src/components/organisms/Modals/GovActionModal.tsx index 46d531ba..f6ae2723 100644 --- a/frontend/src/components/organisms/Modals/GovActionModal.tsx +++ b/frontend/src/components/organisms/Modals/GovActionModal.tsx @@ -69,7 +69,9 @@ export const GovActionModal = () => { src={IMAGES.pastelSignIn} /> - {govAction.title} + + {govAction.title} + { fontWeight={400} sx={{ pb: 0 }} color={customPalette.textGray} + data-testid="governance-action-modal-abstract-text" > {govAction?.abstract} @@ -91,7 +94,10 @@ export const GovActionModal = () => { {t("govActionModal.govActionCategory")} - + {getProposalTypeLabel(govAction.type)} @@ -100,7 +106,10 @@ export const GovActionModal = () => { {t("govActionModal.gaStatus")} - + {govAction.status} @@ -122,6 +131,7 @@ export const GovActionModal = () => { fontWeight={600} sx={{ flexWrap: "nowrap" }} variant="caption" + data-testid="governance-action-modal-submit-time" > {formatDisplayDate(govAction.submit_time)} @@ -143,13 +153,19 @@ export const GovActionModal = () => { fontWeight={600} sx={{ flexWrap: "nowrap" }} variant="caption" + data-testid="governance-action-modal-end-time" > {formatDisplayDate(govAction.end_time)} )} - diff --git a/frontend/src/components/organisms/Modals/PreviewReasoningModal.tsx b/frontend/src/components/organisms/Modals/PreviewReasoningModal.tsx index 52e9b7e6..9ab362e3 100644 --- a/frontend/src/components/organisms/Modals/PreviewReasoningModal.tsx +++ b/frontend/src/components/organisms/Modals/PreviewReasoningModal.tsx @@ -125,13 +125,16 @@ export const PreviewReasoningModal = () => { src={IMAGES.pastelAddMember} /> - {t("previewRationale.headline")} + + {t("previewRationale.headline")} + {t("previewRationale.description")} @@ -158,6 +161,7 @@ export const PreviewReasoningModal = () => { description={reasoning.comment} link={reasoning.url} hash={reasoning.blake2b} + data-testid="asdf" /> )} @@ -173,11 +177,14 @@ export const PreviewReasoningModal = () => { )} /> - + {t("previewRationale.governanceActionCategory")} - + {getProposalTypeLabel(govAction.type)} @@ -186,7 +193,11 @@ export const PreviewReasoningModal = () => { {t("previewRationale.voted")} - + @@ -200,7 +211,7 @@ export const PreviewReasoningModal = () => { tooltipParagraph={t( "previewRationale.tooltips.submissionDate.paragraphOne" )} - dataTestId="submit-date" + dataTestId="submit-date-row" /> )} {govAction.vote_submit_time && ( @@ -213,7 +224,7 @@ export const PreviewReasoningModal = () => { tooltipParagraph={t( "previewRationale.tooltips.submissionDate.vote.paragraphOne" )} - dataTestId="vote-submit-date" + dataTestId="vote-submit-date-row" /> )} {govAction.end_time && ( @@ -224,8 +235,8 @@ export const PreviewReasoningModal = () => { tooltipParagraph={t( "previewRationale.tooltips.expiryDate.paragraphTwo" )} - dataTestId="expiry-date" bgColor="rgba(247, 249, 251, 1)" + dataTestId="expiry-date-row" /> )} @@ -244,6 +255,7 @@ export const PreviewReasoningModal = () => { width: "100%", marginBottom: 1.5, }} + data-testid="rationale-modal-action-button" > {actionTitle} @@ -255,6 +267,7 @@ export const PreviewReasoningModal = () => { sx={{ width: "100%", }} + data-testid="rationale-modal-close-button" > {t("common.close")} diff --git a/frontend/src/components/organisms/Modals/SignInModal.tsx b/frontend/src/components/organisms/Modals/SignInModal.tsx index d220e7d7..19ab4414 100644 --- a/frontend/src/components/organisms/Modals/SignInModal.tsx +++ b/frontend/src/components/organisms/Modals/SignInModal.tsx @@ -34,10 +34,18 @@ export const SignInModal = () => { return ( - {t("signIn.headline")} + + + {t("signIn.headline")} + +
- + {t("signIn.description")} @@ -47,6 +55,7 @@ export const SignInModal = () => { control={control} type="email" {...register("email", { required: "Email is required" })} + data-testid="sign-in-modal-input-field" /> diff --git a/frontend/src/components/organisms/Modals/SignOutModal.tsx b/frontend/src/components/organisms/Modals/SignOutModal.tsx index 3e02fc86..0cf1773f 100644 --- a/frontend/src/components/organisms/Modals/SignOutModal.tsx +++ b/frontend/src/components/organisms/Modals/SignOutModal.tsx @@ -25,13 +25,21 @@ export const SignOutModal = () => { return ( - {t("signOut.headline")} + + + {t("signOut.headline")} + + - + {t("signOut.description")} - +
diff --git a/frontend/src/components/organisms/Modals/SignUpModal.tsx b/frontend/src/components/organisms/Modals/SignUpModal.tsx index 2d3bc3f6..df665042 100644 --- a/frontend/src/components/organisms/Modals/SignUpModal.tsx +++ b/frontend/src/components/organisms/Modals/SignUpModal.tsx @@ -143,6 +143,7 @@ export const SignUpModal = () => { errors={errors} control={control} accept="image/png, image/jpg, image/jpeg" + dataTestId="upload-profile-photo-button" {...register("file", { validate: { fileType: (file) => @@ -169,6 +170,7 @@ export const SignUpModal = () => { ) : ( @@ -78,7 +87,12 @@ export const AdminTopNav = () => { permissions={userSession?.permissions} requiredPermission="add_constitution_version" > - @@ -94,7 +108,10 @@ export const AdminTopNav = () => { {!!userSession && ( <> - + {getNavItems()} diff --git a/frontend/src/components/organisms/TopNavigation/TopNav.tsx b/frontend/src/components/organisms/TopNavigation/TopNav.tsx index bfb16e48..e63dfb06 100644 --- a/frontend/src/components/organisms/TopNavigation/TopNav.tsx +++ b/frontend/src/components/organisms/TopNavigation/TopNav.tsx @@ -33,7 +33,7 @@ export const TopNav = () => { items.map((navItem) => ( @@ -51,6 +51,7 @@ export const TopNav = () => { variant="outlined" href={PATHS.admin.dashboard} component={NextLink} + data-testid="top-nav-admin-dashboard-button" > {t("adminDashboard")} diff --git a/frontend/src/components/organisms/VotesTable/VotesTableRow.tsx b/frontend/src/components/organisms/VotesTable/VotesTableRow.tsx index 3600e49d..794dbeb7 100644 --- a/frontend/src/components/organisms/VotesTable/VotesTableRow.tsx +++ b/frontend/src/components/organisms/VotesTable/VotesTableRow.tsx @@ -22,7 +22,7 @@ export const VotesTableRow = ({ votes, disabled, actionTitle, - onActionClick + onActionClick, }: Props) => { const t = useTranslations("LatestUpdates"); const { openModal } = useModal(); @@ -34,14 +34,14 @@ export const VotesTableRow = ({ reasoning_comment, gov_action_proposal_id, gov_action_proposal_title, - gov_action_proposal_type + gov_action_proposal_type, } = votes; const openGAModal = () => { openModal({ type: "govActionModal", state: { - id: gov_action_proposal_id - } + id: gov_action_proposal_id, + }, }); }; @@ -50,10 +50,10 @@ export const VotesTableRow = ({ item mb={3} sx={{ - opacity: disabled && 0.5 + opacity: disabled && 0.5, }} > - + {t("govActionCategoryShort")} - + {getProposalTypeLabel(gov_action_proposal_type)} @@ -203,7 +207,7 @@ export const VotesTableRow = ({ > {t("rationale")} - + {reasoning_comment ? truncateText(reasoning_comment, 100) : t("notAvailable")} @@ -216,6 +220,7 @@ export const VotesTableRow = ({ sx={{ whiteSpace: "nowrap" }} onClick={() => onActionClick(votes)} variant="outlined" + data-testid="ga-show-more-button" > {actionTitle} @@ -226,4 +231,4 @@ export const VotesTableRow = ({ ); -}; +}; \ No newline at end of file diff --git a/frontend/src/context/usersnap.tsx b/frontend/src/context/usersnap.tsx index 7d81596d..979b4fde 100644 --- a/frontend/src/context/usersnap.tsx +++ b/frontend/src/context/usersnap.tsx @@ -1,6 +1,7 @@ "use client"; import React, { useEffect, useState, useContext } from "react"; import { InitOptions, loadSpace, SpaceApi } from "@usersnap/browser"; +import { usePathname, useSearchParams } from "next/navigation"; export const UsersnapContext = React.createContext(null); @@ -11,26 +12,46 @@ export const UsersnapProvider = ({ children, }: UsersnapProviderProps) => { const [usersnapApi, setUsersnapApi] = useState(null); + const pathname = usePathname(); + const searchParams = useSearchParams(); useEffect(() => { + let api: SpaceApi | null = null; + + const hideHiddenProjects = () => { + if (api) { + const hiddenProjects = + process.env.NEXT_PUBLIC_HIDDEN_USERSNAP_PROJECT_IDS?.split("||") || + []; + hiddenProjects.forEach((p) => { + api.hide(p); + }); + } + }; + if (process.env.NEXT_PUBLIC_USERSNAP_SPACE_API_KEY) { - const hiddenProjects = process.env.NEXT_PUBLIC_HIDDEN_USERSNAP_PROJECT_IDS?.split("||") || [] loadSpace(process.env.NEXT_PUBLIC_USERSNAP_SPACE_API_KEY).then( - (api: SpaceApi) => { + (loadedApi: SpaceApi) => { + api = loadedApi; api.init(initParams); setUsersnapApi(api); - const hideHiddenProjects = () => { - hiddenProjects.forEach(p => { - api.hide(p); - }); - }; + + api.on("submit", hideHiddenProjects); + api.on("open", hideHiddenProjects); + api.on("close", hideHiddenProjects); hideHiddenProjects(); - api.on("close", hideHiddenProjects) - api.on("submit", hideHiddenProjects) } ); } - }, [initParams]); + + return () => { + if (api) { + api.off("submit", hideHiddenProjects); + api.off("open", hideHiddenProjects); + api.off("close", hideHiddenProjects); + } + }; + }, [initParams, pathname, searchParams]); return ( From 0cac7f25309d6dd8e058ed798ed037ac4fbc9062 Mon Sep 17 00:00:00 2001 From: Milos <161627443+BEdev24@users.noreply.github.com> Date: Wed, 25 Sep 2024 11:19:46 +0200 Subject: [PATCH 16/20] Update merge.yaml (#386) --- .github/workflows/merge.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/merge.yaml b/.github/workflows/merge.yaml index 9ba8b3b7..0f939257 100644 --- a/.github/workflows/merge.yaml +++ b/.github/workflows/merge.yaml @@ -161,7 +161,7 @@ jobs: docker push ${{ steps.image_lowercase.outputs.lowercase }}:${{ env.TAG }} - name: Deploy with Qovery - if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master' + if: github.ref == 'refs/heads/develop' env: QOVERY_CLI_ACCESS_TOKEN: ${{secrets.QOVERY_CLI_ACCESS_TOKEN }} run: | From 6cc5da031da75fdfe5ccf61761e99710bca6a54c Mon Sep 17 00:00:00 2001 From: Ryan Date: Fri, 18 Oct 2024 13:55:29 +0100 Subject: [PATCH 17/20] chore: update issue template to add issues to projects (#405) --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- .github/ISSUE_TEMPLATE/feature_idea.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index f2dbf1ff..5eb15fdc 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -2,7 +2,7 @@ name: 🐛 Bug report description: You found a bug! title: '🐛 ' labels: ["🐛 Bug"] -projects: [ ] +projects: ["IntersectMBO/24", "IntersectMBO/34"] body: - type: markdown attributes: diff --git a/.github/ISSUE_TEMPLATE/feature_idea.yml b/.github/ISSUE_TEMPLATE/feature_idea.yml index 9fe8d7ae..1d84b8be 100644 --- a/.github/ISSUE_TEMPLATE/feature_idea.yml +++ b/.github/ISSUE_TEMPLATE/feature_idea.yml @@ -2,7 +2,7 @@ name: 💡 Feature idea description: Idea or request for some feature on the CC Portal roadmap title: "💡 " labels: ["💡 Feature idea"] -projects: [ ] +projects: ["IntersectMBO/24", "IntersectMBO/34"] body: - type: markdown attributes: From df822bc42e58b6fdd4730b18a07b4ba8093cb65a Mon Sep 17 00:00:00 2001 From: Milos <161627443+BEdev24@users.noreply.github.com> Date: Fri, 1 Nov 2024 09:29:33 +0100 Subject: [PATCH 18/20] feat/improvements (#439) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: add correct env vars (#353) * fix dockle scan on ci * fix registry login * debug imgs * scan tar imgs * test * add tar cleanup * test * pr workflow fix * declutter dockle * add comment * add microservice in pr comment * test w/ individual service failing * fix dockerfile * fix: vote table row responsiveness * Refactor/change logic for file upload to S3 (#328) * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * feat: dht-queue (#336) Added persistent dht-queue which will be responsible for publishing cid to dht * refactor: image upload to S3 (#337) * fitx/rationale-governance-format Rationale - Removed body.references since it will be empty until CC-portal enables that feature GAP title and abstract is now parsing in compatibility with CIP-0108 (body.title, body.abstract) * chore: change guides btn link * fix: rm-gap-title-abstract-len-constraint Remove len constraints for gap.title and gap.abstract (was 80 and 2500 char length) fixed error if db data is undefined when fetching from db sync * refactor: add redis username Added username env variable within backend/worker-service/ipfs-service * Fix add redis creds (#343) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args --------- Co-authored-by: nike-getto Co-authored-by: BEDev24 * Fix add redis creds (#344) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args * refactor: cache docker-compose --------- Co-authored-by: nike-getto Co-authored-by: BEDev24 * fix: typo * fix: typo * refactor: cache service * refactor/redis-auth (#345) * fix: plural grammar corrections * refactor: pruning worker processors (#346) * fix: latest updates content overlaping * refactor: ipfs service path and minor refactoring * fix: usersnap remove other buttons (#323) * fix: Overlapping on tables * fix: don't show top banner on mainnet * fix: show more btn not loading more content, update env example * refactor: renamed migration name for gap len constraint removal * refactor: ipfs volume * add correct vars (#352) Co-authored-by: nike-getto --------- Co-authored-by: Baja-KS Co-authored-by: Lazar Lukić <57199246+Baja-KS@users.noreply.github.com> Co-authored-by: Vojimirovich Co-authored-by: Vojimirovich <85948457+Vojimirovich@users.noreply.github.com> Co-authored-by: nike-getto Co-authored-by: BEDev24 Co-authored-by: kubet * fix:redis-tls (#361) * fix dockle scan on ci * fix registry login * debug imgs * scan tar imgs * test * add tar cleanup * test * pr workflow fix * declutter dockle * add comment * add microservice in pr comment * test w/ individual service failing * fix dockerfile * fix: vote table row responsiveness * Refactor/change logic for file upload to S3 (#328) * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * feat: dht-queue (#336) Added persistent dht-queue which will be responsible for publishing cid to dht * refactor: image upload to S3 (#337) * fitx/rationale-governance-format Rationale - Removed body.references since it will be empty until CC-portal enables that feature GAP title and abstract is now parsing in compatibility with CIP-0108 (body.title, body.abstract) * chore: change guides btn link * fix: rm-gap-title-abstract-len-constraint Remove len constraints for gap.title and gap.abstract (was 80 and 2500 char length) fixed error if db data is undefined when fetching from db sync * refactor: add redis username Added username env variable within backend/worker-service/ipfs-service * Fix add redis creds (#343) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args --------- Co-authored-by: nike-getto Co-authored-by: BEDev24 * Fix add redis creds (#344) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args * refactor: cache docker-compose --------- Co-authored-by: nike-getto Co-authored-by: BEDev24 * fix: typo * fix: typo * refactor: cache service * refactor/redis-auth (#345) * fix: plural grammar corrections * refactor: pruning worker processors (#346) * fix: latest updates content overlaping * refactor: ipfs service path and minor refactoring * fix: usersnap remove other buttons (#323) * fix: Overlapping on tables * fix: don't show top banner on mainnet * fix: show more btn not loading more content, update env example * refactor: renamed migration name for gap len constraint removal * refactor: ipfs volume * add correct vars (#352) Co-authored-by: nike-getto * fix: ipfs-redis-service (#360) * fix/ipfs-redis-service: tls connection to redis * fix/ipfs-redis-service: tls connection to redis --------- Co-authored-by: Baja-KS Co-authored-by: Lazar Lukić <57199246+Baja-KS@users.noreply.github.com> Co-authored-by: Vojimirovich Co-authored-by: Vojimirovich <85948457+Vojimirovich@users.noreply.github.com> Co-authored-by: nike-getto Co-authored-by: BEDev24 Co-authored-by: kubet * fix:add-update-rationale-button (#364) * fix dockle scan on ci * fix registry login * debug imgs * scan tar imgs * test * add tar cleanup * test * pr workflow fix * declutter dockle * add comment * add microservice in pr comment * test w/ individual service failing * fix dockerfile * fix: vote table row responsiveness * Refactor/change logic for file upload to S3 (#328) * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * feat: dht-queue (#336) Added persistent dht-queue which will be responsible for publishing cid to dht * refactor: image upload to S3 (#337) * fitx/rationale-governance-format Rationale - Removed body.references since it will be empty until CC-portal enables that feature GAP title and abstract is now parsing in compatibility with CIP-0108 (body.title, body.abstract) * chore: change guides btn link * fix: rm-gap-title-abstract-len-constraint Remove len constraints for gap.title and gap.abstract (was 80 and 2500 char length) fixed error if db data is undefined when fetching from db sync * refactor: add redis username Added username env variable within backend/worker-service/ipfs-service * Fix add redis creds (#343) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args --------- Co-authored-by: nike-getto Co-authored-by: BEDev24 * Fix add redis creds (#344) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args * refactor: cache docker-compose --------- Co-authored-by: nike-getto Co-authored-by: BEDev24 * fix: typo * fix: typo * refactor: cache service * refactor/redis-auth (#345) * fix: plural grammar corrections * refactor: pruning worker processors (#346) * fix: latest updates content overlaping * refactor: ipfs service path and minor refactoring * fix: usersnap remove other buttons (#323) * fix: Overlapping on tables * fix: don't show top banner on mainnet * fix: show more btn not loading more content, update env example * refactor: renamed migration name for gap len constraint removal * refactor: ipfs volume * add correct vars (#352) Co-authored-by: nike-getto * fix: ipfs-redis-service (#360) * fix/ipfs-redis-service: tls connection to redis * fix/ipfs-redis-service: tls connection to redis * fix/gov-search-rationale-votes: user votes and rationale are being checked when data is fetched (#359) Co-authored-by: BEDev24 --------- Co-authored-by: Baja-KS Co-authored-by: Lazar Lukić <57199246+Baja-KS@users.noreply.github.com> Co-authored-by: Vojimirovich Co-authored-by: Vojimirovich <85948457+Vojimirovich@users.noreply.github.com> Co-authored-by: nike-getto Co-authored-by: BEDev24 Co-authored-by: kubet * refactor/staging-deploy (#380) * Update merge.yaml * refactor: pr pipeline * merge develop-staging (#381) * feat: added new selectors * feat: Upload button selector ids * feat: Input and Select selector ids * feat: User List table selector ids * fix: MultipleSelect rename selector ids * fix: Rename Upload component selctor ids * feat: Modal action buttons selector ids-Add member and Upload constitution * feat: AdminTopNav Search component selector id * feat: Admin signout & modal selector ids * feat: AdminTopNav buttons selector ids * feat: Navigation links selector ids * Feat: Footer selector ids * feat: Constitution page selector ids * feat: Latest updates and votes selector ids * feat: GA table selector ids * fix dockle scan on ci * fix registry login * debug imgs * scan tar imgs * test * add tar cleanup * test * pr workflow fix * declutter dockle * add comment * add microservice in pr comment * test w/ individual service failing * fix dockerfile * fix: vote table row responsiveness * Refactor/change logic for file upload to S3 (#328) * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * feat: dht-queue (#336) Added persistent dht-queue which will be responsible for publishing cid to dht * refactor: image upload to S3 (#337) * fitx/rationale-governance-format Rationale - Removed body.references since it will be empty until CC-portal enables that feature GAP title and abstract is now parsing in compatibility with CIP-0108 (body.title, body.abstract) * chore: change guides btn link * fix: rm-gap-title-abstract-len-constraint Remove len constraints for gap.title and gap.abstract (was 80 and 2500 char length) fixed error if db data is undefined when fetching from db sync * refactor: add redis username Added username env variable within backend/worker-service/ipfs-service * Fix add redis creds (#343) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args --------- Co-authored-by: nike-getto Co-authored-by: BEDev24 * Fix add redis creds (#344) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args * refactor: cache docker-compose --------- Co-authored-by: nike-getto Co-authored-by: BEDev24 * fix: typo * fix: typo * refactor: cache service * refactor/redis-auth (#345) * fix: plural grammar corrections * refactor: pruning worker processors (#346) * fix: latest updates content overlaping * refactor: ipfs service path and minor refactoring * fix: usersnap remove other buttons (#323) * fix: Overlapping on tables * fix: don't show top banner on mainnet * fix: show more btn not loading more content, update env example * refactor: renamed migration name for gap len constraint removal * refactor: ipfs volume * add correct vars (#352) Co-authored-by: nike-getto * fix: ipfs-redis-service (#360) * fix/ipfs-redis-service: tls connection to redis * fix/ipfs-redis-service: tls connection to redis * fix/gov-search-rationale-votes: user votes and rationale are being checked when data is fetched (#359) Co-authored-by: BEDev24 * fix: usersnap showing all on path change * fix: Remove comments for selector ids * fix: Usersnap query params issue --------- Co-authored-by: nikolajovancevic Co-authored-by: Kristina Co-authored-by: Baja-KS Co-authored-by: Lazar Lukić <57199246+Baja-KS@users.noreply.github.com> Co-authored-by: Vojimirovich Co-authored-by: Vojimirovich <85948457+Vojimirovich@users.noreply.github.com> Co-authored-by: nike-getto Co-authored-by: BEDev24 Co-authored-by: kubet Co-authored-by: Kristina <42462482+Kristina2103@users.noreply.github.com> * refactor:staging-branch (#382) * Update merge.yaml (#387) * Develop (#421) * feat: added new selectors * feat: Upload button selector ids * feat: Input and Select selector ids * feat: User List table selector ids * fix: MultipleSelect rename selector ids * fix: Rename Upload component selctor ids * feat: Modal action buttons selector ids-Add member and Upload constitution * feat: AdminTopNav Search component selector id * feat: Admin signout & modal selector ids * feat: AdminTopNav buttons selector ids * feat: Navigation links selector ids * Feat: Footer selector ids * feat: Constitution page selector ids * feat: Latest updates and votes selector ids * feat: GA table selector ids * fix dockle scan on ci * fix registry login * debug imgs * scan tar imgs * test * add tar cleanup * test * pr workflow fix * declutter dockle * add comment * add microservice in pr comment * test w/ individual service failing * fix dockerfile * fix: vote table row responsiveness * Refactor/change logic for file upload to S3 (#328) * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * feat: dht-queue (#336) Added persistent dht-queue which will be responsible for publishing cid to dht * refactor: image upload to S3 (#337) * fitx/rationale-governance-format Rationale - Removed body.references since it will be empty until CC-portal enables that feature GAP title and abstract is now parsing in compatibility with CIP-0108 (body.title, body.abstract) * chore: change guides btn link * fix: rm-gap-title-abstract-len-constraint Remove len constraints for gap.title and gap.abstract (was 80 and 2500 char length) fixed error if db data is undefined when fetching from db sync * refactor: add redis username Added username env variable within backend/worker-service/ipfs-service * Fix add redis creds (#343) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args --------- Co-authored-by: nike-getto Co-authored-by: BEDev24 * Fix add redis creds (#344) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args * refactor: cache docker-compose --------- Co-authored-by: nike-getto Co-authored-by: BEDev24 * fix: typo * fix: typo * refactor: cache service * refactor/redis-auth (#345) * fix: plural grammar corrections * refactor: pruning worker processors (#346) * fix: latest updates content overlaping * refactor: ipfs service path and minor refactoring * fix: usersnap remove other buttons (#323) * fix: Overlapping on tables * fix: don't show top banner on mainnet * fix: show more btn not loading more content, update env example * refactor: renamed migration name for gap len constraint removal * refactor: ipfs volume * add correct vars (#352) Co-authored-by: nike-getto * fix: ipfs-redis-service (#360) * fix/ipfs-redis-service: tls connection to redis * fix/ipfs-redis-service: tls connection to redis * fix/gov-search-rationale-votes: user votes and rationale are being checked when data is fetched (#359) Co-authored-by: BEDev24 * fix: usersnap showing all on path change * fix: Remove comments for selector ids * fix: Usersnap query params issue * fix/logging-magic-link: disabled mailing on local (#363) * fix: search not unchecking filters after clicking on clear * fix/add-indexes-to-searchable-columns: added indexes to searcable columns in the database (#394) * feat: resend register invite (#397) * feature/resend-register-invite: added endpoint for resending the register invite * feature/resend-register-invite: minor changes * feature/resend-register-invite: minor changes * feat: resend invitation, inactive/active, hard delete * feature/hard-delete-user: added hard delete user ability (#398) * Feat: hard delete user (#400) * feature/hard-delete-user: added hard delete user ability * feature/hard-delete-user: updated swagger * feat: hard delete user (#401) * feature/hard-delete-user: added hard delete user ability * feature/hard-delete-user: updated swagger * feature/hard-delete-user: try catch for removing profile photo * feat: implement delete user * chore: refactor delete button component * test/remove-users: added unit tests (#406) * fix/sorting-users: sorted users by name in ascending order (#408) * feat: add switch user modal and remove X button from role bar on admin dashboard * fix: allow super admin to change status of cc memeber * fix/sync-votes: sync vote rationale url (#412) * fix: sync votes (#418) * fix/sync-votes: sync vote rationale url * fix/sync-votes: fixed unit tests * feat: constitution page design improvements * refactor/open-port-3002 * added rationale link on latest updates table * refactor/worker-bull-borad * feat: implemented new contents design * fix: contents scroll --------- Co-authored-by: nikolajovancevic Co-authored-by: Kristina Co-authored-by: Baja-KS Co-authored-by: Lazar Lukić <57199246+Baja-KS@users.noreply.github.com> Co-authored-by: Vojimirovich Co-authored-by: Vojimirovich <85948457+Vojimirovich@users.noreply.github.com> Co-authored-by: nike-getto Co-authored-by: BEDev24 Co-authored-by: kubet Co-authored-by: Kristina <42462482+Kristina2103@users.noreply.github.com> Co-authored-by: Vojimirovich * fix:navigation-side-bar-issues (#434) * feat: added new selectors * feat: Upload button selector ids * feat: Input and Select selector ids * feat: User List table selector ids * fix: MultipleSelect rename selector ids * fix: Rename Upload component selctor ids * feat: Modal action buttons selector ids-Add member and Upload constitution * feat: AdminTopNav Search component selector id * feat: Admin signout & modal selector ids * feat: AdminTopNav buttons selector ids * feat: Navigation links selector ids * Feat: Footer selector ids * feat: Constitution page selector ids * feat: Latest updates and votes selector ids * feat: GA table selector ids * fix dockle scan on ci * fix registry login * debug imgs * scan tar imgs * test * add tar cleanup * test * pr workflow fix * declutter dockle * add comment * add microservice in pr comment * test w/ individual service failing * fix dockerfile * fix: vote table row responsiveness * Refactor/change logic for file upload to S3 (#328) * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * refactor: changed getFileUrl function in order to display images on website for longer than 7 days * feat: dht-queue (#336) Added persistent dht-queue which will be responsible for publishing cid to dht * refactor: image upload to S3 (#337) * fitx/rationale-governance-format Rationale - Removed body.references since it will be empty until CC-portal enables that feature GAP title and abstract is now parsing in compatibility with CIP-0108 (body.title, body.abstract) * chore: change guides btn link * fix: rm-gap-title-abstract-len-constraint Remove len constraints for gap.title and gap.abstract (was 80 and 2500 char length) fixed error if db data is undefined when fetching from db sync * refactor: add redis username Added username env variable within backend/worker-service/ipfs-service * Fix add redis creds (#343) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args --------- Co-authored-by: nike-getto Co-authored-by: BEDev24 * Fix add redis creds (#344) * feat: add redis user * fix: add config to worker-service * fix-add-redis-creds: fixed order within example.env * fix: add docker compose args * refactor: cache docker-compose --------- Co-authored-by: nike-getto Co-authored-by: BEDev24 * fix: typo * fix: typo * refactor: cache service * refactor/redis-auth (#345) * fix: plural grammar corrections * refactor: pruning worker processors (#346) * fix: latest updates content overlaping * refactor: ipfs service path and minor refactoring * fix: usersnap remove other buttons (#323) * fix: Overlapping on tables * fix: don't show top banner on mainnet * fix: show more btn not loading more content, update env example * refactor: renamed migration name for gap len constraint removal * refactor: ipfs volume * add correct vars (#352) Co-authored-by: nike-getto * fix: ipfs-redis-service (#360) * fix/ipfs-redis-service: tls connection to redis * fix/ipfs-redis-service: tls connection to redis * fix/gov-search-rationale-votes: user votes and rationale are being checked when data is fetched (#359) Co-authored-by: BEDev24 * fix: usersnap showing all on path change * fix: Remove comments for selector ids * fix: Usersnap query params issue * fix/logging-magic-link: disabled mailing on local (#363) * fix: search not unchecking filters after clicking on clear * fix/add-indexes-to-searchable-columns: added indexes to searcable columns in the database (#394) * feat: resend register invite (#397) * feature/resend-register-invite: added endpoint for resending the register invite * feature/resend-register-invite: minor changes * feature/resend-register-invite: minor changes * feat: resend invitation, inactive/active, hard delete * feature/hard-delete-user: added hard delete user ability (#398) * Feat: hard delete user (#400) * feature/hard-delete-user: added hard delete user ability * feature/hard-delete-user: updated swagger * feat: hard delete user (#401) * feature/hard-delete-user: added hard delete user ability * feature/hard-delete-user: updated swagger * feature/hard-delete-user: try catch for removing profile photo * feat: implement delete user * chore: refactor delete button component * test/remove-users: added unit tests (#406) * fix/sorting-users: sorted users by name in ascending order (#408) * feat: add switch user modal and remove X button from role bar on admin dashboard * fix: allow super admin to change status of cc memeber * fix/sync-votes: sync vote rationale url (#412) * fix: sync votes (#418) * fix/sync-votes: sync vote rationale url * fix/sync-votes: fixed unit tests * feat: constitution page design improvements * refactor/open-port-3002 * added rationale link on latest updates table * refactor/worker-bull-borad * feat: implemented new contents design * fix: contents scroll * fix: navigation side bar visual known issues * fix: tooltip not showing on accordion summary * fix: tooltip not showing on accordion summary --------- Co-authored-by: nikolajovancevic Co-authored-by: Kristina Co-authored-by: Baja-KS Co-authored-by: Lazar Lukić <57199246+Baja-KS@users.noreply.github.com> Co-authored-by: Vojimirovich Co-authored-by: Vojimirovich <85948457+Vojimirovich@users.noreply.github.com> Co-authored-by: nike-getto Co-authored-by: BEDev24 Co-authored-by: kubet Co-authored-by: Kristina <42462482+Kristina2103@users.noreply.github.com> Co-authored-by: Vojimirovich * Update PreviewReasoningModal.tsx --------- Co-authored-by: Baja-KS Co-authored-by: Lazar Lukić <57199246+Baja-KS@users.noreply.github.com> Co-authored-by: Vojimirovich Co-authored-by: Vojimirovich <85948457+Vojimirovich@users.noreply.github.com> Co-authored-by: nike-getto Co-authored-by: BEDev24 Co-authored-by: kubet Co-authored-by: nikolajovancevic Co-authored-by: Kristina Co-authored-by: Kristina <42462482+Kristina2103@users.noreply.github.com> Co-authored-by: Vojimirovich --- .github/workflows/pr.yaml | 2 +- ...27027-add-indexes-to-searchable-columns.ts | 59 ++++++ .../1728062638428-users-relations.ts | 35 ++++ .../1729504273717-vote-metadata-url.ts | 17 ++ .../CC Portal develop.postman_collection.json | 72 ++++++- backend/src/auth/api/auth.controller.ts | 27 +++ .../api/request/resend-register.request.ts | 12 ++ backend/src/auth/facade/auth.facade.spec.ts | 98 +++++++++- backend/src/auth/facade/auth.facade.ts | 17 +- .../src/auth/strategy/magiclogin.strategy.ts | 8 +- .../auth/strategy/magicregister.strategy.ts | 8 +- .../facade/constitution.facade.spec.ts | 6 + .../governance/api/response/vote.response.ts | 8 + backend/src/governance/dto/vote.dto.ts | 1 + .../entities/gov-action-proposal.entity.ts | 6 +- .../governance/entities/rationale.entity.ts | 7 + .../src/governance/entities/vote.entity.ts | 26 ++- .../facade/governance.facade.spec.ts | 25 ++- .../governance/mapper/governance-mapper.ts | 2 + .../services/governance.service.spec.ts | 44 ++++- backend/src/s3/service/s3.service.spec.ts | 10 +- .../users/api/request/remove-user.request.ts | 12 ++ backend/src/users/api/users.controller.ts | 35 ++++ .../src/users/entities/hotaddress.entity.ts | 4 +- backend/src/users/entities/role.entity.ts | 2 + backend/src/users/entities/user.entity.ts | 15 ++ backend/src/users/facade/users.facade.spec.ts | 69 ++++++- backend/src/users/facade/users.facade.ts | 42 ++-- .../src/users/services/users.service.spec.ts | 32 +++ backend/src/users/services/users.service.ts | 20 ++ .../util/pagination/user-pagination.config.ts | 2 +- docker-compose.yaml | 2 + frontend/messages/de.json | 45 ++++- frontend/messages/en.json | 45 ++++- frontend/package-lock.json | 38 ++-- frontend/package.json | 8 +- frontend/public/icons/MenuIcon.svg | 7 +- frontend/public/images/DocSearch.png | Bin 0 -> 520 bytes frontend/public/images/HeroImage.png | Bin 205801 -> 119634 bytes frontend/public/images/Menu.png | Bin 0 -> 174 bytes .../[locale]/interim-constitution/layout.tsx | 10 + frontend/src/components/atoms/Chip/Chip.tsx | 5 +- frontend/src/components/atoms/Link.tsx | 17 +- .../components/atoms/modal/ModalActions.tsx | 9 +- .../molecules/GovernanceActionsFilters.tsx | 12 +- .../organisms/Constitution/Constitution.tsx | 68 ++++--- .../Constitution/ConstitutionSidebar.tsx | 82 +++----- .../organisms/Constitution/MDXComponents.tsx | 98 +++++----- .../organisms/Constitution/TOCAccordion.tsx | 135 +++++++++++++ .../organisms/Constitution/TOCLink.tsx | 43 ++-- .../organisms/Constitution/TOCNested.tsx | 57 ++++++ .../organisms/Footer/AdminFooter.tsx | 14 +- .../components/organisms/Footer/Footer.tsx | 21 +- .../src/components/organisms/Hero/Hero.tsx | 12 +- .../components/organisms/LatestUpdates.tsx | 30 +-- .../organisms/MembersCard/MembersCard.tsx | 9 +- .../organisms/Modals/DeleteUser.tsx | 74 +++++++ .../Modals/PreviewReasoningModal.tsx | 124 ++++++------ .../organisms/Modals/SiwtchUsersStatus.tsx | 74 +++++++ .../organisms/TopNavigation/AdminTopNav.tsx | 31 ++- .../organisms/TopNavigation/TopNav.tsx | 82 +++++--- .../organisms/TopNavigation/TopNavWrapper.tsx | 14 +- .../UsersList/UserListStatusDeleteButton.tsx | 36 ++++ .../UsersList/UserListStatusSwitchButton.tsx | 117 +++++++++++ .../organisms/UsersList/UsersList.tsx | 20 +- .../organisms/UsersList/UsersListItem.tsx | 157 +++++++++++---- .../organisms/VotesTable/VotesTableRow.tsx | 8 +- frontend/src/components/organisms/types.ts | 19 +- frontend/src/constants/colors.ts | 24 ++- frontend/src/constants/images.ts | 2 + frontend/src/constants/pageTitleTabs.ts | 16 +- frontend/src/context/modal.tsx | 58 +++--- frontend/src/lib/api.ts | 185 +++++++++++------- frontend/src/lib/requests/getConstitution.ts | 21 +- frontend/src/lib/requests/types.ts | 12 +- frontend/src/theme.ts | 89 +++++---- worker-service/src/common/common-service.ts | 8 + .../src/governance/dto/vote.request.ts | 3 +- .../src/governance/entities/vote.entity.ts | 7 + .../facade/governance.facade.spec.ts | 3 + .../src/governance/mapper/vote.mapper.ts | 5 +- .../gov-action-proposal.service.spec.ts | 14 +- .../services/gov-action-proposal.service.ts | 6 +- .../governance/services/vote.service.spec.ts | 35 ++-- .../src/governance/services/vote.service.ts | 13 +- .../src/governance/sql/get-votes.sql | 9 +- 86 files changed, 2085 insertions(+), 671 deletions(-) create mode 100644 backend/migrations/1727279527027-add-indexes-to-searchable-columns.ts create mode 100644 backend/migrations/1728062638428-users-relations.ts create mode 100644 backend/migrations/1729504273717-vote-metadata-url.ts create mode 100644 backend/src/auth/api/request/resend-register.request.ts create mode 100644 backend/src/users/api/request/remove-user.request.ts create mode 100644 frontend/public/images/DocSearch.png create mode 100644 frontend/public/images/Menu.png create mode 100644 frontend/src/app/[locale]/interim-constitution/layout.tsx create mode 100644 frontend/src/components/organisms/Constitution/TOCAccordion.tsx create mode 100644 frontend/src/components/organisms/Constitution/TOCNested.tsx create mode 100644 frontend/src/components/organisms/Modals/DeleteUser.tsx create mode 100644 frontend/src/components/organisms/Modals/SiwtchUsersStatus.tsx create mode 100644 frontend/src/components/organisms/UsersList/UserListStatusDeleteButton.tsx create mode 100644 frontend/src/components/organisms/UsersList/UserListStatusSwitchButton.tsx diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index a095c0bb..470f9416 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -123,7 +123,7 @@ jobs: NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY=${{ secrets.PROD_NEXT_PUBLIC_USERSNAP_PROJECT_API_KEY }} NEXT_PUBLIC_HIDDEN_USERSNAP_PROJECT_IDS=${{ secrets.PROD_NEXT_PUBLIC_HIDDEN_USERSNAP_PROJECT_IDS }} NEXT_PUBLIC_IS_MAINNET=${{ secrets.PROD_NEXT_PUBLIC_IS_MAINNET }} - + - name: Scan Docker image with Dockle id: dockle run: | diff --git a/backend/migrations/1727279527027-add-indexes-to-searchable-columns.ts b/backend/migrations/1727279527027-add-indexes-to-searchable-columns.ts new file mode 100644 index 00000000..7215c9c1 --- /dev/null +++ b/backend/migrations/1727279527027-add-indexes-to-searchable-columns.ts @@ -0,0 +1,59 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class AddIndexesToSearchableColumns1727279527027 + implements MigrationInterface +{ + name = 'AddIndexesToSearchableColumns1727279527027'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE INDEX "users_status_idx" ON "users" ("status") `, + ); + await queryRunner.query( + `CREATE INDEX "users_role_id_idx" ON "users" ("role_id") `, + ); + await queryRunner.query( + `CREATE INDEX "roles_code_idx" ON "roles" ("code") `, + ); + await queryRunner.query( + `CREATE INDEX "gov_action_status_idx" ON "gov_action_proposals" ("status") `, + ); + await queryRunner.query( + `CREATE INDEX "gov_action_type_idx" ON "gov_action_proposals" ("gov_action_type") `, + ); + await queryRunner.query( + `CREATE INDEX "votes_user_id_idx" ON "votes" ("user_id") `, + ); + await queryRunner.query( + `CREATE INDEX "votes_gov_action_proposal_id_idx" ON "votes" ("gov_action_proposal_id") `, + ); + await queryRunner.query( + `CREATE INDEX "votes_vote_idx" ON "votes" ("vote") `, + ); + await queryRunner.query( + `ALTER TABLE "rationales" ADD CONSTRAINT "UQ_d2e92e8f049eaa02a6de27bcb48" UNIQUE ("user_id", "gov_action_proposal_id")`, + ); + await queryRunner.query( + `ALTER TABLE "rationales" ADD CONSTRAINT "FK_a5fa1ad294195c3957205a2937a" FOREIGN KEY ("gov_action_proposal_id") REFERENCES "gov_action_proposals"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "rationales" DROP CONSTRAINT "FK_a5fa1ad294195c3957205a2937a"`, + ); + await queryRunner.query( + `ALTER TABLE "rationales" DROP CONSTRAINT "UQ_d2e92e8f049eaa02a6de27bcb48"`, + ); + await queryRunner.query(`DROP INDEX "public"."votes_vote_idx"`); + await queryRunner.query( + `DROP INDEX "public"."votes_gov_action_proposal_id_idx"`, + ); + await queryRunner.query(`DROP INDEX "public"."votes_user_id_idx"`); + await queryRunner.query(`DROP INDEX "public"."gov_action_type_idx"`); + await queryRunner.query(`DROP INDEX "public"."gov_action_status_idx"`); + await queryRunner.query(`DROP INDEX "public"."roles_code_idx"`); + await queryRunner.query(`DROP INDEX "public"."users_role_id_idx"`); + await queryRunner.query(`DROP INDEX "public"."users_status_idx"`); + } +} diff --git a/backend/migrations/1728062638428-users-relations.ts b/backend/migrations/1728062638428-users-relations.ts new file mode 100644 index 00000000..2ca1c5f0 --- /dev/null +++ b/backend/migrations/1728062638428-users-relations.ts @@ -0,0 +1,35 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class UsersRelations1728062638428 implements MigrationInterface { + name = 'UsersRelations1728062638428'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "hot_addresses" DROP CONSTRAINT "FK_e125763f26d4736a5701f6c4d4b"`, + ); + await queryRunner.query( + `ALTER TABLE "hot_addresses" ADD CONSTRAINT "FK_e125763f26d4736a5701f6c4d4b" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, + ); + await queryRunner.query( + `ALTER TABLE "votes" ADD CONSTRAINT "FK_27be2cab62274f6876ad6a31641" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, + ); + await queryRunner.query( + `ALTER TABLE "rationales" ADD CONSTRAINT "FK_182656ae5052a7efd72a02c64e9" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "rationales" DROP CONSTRAINT "FK_182656ae5052a7efd72a02c64e9"`, + ); + await queryRunner.query( + `ALTER TABLE "votes" DROP CONSTRAINT "FK_27be2cab62274f6876ad6a31641"`, + ); + await queryRunner.query( + `ALTER TABLE "hot_addresses" DROP CONSTRAINT "FK_e125763f26d4736a5701f6c4d4b"`, + ); + await queryRunner.query( + `ALTER TABLE "hot_addresses" ADD CONSTRAINT "FK_e125763f26d4736a5701f6c4d4b" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`, + ); + } +} diff --git a/backend/migrations/1729504273717-vote-metadata-url.ts b/backend/migrations/1729504273717-vote-metadata-url.ts new file mode 100644 index 00000000..9c2baa03 --- /dev/null +++ b/backend/migrations/1729504273717-vote-metadata-url.ts @@ -0,0 +1,17 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class VoteMetadataUrl1729504273717 implements MigrationInterface { + name = 'VoteMetadataUrl1729504273717'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "votes" ADD "vote_metadata_url" character varying`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "votes" DROP COLUMN "vote_metadata_url"`, + ); + } +} diff --git a/backend/postman/CC Portal develop.postman_collection.json b/backend/postman/CC Portal develop.postman_collection.json index 10d6daba..90b6489d 100644 --- a/backend/postman/CC Portal develop.postman_collection.json +++ b/backend/postman/CC Portal develop.postman_collection.json @@ -1,7 +1,7 @@ { "info": { - "_postman_id": "e842d76b-56e2-476d-b31d-bbeffd0853bc", - "name": "CC Portal develop Copy", + "_postman_id": "76b45677-bce1-4b13-8de8-db1a76d8e827", + "name": "CC Portal develop", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", "_exporter_id": "20133713" }, @@ -244,6 +244,40 @@ } }, "response": [] + }, + { + "name": "Delete User", + "request": { + "method": "DELETE", + "header": [ + { + "key": "Authorization", + "value": "{{accessToken}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"user_id\": \"a132f533-875f-466a-b194-79f4afe0937b\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base-url}}/api/users/{{userId}}", + "host": [ + "{{base-url}}" + ], + "path": [ + "api", + "users", + "{{userId}}" + ] + } + }, + "response": [] } ] }, @@ -356,6 +390,40 @@ }, "response": [] }, + { + "name": "Resend Register Invite", + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "{{accessToken}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"destination\": \"test.user@test.com\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base-url}}/api/auth/resend-register-invite", + "host": [ + "{{base-url}}" + ], + "path": [ + "api", + "auth", + "resend-register-invite" + ] + } + }, + "response": [] + }, { "name": "Login", "request": { diff --git a/backend/src/auth/api/auth.controller.ts b/backend/src/auth/api/auth.controller.ts index 43fe8ec2..b607607d 100644 --- a/backend/src/auth/api/auth.controller.ts +++ b/backend/src/auth/api/auth.controller.ts @@ -14,6 +14,7 @@ import { AuthFacade } from '../facade/auth.facade'; import { AuthGuard } from '@nestjs/passport'; import { TokenResponse } from './response/token.response'; import { + ApiBearerAuth, ApiBody, ApiOperation, ApiParam, @@ -31,6 +32,7 @@ import { CreateCCMemberRequest } from 'src/users/api/request/create-cc-member.re import { UserMapper } from 'src/users/mapper/userMapper.mapper'; import { CreateAdminRequest } from 'src/users/api/request/create-admin.request'; import { ApiConditionalExcludeEndpoint } from 'src/common/decorators/api-conditional-exclude-endpoint.decorator'; +import { ResendRegisterRequest } from './request/resend-register.request'; @ApiTags('Auth') @Controller('auth') @@ -192,4 +194,29 @@ export class AuthController { return response; } + + @ApiConditionalExcludeEndpoint() + @ApiOperation({ + summary: 'Resend Register invite. Sending email with a magic link', + }) + @ApiBearerAuth('JWT-auth') + @ApiResponse({ status: 201, description: `{ "success": "true" }` }) + @ApiResponse({ status: 401, description: 'Unauthorized' }) + @ApiResponse({ status: 403, description: 'Forbidden resource' }) + @ApiResponse({ status: 409, description: 'Conflict' }) + @ApiBody({ type: ResendRegisterRequest }) + @UseGuards(JwtAuthGuard, PermissionGuard) + @Post('resend-register-invite') + async resendRegisterInvite( + @Req() req, + @Res() res, + @Body() resendRequest: ResendRegisterRequest, + ) { + const permissions: PermissionEnum[] = req.user.permissions; + await this.authFacade.checkAbilityResendRegisterInvite( + resendRequest.destination, + permissions, + ); + return this.registerStrategy.send(req, res); + } } diff --git a/backend/src/auth/api/request/resend-register.request.ts b/backend/src/auth/api/request/resend-register.request.ts new file mode 100644 index 00000000..7a54d52c --- /dev/null +++ b/backend/src/auth/api/request/resend-register.request.ts @@ -0,0 +1,12 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsEmail, MaxLength } from 'class-validator'; + +export class ResendRegisterRequest { + @ApiProperty({ + description: 'Email address of the user', + example: 'john.doe@example.com', + }) + @MaxLength(80, { message: `Maximum character length is 80` }) + @IsEmail() + destination: string; +} diff --git a/backend/src/auth/facade/auth.facade.spec.ts b/backend/src/auth/facade/auth.facade.spec.ts index 02b82d86..5e27b48c 100644 --- a/backend/src/auth/facade/auth.facade.spec.ts +++ b/backend/src/auth/facade/auth.facade.spec.ts @@ -9,6 +9,7 @@ import { CreateUserDto } from 'src/users/dto/create-user.dto'; import { BadRequestException, ConflictException, + ForbiddenException, NotFoundException, UnauthorizedException, } from '@nestjs/common'; @@ -18,6 +19,7 @@ import { Role } from 'src/users/entities/role.entity'; import { TokenResponse } from '../api/response/token.response'; import { EmailService } from '../../email/service/email.service'; import { UserStatusEnum } from '../../users/enums/user-status.enum'; +import { PermissionEnum } from 'src/users/enums/permission.enum'; describe('AuthFacade', () => { let facade: AuthFacade; @@ -135,6 +137,20 @@ describe('AuthFacade', () => { createdAt: null, updatedAt: null, }, + { + id: '3', + name: 'Test User 3', + email: 'test@test.com', + description: 'Lorem ipsum dolor sit amet 3', + profilePhotoUrl: 'https://example3.com/profile.jpg', + status: UserStatusEnum.PENDING, + hotAddresses: ['addr1', 'addr2'], + role: mockRoles[2].code, + permissions: [], + deactivatedAt: null, + createdAt: null, + updatedAt: null, + }, ]; const mockTokenResponse: TokenResponse = { @@ -233,6 +249,7 @@ describe('AuthFacade', () => { } return user; }), + checkRoleManagedByPermission: jest.fn(), }; const mockAuthService = { @@ -408,7 +425,7 @@ describe('AuthFacade', () => { }); describe('Validate User', () => { - it('should validate user by email', async () => { + it('should find user by email', async () => { const email = 'sofija@example.com'; const userDto: UserDto = { id: '1', @@ -425,7 +442,7 @@ describe('AuthFacade', () => { updatedAt: null, }; - const result = await facade.validateUser(email); + const result = await facade.findUserByEmail(email); expect(result).toEqual(userDto); expect(mockUserService.findByEmail).toHaveBeenCalledWith(email); @@ -435,7 +452,7 @@ describe('AuthFacade', () => { const email = 'non_existing@example.com'; try { - await facade.validateUser(email); + await facade.findUserByEmail(email); } catch (e) { expect(e).toBeInstanceOf(NotFoundException); expect(e.message).toBe(`User with this email address not found`); @@ -534,4 +551,79 @@ describe('AuthFacade', () => { ); }); }); + + describe('Check Ability Resend Register Invite', () => { + it('should call checkRoleManagedByPermission if user status is PENDING', async () => { + const mockUser = mockUsers[2]; + jest.spyOn(facade, 'findUserByEmail').mockResolvedValue(mockUser); + const permissions = [PermissionEnum.MANAGE_CC_MEMBERS]; + + await facade.checkAbilityResendRegisterInvite( + mockUser.email, + permissions, + ); + + expect(facade.findUserByEmail).toHaveBeenCalledWith(mockUser.email); + expect(mockUserService.checkRoleManagedByPermission).toHaveBeenCalledWith( + mockUser.role, + permissions, + ); + }); + + it(`should throw error if user's status is not PENDING`, async () => { + const mockUser = mockUsers[1]; + jest.spyOn(facade, 'findUserByEmail').mockResolvedValue(mockUser); + const permissions = [PermissionEnum.MANAGE_CC_MEMBERS]; + + try { + await facade.checkAbilityResendRegisterInvite( + mockUser.email, + permissions, + ); + } catch (e) { + expect(e).toBeInstanceOf(ConflictException); + expect(e.status).toEqual(409); + expect(e.message).toEqual(`Unable to resend register invite`); + } + }); + + it('should throw NotFoundException if user with given email is not found', async () => { + const mockUser = mockUsers[2]; + mockUser.email = 'not-existing-email@test.com'; + jest + .spyOn(facade, 'findUserByEmail') + .mockRejectedValue( + new NotFoundException(`User with this email address not found`), + ); + const permissions = [PermissionEnum.MANAGE_CC_MEMBERS]; + try { + await facade.checkAbilityResendRegisterInvite( + mockUser.email, + permissions, + ); + } catch (e) { + expect(e).toBeInstanceOf(NotFoundException); + expect(e.status).toEqual(404); + expect(e.message).toEqual(`User with this email address not found`); + } + }); + + it('should call checkRoleManagedByPermission if user status is PENDING', async () => { + const mockUser = mockUsers[2]; + mockUser.role = RoleEnum.ADMIN; + jest.spyOn(facade, 'findUserByEmail').mockResolvedValue(mockUser); + const permissions = [PermissionEnum.ADD_CONSTITUTION]; + + try { + await facade.checkAbilityResendRegisterInvite( + mockUser.email, + permissions, + ); + } catch (e) { + expect(e).toBeInstanceOf(ForbiddenException); + expect(e.status).toEqual(403); + expect(e.message).toEqual(`You have no permission for this action`); + } + }); + }); }); diff --git a/backend/src/auth/facade/auth.facade.ts b/backend/src/auth/facade/auth.facade.ts index 69e01d46..b237c5c6 100644 --- a/backend/src/auth/facade/auth.facade.ts +++ b/backend/src/auth/facade/auth.facade.ts @@ -14,6 +14,7 @@ import { EmailDto } from 'src/email/dto/email.dto'; import { UserStatusEnum } from '../../users/enums/user-status.enum'; import { CreateUserRequest } from 'src/users/api/request/create-user.request'; import { RoleEnum } from 'src/users/enums/role.enum'; +import { PermissionEnum } from 'src/users/enums/permission.enum'; @Injectable() export class AuthFacade { @@ -47,8 +48,7 @@ export class AuthFacade { return updatedUser; } - // validateUser checks user by email - async validateUser(email: string): Promise { + async findUserByEmail(email: string): Promise { const user = await this.usersService.findByEmail(email); return user; } @@ -60,7 +60,7 @@ export class AuthFacade { // checkLoginAbility checks whether the user can login according to his status async checkLoginAbility(email: string): Promise { - const user = await this.validateUser(email); + const user = await this.findUserByEmail(email); if (user.status !== UserStatusEnum.ACTIVE) { throw new BadRequestException(`User is not active`); } @@ -106,4 +106,15 @@ export class AuthFacade { async sendEmail(emailDto: EmailDto): Promise { await this.emailService.sendEmail(emailDto); } + + async checkAbilityResendRegisterInvite( + email: string, + permissions: PermissionEnum[], + ) { + const user = await this.findUserByEmail(email); + if (user.status !== UserStatusEnum.PENDING) { + throw new ConflictException(`Unable to resend register invite`); + } + this.usersService.checkRoleManagedByPermission(user.role, permissions); + } } diff --git a/backend/src/auth/strategy/magiclogin.strategy.ts b/backend/src/auth/strategy/magiclogin.strategy.ts index e624e375..d5aadccf 100644 --- a/backend/src/auth/strategy/magiclogin.strategy.ts +++ b/backend/src/auth/strategy/magiclogin.strategy.ts @@ -25,8 +25,12 @@ export class MagicLoginStrategy extends PassportStrategy( callbackUrl: configService.getOrThrow('FE_LOGIN_CALLBACK_URL'), sendMagicLink: async (destination: string, href: string) => { const emailDto: EmailDto = EmailMapper.loginEmail(destination, href); + const localEnv = configService.get('ENVIRONMENT') === 'local'; + if (localEnv) { + this.logger.log(`sending email to ${destination}, with link ${href}`); + return; + } await this.authFacade.sendEmail(emailDto); - this.logger.log(`sending email to ${destination}, with link ${href}`); }, verify: async (payload, callback) => callback(null, this.validate(payload)), @@ -34,7 +38,7 @@ export class MagicLoginStrategy extends PassportStrategy( } validate(payload: { destination: string }) { - const user = this.authFacade.validateUser(payload.destination); + const user = this.authFacade.findUserByEmail(payload.destination); return user; } } diff --git a/backend/src/auth/strategy/magicregister.strategy.ts b/backend/src/auth/strategy/magicregister.strategy.ts index 52b469d2..d70695cf 100644 --- a/backend/src/auth/strategy/magicregister.strategy.ts +++ b/backend/src/auth/strategy/magicregister.strategy.ts @@ -29,8 +29,12 @@ export class MagicRegisterStrategy extends PassportStrategy( destination, href, ); + const localEnv = configService.get('ENVIRONMENT') === 'local'; + if (localEnv) { + this.logger.log(`sending email to ${destination}, with link ${href}`); + return; + } await this.authFacade.sendEmail(emailDto); - this.logger.log(`sending email to ${destination}, with link ${href}`); }, verify: async (payload, callback) => callback(null, this.validate(payload)), @@ -38,7 +42,7 @@ export class MagicRegisterStrategy extends PassportStrategy( } validate(payload: { destination: string }) { - const user = this.authFacade.validateUser(payload.destination); + const user = this.authFacade.findUserByEmail(payload.destination); return user; } } diff --git a/backend/src/constitution/facade/constitution.facade.spec.ts b/backend/src/constitution/facade/constitution.facade.spec.ts index 172f2e55..d4cdc6e8 100644 --- a/backend/src/constitution/facade/constitution.facade.spec.ts +++ b/backend/src/constitution/facade/constitution.facade.spec.ts @@ -59,12 +59,16 @@ describe('ConstitutionFacade', () => { const mockFirstConstitutionMetadataResponse: ConstitutionMetadataResponse = { title: 'Revision 1', cid: 'bafkreibxlpnlpsg6ewqzxhslwyhzl4p4vc6bifj3nb4k2lxhbnfaojbmwy', + blake2b: 'f6f811fbde53b09c1b653766f27578cc867e9b634b9142800f56e282b041de00', + url: 'https://ipfs.io/ipfs/bafkreibxlpnlpsg6ewqzxhslwyhzl4p4vc6bifj3nb4k2lxhbnfaojbmwy', version: '1713769514', createdDate: '2024-04-21 11:21:59.334', }; const mockFirstConstitutionResponse: ConstitutionResponse = { cid: 'bafkreibxlpnlpsg6ewqzxhslwyhzl4p4vc6bifj3nb4k2lxhbnfaojbmwy', + blake2b: 'f6f811fbde53b09c1b653766f27578cc867e9b634b9142800f56e282b041de00', + url: 'https://ipfs.io/ipfs/bafkreibxlpnlpsg6ewqzxhslwyhzl4p4vc6bifj3nb4k2lxhbnfaojbmwy', version: '1713769514', contents: 'The morning sun cast a golden glow over the tranquil village, painting the cobblestone streets with warmth. Birds chirped melodiously, adding to the serene ambiance that enveloped the small community. Life moved at a leisurely pace here, far removed from the hustle and bustle of the city. Neighbors greeted each other with smiles and friendly nods as they went about their daily routines, weaving a tight-knit tapestry of camaraderie.\n', @@ -93,6 +97,8 @@ describe('ConstitutionFacade', () => { const mockSecondConstitutionMetadataResponse: ConstitutionMetadataResponse = { title: 'Revision 2', cid: 'bafkreich5c3rbz4amwevqy676czysmr27ctby46zdhja7gnpzriyqwdv4i', + blake2b: 'f6f811fbde53b09c1b653766f27578cc867e9b634b9142800f56e282b041de00', + url: 'https://ipfs.io/ipfs/bafkreich5c3rbz4amwevqy676czysmr27ctby46zdhja7gnpzriyqwdv4i', version: '1713769479', createdDate: '2024-04-22 11:21:59.334', }; diff --git a/backend/src/governance/api/response/vote.response.ts b/backend/src/governance/api/response/vote.response.ts index e4f379f2..70a1ac87 100644 --- a/backend/src/governance/api/response/vote.response.ts +++ b/backend/src/governance/api/response/vote.response.ts @@ -33,6 +33,14 @@ export class VoteResponse { @Expose({ name: 'value' }) voteValue: VoteValue; + @ApiProperty({ + description: 'Gives an on chain rationale url to a vote', + example: + 'https://ipfs.io.ipfs/QmaoWaMwKjrrvLKWZaWgeLpT7qcrYJNUby2Mnk5uYBrkG4', + }) + @Expose({ name: 'rationale_url' }) + rationaleUrl: string; + @ApiProperty({ description: 'Gives an on chain rationale title related to a vote', example: 'This proposal is good for the ecosystem', diff --git a/backend/src/governance/dto/vote.dto.ts b/backend/src/governance/dto/vote.dto.ts index ff3ab88e..58631106 100644 --- a/backend/src/governance/dto/vote.dto.ts +++ b/backend/src/governance/dto/vote.dto.ts @@ -8,6 +8,7 @@ export class VoteDto { userAddress: string; userPhotoUrl: string; voteValue: VoteValue; + rationaleUrl: string; rationaleTitle: string; rationaleComment: string; govActionProposalId: string; diff --git a/backend/src/governance/entities/gov-action-proposal.entity.ts b/backend/src/governance/entities/gov-action-proposal.entity.ts index 7494972f..c44244c9 100644 --- a/backend/src/governance/entities/gov-action-proposal.entity.ts +++ b/backend/src/governance/entities/gov-action-proposal.entity.ts @@ -1,5 +1,5 @@ import { CommonEntity } from '../../common/entities/common.entity'; -import { Column, Entity, OneToMany, PrimaryColumn } from 'typeorm'; +import { Column, Entity, Index, OneToMany, PrimaryColumn } from 'typeorm'; import { Vote } from './vote.entity'; import { Rationale } from './rationale.entity'; @@ -23,7 +23,6 @@ export class GovActionProposal extends CommonEntity { @Column({ name: 'title', type: 'varchar', - length: 80, nullable: true, }) title: string; @@ -31,7 +30,6 @@ export class GovActionProposal extends CommonEntity { @Column({ name: 'abstract', type: 'varchar', - length: 2500, nullable: true, }) abstract: string; @@ -42,12 +40,14 @@ export class GovActionProposal extends CommonEntity { }) govMetadataUrl: string; + @Index('gov_action_status_idx') @Column({ name: 'status', type: 'varchar', }) status: string; + @Index('gov_action_type_idx') @Column({ name: 'gov_action_type', type: 'varchar', diff --git a/backend/src/governance/entities/rationale.entity.ts b/backend/src/governance/entities/rationale.entity.ts index 2caab91f..80e0c7ca 100644 --- a/backend/src/governance/entities/rationale.entity.ts +++ b/backend/src/governance/entities/rationale.entity.ts @@ -8,10 +8,17 @@ import { Unique, } from 'typeorm'; import { GovActionProposal } from './gov-action-proposal.entity'; +import { User } from '../../users/entities/user.entity'; @Entity('rationales') @Unique(['userId', 'govActionProposalId']) export class Rationale extends CommonEntity { + @ManyToOne(() => User, (user) => user.rationales, { + onDelete: 'CASCADE', + }) + @JoinColumn({ name: 'user_id' }) + user: User; + @PrimaryColumn({ name: 'user_id', type: 'uuid', diff --git a/backend/src/governance/entities/vote.entity.ts b/backend/src/governance/entities/vote.entity.ts index 2ba497ea..b2b2aaea 100644 --- a/backend/src/governance/entities/vote.entity.ts +++ b/backend/src/governance/entities/vote.entity.ts @@ -1,6 +1,14 @@ import { CommonEntity } from '../../common/entities/common.entity'; -import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm'; +import { + Column, + Entity, + Index, + JoinColumn, + ManyToOne, + PrimaryColumn, +} from 'typeorm'; import { GovActionProposal } from './gov-action-proposal.entity'; +import { User } from '../../users/entities/user.entity'; @Entity('votes') export class Vote extends CommonEntity { @@ -10,18 +18,26 @@ export class Vote extends CommonEntity { }) id: string; + @Index('votes_user_id_idx') @Column({ name: 'user_id', type: 'uuid', }) userId: string; + @ManyToOne(() => User, (user) => user.votes, { + onDelete: 'CASCADE', + }) + @JoinColumn({ name: 'user_id' }) + user: User; + @Column({ name: 'hot_address', type: 'varchar', }) hotAddress: string; + @Index('votes_gov_action_proposal_id_idx') @ManyToOne( () => GovActionProposal, (govActionProposal) => govActionProposal.id, @@ -32,6 +48,7 @@ export class Vote extends CommonEntity { @JoinColumn({ name: 'gov_action_proposal_id' }) govActionProposal: GovActionProposal; + @Index('votes_vote_idx') @Column({ name: 'vote', type: 'varchar', @@ -52,6 +69,13 @@ export class Vote extends CommonEntity { }) comment: string; + @Column({ + name: 'vote_metadata_url', + type: 'varchar', + nullable: true, + }) + voteMetadataUrl: string; + @Column({ name: 'submit_time', type: 'timestamp', diff --git a/backend/src/governance/facade/governance.facade.spec.ts b/backend/src/governance/facade/governance.facade.spec.ts index 3cd0ddaf..5acc4595 100644 --- a/backend/src/governance/facade/governance.facade.spec.ts +++ b/backend/src/governance/facade/governance.facade.spec.ts @@ -36,6 +36,8 @@ describe('GovernanceFacade', () => { status: UserStatusEnum.ACTIVE, role: null, permissions: [], + rationales: null, + votes: null, createdAt: null, updatedAt: null, deactivatedAt: null, @@ -50,6 +52,8 @@ describe('GovernanceFacade', () => { status: UserStatusEnum.ACTIVE, role: null, permissions: [], + rationales: null, + votes: null, createdAt: null, updatedAt: null, deactivatedAt: null, @@ -69,6 +73,8 @@ describe('GovernanceFacade', () => { hasRationale: null, submitTime: null, endTime: null, + votedBy: null, + rationaleBy: null, }, { id: '2', @@ -82,6 +88,8 @@ describe('GovernanceFacade', () => { hasRationale: null, submitTime: null, endTime: null, + votedBy: null, + rationaleBy: null, }, ]; @@ -172,6 +180,7 @@ describe('GovernanceFacade', () => { userAddress: 'hotAddress_1', userPhotoUrl: 'photoUrl', voteValue: VoteValue.Yes, + rationaleUrl: 'rationaleUrl_1', rationaleTitle: 'Title_1', rationaleComment: 'Comment_1', govActionProposalId: mockGovActionProposals[0].id, @@ -189,6 +198,7 @@ describe('GovernanceFacade', () => { userAddress: 'hotAddress_1', userPhotoUrl: 'photoUrl', voteValue: VoteValue.Yes, + rationaleUrl: 'rationaleUrl_2', rationaleTitle: 'Title_2', rationaleComment: 'Comment_2', govActionProposalId: mockGovActionProposals[1].id, @@ -568,7 +578,7 @@ describe('GovernanceFacade', () => { expect( mockGovernanceService.searchGovActionProposals, - ).toHaveBeenCalledWith(query, userId); + ).toHaveBeenCalledWith(query); }); it('should return an empty array - not found by userId', async () => { @@ -578,13 +588,22 @@ describe('GovernanceFacade', () => { limit: 10, path: 'randomPath', }; + mockGovernanceService.searchGovActionProposals.mockReturnValueOnce({ + items: [], + itemCount: 0, + pageOptions: { + page: query.page, + perPage: query.limit, + skip: 10, + }, + } as PaginatedDto); const result = await facade.searchGovActionProposals(query, userId); expect(result.data).toEqual([]); expect( mockGovernanceService.searchGovActionProposals, - ).toHaveBeenCalledWith(query, userId); + ).toHaveBeenCalledWith(query); }); it('should return an empty array - not found by search parameter', async () => { @@ -601,7 +620,7 @@ describe('GovernanceFacade', () => { expect(result.data).toEqual([]); expect( mockGovernanceService.searchGovActionProposals, - ).toHaveBeenCalledWith(query, userId); + ).toHaveBeenCalledWith(query); }); }); }); diff --git a/backend/src/governance/mapper/governance-mapper.ts b/backend/src/governance/mapper/governance-mapper.ts index f13a3c99..3d22dccc 100644 --- a/backend/src/governance/mapper/governance-mapper.ts +++ b/backend/src/governance/mapper/governance-mapper.ts @@ -24,6 +24,7 @@ export class GovernanceMapper { voteResponse.userPhotoUrl = voteDto.userPhotoUrl; voteResponse.userAddress = voteDto.userAddress; voteResponse.voteValue = voteDto.voteValue; + voteResponse.rationaleUrl = voteDto.rationaleUrl; voteResponse.rationaleTitle = voteDto.rationaleTitle; voteResponse.rationaleComment = voteDto.rationaleComment; voteResponse.govActionProposalId = voteDto.govActionProposalId; @@ -42,6 +43,7 @@ export class GovernanceMapper { voteDto.userId = vote.userId; voteDto.userAddress = vote.hotAddress; voteDto.voteValue = VoteValue[vote.vote]; + voteDto.rationaleUrl = vote.voteMetadataUrl; voteDto.rationaleTitle = vote.title; voteDto.rationaleComment = vote.comment; voteDto.govActionProposalId = vote.govActionProposal?.id; diff --git a/backend/src/governance/services/governance.service.spec.ts b/backend/src/governance/services/governance.service.spec.ts index 68fc8ac3..4138b0d1 100644 --- a/backend/src/governance/services/governance.service.spec.ts +++ b/backend/src/governance/services/governance.service.spec.ts @@ -13,6 +13,9 @@ import { PaginatedDto } from 'src/util/pagination/dto/paginated.dto'; import { VoteDto } from '../dto/vote.dto'; import { VoteStatus } from '../enums/vote-status.enum'; import { VoteValue } from '../enums/vote-value.enum'; +import { User } from 'src/users/entities/user.entity'; +import { UserStatusEnum } from 'src/users/enums/user-status.enum'; +import { RoleEnum } from 'src/users/enums/role.enum'; describe('IpfsService', () => { let service: GovernanceService; @@ -30,6 +33,8 @@ describe('IpfsService', () => { hasRationale: null, submitTime: null, endTime: null, + votedBy: null, + rationaleBy: null, }, { id: '2', @@ -43,6 +48,8 @@ describe('IpfsService', () => { hasRationale: null, submitTime: null, endTime: null, + votedBy: null, + rationaleBy: null, }, ]; @@ -92,12 +99,38 @@ describe('IpfsService', () => { }, ]; + const mockUser: User = { + id: 'userId', + name: 'John Doe', + email: 'mockedEmail', + description: 'mockedDescription', + profilePhotoUrl: 'mockedProfilePhoto', + status: UserStatusEnum.ACTIVE, + role: { + id: 'roleId3', + code: RoleEnum.USER, + users: [], + permissions: [], + createdAt: null, + updatedAt: null, + }, + permissions: null, + hotAddresses: null, + rationales: null, + votes: null, + deactivatedAt: null, + createdAt: null, + updatedAt: null, + }; + const vote: Vote = { id: '1', userId: 'userId', + user: mockUser, hotAddress: 'hotAddress_1', govActionProposal: mockGovActionProposals[0], vote: VoteValue.Yes, + voteMetadataUrl: 'voteMetadataUrl_1', title: 'Title_1', comment: 'Comment_1', submitTime: null, @@ -109,9 +142,11 @@ describe('IpfsService', () => { { id: 'Vote_1', userId: 'User_1', + user: mockUser, hotAddress: 'hotAddress_1', govActionProposal: mockGovActionProposals[0], vote: VoteValue.Yes, + voteMetadataUrl: 'voteMetadataUrl_1', title: 'Title_1', comment: 'Comment_1', submitTime: null, @@ -121,9 +156,11 @@ describe('IpfsService', () => { { id: 'Vote_2', userId: 'User_1', + user: mockUser, hotAddress: 'hotAddress_1', govActionProposal: mockGovActionProposals[1], vote: VoteValue.Yes, + voteMetadataUrl: 'voteMetadataUrl_2', title: 'Title_2', comment: 'Comment_2', submitTime: null, @@ -448,9 +485,6 @@ describe('IpfsService', () => { search: 'govActionProposal_Title', path: 'randomPath', }; - jest - .spyOn(service, 'returnGapQuery') - .mockResolvedValueOnce(mockGovActionProposals[0]); mockPaginator.paginate.mockResolvedValue(paginatedValueGap); const gapPaginatedDto: PaginatedDto = await service.searchGovActionProposals(query); @@ -468,7 +502,6 @@ describe('IpfsService', () => { search: 'NotExisting', path: 'randomPath', }; - jest.spyOn(service, 'returnGapQuery').mockResolvedValueOnce([]); mockPaginator.paginate.mockResolvedValueOnce(paginatedEmptyValueGap); const gapPaginatedDto: PaginatedDto = await service.searchGovActionProposals(query); @@ -502,10 +535,9 @@ describe('IpfsService', () => { limit: 10, path: 'randomPath', }; - const userId = 'user1'; mockPaginator.paginate.mockResolvedValueOnce(paginatedMultiValueGap); const gapPaginatedDto: PaginatedDto = - await service.searchGovActionProposals(query, userId); + await service.searchGovActionProposals(query); expect(gapPaginatedDto.items[0].title).toEqual( mockGovActionProposals[0].title, ); diff --git a/backend/src/s3/service/s3.service.spec.ts b/backend/src/s3/service/s3.service.spec.ts index 0e56d551..50e902d7 100644 --- a/backend/src/s3/service/s3.service.spec.ts +++ b/backend/src/s3/service/s3.service.spec.ts @@ -11,10 +11,13 @@ const mockBucket = { }; const mockConfigService = { - get: jest.fn().mockImplementation((minioBucked) => { - if (minioBucked === 'MINIO_BUCKET') { + get: jest.fn().mockImplementation((variable) => { + if (variable === 'MINIO_BUCKET') { return 'cc-portal'; } + if (variable === 'S3_BASE_URL') { + return 'https://cc-portal.s3.amazonaws.com'; + } }), }; @@ -88,13 +91,14 @@ describe('S3Service', () => { const result = await service.uploadFile(context, fileName, file); expect(result).toBe( - 'https://cc-portal.s3.amazonaws.com/profile-photo-test-upload.txt', + 'https://cc-portal.s3.amazonaws.com/cc-portal/profile-photo-test-upload.txt', ); expect(mockMinioClient.putObject).toHaveBeenCalledWith( 'cc-portal', 'profile-photo-test-upload.txt', expect.any(Buffer), 100, + { 'Content-Type': undefined }, ); }); diff --git a/backend/src/users/api/request/remove-user.request.ts b/backend/src/users/api/request/remove-user.request.ts new file mode 100644 index 00000000..3a140c0f --- /dev/null +++ b/backend/src/users/api/request/remove-user.request.ts @@ -0,0 +1,12 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsUUID } from 'class-validator'; + +export class RemoveUserRequest { + @ApiProperty({ + description: 'Identification number of the user', + example: '82dbbfb1-2552-4aaf-a9a7-1195497410c0', + name: 'user_id', + }) + @IsUUID() + userId: string; +} diff --git a/backend/src/users/api/users.controller.ts b/backend/src/users/api/users.controller.ts index 9c086d03..71f851c3 100644 --- a/backend/src/users/api/users.controller.ts +++ b/backend/src/users/api/users.controller.ts @@ -13,6 +13,7 @@ import { UseGuards, Request, Delete, + BadRequestException, } from '@nestjs/common'; import { UsersFacade } from '../facade/users.facade'; import { UpdateUserRequest } from './request/update-user.request'; @@ -40,6 +41,8 @@ import { PermissionEnum } from '../enums/permission.enum'; import { PermissionGuard } from 'src/auth/guard/permission.guard'; import { ToggleStatusRequest } from './request/toggle-status.request'; import { ApiConditionalExcludeEndpoint } from 'src/common/decorators/api-conditional-exclude-endpoint.decorator'; +import { Permissions } from 'src/auth/guard/permission.decorator'; +import { RemoveUserRequest } from './request/remove-user.request'; @ApiTags('Users') @Controller('users') @@ -272,4 +275,36 @@ export class UsersController { permissions, ); } + + @ApiConditionalExcludeEndpoint() + @ApiBearerAuth('JWT-auth') + @ApiOperation({ summary: 'Delete user' }) + @ApiResponse({ status: 200, description: 'User deleted successfully' }) + @ApiResponse({ status: 400, description: 'Bad requset' }) + @ApiResponse({ status: 401, description: 'Unauthorized' }) + @ApiResponse({ status: 403, description: 'Forbidden resource' }) + @ApiResponse({ status: 404, description: 'Not found' }) + @ApiParam({ + name: 'id', + type: String, + description: 'identifactor of user', + }) + @ApiBody({ type: RemoveUserRequest }) + @HttpCode(200) + @Permissions(PermissionEnum.MANAGE_ADMINS) // Superadmin only + @UseGuards(JwtAuthGuard, UserPathGuard, PermissionGuard) + @Delete(':id') + async removeUser( + @Param('id', ParseUUIDPipe) id: string, + @Body() removeUserRequest: RemoveUserRequest, + ) { + if (id === removeUserRequest.userId) { + throw new BadRequestException(`You cannot delete yourself`); + } + await this.usersFacade.removeUser(removeUserRequest.userId); + return { + success: true, + message: 'User deleted successfully', + }; + } } diff --git a/backend/src/users/entities/hotaddress.entity.ts b/backend/src/users/entities/hotaddress.entity.ts index 8b29238e..c226eb66 100644 --- a/backend/src/users/entities/hotaddress.entity.ts +++ b/backend/src/users/entities/hotaddress.entity.ts @@ -20,7 +20,9 @@ export class HotAddress extends CommonEntity { }) address: string; - @ManyToOne(() => User, (user) => user.hotAddresses) + @ManyToOne(() => User, (user) => user.hotAddresses, { + onDelete: 'CASCADE', + }) @JoinColumn({ name: 'user_id' }) user: User; } diff --git a/backend/src/users/entities/role.entity.ts b/backend/src/users/entities/role.entity.ts index 9dd088ea..ab41d3d9 100644 --- a/backend/src/users/entities/role.entity.ts +++ b/backend/src/users/entities/role.entity.ts @@ -1,6 +1,7 @@ import { Column, Entity, + Index, JoinTable, ManyToMany, OneToMany, @@ -16,6 +17,7 @@ export class Role extends CommonEntity { @PrimaryGeneratedColumn('uuid') id: string; + @Index('roles_code_idx') @Column({ name: 'code', type: 'enum', diff --git a/backend/src/users/entities/user.entity.ts b/backend/src/users/entities/user.entity.ts index 052acf70..6cbecf6d 100644 --- a/backend/src/users/entities/user.entity.ts +++ b/backend/src/users/entities/user.entity.ts @@ -1,6 +1,7 @@ import { Column, Entity, + Index, JoinColumn, JoinTable, ManyToMany, @@ -13,6 +14,8 @@ import { CommonEntity } from '../../common/entities/common.entity'; import { Permission } from './permission.entity'; import { HotAddress } from './hotaddress.entity'; import { UserStatusEnum } from '../enums/user-status.enum'; +import { Rationale } from '../../governance/entities/rationale.entity'; +import { Vote } from '../../governance/entities/vote.entity'; @Entity('users') export class User extends CommonEntity { @@ -50,6 +53,7 @@ export class User extends CommonEntity { }) profilePhotoUrl: string; + @Index('users_status_idx') @Column({ name: 'status', type: 'enum', @@ -63,6 +67,17 @@ export class User extends CommonEntity { }) hotAddresses: HotAddress[]; + @OneToMany(() => Rationale, (rationale) => rationale.user, { + cascade: true, + }) + rationales: Rationale[]; + + @OneToMany(() => Vote, (vote) => vote.user, { + cascade: true, + }) + votes: Vote[]; + + @Index('users_role_id_idx') @ManyToOne(() => Role, (role) => role.users, { eager: true, }) diff --git a/backend/src/users/facade/users.facade.spec.ts b/backend/src/users/facade/users.facade.spec.ts index cd2fead5..b917d127 100644 --- a/backend/src/users/facade/users.facade.spec.ts +++ b/backend/src/users/facade/users.facade.spec.ts @@ -4,6 +4,7 @@ import { UsersService } from '../services/users.service'; import { ConflictException, ForbiddenException, + Logger, NotFoundException, } from '@nestjs/common'; import { UserStatusEnum } from '../enums/user-status.enum'; @@ -23,6 +24,7 @@ import { RoleFactory } from '../role/role.factory'; describe('UsersFacade', () => { let facade: UsersFacade; + let logger: Logger; let mockRoles: Role[] = [ { @@ -215,13 +217,6 @@ describe('UsersFacade', () => { ); } - // const sortedUsers = filteredUsers.sort((a, b) => { - // if (query.sortBy === SortOrder.ASC) { - // return a.name > b.name ? 1 : -1; - // } else if (order === SortOrder.DESC) { - // return b.name > a.name ? -1 : -1; - // } - // }); const currentPosition = query.page * query.limit; const paginatedUsers = filteredUsers.slice( currentPosition, @@ -241,6 +236,8 @@ describe('UsersFacade', () => { return usersPaginatedDto; }), updateUserStatus: jest.fn(), + removeUser: jest.fn(), + checkRoleManagedByPermission: jest.fn(), }; const mockS3Service = { @@ -264,10 +261,17 @@ describe('UsersFacade', () => { provide: RoleFactory, useValue: mockRoleFactory, }, + { + provide: Logger, + useValue: { + error: jest.fn(), + }, + }, ], }).compile(); facade = module.get(UsersFacade); + logger = module.get(Logger); }); afterEach(() => { @@ -490,7 +494,7 @@ describe('UsersFacade', () => { }); it('should deactivate an admin', async () => { - const user = mockUsers[0]; + const user = mockUsers[1]; const request: ToggleStatusRequest = { userId: user.id, status: UserStatusEnum.INACTIVE, @@ -516,7 +520,7 @@ describe('UsersFacade', () => { }); it(`shouldn't deactivate an admin - no permission`, async () => { - const user = mockUsers[0]; + const user = mockUsers[1]; const request: ToggleStatusRequest = { userId: user.id, status: UserStatusEnum.INACTIVE, @@ -535,7 +539,7 @@ describe('UsersFacade', () => { }); it(`shouldn't deactivate a super admin - no permission`, async () => { - const user = mockUsers[0]; + const user = mockUsers[1]; const request: ToggleStatusRequest = { userId: user.id, status: UserStatusEnum.INACTIVE, @@ -574,4 +578,49 @@ describe('UsersFacade', () => { } }); }); + + describe(`Remove user`, () => { + it('should remove a user and delete their profile photo if it exists', async () => { + const mockUserDto = mockUsers[0]; + jest.spyOn(mockS3Service, 'deleteFile').mockResolvedValue('profile.jpg'); + jest.spyOn(mockUserService, 'removeUser').mockResolvedValue(undefined); + + await facade.removeUser(mockUserDto.id); + + // Assert: Ensure that the user was removed and file was deleted + expect(mockUserService.findById).toHaveBeenCalledWith(mockUserDto.id); + expect(mockUserService.removeUser).toHaveBeenCalledWith(mockUserDto.id); + expect(mockS3Service.deleteFile).toHaveBeenCalledWith('profile.jpg'); + }); + + it('should remove a user without attempting to delete the profile photo if none exists', async () => { + const mockUserDto = mockUsers[0]; + mockUserDto.profilePhotoUrl = null; + jest.spyOn(mockUserService, 'removeUser').mockResolvedValue(undefined); + + await facade.removeUser(mockUserDto.id); + + // Assert: Ensure the profile photo was not deleted + expect(mockUserService.findById).toHaveBeenCalledWith(mockUserDto.id); + expect(mockUserService.removeUser).toHaveBeenCalledWith(mockUserDto.id); + expect(mockS3Service.deleteFile).not.toHaveBeenCalled(); + }); + + it('should log an error if deleting the profile photo fails', async () => { + const mockUserDto = mockUsers[0]; + jest + .spyOn(mockS3Service, 'deleteFile') + .mockRejectedValue(new Error('Deletion error')); + jest.spyOn(logger, 'error').mockImplementation(jest.fn()); + + try { + await facade.removeUser(mockUserDto.id); + } catch (error) { + // Assert: Ensure the error is logged but the process doesn't crash + expect(logger.error).toHaveBeenCalledWith( + `Error when removing profile photo of the user with id ${mockUserDto.id}: Deletion error`, + ); + } + }); + }); }); diff --git a/backend/src/users/facade/users.facade.ts b/backend/src/users/facade/users.facade.ts index 568682c4..441f46f5 100644 --- a/backend/src/users/facade/users.facade.ts +++ b/backend/src/users/facade/users.facade.ts @@ -1,7 +1,8 @@ import { + BadRequestException, ConflictException, - ForbiddenException, Injectable, + Logger, } from '@nestjs/common'; import { UpdateUserRequest } from '../api/request/update-user.request'; import { UsersService } from '../services/users.service'; @@ -18,13 +19,13 @@ import { PaginateQuery } from 'nestjs-paginate'; import { PaginationDtoMapper } from 'src/util/pagination/mapper/pagination.mapper'; import { PermissionEnum } from '../enums/permission.enum'; import { ToggleStatusRequest } from '../api/request/toggle-status.request'; -import { RoleFactory } from '../role/role.factory'; +import { UserStatusEnum } from '../enums/user-status.enum'; @Injectable() export class UsersFacade { + private logger = new Logger(UsersService.name); constructor( private readonly usersService: UsersService, private readonly s3Service: S3Service, - private readonly roleFactory: RoleFactory, ) {} async getAllRoles(): Promise { @@ -100,7 +101,13 @@ export class UsersFacade { permissions: PermissionEnum[], ): Promise { const user = await this.usersService.findById(toggleStatusRequest.userId); - this.checkAbilityToggleStatus(user, permissions); + // Current status of the user 'pending' cannot be changed in this way + if (user.status === UserStatusEnum.PENDING) { + throw new BadRequestException( + `Unable to change current status ${UserStatusEnum.PENDING}`, + ); + } + this.usersService.checkRoleManagedByPermission(user.role, permissions); const result = await this.usersService.updateUserStatus( user.id, toggleStatusRequest.status, @@ -108,19 +115,20 @@ export class UsersFacade { return UserMapper.mapUserDtoToResponse(result); } - /** - * Checks whether the logged-in user can change status - * @param user - User whose status we change - * @param permissions - Permissions of the logged-in user - */ - private checkAbilityToggleStatus( - user: UserDto, - permissions: PermissionEnum[], - ): void { - const role = this.roleFactory.getInstance(user.role); - const managedBy = role.managedBy(); - if (!permissions.includes(managedBy)) { - throw new ForbiddenException(`You have no permission for this action`); + async removeUser(userId: string): Promise { + const userDto = await this.usersService.findById(userId); + await this.usersService.removeUser(userDto.id); + try { + if (userDto.profilePhotoUrl) { + const fileName = S3Service.extractFileNameFromUrl( + userDto.profilePhotoUrl, + ); + await this.s3Service.deleteFile(fileName); + } + } catch (e) { + this.logger.error( + `Error when removing profile photo of the user with id ${userId}: ${e.message}`, + ); } } } diff --git a/backend/src/users/services/users.service.spec.ts b/backend/src/users/services/users.service.spec.ts index b0199aa6..521c9670 100644 --- a/backend/src/users/services/users.service.spec.ts +++ b/backend/src/users/services/users.service.spec.ts @@ -18,6 +18,7 @@ import { UserDto } from '../dto/user.dto'; import { PaginateQuery, Paginated } from 'nestjs-paginate'; import { Paginator } from 'src/util/pagination/paginator'; import { RoleEnum } from '../enums/role.enum'; +import { RoleFactory } from '../role/role.factory'; const mockS3Service = { uploadFileMinio: jest.fn().mockResolvedValue('mocked_file_name'), createBucketIfNotExists: jest.fn().mockResolvedValue('new_bucket'), @@ -41,6 +42,8 @@ const user: User = { }, permissions: null, hotAddresses: null, + rationales: null, + votes: null, deactivatedAt: null, createdAt: null, updatedAt: null, @@ -130,6 +133,8 @@ const mockUsers: User[] = [ status: UserStatusEnum.ACTIVE, role: mockRoles[2], permissions: [], + rationales: null, + votes: null, deactivatedAt: null, createdAt: null, updatedAt: null, @@ -144,6 +149,8 @@ const mockUsers: User[] = [ status: UserStatusEnum.ACTIVE, role: mockRoles[1], permissions: [mockPermissions[0], mockPermissions[1]], + rationales: null, + votes: null, deactivatedAt: null, createdAt: null, updatedAt: null, @@ -243,6 +250,7 @@ const mockUserRepository = { return mockUsers; }), count: jest.fn().mockResolvedValue(mockUsers.length), + remove: jest.fn(), }; const mockRoleRepository = { create: jest.fn().mockReturnValue({}), @@ -327,6 +335,10 @@ describe('UsersService', () => { provide: ConfigService, useValue: {}, }, + { + provide: RoleFactory, + useValue: {}, + }, ], }).compile(); @@ -709,4 +721,24 @@ describe('UsersService', () => { expect(mockPaginator.paginate).toHaveBeenCalled(); }); }); + + describe('removeUser', () => { + it('should remove a user successfully', async () => { + const mockUser = mockUsers[0]; + const mockFindEntityById = jest + .spyOn(service, 'findEntityById') + .mockResolvedValueOnce(mockUser); + await service.removeUser(mockUser.id); + expect(mockFindEntityById).toHaveBeenCalledWith(mockUser.id); + expect(mockUserRepository.remove).toHaveBeenCalledWith(mockUser); + }); + it('should throw NotFoundException if user is not found', async () => { + jest + .spyOn(service, 'findEntityById') + .mockRejectedValue(new NotFoundException()); + await expect(service.removeUser('non-existent-user')).rejects.toThrow( + NotFoundException, + ); + }); + }); }); diff --git a/backend/src/users/services/users.service.ts b/backend/src/users/services/users.service.ts index c21579bb..cc190992 100644 --- a/backend/src/users/services/users.service.ts +++ b/backend/src/users/services/users.service.ts @@ -1,6 +1,7 @@ import { BadRequestException, ConflictException, + ForbiddenException, Injectable, InternalServerErrorException, Logger, @@ -25,6 +26,8 @@ import { USER_PAGINATION_CONFIG } from '../util/pagination/user-pagination.confi import { PaginatedDto } from 'src/util/pagination/dto/paginated.dto'; import { PaginationEntityMapper } from 'src/util/pagination/mapper/pagination.mapper'; import { Paginator } from 'src/util/pagination/paginator'; +import { RoleFactory } from '../role/role.factory'; +import { PermissionEnum } from '../enums/permission.enum'; @Injectable() export class UsersService { @@ -42,6 +45,7 @@ export class UsersService { @InjectEntityManager() private readonly entityManager: EntityManager, private readonly paginator: Paginator, + private readonly roleFactory: RoleFactory, ) {} async create(createUserDto: CreateUserDto): Promise { @@ -272,4 +276,20 @@ export class UsersService { .where('role.code = :code', { code: RoleEnum.USER }) .andWhere('users.status = :status', { status: UserStatusEnum.ACTIVE }); } + + checkRoleManagedByPermission( + usersRole: string, + permissions: PermissionEnum[], + ): void { + const role = this.roleFactory.getInstance(usersRole); + const managedBy = role.managedBy(); + if (!permissions.includes(managedBy)) { + throw new ForbiddenException(`You have no permission for this action`); + } + } + + async removeUser(userId: string): Promise { + const user = await this.findEntityById(userId); + await this.userRepository.remove(user); + } } diff --git a/backend/src/users/util/pagination/user-pagination.config.ts b/backend/src/users/util/pagination/user-pagination.config.ts index 2c70fad9..79c03d76 100644 --- a/backend/src/users/util/pagination/user-pagination.config.ts +++ b/backend/src/users/util/pagination/user-pagination.config.ts @@ -4,5 +4,5 @@ import { User } from 'src/users/entities/user.entity'; export const USER_PAGINATION_CONFIG: PaginateConfig = { sortableColumns: ['name'], searchableColumns: ['name'], - defaultSortBy: [['name', 'DESC']], + defaultSortBy: [['name', 'ASC']], }; diff --git a/docker-compose.yaml b/docker-compose.yaml index 1509ef83..eb1cb9b9 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -21,6 +21,8 @@ services: dockerfile: Dockerfile container_name: worker restart: unless-stopped + ports: + - "3002:3002" networks: - cc diff --git a/frontend/messages/de.json b/frontend/messages/de.json index 18830c42..e68e972d 100644 --- a/frontend/messages/de.json +++ b/frontend/messages/de.json @@ -14,7 +14,7 @@ "drawer": { "compare": "Vergleichen", "latestRevisions": "Latest Revisions", - "tableOfContents": "Content", + "tableOfContents": "Contents", "latest": "Latest" } }, @@ -32,7 +32,8 @@ "voted": "Voted", "rationale": "Rationale", "actionTitle": "Show more", - "notAvailable": "Not Available" + "notAvailable": "Not Available", + "available": "Available" }, "MyActions": { "myVotesTab": "My Votes", @@ -130,6 +131,34 @@ "error": "Error changing user status" } }, + "deleteUser": { + "headline": "Delete user", + "description": "Are you sure you want to delete this user?", + "fields": { + "confirm": { + "label": "Please confirm the action by typing expected below", + "placeholder": "Write DELETE" + } + }, + "alerts": { + "success": "User deleted successfully", + "error": "Error deleting user" + } + }, + "switchUserStatus": { + "headline": "Change status", + "description": "Are you sure you want to change the status?", + "fields": { + "confirm": { + "label": "Please confirm the action by typing expected below", + "placeholder": "Write CONFIRM" + } + }, + "alerts": { + "success": "Status changed successfully", + "error": "Error changing status user" + } + }, "addMember": { "headline": "Add member", "fields": { @@ -196,6 +225,8 @@ "previewRationale": { "headline": "Rationale", "description": "Please update rationale for your vote on specific governance action.", + "noRationaleUrl": "A rationale has not been provided for this vote", + "rationaleLink": "Rationale link", "governanceActionCategory": "Governance Action Category", "governanceActionId": "Governance Action ID", "voted": "Voted", @@ -289,5 +320,15 @@ "sessionExists": "Session already exists. Please try again.", "pagination": "Error loading more data" } + }, + "UsersList": { + "resendInv": "Resend Invitation", + "makeInactive": "Make Inactive", + "makeActive": "Make Active", + "deleteUser": "Delete User", + "resendAlerts": { + "success": "Email successfully resent", + "error": "Error resending email" + } } } diff --git a/frontend/messages/en.json b/frontend/messages/en.json index fbae8799..053776d0 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -14,7 +14,7 @@ "drawer": { "compare": "Compare", "latestRevisions": "Latest Revisions", - "tableOfContents": "Content", + "tableOfContents": "Contents", "latest": "Latest" } }, @@ -32,7 +32,8 @@ "voted": "Voted", "rationale": "Rationale", "actionTitle": "Show more", - "notAvailable": "Not Available" + "notAvailable": "Not Available", + "available": "Available" }, "MyActions": { "myVotesTab": "My Votes", @@ -130,6 +131,34 @@ "error": "Error changing user status" } }, + "deleteUser": { + "headline": "Delete user", + "description": "Are you sure you want to delete this user?", + "fields": { + "confirm": { + "label": "Please confirm the action by typing expected below", + "placeholder": "Write DELETE" + } + }, + "alerts": { + "success": "User deleted successfully", + "error": "Error deleting user" + } + }, + "switchUserStatus": { + "headline": "Change status", + "description": "Are you sure you want to change the status?", + "fields": { + "confirm": { + "label": "Please confirm the action by typing expected below", + "placeholder": "Write CONFIRM" + } + }, + "alerts": { + "success": "Status changed successfully", + "error": "Error changing status user" + } + }, "addMember": { "headline": "Add member", "fields": { @@ -196,6 +225,8 @@ "previewRationale": { "headline": "Rationale", "description": "Please update rationale for your vote on specific governance action.", + "noRationaleUrl": "A rationale has not been provided for this vote", + "rationaleLink": "Rationale link", "governanceActionCategory": "Governance Action Category", "governanceActionId": "Governance Action ID", "voted": "Voted", @@ -289,5 +320,15 @@ "sessionExists": "Session already exists. Please try again.", "pagination": "Error loading more data" } + }, + "UsersList": { + "resendInv": "Resend Invitation", + "makeInactive": "Make Inactive", + "makeActive": "Make Active", + "deleteUser": "Delete User", + "resendAlerts": { + "success": "Email successfully resent", + "error": "Error resending email" + } } } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 31b71ec6..cb3e8956 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,10 +8,10 @@ "name": "frontend", "version": "0.1.0", "dependencies": { - "@emotion/react": "^11.11.3", - "@emotion/styled": "^11.11.0", - "@mui/icons-material": "^5.15.20", - "@mui/material": "^5.15.7", + "@emotion/react": "^11.13.3", + "@emotion/styled": "^11.13.0", + "@mui/icons-material": "^5.16.7", + "@mui/material": "^5.16.7", "@mui/material-nextjs": "^5.15.11", "@sentry/nextjs": "^7.100.1", "@usersnap/browser": "^0.0.5", @@ -1825,14 +1825,14 @@ "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" }, "node_modules/@emotion/react": { - "version": "11.13.0", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.0.tgz", - "integrity": "sha512-WkL+bw1REC2VNV1goQyfxjx1GYJkcc23CRQkXX+vZNLINyfI7o+uUn/rTGPt/xJ3bJHd5GcljgnxHf4wRw5VWQ==", + "version": "11.13.3", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.3.tgz", + "integrity": "sha512-lIsdU6JNrmYfJ5EbUCf4xW1ovy5wKQ2CkPRM4xogziOxH1nXxBSjpC9YqbFAP7circxMfYp+6x676BqWcEiixg==", "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.12.0", "@emotion/cache": "^11.13.0", - "@emotion/serialize": "^1.3.0", + "@emotion/serialize": "^1.3.1", "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", "@emotion/utils": "^1.4.0", "@emotion/weak-memoize": "^0.4.0", @@ -1848,14 +1848,14 @@ } }, "node_modules/@emotion/serialize": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.0.tgz", - "integrity": "sha512-jACuBa9SlYajnpIVXB+XOXnfJHyckDfe6fOpORIM6yhBDlqGuExvDdZYHDQGoDf3bZXGv7tNr+LpLjJqiEQ6EA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.2.tgz", + "integrity": "sha512-grVnMvVPK9yUVE6rkKfAJlYZgo0cu3l9iMC77V7DW6E1DUIrU68pSEXRmFZFOFB1QFo57TncmOcvcbMDWsL4yA==", "dependencies": { "@emotion/hash": "^0.9.2", "@emotion/memoize": "^0.9.0", - "@emotion/unitless": "^0.9.0", - "@emotion/utils": "^1.4.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.1", "csstype": "^3.0.2" } }, @@ -1887,9 +1887,9 @@ } }, "node_modules/@emotion/unitless": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.9.0.tgz", - "integrity": "sha512-TP6GgNZtmtFaFcsOgExdnfxLLpRDla4Q66tnenA9CktvVSdNKDvMVuUah4QvWPIpNjrWsGg3qeGo9a43QooGZQ==" + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==" }, "node_modules/@emotion/use-insertion-effect-with-fallbacks": { "version": "1.1.0", @@ -1900,9 +1900,9 @@ } }, "node_modules/@emotion/utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.0.tgz", - "integrity": "sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ==" + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.1.tgz", + "integrity": "sha512-BymCXzCG3r72VKJxaYVwOXATqXIZ85cuvg0YOUDxMGNrKc1DJRZk8MgV5wyXRyEayIMd4FuXJIUgTBXvDNW5cA==" }, "node_modules/@emotion/weak-memoize": { "version": "0.4.0", diff --git a/frontend/package.json b/frontend/package.json index 4884da1e..298afe58 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,10 +10,10 @@ "test": "jest" }, "dependencies": { - "@emotion/react": "^11.11.3", - "@emotion/styled": "^11.11.0", - "@mui/icons-material": "^5.15.20", - "@mui/material": "^5.15.7", + "@emotion/react": "^11.13.3", + "@emotion/styled": "^11.13.0", + "@mui/icons-material": "^5.16.7", + "@mui/material": "^5.16.7", "@mui/material-nextjs": "^5.15.11", "@sentry/nextjs": "^7.100.1", "@usersnap/browser": "^0.0.5", diff --git a/frontend/public/icons/MenuIcon.svg b/frontend/public/icons/MenuIcon.svg index 3996c35b..06976356 100644 --- a/frontend/public/icons/MenuIcon.svg +++ b/frontend/public/icons/MenuIcon.svg @@ -1,6 +1,3 @@ - - - - - + + diff --git a/frontend/public/images/DocSearch.png b/frontend/public/images/DocSearch.png new file mode 100644 index 0000000000000000000000000000000000000000..997b2ca3becec7ee389ff4111d470346a48bc300 GIT binary patch literal 520 zcmV+j0{8uiP)*IX^g4A!t&j0l^P=0{KDm0+JW-goqy`F90bi(m@9u_k*~Kkeu^o_Y6eA z=iC|5Fok{E^X}};?XCgN9l~a8w7Me{cn=6siPsEudZ$(&3aSz`+TAfC1$RSXmiApF z1%kNU`Q*&WIkq{=W={&Cr{pPpNP>c8D@&P^TFn$<*r)G!Uy7hMmCaiT-UJ?~LUI&A z6_TR~tR!LW`J@DYNEisc!~F~JfT^5Nb9Oh|B6y+ddDs;KlfhUI^njf3KK$zfHc#T;Y^P09Io92}XsG$btjp?IOvxMb<%P{YBB*{)dkeK)8 zD%smMd#NIqyPF_`h54|q$E>-Oy(kFuh;0b)>T)kuQC`yqe8C{J%*`;QiycB;^O})B zmO6)GfndFSi+90AKtqj|OiJT>AwckbBs6UofZtx@+S&(&;7Aj5=?-Q?;1%4FsgW{A za=2GGfh{<7>Dt&zq0N(|n}F*C<^~TlM{prQz$dkQ_xTf^8GZn%QtKta+_Pu^0000< KMNUMnLSTXzK;pyz literal 0 HcmV?d00001 diff --git a/frontend/public/images/HeroImage.png b/frontend/public/images/HeroImage.png index af7b88e0f466fb76e21816123196716319e26654..8a89a0e73fea1ab5a39665399ca5f9047534470c 100644 GIT binary patch literal 119634 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

k$bm0F8&lGU(|BXMy-^rMh--` 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 CBCT)$ literal 205801 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 h$o3ij=8EDx+qo@e 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 diff --git a/frontend/public/images/Menu.png b/frontend/public/images/Menu.png new file mode 100644 index 0000000000000000000000000000000000000000..1fd408bad0a47eb9b15d2274df62f27f283b252d GIT binary patch literal 174 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjoCO|{#S9GG!XV7ZFl!D-1!HlL zyA#8@b22Z19F}xPUq=Rpjs4tz5?O(KXHOT$kP61PmlpCeDDbcxX!l%^%Dya}J?AEi zfy#nt=AXuAm!DkC{-XLJ&!p~klM^m)4ZW!tx1Q0upRees=tS9Y7ycP(?V>DutdtCa P#xZ!h`njxgN@xNAD@`$| literal 0 HcmV?d00001 diff --git a/frontend/src/app/[locale]/interim-constitution/layout.tsx b/frontend/src/app/[locale]/interim-constitution/layout.tsx new file mode 100644 index 00000000..740fcaaf --- /dev/null +++ b/frontend/src/app/[locale]/interim-constitution/layout.tsx @@ -0,0 +1,10 @@ +import { customPalette } from "@/constants"; +import { Box } from "@mui/material"; + +export default function ConstitutionLayout({ + children +}: { + children: React.ReactNode; +}) { + return {children}; +} diff --git a/frontend/src/components/atoms/Chip/Chip.tsx b/frontend/src/components/atoms/Chip/Chip.tsx index bc597598..fc01ee0e 100644 --- a/frontend/src/components/atoms/Chip/Chip.tsx +++ b/frontend/src/components/atoms/Chip/Chip.tsx @@ -12,7 +12,7 @@ export const Chip = ({ label, showCloseButton = false, onClick, - dataTestId, + dataTestId }: ChipProps) => ( {label} @@ -31,7 +32,7 @@ export const Chip = ({ sx={{ padding: 0 }} data-testid={`${dataTestId}--button`} > - + )} diff --git a/frontend/src/components/atoms/Link.tsx b/frontend/src/components/atoms/Link.tsx index c20a53ec..2d9d8ed7 100644 --- a/frontend/src/components/atoms/Link.tsx +++ b/frontend/src/components/atoms/Link.tsx @@ -1,7 +1,8 @@ -import { FC } from "react"; -import NextLink from "next/link"; import MUILink from "@mui/material/Link"; +import NextLink from "next/link"; +import { FC } from "react"; +import { customPalette } from "@/constants"; import { Typography } from "@mui/material"; import { usePathname } from "next/navigation"; @@ -20,7 +21,7 @@ export const Link: FC = (props) => { const fontSize = { small: 14, - big: 22, + big: 22 }[size]; return ( @@ -33,8 +34,14 @@ export const Link: FC = (props) => { diff --git a/frontend/src/components/atoms/modal/ModalActions.tsx b/frontend/src/components/atoms/modal/ModalActions.tsx index 43130eaf..e1a0b8a9 100644 --- a/frontend/src/components/atoms/modal/ModalActions.tsx +++ b/frontend/src/components/atoms/modal/ModalActions.tsx @@ -1,8 +1,8 @@ -import { Box, CircularProgress } from "@mui/material"; import { Button } from "@atoms"; -import { useTranslations } from "next-intl"; import { useModal } from "@context"; +import { Box, CircularProgress } from "@mui/material"; import { callAll } from "@utils"; +import { useTranslations } from "next-intl"; interface Props { onClose?: () => void; @@ -13,7 +13,7 @@ interface Props { export const ModalActions = ({ onClose, isSubmitting, - dataTestId = "modal-action", + dataTestId = "modal-action" }: Props) => { const t = useTranslations("Modals"); const { closeModal } = useModal(); @@ -22,7 +22,7 @@ export const ModalActions = ({ diff --git a/frontend/src/components/molecules/GovernanceActionsFilters.tsx b/frontend/src/components/molecules/GovernanceActionsFilters.tsx index 4f8d19df..45a41c8b 100644 --- a/frontend/src/components/molecules/GovernanceActionsFilters.tsx +++ b/frontend/src/components/molecules/GovernanceActionsFilters.tsx @@ -1,11 +1,11 @@ -import { Dispatch, SetStateAction, useCallback } from "react"; import { Box, Checkbox, FormControlLabel, FormLabel, - Typography, + Typography } from "@mui/material"; +import { Dispatch, SetStateAction, useCallback } from "react"; import { useTranslations } from "next-intl"; import { FilterItems } from "./types"; @@ -19,13 +19,14 @@ interface Props { export const GovernanceActionsFilters = ({ chosenFilters, setChosenFilters, - filterOptions, + filterOptions }: Props) => { const t = useTranslations(); const handleFilterChange = useCallback( (e: React.ChangeEvent, key: string) => { const { name, checked } = e.target; + setChosenFilters((prevFilters) => { const newFilters = { ...prevFilters }; if (checked) { @@ -43,6 +44,7 @@ export const GovernanceActionsFilters = ({ return ( {filter.title} diff --git a/frontend/src/components/organisms/Constitution/Constitution.tsx b/frontend/src/components/organisms/Constitution/Constitution.tsx index 879d5538..69662e39 100644 --- a/frontend/src/components/organisms/Constitution/Constitution.tsx +++ b/frontend/src/components/organisms/Constitution/Constitution.tsx @@ -1,9 +1,16 @@ "use client"; -import { Card } from "@molecules"; +import { ContentWrapper, Typography } from "@/components/atoms"; +import { customPalette, IMAGES } from "@consts"; +import { useScreenDimension } from "@hooks"; import { Box, Grid, IconButton } from "@mui/material"; +import { useTranslations } from "next-intl"; import { MDXRemote } from "next-mdx-remote"; import { useEffect, useState } from "react"; +import { Footer } from "../Footer"; +import { DrawerMobile } from "../TopNavigation"; +import { ConstitutionProps } from "../types"; +import { ConstitutionSidebar } from "./ConstitutionSidebar"; import { Code, Heading1, @@ -12,16 +19,9 @@ import { ListItem, NavDrawerDesktop, Paragraph, - TABLE_OF_CONTENTS_WRAPPER_STYLE_PROPS, + TABLE_OF_CONTENTS_WRAPPER_STYLE_PROPS } from "./MDXComponents"; -import { ConstitutionProps } from "../types"; -import { useTranslations } from "next-intl"; -import { Footer } from "../Footer"; -import { customPalette, IMAGES } from "@consts"; -import { ContentWrapper, Typography } from "@/components/atoms"; -import { useScreenDimension } from "@hooks"; -import { DrawerMobile } from "../TopNavigation"; -import { ConstitutionSidebar } from "./ConstitutionSidebar"; +import { TocAccordion } from "./TOCAccordion"; import TOCLink from "./TOCLink"; export function Constitution({ constitution, metadata }: ConstitutionProps) { @@ -57,7 +57,7 @@ export function Constitution({ constitution, metadata }: ConstitutionProps) { setIsOpen(!isOpen)} - top={{ xxs: 0, md: 90 }} + top={{ xxs: 0, md: 85 }} left={0} > @@ -69,12 +69,25 @@ export function Constitution({ constitution, metadata }: ConstitutionProps) { p: Paragraph, li: ListItem, code: Code, + ol: (props) => { + //make sure we render ol from toc with TocAccordion otherwise return default + if (props.className && props.className.includes("toc-level")) { + return ; + } + return

    ; + }, a: (props) => { if (props.href && props.href.startsWith("#")) { - return ; + return ( + + ); } return ; - }, + } }; return ( @@ -82,10 +95,18 @@ export function Constitution({ constitution, metadata }: ConstitutionProps) { data-testid="constitution-page-wrapper" container position="relative" - justifyContent={{ xxs: "flex-start", md: "flex-end" }} + justifyContent={{ xxs: "flex-start" }} flex={1} > - + {/* fake elemnt to push content to the right since tos is fixed on left */} + +   + + @@ -93,7 +114,9 @@ export function Constitution({ constitution, metadata }: ConstitutionProps) { display="flex" justifyContent="space-between" alignItems="center" - pb={4} + position={{ xxs: "sticky", md: "static" }} + top="72px" + bgcolor={customPalette.bgWhite} > {t("title")} - + - + - + -