Compare commits

..

7 Commits

Author SHA1 Message Date
Maksim Eltyshev
d5d3f1de44 chore: Update version 2026-02-23 18:44:06 +01:00
Maksim Eltyshev
4e9e842e3d chore: Update server dependencies 2026-02-23 18:12:14 +01:00
Fabian Reinold
605dcace54 fix(gravatar): Update hash algorithm to SHA-256 for improved security (#1550) 2026-02-23 16:59:55 +01:00
SnoozeFreddo
61753f08eb fix(helm): Add writable temp directory mounts when readOnlyRootFilesystem is enabled (#1542) 2026-02-20 16:18:30 +01:00
Maksim Eltyshev
52c96c6c8f fix(platform): Make app compatible with Windows 2026-02-19 20:15:28 +01:00
Maksim Eltyshev
2a1760393f fix(dropzone): Prevent dropzone from overflowing content 2026-02-19 17:09:21 +01:00
seals187
7758312e05 fix(backup): Improve backup/restore scripts, allow specifying backup directory (#1541) 2026-02-19 13:13:12 +01:00
19 changed files with 625 additions and 477 deletions

View File

@@ -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: 2.0.1
version: 2.0.2
# 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: "2.0.1"
appVersion: "2.0.2"
dependencies:
- alias: postgresql

View File

@@ -70,6 +70,12 @@ spec:
- mountPath: /app/logs
subPath: app-logs
name: emptydir
- mountPath: /app/.tmp
subPath: app-tmp
name: emptydir
- mountPath: /tmp
subPath: tmp
name: emptydir
{{- end }}
{{- /* Extra volume mounts */}}
{{- range .Values.extraMounts }}

View File

@@ -1,4 +1,13 @@
# [2.0.1] - 2026-02-17
# [2.0.2] - 2026-02-23
### Fixed
* Prevent dropzone from overflowing content
* Update Gravatar hash algorithm
* Improve backup and restore scripts
* Improve installation on Windows and containerized environments
## [2.0.1] - 2026-02-17
### Fixed

View File

@@ -132,7 +132,11 @@ const AddAttachmentZone = React.memo(({ children }) => {
<>
{/* eslint-disable-next-line react/jsx-props-no-spreading */}
<div {...getRootProps()}>
{isDragActive && <div className={styles.dropzone}>{t('common.dropFileToUpload')}</div>}
{isDragActive && (
<div className={styles.dropzone}>
<div className={styles.dropzoneText}>{t('common.dropFileToUpload')}</div>
</div>
)}
{children}
{/* eslint-disable-next-line react/jsx-props-no-spreading */}
<input {...getInputProps()} />

View File

@@ -8,13 +8,18 @@
background: white;
font-size: 20px;
font-weight: bold;
height: 100%;
inset: 0;
line-height: 30px;
opacity: 0.7;
padding: 200px 50px;
position: absolute;
text-align: center;
width: 100%;
z-index: 2001;
}
.dropzoneText {
left: 50%;
position: absolute;
top: min(200px, 50%);
transform: translateX(-50%) translateY(-50%);
}
}

View File

@@ -68,7 +68,11 @@ const AddImageZone = React.memo(({ children, onCreate }) => {
return (
/* eslint-disable-next-line react/jsx-props-no-spreading */
<div {...getRootProps()}>
{isDragActive && <div className={styles.dropzone}>{t('common.dropFileToUpload')}</div>}
{isDragActive && (
<div className={styles.dropzone}>
<div className={styles.dropzoneText}>{t('common.dropFileToUpload')}</div>
</div>
)}
{children}
{/* eslint-disable-next-line react/jsx-props-no-spreading */}
<input {...getInputProps()} />

View File

@@ -8,13 +8,18 @@
background: white;
font-size: 20px;
font-weight: bold;
height: 100%;
inset: 0;
line-height: 30px;
opacity: 0.7;
padding-top: 200px;
position: absolute;
text-align: center;
width: 100%;
z-index: 2001;
}
.dropzoneText {
left: 50%;
position: absolute;
top: min(200px, 50%);
transform: translateX(-50%) translateY(-50%);
}
}

View File

@@ -1 +1 @@
export default '2.0.1';
export default '2.0.2';

View File

@@ -1,13 +1,22 @@
#!/bin/bash
# Stop on Error
# Stop on error
set -e
# Configure those to match your PLANKA Docker container names
PLANKA_DOCKER_CONTAINER_POSTGRES="planka-postgres-1"
PLANKA_DOCKER_CONTAINER_PLANKA="planka-planka-1"
# Configure those to match your Docker container names
DOCKER_CONTAINER_POSTGRES="planka-postgres-1"
DOCKER_CONTAINER_PLANKA="planka-planka-1"
# Use provided directory or default to current directory
BACKUP_DIR="${1:-$(pwd)}"
if [ -z "$1" ]; then
echo "No backup directory specified, backing up to current directory: $BACKUP_DIR"
else
echo "Backing up to: $BACKUP_DIR"
fi
echo
# Create Temporary folder
if date --version >/dev/null 2>&1; then
# GNU date (Linux)
BACKUP_DATETIME=$(date --utc +%FT%H-%M-%SZ)
@@ -15,28 +24,30 @@ else
# BSD date (macOS)
BACKUP_DATETIME=$(date -u +%FT%H-%M-%SZ)
fi
mkdir -p "$BACKUP_DATETIME-backup"
# Dump DB into SQL File
BACKUP_TEMP="$BACKUP_DIR/$BACKUP_DATETIME-backup"
# Create temporary directory
mkdir -p "$BACKUP_TEMP"
echo -n "Exporting postgres database ... "
docker exec -t "$PLANKA_DOCKER_CONTAINER_POSTGRES" pg_dumpall -c -U postgres > "$BACKUP_DATETIME-backup/postgres.sql"
docker exec -t "$DOCKER_CONTAINER_POSTGRES" pg_dumpall -c -U postgres > "$BACKUP_TEMP/postgres.sql"
echo "Success!"
echo
# Export Docker Volume
echo -n "Exporting data volume ... "
docker run --rm --volumes-from "$PLANKA_DOCKER_CONTAINER_PLANKA" -v "$(pwd)/$BACKUP_DATETIME-backup:/backup" ubuntu cp -r /app/data /backup/data
docker run --rm --volumes-from "$DOCKER_CONTAINER_PLANKA" -v "$BACKUP_TEMP:/backup" node:22-alpine cp -r /app/data /backup/data
echo "Success!"
echo
# Create tgz
echo -n "Creating final tarball $BACKUP_DATETIME-backup.tgz ... "
tar -czf "$BACKUP_DATETIME-backup.tgz" \
"$BACKUP_DATETIME-backup/postgres.sql" \
"$BACKUP_DATETIME-backup/data"
tar -C "$BACKUP_DIR" -czf "$BACKUP_TEMP.tgz" "$BACKUP_DATETIME-backup"
echo "Success!"
echo
# Remove source files
echo -n "Cleaning up temporary files and folders ... "
rm -rf "$BACKUP_DATETIME-backup"
echo -n "Cleaning up temporary files and directories ... "
rm -rf "$BACKUP_TEMP"
echo "Success!"
echo
echo "Backup Complete!"

View File

@@ -1,31 +1,41 @@
#!/bin/bash
# Stop on Error
# Stop on error
set -e
# Configure those to match your PLANKA Docker container names
PLANKA_DOCKER_CONTAINER_POSTGRES="planka-postgres-1"
PLANKA_DOCKER_CONTAINER_PLANKA="planka-planka-1"
# Configure those to match your Docker container names
DOCKER_CONTAINER_POSTGRES="planka-postgres-1"
DOCKER_CONTAINER_PLANKA="planka-planka-1"
# Extract tgz archive
PLANKA_BACKUP_ARCHIVE_TGZ=$1
PLANKA_BACKUP_ARCHIVE=$(basename "$PLANKA_BACKUP_ARCHIVE_TGZ" .tgz)
echo -n "Extracting tarball $PLANKA_BACKUP_ARCHIVE_TGZ ... "
tar -xzf "$PLANKA_BACKUP_ARCHIVE_TGZ"
# Use provided archive
BACKUP_ARCHIVE="$1"
if [ -z "$BACKUP_ARCHIVE" ]; then
echo "Usage: $0 <backup-archive.tgz>"
exit 1
fi
BACKUP_DIR=$(dirname "$BACKUP_ARCHIVE")
BACKUP_TEMP="$BACKUP_DIR/$(basename "$BACKUP_ARCHIVE" .tgz)"
echo -n "Extracting tarball $BACKUP_ARCHIVE ... "
tar -C "$BACKUP_DIR" -xzf "$BACKUP_ARCHIVE"
echo "Success!"
echo
# Import Database
echo -n "Importing postgres database ... "
cat "$PLANKA_BACKUP_ARCHIVE/postgres.sql" | docker exec -i "$PLANKA_DOCKER_CONTAINER_POSTGRES" psql -U postgres
cat "$BACKUP_TEMP/postgres.sql" | docker exec -i "$DOCKER_CONTAINER_POSTGRES" psql -U postgres
echo "Success!"
echo
# Restore Docker Volume
echo -n "Importing data volume ... "
docker run --rm --volumes-from "$PLANKA_DOCKER_CONTAINER_PLANKA" -v "$(pwd)/$PLANKA_BACKUP_ARCHIVE:/backup" ubuntu cp -rf /backup/data/. /app/data
docker run --rm --user root --volumes-from "$DOCKER_CONTAINER_PLANKA" -v "$BACKUP_TEMP:/backup" node:22-alpine sh -c "cp -rf /backup/data/. /app/data && chown -R node:node /app/data/*"
echo "Success!"
echo
echo -n "Cleaning up temporary files and folders ... "
rm -r "$PLANKA_BACKUP_ARCHIVE"
echo -n "Cleaning up temporary files and directories ... "
rm -r "$BACKUP_TEMP"
echo "Success!"
echo
echo "Restore complete!"

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "planka",
"version": "2.0.1",
"version": "2.0.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "planka",
"version": "2.0.1",
"version": "2.0.2",
"hasInstallScript": true,
"dependencies": {
"concurrently": "^9.2.1",

View File

@@ -1,6 +1,6 @@
{
"name": "planka",
"version": "2.0.1",
"version": "2.0.2",
"private": true,
"scripts": {
"client:build": "npm run build --prefix client",

View File

@@ -20,7 +20,7 @@ module.exports = {
return null;
}
const hash = crypto.createHash('md5').update(inputs.record.email).digest('hex');
const hash = crypto.createHash('sha256').update(inputs.record.email).digest('hex');
return `${sails.config.custom.gravatarBaseUrl}${hash}?s=180&d=initials`;
},
};

View File

@@ -4,8 +4,14 @@
*/
const { execFile } = require('child_process');
const path = require('path');
const util = require('util');
const PYTHON_PATH =
process.platform === 'win32'
? path.join(sails.config.appPath, '.venv', 'Scripts', 'python.exe')
: path.join(sails.config.appPath, '.venv', 'bin', 'python');
const promisifyExecFile = util.promisify(execFile);
module.exports = {
@@ -27,9 +33,9 @@ module.exports = {
async fn(inputs) {
try {
await promisifyExecFile(
`${sails.config.appPath}/.venv/bin/python3`,
PYTHON_PATH,
[
`${sails.config.appPath}/utils/send_notifications.py`,
path.join(sails.config.appPath, 'utils', 'send_notifications.py'),
JSON.stringify(inputs.services),
inputs.title,
JSON.stringify(inputs.bodyByFormat),

891
server/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,7 @@
"db:upgrade": "node db/upgrade.js",
"postinstall": "patch-package && npm run setup-python",
"lint": "eslint . --max-warnings=0 --report-unused-disable-directives && echo '✔ Your .js files look good.'",
"setup-python": "python3 -m venv .venv && .venv/bin/pip3 install -r requirements.txt",
"setup-python": "node setup-python.js",
"start": "nodemon",
"start:prod": "cross-env NODE_ENV=production node app.js --prod",
"swagger:generate": "node generate-swagger.js",
@@ -44,20 +44,17 @@
}
},
"overrides": {
"body-parser": {
"qs": "^6.14.1"
},
"waterline-utils": {
"qs": "^6.14.1"
"qs": "^6.15.0"
}
},
"dependencies": {
"@aws-sdk/client-s3": "^3.982.0",
"@aws-sdk/lib-storage": "^3.982.0",
"@aws-sdk/client-s3": "^3.995.0",
"@aws-sdk/lib-storage": "^3.995.0",
"bcrypt": "^6.0.0",
"bytes": "^3.1.2",
"cross-env": "^10.1.0",
"dotenv": "^17.2.3",
"dotenv": "^17.3.1",
"dotenv-cli": "^11.0.0",
"escape-html": "^1.0.3",
"escape-markdown": "^1.0.4",
@@ -76,14 +73,14 @@
"patch-package": "^8.0.1",
"pg": "^8.18.0",
"read": "^5.0.1",
"rimraf": "^6.1.2",
"sails": "^1.5.16",
"rimraf": "^6.1.3",
"sails": "^1.5.17",
"sails-hook-orm": "^4.0.3",
"sails-hook-sockets": "^3.0.2",
"sails-postgresql": "^5.0.1",
"serve-static": "^2.2.1",
"sharp": "^0.34.5",
"undici": "^7.21.0",
"undici": "^7.22.0",
"uuid": "^11.1.0",
"validator": "^13.15.26",
"winston": "^3.19.0",
@@ -98,7 +95,7 @@
"eslint-plugin-prettier": "^5.5.5",
"ignore": "^7.0.5",
"mocha": "^11.7.5",
"nodemon": "^3.1.11",
"nodemon": "^3.1.14",
"prettier": "3.8.1",
"supertest": "^7.2.2",
"swagger-jsdoc": "^6.2.8"

28
server/setup-python.js Normal file
View File

@@ -0,0 +1,28 @@
const { spawnSync } = require('child_process');
const path = require('path');
const VENV_PATH = path.join(__dirname, '.venv');
const REQUIREMENTS_PATH = path.join(__dirname, 'requirements.txt');
const PYTHON_PATH =
process.platform === 'win32'
? path.join(VENV_PATH, 'Scripts', 'python.exe')
: path.join(VENV_PATH, 'bin', 'python');
const getSystemPythonCommand = () => {
let result = spawnSync('python3', ['--version'], { stdio: 'ignore' });
if (result.status === 0) return 'python3';
result = spawnSync('python', ['--version'], { stdio: 'ignore' });
if (result.status === 0) return 'python';
throw new Error('Python is not installed or not in PATH');
};
const run = (command, args) => {
const result = spawnSync(command, args, { stdio: 'inherit' });
if (result.status !== 0) process.exit(result.status);
};
run(getSystemPythonCommand(), ['-m', 'venv', VENV_PATH]);
run(PYTHON_PATH, ['-m', 'pip', 'install', '-r', REQUIREMENTS_PATH]);

View File

@@ -1 +1 @@
module.exports = '2.0.1';
module.exports = '2.0.2';