From b8ce112dc3b476df9bd5fec36d2b5e914fecbbbb Mon Sep 17 00:00:00 2001 From: Brad Bahls Date: Sat, 23 Dec 2023 08:52:07 -0700 Subject: [PATCH 01/42] added new custom service with slack integration helper functions; added axios package; added notifications for card create, delete, and update (move); added notifications for comment create --- package.json | 1 + server/api/controllers/cards/create.js | 7 ++ server/api/controllers/cards/delete.js | 7 ++ server/api/controllers/cards/update.js | 14 ++++ .../api/controllers/comment-actions/create.js | 8 ++ server/api/services/custom.js | 73 +++++++++++++++++++ 6 files changed, 110 insertions(+) create mode 100644 server/api/services/custom.js diff --git a/package.json b/package.json index 9616e440..d329db8c 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ } }, "dependencies": { + "axios": "^1.6.2", "concurrently": "^8.2.2", "husky": "^8.0.3", "lint-staged": "^15.1.0" diff --git a/server/api/controllers/cards/create.js b/server/api/controllers/cards/create.js index ab0c444e..ead92758 100755 --- a/server/api/controllers/cards/create.js +++ b/server/api/controllers/cards/create.js @@ -1,4 +1,5 @@ const moment = require('moment'); +const services = require('../../services/custom'); const Errors = { NOT_ENOUGH_RIGHTS: { @@ -108,6 +109,12 @@ module.exports = { }) .intercept('positionMustBeInValues', () => Errors.POSITION_MUST_BE_PRESENT); + const cardUrl = services.buildCardUrl(card); + const messageText = cardUrl + ' was created by ' + currentUser.username + ' in *' + list.name + '*'; + services.sendSlackMessage(messageText) + .then(() => { console.log('Slack message sent successfully.'); }) + .catch((error) => { console.error('Failed to send Slack message:', error.message); }); + return { item: card, }; diff --git a/server/api/controllers/cards/delete.js b/server/api/controllers/cards/delete.js index e2b6d00b..865cd2e9 100755 --- a/server/api/controllers/cards/delete.js +++ b/server/api/controllers/cards/delete.js @@ -1,3 +1,5 @@ +const services = require('../../services/custom'); + const Errors = { NOT_ENOUGH_RIGHTS: { notEnoughRights: 'Not enough rights', @@ -54,6 +56,11 @@ module.exports = { throw Errors.CARD_NOT_FOUND; } + const messageText = '*' + card.name + '* was deleted by ' + currentUser.username; + services.sendSlackMessage(messageText) + .then(() => { console.log('Slack message sent successfully.'); }) + .catch((error) => { console.error('Failed to send Slack message:', error.message); }); + return { item: card, }; diff --git a/server/api/controllers/cards/update.js b/server/api/controllers/cards/update.js index 8ee37523..df69f578 100755 --- a/server/api/controllers/cards/update.js +++ b/server/api/controllers/cards/update.js @@ -1,4 +1,5 @@ const moment = require('moment'); +const services = require('../../services/custom'); const Errors = { NOT_ENOUGH_RIGHTS: { @@ -175,6 +176,8 @@ module.exports = { 'isSubscribed', ]); + const cardPositionBefore = card.position; + card = await sails.helpers.cards.updateOne .with({ board, @@ -195,6 +198,17 @@ module.exports = { throw Errors.CARD_NOT_FOUND; } + const cardPositionAfter = card.position; + const cardMoved = cardPositionBefore !== cardPositionAfter; + + if (cardMoved) { + const cardUrl = services.buildCardUrl(card); + const messageText = cardUrl + ' was moved by ' + currentUser.username + ' to *' + nextList.name + '*'; + services.sendSlackMessage(messageText) + .then(() => { console.log('Slack message sent successfully.'); }) + .catch((error) => { console.error('Failed to send Slack message:', error.message); }); + } + return { item: card, }; diff --git a/server/api/controllers/comment-actions/create.js b/server/api/controllers/comment-actions/create.js index ddf4b991..7e5d97e8 100755 --- a/server/api/controllers/comment-actions/create.js +++ b/server/api/controllers/comment-actions/create.js @@ -1,3 +1,5 @@ +const services = require('../../services/custom'); + const Errors = { NOT_ENOUGH_RIGHTS: { notEnoughRights: 'Not enough rights', @@ -63,6 +65,12 @@ module.exports = { request: this.req, }); + const cardUrl = services.buildCardUrl(card); + const messageText = '*' + currentUser.username + '* commented on ' + cardUrl + ':\n>' + inputs.text; + services.sendSlackMessage(messageText) + .then(() => { console.log('Slack message sent successfully.'); }) + .catch((error) => { console.error('Failed to send Slack message:', error.message); }); + return { item: action, }; diff --git a/server/api/services/custom.js b/server/api/services/custom.js new file mode 100644 index 00000000..1166934a --- /dev/null +++ b/server/api/services/custom.js @@ -0,0 +1,73 @@ +const axios = require('axios'); +const slackPostUrl = 'https://slack.com/api/chat.postMessage'; +const channelId = 'C06B6F4R9RT'; + +const plankaProdUrl = 'https://kanban.glitchsecure.com'; +const plankaTestUrl = 'http://localhost:3000'; +const plankaTestWebhookUrl = 'https://hooks.slack.com/services/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'; +const slackAPIToken = process.env.SLACK_BOT_TOKEN; + +async function sendSlackMessage(messageText) { + if (!slackAPIToken) { + throw new Error('No Slack BOT token found'); + } + + console.log('Sending to Slack'); + + + const postData = { + blocks: [ { + type: 'section', + text: { + type: 'mrkdwn', + text: messageText, + }, + }] + }; + + try { + // Prod path + const config = { + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${slackAPIToken}`, + }, + }; + + axios.post(slackPostUrl, { ...postData, channel: channelId }, config) + .then(response => { + console.log('Slack response:', response.data); + }) + .catch(error => { + console.error('Error sending to Slack:', error.message); + }); + + + // Testing in dev environment (Brad) + /* + const response = await axios.post(plankaTestWebhookUrl, postData, { + headers: { + 'Content-Type': 'application/json' + } + }); + */ + + console.log('Slack response:', response.data); + return response.data; + } catch (error) { + console.error('Error sending to Slack:', error.message); + throw error; + } + } + + function buildCardUrl(card) { + const url = plankaProdUrl + '/cards/' + card.id; + const cardUrl = '<' + url + '|' + card.name + '>'; + console.log(cardUrl); + return cardUrl; + } + + module.exports = { + sendSlackMessage, + buildCardUrl + }; From 4d12fbf72d532d07f70d5a327fb73f1f58b7de5f Mon Sep 17 00:00:00 2001 From: Brad Bahls Date: Sat, 23 Dec 2023 08:58:22 -0700 Subject: [PATCH 02/42] removed test webhook url --- server/api/services/custom.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/api/services/custom.js b/server/api/services/custom.js index 1166934a..3e2dd9b9 100644 --- a/server/api/services/custom.js +++ b/server/api/services/custom.js @@ -4,7 +4,7 @@ const channelId = 'C06B6F4R9RT'; const plankaProdUrl = 'https://kanban.glitchsecure.com'; const plankaTestUrl = 'http://localhost:3000'; -const plankaTestWebhookUrl = 'https://hooks.slack.com/services/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'; +const plankaTestWebhookUrl = ''; const slackAPIToken = process.env.SLACK_BOT_TOKEN; async function sendSlackMessage(messageText) { From 22ffa779668afdae93cfaf7750338b2fd7b396a0 Mon Sep 17 00:00:00 2001 From: GlitchWitch Date: Sat, 23 Dec 2023 10:48:50 -0600 Subject: [PATCH 03/42] Replace plankaProdUrl with one set by environment. Remove hardcoded channel and unused variables. --- server/api/services/custom.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/server/api/services/custom.js b/server/api/services/custom.js index 3e2dd9b9..6f6c5d13 100644 --- a/server/api/services/custom.js +++ b/server/api/services/custom.js @@ -1,11 +1,8 @@ const axios = require('axios'); const slackPostUrl = 'https://slack.com/api/chat.postMessage'; -const channelId = 'C06B6F4R9RT'; - -const plankaProdUrl = 'https://kanban.glitchsecure.com'; -const plankaTestUrl = 'http://localhost:3000'; -const plankaTestWebhookUrl = ''; +const channelId = process.env.SLACK_CHANNEL_ID; const slackAPIToken = process.env.SLACK_BOT_TOKEN; +const plankaProdUrl = process.env.BASE_URL; async function sendSlackMessage(messageText) { if (!slackAPIToken) { From ddbf2c528d975477647b1227e72b0c3b1e886901 Mon Sep 17 00:00:00 2001 From: GlitchWitch Date: Sat, 23 Dec 2023 10:49:02 -0600 Subject: [PATCH 04/42] Add slack variables to docker-compose --- docker-compose.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 9d8fef1e..6fac280e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -46,6 +46,9 @@ services: # - OIDC_ADMIN_ROLES=admin # - OIDC_ROLES_ATTRIBUTE=groups # - OIDC_IGNORE_ROLES=true + + # - SLACK_BOT_TOKEN=xoxb-xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxx + # - SLACK_CHANNEL_ID=xxxxxxxxxx depends_on: - postgres From 719ba9fc9ce9ac082de5ebecc08d9b3bd30b152a Mon Sep 17 00:00:00 2001 From: GlitchWitch Date: Sat, 23 Dec 2023 10:52:15 -0600 Subject: [PATCH 05/42] Rename custom.js -> slack.js --- server/api/controllers/cards/create.js | 2 +- server/api/controllers/cards/delete.js | 2 +- server/api/controllers/cards/update.js | 2 +- server/api/controllers/comment-actions/create.js | 2 +- server/api/services/{custom.js => slack.js} | 0 5 files changed, 4 insertions(+), 4 deletions(-) rename server/api/services/{custom.js => slack.js} (100%) diff --git a/server/api/controllers/cards/create.js b/server/api/controllers/cards/create.js index ead92758..9acfc74c 100755 --- a/server/api/controllers/cards/create.js +++ b/server/api/controllers/cards/create.js @@ -1,5 +1,5 @@ const moment = require('moment'); -const services = require('../../services/custom'); +const services = require('../../services/slack'); const Errors = { NOT_ENOUGH_RIGHTS: { diff --git a/server/api/controllers/cards/delete.js b/server/api/controllers/cards/delete.js index 865cd2e9..32d45003 100755 --- a/server/api/controllers/cards/delete.js +++ b/server/api/controllers/cards/delete.js @@ -1,4 +1,4 @@ -const services = require('../../services/custom'); +const services = require('../../services/slack'); const Errors = { NOT_ENOUGH_RIGHTS: { diff --git a/server/api/controllers/cards/update.js b/server/api/controllers/cards/update.js index df69f578..4e3a8445 100755 --- a/server/api/controllers/cards/update.js +++ b/server/api/controllers/cards/update.js @@ -1,5 +1,5 @@ const moment = require('moment'); -const services = require('../../services/custom'); +const services = require('../../services/slack'); const Errors = { NOT_ENOUGH_RIGHTS: { diff --git a/server/api/controllers/comment-actions/create.js b/server/api/controllers/comment-actions/create.js index 7e5d97e8..950effd6 100755 --- a/server/api/controllers/comment-actions/create.js +++ b/server/api/controllers/comment-actions/create.js @@ -1,4 +1,4 @@ -const services = require('../../services/custom'); +const services = require('../../services/slack'); const Errors = { NOT_ENOUGH_RIGHTS: { diff --git a/server/api/services/custom.js b/server/api/services/slack.js similarity index 100% rename from server/api/services/custom.js rename to server/api/services/slack.js From f11fa8d50412bd204f87fbc3c14dd06f6237f1bf Mon Sep 17 00:00:00 2001 From: Brad Bahls Date: Thu, 28 Dec 2023 09:03:41 -0700 Subject: [PATCH 06/42] updated to use currentUser.name for messages --- server/api/controllers/cards/create.js | 2 +- server/api/controllers/cards/delete.js | 2 +- server/api/controllers/cards/update.js | 2 +- server/api/controllers/comment-actions/create.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/server/api/controllers/cards/create.js b/server/api/controllers/cards/create.js index 9acfc74c..d8580581 100755 --- a/server/api/controllers/cards/create.js +++ b/server/api/controllers/cards/create.js @@ -110,7 +110,7 @@ module.exports = { .intercept('positionMustBeInValues', () => Errors.POSITION_MUST_BE_PRESENT); const cardUrl = services.buildCardUrl(card); - const messageText = cardUrl + ' was created by ' + currentUser.username + ' in *' + list.name + '*'; + const messageText = cardUrl + ' was created by ' + currentUser.name + ' in *' + list.name + '*'; services.sendSlackMessage(messageText) .then(() => { console.log('Slack message sent successfully.'); }) .catch((error) => { console.error('Failed to send Slack message:', error.message); }); diff --git a/server/api/controllers/cards/delete.js b/server/api/controllers/cards/delete.js index 32d45003..84d188d0 100755 --- a/server/api/controllers/cards/delete.js +++ b/server/api/controllers/cards/delete.js @@ -56,7 +56,7 @@ module.exports = { throw Errors.CARD_NOT_FOUND; } - const messageText = '*' + card.name + '* was deleted by ' + currentUser.username; + const messageText = '*' + card.name + '* was deleted by ' + currentUser.name; services.sendSlackMessage(messageText) .then(() => { console.log('Slack message sent successfully.'); }) .catch((error) => { console.error('Failed to send Slack message:', error.message); }); diff --git a/server/api/controllers/cards/update.js b/server/api/controllers/cards/update.js index 4e3a8445..2c0a2c29 100755 --- a/server/api/controllers/cards/update.js +++ b/server/api/controllers/cards/update.js @@ -203,7 +203,7 @@ module.exports = { if (cardMoved) { const cardUrl = services.buildCardUrl(card); - const messageText = cardUrl + ' was moved by ' + currentUser.username + ' to *' + nextList.name + '*'; + const messageText = cardUrl + ' was moved by ' + currentUser.name + ' to *' + nextList.name + '*'; services.sendSlackMessage(messageText) .then(() => { console.log('Slack message sent successfully.'); }) .catch((error) => { console.error('Failed to send Slack message:', error.message); }); diff --git a/server/api/controllers/comment-actions/create.js b/server/api/controllers/comment-actions/create.js index 950effd6..81bc420d 100755 --- a/server/api/controllers/comment-actions/create.js +++ b/server/api/controllers/comment-actions/create.js @@ -66,7 +66,7 @@ module.exports = { }); const cardUrl = services.buildCardUrl(card); - const messageText = '*' + currentUser.username + '* commented on ' + cardUrl + ':\n>' + inputs.text; + const messageText = '*' + currentUser.name + '* commented on ' + cardUrl + ':\n>' + inputs.text; services.sendSlackMessage(messageText) .then(() => { console.log('Slack message sent successfully.'); }) .catch((error) => { console.error('Failed to send Slack message:', error.message); }); From 75e642cd73a249eadb49442fe96902ff2f8ac2c0 Mon Sep 17 00:00:00 2001 From: GlitchWitch Date: Thu, 28 Dec 2023 12:01:38 -0600 Subject: [PATCH 07/42] Remove unused code and comments --- server/api/services/slack.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/server/api/services/slack.js b/server/api/services/slack.js index 6f6c5d13..c06aa5fe 100644 --- a/server/api/services/slack.js +++ b/server/api/services/slack.js @@ -11,7 +11,6 @@ async function sendSlackMessage(messageText) { console.log('Sending to Slack'); - const postData = { blocks: [ { type: 'section', @@ -23,7 +22,6 @@ async function sendSlackMessage(messageText) { }; try { - // Prod path const config = { headers: { 'Content-Type': 'application/json', @@ -39,16 +37,6 @@ async function sendSlackMessage(messageText) { console.error('Error sending to Slack:', error.message); }); - - // Testing in dev environment (Brad) - /* - const response = await axios.post(plankaTestWebhookUrl, postData, { - headers: { - 'Content-Type': 'application/json' - } - }); - */ - console.log('Slack response:', response.data); return response.data; } catch (error) { From f0b2de8c400bc9bcd943a8ad7ae6ee7366a1ef41 Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Wed, 3 Jan 2024 13:59:14 +0500 Subject: [PATCH 08/42] chore: Bump sharp version --- server/package-lock.json | 190 +++++++++++++++++++-------------------- server/package.json | 2 +- 2 files changed, 96 insertions(+), 96 deletions(-) diff --git a/server/package-lock.json b/server/package-lock.json index 99e0e2a7..1b07cb37 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -21,7 +21,7 @@ "sails-hook-orm": "^4.0.2", "sails-hook-sockets": "^2.0.4", "sails-postgresql-redacted": "^1.0.2-9", - "sharp": "^0.33.0", + "sharp": "^0.33.1", "stream-to-array": "^2.3.0", "uuid": "^9.0.1", "validator": "^13.11.0", @@ -167,9 +167,9 @@ "dev": true }, "node_modules/@img/sharp-darwin-arm64": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.0.tgz", - "integrity": "sha512-070tEheekI1LJWTGPC9WlQEa5UoKTXzzlORBHMX4TbfUxMiL336YHR8vBEUNsjse0RJCX8dZ4ZXwT595aEF1ug==", + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.1.tgz", + "integrity": "sha512-esr2BZ1x0bo+wl7Gx2hjssYhjrhUsD88VQulI0FrG8/otRQUOxLWHMBd1Y1qo2Gfg2KUvXNpT0ASnV9BzJCexw==", "cpu": [ "arm64" ], @@ -192,9 +192,9 @@ } }, "node_modules/@img/sharp-darwin-x64": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.0.tgz", - "integrity": "sha512-pu/nvn152F3qbPeUkr+4e9zVvEhD3jhwzF473veQfMPkOYo9aoWXSfdZH/E6F+nYC3qvFjbxbvdDbUtEbghLqw==", + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.1.tgz", + "integrity": "sha512-YrnuB3bXuWdG+hJlXtq7C73lF8ampkhU3tMxg5Hh+E7ikxbUVOU9nlNtVTloDXz6pRHt2y2oKJq7DY/yt+UXYw==", "cpu": [ "x64" ], @@ -385,9 +385,9 @@ } }, "node_modules/@img/sharp-linux-arm": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.0.tgz", - "integrity": "sha512-4horD3wMFd5a0ddbDY8/dXU9CaOgHjEHALAddXgafoR5oWq5s8X61PDgsSeh4Qupsdo6ycfPPSSNBrfVQnwwrg==", + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.1.tgz", + "integrity": "sha512-Ii4X1vnzzI4j0+cucsrYA5ctrzU9ciXERfJR633S2r39CiD8npqH2GMj63uFZRCFt3E687IenAdbwIpQOJ5BNA==", "cpu": [ "arm" ], @@ -410,9 +410,9 @@ } }, "node_modules/@img/sharp-linux-arm64": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.0.tgz", - "integrity": "sha512-dcomVSrtgF70SyOr8RCOCQ8XGVThXwe71A1d8MGA+mXEVRJ/J6/TrCbBEJh9ddcEIIsrnrkolaEvYSHqVhswQw==", + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.1.tgz", + "integrity": "sha512-59B5GRO2d5N3tIfeGHAbJps7cLpuWEQv/8ySd9109ohQ3kzyCACENkFVAnGPX00HwPTQcaBNF7HQYEfZyZUFfw==", "cpu": [ "arm64" ], @@ -435,9 +435,9 @@ } }, "node_modules/@img/sharp-linux-s390x": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.0.tgz", - "integrity": "sha512-TiVJbx38J2rNVfA309ffSOB+3/7wOsZYQEOlKqOUdWD/nqkjNGrX+YQGz7nzcf5oy2lC+d37+w183iNXRZNngQ==", + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.1.tgz", + "integrity": "sha512-tRGrb2pHnFUXpOAj84orYNxHADBDIr0J7rrjwQrTNMQMWA4zy3StKmMvwsI7u3dEZcgwuMMooIIGWEWOjnmG8A==", "cpu": [ "s390x" ], @@ -460,9 +460,9 @@ } }, "node_modules/@img/sharp-linux-x64": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.0.tgz", - "integrity": "sha512-PaZM4Zi7/Ek71WgTdvR+KzTZpBqrQOFcPe7/8ZoPRlTYYRe43k6TWsf4GVH6XKRLMYeSp8J89RfAhBrSP4itNA==", + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.1.tgz", + "integrity": "sha512-4y8osC0cAc1TRpy02yn5omBeloZZwS62fPZ0WUAYQiLhSFSpWJfY/gMrzKzLcHB9ulUV6ExFiu2elMaixKDbeg==", "cpu": [ "x64" ], @@ -485,9 +485,9 @@ } }, "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.0.tgz", - "integrity": "sha512-1QLbbN0zt+32eVrg7bb1lwtvEaZwlhEsY1OrijroMkwAqlHqFj6R33Y47s2XUv7P6Ie1PwCxK/uFnNqMnkd5kg==", + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.1.tgz", + "integrity": "sha512-D3lV6clkqIKUizNS8K6pkuCKNGmWoKlBGh5p0sLO2jQERzbakhu4bVX1Gz+RS4vTZBprKlWaf+/Rdp3ni2jLfA==", "cpu": [ "arm64" ], @@ -510,9 +510,9 @@ } }, "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.0.tgz", - "integrity": "sha512-CecqgB/CnkvCWFhmfN9ZhPGMLXaEBXl4o7WtA6U3Ztrlh/s7FUKX4vNxpMSYLIrWuuzjiaYdfU3+Tdqh1xaHfw==", + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.1.tgz", + "integrity": "sha512-LOGKNu5w8uu1evVqUAUKTix2sQu1XDRIYbsi5Q0c/SrXhvJ4QyOx+GaajxmOg5PZSsSnCYPSmhjHHsRBx06/wQ==", "cpu": [ "x64" ], @@ -535,9 +535,9 @@ } }, "node_modules/@img/sharp-wasm32": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.0.tgz", - "integrity": "sha512-Hn4js32gUX9qkISlemZBUPuMs0k/xNJebUNl/L6djnU07B/HAA2KaxRVb3HvbU5fL242hLOcp0+tR+M8dvJUFw==", + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.1.tgz", + "integrity": "sha512-vWI/sA+0p+92DLkpAMb5T6I8dg4z2vzCUnp8yvxHlwBpzN8CIcO3xlSXrLltSvK6iMsVMNswAv+ub77rsf25lA==", "cpu": [ "wasm32" ], @@ -556,9 +556,9 @@ } }, "node_modules/@img/sharp-win32-ia32": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.0.tgz", - "integrity": "sha512-5HfcsCZi3l5nPRF2q3bllMVMDXBqEWI3Q8KQONfzl0TferFE5lnsIG0A1YrntMAGqvkzdW6y1Ci1A2uTvxhfzg==", + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.1.tgz", + "integrity": "sha512-/xhYkylsKL05R+NXGJc9xr2Tuw6WIVl2lubFJaFYfW4/MQ4J+dgjIo/T4qjNRizrqs/szF/lC9a5+updmY9jaQ==", "cpu": [ "ia32" ], @@ -577,9 +577,9 @@ } }, "node_modules/@img/sharp-win32-x64": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.0.tgz", - "integrity": "sha512-i3DtP/2ce1yKFj4OzOnOYltOEL/+dp4dc4dJXJBv6god1AFTcmkaA99H/7SwOmkCOBQkbVvA3lCGm3/5nDtf9Q==", + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.1.tgz", + "integrity": "sha512-XaM69X0n6kTEsp9tVYYLhXdg7Qj32vYJlAKRutxUsm1UlgQNx6BOhHwZPwukCGXBU2+tH87ip2eV1I/E8MQnZg==", "cpu": [ "x64" ], @@ -7269,9 +7269,9 @@ "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" }, "node_modules/sharp": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.0.tgz", - "integrity": "sha512-99DZKudjm/Rmz+M0/26t4DKpXyywAOJaayGS9boEn7FvgtG0RYBi46uPE2c+obcJRtA3AZa0QwJot63gJQ1F0Q==", + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.1.tgz", + "integrity": "sha512-iAYUnOdTqqZDb3QjMneBKINTllCJDZ3em6WaWy7NPECM4aHncvqHRm0v0bN9nqJxMiwamv5KIdauJ6lUzKDpTQ==", "hasInstallScript": true, "dependencies": { "color": "^4.2.3", @@ -7286,8 +7286,8 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.33.0", - "@img/sharp-darwin-x64": "0.33.0", + "@img/sharp-darwin-arm64": "0.33.1", + "@img/sharp-darwin-x64": "0.33.1", "@img/sharp-libvips-darwin-arm64": "1.0.0", "@img/sharp-libvips-darwin-x64": "1.0.0", "@img/sharp-libvips-linux-arm": "1.0.0", @@ -7296,15 +7296,15 @@ "@img/sharp-libvips-linux-x64": "1.0.0", "@img/sharp-libvips-linuxmusl-arm64": "1.0.0", "@img/sharp-libvips-linuxmusl-x64": "1.0.0", - "@img/sharp-linux-arm": "0.33.0", - "@img/sharp-linux-arm64": "0.33.0", - "@img/sharp-linux-s390x": "0.33.0", - "@img/sharp-linux-x64": "0.33.0", - "@img/sharp-linuxmusl-arm64": "0.33.0", - "@img/sharp-linuxmusl-x64": "0.33.0", - "@img/sharp-wasm32": "0.33.0", - "@img/sharp-win32-ia32": "0.33.0", - "@img/sharp-win32-x64": "0.33.0" + "@img/sharp-linux-arm": "0.33.1", + "@img/sharp-linux-arm64": "0.33.1", + "@img/sharp-linux-s390x": "0.33.1", + "@img/sharp-linux-x64": "0.33.1", + "@img/sharp-linuxmusl-arm64": "0.33.1", + "@img/sharp-linuxmusl-x64": "0.33.1", + "@img/sharp-wasm32": "0.33.1", + "@img/sharp-win32-ia32": "0.33.1", + "@img/sharp-win32-x64": "0.33.1" } }, "node_modules/sharp/node_modules/semver": { @@ -9094,18 +9094,18 @@ "dev": true }, "@img/sharp-darwin-arm64": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.0.tgz", - "integrity": "sha512-070tEheekI1LJWTGPC9WlQEa5UoKTXzzlORBHMX4TbfUxMiL336YHR8vBEUNsjse0RJCX8dZ4ZXwT595aEF1ug==", + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.1.tgz", + "integrity": "sha512-esr2BZ1x0bo+wl7Gx2hjssYhjrhUsD88VQulI0FrG8/otRQUOxLWHMBd1Y1qo2Gfg2KUvXNpT0ASnV9BzJCexw==", "optional": true, "requires": { "@img/sharp-libvips-darwin-arm64": "1.0.0" } }, "@img/sharp-darwin-x64": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.0.tgz", - "integrity": "sha512-pu/nvn152F3qbPeUkr+4e9zVvEhD3jhwzF473veQfMPkOYo9aoWXSfdZH/E6F+nYC3qvFjbxbvdDbUtEbghLqw==", + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.1.tgz", + "integrity": "sha512-YrnuB3bXuWdG+hJlXtq7C73lF8ampkhU3tMxg5Hh+E7ikxbUVOU9nlNtVTloDXz6pRHt2y2oKJq7DY/yt+UXYw==", "optional": true, "requires": { "@img/sharp-libvips-darwin-x64": "1.0.0" @@ -9160,78 +9160,78 @@ "optional": true }, "@img/sharp-linux-arm": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.0.tgz", - "integrity": "sha512-4horD3wMFd5a0ddbDY8/dXU9CaOgHjEHALAddXgafoR5oWq5s8X61PDgsSeh4Qupsdo6ycfPPSSNBrfVQnwwrg==", + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.1.tgz", + "integrity": "sha512-Ii4X1vnzzI4j0+cucsrYA5ctrzU9ciXERfJR633S2r39CiD8npqH2GMj63uFZRCFt3E687IenAdbwIpQOJ5BNA==", "optional": true, "requires": { "@img/sharp-libvips-linux-arm": "1.0.0" } }, "@img/sharp-linux-arm64": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.0.tgz", - "integrity": "sha512-dcomVSrtgF70SyOr8RCOCQ8XGVThXwe71A1d8MGA+mXEVRJ/J6/TrCbBEJh9ddcEIIsrnrkolaEvYSHqVhswQw==", + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.1.tgz", + "integrity": "sha512-59B5GRO2d5N3tIfeGHAbJps7cLpuWEQv/8ySd9109ohQ3kzyCACENkFVAnGPX00HwPTQcaBNF7HQYEfZyZUFfw==", "optional": true, "requires": { "@img/sharp-libvips-linux-arm64": "1.0.0" } }, "@img/sharp-linux-s390x": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.0.tgz", - "integrity": "sha512-TiVJbx38J2rNVfA309ffSOB+3/7wOsZYQEOlKqOUdWD/nqkjNGrX+YQGz7nzcf5oy2lC+d37+w183iNXRZNngQ==", + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.1.tgz", + "integrity": "sha512-tRGrb2pHnFUXpOAj84orYNxHADBDIr0J7rrjwQrTNMQMWA4zy3StKmMvwsI7u3dEZcgwuMMooIIGWEWOjnmG8A==", "optional": true, "requires": { "@img/sharp-libvips-linux-s390x": "1.0.0" } }, "@img/sharp-linux-x64": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.0.tgz", - "integrity": "sha512-PaZM4Zi7/Ek71WgTdvR+KzTZpBqrQOFcPe7/8ZoPRlTYYRe43k6TWsf4GVH6XKRLMYeSp8J89RfAhBrSP4itNA==", + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.1.tgz", + "integrity": "sha512-4y8osC0cAc1TRpy02yn5omBeloZZwS62fPZ0WUAYQiLhSFSpWJfY/gMrzKzLcHB9ulUV6ExFiu2elMaixKDbeg==", "optional": true, "requires": { "@img/sharp-libvips-linux-x64": "1.0.0" } }, "@img/sharp-linuxmusl-arm64": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.0.tgz", - "integrity": "sha512-1QLbbN0zt+32eVrg7bb1lwtvEaZwlhEsY1OrijroMkwAqlHqFj6R33Y47s2XUv7P6Ie1PwCxK/uFnNqMnkd5kg==", + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.1.tgz", + "integrity": "sha512-D3lV6clkqIKUizNS8K6pkuCKNGmWoKlBGh5p0sLO2jQERzbakhu4bVX1Gz+RS4vTZBprKlWaf+/Rdp3ni2jLfA==", "optional": true, "requires": { "@img/sharp-libvips-linuxmusl-arm64": "1.0.0" } }, "@img/sharp-linuxmusl-x64": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.0.tgz", - "integrity": "sha512-CecqgB/CnkvCWFhmfN9ZhPGMLXaEBXl4o7WtA6U3Ztrlh/s7FUKX4vNxpMSYLIrWuuzjiaYdfU3+Tdqh1xaHfw==", + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.1.tgz", + "integrity": "sha512-LOGKNu5w8uu1evVqUAUKTix2sQu1XDRIYbsi5Q0c/SrXhvJ4QyOx+GaajxmOg5PZSsSnCYPSmhjHHsRBx06/wQ==", "optional": true, "requires": { "@img/sharp-libvips-linuxmusl-x64": "1.0.0" } }, "@img/sharp-wasm32": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.0.tgz", - "integrity": "sha512-Hn4js32gUX9qkISlemZBUPuMs0k/xNJebUNl/L6djnU07B/HAA2KaxRVb3HvbU5fL242hLOcp0+tR+M8dvJUFw==", + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.1.tgz", + "integrity": "sha512-vWI/sA+0p+92DLkpAMb5T6I8dg4z2vzCUnp8yvxHlwBpzN8CIcO3xlSXrLltSvK6iMsVMNswAv+ub77rsf25lA==", "optional": true, "requires": { "@emnapi/runtime": "^0.44.0" } }, "@img/sharp-win32-ia32": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.0.tgz", - "integrity": "sha512-5HfcsCZi3l5nPRF2q3bllMVMDXBqEWI3Q8KQONfzl0TferFE5lnsIG0A1YrntMAGqvkzdW6y1Ci1A2uTvxhfzg==", + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.1.tgz", + "integrity": "sha512-/xhYkylsKL05R+NXGJc9xr2Tuw6WIVl2lubFJaFYfW4/MQ4J+dgjIo/T4qjNRizrqs/szF/lC9a5+updmY9jaQ==", "optional": true }, "@img/sharp-win32-x64": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.0.tgz", - "integrity": "sha512-i3DtP/2ce1yKFj4OzOnOYltOEL/+dp4dc4dJXJBv6god1AFTcmkaA99H/7SwOmkCOBQkbVvA3lCGm3/5nDtf9Q==", + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.1.tgz", + "integrity": "sha512-XaM69X0n6kTEsp9tVYYLhXdg7Qj32vYJlAKRutxUsm1UlgQNx6BOhHwZPwukCGXBU2+tH87ip2eV1I/E8MQnZg==", "optional": true }, "@isaacs/cliui": { @@ -14411,12 +14411,12 @@ "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" }, "sharp": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.0.tgz", - "integrity": "sha512-99DZKudjm/Rmz+M0/26t4DKpXyywAOJaayGS9boEn7FvgtG0RYBi46uPE2c+obcJRtA3AZa0QwJot63gJQ1F0Q==", + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.1.tgz", + "integrity": "sha512-iAYUnOdTqqZDb3QjMneBKINTllCJDZ3em6WaWy7NPECM4aHncvqHRm0v0bN9nqJxMiwamv5KIdauJ6lUzKDpTQ==", "requires": { - "@img/sharp-darwin-arm64": "0.33.0", - "@img/sharp-darwin-x64": "0.33.0", + "@img/sharp-darwin-arm64": "0.33.1", + "@img/sharp-darwin-x64": "0.33.1", "@img/sharp-libvips-darwin-arm64": "1.0.0", "@img/sharp-libvips-darwin-x64": "1.0.0", "@img/sharp-libvips-linux-arm": "1.0.0", @@ -14425,15 +14425,15 @@ "@img/sharp-libvips-linux-x64": "1.0.0", "@img/sharp-libvips-linuxmusl-arm64": "1.0.0", "@img/sharp-libvips-linuxmusl-x64": "1.0.0", - "@img/sharp-linux-arm": "0.33.0", - "@img/sharp-linux-arm64": "0.33.0", - "@img/sharp-linux-s390x": "0.33.0", - "@img/sharp-linux-x64": "0.33.0", - "@img/sharp-linuxmusl-arm64": "0.33.0", - "@img/sharp-linuxmusl-x64": "0.33.0", - "@img/sharp-wasm32": "0.33.0", - "@img/sharp-win32-ia32": "0.33.0", - "@img/sharp-win32-x64": "0.33.0", + "@img/sharp-linux-arm": "0.33.1", + "@img/sharp-linux-arm64": "0.33.1", + "@img/sharp-linux-s390x": "0.33.1", + "@img/sharp-linux-x64": "0.33.1", + "@img/sharp-linuxmusl-arm64": "0.33.1", + "@img/sharp-linuxmusl-x64": "0.33.1", + "@img/sharp-wasm32": "0.33.1", + "@img/sharp-win32-ia32": "0.33.1", + "@img/sharp-win32-x64": "0.33.1", "color": "^4.2.3", "detect-libc": "^2.0.2", "semver": "^7.5.4" diff --git a/server/package.json b/server/package.json index 5301c1fb..6a11147a 100644 --- a/server/package.json +++ b/server/package.json @@ -42,7 +42,7 @@ "sails-hook-orm": "^4.0.2", "sails-hook-sockets": "^2.0.4", "sails-postgresql-redacted": "^1.0.2-9", - "sharp": "^0.33.0", + "sharp": "^0.33.1", "stream-to-array": "^2.3.0", "uuid": "^9.0.1", "validator": "^13.11.0", From 1e78c7df8f150095f8eb6de442069f9e070f5c34 Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Thu, 18 Jan 2024 10:58:26 +0100 Subject: [PATCH 09/42] fix: Fix images becoming black and white when resizing Closes #574, closes #585 --- server/package-lock.json | 368 +++++++++++++++++++-------------------- server/package.json | 2 +- temp | 1 - 3 files changed, 185 insertions(+), 186 deletions(-) delete mode 100644 temp diff --git a/server/package-lock.json b/server/package-lock.json index 1b07cb37..05527a7f 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -21,7 +21,7 @@ "sails-hook-orm": "^4.0.2", "sails-hook-sockets": "^2.0.4", "sails-postgresql-redacted": "^1.0.2-9", - "sharp": "^0.33.1", + "sharp": "^0.33.2", "stream-to-array": "^2.3.0", "uuid": "^9.0.1", "validator": "^13.11.0", @@ -69,9 +69,9 @@ } }, "node_modules/@emnapi/runtime": { - "version": "0.44.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-0.44.0.tgz", - "integrity": "sha512-ZX/etZEZw8DR7zAB1eVQT40lNo0jeqpb6dCgOvctB6FIQ5PoXfMuNY8+ayQfu8tNQbAB8gQWSSJupR8NxeiZXw==", + "version": "0.45.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-0.45.0.tgz", + "integrity": "sha512-Txumi3td7J4A/xTTwlssKieHKTGl3j4A1tglBx72auZ49YK7ePY6XZricgIg9mnZT4xPfA+UPCUdnhRuEFDL+w==", "optional": true, "dependencies": { "tslib": "^2.4.0" @@ -167,9 +167,9 @@ "dev": true }, "node_modules/@img/sharp-darwin-arm64": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.1.tgz", - "integrity": "sha512-esr2BZ1x0bo+wl7Gx2hjssYhjrhUsD88VQulI0FrG8/otRQUOxLWHMBd1Y1qo2Gfg2KUvXNpT0ASnV9BzJCexw==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.2.tgz", + "integrity": "sha512-itHBs1rPmsmGF9p4qRe++CzCgd+kFYktnsoR1sbIAfsRMrJZau0Tt1AH9KVnufc2/tU02Gf6Ibujx+15qRE03w==", "cpu": [ "arm64" ], @@ -188,13 +188,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.0.0" + "@img/sharp-libvips-darwin-arm64": "1.0.1" } }, "node_modules/@img/sharp-darwin-x64": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.1.tgz", - "integrity": "sha512-YrnuB3bXuWdG+hJlXtq7C73lF8ampkhU3tMxg5Hh+E7ikxbUVOU9nlNtVTloDXz6pRHt2y2oKJq7DY/yt+UXYw==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.2.tgz", + "integrity": "sha512-/rK/69Rrp9x5kaWBjVN07KixZanRr+W1OiyKdXcbjQD6KbW+obaTeBBtLUAtbBsnlTTmWthw99xqoOS7SsySDg==", "cpu": [ "x64" ], @@ -213,13 +213,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.0.0" + "@img/sharp-libvips-darwin-x64": "1.0.1" } }, "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.0.tgz", - "integrity": "sha512-VzYd6OwnUR81sInf3alj1wiokY50DjsHz5bvfnsFpxs5tqQxESoHtJO6xyksDs3RIkyhMWq2FufXo6GNSU9BMw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.1.tgz", + "integrity": "sha512-kQyrSNd6lmBV7O0BUiyu/OEw9yeNGFbQhbxswS1i6rMDwBBSX+e+rPzu3S+MwAiGU3HdLze3PanQ4Xkfemgzcw==", "cpu": [ "arm64" ], @@ -238,9 +238,9 @@ } }, "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.0.tgz", - "integrity": "sha512-dD9OznTlHD6aovRswaPNEy8dKtSAmNo4++tO7uuR4o5VxbVAOoEQ1uSmN4iFAdQneTHws1lkTZeiXPrcCkh6IA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.1.tgz", + "integrity": "sha512-eVU/JYLPVjhhrd8Tk6gosl5pVlvsqiFlt50wotCvdkFGf+mDNBJxMh+bvav+Wt3EBnNZWq8Sp2I7XfSjm8siog==", "cpu": [ "x64" ], @@ -259,9 +259,9 @@ } }, "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.0.tgz", - "integrity": "sha512-VwgD2eEikDJUk09Mn9Dzi1OW2OJFRQK+XlBTkUNmAWPrtj8Ly0yq05DFgu1VCMx2/DqCGQVi5A1dM9hTmxf3uw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.1.tgz", + "integrity": "sha512-FtdMvR4R99FTsD53IA3LxYGghQ82t3yt0ZQ93WMZ2xV3dqrb0E8zq4VHaTOuLEAuA83oDawHV3fd+BsAPadHIQ==", "cpu": [ "arm" ], @@ -280,9 +280,9 @@ } }, "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.0.tgz", - "integrity": "sha512-xTYThiqEZEZc0PRU90yVtM3KE7lw1bKdnDQ9kCTHWbqWyHOe4NpPOtMGy27YnN51q0J5dqRrvicfPbALIOeAZA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.1.tgz", + "integrity": "sha512-bnGG+MJjdX70mAQcSLxgeJco11G+MxTz+ebxlz8Y3dxyeb3Nkl7LgLI0mXupoO+u1wRNx/iRj5yHtzA4sde1yA==", "cpu": [ "arm64" ], @@ -301,9 +301,9 @@ } }, "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.0.tgz", - "integrity": "sha512-o9E46WWBC6JsBlwU4QyU9578G77HBDT1NInd+aERfxeOPbk0qBZHgoDsQmA2v9TbqJRWzoBPx1aLOhprBMgPjw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.1.tgz", + "integrity": "sha512-3+rzfAR1YpMOeA2zZNp+aYEzGNWK4zF3+sdMxuCS3ey9HhDbJ66w6hDSHDMoap32DueFwhhs3vwooAB2MaK4XQ==", "cpu": [ "s390x" ], @@ -322,9 +322,9 @@ } }, "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.0.tgz", - "integrity": "sha512-naldaJy4hSVhWBgEjfdBY85CAa4UO+W1nx6a1sWStHZ7EUfNiuBTTN2KUYT5dH1+p/xij1t2QSXfCiFJoC5S/Q==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.1.tgz", + "integrity": "sha512-3NR1mxFsaSgMMzz1bAnnKbSAI+lHXVTqAHgc1bgzjHuXjo4hlscpUxc0vFSAPKI3yuzdzcZOkq7nDPrP2F8Jgw==", "cpu": [ "x64" ], @@ -343,9 +343,9 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.0.tgz", - "integrity": "sha512-OdorplCyvmSAPsoJLldtLh3nLxRrkAAAOHsGWGDYfN0kh730gifK+UZb3dWORRa6EusNqCTjfXV4GxvgJ/nPDQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.1.tgz", + "integrity": "sha512-5aBRcjHDG/T6jwC3Edl3lP8nl9U2Yo8+oTl5drd1dh9Z1EBfzUKAJFUDTDisDjUwc7N4AjnPGfCA3jl3hY8uDg==", "cpu": [ "arm64" ], @@ -364,9 +364,9 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.0.tgz", - "integrity": "sha512-FW8iK6rJrg+X2jKD0Ajhjv6y74lToIBEvkZhl42nZt563FfxkCYacrXZtd+q/sRQDypQLzY5WdLkVTbJoPyqNg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.1.tgz", + "integrity": "sha512-dcT7inI9DBFK6ovfeWRe3hG30h51cBAP5JXlZfx6pzc/Mnf9HFCQDLtYf4MCBjxaaTfjCCjkBxcy3XzOAo5txw==", "cpu": [ "x64" ], @@ -385,9 +385,9 @@ } }, "node_modules/@img/sharp-linux-arm": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.1.tgz", - "integrity": "sha512-Ii4X1vnzzI4j0+cucsrYA5ctrzU9ciXERfJR633S2r39CiD8npqH2GMj63uFZRCFt3E687IenAdbwIpQOJ5BNA==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.2.tgz", + "integrity": "sha512-Fndk/4Zq3vAc4G/qyfXASbS3HBZbKrlnKZLEJzPLrXoJuipFNNwTes71+Ki1hwYW5lch26niRYoZFAtZVf3EGA==", "cpu": [ "arm" ], @@ -406,13 +406,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.0.0" + "@img/sharp-libvips-linux-arm": "1.0.1" } }, "node_modules/@img/sharp-linux-arm64": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.1.tgz", - "integrity": "sha512-59B5GRO2d5N3tIfeGHAbJps7cLpuWEQv/8ySd9109ohQ3kzyCACENkFVAnGPX00HwPTQcaBNF7HQYEfZyZUFfw==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.2.tgz", + "integrity": "sha512-pz0NNo882vVfqJ0yNInuG9YH71smP4gRSdeL09ukC2YLE6ZyZePAlWKEHgAzJGTiOh8Qkaov6mMIMlEhmLdKew==", "cpu": [ "arm64" ], @@ -431,13 +431,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.0.0" + "@img/sharp-libvips-linux-arm64": "1.0.1" } }, "node_modules/@img/sharp-linux-s390x": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.1.tgz", - "integrity": "sha512-tRGrb2pHnFUXpOAj84orYNxHADBDIr0J7rrjwQrTNMQMWA4zy3StKmMvwsI7u3dEZcgwuMMooIIGWEWOjnmG8A==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.2.tgz", + "integrity": "sha512-MBoInDXDppMfhSzbMmOQtGfloVAflS2rP1qPcUIiITMi36Mm5YR7r0ASND99razjQUpHTzjrU1flO76hKvP5RA==", "cpu": [ "s390x" ], @@ -456,13 +456,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.0.0" + "@img/sharp-libvips-linux-s390x": "1.0.1" } }, "node_modules/@img/sharp-linux-x64": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.1.tgz", - "integrity": "sha512-4y8osC0cAc1TRpy02yn5omBeloZZwS62fPZ0WUAYQiLhSFSpWJfY/gMrzKzLcHB9ulUV6ExFiu2elMaixKDbeg==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.2.tgz", + "integrity": "sha512-xUT82H5IbXewKkeF5aiooajoO1tQV4PnKfS/OZtb5DDdxS/FCI/uXTVZ35GQ97RZXsycojz/AJ0asoz6p2/H/A==", "cpu": [ "x64" ], @@ -481,13 +481,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.0.0" + "@img/sharp-libvips-linux-x64": "1.0.1" } }, "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.1.tgz", - "integrity": "sha512-D3lV6clkqIKUizNS8K6pkuCKNGmWoKlBGh5p0sLO2jQERzbakhu4bVX1Gz+RS4vTZBprKlWaf+/Rdp3ni2jLfA==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.2.tgz", + "integrity": "sha512-F+0z8JCu/UnMzg8IYW1TMeiViIWBVg7IWP6nE0p5S5EPQxlLd76c8jYemG21X99UzFwgkRo5yz2DS+zbrnxZeA==", "cpu": [ "arm64" ], @@ -506,13 +506,13 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.0.0" + "@img/sharp-libvips-linuxmusl-arm64": "1.0.1" } }, "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.1.tgz", - "integrity": "sha512-LOGKNu5w8uu1evVqUAUKTix2sQu1XDRIYbsi5Q0c/SrXhvJ4QyOx+GaajxmOg5PZSsSnCYPSmhjHHsRBx06/wQ==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.2.tgz", + "integrity": "sha512-+ZLE3SQmSL+Fn1gmSaM8uFusW5Y3J9VOf+wMGNnTtJUMUxFhv+P4UPaYEYT8tqnyYVaOVGgMN/zsOxn9pSsO2A==", "cpu": [ "x64" ], @@ -531,19 +531,19 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.0.0" + "@img/sharp-libvips-linuxmusl-x64": "1.0.1" } }, "node_modules/@img/sharp-wasm32": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.1.tgz", - "integrity": "sha512-vWI/sA+0p+92DLkpAMb5T6I8dg4z2vzCUnp8yvxHlwBpzN8CIcO3xlSXrLltSvK6iMsVMNswAv+ub77rsf25lA==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.2.tgz", + "integrity": "sha512-fLbTaESVKuQcpm8ffgBD7jLb/CQLcATju/jxtTXR1XCLwbOQt+OL5zPHSDMmp2JZIeq82e18yE0Vv7zh6+6BfQ==", "cpu": [ "wasm32" ], "optional": true, "dependencies": { - "@emnapi/runtime": "^0.44.0" + "@emnapi/runtime": "^0.45.0" }, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0", @@ -556,9 +556,9 @@ } }, "node_modules/@img/sharp-win32-ia32": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.1.tgz", - "integrity": "sha512-/xhYkylsKL05R+NXGJc9xr2Tuw6WIVl2lubFJaFYfW4/MQ4J+dgjIo/T4qjNRizrqs/szF/lC9a5+updmY9jaQ==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.2.tgz", + "integrity": "sha512-okBpql96hIGuZ4lN3+nsAjGeggxKm7hIRu9zyec0lnfB8E7Z6p95BuRZzDDXZOl2e8UmR4RhYt631i7mfmKU8g==", "cpu": [ "ia32" ], @@ -577,9 +577,9 @@ } }, "node_modules/@img/sharp-win32-x64": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.1.tgz", - "integrity": "sha512-XaM69X0n6kTEsp9tVYYLhXdg7Qj32vYJlAKRutxUsm1UlgQNx6BOhHwZPwukCGXBU2+tH87ip2eV1I/E8MQnZg==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.2.tgz", + "integrity": "sha512-E4magOks77DK47FwHUIGH0RYWSgRBfGdK56kIHSVeB9uIS4pPFr4N2kIVsXdQQo4LzOsENKV5KAhRlRL7eMAdg==", "cpu": [ "x64" ], @@ -7269,9 +7269,9 @@ "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" }, "node_modules/sharp": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.1.tgz", - "integrity": "sha512-iAYUnOdTqqZDb3QjMneBKINTllCJDZ3em6WaWy7NPECM4aHncvqHRm0v0bN9nqJxMiwamv5KIdauJ6lUzKDpTQ==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.2.tgz", + "integrity": "sha512-WlYOPyyPDiiM07j/UO+E720ju6gtNtHjEGg5vovUk1Lgxyjm2LFO+37Nt/UI3MMh2l6hxTWQWi7qk3cXJTutcQ==", "hasInstallScript": true, "dependencies": { "color": "^4.2.3", @@ -7279,32 +7279,32 @@ "semver": "^7.5.4" }, "engines": { - "libvips": ">=8.15.0", + "libvips": ">=8.15.1", "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.33.1", - "@img/sharp-darwin-x64": "0.33.1", - "@img/sharp-libvips-darwin-arm64": "1.0.0", - "@img/sharp-libvips-darwin-x64": "1.0.0", - "@img/sharp-libvips-linux-arm": "1.0.0", - "@img/sharp-libvips-linux-arm64": "1.0.0", - "@img/sharp-libvips-linux-s390x": "1.0.0", - "@img/sharp-libvips-linux-x64": "1.0.0", - "@img/sharp-libvips-linuxmusl-arm64": "1.0.0", - "@img/sharp-libvips-linuxmusl-x64": "1.0.0", - "@img/sharp-linux-arm": "0.33.1", - "@img/sharp-linux-arm64": "0.33.1", - "@img/sharp-linux-s390x": "0.33.1", - "@img/sharp-linux-x64": "0.33.1", - "@img/sharp-linuxmusl-arm64": "0.33.1", - "@img/sharp-linuxmusl-x64": "0.33.1", - "@img/sharp-wasm32": "0.33.1", - "@img/sharp-win32-ia32": "0.33.1", - "@img/sharp-win32-x64": "0.33.1" + "@img/sharp-darwin-arm64": "0.33.2", + "@img/sharp-darwin-x64": "0.33.2", + "@img/sharp-libvips-darwin-arm64": "1.0.1", + "@img/sharp-libvips-darwin-x64": "1.0.1", + "@img/sharp-libvips-linux-arm": "1.0.1", + "@img/sharp-libvips-linux-arm64": "1.0.1", + "@img/sharp-libvips-linux-s390x": "1.0.1", + "@img/sharp-libvips-linux-x64": "1.0.1", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.1", + "@img/sharp-libvips-linuxmusl-x64": "1.0.1", + "@img/sharp-linux-arm": "0.33.2", + "@img/sharp-linux-arm64": "0.33.2", + "@img/sharp-linux-s390x": "0.33.2", + "@img/sharp-linux-x64": "0.33.2", + "@img/sharp-linuxmusl-arm64": "0.33.2", + "@img/sharp-linuxmusl-x64": "0.33.2", + "@img/sharp-wasm32": "0.33.2", + "@img/sharp-win32-ia32": "0.33.2", + "@img/sharp-win32-x64": "0.33.2" } }, "node_modules/sharp/node_modules/semver": { @@ -9024,9 +9024,9 @@ } }, "@emnapi/runtime": { - "version": "0.44.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-0.44.0.tgz", - "integrity": "sha512-ZX/etZEZw8DR7zAB1eVQT40lNo0jeqpb6dCgOvctB6FIQ5PoXfMuNY8+ayQfu8tNQbAB8gQWSSJupR8NxeiZXw==", + "version": "0.45.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-0.45.0.tgz", + "integrity": "sha512-Txumi3td7J4A/xTTwlssKieHKTGl3j4A1tglBx72auZ49YK7ePY6XZricgIg9mnZT4xPfA+UPCUdnhRuEFDL+w==", "optional": true, "requires": { "tslib": "^2.4.0" @@ -9094,144 +9094,144 @@ "dev": true }, "@img/sharp-darwin-arm64": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.1.tgz", - "integrity": "sha512-esr2BZ1x0bo+wl7Gx2hjssYhjrhUsD88VQulI0FrG8/otRQUOxLWHMBd1Y1qo2Gfg2KUvXNpT0ASnV9BzJCexw==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.2.tgz", + "integrity": "sha512-itHBs1rPmsmGF9p4qRe++CzCgd+kFYktnsoR1sbIAfsRMrJZau0Tt1AH9KVnufc2/tU02Gf6Ibujx+15qRE03w==", "optional": true, "requires": { - "@img/sharp-libvips-darwin-arm64": "1.0.0" + "@img/sharp-libvips-darwin-arm64": "1.0.1" } }, "@img/sharp-darwin-x64": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.1.tgz", - "integrity": "sha512-YrnuB3bXuWdG+hJlXtq7C73lF8ampkhU3tMxg5Hh+E7ikxbUVOU9nlNtVTloDXz6pRHt2y2oKJq7DY/yt+UXYw==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.2.tgz", + "integrity": "sha512-/rK/69Rrp9x5kaWBjVN07KixZanRr+W1OiyKdXcbjQD6KbW+obaTeBBtLUAtbBsnlTTmWthw99xqoOS7SsySDg==", "optional": true, "requires": { - "@img/sharp-libvips-darwin-x64": "1.0.0" + "@img/sharp-libvips-darwin-x64": "1.0.1" } }, "@img/sharp-libvips-darwin-arm64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.0.tgz", - "integrity": "sha512-VzYd6OwnUR81sInf3alj1wiokY50DjsHz5bvfnsFpxs5tqQxESoHtJO6xyksDs3RIkyhMWq2FufXo6GNSU9BMw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.1.tgz", + "integrity": "sha512-kQyrSNd6lmBV7O0BUiyu/OEw9yeNGFbQhbxswS1i6rMDwBBSX+e+rPzu3S+MwAiGU3HdLze3PanQ4Xkfemgzcw==", "optional": true }, "@img/sharp-libvips-darwin-x64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.0.tgz", - "integrity": "sha512-dD9OznTlHD6aovRswaPNEy8dKtSAmNo4++tO7uuR4o5VxbVAOoEQ1uSmN4iFAdQneTHws1lkTZeiXPrcCkh6IA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.1.tgz", + "integrity": "sha512-eVU/JYLPVjhhrd8Tk6gosl5pVlvsqiFlt50wotCvdkFGf+mDNBJxMh+bvav+Wt3EBnNZWq8Sp2I7XfSjm8siog==", "optional": true }, "@img/sharp-libvips-linux-arm": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.0.tgz", - "integrity": "sha512-VwgD2eEikDJUk09Mn9Dzi1OW2OJFRQK+XlBTkUNmAWPrtj8Ly0yq05DFgu1VCMx2/DqCGQVi5A1dM9hTmxf3uw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.1.tgz", + "integrity": "sha512-FtdMvR4R99FTsD53IA3LxYGghQ82t3yt0ZQ93WMZ2xV3dqrb0E8zq4VHaTOuLEAuA83oDawHV3fd+BsAPadHIQ==", "optional": true }, "@img/sharp-libvips-linux-arm64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.0.tgz", - "integrity": "sha512-xTYThiqEZEZc0PRU90yVtM3KE7lw1bKdnDQ9kCTHWbqWyHOe4NpPOtMGy27YnN51q0J5dqRrvicfPbALIOeAZA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.1.tgz", + "integrity": "sha512-bnGG+MJjdX70mAQcSLxgeJco11G+MxTz+ebxlz8Y3dxyeb3Nkl7LgLI0mXupoO+u1wRNx/iRj5yHtzA4sde1yA==", "optional": true }, "@img/sharp-libvips-linux-s390x": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.0.tgz", - "integrity": "sha512-o9E46WWBC6JsBlwU4QyU9578G77HBDT1NInd+aERfxeOPbk0qBZHgoDsQmA2v9TbqJRWzoBPx1aLOhprBMgPjw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.1.tgz", + "integrity": "sha512-3+rzfAR1YpMOeA2zZNp+aYEzGNWK4zF3+sdMxuCS3ey9HhDbJ66w6hDSHDMoap32DueFwhhs3vwooAB2MaK4XQ==", "optional": true }, "@img/sharp-libvips-linux-x64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.0.tgz", - "integrity": "sha512-naldaJy4hSVhWBgEjfdBY85CAa4UO+W1nx6a1sWStHZ7EUfNiuBTTN2KUYT5dH1+p/xij1t2QSXfCiFJoC5S/Q==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.1.tgz", + "integrity": "sha512-3NR1mxFsaSgMMzz1bAnnKbSAI+lHXVTqAHgc1bgzjHuXjo4hlscpUxc0vFSAPKI3yuzdzcZOkq7nDPrP2F8Jgw==", "optional": true }, "@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.0.tgz", - "integrity": "sha512-OdorplCyvmSAPsoJLldtLh3nLxRrkAAAOHsGWGDYfN0kh730gifK+UZb3dWORRa6EusNqCTjfXV4GxvgJ/nPDQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.1.tgz", + "integrity": "sha512-5aBRcjHDG/T6jwC3Edl3lP8nl9U2Yo8+oTl5drd1dh9Z1EBfzUKAJFUDTDisDjUwc7N4AjnPGfCA3jl3hY8uDg==", "optional": true }, "@img/sharp-libvips-linuxmusl-x64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.0.tgz", - "integrity": "sha512-FW8iK6rJrg+X2jKD0Ajhjv6y74lToIBEvkZhl42nZt563FfxkCYacrXZtd+q/sRQDypQLzY5WdLkVTbJoPyqNg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.1.tgz", + "integrity": "sha512-dcT7inI9DBFK6ovfeWRe3hG30h51cBAP5JXlZfx6pzc/Mnf9HFCQDLtYf4MCBjxaaTfjCCjkBxcy3XzOAo5txw==", "optional": true }, "@img/sharp-linux-arm": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.1.tgz", - "integrity": "sha512-Ii4X1vnzzI4j0+cucsrYA5ctrzU9ciXERfJR633S2r39CiD8npqH2GMj63uFZRCFt3E687IenAdbwIpQOJ5BNA==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.2.tgz", + "integrity": "sha512-Fndk/4Zq3vAc4G/qyfXASbS3HBZbKrlnKZLEJzPLrXoJuipFNNwTes71+Ki1hwYW5lch26niRYoZFAtZVf3EGA==", "optional": true, "requires": { - "@img/sharp-libvips-linux-arm": "1.0.0" + "@img/sharp-libvips-linux-arm": "1.0.1" } }, "@img/sharp-linux-arm64": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.1.tgz", - "integrity": "sha512-59B5GRO2d5N3tIfeGHAbJps7cLpuWEQv/8ySd9109ohQ3kzyCACENkFVAnGPX00HwPTQcaBNF7HQYEfZyZUFfw==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.2.tgz", + "integrity": "sha512-pz0NNo882vVfqJ0yNInuG9YH71smP4gRSdeL09ukC2YLE6ZyZePAlWKEHgAzJGTiOh8Qkaov6mMIMlEhmLdKew==", "optional": true, "requires": { - "@img/sharp-libvips-linux-arm64": "1.0.0" + "@img/sharp-libvips-linux-arm64": "1.0.1" } }, "@img/sharp-linux-s390x": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.1.tgz", - "integrity": "sha512-tRGrb2pHnFUXpOAj84orYNxHADBDIr0J7rrjwQrTNMQMWA4zy3StKmMvwsI7u3dEZcgwuMMooIIGWEWOjnmG8A==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.2.tgz", + "integrity": "sha512-MBoInDXDppMfhSzbMmOQtGfloVAflS2rP1qPcUIiITMi36Mm5YR7r0ASND99razjQUpHTzjrU1flO76hKvP5RA==", "optional": true, "requires": { - "@img/sharp-libvips-linux-s390x": "1.0.0" + "@img/sharp-libvips-linux-s390x": "1.0.1" } }, "@img/sharp-linux-x64": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.1.tgz", - "integrity": "sha512-4y8osC0cAc1TRpy02yn5omBeloZZwS62fPZ0WUAYQiLhSFSpWJfY/gMrzKzLcHB9ulUV6ExFiu2elMaixKDbeg==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.2.tgz", + "integrity": "sha512-xUT82H5IbXewKkeF5aiooajoO1tQV4PnKfS/OZtb5DDdxS/FCI/uXTVZ35GQ97RZXsycojz/AJ0asoz6p2/H/A==", "optional": true, "requires": { - "@img/sharp-libvips-linux-x64": "1.0.0" + "@img/sharp-libvips-linux-x64": "1.0.1" } }, "@img/sharp-linuxmusl-arm64": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.1.tgz", - "integrity": "sha512-D3lV6clkqIKUizNS8K6pkuCKNGmWoKlBGh5p0sLO2jQERzbakhu4bVX1Gz+RS4vTZBprKlWaf+/Rdp3ni2jLfA==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.2.tgz", + "integrity": "sha512-F+0z8JCu/UnMzg8IYW1TMeiViIWBVg7IWP6nE0p5S5EPQxlLd76c8jYemG21X99UzFwgkRo5yz2DS+zbrnxZeA==", "optional": true, "requires": { - "@img/sharp-libvips-linuxmusl-arm64": "1.0.0" + "@img/sharp-libvips-linuxmusl-arm64": "1.0.1" } }, "@img/sharp-linuxmusl-x64": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.1.tgz", - "integrity": "sha512-LOGKNu5w8uu1evVqUAUKTix2sQu1XDRIYbsi5Q0c/SrXhvJ4QyOx+GaajxmOg5PZSsSnCYPSmhjHHsRBx06/wQ==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.2.tgz", + "integrity": "sha512-+ZLE3SQmSL+Fn1gmSaM8uFusW5Y3J9VOf+wMGNnTtJUMUxFhv+P4UPaYEYT8tqnyYVaOVGgMN/zsOxn9pSsO2A==", "optional": true, "requires": { - "@img/sharp-libvips-linuxmusl-x64": "1.0.0" + "@img/sharp-libvips-linuxmusl-x64": "1.0.1" } }, "@img/sharp-wasm32": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.1.tgz", - "integrity": "sha512-vWI/sA+0p+92DLkpAMb5T6I8dg4z2vzCUnp8yvxHlwBpzN8CIcO3xlSXrLltSvK6iMsVMNswAv+ub77rsf25lA==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.2.tgz", + "integrity": "sha512-fLbTaESVKuQcpm8ffgBD7jLb/CQLcATju/jxtTXR1XCLwbOQt+OL5zPHSDMmp2JZIeq82e18yE0Vv7zh6+6BfQ==", "optional": true, "requires": { - "@emnapi/runtime": "^0.44.0" + "@emnapi/runtime": "^0.45.0" } }, "@img/sharp-win32-ia32": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.1.tgz", - "integrity": "sha512-/xhYkylsKL05R+NXGJc9xr2Tuw6WIVl2lubFJaFYfW4/MQ4J+dgjIo/T4qjNRizrqs/szF/lC9a5+updmY9jaQ==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.2.tgz", + "integrity": "sha512-okBpql96hIGuZ4lN3+nsAjGeggxKm7hIRu9zyec0lnfB8E7Z6p95BuRZzDDXZOl2e8UmR4RhYt631i7mfmKU8g==", "optional": true }, "@img/sharp-win32-x64": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.1.tgz", - "integrity": "sha512-XaM69X0n6kTEsp9tVYYLhXdg7Qj32vYJlAKRutxUsm1UlgQNx6BOhHwZPwukCGXBU2+tH87ip2eV1I/E8MQnZg==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.2.tgz", + "integrity": "sha512-E4magOks77DK47FwHUIGH0RYWSgRBfGdK56kIHSVeB9uIS4pPFr4N2kIVsXdQQo4LzOsENKV5KAhRlRL7eMAdg==", "optional": true }, "@isaacs/cliui": { @@ -14411,29 +14411,29 @@ "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" }, "sharp": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.1.tgz", - "integrity": "sha512-iAYUnOdTqqZDb3QjMneBKINTllCJDZ3em6WaWy7NPECM4aHncvqHRm0v0bN9nqJxMiwamv5KIdauJ6lUzKDpTQ==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.2.tgz", + "integrity": "sha512-WlYOPyyPDiiM07j/UO+E720ju6gtNtHjEGg5vovUk1Lgxyjm2LFO+37Nt/UI3MMh2l6hxTWQWi7qk3cXJTutcQ==", "requires": { - "@img/sharp-darwin-arm64": "0.33.1", - "@img/sharp-darwin-x64": "0.33.1", - "@img/sharp-libvips-darwin-arm64": "1.0.0", - "@img/sharp-libvips-darwin-x64": "1.0.0", - "@img/sharp-libvips-linux-arm": "1.0.0", - "@img/sharp-libvips-linux-arm64": "1.0.0", - "@img/sharp-libvips-linux-s390x": "1.0.0", - "@img/sharp-libvips-linux-x64": "1.0.0", - "@img/sharp-libvips-linuxmusl-arm64": "1.0.0", - "@img/sharp-libvips-linuxmusl-x64": "1.0.0", - "@img/sharp-linux-arm": "0.33.1", - "@img/sharp-linux-arm64": "0.33.1", - "@img/sharp-linux-s390x": "0.33.1", - "@img/sharp-linux-x64": "0.33.1", - "@img/sharp-linuxmusl-arm64": "0.33.1", - "@img/sharp-linuxmusl-x64": "0.33.1", - "@img/sharp-wasm32": "0.33.1", - "@img/sharp-win32-ia32": "0.33.1", - "@img/sharp-win32-x64": "0.33.1", + "@img/sharp-darwin-arm64": "0.33.2", + "@img/sharp-darwin-x64": "0.33.2", + "@img/sharp-libvips-darwin-arm64": "1.0.1", + "@img/sharp-libvips-darwin-x64": "1.0.1", + "@img/sharp-libvips-linux-arm": "1.0.1", + "@img/sharp-libvips-linux-arm64": "1.0.1", + "@img/sharp-libvips-linux-s390x": "1.0.1", + "@img/sharp-libvips-linux-x64": "1.0.1", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.1", + "@img/sharp-libvips-linuxmusl-x64": "1.0.1", + "@img/sharp-linux-arm": "0.33.2", + "@img/sharp-linux-arm64": "0.33.2", + "@img/sharp-linux-s390x": "0.33.2", + "@img/sharp-linux-x64": "0.33.2", + "@img/sharp-linuxmusl-arm64": "0.33.2", + "@img/sharp-linuxmusl-x64": "0.33.2", + "@img/sharp-wasm32": "0.33.2", + "@img/sharp-win32-ia32": "0.33.2", + "@img/sharp-win32-x64": "0.33.2", "color": "^4.2.3", "detect-libc": "^2.0.2", "semver": "^7.5.4" diff --git a/server/package.json b/server/package.json index 6a11147a..59bb2f78 100644 --- a/server/package.json +++ b/server/package.json @@ -42,7 +42,7 @@ "sails-hook-orm": "^4.0.2", "sails-hook-sockets": "^2.0.4", "sails-postgresql-redacted": "^1.0.2-9", - "sharp": "^0.33.1", + "sharp": "^0.33.2", "stream-to-array": "^2.3.0", "uuid": "^9.0.1", "validator": "^13.11.0", diff --git a/temp b/temp deleted file mode 100644 index a1c2b7dd..00000000 --- a/temp +++ /dev/null @@ -1 +0,0 @@ -Just a file to trigger the build workflow. From 32ce07a84377899db758fbdc0b9b680e3a17242c Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Thu, 18 Jan 2024 11:00:20 +0100 Subject: [PATCH 10/42] chore: Update version --- charts/planka/Chart.yaml | 4 ++-- client/.env | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/charts/planka/Chart.yaml b/charts/planka/Chart.yaml index a24cdaec..1c32bf7f 100644 --- a/charts/planka/Chart.yaml +++ b/charts/planka/Chart.yaml @@ -15,13 +15,13 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.14 +version: 0.1.15 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "1.15.3" +appVersion: "1.15.4" dependencies: - alias: postgresql diff --git a/client/.env b/client/.env index b798cdc0..4d4ab730 100644 --- a/client/.env +++ b/client/.env @@ -1 +1 @@ -REACT_APP_VERSION=1.15.3 +REACT_APP_VERSION=1.15.4 diff --git a/package-lock.json b/package-lock.json index 10785613..51e7931d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "planka", - "version": "1.15.3", + "version": "1.15.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "planka", - "version": "1.15.3", + "version": "1.15.4", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index a7673213..e76450c3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "planka", - "version": "1.15.3", + "version": "1.15.4", "private": true, "homepage": "https://plankanban.github.io/planka", "repository": { From def232716548220ccc4ed239a85f605f8e47ffb2 Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Thu, 25 Jan 2024 23:01:59 +0100 Subject: [PATCH 11/42] feat: Add ability to map OIDC attributes and ignore username Closes #554 --- .../AccountPane/AccountPane.jsx | 110 ++++++++++-------- .../UserSettingsModal/UserSettingsModal.jsx | 3 + .../UsersModal/Item/ActionsStep.jsx | 12 +- .../src/components/UsersModal/Item/Item.jsx | 3 + .../src/components/UsersModal/UsersModal.jsx | 1 + .../containers/UserSettingsModalContainer.js | 2 + client/src/models/User.js | 1 + docker-compose.yml | 4 + server/.env.sample | 4 + .../api/controllers/users/update-username.js | 21 ++-- .../users/get-or-create-one-using-oidc.js | 18 ++- server/api/models/User.js | 1 + server/config/custom.js | 4 + 13 files changed, 112 insertions(+), 72 deletions(-) diff --git a/client/src/components/UserSettingsModal/AccountPane/AccountPane.jsx b/client/src/components/UserSettingsModal/AccountPane/AccountPane.jsx index 7333cf5d..eed13261 100644 --- a/client/src/components/UserSettingsModal/AccountPane/AccountPane.jsx +++ b/client/src/components/UserSettingsModal/AccountPane/AccountPane.jsx @@ -24,6 +24,7 @@ const AccountPane = React.memo( organization, language, isLocked, + isUsernameLocked, isAvatarUpdating, usernameUpdateForm, emailUpdateForm, @@ -104,7 +105,7 @@ const AccountPane = React.memo( value={language || 'auto'} onChange={handleLanguageChange} /> - {!isLocked && ( + {(!isLocked || !isUsernameLocked) && ( <>
@@ -113,56 +114,62 @@ const AccountPane = React.memo( })}
-
- - - -
-
- - - -
-
- - - -
+ {!isUsernameLocked && ( +
+ + + +
+ )} + {!isLocked && ( + <> +
+ + + +
+
+ + + +
+ + )} )} @@ -179,6 +186,7 @@ AccountPane.propTypes = { organization: PropTypes.string, language: PropTypes.string, isLocked: PropTypes.bool.isRequired, + isUsernameLocked: PropTypes.bool.isRequired, isAvatarUpdating: PropTypes.bool.isRequired, /* eslint-disable react/forbid-prop-types */ usernameUpdateForm: PropTypes.object.isRequired, diff --git a/client/src/components/UserSettingsModal/UserSettingsModal.jsx b/client/src/components/UserSettingsModal/UserSettingsModal.jsx index fc8ac9c7..8767ac4e 100644 --- a/client/src/components/UserSettingsModal/UserSettingsModal.jsx +++ b/client/src/components/UserSettingsModal/UserSettingsModal.jsx @@ -18,6 +18,7 @@ const UserSettingsModal = React.memo( language, subscribeToOwnCards, isLocked, + isUsernameLocked, isAvatarUpdating, usernameUpdateForm, emailUpdateForm, @@ -50,6 +51,7 @@ const UserSettingsModal = React.memo( organization={organization} language={language} isLocked={isLocked} + isUsernameLocked={isUsernameLocked} isAvatarUpdating={isAvatarUpdating} usernameUpdateForm={usernameUpdateForm} emailUpdateForm={emailUpdateForm} @@ -108,6 +110,7 @@ UserSettingsModal.propTypes = { language: PropTypes.string, subscribeToOwnCards: PropTypes.bool.isRequired, isLocked: PropTypes.bool.isRequired, + isUsernameLocked: PropTypes.bool.isRequired, isAvatarUpdating: PropTypes.bool.isRequired, /* eslint-disable react/forbid-prop-types */ usernameUpdateForm: PropTypes.object.isRequired, diff --git a/client/src/components/UsersModal/Item/ActionsStep.jsx b/client/src/components/UsersModal/Item/ActionsStep.jsx index f8a2959b..7b0eaed6 100644 --- a/client/src/components/UsersModal/Item/ActionsStep.jsx +++ b/client/src/components/UsersModal/Item/ActionsStep.jsx @@ -136,13 +136,15 @@ const ActionsStep = React.memo( context: 'title', })} + {!user.isUsernameLocked && ( + + {t('action.editUsername', { + context: 'title', + })} + + )} {!user.isLocked && ( <> - - {t('action.editUsername', { - context: 'title', - })} - {t('action.editEmail', { context: 'title', diff --git a/client/src/components/UsersModal/Item/Item.jsx b/client/src/components/UsersModal/Item/Item.jsx index 80db3568..ed68da3a 100755 --- a/client/src/components/UsersModal/Item/Item.jsx +++ b/client/src/components/UsersModal/Item/Item.jsx @@ -19,6 +19,7 @@ const Item = React.memo( isAdmin, isLocked, isRoleLocked, + isUsernameLocked, isDeletionLocked, emailUpdateForm, passwordUpdateForm, @@ -61,6 +62,7 @@ const Item = React.memo( phone, isAdmin, isLocked, + isUsernameLocked, isDeletionLocked, emailUpdateForm, passwordUpdateForm, @@ -95,6 +97,7 @@ Item.propTypes = { isAdmin: PropTypes.bool.isRequired, isLocked: PropTypes.bool.isRequired, isRoleLocked: PropTypes.bool.isRequired, + isUsernameLocked: PropTypes.bool.isRequired, isDeletionLocked: PropTypes.bool.isRequired, /* eslint-disable react/forbid-prop-types */ emailUpdateForm: PropTypes.object.isRequired, diff --git a/client/src/components/UsersModal/UsersModal.jsx b/client/src/components/UsersModal/UsersModal.jsx index 0b55778e..280cd08a 100755 --- a/client/src/components/UsersModal/UsersModal.jsx +++ b/client/src/components/UsersModal/UsersModal.jsx @@ -112,6 +112,7 @@ const UsersModal = React.memo( isAdmin={item.isAdmin} isLocked={item.isLocked} isRoleLocked={item.isRoleLocked} + isUsernameLocked={item.isUsernameLocked} isDeletionLocked={item.isDeletionLocked} emailUpdateForm={item.emailUpdateForm} passwordUpdateForm={item.passwordUpdateForm} diff --git a/client/src/containers/UserSettingsModalContainer.js b/client/src/containers/UserSettingsModalContainer.js index 620632e0..8c3b1c36 100644 --- a/client/src/containers/UserSettingsModalContainer.js +++ b/client/src/containers/UserSettingsModalContainer.js @@ -16,6 +16,7 @@ const mapStateToProps = (state) => { language, subscribeToOwnCards, isLocked, + isUsernameLocked, isAvatarUpdating, emailUpdateForm, passwordUpdateForm, @@ -32,6 +33,7 @@ const mapStateToProps = (state) => { language, subscribeToOwnCards, isLocked, + isUsernameLocked, isAvatarUpdating, emailUpdateForm, passwordUpdateForm, diff --git a/client/src/models/User.js b/client/src/models/User.js index 84555308..9bf8208f 100755 --- a/client/src/models/User.js +++ b/client/src/models/User.js @@ -46,6 +46,7 @@ export default class extends BaseModel { isAdmin: attr(), isLocked: attr(), isRoleLocked: attr(), + isUsernameLocked: attr(), isDeletionLocked: attr(), deletedAt: attr(), createdAt: attr({ diff --git a/docker-compose.yml b/docker-compose.yml index 6fac280e..3e9d023d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -44,7 +44,11 @@ services: # - OIDC_CLIENT_SECRET= # - OIDC_SCOPES=openid email profile # - OIDC_ADMIN_ROLES=admin + # - OIDC_EMAIL_ATTRIBUTE=email + # - OIDC_NAME_ATTRIBUTE=name + # - OIDC_USERNAME_ATTRIBUTE=preferred_username # - OIDC_ROLES_ATTRIBUTE=groups + # - OIDC_IGNORE_USERNAME=true # - OIDC_IGNORE_ROLES=true # - SLACK_BOT_TOKEN=xoxb-xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxx diff --git a/server/.env.sample b/server/.env.sample index f06b6470..31f2342b 100644 --- a/server/.env.sample +++ b/server/.env.sample @@ -27,7 +27,11 @@ SECRET_KEY=notsecretkey # OIDC_CLIENT_SECRET= # OIDC_SCOPES=openid email profile # OIDC_ADMIN_ROLES=admin +# OIDC_EMAIL_ATTRIBUTE=email +# OIDC_NAME_ATTRIBUTE=name +# OIDC_USERNAME_ATTRIBUTE=preferred_username # OIDC_ROLES_ATTRIBUTE=groups +# OIDC_IGNORE_USERNAME=true # OIDC_IGNORE_ROLES=true ## Do not edit this diff --git a/server/api/controllers/users/update-username.js b/server/api/controllers/users/update-username.js index 58059460..b55529b4 100644 --- a/server/api/controllers/users/update-username.js +++ b/server/api/controllers/users/update-username.js @@ -53,11 +53,7 @@ module.exports = { async fn(inputs) { const { currentUser } = this.req; - if (inputs.id === currentUser.id) { - if (!inputs.currentPassword) { - throw Errors.INVALID_CURRENT_PASSWORD; - } - } else if (!currentUser.isAdmin) { + if (inputs.id !== currentUser.id && !currentUser.isAdmin) { throw Errors.USER_NOT_FOUND; // Forbidden } @@ -67,15 +63,18 @@ module.exports = { throw Errors.USER_NOT_FOUND; } - if (user.email === sails.config.custom.defaultAdminEmail || user.isSso) { + if (user.email === sails.config.custom.defaultAdminEmail) { throw Errors.NOT_ENOUGH_RIGHTS; } - if ( - inputs.id === currentUser.id && - !bcrypt.compareSync(inputs.currentPassword, user.password) - ) { - throw Errors.INVALID_CURRENT_PASSWORD; + if (user.isSso) { + if (!sails.config.custom.oidcIgnoreUsername) { + throw Errors.NOT_ENOUGH_RIGHTS; + } + } else if (inputs.id === currentUser.id) { + if (!inputs.currentPassword || !bcrypt.compareSync(inputs.currentPassword, user.password)) { + throw Errors.INVALID_CURRENT_PASSWORD; + } } const values = _.pick(inputs, ['username']); diff --git a/server/api/helpers/users/get-or-create-one-using-oidc.js b/server/api/helpers/users/get-or-create-one-using-oidc.js index 6d1c49f0..2186c099 100644 --- a/server/api/helpers/users/get-or-create-one-using-oidc.js +++ b/server/api/helpers/users/get-or-create-one-using-oidc.js @@ -38,7 +38,10 @@ module.exports = { throw 'invalidCodeOrNonce'; } - if (!userInfo.email || !userInfo.name) { + if ( + !userInfo[sails.config.custom.oidcEmailAttribute] || + !userInfo[sails.config.custom.oidcNameAttribute] + ) { throw 'missingValues'; } @@ -56,12 +59,14 @@ module.exports = { const values = { isAdmin, - email: userInfo.email, + email: userInfo[sails.config.custom.oidcEmailAttribute], isSso: true, - name: userInfo.name, - username: userInfo.preferred_username, + name: userInfo[sails.config.custom.oidcNameAttribute], subscribeToOwnCards: false, }; + if (!sails.config.custom.oidcIgnoreUsername) { + values.username = userInfo[sails.config.custom.oidcUsernameAttribute]; + } let user; // This whole block technically needs to be executed in a transaction @@ -95,7 +100,10 @@ module.exports = { }); } - const updateFieldKeys = ['email', 'isSso', 'name', 'username']; + const updateFieldKeys = ['email', 'isSso', 'name']; + if (!sails.config.custom.oidcIgnoreUsername) { + updateFieldKeys.push('username'); + } if (!sails.config.custom.oidcIgnoreRoles) { updateFieldKeys.push('isAdmin'); } diff --git a/server/api/models/User.js b/server/api/models/User.js index 9bf8a298..1d875318 100755 --- a/server/api/models/User.js +++ b/server/api/models/User.js @@ -116,6 +116,7 @@ module.exports = { ..._.omit(this, ['password', 'isSso', 'avatar', 'passwordChangedAt']), isLocked: this.isSso || isDefaultAdmin, isRoleLocked: (this.isSso && !sails.config.custom.oidcIgnoreRoles) || isDefaultAdmin, + isUsernameLocked: (this.isSso && !sails.config.custom.oidcIgnoreUsername) || isDefaultAdmin, isDeletionLocked: isDefaultAdmin, avatarUrl: this.avatar && diff --git a/server/config/custom.js b/server/config/custom.js index cbbc89ba..afd60ec4 100644 --- a/server/config/custom.js +++ b/server/config/custom.js @@ -38,7 +38,11 @@ module.exports.custom = { oidcClientSecret: process.env.OIDC_CLIENT_SECRET, oidcScopes: process.env.OIDC_SCOPES || 'openid email profile', oidcAdminRoles: process.env.OIDC_ADMIN_ROLES ? process.env.OIDC_ADMIN_ROLES.split(',') : [], + oidcEmailAttribute: process.env.OIDC_EMAIL_ATTRIBUTE || 'email', + oidcNameAttribute: process.env.OIDC_NAME_ATTRIBUTE || 'name', + oidcUsernameAttribute: process.env.OIDC_USERNAME_ATTRIBUTE || 'preferred_username', oidcRolesAttribute: process.env.OIDC_ROLES_ATTRIBUTE || 'groups', + oidcIgnoreUsername: process.env.OIDC_IGNORE_USERNAME === 'true', oidcIgnoreRoles: process.env.OIDC_IGNORE_ROLES === 'true', // TODO: move client base url to environment variable? From 988afba1d06c9445e2aad56e4fef074a3def7f81 Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Wed, 31 Jan 2024 15:58:57 +0100 Subject: [PATCH 12/42] chore: Update version --- charts/planka/Chart.yaml | 4 ++-- client/.env | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/charts/planka/Chart.yaml b/charts/planka/Chart.yaml index 1c32bf7f..cf4fe0c5 100644 --- a/charts/planka/Chart.yaml +++ b/charts/planka/Chart.yaml @@ -15,13 +15,13 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.15 +version: 0.1.16 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "1.15.4" +appVersion: "1.15.5" dependencies: - alias: postgresql diff --git a/client/.env b/client/.env index 4d4ab730..b54a3946 100644 --- a/client/.env +++ b/client/.env @@ -1 +1 @@ -REACT_APP_VERSION=1.15.4 +REACT_APP_VERSION=1.15.5 diff --git a/package-lock.json b/package-lock.json index 51e7931d..ed45ee04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "planka", - "version": "1.15.4", + "version": "1.15.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "planka", - "version": "1.15.4", + "version": "1.15.5", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index e76450c3..fb2621cf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "planka", - "version": "1.15.4", + "version": "1.15.5", "private": true, "homepage": "https://plankanban.github.io/planka", "repository": { From 6c826c71277bb89e643ce6584b8e4e0b84b4ab0a Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Thu, 1 Feb 2024 00:31:15 +0100 Subject: [PATCH 13/42] feat: Add ability to enforce SSO Closes #543, closes #545 --- client/src/components/Login/Login.jsx | 90 ++++++++++--------- .../src/components/UsersModal/UsersModal.jsx | 14 +-- client/src/containers/LoginContainer.js | 1 + client/src/containers/UsersModalContainer.js | 2 + docker-compose.yml | 1 + server/.env.sample | 1 + .../api/controllers/access-tokens/create.js | 5 +- server/api/controllers/show-config.js | 1 + server/api/controllers/users/create.js | 10 +++ server/config/custom.js | 1 + 10 files changed, 80 insertions(+), 46 deletions(-) diff --git a/client/src/components/Login/Login.jsx b/client/src/components/Login/Login.jsx index 84e6a9d0..6f547ee2 100755 --- a/client/src/components/Login/Login.jsx +++ b/client/src/components/Login/Login.jsx @@ -68,6 +68,7 @@ const Login = React.memo( isSubmittingUsingOidc, error, withOidc, + isOidcEnforced, onAuthenticate, onAuthenticateUsingOidc, onMessageDismiss, @@ -107,8 +108,10 @@ const Login = React.memo( }, [onAuthenticate, data]); useEffect(() => { - emailOrUsernameField.current.focus(); - }, []); + if (!isOidcEnforced) { + emailOrUsernameField.current.focus(); + } + }, [isOidcEnforced]); useEffect(() => { if (wasSubmitting && !isSubmitting && error) { @@ -159,51 +162,57 @@ const Login = React.memo( onDismiss={onMessageDismiss} /> )} -
-
-
{t('common.emailOrUsername')}
- +
+
{t('common.emailOrUsername')}
+ +
+
+
{t('common.password')}
+ +
+ -
-
-
{t('common.password')}
- -
- - + + )} {withOidc && ( + /> )} @@ -242,6 +251,7 @@ Login.propTypes = { isSubmittingUsingOidc: PropTypes.bool.isRequired, error: PropTypes.object, // eslint-disable-line react/forbid-prop-types withOidc: PropTypes.bool.isRequired, + isOidcEnforced: PropTypes.bool.isRequired, onAuthenticate: PropTypes.func.isRequired, onAuthenticateUsingOidc: PropTypes.func.isRequired, onMessageDismiss: PropTypes.func.isRequired, diff --git a/client/src/components/UsersModal/UsersModal.jsx b/client/src/components/UsersModal/UsersModal.jsx index 280cd08a..68f0f82f 100755 --- a/client/src/components/UsersModal/UsersModal.jsx +++ b/client/src/components/UsersModal/UsersModal.jsx @@ -10,6 +10,7 @@ import Item from './Item'; const UsersModal = React.memo( ({ items, + canAdd, onUpdate, onUsernameUpdate, onUsernameUpdateMessageDismiss, @@ -130,11 +131,13 @@ const UsersModal = React.memo( - - - + onUpdate: (data) => entryActions.updateCard(id, data), onMove: (listId, index) => entryActions.moveCard(id, listId, index), onTransfer: (boardId, listId) => entryActions.transferCard(id, boardId, listId), + onDuplicate: () => entryActions.duplicateCard(id), onDelete: () => entryActions.deleteCard(id), onUserAdd: (userId) => entryActions.addUserToCard(userId, id), onUserRemove: (userId) => entryActions.removeUserFromCard(userId, id), diff --git a/client/src/containers/CardModalContainer.js b/client/src/containers/CardModalContainer.js index ceae9840..a8df6ea0 100755 --- a/client/src/containers/CardModalContainer.js +++ b/client/src/containers/CardModalContainer.js @@ -78,6 +78,7 @@ const mapDispatchToProps = (dispatch) => onUpdate: entryActions.updateCurrentCard, onMove: entryActions.moveCurrentCard, onTransfer: entryActions.transferCurrentCard, + onDuplicate: entryActions.duplicateCurrentCard, onDelete: entryActions.deleteCurrentCard, onUserAdd: entryActions.addUserToCurrentCard, onUserRemove: entryActions.removeUserFromCurrentCard, diff --git a/client/src/entry-actions/cards.js b/client/src/entry-actions/cards.js index d73b2476..346fc8d8 100755 --- a/client/src/entry-actions/cards.js +++ b/client/src/entry-actions/cards.js @@ -74,6 +74,18 @@ const transferCurrentCard = (boardId, listId, index = 0) => ({ }, }); +const duplicateCard = (id) => ({ + type: EntryActionTypes.CARD_DUPLICATE, + payload: { + id, + }, +}); + +const duplicateCurrentCard = () => ({ + type: EntryActionTypes.CURRENT_CARD_DUPLICATE, + payload: {}, +}); + const deleteCard = (id) => ({ type: EntryActionTypes.CARD_DELETE, payload: { @@ -103,6 +115,8 @@ export default { moveCurrentCard, transferCard, transferCurrentCard, + duplicateCard, + duplicateCurrentCard, deleteCard, deleteCurrentCard, handleCardDelete, diff --git a/client/src/locales/en/core.js b/client/src/locales/en/core.js index 83b01168..41e4494d 100644 --- a/client/src/locales/en/core.js +++ b/client/src/locales/en/core.js @@ -51,6 +51,7 @@ export default { cardNotFound_title: 'Card Not Found', cardOrActionAreDeleted: 'Card or action are deleted.', color: 'Color', + copy_inline: 'copy', createBoard_title: 'Create Board', createLabel_title: 'Create Label', createNewOneOrSelectExistingOne: 'Create a new one or select
an existing one.', @@ -196,6 +197,8 @@ export default { deleteTask: 'Delete task', deleteTask_title: 'Delete Task', deleteUser: 'Delete user', + duplicate: 'Duplicate', + duplicateCard_title: 'Duplicate Card', edit: 'Edit', editDueDate_title: 'Edit Due Date', editDescription_title: 'Edit Description', diff --git a/client/src/locales/fr/core.js b/client/src/locales/fr/core.js index e20e2910..1b9296ff 100644 --- a/client/src/locales/fr/core.js +++ b/client/src/locales/fr/core.js @@ -169,6 +169,7 @@ export default { deleteTask: 'Supprimer la tâche', deleteTask_title: 'Supprimer la tâche', deleteUser: "Supprimer l'utilisateur", + duplicate: 'Dupliquer', edit: 'Modifier', editDueDate_title: "Modifier la date d'échéance", editDescription_title: 'Éditer la description', diff --git a/client/src/models/Card.js b/client/src/models/Card.js index 78c682cc..3c452569 100755 --- a/client/src/models/Card.js +++ b/client/src/models/Card.js @@ -1,3 +1,4 @@ +import pick from 'lodash/pick'; import { attr, fk, many, oneToOne } from 'redux-orm'; import BaseModel from './BaseModel'; @@ -165,7 +166,6 @@ export default class extends BaseModel { break; case ActionTypes.CARD_CREATE: - case ActionTypes.CARD_CREATE_HANDLE: case ActionTypes.CARD_UPDATE__SUCCESS: case ActionTypes.CARD_UPDATE_HANDLE: Card.upsert(payload.card); @@ -176,10 +176,63 @@ export default class extends BaseModel { Card.upsert(payload.card); break; + case ActionTypes.CARD_CREATE_HANDLE: { + const cardModel = Card.upsert(payload.card); + + payload.cardMemberships.forEach(({ userId }) => { + cardModel.users.add(userId); + }); + + payload.cardLabels.forEach(({ labelId }) => { + cardModel.labels.add(labelId); + }); + + break; + } case ActionTypes.CARD_UPDATE: Card.withId(payload.id).update(payload.data); break; + case ActionTypes.CARD_DUPLICATE: { + const cardModel = Card.withId(payload.id); + + const nextCardModel = Card.upsert({ + ...pick(cardModel.ref, [ + 'boardId', + 'listId', + 'position', + 'name', + 'description', + 'dueDate', + 'stopwatch', + ]), + ...payload.card, + }); + + cardModel.users.toRefArray().forEach(({ id }) => { + nextCardModel.users.add(id); + }); + + cardModel.labels.toRefArray().forEach(({ id }) => { + nextCardModel.labels.add(id); + }); + + break; + } + case ActionTypes.CARD_DUPLICATE__SUCCESS: { + Card.withId(payload.localId).deleteWithRelated(); + const cardModel = Card.upsert(payload.card); + + payload.cardMemberships.forEach(({ userId }) => { + cardModel.users.add(userId); + }); + + payload.cardLabels.forEach(({ labelId }) => { + cardModel.labels.add(labelId); + }); + + break; + } case ActionTypes.CARD_DELETE: Card.withId(payload.id).deleteWithRelated(); diff --git a/client/src/models/Task.js b/client/src/models/Task.js index 1a472718..b990fe21 100755 --- a/client/src/models/Task.js +++ b/client/src/models/Task.js @@ -1,5 +1,6 @@ import { attr, fk } from 'redux-orm'; +import { createLocalId } from '../utils/local-id'; import BaseModel from './BaseModel'; import ActionTypes from '../constants/ActionTypes'; @@ -44,10 +45,24 @@ export default class extends BaseModel { break; case ActionTypes.BOARD_FETCH__SUCCESS: + case ActionTypes.CARD_CREATE_HANDLE: + case ActionTypes.CARD_DUPLICATE__SUCCESS: payload.tasks.forEach((task) => { Task.upsert(task); }); + break; + case ActionTypes.CARD_DUPLICATE: + payload.taskIds.forEach((taskId, index) => { + const taskModel = Task.withId(taskId); + + Task.upsert({ + ...taskModel.ref, + id: `${createLocalId()}-${index}`, // TODO: hack? + cardId: payload.card.id, + }); + }); + break; case ActionTypes.TASK_CREATE: case ActionTypes.TASK_CREATE_HANDLE: diff --git a/client/src/sagas/core/services/cards.js b/client/src/sagas/core/services/cards.js index 40c3db83..eb2d1da4 100644 --- a/client/src/sagas/core/services/cards.js +++ b/client/src/sagas/core/services/cards.js @@ -5,6 +5,7 @@ import request from '../request'; import selectors from '../../../selectors'; import actions from '../../../actions'; import api from '../../../api'; +import i18n from '../../../i18n'; import { createLocalId } from '../../../utils/local-id'; export function* createCard(listId, data, autoOpen) { @@ -41,8 +42,23 @@ export function* createCard(listId, data, autoOpen) { } } -export function* handleCardCreate(card) { - yield put(actions.handleCardCreate(card)); +export function* handleCardCreate({ id }) { + let card; + let cardMemberships; + let cardLabels; + let tasks; + let attachments; + + try { + ({ + item: card, + included: { cardMemberships, cardLabels, tasks, attachments }, + } = yield call(request, api.getCard, id)); + } catch (error) { + return; + } + + yield put(actions.handleCardCreate(card, cardMemberships, cardLabels, tasks, attachments)); } export function* updateCard(id, data) { @@ -106,6 +122,55 @@ export function* transferCurrentCard(boardId, listId, index) { yield call(transferCard, cardId, boardId, listId, index); } +export function* duplicateCard(id) { + const { listId, name } = yield select(selectors.selectCardById, id); + const index = yield select(selectors.selectCardIndexById, id); + + const nextData = { + position: yield select(selectors.selectNextCardPosition, listId, index + 1), + name: `${name} (${i18n.t('common.copy', { + context: 'inline', + })})`, + }; + + const localId = yield call(createLocalId); + const taskIds = yield select(selectors.selectTaskIdsByCardId, id); + + yield put( + actions.duplicateCard( + id, + { + ...nextData, + id: localId, + }, + taskIds, + ), + ); + + let card; + let cardMemberships; + let cardLabels; + let tasks; + + try { + ({ + item: card, + included: { cardMemberships, cardLabels, tasks }, + } = yield call(request, api.duplicateCard, id, nextData)); + } catch (error) { + yield put(actions.duplicateCard.failure(localId, error)); + return; + } + + yield put(actions.duplicateCard.success(localId, card, cardMemberships, cardLabels, tasks)); +} + +export function* duplicateCurrentCard() { + const { cardId } = yield select(selectors.selectPath); + + yield call(duplicateCard, cardId); +} + export function* deleteCard(id) { const { cardId, boardId } = yield select(selectors.selectPath); @@ -147,11 +212,13 @@ export default { handleCardCreate, updateCard, updateCurrentCard, + handleCardUpdate, moveCard, moveCurrentCard, transferCard, transferCurrentCard, - handleCardUpdate, + duplicateCard, + duplicateCurrentCard, deleteCard, deleteCurrentCard, handleCardDelete, diff --git a/client/src/sagas/core/watchers/cards.js b/client/src/sagas/core/watchers/cards.js index 02905150..3fcb5992 100644 --- a/client/src/sagas/core/watchers/cards.js +++ b/client/src/sagas/core/watchers/cards.js @@ -32,6 +32,8 @@ export default function* cardsWatchers() { takeEvery(EntryActionTypes.CURRENT_CARD_TRANSFER, ({ payload: { boardId, listId, index } }) => services.transferCurrentCard(boardId, listId, index), ), + takeEvery(EntryActionTypes.CARD_DUPLICATE, ({ payload: { id } }) => services.duplicateCard(id)), + takeEvery(EntryActionTypes.CURRENT_CARD_DUPLICATE, () => services.duplicateCurrentCard()), takeEvery(EntryActionTypes.CARD_DELETE, ({ payload: { id } }) => services.deleteCard(id)), takeEvery(EntryActionTypes.CURRENT_CARD_DELETE, () => services.deleteCurrentCard()), takeEvery(EntryActionTypes.CARD_DELETE_HANDLE, ({ payload: { card } }) => diff --git a/client/src/selectors/cards.js b/client/src/selectors/cards.js index 8f100d57..d1137dc8 100644 --- a/client/src/selectors/cards.js +++ b/client/src/selectors/cards.js @@ -26,6 +26,24 @@ export const makeSelectCardById = () => export const selectCardById = makeSelectCardById(); +export const makeSelectCardIndexById = () => + createSelector( + orm, + (_, id) => id, + ({ Card }, id) => { + const cardModel = Card.withId(id); + + if (!cardModel) { + return cardModel; + } + + const cardModels = cardModel.list.getFilteredOrderedCardsModelArray(); + return cardModels.findIndex((cardModelItem) => cardModelItem.id === cardModel.id); + }, + ); + +export const selectCardIndexById = makeSelectCardIndexById(); + export const makeSelectUsersByCardId = () => createSelector( orm, @@ -60,6 +78,26 @@ export const makeSelectLabelsByCardId = () => export const selectLabelsByCardId = makeSelectLabelsByCardId(); +export const makeSelectTaskIdsByCardId = () => + createSelector( + orm, + (_, id) => id, + ({ Card }, id) => { + const cardModel = Card.withId(id); + + if (!cardModel) { + return cardModel; + } + + return cardModel + .getOrderedTasksQuerySet() + .toRefArray() + .map((task) => task.id); + }, + ); + +export const selectTaskIdsByCardId = makeSelectTaskIdsByCardId(); + export const makeSelectTasksByCardId = () => createSelector( orm, @@ -286,10 +324,14 @@ export const selectNotificationIdsForCurrentCard = createSelector( export default { makeSelectCardById, selectCardById, + makeSelectCardIndexById, + selectCardIndexById, makeSelectUsersByCardId, selectUsersByCardId, makeSelectLabelsByCardId, selectLabelsByCardId, + makeSelectTaskIdsByCardId, + selectTaskIdsByCardId, makeSelectTasksByCardId, selectTasksByCardId, makeSelectLastActivityIdByCardId, diff --git a/server/api/controllers/cards/duplicate.js b/server/api/controllers/cards/duplicate.js new file mode 100755 index 00000000..918a8ec1 --- /dev/null +++ b/server/api/controllers/cards/duplicate.js @@ -0,0 +1,82 @@ +const Errors = { + NOT_ENOUGH_RIGHTS: { + notEnoughRights: 'Not enough rights', + }, + CARD_NOT_FOUND: { + cardNotFound: 'Card not found', + }, +}; + +module.exports = { + inputs: { + id: { + type: 'string', + regex: /^[0-9]+$/, + required: true, + }, + position: { + type: 'number', + required: true, + }, + name: { + type: 'string', + }, + }, + + exits: { + notEnoughRights: { + responseType: 'forbidden', + }, + cardNotFound: { + responseType: 'notFound', + }, + }, + + async fn(inputs) { + const { currentUser } = this.req; + + const { card, list, board } = await sails.helpers.cards + .getProjectPath(inputs.id) + .intercept('pathNotFound', () => Errors.CARD_NOT_FOUND); + + const boardMembership = await BoardMembership.findOne({ + boardId: card.boardId, + userId: currentUser.id, + }); + + if (!boardMembership) { + throw Errors.CARD_NOT_FOUND; // Forbidden + } + + if (boardMembership.role !== BoardMembership.Roles.EDITOR) { + throw Errors.NOT_ENOUGH_RIGHTS; + } + + const values = _.pick(inputs, ['position', 'name']); + + const { + card: nextCard, + cardMemberships, + cardLabels, + tasks, + } = await sails.helpers.cards.duplicateOne.with({ + board, + list, + record: card, + values: { + ...values, + creatorUser: currentUser, + }, + request: this.req, + }); + + return { + item: nextCard, + included: { + cardMemberships, + cardLabels, + tasks, + }, + }; + }, +}; diff --git a/server/api/helpers/boards/import-from-trello.js b/server/api/helpers/boards/import-from-trello.js index efc74dc0..2ab6e0af 100644 --- a/server/api/helpers/boards/import-from-trello.js +++ b/server/api/helpers/boards/import-from-trello.js @@ -1,3 +1,5 @@ +const POSITION_GAP = 65535; // TODO: move to config + module.exports = { inputs: { user: { @@ -124,7 +126,7 @@ module.exports = { getUsedTrelloLabels().map(async (trelloLabel, index) => { const plankaLabel = await Label.create({ boardId: inputs.board.id, - position: 65535 * (index + 1), // TODO: move to config + position: POSITION_GAP * (index + 1), name: trelloLabel.name || null, color: getPlankaLabelColor(trelloLabel.color), }).fetch(); diff --git a/server/api/helpers/cards/duplicate-one.js b/server/api/helpers/cards/duplicate-one.js new file mode 100644 index 00000000..a63feaac --- /dev/null +++ b/server/api/helpers/cards/duplicate-one.js @@ -0,0 +1,144 @@ +const valuesValidator = (value) => { + if (!_.isPlainObject(value)) { + return false; + } + + if (!_.isUndefined(value.position) && !_.isFinite(value.position)) { + return false; + } + + if (!_.isPlainObject(value.creatorUser)) { + return false; + } + + return true; +}; + +module.exports = { + inputs: { + record: { + type: 'ref', + required: true, + }, + values: { + type: 'ref', + custom: valuesValidator, + required: true, + }, + board: { + type: 'ref', + required: true, + }, + list: { + type: 'ref', + required: true, + }, + request: { + type: 'ref', + }, + }, + + async fn(inputs) { + const { values } = inputs; + + const cards = await sails.helpers.lists.getCards(inputs.record.listId); + + const { position, repositions } = sails.helpers.utils.insertToPositionables( + values.position, + cards, + ); + + repositions.forEach(async ({ id, position: nextPosition }) => { + await Card.update({ + id, + listId: inputs.record.listId, + }).set({ + position: nextPosition, + }); + + sails.sockets.broadcast(`board:${inputs.record.boardId}`, 'cardUpdate', { + item: { + id, + position: nextPosition, + }, + }); + }); + + const card = await Card.create({ + ..._.pick(inputs.record, [ + 'boardId', + 'listId', + 'name', + 'description', + 'dueDate', + 'stopwatch', + ]), + ...values, + position, + creatorUserId: values.creatorUser.id, + }).fetch(); + + const cardMemberships = await sails.helpers.cards.getCardMemberships(inputs.record.id); + const cardMembershipsValues = cardMemberships.map((cardMembership) => ({ + ..._.pick(cardMembership, ['userId']), + cardId: card.id, + })); + const nextCardMemberships = await CardMembership.createEach(cardMembershipsValues).fetch(); + + const cardLabels = await sails.helpers.cards.getCardLabels(inputs.record.id); + const cardLabelsValues = cardLabels.map((cardLabel) => ({ + ..._.pick(cardLabel, ['labelId']), + cardId: card.id, + })); + const nextCardLabels = await CardLabel.createEach(cardLabelsValues).fetch(); + + const tasks = await sails.helpers.cards.getTasks(inputs.record.id); + const tasksValues = tasks.map((task) => ({ + ..._.pick(task, ['position', 'name', 'isCompleted']), + cardId: card.id, + })); + const nextTasks = await Task.createEach(tasksValues).fetch(); + + sails.sockets.broadcast( + `board:${card.boardId}`, + 'cardCreate', + { + item: card, + }, + inputs.request, + ); + + if (values.creatorUser.subscribeToOwnCards) { + await CardSubscription.create({ + cardId: card.id, + userId: card.creatorUserId, + }).tolerate('E_UNIQUE'); + + sails.sockets.broadcast(`user:${card.creatorUserId}`, 'cardUpdate', { + item: { + id: card.id, + isSubscribed: true, + }, + }); + } + + await sails.helpers.actions.createOne.with({ + values: { + card, + type: Action.Types.CREATE_CARD, // TODO: introduce separate type? + data: { + list: _.pick(inputs.list, ['id', 'name']), + }, + user: values.creatorUser, + }, + board: inputs.board, + }); + + return { + card, + cardMemberships: nextCardMemberships, + cardLabels: nextCardLabels, + tasks: nextTasks, + }; + }, +}; diff --git a/server/config/routes.js b/server/config/routes.js index 77f5c43b..8b88df5b 100644 --- a/server/config/routes.js +++ b/server/config/routes.js @@ -55,6 +55,7 @@ module.exports.routes = { 'POST /api/lists/:listId/cards': 'cards/create', 'GET /api/cards/:id': 'cards/show', 'PATCH /api/cards/:id': 'cards/update', + 'POST /api/cards/:id/duplicate': 'cards/duplicate', 'DELETE /api/cards/:id': 'cards/delete', 'POST /api/cards/:cardId/memberships': 'card-memberships/create', 'DELETE /api/cards/:cardId/memberships': 'card-memberships/delete', From a7328102f239a178cd5c968005d0ca442d4cef39 Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Fri, 5 Apr 2024 22:49:02 +0200 Subject: [PATCH 38/42] chore: Update version --- charts/planka/Chart.yaml | 4 ++-- client/.env | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/charts/planka/Chart.yaml b/charts/planka/Chart.yaml index 3f291a93..5a6debee 100644 --- a/charts/planka/Chart.yaml +++ b/charts/planka/Chart.yaml @@ -15,13 +15,13 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.22 +version: 0.1.23 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "1.16.1" +appVersion: "1.16.2" dependencies: - alias: postgresql diff --git a/client/.env b/client/.env index 0718c001..e17aeb7d 100644 --- a/client/.env +++ b/client/.env @@ -1 +1 @@ -REACT_APP_VERSION=1.16.1 +REACT_APP_VERSION=1.16.2 diff --git a/package-lock.json b/package-lock.json index 1bd8b53f..eee91c99 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "planka", - "version": "1.16.1", + "version": "1.16.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "planka", - "version": "1.16.1", + "version": "1.16.2", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index 8e047d5c..ab2bc3d4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "planka", - "version": "1.16.1", + "version": "1.16.2", "private": true, "homepage": "https://plankanban.github.io/planka", "repository": { From 9962a2c8c9117e3efc43bb449b071aafe2de3286 Mon Sep 17 00:00:00 2001 From: leroyloren <57643470+leroyloren@users.noreply.github.com> Date: Sun, 7 Apr 2024 21:58:27 +0200 Subject: [PATCH 39/42] fix: Update Czech translation (#679) --- client/src/locales/cs/core.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/client/src/locales/cs/core.js b/client/src/locales/cs/core.js index 04dfc8d8..40015133 100644 --- a/client/src/locales/cs/core.js +++ b/client/src/locales/cs/core.js @@ -39,9 +39,9 @@ export default { areYouSureYouWantToLeaveBoard: 'Opravdu chcete opustit tuto tabuli?', areYouSureYouWantToLeaveProject: 'Opravdu chcete opustit projekt?', areYouSureYouWantToRemoveThisManagerFromProject: - 'Are you sure you want to remove this manager from the project?', + 'Jste si jisti, že chcete tohoto správce z projektu odebrat?', areYouSureYouWantToRemoveThisMemberFromBoard: - 'Opravdu chcete odstranit tohoto člena z tabule?', + 'Jste si jisti, že chcete tohoto člena odebrat z tabule?', attachment: 'Příloha', attachments: 'Přílohy', authentication: 'Ověření', @@ -55,6 +55,7 @@ export default { cardNotFound_title: 'Karta nenalezena', cardOrActionAreDeleted: 'Karta nebo akce je smazána.', color: 'Barva', + copy_inline: 'copy', createBoard_title: 'Vytvořit tabuli', createLabel_title: 'Vytvořit štítek', createNewOneOrSelectExistingOne: 'Vytvořit nový nebo vyberte
již existující.', @@ -130,7 +131,7 @@ export default { phone: 'Telefon', preferences: 'Volby', pressPasteShortcutToAddAttachmentFromClipboard: - 'Tip: dejte Ctrl-V (Cmd-V na Mac) pro vložení přílohy ze schránky.', + 'Tip: stisknutím Ctrl-V (Cmd-V na Mac) přidáte přílohu ze schránky.', project: 'Projekt', projectNotFound_title: 'Projekt nenalezen', removeManager_title: 'Odstranit vedoucího', @@ -199,6 +200,8 @@ export default { deleteTask: 'Smazat úkol', deleteTask_title: 'Smazat úkol', deleteUser: 'Smazat uživatele', + duplicate: 'Duplikovat', + duplicateCard_title: 'Duplikovat kartu', edit: 'Upravit', editDueDate_title: 'Upravit termín do', editDescription_title: 'Upravit popis', @@ -226,13 +229,13 @@ export default { removeMember: 'Odstranit člena', save: 'Uložit', showAllAttachments: 'Zozbrazit všechny přílohy ({{hidden}} skryté)', - showFewerAttachments: 'Zobrazit méně příloh', showDetails: 'Zobrazit detaily', + showFewerAttachments: 'Zobrazit méně příloh', start: 'Start', stop: 'Stop', subscribe: 'Odebírat', unsubscribe: 'Neodebírat', - uploadNewAvatar: 'Nahrát nového avatara', + uploadNewAvatar: 'Nahrát nový avatar', uploadNewImage: 'Nahrát nový obrázek', }, }, From 90435da0ab7d3048bdf97d3dc9423c51c4181e95 Mon Sep 17 00:00:00 2001 From: Blyamur <409434+blyamur@users.noreply.github.com> Date: Sun, 7 Apr 2024 23:05:22 +0300 Subject: [PATCH 40/42] fix: Update Russian translation (#686) --- client/src/locales/ru/core.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/src/locales/ru/core.js b/client/src/locales/ru/core.js index 138b893a..06520c6f 100644 --- a/client/src/locales/ru/core.js +++ b/client/src/locales/ru/core.js @@ -199,6 +199,8 @@ export default { deleteProject: 'Удалить проект', deleteTask: 'Удалить задачу', deleteUser: 'Удалить пользователя', + duplicate: 'Дублировать', + duplicateCard_title: 'Дублировать карточку', edit: 'Изменить', editBackground: 'Изменить фон', editDueDate: 'Изменить срок', From 2eff8b80f14dfa42eff0675390d347b674ce89cc Mon Sep 17 00:00:00 2001 From: Matthieu Bollot Date: Mon, 8 Apr 2024 00:33:29 +0200 Subject: [PATCH 41/42] feat: Slack bot notifications (#676) --- docker-compose.yml | 20 +++---- server/.env.sample | 19 ++++--- server/api/controllers/cards/delete.js | 1 + server/api/helpers/actions/create-one.js | 28 ++++++++++ server/api/helpers/cards/delete-one.js | 12 +++++ .../api/helpers/notifications/create-one.js | 2 + server/api/helpers/utils/send-email.js | 2 +- .../api/helpers/utils/send-slack-message.js | 53 +++++++++++++++++++ server/config/custom.js | 17 +++--- 9 files changed, 128 insertions(+), 26 deletions(-) create mode 100644 server/api/helpers/utils/send-slack-message.js diff --git a/docker-compose.yml b/docker-compose.yml index 0a294fb1..f7935aa1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -31,14 +31,6 @@ services: # - DEFAULT_ADMIN_NAME=Demo Demo # - DEFAULT_ADMIN_USERNAME=demo - # Email Notifications (https://nodemailer.com/smtp/) - # - SMTP_HOST= - # - SMTP_PORT=587 - # - SMTP_SECURE=true - # - SMTP_USER= - # - SMTP_PASSWORD= - # - SMTP_FROM="Demo Demo" - # - OIDC_ISSUER= # - OIDC_CLIENT_ID= # - OIDC_CLIENT_SECRET= @@ -52,8 +44,16 @@ services: # - OIDC_IGNORE_ROLES=true # - OIDC_ENFORCED=true - # - SLACK_BOT_TOKEN=xoxb-xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxx - # - SLACK_CHANNEL_ID=xxxxxxxxxx + # Email Notifications (https://nodemailer.com/smtp/) + # - SMTP_HOST= + # - SMTP_PORT=587 + # - SMTP_SECURE=true + # - SMTP_USER= + # - SMTP_PASSWORD= + # - SMTP_FROM="Demo Demo" + + # - SLACK_BOT_TOKEN= + # - SLACK_CHANNEL_ID= depends_on: postgres: condition: service_healthy diff --git a/server/.env.sample b/server/.env.sample index fb5a8288..15d66ed7 100644 --- a/server/.env.sample +++ b/server/.env.sample @@ -22,14 +22,6 @@ SECRET_KEY=notsecretkey # DEFAULT_ADMIN_NAME=Demo Demo # DEFAULT_ADMIN_USERNAME=demo -# Email Notifications (https://nodemailer.com/smtp/) -# SMTP_HOST= -# SMTP_PORT=587 -# SMTP_SECURE=true -# SMTP_USER= -# SMTP_PASSWORD= -# SMTP_FROM="Demo Demo" - # OIDC_ISSUER= # OIDC_CLIENT_ID= # OIDC_CLIENT_SECRET= @@ -43,6 +35,17 @@ SECRET_KEY=notsecretkey # OIDC_IGNORE_ROLES=true # OIDC_ENFORCED=true +# Email Notifications (https://nodemailer.com/smtp/) +# SMTP_HOST= +# SMTP_PORT=587 +# SMTP_SECURE=true +# SMTP_USER= +# SMTP_PASSWORD= +# SMTP_FROM="Demo Demo" + +# SLACK_BOT_TOKEN= +# SLACK_CHANNEL_ID= + ## Do not edit this TZ=UTC diff --git a/server/api/controllers/cards/delete.js b/server/api/controllers/cards/delete.js index 84d188d0..51d14a4b 100755 --- a/server/api/controllers/cards/delete.js +++ b/server/api/controllers/cards/delete.js @@ -49,6 +49,7 @@ module.exports = { card = await sails.helpers.cards.deleteOne.with({ record: card, + user: currentUser, request: this.req, }); diff --git a/server/api/helpers/actions/create-one.js b/server/api/helpers/actions/create-one.js index 78d5e0c5..b03adfdc 100644 --- a/server/api/helpers/actions/create-one.js +++ b/server/api/helpers/actions/create-one.js @@ -14,6 +14,30 @@ const valuesValidator = (value) => { return true; }; +const buildAndSendSlackMessage = async (user, card, action) => { + const cardLink = `<${sails.config.custom.baseUrl}/cards/${card.id}|${card.name}>`; + + let markdown; + switch (action.type) { + case Action.Types.CREATE_CARD: + markdown = `${cardLink} was created by ${user.name} in *${action.data.list.name}*`; + + break; + case Action.Types.MOVE_CARD: + markdown = `${cardLink} was moved by ${user.name} to *${action.data.toList.name}*`; + + break; + case Action.Types.COMMENT_CARD: + markdown = `*${user.name}* commented on ${cardLink}:\n>${action.data.text}`; + + break; + default: + return; + } + + await sails.helpers.utils.sendSlackMessage(markdown); +}; + module.exports = { inputs: { values: { @@ -67,6 +91,10 @@ module.exports = { ), ); + if (sails.config.custom.slackBotToken) { + buildAndSendSlackMessage(values.user, values.card, action); + } + return action; }, }; diff --git a/server/api/helpers/cards/delete-one.js b/server/api/helpers/cards/delete-one.js index fb72787f..a947f738 100644 --- a/server/api/helpers/cards/delete-one.js +++ b/server/api/helpers/cards/delete-one.js @@ -1,9 +1,17 @@ +const buildAndSendSlackMessage = async (user, card) => { + await sails.helpers.utils.sendSlackMessage(`*${card.name}* was deleted by ${user.name}`); +}; + module.exports = { inputs: { record: { type: 'ref', required: true, }, + user: { + type: 'ref', + required: true, + }, request: { type: 'ref', }, @@ -21,6 +29,10 @@ module.exports = { }, inputs.request, ); + + if (sails.config.custom.slackBotToken) { + buildAndSendSlackMessage(inputs.user, card); + } } return card; diff --git a/server/api/helpers/notifications/create-one.js b/server/api/helpers/notifications/create-one.js index 271a9179..f24e4bfa 100644 --- a/server/api/helpers/notifications/create-one.js +++ b/server/api/helpers/notifications/create-one.js @@ -27,6 +27,7 @@ const buildAndSendEmail = async (user, board, card, action, notifiableUser) => { `from ${action.data.fromList.name} to ${action.data.toList.name} ` + `on ${board.name}

`, }; + break; case Action.Types.COMMENT_CARD: emailData = { @@ -37,6 +38,7 @@ const buildAndSendEmail = async (user, board, card, action, notifiableUser) => { `on ${board.name}

` + `

${action.data.text}

`, }; + break; default: return; diff --git a/server/api/helpers/utils/send-email.js b/server/api/helpers/utils/send-email.js index 5d9be724..7b8d08bf 100644 --- a/server/api/helpers/utils/send-email.js +++ b/server/api/helpers/utils/send-email.js @@ -25,7 +25,7 @@ module.exports = { sails.log.info('Email sent: %s', info.messageId); } catch (error) { - sails.log.error(error); + sails.log.error(error); // TODO: provide description text? } }, }; diff --git a/server/api/helpers/utils/send-slack-message.js b/server/api/helpers/utils/send-slack-message.js new file mode 100644 index 00000000..573fcf87 --- /dev/null +++ b/server/api/helpers/utils/send-slack-message.js @@ -0,0 +1,53 @@ +const POST_MESSAGE_API_URL = 'https://slack.com/api/chat.postMessage'; + +module.exports = { + inputs: { + markdown: { + type: 'string', + required: true, + }, + }, + + async fn(inputs) { + const headers = { + Authorization: `Bearer ${sails.config.custom.slackBotToken}`, + 'Content-Type': 'application/json; charset=utf-8', + }; + + const body = { + blocks: [ + { + type: 'section', + text: { + type: 'mrkdwn', + text: inputs.markdown, + }, + }, + ], + channel: sails.config.custom.slackChannelId, + }; + + let response; + try { + response = await fetch(POST_MESSAGE_API_URL, { + headers, + method: 'POST', + body: JSON.stringify(body), + }); + } catch (error) { + sails.log.error(error); // TODO: provide description text? + return; + } + + if (!response.ok) { + sails.log.error('Error sending to Slack: %s', response.error); + return; + } + + const responseJson = await response.json(); + + if (!responseJson.ok) { + sails.log.error('Error sending to Slack: %s', responseJson.error); + } + }, +}; diff --git a/server/config/custom.js b/server/config/custom.js index 76473245..ac344d05 100644 --- a/server/config/custom.js +++ b/server/config/custom.js @@ -34,13 +34,6 @@ module.exports.custom = { defaultAdminEmail: process.env.DEFAULT_ADMIN_EMAIL && process.env.DEFAULT_ADMIN_EMAIL.toLowerCase(), - smtpHost: process.env.SMTP_HOST, - smtpPort: process.env.SMTP_PORT || 587, - smtpSecure: process.env.SMTP_SECURE === 'true', - smtpUser: process.env.SMTP_USER, - smtpPassword: process.env.SMTP_PASSWORD, - smtpFrom: process.env.SMTP_FROM, - oidcIssuer: process.env.OIDC_ISSUER, oidcClientId: process.env.OIDC_CLIENT_ID, oidcClientSecret: process.env.OIDC_CLIENT_SECRET, @@ -58,4 +51,14 @@ module.exports.custom = { oidcRedirectUri: `${ sails.config.environment === 'production' ? process.env.BASE_URL : 'http://localhost:3000' }/oidc-callback`, + + smtpHost: process.env.SMTP_HOST, + smtpPort: process.env.SMTP_PORT || 587, + smtpSecure: process.env.SMTP_SECURE === 'true', + smtpUser: process.env.SMTP_USER, + smtpPassword: process.env.SMTP_PASSWORD, + smtpFrom: process.env.SMTP_FROM, + + slackBotToken: process.env.SLACK_BOT_TOKEN, + slackChannelId: process.env.SLACK_CHANNEL_ID, }; From e9bfbc576bf189ac18e34079186a47c7bbf346be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2=20Pedrini?= Date: Mon, 8 Apr 2024 00:50:52 +0200 Subject: [PATCH 42/42] fix: Update Italian translation (#688) --- client/src/locales/it/core.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/client/src/locales/it/core.js b/client/src/locales/it/core.js index f08a9460..1f605b17 100644 --- a/client/src/locales/it/core.js +++ b/client/src/locales/it/core.js @@ -3,10 +3,10 @@ export default { date: 'd/M/yyyy', time: 'p', dateTime: '$t(format:date) $t(format:time)', - longDate: 'MMM d', - longDateTime: "MMMM d 'at' p", - fullDate: 'MMM d, y', - fullDateTime: "MMMM d, y 'at' p", + longDate: 'd MMM', + longDateTime: "d MMMM 'alle' p", + fullDate: 'd MMM, y', + fullDateTime: "d MMMM, y 'alle' p", }, translation: { @@ -21,7 +21,7 @@ export default { administrator: 'Amministratore', all: 'tutto', allChangesWillBeAutomaticallySavedAfterConnectionRestored: - 'All changes will be automatically saved
after connection restored.', + 'Tutte le modifiche verranno salvate
al ripristino della connessione.', areYouSureYouWantToDeleteThisAttachment: 'Sei sicuro di voler eliminare questo allegato?', areYouSureYouWantToDeleteThisBoard: 'Sei sicuro di voler eliminare questa bacheca?', areYouSureYouWantToDeleteThisCard: 'Sei sicuro di voler eliminare questa card?', @@ -50,6 +50,7 @@ export default { cardNotFound_title: 'Card non trovata', cardOrActionAreDeleted: "La card o l'azione vengono eliminate.", color: 'Colore', + copy_inline: 'copia', createBoard_title: 'Crea Bacheca', createLabel_title: 'Crea Etichetta', createNewOneOrSelectExistingOne: 'Crea nuovo o seleziona
esistente.', @@ -94,8 +95,10 @@ export default { filterByLabels_title: 'Filtra per Etichetta', filterByMembers_title: 'Filtra per Membro', fromComputer_title: 'Dal Computer', + fromTrello: 'Da Trello', general: 'Generale', hours: 'Ore', + importBoard_title: 'Importa Board', invalidCurrentPassword: 'Password corrente non valida', labels: 'Etichette', language: 'Lingua', @@ -123,7 +126,7 @@ export default { phone: 'Telefono', preferences: 'Preferenze', pressPasteShortcutToAddAttachmentFromClipboard: - 'Tip: prmi Ctrl-V (Cmd-V on Mac) per aggiungere un allegato dalla clipboard.', + 'Consiglio: premi Ctrl-V (Cmd-V on Mac) per aggiungere un allegato dalla clipboard.', project: 'Progetto', projectNotFound_title: 'Progetto non trovato', removeManager_title: 'Rimuovi Manager', @@ -193,6 +196,8 @@ export default { deleteTask: 'Elimina task', deleteTask_title: 'Elimina Task', deleteUser: 'Elimina utente', + duplicate: 'Duplica', + duplicateCard_title: 'Duplica Card', edit: 'Modifica', editDueDate_title: 'Modifica data di scadenza', editDescription_title: 'Modifica Descrizione', @@ -204,9 +209,10 @@ export default { editTitle_title: 'Modifica Titolo', editUsername_title: 'Modifica Username', hideDetails: 'Nascondi dettagli', + import: 'Importa', leaveBoard: 'Lascia bacheca', leaveProject: 'Lascia progetto', - logOut_title: 'Log Out', + logOut_title: 'Disconnettiti', makeCover_title: 'Crea Cover', move: 'Muovi', moveCard_title: 'Muovi Card',