+
# OIDC_ISSUER=
# OIDC_CLIENT_ID=
# OIDC_CLIENT_SECRET=
diff --git a/server/api/controllers/cards/create.js b/server/api/controllers/cards/create.js
index ab0c444..b847c3e 100755
--- a/server/api/controllers/cards/create.js
+++ b/server/api/controllers/cards/create.js
@@ -78,12 +78,12 @@ module.exports = {
async fn(inputs) {
const { currentUser } = this.req;
- const { list } = await sails.helpers.lists
+ const { board, list } = await sails.helpers.lists
.getProjectPath(inputs.listId)
.intercept('pathNotFound', () => Errors.LIST_NOT_FOUND);
const boardMembership = await BoardMembership.findOne({
- boardId: list.boardId,
+ boardId: board.id,
userId: currentUser.id,
});
@@ -99,6 +99,7 @@ module.exports = {
const card = await sails.helpers.cards.createOne
.with({
+ board,
values: {
...values,
list,
diff --git a/server/api/controllers/comment-actions/create.js b/server/api/controllers/comment-actions/create.js
index ddf4b99..7712a3a 100755
--- a/server/api/controllers/comment-actions/create.js
+++ b/server/api/controllers/comment-actions/create.js
@@ -32,12 +32,12 @@ module.exports = {
async fn(inputs) {
const { currentUser } = this.req;
- const { card } = await sails.helpers.cards
+ const { board, card } = await sails.helpers.cards
.getProjectPath(inputs.cardId)
.intercept('pathNotFound', () => Errors.CARD_NOT_FOUND);
const boardMembership = await BoardMembership.findOne({
- boardId: card.boardId,
+ boardId: board.id,
userId: currentUser.id,
});
@@ -55,6 +55,7 @@ module.exports = {
};
const action = await sails.helpers.actions.createOne.with({
+ board,
values: {
...values,
card,
diff --git a/server/api/helpers/actions/create-one.js b/server/api/helpers/actions/create-one.js
index e96df93..78d5e0c 100644
--- a/server/api/helpers/actions/create-one.js
+++ b/server/api/helpers/actions/create-one.js
@@ -21,6 +21,10 @@ module.exports = {
custom: valuesValidator,
required: true,
},
+ board: {
+ type: 'ref',
+ required: true,
+ },
request: {
type: 'ref',
},
@@ -56,6 +60,9 @@ module.exports = {
userId,
action,
},
+ user: values.user,
+ board: inputs.board,
+ card: values.card,
}),
),
);
diff --git a/server/api/helpers/cards/create-one.js b/server/api/helpers/cards/create-one.js
index e1a96b4..847a00c 100644
--- a/server/api/helpers/cards/create-one.js
+++ b/server/api/helpers/cards/create-one.js
@@ -25,6 +25,10 @@ module.exports = {
custom: valuesValidator,
required: true,
},
+ board: {
+ type: 'ref',
+ required: true,
+ },
request: {
type: 'ref',
},
@@ -104,6 +108,7 @@ module.exports = {
},
user: values.creatorUser,
},
+ board: inputs.board,
});
return card;
diff --git a/server/api/helpers/cards/update-one.js b/server/api/helpers/cards/update-one.js
index 1a78f8d..4363f9b 100644
--- a/server/api/helpers/cards/update-one.js
+++ b/server/api/helpers/cards/update-one.js
@@ -232,6 +232,7 @@ module.exports = {
toList: _.pick(values.list, ['id', 'name']),
},
},
+ board: inputs.board,
});
}
diff --git a/server/api/helpers/notifications/create-one.js b/server/api/helpers/notifications/create-one.js
index cc6a0b6..271a917 100644
--- a/server/api/helpers/notifications/create-one.js
+++ b/server/api/helpers/notifications/create-one.js
@@ -14,6 +14,40 @@ const valuesValidator = (value) => {
return true;
};
+// TODO: use templates (views) to build html
+const buildAndSendEmail = async (user, board, card, action, notifiableUser) => {
+ let emailData;
+ switch (action.type) {
+ case Action.Types.MOVE_CARD:
+ emailData = {
+ subject: `${user.name} moved ${card.name} from ${action.data.fromList.name} to ${action.data.toList.name} on ${board.name}`,
+ html:
+ `${user.name} moved ` +
+ `${card.name} ` +
+ `from ${action.data.fromList.name} to ${action.data.toList.name} ` +
+ `on ${board.name}
`,
+ };
+ break;
+ case Action.Types.COMMENT_CARD:
+ emailData = {
+ subject: `${user.name} left a new comment to ${card.name} on ${board.name}`,
+ html:
+ `${user.name} left a new comment to ` +
+ `${card.name} ` +
+ `on ${board.name}
` +
+ `${action.data.text}
`,
+ };
+ break;
+ default:
+ return;
+ }
+
+ await sails.helpers.utils.sendEmail.with({
+ ...emailData,
+ to: notifiableUser.email,
+ });
+};
+
module.exports = {
inputs: {
values: {
@@ -21,6 +55,18 @@ module.exports = {
custom: valuesValidator,
required: true,
},
+ user: {
+ type: 'ref',
+ required: true,
+ },
+ board: {
+ type: 'ref',
+ required: true,
+ },
+ card: {
+ type: 'ref',
+ required: true,
+ },
},
async fn(inputs) {
@@ -40,6 +86,17 @@ module.exports = {
item: notification,
});
+ if (sails.hooks.smtp.isActive()) {
+ let notifiableUser;
+ if (values.user) {
+ notifiableUser = values.user;
+ } else {
+ notifiableUser = await sails.helpers.users.getOne(notification.userId);
+ }
+
+ buildAndSendEmail(inputs.user, inputs.board, inputs.card, values.action, notifiableUser);
+ }
+
return notification;
},
};
diff --git a/server/api/helpers/utils/send-email.js b/server/api/helpers/utils/send-email.js
new file mode 100644
index 0000000..5d9be72
--- /dev/null
+++ b/server/api/helpers/utils/send-email.js
@@ -0,0 +1,31 @@
+module.exports = {
+ inputs: {
+ to: {
+ type: 'string',
+ required: true,
+ },
+ subject: {
+ type: 'string',
+ required: true,
+ },
+ html: {
+ type: 'string',
+ required: true,
+ },
+ },
+
+ async fn(inputs) {
+ const transporter = sails.hooks.smtp.getTransporter(); // TODO: check if active?
+
+ try {
+ const info = await transporter.sendMail({
+ ...inputs,
+ from: sails.config.custom.smtpFrom,
+ });
+
+ sails.log.info('Email sent: %s', info.messageId);
+ } catch (error) {
+ sails.log.error(error);
+ }
+ },
+};
diff --git a/server/api/hooks/smtp/index.js b/server/api/hooks/smtp/index.js
new file mode 100644
index 0000000..4cd0503
--- /dev/null
+++ b/server/api/hooks/smtp/index.js
@@ -0,0 +1,35 @@
+const nodemailer = require('nodemailer');
+
+module.exports = function smtpServiceHook(sails) {
+ let transporter = null;
+
+ return {
+ /**
+ * Runs when this Sails app loads/lifts.
+ */
+
+ async initialize() {
+ if (sails.config.custom.smtpHost) {
+ transporter = nodemailer.createTransport({
+ pool: true,
+ host: sails.config.custom.smtpHost,
+ port: sails.config.custom.smtpPort,
+ secure: sails.config.custom.smtpSecure,
+ auth: sails.config.custom.smtpUser && {
+ user: sails.config.custom.smtpUser,
+ pass: sails.config.custom.smtpPassword,
+ },
+ });
+ sails.log.info('SMTP hook has been loaded successfully');
+ }
+ },
+
+ getTransporter() {
+ return transporter;
+ },
+
+ isActive() {
+ return transporter !== null;
+ },
+ };
+};
diff --git a/server/config/custom.js b/server/config/custom.js
index f074575..7647324 100644
--- a/server/config/custom.js
+++ b/server/config/custom.js
@@ -34,6 +34,13 @@ 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,
diff --git a/server/package-lock.json b/server/package-lock.json
index 05527a7..93453a8 100644
--- a/server/package-lock.json
+++ b/server/package-lock.json
@@ -15,6 +15,7 @@
"lodash": "^4.17.21",
"moment": "^2.29.4",
"move-file": "^2.1.0",
+ "nodemailer": "^6.9.12",
"openid-client": "^5.6.1",
"rimraf": "^5.0.5",
"sails": "^1.5.7",
@@ -5257,6 +5258,14 @@
}
}
},
+ "node_modules/nodemailer": {
+ "version": "6.9.12",
+ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.12.tgz",
+ "integrity": "sha512-pnLo7g37Br3jXbF0bl5DekBJihm2q+3bB3l2o/B060sWmb5l+VqeScAQCBqaQ+5ezRZFzW5SciZNGdRDEbq89w==",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
"node_modules/nodemon": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz",
@@ -12852,6 +12861,11 @@
"whatwg-url": "^5.0.0"
}
},
+ "nodemailer": {
+ "version": "6.9.12",
+ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.12.tgz",
+ "integrity": "sha512-pnLo7g37Br3jXbF0bl5DekBJihm2q+3bB3l2o/B060sWmb5l+VqeScAQCBqaQ+5ezRZFzW5SciZNGdRDEbq89w=="
+ },
"nodemon": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz",
diff --git a/server/package.json b/server/package.json
index 59bb2f7..67fc5e0 100644
--- a/server/package.json
+++ b/server/package.json
@@ -36,6 +36,7 @@
"lodash": "^4.17.21",
"moment": "^2.29.4",
"move-file": "^2.1.0",
+ "nodemailer": "^6.9.12",
"openid-client": "^5.6.1",
"rimraf": "^5.0.5",
"sails": "^1.5.7",
From bb358e01dd6ecdb9bb07463f66c25dc241e63f23 Mon Sep 17 00:00:00 2001
From: Maksim Eltyshev
Date: Fri, 22 Mar 2024 00:52:45 +0100
Subject: [PATCH 07/11] 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 04e8140..23f62c5 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.18
+version: 0.1.19
# 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.7"
+appVersion: "1.16.0"
dependencies:
- alias: postgresql
diff --git a/client/.env b/client/.env
index 9e7b08c..3f08ab3 100644
--- a/client/.env
+++ b/client/.env
@@ -1 +1 @@
-REACT_APP_VERSION=1.15.7
+REACT_APP_VERSION=1.16.0
diff --git a/package-lock.json b/package-lock.json
index a13d186..c288e72 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "planka",
- "version": "1.15.7",
+ "version": "1.16.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "planka",
- "version": "1.15.7",
+ "version": "1.16.0",
"hasInstallScript": true,
"license": "AGPL-3.0",
"dependencies": {
diff --git a/package.json b/package.json
index 68f3df1..77f698a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "planka",
- "version": "1.15.7",
+ "version": "1.16.0",
"private": true,
"homepage": "https://plankanban.github.io/planka",
"repository": {
From 1a5a853fa39ae636ccf0ba5bb3d29fe7ffa0097a Mon Sep 17 00:00:00 2001
From: Maksim Eltyshev
Date: Fri, 22 Mar 2024 14:26:23 +0100
Subject: [PATCH 08/11] fix: Fix scrollbar styles
---
.../BoardMembershipsStep/BoardMembershipsStep.module.scss | 1 -
client/src/components/Boards/Boards.module.scss | 1 -
client/src/components/Header/NotificationsStep.module.scss | 1 -
client/src/components/LabelsStep/LabelsStep.module.scss | 1 -
client/src/components/List/List.module.scss | 1 -
client/src/components/Memberships/AddStep/AddStep.module.scss | 1 -
6 files changed, 6 deletions(-)
diff --git a/client/src/components/BoardMembershipsStep/BoardMembershipsStep.module.scss b/client/src/components/BoardMembershipsStep/BoardMembershipsStep.module.scss
index deec2a3..6d50f19 100644
--- a/client/src/components/BoardMembershipsStep/BoardMembershipsStep.module.scss
+++ b/client/src/components/BoardMembershipsStep/BoardMembershipsStep.module.scss
@@ -4,7 +4,6 @@
max-height: 60vh;
overflow-x: hidden;
overflow-y: auto;
- scrollbar-width: thin;
width: 100%;
&::-webkit-scrollbar {
diff --git a/client/src/components/Boards/Boards.module.scss b/client/src/components/Boards/Boards.module.scss
index 848dbe5..e38de2d 100644
--- a/client/src/components/Boards/Boards.module.scss
+++ b/client/src/components/Boards/Boards.module.scss
@@ -85,7 +85,6 @@
height: 56px;
overflow-x: auto;
overflow-y: hidden;
- scrollbar-width: thin;
&:hover {
height: 38px;
diff --git a/client/src/components/Header/NotificationsStep.module.scss b/client/src/components/Header/NotificationsStep.module.scss
index cdad65b..a86a0e9 100644
--- a/client/src/components/Header/NotificationsStep.module.scss
+++ b/client/src/components/Header/NotificationsStep.module.scss
@@ -49,7 +49,6 @@
max-height: 60vh;
overflow-x: hidden;
overflow-y: auto;
- scrollbar-width: thin;
&::-webkit-scrollbar {
width: 5px;
diff --git a/client/src/components/LabelsStep/LabelsStep.module.scss b/client/src/components/LabelsStep/LabelsStep.module.scss
index c5ec023..1be274c 100644
--- a/client/src/components/LabelsStep/LabelsStep.module.scss
+++ b/client/src/components/LabelsStep/LabelsStep.module.scss
@@ -25,7 +25,6 @@
max-height: 60vh;
overflow-x: hidden;
overflow-y: auto;
- scrollbar-width: thin;
&::-webkit-scrollbar {
width: 5px;
diff --git a/client/src/components/List/List.module.scss b/client/src/components/List/List.module.scss
index 7b47c89..b1a7096 100644
--- a/client/src/components/List/List.module.scss
+++ b/client/src/components/List/List.module.scss
@@ -43,7 +43,6 @@
max-height: calc(100vh - 268px);
overflow-x: hidden;
overflow-y: auto;
- scrollbar-width: thin;
width: 290px;
&:hover {
diff --git a/client/src/components/Memberships/AddStep/AddStep.module.scss b/client/src/components/Memberships/AddStep/AddStep.module.scss
index 95be8d0..917142f 100644
--- a/client/src/components/Memberships/AddStep/AddStep.module.scss
+++ b/client/src/components/Memberships/AddStep/AddStep.module.scss
@@ -4,7 +4,6 @@
max-height: 60vh;
overflow-x: hidden;
overflow-y: auto;
- scrollbar-width: thin;
&::-webkit-scrollbar {
width: 5px;
From 9d95ed6c41d6195b87d49b23e415d4c98444815d Mon Sep 17 00:00:00 2001
From: Maksim Eltyshev
Date: Tue, 26 Mar 2024 14:07:07 +0100
Subject: [PATCH 09/11] fix: Fix OIDC authentication error when redirecting
from another tab
Closes #650
---
client/src/sagas/login/services/login.js | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/client/src/sagas/login/services/login.js b/client/src/sagas/login/services/login.js
index ef02a38..7340307 100644
--- a/client/src/sagas/login/services/login.js
+++ b/client/src/sagas/login/services/login.js
@@ -33,10 +33,10 @@ export function* authenticateUsingOidc() {
const oidcConfig = yield select(selectors.selectOidcConfig);
const state = nanoid();
- window.sessionStorage.setItem('oidc-state', state);
+ window.localStorage.setItem('oidc-state', state);
const nonce = nanoid();
- window.sessionStorage.setItem('oidc-nonce', nonce);
+ window.localStorage.setItem('oidc-nonce', nonce);
let redirectUrl = `${oidcConfig.authorizationUrl}`;
redirectUrl += `&state=${encodeURIComponent(state)}`;
@@ -49,11 +49,11 @@ export function* authenticateUsingOidcCallback() {
// https://github.com/plankanban/planka/issues/511#issuecomment-1771385639
const params = new URLSearchParams(window.location.hash.substring(1) || window.location.search);
- const state = window.sessionStorage.getItem('oidc-state');
- window.sessionStorage.removeItem('oidc-state');
+ const state = window.localStorage.getItem('oidc-state');
+ window.localStorage.removeItem('oidc-state');
- const nonce = window.sessionStorage.getItem('oidc-nonce');
- window.sessionStorage.removeItem('oidc-nonce');
+ const nonce = window.localStorage.getItem('oidc-nonce');
+ window.localStorage.removeItem('oidc-nonce');
yield put(replace(Paths.LOGIN));
From d911030831ceb75581b47513d38fc21d838abf88 Mon Sep 17 00:00:00 2001
From: Maksim Eltyshev
Date: Tue, 26 Mar 2024 14:08:59 +0100
Subject: [PATCH 10/11] 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 23f62c5..8ecb658 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.19
+version: 0.1.20
# 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.0"
+appVersion: "1.16.1"
dependencies:
- alias: postgresql
diff --git a/client/.env b/client/.env
index 3f08ab3..0718c00 100644
--- a/client/.env
+++ b/client/.env
@@ -1 +1 @@
-REACT_APP_VERSION=1.16.0
+REACT_APP_VERSION=1.16.1
diff --git a/package-lock.json b/package-lock.json
index c288e72..1bd8b53 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "planka",
- "version": "1.16.0",
+ "version": "1.16.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "planka",
- "version": "1.16.0",
+ "version": "1.16.1",
"hasInstallScript": true,
"license": "AGPL-3.0",
"dependencies": {
diff --git a/package.json b/package.json
index 77f698a..e880d0a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "planka",
- "version": "1.16.0",
+ "version": "1.16.1",
"private": true,
"homepage": "https://plankanban.github.io/planka",
"repository": {
From d0335209276196cff6a700316a7f00214fe4553f Mon Sep 17 00:00:00 2001
From: piero <46724833+pbackz@users.noreply.github.com>
Date: Wed, 3 Apr 2024 18:59:23 +0000
Subject: [PATCH 11/11] fix: Update HorizontalPodAutoscaler version and spec in
chart (#666)
Closes #667
---
charts/planka/Chart.yaml | 2 +-
charts/planka/README.md | 5 +++--
charts/planka/templates/hpa.yaml | 10 +++++++---
3 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/charts/planka/Chart.yaml b/charts/planka/Chart.yaml
index 8ecb658..1d733e7 100644
--- a/charts/planka/Chart.yaml
+++ b/charts/planka/Chart.yaml
@@ -15,7 +15,7 @@ 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.20
+version: 0.1.21
# 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
diff --git a/charts/planka/README.md b/charts/planka/README.md
index ed305b0..f9250e1 100644
--- a/charts/planka/README.md
+++ b/charts/planka/README.md
@@ -46,7 +46,7 @@ helm install planka . --set secretkey=$SECRETKEY \
--set admin_email="demo@demo.demo" \
--set admin_password="demo" \
--set admin_name="Demo Demo" \
---set admin_username="demo"
+--set admin_username="demo" \
--set ingress.enabled=true \
--set ingress.hosts[0].host=planka.example.dev \
@@ -55,7 +55,7 @@ helm install planka . --set secretkey=$SECRETKEY \
--set admin_email="demo@demo.demo" \
--set admin_password="demo" \
--set admin_name="Demo Demo" \
---set admin_username="demo"
+--set admin_username="demo" \
--set ingress.enabled=true \
--set ingress.hosts[0].host=planka.example.dev \
--set ingress.tls[0].secretName=planka-tls \
@@ -76,6 +76,7 @@ admin_name: "Demo Demo"
admin_username: "demo"
# Admin user
+# Ingress
ingress:
enabled: true
hosts:
diff --git a/charts/planka/templates/hpa.yaml b/charts/planka/templates/hpa.yaml
index 09e4c39..257a09d 100644
--- a/charts/planka/templates/hpa.yaml
+++ b/charts/planka/templates/hpa.yaml
@@ -1,5 +1,5 @@
{{- if .Values.autoscaling.enabled }}
-apiVersion: autoscaling/v2beta1
+apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "planka.fullname" . }}
@@ -17,12 +17,16 @@ spec:
- type: Resource
resource:
name: cpu
- targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
+ target:
+ type: Utilization
+ averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
- type: Resource
resource:
name: memory
- targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
+ target:
+ type: Utilization
+ averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
{{- end }}
{{- end }}