Compare commits

...
11 Commits
14 changed files with 391 additions and 61 deletions
@@ -0,0 +1,44 @@
name: Build and push Docker base image
on:
push:
paths:
- ./Dockerfile.base
branches:
- master
workflow_dispatch:
env:
ALPINE_VERSION: 3.15
jobs:
build-and-push-docker-base-image:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to GitHub Container Registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
platforms: linux/amd64,linux/arm64,linux/arm/v7
file: Dockerfile.base
build-args: ALPINE_VERSION=${{ env.ALPINE_VERSION }}
push: true
tags: |
ghcr.io/plankanban/planka:base-latest
ghcr.io/plankanban/planka:base-${{ env.ALPINE_VERSION }}
@@ -0,0 +1,42 @@
name: Build and push Docker image
on:
release:
types: [created]
jobs:
build-and-push-docker-image:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to GitHub Container Registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set version
uses: actions/github-script@v6
id: set-version
with:
result-encoding: string
script: return context.payload.release.tag_name.replace('v', '')
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true
tags: |
ghcr.io/plankanban/planka:latest
ghcr.io/plankanban/planka:${{ steps.set-version.outputs.result }}
+1
View File
@@ -1,5 +1,6 @@
node_modules
docker-compose.override.yml
.idea
.vscode
.DS_Store
+6 -29
View File
@@ -10,47 +10,24 @@ RUN npm install npm@latest --global \
COPY client .
RUN npm run build
FROM node:lts-alpine
FROM ghcr.io/plankanban/planka:base-latest
WORKDIR /app
COPY server/.npmrc server/package.json server/package-lock.json ./
ARG ALPINE_VERSION=3.15
ARG VIPS_VERSION=8.12.2
RUN apk -U upgrade \
&& apk add \
bash giflib glib lcms2 libexif \
libgsf libjpeg-turbo libpng librsvg libwebp \
orc pango tiff \
--repository https://alpine.global.ssl.fastly.net/alpine/v${ALPINE_VERSION}/community/ \
--repository https://alpine.global.ssl.fastly.net/alpine/v${ALPINE_VERSION}/main/ \
RUN apk add \
g++ make python3 \
--virtual node-pre-gyp-dependencies \
--no-cache \
&& apk add \
build-base giflib-dev glib-dev lcms2-dev libexif-dev \
libgsf-dev libjpeg-turbo-dev libpng-dev librsvg-dev libwebp-dev \
orc-dev pango-dev tiff-dev \
--virtual vips-dependencies \
--repository https://alpine.global.ssl.fastly.net/alpine/v${ALPINE_VERSION}/community/ \
--repository https://alpine.global.ssl.fastly.net/alpine/v${ALPINE_VERSION}/main/ \
--no-cache \
&& wget -O- https://github.com/libvips/libvips/releases/download/v${VIPS_VERSION}/vips-${VIPS_VERSION}.tar.gz | tar xzC /tmp \
&& cd /tmp/vips-${VIPS_VERSION} \
&& ./configure \
&& make \
&& make install-strip \
&& cd $OLDPWD \
&& rm -rf /tmp/vips-${VIPS_VERSION} \
&& npm install npm@latest --global \
&& npm install --production \
&& apk del vips-dependencies --purge
&& apk del node-pre-gyp-dependencies --purge
COPY docker-start.sh start.sh
COPY server .
RUN chmod +x start.sh \
&& cp .env.sample .env
RUN cp .env.sample .env
COPY --from=client-builder /app/build public
COPY --from=client-builder /app/build/index.html views
+28
View File
@@ -0,0 +1,28 @@
FROM node:lts-alpine
ARG ALPINE_VERSION=3.15
ARG VIPS_VERSION=8.12.2
RUN apk -U upgrade \
&& apk add \
bash giflib glib lcms2 libexif \
libgsf libjpeg-turbo libpng librsvg libwebp \
orc pango tiff \
--repository https://alpine.global.ssl.fastly.net/alpine/v${ALPINE_VERSION}/community/ \
--repository https://alpine.global.ssl.fastly.net/alpine/v${ALPINE_VERSION}/main/ \
--no-cache \
&& apk add \
build-base giflib-dev glib-dev lcms2-dev libexif-dev \
libgsf-dev libjpeg-turbo-dev libpng-dev librsvg-dev libwebp-dev \
orc-dev pango-dev tiff-dev \
--virtual vips-dependencies \
--repository https://alpine.global.ssl.fastly.net/alpine/v${ALPINE_VERSION}/community/ \
--repository https://alpine.global.ssl.fastly.net/alpine/v${ALPINE_VERSION}/main/ \
--no-cache \
&& wget -O- https://github.com/libvips/libvips/releases/download/v${VIPS_VERSION}/vips-${VIPS_VERSION}.tar.gz | tar xzC /tmp \
&& cd /tmp/vips-${VIPS_VERSION} \
&& ./configure \
&& make \
&& make install-strip \
&& rm -rf /tmp/vips-${VIPS_VERSION} \
&& apk del vips-dependencies --purge
+2
View File
@@ -11,6 +11,7 @@ import frLogin from './fr/login';
import jaLogin from './ja/login';
import plLogin from './pl/login';
import ruLogin from './ru/login';
import seLogin from './se/login';
import uzLogin from './uz/login';
import zhLogin from './zh/login';
@@ -24,6 +25,7 @@ const localePairs = [
['ja', jaLogin],
['pl', plLogin],
['ru', ruLogin],
['se', seLogin],
['uz', uzLogin],
['zh', zhLogin],
];
+213
View File
@@ -0,0 +1,213 @@
import dateFns from 'date-fns/locale/se';
export default {
dateFns,
format: {
date: 'd/M/yyyy',
time: 'p',
dateTime: '$t(format:date) $t(format:time)',
longDate: 'MMM d',
longDateTime: "MMMM d 'at' p",
},
translation: {
common: {
account: 'Konto',
actions: 'Åtgärder',
addAttachment_title: 'Bifoga',
addComment: 'Kommentera',
addManager_title: 'Lägg till Projektledare',
addMember_title: 'Lägg till Medlem',
addUser_title: 'Lägg till Användare',
administrator: 'Administratör',
all: 'Alla',
allChangesWillBeAutomaticallySavedAfterConnectionRestored:
'Alla ändringar kommer att sparas automatiskt<br />så fort anslutningen är återställd',
areYouSureYouWantToDeleteThisAttachment: 'Är du säker på att du vill ta bort den här bilagan?',
areYouSureYouWantToDeleteThisBoard: 'Är du säker på att du vill ta bort den här tavlan?',
areYouSureYouWantToDeleteThisCard: 'Är du säker på att du vill ta bort det här kortet?',
areYouSureYouWantToDeleteThisComment: 'Är du säker på att du vill ta bort den här kommentaren?',
areYouSureYouWantToDeleteThisLabel: 'Är du säker på att du vill ta bort den här etiketten?',
areYouSureYouWantToDeleteThisList: 'Är du säker på att du vill ta bort den här listan?',
areYouSureYouWantToDeleteThisProject: 'Är du säker på att du vill ta bort det här projektet?',
areYouSureYouWantToDeleteThisTask: 'Är du säker på att du vill ta bort den här uppgiften?',
areYouSureYouWantToDeleteThisUser: 'Är du säker på att du vill ta bort den här användaren?',
areYouSureYouWantToLeaveBoard: 'Är du säker på att du vill lämna tavlan?',
areYouSureYouWantToLeaveProject: 'Är du säker på att du vill lämna projektet?',
areYouSureYouWantToRemoveThisManagerFromProject:
'Är du säker på att du vill ta bort den här projektledaren från projektet?',
areYouSureYouWantToRemoveThisMemberFromBoard:
'Är du säker på att du vill ta bort den här medlemmen från tavlan?',
attachment: 'Bilaga',
attachments: 'Bilagor',
authentication: 'Autentisering',
background: 'Bakgrund',
board: 'Tavla',
boardNotFound_title: 'Tavla Ej Funnen',
cardActions_title: 'Kortåtgärder',
cardNotFound_title: 'Kort Ej Funnet',
cardOrActionAreDeleted: 'Kort eller åtgärd är borttagen',
color: 'Färg',
createBoard_title: 'Skapa Tavla',
createLabel_title: 'Skapa Etikett',
createNewOneOrSelectExistingOne: 'Skapa en ny eller välj<br />en redan existerande',
createProject_title: 'Skapa Projekt',
createTextFile_title: 'Skapa Textfil',
currentPassword: 'Nuvarande lösenord',
dangerZone_title: 'Farozon',
date: 'Datum',
dueDate_title: 'Förfallodatum',
deleteAttachment_title: 'Ta Bort Bilaga',
deleteBoard_title: 'Ta Bort Tavla',
deleteCard_title: 'Ta Bort Kort',
deleteComment_title: 'Ta Bort Kommentar',
deleteLabel_title: 'Ta Bort Etikett',
deleteList_title: 'Ta Bort Lista',
deleteProject_title: 'Ta Bort Projekt',
deleteTask_title: 'Ta Bort Uppgift',
deleteUser_title: 'Ta Bort Användare',
description: 'Beskrivning',
dropFileToUpload: 'Släpp en fil för att ladda upp',
editAttachment_title: 'Redigera Bilaga',
editAvatar_title: 'Redigera Avatar',
editBoard_title: 'Redigera Tavla',
editDueDate_title: 'Redigera Förfallodatum',
editEmail_title: 'Redigera E-mail',
editLabel_title: 'Redigera Etikett',
editPassword_title: 'Redigera Lösenord',
editTimer_title: 'Redigera Timer',
editUsername_title: 'Redigera Användarnamn',
email: 'E-mail',
emailAlreadyInUse: 'E-mail används redan',
enterCardTitle: 'Ange kortets titel...',
enterDescription: 'Ange beskrivning...',
enterFilename: 'Ange filnamn',
enterListTitle: 'Ange listans titel...',
enterProjectTitle: 'Ange projektets titel',
enterTaskDescription: 'Ange uppgiftsbeskrivning...',
filterByLabels_title: 'Filtrera Efter Etiketter',
filterByMembers_title: 'Filtrera Efter Medlemmar',
fromComputer_title: 'Från dator',
general: 'Allmänt',
hours: 'Timmar',
invalidCurrentPassword: 'Ogiltigt nuvarande lösenord',
labels: 'Etiketter',
leaveBoard_title: 'Lämna Tavla',
leaveProject_title: 'Lämna Projekt',
list: 'Lista',
listActions_title: 'Liståtgärder',
managers: 'Projektledare',
members: 'Medlemmar',
minutes: 'Minuter',
moveCard_title: 'Flytta Kort',
name: 'Namn',
newEmail: 'Ny e-mail',
newPassword: 'Nytt lösenord',
newUsername: 'Nytt användarnamn',
noConnectionToServer: 'Ingen anslutning till servern',
noBoards: 'Inga tavlor',
noLists: 'Inga listor',
noProjects: 'Inga projekt',
notifications: 'Notifikationer',
noUnreadNotifications: 'Inga olästa notifikationer',
openBoard_title: 'Öppna Tavla',
optional_inline: 'valfri',
organization: 'Organisation',
phone: 'Telefon',
preferences: 'Preferenser',
pressPasteShortcutToAddAttachmentFromClipboard:
'Tips: tryck på Ctrl-V (Cmd-V på Mac) för att lägga till en bilaga från urklipp.',
project: 'Projekt',
projectNotFound_title: 'Projekt Ej Funnet',
removeManager_title: 'Ta Bort Projektledare',
removeMember_title: 'Ta Bort Medlem',
seconds: 'Sekunder',
selectBoard: 'Välj tavla',
selectList: 'Välj lista',
selectProject: 'Välj projekt',
settings: 'Inställningar',
subscribeToMyOwnCardsByDefault: 'Prenumerera på mina egna kort som standard',
taskActions_title: 'Uppgiftsåtgärder',
tasks: 'Uppgifter',
time: 'Tid',
timer: 'Timer',
title: 'Titel',
userActions_title: 'Användaråtgärder',
userAddedThisCardToList: '<0>{{user}}</0><1> lade till detta kort i {{list}}</1>',
userLeftNewCommentToCard: '{{user}} lämnade en ny kommentar «{{comment}}» på <2>{{card}}</2>',
userMovedCardFromListToList: '{{user}} flyttade <2>{{card}}</2> från {{fromList}} till {{toList}}',
userMovedThisCardFromListToList:
'<0>{{user}}</0><1> flyttade detta kort från {{fromList}} till {{toList}}</1>',
username: 'Användarnamn',
usernameAlreadyInUse: 'Användarnamnet används redan',
users: 'Användare',
writeComment: 'Skriv en kommentar...',
},
action: {
addAnotherCard: 'Lägg till ytterligare ett kort',
addAnotherList: 'Lägg till ytterligare en lista',
addAnotherTask: 'Lägg till ytterligare en uppgift',
addCard: 'Lägg till kort',
addCard_title: 'Lägg Till Kort',
addComment: 'Lägg till kommentar',
addList: 'Lägg till lista',
addMoreDetailedDescription: 'Lägg till en mer detaljerad beskrivning',
addTask: 'Lägg till uppgift',
addToCard: 'Lägg till i kort',
addUser: 'Lägg till användare',
createBoard: 'Skapa tavla',
createFile: 'Skapa fil',
createLabel: 'Skapa etikett',
createNewLabel: 'Skapa ny etikett',
createProject: 'Skapa projekt',
delete: 'Ta Bort',
deleteAttachment: 'Ta bort bilaga',
deleteAvatar: 'Ta bort avatar',
deleteBoard: 'Ta bort tavla',
deleteCard: 'Ta bort kort',
deleteCard_title: 'Ta Bort Kort',
deleteComment: 'Ta bort kommentar',
deleteImage: 'Ta bort bild',
deleteLabel: 'Ta bort etikett',
deleteList: 'Ta bort lista',
deleteList_title: 'Ta Bort Lista',
deleteProject: 'Ta bort projekt',
deleteProject_title: 'Ta Bort Projekt',
deleteTask: 'Ta bort uppgift',
deleteTask_title: 'Ta Bort Uppgift',
deleteUser: 'Ta bort användare',
edit: 'Redigera',
editDueDate_title: 'Redigera Förfallodatum',
editDescription_title: 'Redigera Beskrivning',
editEmail_title: 'Redigera E-mail',
editPassword_title: 'Redigera Lösenord',
editTimer_title: 'Redigera Timer',
editTitle_title: 'Redigera Titel',
editUsername_title: 'Redigera Användarnamn',
leaveBoard: 'Lämna tavla',
leaveProject: 'Lämna projekt',
logOut_title: 'Logga ut',
makeCover_title: 'Skapa Omslagsbild',
move: 'Flytta',
moveCard_title: 'Flytta Kort',
remove: 'Ta Bort',
removeBackground: 'Ta bort bakgrund',
removeCover_title: 'Ta Bort Omslagsbild',
removeFromBoard: 'Ta bort from tavla',
removeFromProject: 'Ta bort from projekt',
removeManager: 'Ta bort projektledare',
removeMember: 'Ta bort medlem',
save: 'Spara',
showAllAttachments: 'Visa alla bilagor ({{hidden}} dolda)',
showFewerAttachments: 'Visa färre bilagor',
start: 'Starta',
stop: 'Stoppa',
subscribe: 'Prenumerera',
unsubscribe: 'Avprenumerera',
uploadNewAvatar: 'Ladda upp ny avatar',
uploadNewImage: 'Ladda upp ny bild',
},
},
};
+20
View File
@@ -0,0 +1,20 @@
export default {
translation: {
common: {
emailOrUsername: 'E-mail eller användarnamn',
invalidEmailOrUsername: 'Ogiltig e-mail eller användarnamn',
invalidPassword: 'Ogiltigt lösenord',
logInToPlanka: 'Logga in på Planka',
noInternetConnection: 'Ingen internetanslutning',
pageNotFound_title: 'Sidan Kunde Inte Hittas',
password: 'Lösenord',
projectManagement: 'Projektledning',
serverConnectionFailed: 'Server connection failed',
unknownError: 'Okänt fel, försök igen senare',
},
action: {
logIn: 'Logga in',
},
},
};
+1 -1
View File
@@ -2,7 +2,7 @@ version: '3'
services:
planka:
image: meltyshev/planka:latest
image: ghcr.io/plankanban/planka:latest
command: >
bash -c
"for i in `seq 1 30`; do
+4 -2
View File
@@ -1,6 +1,6 @@
{
"name": "planka",
"version": "1.0.0",
"version": "1.1.3",
"private": true,
"homepage": "https://plankanban.github.io/planka",
"repository": {
@@ -14,9 +14,11 @@
"client:lint": "npm run lint --prefix client",
"client:start": "npm start --prefix client",
"client:test": "npm test --prefix client",
"docker:build": "docker build -t ghcr.io/plankanban/planka:local -f Dockerfile .",
"docker:build:base": "docker build -t ghcr.io/plankanban/planka:base-local -f Dockerfile.base .",
"postinstall": "npm i --prefix server && npm i --prefix client",
"prepare": "husky install",
"lint": "npm run server:lint && npm run client:lint",
"prepare": "husky install",
"server:console": "npm run console --prefix server",
"server:db:init": "npm run db:init --prefix server",
"server:db:migrate": "npm run db:migrate --prefix server",
@@ -61,7 +61,9 @@ module.exports = {
throw Errors.ATTACHMENT_NOT_FOUND;
}
this.res.setHeader('Content-Disposition', `inline; ${inputs.filename}`);
this.res.type(attachment.filename);
this.res.set('Cache-Control', 'private, max-age=900'); // TODO: move to config
return exits.success(fs.createReadStream(filePath));
},
};
+4 -10
View File
@@ -14,10 +14,6 @@ module.exports = {
regex: /^[0-9]+$/,
required: true,
},
filename: {
type: 'string',
required: true,
},
},
exits: {
@@ -56,14 +52,12 @@ module.exports = {
throw Errors.ATTACHMENT_NOT_FOUND;
}
let contentDisposition;
if (attachment.isImage || path.extname(attachment.filename) === '.pdf') {
contentDisposition = 'inline';
} else {
contentDisposition = `attachment; ${inputs.filename}`;
this.res.type(attachment.filename);
if (!attachment.isImage && path.extname(attachment.filename) !== '.pdf') {
this.res.set('Content-Disposition', 'attachment');
}
this.res.set('Cache-Control', 'private, max-age=900'); // TODO: move to config
this.res.setHeader('Content-Disposition', contentDisposition);
return exits.success(fs.createReadStream(filePath));
},
};
+19 -8
View File
@@ -3,25 +3,36 @@ module.exports = {
const { currentUser } = this.req;
const managerProjectIds = await sails.helpers.users.getManagerProjectIds(currentUser.id);
const managerProjects = await sails.helpers.projects.getMany(managerProjectIds);
const boardMemberships = await sails.helpers.users.getBoardMemberships(currentUser.id);
const membershipBoardIds = await sails.helpers.utils.mapRecords(boardMemberships, 'boardId');
let boardMemberships = await sails.helpers.users.getBoardMemberships(currentUser.id);
const membershipBoards = await sails.helpers.boards.getMany({
let membershipBoardIds = sails.helpers.utils.mapRecords(boardMemberships, 'boardId');
let membershipBoards = await sails.helpers.boards.getMany({
id: membershipBoardIds,
projectId: {
'!=': managerProjectIds,
},
});
const membershipProjectIds = sails.helpers.utils.mapRecords(
membershipBoards,
'projectId',
true,
let membershipProjectIds = sails.helpers.utils.mapRecords(membershipBoards, 'projectId', true);
const membershipProjects = await sails.helpers.projects.getMany(membershipProjectIds);
membershipProjectIds = sails.helpers.utils.mapRecords(membershipProjects);
membershipBoards = membershipBoards.filter((membershipBoard) =>
membershipProjectIds.includes(membershipBoard.projectId),
);
membershipBoardIds = sails.helpers.utils.mapRecords(membershipBoards);
boardMemberships = boardMemberships.filter((boardMembership) =>
membershipBoardIds.includes(boardMembership.boardId),
);
const projectIds = [...managerProjectIds, ...membershipProjectIds];
const projects = await sails.helpers.projects.getMany(projectIds);
const projects = [...managerProjects, ...membershipProjects];
const projectManagers = await sails.helpers.projects.getProjectManagers(projectIds);
+4 -10
View File
@@ -10,12 +10,6 @@ module.exports = {
},
async fn(inputs) {
const boardIds = await sails.helpers.projects.getBoardIds(inputs.record.id);
await BoardMembership.destroy({
boardId: boardIds,
}).fetch();
const projectManagers = await ProjectManager.destroy({
projectId: inputs.record.id,
}).fetch();
@@ -25,14 +19,14 @@ module.exports = {
if (project) {
const managerUserIds = sails.helpers.utils.mapRecords(projectManagers, 'userId');
const boardIds = await sails.helpers.projects.getBoardIds(project.id);
const boardRooms = boardIds.map((boardId) => `board:${boardId}`);
const memberUserIds = await sails.helpers.boards.getMemberUserIds(boardIds);
const userIds = _.union(managerUserIds, memberUserIds);
userIds.forEach((userId) => {
sails.sockets.removeRoomMembersFromRooms(
`user:${userId}`,
boardIds.map((boardId) => `board:${boardId}`),
);
sails.sockets.removeRoomMembersFromRooms(`user:${userId}`, boardRooms);
sails.sockets.broadcast(
`user:${userId}`,