mirror of
https://github.com/plankanban/planka.git
synced 2025-12-19 01:12:02 +03:00
feat: Add legal requirements (#1306)
This commit is contained in:
18
.github/workflows/build-and-test.yml
vendored
18
.github/workflows/build-and-test.yml
vendored
@@ -13,9 +13,9 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
env:
|
env:
|
||||||
POSTGRES_DB: planka
|
POSTGRES_USERNAME: planka
|
||||||
POSTGRES_USER: user
|
POSTGRES_PASSWORD: planka
|
||||||
POSTGRES_PASSWORD: password
|
POSTGRES_DATABASE: planka
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
@@ -30,9 +30,9 @@ jobs:
|
|||||||
- name: Set up PostgreSQL
|
- name: Set up PostgreSQL
|
||||||
uses: ikalnytskyi/action-setup-postgres@v5
|
uses: ikalnytskyi/action-setup-postgres@v5
|
||||||
with:
|
with:
|
||||||
database: ${{ env.POSTGRES_DB }}
|
username: ${{ env.POSTGRES_USERNAME }}
|
||||||
username: ${{ env.POSTGRES_USER }}
|
|
||||||
password: ${{ env.POSTGRES_PASSWORD }}
|
password: ${{ env.POSTGRES_PASSWORD }}
|
||||||
|
database: ${{ env.POSTGRES_DATABASE }}
|
||||||
|
|
||||||
- name: Cache Node.js modules
|
- name: Cache Node.js modules
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
@@ -58,7 +58,7 @@ jobs:
|
|||||||
client/tests/setup-symlinks.sh
|
client/tests/setup-symlinks.sh
|
||||||
cd server
|
cd server
|
||||||
cp .env.sample .env
|
cp .env.sample .env
|
||||||
sed -i "s|^DATABASE_URL=.*|DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost/${POSTGRES_DB}|" .env
|
sed -i "s|^DATABASE_URL=.*|DATABASE_URL=postgresql://${POSTGRES_USERNAME}:${POSTGRES_PASSWORD}@localhost/${POSTGRES_DATABASE}|" .env
|
||||||
npm run db:init
|
npm run db:init
|
||||||
npm start --prod &
|
npm start --prod &
|
||||||
|
|
||||||
@@ -67,6 +67,12 @@ jobs:
|
|||||||
sudo apt-get install wait-for-it -y
|
sudo apt-get install wait-for-it -y
|
||||||
wait-for-it -h localhost -p 1337 -t 10
|
wait-for-it -h localhost -p 1337 -t 10
|
||||||
|
|
||||||
|
- name: Seed database with terms signature
|
||||||
|
run: |
|
||||||
|
TERMS_SIGNATURE=$(sha256sum terms/en-US/extended.md | awk '{print $1}')
|
||||||
|
PGPASSWORD=$POSTGRES_PASSWORD psql -h localhost -U $POSTGRES_USERNAME -d $POSTGRES_DATABASE -c "UPDATE user_account SET terms_signature = '$TERMS_SIGNATURE';"
|
||||||
|
working-directory: ./server
|
||||||
|
|
||||||
- name: Run UI tests
|
- name: Run UI tests
|
||||||
run: |
|
run: |
|
||||||
npx playwright install chromium
|
npx playwright install chromium
|
||||||
|
|||||||
@@ -91,8 +91,8 @@ const logout = () => ({
|
|||||||
payload: {},
|
payload: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
logout.invalidateAccessToken = () => ({
|
logout.revokeAccessToken = () => ({
|
||||||
type: ActionTypes.LOGOUT__ACCESS_TOKEN_INVALIDATE,
|
type: ActionTypes.LOGOUT__ACCESS_TOKEN_REVOKE,
|
||||||
payload: {},
|
payload: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -26,10 +26,11 @@ authenticate.success = (accessToken) => ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
authenticate.failure = (error) => ({
|
authenticate.failure = (error, terms) => ({
|
||||||
type: ActionTypes.AUTHENTICATE__FAILURE,
|
type: ActionTypes.AUTHENTICATE__FAILURE,
|
||||||
payload: {
|
payload: {
|
||||||
error,
|
error,
|
||||||
|
terms,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -45,10 +46,11 @@ authenticateWithOidc.success = (accessToken) => ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
authenticateWithOidc.failure = (error) => ({
|
authenticateWithOidc.failure = (error, terms) => ({
|
||||||
type: ActionTypes.WITH_OIDC_AUTHENTICATE__FAILURE,
|
type: ActionTypes.WITH_OIDC_AUTHENTICATE__FAILURE,
|
||||||
payload: {
|
payload: {
|
||||||
error,
|
error,
|
||||||
|
terms,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -57,9 +59,71 @@ const clearAuthenticateError = () => ({
|
|||||||
payload: {},
|
payload: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const acceptTerms = (signature) => ({
|
||||||
|
type: ActionTypes.TERMS_ACCEPT,
|
||||||
|
payload: {
|
||||||
|
signature,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
acceptTerms.success = (accessToken) => ({
|
||||||
|
type: ActionTypes.TERMS_ACCEPT__SUCCESS,
|
||||||
|
payload: {
|
||||||
|
accessToken,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
acceptTerms.failure = (error) => ({
|
||||||
|
type: ActionTypes.TERMS_ACCEPT__FAILURE,
|
||||||
|
payload: {
|
||||||
|
error,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const cancelTerms = () => ({
|
||||||
|
type: ActionTypes.TERMS_CANCEL,
|
||||||
|
payload: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
cancelTerms.success = () => ({
|
||||||
|
type: ActionTypes.TERMS_CANCEL__SUCCESS,
|
||||||
|
payload: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
cancelTerms.failure = (error) => ({
|
||||||
|
type: ActionTypes.TERMS_CANCEL__FAILURE,
|
||||||
|
payload: {
|
||||||
|
error,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateTermsLanguage = (value) => ({
|
||||||
|
type: ActionTypes.TERMS_LANGUAGE_UPDATE,
|
||||||
|
payload: {
|
||||||
|
value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
updateTermsLanguage.success = (terms) => ({
|
||||||
|
type: ActionTypes.TERMS_LANGUAGE_UPDATE__SUCCESS,
|
||||||
|
payload: {
|
||||||
|
terms,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
updateTermsLanguage.failure = (error) => ({
|
||||||
|
type: ActionTypes.TERMS_LANGUAGE_UPDATE__FAILURE,
|
||||||
|
payload: {
|
||||||
|
error,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
initializeLogin,
|
initializeLogin,
|
||||||
authenticate,
|
authenticate,
|
||||||
authenticateWithOidc,
|
authenticateWithOidc,
|
||||||
clearAuthenticateError,
|
clearAuthenticateError,
|
||||||
|
acceptTerms,
|
||||||
|
cancelTerms,
|
||||||
|
updateTermsLanguage,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,10 +13,18 @@ const createAccessToken = (data, headers) =>
|
|||||||
const exchangeForAccessTokenWithOidc = (data, headers) =>
|
const exchangeForAccessTokenWithOidc = (data, headers) =>
|
||||||
http.post('/access-tokens/exchange-with-oidc?withHttpOnlyToken=true', data, headers);
|
http.post('/access-tokens/exchange-with-oidc?withHttpOnlyToken=true', data, headers);
|
||||||
|
|
||||||
|
// TODO: rename?
|
||||||
|
const acceptTerms = (data, headers) => http.post('/access-tokens/accept-terms', data, headers);
|
||||||
|
|
||||||
|
const revokePendingToken = (data, headers) =>
|
||||||
|
http.post('/access-tokens/revoke-pending-token', data, headers);
|
||||||
|
|
||||||
const deleteCurrentAccessToken = (headers) => http.delete('/access-tokens/me', undefined, headers);
|
const deleteCurrentAccessToken = (headers) => http.delete('/access-tokens/me', undefined, headers);
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
createAccessToken,
|
createAccessToken,
|
||||||
exchangeForAccessTokenWithOidc,
|
exchangeForAccessTokenWithOidc,
|
||||||
|
acceptTerms,
|
||||||
|
revokePendingToken,
|
||||||
deleteCurrentAccessToken,
|
deleteCurrentAccessToken,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
import http from './http';
|
import http from './http';
|
||||||
import socket from './socket';
|
import socket from './socket';
|
||||||
import config from './config';
|
import config from './config';
|
||||||
|
import terms from './terms';
|
||||||
import accessTokens from './access-tokens';
|
import accessTokens from './access-tokens';
|
||||||
import webhooks from './webhooks';
|
import webhooks from './webhooks';
|
||||||
import users from './users';
|
import users from './users';
|
||||||
@@ -35,6 +36,7 @@ export { http, socket };
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
...config,
|
...config,
|
||||||
|
...terms,
|
||||||
...accessTokens,
|
...accessTokens,
|
||||||
...webhooks,
|
...webhooks,
|
||||||
...users,
|
...users,
|
||||||
|
|||||||
15
client/src/api/terms.js
Normal file
15
client/src/api/terms.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/*!
|
||||||
|
* Copyright (c) 2024 PLANKA Software GmbH
|
||||||
|
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||||
|
*/
|
||||||
|
|
||||||
|
import http from './http';
|
||||||
|
|
||||||
|
/* Actions */
|
||||||
|
|
||||||
|
const getTerms = (type, language, headers) =>
|
||||||
|
http.get(`/terms/${type}${language ? `?language=${language}` : ''}`, undefined, headers);
|
||||||
|
|
||||||
|
export default {
|
||||||
|
getTerms,
|
||||||
|
};
|
||||||
@@ -16,6 +16,8 @@ import selectors from '../../../selectors';
|
|||||||
import entryActions from '../../../entry-actions';
|
import entryActions from '../../../entry-actions';
|
||||||
import { useForm, useNestedRef } from '../../../hooks';
|
import { useForm, useNestedRef } from '../../../hooks';
|
||||||
import { isUsername } from '../../../utils/validator';
|
import { isUsername } from '../../../utils/validator';
|
||||||
|
import AccessTokenSteps from '../../../constants/AccessTokenSteps';
|
||||||
|
import TermsModal from './TermsModal';
|
||||||
|
|
||||||
import styles from './Content.module.scss';
|
import styles from './Content.module.scss';
|
||||||
|
|
||||||
@@ -45,6 +47,11 @@ const createMessage = (error) => {
|
|||||||
type: 'error',
|
type: 'error',
|
||||||
content: 'common.useSingleSignOn',
|
content: 'common.useSingleSignOn',
|
||||||
};
|
};
|
||||||
|
case 'Admin login required to initialize instance':
|
||||||
|
return {
|
||||||
|
type: 'error',
|
||||||
|
content: 'common.adminLoginRequiredToInitializeInstance',
|
||||||
|
};
|
||||||
case 'Email already in use':
|
case 'Email already in use':
|
||||||
return {
|
return {
|
||||||
type: 'error',
|
type: 'error',
|
||||||
@@ -86,6 +93,7 @@ const Content = React.memo(() => {
|
|||||||
isSubmitting,
|
isSubmitting,
|
||||||
isSubmittingWithOidc,
|
isSubmittingWithOidc,
|
||||||
error,
|
error,
|
||||||
|
step,
|
||||||
} = useSelector(selectors.selectAuthenticateForm);
|
} = useSelector(selectors.selectAuthenticateForm);
|
||||||
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
@@ -265,6 +273,7 @@ const Content = React.memo(() => {
|
|||||||
<div className={styles.coverOverlay} />
|
<div className={styles.coverOverlay} />
|
||||||
</Grid.Column>
|
</Grid.Column>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
{step === AccessTokenSteps.ACCEPT_TERMS && <TermsModal />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
93
client/src/components/common/Login/TermsModal.jsx
Normal file
93
client/src/components/common/Login/TermsModal.jsx
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
/*!
|
||||||
|
* Copyright (c) 2024 PLANKA Software GmbH
|
||||||
|
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React, { useCallback, useState } from 'react';
|
||||||
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { Button, Checkbox, Dropdown, Modal } from 'semantic-ui-react';
|
||||||
|
|
||||||
|
import selectors from '../../../selectors';
|
||||||
|
import entryActions from '../../../entry-actions';
|
||||||
|
import { localeByLanguage } from '../../../locales';
|
||||||
|
import TERMS_LANGUAGES from '../../../constants/TermsLanguages';
|
||||||
|
import Markdown from '../Markdown';
|
||||||
|
|
||||||
|
import styles from './TermsModal.module.scss';
|
||||||
|
|
||||||
|
const LOCALES = TERMS_LANGUAGES.map((language) => localeByLanguage[language]);
|
||||||
|
|
||||||
|
const TermsModal = React.memo(() => {
|
||||||
|
const {
|
||||||
|
termsForm: { payload: terms, isSubmitting, isCancelling, isLanguageUpdating },
|
||||||
|
} = useSelector(selectors.selectAuthenticateForm);
|
||||||
|
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const [t] = useTranslation();
|
||||||
|
const [isTermsAccepted, setIsTermsAccepted] = useState(false);
|
||||||
|
|
||||||
|
const handleContinueClick = useCallback(() => {
|
||||||
|
dispatch(entryActions.acceptTerms(terms.signature));
|
||||||
|
}, [terms.signature, dispatch]);
|
||||||
|
|
||||||
|
const handleCancelClick = useCallback(() => {
|
||||||
|
dispatch(entryActions.cancelTerms());
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
|
const handleLanguageChange = useCallback(
|
||||||
|
(_, { value }) => {
|
||||||
|
dispatch(entryActions.updateTermsLanguage(value));
|
||||||
|
},
|
||||||
|
[dispatch],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleToggleAcceptClick = useCallback((_, { checked }) => {
|
||||||
|
setIsTermsAccepted(checked);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal open centered={false}>
|
||||||
|
<Modal.Content>
|
||||||
|
<Dropdown
|
||||||
|
fluid
|
||||||
|
selection
|
||||||
|
options={LOCALES.map((locale) => ({
|
||||||
|
value: locale.language,
|
||||||
|
flag: locale.country,
|
||||||
|
text: locale.name,
|
||||||
|
}))}
|
||||||
|
value={terms.language}
|
||||||
|
loading={isLanguageUpdating}
|
||||||
|
disabled={isLanguageUpdating}
|
||||||
|
className={styles.language}
|
||||||
|
onChange={handleLanguageChange}
|
||||||
|
/>
|
||||||
|
<Markdown>{terms.content}</Markdown>
|
||||||
|
</Modal.Content>
|
||||||
|
<Modal.Actions>
|
||||||
|
<Button
|
||||||
|
content={t('action.cancelAndClose')}
|
||||||
|
floated="left"
|
||||||
|
loading={isCancelling}
|
||||||
|
disabled={isSubmitting || isCancelling}
|
||||||
|
className={styles.cancelButton}
|
||||||
|
onClick={handleCancelClick}
|
||||||
|
/>
|
||||||
|
<Checkbox
|
||||||
|
label={t('common.iHaveReadAndAgreeToTheseTerms')}
|
||||||
|
onChange={handleToggleAcceptClick}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
positive
|
||||||
|
content={t('action.continue')}
|
||||||
|
loading={isSubmitting}
|
||||||
|
disabled={!isTermsAccepted || isSubmitting || isCancelling}
|
||||||
|
onClick={handleContinueClick}
|
||||||
|
/>
|
||||||
|
</Modal.Actions>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default TermsModal;
|
||||||
14
client/src/components/common/Login/TermsModal.module.scss
Normal file
14
client/src/components/common/Login/TermsModal.module.scss
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/*!
|
||||||
|
* Copyright (c) 2024 PLANKA Software GmbH
|
||||||
|
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||||
|
*/
|
||||||
|
|
||||||
|
:global(#app) {
|
||||||
|
.cancelButton {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.language {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,8 @@ import { useDispatch, useSelector } from 'react-redux';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Button, Divider, Dropdown, Header, Tab } from 'semantic-ui-react';
|
import { Button, Divider, Dropdown, Header, Tab } from 'semantic-ui-react';
|
||||||
|
|
||||||
|
import selectors from '../../../../selectors';
|
||||||
|
import entryActions from '../../../../entry-actions';
|
||||||
import { usePopupInClosableContext } from '../../../../hooks';
|
import { usePopupInClosableContext } from '../../../../hooks';
|
||||||
import locales from '../../../../locales';
|
import locales from '../../../../locales';
|
||||||
import EditAvatarStep from './EditAvatarStep';
|
import EditAvatarStep from './EditAvatarStep';
|
||||||
@@ -17,9 +19,6 @@ import EditUserEmailStep from '../../EditUserEmailStep';
|
|||||||
import EditUserPasswordStep from '../../EditUserPasswordStep';
|
import EditUserPasswordStep from '../../EditUserPasswordStep';
|
||||||
import UserAvatar from '../../UserAvatar';
|
import UserAvatar from '../../UserAvatar';
|
||||||
|
|
||||||
import selectors from '../../../../selectors';
|
|
||||||
import entryActions from '../../../../entry-actions';
|
|
||||||
|
|
||||||
import styles from './AccountPane.module.scss';
|
import styles from './AccountPane.module.scss';
|
||||||
|
|
||||||
const AccountPane = React.memo(() => {
|
const AccountPane = React.memo(() => {
|
||||||
|
|||||||
49
client/src/components/users/UserSettingsModal/TermsPane.jsx
Normal file
49
client/src/components/users/UserSettingsModal/TermsPane.jsx
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*!
|
||||||
|
* Copyright (c) 2024 PLANKA Software GmbH
|
||||||
|
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { Loader, Tab } from 'semantic-ui-react';
|
||||||
|
|
||||||
|
import selectors from '../../../selectors';
|
||||||
|
import api from '../../../api';
|
||||||
|
import Markdown from '../../common/Markdown';
|
||||||
|
|
||||||
|
import styles from './TermsPane.module.scss';
|
||||||
|
|
||||||
|
const TermsPane = React.memo(() => {
|
||||||
|
const type = useSelector((state) => selectors.selectCurrentUser(state).termsType);
|
||||||
|
|
||||||
|
const { i18n } = useTranslation();
|
||||||
|
const [content, setContent] = useState(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function fetchTerms() {
|
||||||
|
let terms;
|
||||||
|
try {
|
||||||
|
({ item: terms } = await api.getTerms(type, i18n.resolvedLanguage));
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setContent(terms.content);
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchTerms();
|
||||||
|
}, [type, i18n.resolvedLanguage]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tab.Pane attached={false} className={styles.wrapper}>
|
||||||
|
{content ? (
|
||||||
|
<Markdown>{content}</Markdown>
|
||||||
|
) : (
|
||||||
|
<Loader active inverted inline="centered" size="small" />
|
||||||
|
)}
|
||||||
|
</Tab.Pane>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default TermsPane;
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
/*!
|
||||||
|
* Copyright (c) 2024 PLANKA Software GmbH
|
||||||
|
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||||
|
*/
|
||||||
|
|
||||||
|
:global(#app) {
|
||||||
|
.wrapper {
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ import { useClosableModal } from '../../../hooks';
|
|||||||
import AccountPane from './AccountPane';
|
import AccountPane from './AccountPane';
|
||||||
import PreferencesPane from './PreferencesPane';
|
import PreferencesPane from './PreferencesPane';
|
||||||
import NotificationsPane from './NotificationsPane';
|
import NotificationsPane from './NotificationsPane';
|
||||||
|
import TermsPane from './TermsPane';
|
||||||
import AboutPane from './AboutPane';
|
import AboutPane from './AboutPane';
|
||||||
|
|
||||||
const UserSettingsModal = React.memo(() => {
|
const UserSettingsModal = React.memo(() => {
|
||||||
@@ -44,6 +45,12 @@ const UserSettingsModal = React.memo(() => {
|
|||||||
}),
|
}),
|
||||||
render: () => <NotificationsPane />,
|
render: () => <NotificationsPane />,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
menuItem: t('common.terms', {
|
||||||
|
context: 'title',
|
||||||
|
}),
|
||||||
|
render: () => <TermsPane />,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
menuItem: t('common.aboutPlanka', {
|
menuItem: t('common.aboutPlanka', {
|
||||||
context: 'title',
|
context: 'title',
|
||||||
|
|||||||
8
client/src/constants/AccessTokenSteps.js
Normal file
8
client/src/constants/AccessTokenSteps.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
/*!
|
||||||
|
* Copyright (c) 2024 PLANKA Software GmbH
|
||||||
|
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default {
|
||||||
|
ACCEPT_TERMS: 'accept-terms',
|
||||||
|
};
|
||||||
@@ -26,6 +26,15 @@ export default {
|
|||||||
WITH_OIDC_AUTHENTICATE__SUCCESS: 'WITH_OIDC_AUTHENTICATE__SUCCESS',
|
WITH_OIDC_AUTHENTICATE__SUCCESS: 'WITH_OIDC_AUTHENTICATE__SUCCESS',
|
||||||
WITH_OIDC_AUTHENTICATE__FAILURE: 'WITH_OIDC_AUTHENTICATE__FAILURE',
|
WITH_OIDC_AUTHENTICATE__FAILURE: 'WITH_OIDC_AUTHENTICATE__FAILURE',
|
||||||
AUTHENTICATE_ERROR_CLEAR: 'AUTHENTICATE_ERROR_CLEAR',
|
AUTHENTICATE_ERROR_CLEAR: 'AUTHENTICATE_ERROR_CLEAR',
|
||||||
|
TERMS_ACCEPT: 'TERMS_ACCEPT',
|
||||||
|
TERMS_ACCEPT__SUCCESS: 'TERMS_ACCEPT__SUCCESS',
|
||||||
|
TERMS_ACCEPT__FAILURE: 'TERMS_ACCEPT__FAILURE',
|
||||||
|
TERMS_CANCEL: 'TERMS_CANCEL',
|
||||||
|
TERMS_CANCEL__SUCCESS: 'TERMS_CANCEL__SUCCESS',
|
||||||
|
TERMS_CANCEL__FAILURE: 'TERMS_CANCEL__FAILURE',
|
||||||
|
TERMS_LANGUAGE_UPDATE: 'TERMS_LANGUAGE_UPDATE',
|
||||||
|
TERMS_LANGUAGE_UPDATE__SUCCESS: 'TERMS_LANGUAGE_UPDATE__SUCCESS',
|
||||||
|
TERMS_LANGUAGE_UPDATE__FAILURE: 'TERMS_LANGUAGE_UPDATE__FAILURE',
|
||||||
|
|
||||||
/* Core */
|
/* Core */
|
||||||
|
|
||||||
@@ -35,7 +44,7 @@ export default {
|
|||||||
EDIT_MODE_TOGGLE: 'EDIT_MODE_TOGGLE',
|
EDIT_MODE_TOGGLE: 'EDIT_MODE_TOGGLE',
|
||||||
HOME_VIEW_UPDATE: 'HOME_VIEW_UPDATE',
|
HOME_VIEW_UPDATE: 'HOME_VIEW_UPDATE',
|
||||||
LOGOUT: 'LOGOUT',
|
LOGOUT: 'LOGOUT',
|
||||||
LOGOUT__ACCESS_TOKEN_INVALIDATE: 'LOGOUT__ACCESS_TOKEN_INVALIDATE',
|
LOGOUT__ACCESS_TOKEN_REVOKE: 'LOGOUT__ACCESS_TOKEN_REVOKE',
|
||||||
|
|
||||||
/* Modals */
|
/* Modals */
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ export default {
|
|||||||
AUTHENTICATE: `${PREFIX}/AUTHENTICATE`,
|
AUTHENTICATE: `${PREFIX}/AUTHENTICATE`,
|
||||||
WITH_OIDC_AUTHENTICATE: `${PREFIX}/WITH_OIDC_AUTHENTICATE`,
|
WITH_OIDC_AUTHENTICATE: `${PREFIX}/WITH_OIDC_AUTHENTICATE`,
|
||||||
AUTHENTICATE_ERROR_CLEAR: `${PREFIX}/AUTHENTICATE_ERROR_CLEAR`,
|
AUTHENTICATE_ERROR_CLEAR: `${PREFIX}/AUTHENTICATE_ERROR_CLEAR`,
|
||||||
|
TERMS_ACCEPT: `${PREFIX}/TERMS_ACCEPT`,
|
||||||
|
TERMS_CANCEL: `${PREFIX}/TERMS_CANCEL`,
|
||||||
|
TERMS_LANGUAGE_UPDATE: `${PREFIX}/TERMS_LANGUAGE_UPDATE`,
|
||||||
|
|
||||||
/* Core */
|
/* Core */
|
||||||
|
|
||||||
|
|||||||
6
client/src/constants/TermsLanguages.js
Normal file
6
client/src/constants/TermsLanguages.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/*!
|
||||||
|
* Copyright (c) 2024 PLANKA Software GmbH
|
||||||
|
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default ['de-DE', 'en-US'];
|
||||||
@@ -26,10 +26,10 @@ const updateHomeView = (value) => ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const logout = (invalidateAccessToken = true) => ({
|
const logout = (revokeAccessToken = true) => ({
|
||||||
type: EntryActionTypes.LOGOUT,
|
type: EntryActionTypes.LOGOUT,
|
||||||
payload: {
|
payload: {
|
||||||
invalidateAccessToken,
|
revokeAccessToken,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,30 @@ const clearAuthenticateError = () => ({
|
|||||||
payload: {},
|
payload: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const acceptTerms = (signature) => ({
|
||||||
|
type: EntryActionTypes.TERMS_ACCEPT,
|
||||||
|
payload: {
|
||||||
|
signature,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const cancelTerms = () => ({
|
||||||
|
type: EntryActionTypes.TERMS_CANCEL,
|
||||||
|
payload: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateTermsLanguage = (value) => ({
|
||||||
|
type: EntryActionTypes.TERMS_LANGUAGE_UPDATE,
|
||||||
|
payload: {
|
||||||
|
value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
authenticate,
|
authenticate,
|
||||||
authenticateWithOidc,
|
authenticateWithOidc,
|
||||||
clearAuthenticateError,
|
clearAuthenticateError,
|
||||||
|
acceptTerms,
|
||||||
|
cancelTerms,
|
||||||
|
updateTermsLanguage,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -270,6 +270,7 @@ export default {
|
|||||||
taskListActions_title: null,
|
taskListActions_title: null,
|
||||||
taskList_title: null,
|
taskList_title: null,
|
||||||
team: null,
|
team: null,
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment: 'لا يوجد معاينة متاحة لهذا المرفق.',
|
thereIsNoPreviewAvailableForThisAttachment: 'لا يوجد معاينة متاحة لهذا المرفق.',
|
||||||
time: 'الوقت',
|
time: 'الوقت',
|
||||||
title: 'العنوان',
|
title: 'العنوان',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: null,
|
activeUsersLimitReached: null,
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'البريد الإلكتروني مستخدم بالفعل',
|
emailAlreadyInUse: 'البريد الإلكتروني مستخدم بالفعل',
|
||||||
emailOrUsername: 'البريد الإلكتروني أو اسم المستخدم',
|
emailOrUsername: 'البريد الإلكتروني أو اسم المستخدم',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: 'بيانات الاعتماد غير صالحة',
|
invalidCredentials: 'بيانات الاعتماد غير صالحة',
|
||||||
invalidEmailOrUsername: 'البريد الإلكتروني أو اسم المستخدم غير صالح',
|
invalidEmailOrUsername: 'البريد الإلكتروني أو اسم المستخدم غير صالح',
|
||||||
invalidPassword: 'كلمة المرور غير صالحة',
|
invalidPassword: 'كلمة المرور غير صالحة',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'تسجيل الدخول',
|
logIn: 'تسجيل الدخول',
|
||||||
logInWithSso: 'تسجيل الدخول باستخدام SSO',
|
logInWithSso: 'تسجيل الدخول باستخدام SSO',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -274,6 +274,7 @@ export default {
|
|||||||
taskListActions_title: null,
|
taskListActions_title: null,
|
||||||
taskList_title: null,
|
taskList_title: null,
|
||||||
team: null,
|
team: null,
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment: 'Няма наличен преглед за този прикачен файл.',
|
thereIsNoPreviewAvailableForThisAttachment: 'Няма наличен преглед за този прикачен файл.',
|
||||||
time: 'Време',
|
time: 'Време',
|
||||||
title: 'Заглавие',
|
title: 'Заглавие',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: null,
|
activeUsersLimitReached: null,
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'Имейлът вече се използва',
|
emailAlreadyInUse: 'Имейлът вече се използва',
|
||||||
emailOrUsername: 'Имейл или потребителско име',
|
emailOrUsername: 'Имейл или потребителско име',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: null,
|
invalidCredentials: null,
|
||||||
invalidEmailOrUsername: 'Невалиден имейл или потребителско име',
|
invalidEmailOrUsername: 'Невалиден имейл или потребителско име',
|
||||||
invalidPassword: 'Невалидна парола',
|
invalidPassword: 'Невалидна парола',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'Вход',
|
logIn: 'Вход',
|
||||||
logInWithSso: 'Вход чрез SSO',
|
logInWithSso: 'Вход чрез SSO',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -284,6 +284,7 @@ export default {
|
|||||||
taskListActions_title: 'Akce seznamu úkolů',
|
taskListActions_title: 'Akce seznamu úkolů',
|
||||||
taskList_title: 'Seznam úkolů',
|
taskList_title: 'Seznam úkolů',
|
||||||
team: 'Tým',
|
team: 'Tým',
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment: 'Pro tuto přílohu není k dispozici žádný náhled.',
|
thereIsNoPreviewAvailableForThisAttachment: 'Pro tuto přílohu není k dispozici žádný náhled.',
|
||||||
time: 'Čas',
|
time: 'Čas',
|
||||||
title: 'Titulek',
|
title: 'Titulek',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: 'Dosažený limit aktivních uživatelů',
|
activeUsersLimitReached: 'Dosažený limit aktivních uživatelů',
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'E-mail se již používá',
|
emailAlreadyInUse: 'E-mail se již používá',
|
||||||
emailOrUsername: 'E-mail nebo uživatelské jméno',
|
emailOrUsername: 'E-mail nebo uživatelské jméno',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: 'Neplatné přihlašovací údaje',
|
invalidCredentials: 'Neplatné přihlašovací údaje',
|
||||||
invalidEmailOrUsername: 'Nesprávný e-mail nebo uživatelské jméno',
|
invalidEmailOrUsername: 'Nesprávný e-mail nebo uživatelské jméno',
|
||||||
invalidPassword: 'Nesprávné heslo',
|
invalidPassword: 'Nesprávné heslo',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'Přihlásit se',
|
logIn: 'Přihlásit se',
|
||||||
logInWithSso: null,
|
logInWithSso: null,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -290,6 +290,7 @@ export default {
|
|||||||
taskListActions_title: 'Opgaveliste handlinger',
|
taskListActions_title: 'Opgaveliste handlinger',
|
||||||
taskList_title: 'Opgaveliste',
|
taskList_title: 'Opgaveliste',
|
||||||
team: 'Team',
|
team: 'Team',
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment:
|
thereIsNoPreviewAvailableForThisAttachment:
|
||||||
'Der er ingen forhåndsvisning tilgængelig for denne vedhæftning.',
|
'Der er ingen forhåndsvisning tilgængelig for denne vedhæftning.',
|
||||||
time: 'Tid',
|
time: 'Tid',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: 'Grænsen for aktive brugere er nået',
|
activeUsersLimitReached: 'Grænsen for aktive brugere er nået',
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'E-mail allerede i brug',
|
emailAlreadyInUse: 'E-mail allerede i brug',
|
||||||
emailOrUsername: 'E-mail eller brugernavn',
|
emailOrUsername: 'E-mail eller brugernavn',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: 'Forkerte loginoplysninger',
|
invalidCredentials: 'Forkerte loginoplysninger',
|
||||||
invalidEmailOrUsername: 'Ugyldig e-mail eller brugernavn',
|
invalidEmailOrUsername: 'Ugyldig e-mail eller brugernavn',
|
||||||
invalidPassword: 'Ugyldig adgangskode',
|
invalidPassword: 'Ugyldig adgangskode',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'Log på',
|
logIn: 'Log på',
|
||||||
logInWithSso: 'Log på med SSO',
|
logInWithSso: 'Log på med SSO',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -299,6 +299,7 @@ export default {
|
|||||||
taskListActions_title: 'Aufgaben-Aktionen',
|
taskListActions_title: 'Aufgaben-Aktionen',
|
||||||
taskList_title: 'Aufgaben',
|
taskList_title: 'Aufgaben',
|
||||||
team: 'Team',
|
team: 'Team',
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment: 'Für diesen Anhang ist keine Vorschau verfügbar.',
|
thereIsNoPreviewAvailableForThisAttachment: 'Für diesen Anhang ist keine Vorschau verfügbar.',
|
||||||
time: 'Zeit',
|
time: 'Zeit',
|
||||||
title: 'Titel',
|
title: 'Titel',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: 'Maximale Anzahl aktiver Benutzer erreicht',
|
activeUsersLimitReached: 'Maximale Anzahl aktiver Benutzer erreicht',
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'E-mail Adresse wird bereits benutzt',
|
emailAlreadyInUse: 'E-mail Adresse wird bereits benutzt',
|
||||||
emailOrUsername: 'E-Mail-Adresse oder Benutzername',
|
emailOrUsername: 'E-Mail-Adresse oder Benutzername',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: 'Ungültige Anmeldeinformationen',
|
invalidCredentials: 'Ungültige Anmeldeinformationen',
|
||||||
invalidEmailOrUsername: 'Ungültige E-Mail-Adresse oder Benutzername',
|
invalidEmailOrUsername: 'Ungültige E-Mail-Adresse oder Benutzername',
|
||||||
invalidPassword: 'Ungültiges Passwort',
|
invalidPassword: 'Ungültiges Passwort',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'Einloggen',
|
logIn: 'Einloggen',
|
||||||
logInWithSso: 'Einloggen mit SSO',
|
logInWithSso: 'Einloggen mit SSO',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -300,6 +300,7 @@ export default {
|
|||||||
taskListActions_title: 'Ενέργειες λίστας εργασιών',
|
taskListActions_title: 'Ενέργειες λίστας εργασιών',
|
||||||
taskList_title: 'Λίστα εργασιών',
|
taskList_title: 'Λίστα εργασιών',
|
||||||
team: 'Ομάδα',
|
team: 'Ομάδα',
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment:
|
thereIsNoPreviewAvailableForThisAttachment:
|
||||||
'Δεν υπάρχει διαθέσιμη προεπισκόπηση για αυτό το συνημμένο.',
|
'Δεν υπάρχει διαθέσιμη προεπισκόπηση για αυτό το συνημμένο.',
|
||||||
time: 'Ώρα',
|
time: 'Ώρα',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: 'Έχει επιτευχθεί το όριο ενεργών χρηστών',
|
activeUsersLimitReached: 'Έχει επιτευχθεί το όριο ενεργών χρηστών',
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'Το e-mail χρησιμοποιείται ήδη',
|
emailAlreadyInUse: 'Το e-mail χρησιμοποιείται ήδη',
|
||||||
emailOrUsername: 'E-mail ή όνομα χρήστη',
|
emailOrUsername: 'E-mail ή όνομα χρήστη',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: 'Μη έγκυρα στοιχεία σύνδεσης',
|
invalidCredentials: 'Μη έγκυρα στοιχεία σύνδεσης',
|
||||||
invalidEmailOrUsername: 'Μη έγκυρο e-mail ή όνομα χρήστη',
|
invalidEmailOrUsername: 'Μη έγκυρο e-mail ή όνομα χρήστη',
|
||||||
invalidPassword: 'Μη έγκυρος κωδικός',
|
invalidPassword: 'Μη έγκυρος κωδικός',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'Σύνδεση',
|
logIn: 'Σύνδεση',
|
||||||
logInWithSso: 'Σύνδεση με SSO',
|
logInWithSso: 'Σύνδεση με SSO',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -290,6 +290,7 @@ export default {
|
|||||||
taskListActions_title: 'Task List Actions',
|
taskListActions_title: 'Task List Actions',
|
||||||
taskList_title: 'Task List',
|
taskList_title: 'Task List',
|
||||||
team: 'Team',
|
team: 'Team',
|
||||||
|
terms: 'Terms',
|
||||||
thereIsNoPreviewAvailableForThisAttachment:
|
thereIsNoPreviewAvailableForThisAttachment:
|
||||||
'There is no preview available for this attachment.',
|
'There is no preview available for this attachment.',
|
||||||
time: 'Time',
|
time: 'Time',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: 'Active users limit reached',
|
activeUsersLimitReached: 'Active users limit reached',
|
||||||
|
adminLoginRequiredToInitializeInstance: 'Admin login required to initialize instance',
|
||||||
emailAlreadyInUse: 'E-mail already in use',
|
emailAlreadyInUse: 'E-mail already in use',
|
||||||
emailOrUsername: 'E-mail or username',
|
emailOrUsername: 'E-mail or username',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: 'I have read and agree to these Terms',
|
||||||
invalidCredentials: 'Invalid credentials',
|
invalidCredentials: 'Invalid credentials',
|
||||||
invalidEmailOrUsername: 'Invalid e-mail or username',
|
invalidEmailOrUsername: 'Invalid e-mail or username',
|
||||||
invalidPassword: 'Invalid password',
|
invalidPassword: 'Invalid password',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: 'Cancel and close',
|
||||||
|
continue: 'Continue',
|
||||||
logIn: 'Log in',
|
logIn: 'Log in',
|
||||||
logInWithSso: 'Log in with SSO',
|
logInWithSso: 'Log in with SSO',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -285,6 +285,7 @@ export default {
|
|||||||
taskListActions_title: 'Task List Actions',
|
taskListActions_title: 'Task List Actions',
|
||||||
taskList_title: 'Task List',
|
taskList_title: 'Task List',
|
||||||
team: 'Team',
|
team: 'Team',
|
||||||
|
terms: 'Terms',
|
||||||
thereIsNoPreviewAvailableForThisAttachment:
|
thereIsNoPreviewAvailableForThisAttachment:
|
||||||
'There is no preview available for this attachment.',
|
'There is no preview available for this attachment.',
|
||||||
time: 'Time',
|
time: 'Time',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: 'Active users limit reached',
|
activeUsersLimitReached: 'Active users limit reached',
|
||||||
|
adminLoginRequiredToInitializeInstance: 'Admin login required to initialize instance',
|
||||||
emailAlreadyInUse: 'E-mail already in use',
|
emailAlreadyInUse: 'E-mail already in use',
|
||||||
emailOrUsername: 'E-mail or username',
|
emailOrUsername: 'E-mail or username',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: 'I have read and agree to these Terms',
|
||||||
invalidCredentials: 'Invalid credentials',
|
invalidCredentials: 'Invalid credentials',
|
||||||
invalidEmailOrUsername: 'Invalid e-mail or username',
|
invalidEmailOrUsername: 'Invalid e-mail or username',
|
||||||
invalidPassword: 'Invalid password',
|
invalidPassword: 'Invalid password',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: 'Cancel and close',
|
||||||
|
continue: 'Continue',
|
||||||
logIn: 'Log in',
|
logIn: 'Log in',
|
||||||
logInWithSso: 'Log in with SSO',
|
logInWithSso: 'Log in with SSO',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -290,6 +290,7 @@ export default {
|
|||||||
taskListActions_title: 'Acciones de la lista de tareas',
|
taskListActions_title: 'Acciones de la lista de tareas',
|
||||||
taskList_title: 'Lista de tareas',
|
taskList_title: 'Lista de tareas',
|
||||||
team: 'Equipo',
|
team: 'Equipo',
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment:
|
thereIsNoPreviewAvailableForThisAttachment:
|
||||||
'No hay vista previa disponible para este adjunto.',
|
'No hay vista previa disponible para este adjunto.',
|
||||||
time: 'Tiempo',
|
time: 'Tiempo',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: null,
|
activeUsersLimitReached: null,
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'El correo ya está en uso',
|
emailAlreadyInUse: 'El correo ya está en uso',
|
||||||
emailOrUsername: 'Correo o nombre de usuario',
|
emailOrUsername: 'Correo o nombre de usuario',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: null,
|
invalidCredentials: null,
|
||||||
invalidEmailOrUsername: 'Correo o nombre de usuario incorrecto',
|
invalidEmailOrUsername: 'Correo o nombre de usuario incorrecto',
|
||||||
invalidPassword: 'Contraseña incorrecta',
|
invalidPassword: 'Contraseña incorrecta',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'Iniciar sesión',
|
logIn: 'Iniciar sesión',
|
||||||
logInWithSso: null,
|
logInWithSso: null,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -289,6 +289,7 @@ export default {
|
|||||||
taskListActions_title: 'Ülesannete nimekiri tegevused',
|
taskListActions_title: 'Ülesannete nimekiri tegevused',
|
||||||
taskList_title: 'Ülesanne nimekiri',
|
taskList_title: 'Ülesanne nimekiri',
|
||||||
team: 'Töögrupp',
|
team: 'Töögrupp',
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment: 'Selle manusi eelvaadet pole saadaval.',
|
thereIsNoPreviewAvailableForThisAttachment: 'Selle manusi eelvaadet pole saadaval.',
|
||||||
time: 'Aeg',
|
time: 'Aeg',
|
||||||
title: 'Pealkiri',
|
title: 'Pealkiri',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: 'Aktiivsete kasutajate limiit on täis',
|
activeUsersLimitReached: 'Aktiivsete kasutajate limiit on täis',
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'E-post on juba kasutusel',
|
emailAlreadyInUse: 'E-post on juba kasutusel',
|
||||||
emailOrUsername: 'E-post või kasutajanimi',
|
emailOrUsername: 'E-post või kasutajanimi',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: 'Vale kasutajanimi või parool',
|
invalidCredentials: 'Vale kasutajanimi või parool',
|
||||||
invalidEmailOrUsername: 'Vale e-post või kasutajanimi',
|
invalidEmailOrUsername: 'Vale e-post või kasutajanimi',
|
||||||
invalidPassword: 'Vale parool',
|
invalidPassword: 'Vale parool',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'Logi sisse',
|
logIn: 'Logi sisse',
|
||||||
logInWithSso: 'Logi sisse SSO-ga',
|
logInWithSso: 'Logi sisse SSO-ga',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -271,6 +271,7 @@ export default {
|
|||||||
taskListActions_title: null,
|
taskListActions_title: null,
|
||||||
taskList_title: null,
|
taskList_title: null,
|
||||||
team: null,
|
team: null,
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment: 'پیش نمایشی برای این پیوست موجود نیست.',
|
thereIsNoPreviewAvailableForThisAttachment: 'پیش نمایشی برای این پیوست موجود نیست.',
|
||||||
time: 'زمان',
|
time: 'زمان',
|
||||||
title: 'عنوان',
|
title: 'عنوان',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: null,
|
activeUsersLimitReached: null,
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'ایمیل قبلا استفاده شده است',
|
emailAlreadyInUse: 'ایمیل قبلا استفاده شده است',
|
||||||
emailOrUsername: 'ایمیل یا نام کاربری',
|
emailOrUsername: 'ایمیل یا نام کاربری',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: null,
|
invalidCredentials: null,
|
||||||
invalidEmailOrUsername: 'ایمیل یا نام کاربری نامعتبر است',
|
invalidEmailOrUsername: 'ایمیل یا نام کاربری نامعتبر است',
|
||||||
invalidPassword: 'رمز عبور نامعتبر است',
|
invalidPassword: 'رمز عبور نامعتبر است',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'ورود',
|
logIn: 'ورود',
|
||||||
logInWithSso: 'ورود با SSO',
|
logInWithSso: 'ورود با SSO',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -285,6 +285,7 @@ export default {
|
|||||||
taskListActions_title: 'Tehtävälistan toiminnot',
|
taskListActions_title: 'Tehtävälistan toiminnot',
|
||||||
taskList_title: 'Tehtävälista',
|
taskList_title: 'Tehtävälista',
|
||||||
team: 'Tiimi',
|
team: 'Tiimi',
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment: 'Tälle liitteelle ei ole esikatselua saatavilla.',
|
thereIsNoPreviewAvailableForThisAttachment: 'Tälle liitteelle ei ole esikatselua saatavilla.',
|
||||||
time: 'Aika',
|
time: 'Aika',
|
||||||
title: 'Otsikko',
|
title: 'Otsikko',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: 'Aktiivisten käyttäjien raja saavutettu',
|
activeUsersLimitReached: 'Aktiivisten käyttäjien raja saavutettu',
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'Sähköposti on jo käytössä',
|
emailAlreadyInUse: 'Sähköposti on jo käytössä',
|
||||||
emailOrUsername: 'Sähköposti tai käyttäjänimi',
|
emailOrUsername: 'Sähköposti tai käyttäjänimi',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: 'Virheelliset tunnistetiedot',
|
invalidCredentials: 'Virheelliset tunnistetiedot',
|
||||||
invalidEmailOrUsername: 'Virheellinen sähköposti tai käyttäjänimi',
|
invalidEmailOrUsername: 'Virheellinen sähköposti tai käyttäjänimi',
|
||||||
invalidPassword: 'Virheellinen salasana',
|
invalidPassword: 'Virheellinen salasana',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'Kirjaudu sisään',
|
logIn: 'Kirjaudu sisään',
|
||||||
logInWithSso: 'Kirjaudu SSO:lla',
|
logInWithSso: 'Kirjaudu SSO:lla',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -293,6 +293,7 @@ export default {
|
|||||||
taskListActions_title: 'Actions de la liste de tâches',
|
taskListActions_title: 'Actions de la liste de tâches',
|
||||||
taskList_title: 'Liste de tâches',
|
taskList_title: 'Liste de tâches',
|
||||||
team: "Mes projets d'équipe",
|
team: "Mes projets d'équipe",
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment:
|
thereIsNoPreviewAvailableForThisAttachment:
|
||||||
"Il n'y a pas d'aperçu disponible pour cette pièce jointe.",
|
"Il n'y a pas d'aperçu disponible pour cette pièce jointe.",
|
||||||
time: 'Temps',
|
time: 'Temps',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: 'La limite d’utilisateurs actifs a été atteinte',
|
activeUsersLimitReached: 'La limite d’utilisateurs actifs a été atteinte',
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'E-mail déjà utilisé',
|
emailAlreadyInUse: 'E-mail déjà utilisé',
|
||||||
emailOrUsername: "E-mail ou nom d'utilisateur",
|
emailOrUsername: "E-mail ou nom d'utilisateur",
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: 'Identifiants invalides',
|
invalidCredentials: 'Identifiants invalides',
|
||||||
invalidEmailOrUsername: "E-mail ou nom d'utilisateur invalide",
|
invalidEmailOrUsername: "E-mail ou nom d'utilisateur invalide",
|
||||||
invalidPassword: 'Mot de passe invalide',
|
invalidPassword: 'Mot de passe invalide',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'Se connecter',
|
logIn: 'Se connecter',
|
||||||
logInWithSso: "Se connecter avec l'authentification unique",
|
logInWithSso: "Se connecter avec l'authentification unique",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -283,6 +283,7 @@ export default {
|
|||||||
taskListActions_title: 'Feladatlista műveletek',
|
taskListActions_title: 'Feladatlista műveletek',
|
||||||
taskList_title: 'Feladatlista',
|
taskList_title: 'Feladatlista',
|
||||||
team: 'Csapat',
|
team: 'Csapat',
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment: 'Nincs elérhető előnézet ehhez a melléklethez.',
|
thereIsNoPreviewAvailableForThisAttachment: 'Nincs elérhető előnézet ehhez a melléklethez.',
|
||||||
time: 'Idő',
|
time: 'Idő',
|
||||||
title: 'Cím',
|
title: 'Cím',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: null,
|
activeUsersLimitReached: null,
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'Az e-mail cím már használatban van',
|
emailAlreadyInUse: 'Az e-mail cím már használatban van',
|
||||||
emailOrUsername: 'E-mail vagy felhasználó',
|
emailOrUsername: 'E-mail vagy felhasználó',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: null,
|
invalidCredentials: null,
|
||||||
invalidEmailOrUsername: 'Érvénytelen e-mail vagy felhasználó',
|
invalidEmailOrUsername: 'Érvénytelen e-mail vagy felhasználó',
|
||||||
invalidPassword: 'Érvénytelen jelszó',
|
invalidPassword: 'Érvénytelen jelszó',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'Belépés',
|
logIn: 'Belépés',
|
||||||
logInWithSso: 'Belépés SSO-val',
|
logInWithSso: 'Belépés SSO-val',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -273,6 +273,7 @@ export default {
|
|||||||
taskListActions_title: null,
|
taskListActions_title: null,
|
||||||
taskList_title: null,
|
taskList_title: null,
|
||||||
team: null,
|
team: null,
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment:
|
thereIsNoPreviewAvailableForThisAttachment:
|
||||||
'Tidak ada pratinjau yang tersedia untuk lampiran ini.',
|
'Tidak ada pratinjau yang tersedia untuk lampiran ini.',
|
||||||
time: 'Waktu',
|
time: 'Waktu',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: null,
|
activeUsersLimitReached: null,
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'E-mail telah digunakan',
|
emailAlreadyInUse: 'E-mail telah digunakan',
|
||||||
emailOrUsername: 'E-mail atau username',
|
emailOrUsername: 'E-mail atau username',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: null,
|
invalidCredentials: null,
|
||||||
invalidEmailOrUsername: 'E-mail atau username salah',
|
invalidEmailOrUsername: 'E-mail atau username salah',
|
||||||
invalidPassword: 'Kata sandi salah',
|
invalidPassword: 'Kata sandi salah',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'Masuk',
|
logIn: 'Masuk',
|
||||||
logInWithSso: 'Masuk dengan SSO',
|
logInWithSso: 'Masuk dengan SSO',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import keyBy from 'lodash/keyBy';
|
||||||
|
|
||||||
import arYE from './ar-YE';
|
import arYE from './ar-YE';
|
||||||
import bgBG from './bg-BG';
|
import bgBG from './bg-BG';
|
||||||
import csCZ from './cs-CZ';
|
import csCZ from './cs-CZ';
|
||||||
@@ -84,3 +86,5 @@ export const embeddedLocales = locales.reduce(
|
|||||||
}),
|
}),
|
||||||
{},
|
{},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const localeByLanguage = keyBy(locales, 'language');
|
||||||
|
|||||||
@@ -291,6 +291,7 @@ export default {
|
|||||||
taskListActions_title: 'Azioni lista di task',
|
taskListActions_title: 'Azioni lista di task',
|
||||||
taskList_title: 'Lista di task',
|
taskList_title: 'Lista di task',
|
||||||
team: 'Team',
|
team: 'Team',
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment:
|
thereIsNoPreviewAvailableForThisAttachment:
|
||||||
'Non è disponibile alcuna anteprima per questo allegato.',
|
'Non è disponibile alcuna anteprima per questo allegato.',
|
||||||
time: 'Tempo',
|
time: 'Tempo',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: 'Limite utenti attivi raggiunto',
|
activeUsersLimitReached: 'Limite utenti attivi raggiunto',
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'E-mail già in uso',
|
emailAlreadyInUse: 'E-mail già in uso',
|
||||||
emailOrUsername: 'E-mail o username',
|
emailOrUsername: 'E-mail o username',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: 'Credenziali non valide',
|
invalidCredentials: 'Credenziali non valide',
|
||||||
invalidEmailOrUsername: 'E-mail o username non valido',
|
invalidEmailOrUsername: 'E-mail o username non valido',
|
||||||
invalidPassword: 'Password non valida',
|
invalidPassword: 'Password non valida',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'Accedi',
|
logIn: 'Accedi',
|
||||||
logInWithSso: null,
|
logInWithSso: null,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -273,6 +273,7 @@ export default {
|
|||||||
taskListActions_title: null,
|
taskListActions_title: null,
|
||||||
taskList_title: null,
|
taskList_title: null,
|
||||||
team: null,
|
team: null,
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment: 'この添付ファイルにはプレビューがありません。',
|
thereIsNoPreviewAvailableForThisAttachment: 'この添付ファイルにはプレビューがありません。',
|
||||||
time: '時間',
|
time: '時間',
|
||||||
title: 'タイトル',
|
title: 'タイトル',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: null,
|
activeUsersLimitReached: null,
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'Eメールは既に使われています',
|
emailAlreadyInUse: 'Eメールは既に使われています',
|
||||||
emailOrUsername: 'Eメールまたはユーザー名',
|
emailOrUsername: 'Eメールまたはユーザー名',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: null,
|
invalidCredentials: null,
|
||||||
invalidEmailOrUsername: 'Eメールまたはユーザー名が無効',
|
invalidEmailOrUsername: 'Eメールまたはユーザー名が無効',
|
||||||
invalidPassword: 'パスワードが無効',
|
invalidPassword: 'パスワードが無効',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'ログイン',
|
logIn: 'ログイン',
|
||||||
logInWithSso: 'SSOでログイン',
|
logInWithSso: 'SSOでログイン',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -271,6 +271,7 @@ export default {
|
|||||||
taskListActions_title: null,
|
taskListActions_title: null,
|
||||||
taskList_title: null,
|
taskList_title: null,
|
||||||
team: null,
|
team: null,
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment:
|
thereIsNoPreviewAvailableForThisAttachment:
|
||||||
'이 첨부 파일에 대한 미리보기를 사용할 수 없습니다.',
|
'이 첨부 파일에 대한 미리보기를 사용할 수 없습니다.',
|
||||||
time: '시간',
|
time: '시간',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: null,
|
activeUsersLimitReached: null,
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: '이미 사용 중인 이메일',
|
emailAlreadyInUse: '이미 사용 중인 이메일',
|
||||||
emailOrUsername: '이메일 또는 사용자 이름',
|
emailOrUsername: '이메일 또는 사용자 이름',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: '잘못된 자격 증명',
|
invalidCredentials: '잘못된 자격 증명',
|
||||||
invalidEmailOrUsername: '잘못된 이메일 또는 사용자 이름',
|
invalidEmailOrUsername: '잘못된 이메일 또는 사용자 이름',
|
||||||
invalidPassword: '잘못된 비밀번호',
|
invalidPassword: '잘못된 비밀번호',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: '로그인',
|
logIn: '로그인',
|
||||||
logInWithSso: 'SSO로 로그인',
|
logInWithSso: 'SSO로 로그인',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -273,6 +273,7 @@ export default {
|
|||||||
taskListActions_title: null,
|
taskListActions_title: null,
|
||||||
taskList_title: null,
|
taskList_title: null,
|
||||||
team: null,
|
team: null,
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment:
|
thereIsNoPreviewAvailableForThisAttachment:
|
||||||
'Er is geen voorbeeld beschikbaar voor deze bijlage.',
|
'Er is geen voorbeeld beschikbaar voor deze bijlage.',
|
||||||
time: 'Tijd',
|
time: 'Tijd',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: null,
|
activeUsersLimitReached: null,
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'E-mail is al in gebruik',
|
emailAlreadyInUse: 'E-mail is al in gebruik',
|
||||||
emailOrUsername: 'E-mail of gebruikersnaam',
|
emailOrUsername: 'E-mail of gebruikersnaam',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: null,
|
invalidCredentials: null,
|
||||||
invalidEmailOrUsername: 'Ongeldig e-mailadres of gebruikersnaam',
|
invalidEmailOrUsername: 'Ongeldig e-mailadres of gebruikersnaam',
|
||||||
invalidPassword: 'Ongeldig wachtwoord',
|
invalidPassword: 'Ongeldig wachtwoord',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'Inloggen',
|
logIn: 'Inloggen',
|
||||||
logInWithSso: 'Inloggen met SSO',
|
logInWithSso: 'Inloggen met SSO',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -281,6 +281,7 @@ export default {
|
|||||||
taskListActions_title: 'Akcje Listy Zadań',
|
taskListActions_title: 'Akcje Listy Zadań',
|
||||||
taskList_title: 'Lista Zadań',
|
taskList_title: 'Lista Zadań',
|
||||||
team: 'Zespół',
|
team: 'Zespół',
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment: 'Brak podglądu dostępnego dla tego załącznika.',
|
thereIsNoPreviewAvailableForThisAttachment: 'Brak podglądu dostępnego dla tego załącznika.',
|
||||||
time: 'Czas',
|
time: 'Czas',
|
||||||
title: 'Tytuł',
|
title: 'Tytuł',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: 'Osiągnięto limit aktywnych użytkowników',
|
activeUsersLimitReached: 'Osiągnięto limit aktywnych użytkowników',
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'E-mail jest już używany',
|
emailAlreadyInUse: 'E-mail jest już używany',
|
||||||
emailOrUsername: 'E-mail lub nazwa użytkownika',
|
emailOrUsername: 'E-mail lub nazwa użytkownika',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: 'Błędne dane logowania',
|
invalidCredentials: 'Błędne dane logowania',
|
||||||
invalidEmailOrUsername: 'Błędny e-mail lub nazwa użytkownika',
|
invalidEmailOrUsername: 'Błędny e-mail lub nazwa użytkownika',
|
||||||
invalidPassword: 'Błędne hasło',
|
invalidPassword: 'Błędne hasło',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'Zaloguj',
|
logIn: 'Zaloguj',
|
||||||
logInWithSso: 'Zaloguj z SSO',
|
logInWithSso: 'Zaloguj z SSO',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -292,6 +292,7 @@ export default {
|
|||||||
taskListActions_title: 'Ações da Lista de Tarefas',
|
taskListActions_title: 'Ações da Lista de Tarefas',
|
||||||
taskList_title: 'Lista de Tarefas',
|
taskList_title: 'Lista de Tarefas',
|
||||||
team: 'Equipe',
|
team: 'Equipe',
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment:
|
thereIsNoPreviewAvailableForThisAttachment:
|
||||||
'Não há pré-visualização disponível para este anexo.',
|
'Não há pré-visualização disponível para este anexo.',
|
||||||
time: 'Tempo',
|
time: 'Tempo',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: null,
|
activeUsersLimitReached: null,
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'E-mail já está em uso',
|
emailAlreadyInUse: 'E-mail já está em uso',
|
||||||
emailOrUsername: 'E-mail ou nome de usuário',
|
emailOrUsername: 'E-mail ou nome de usuário',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: null,
|
invalidCredentials: null,
|
||||||
invalidEmailOrUsername: 'E-mail ou nome de usuário inválido',
|
invalidEmailOrUsername: 'E-mail ou nome de usuário inválido',
|
||||||
invalidPassword: 'Senha inválida',
|
invalidPassword: 'Senha inválida',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'Entrar',
|
logIn: 'Entrar',
|
||||||
logInWithSso: 'Entrar com SSO',
|
logInWithSso: 'Entrar com SSO',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -274,6 +274,7 @@ export default {
|
|||||||
taskListActions_title: null,
|
taskListActions_title: null,
|
||||||
taskList_title: null,
|
taskList_title: null,
|
||||||
team: null,
|
team: null,
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment:
|
thereIsNoPreviewAvailableForThisAttachment:
|
||||||
'Não há pré-visualização disponível para este anexo.',
|
'Não há pré-visualização disponível para este anexo.',
|
||||||
time: 'Tempo',
|
time: 'Tempo',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: null,
|
activeUsersLimitReached: null,
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'E-mail já está em uso',
|
emailAlreadyInUse: 'E-mail já está em uso',
|
||||||
emailOrUsername: 'E-mail ou nome de utilizador',
|
emailOrUsername: 'E-mail ou nome de utilizador',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: null,
|
invalidCredentials: null,
|
||||||
invalidEmailOrUsername: 'E-mail ou nome de utilizador inválido',
|
invalidEmailOrUsername: 'E-mail ou nome de utilizador inválido',
|
||||||
invalidPassword: 'Palavra-passe inválida',
|
invalidPassword: 'Palavra-passe inválida',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'Iniciar sessão',
|
logIn: 'Iniciar sessão',
|
||||||
logInWithSso: 'Iniciar sessão com SSO',
|
logInWithSso: 'Iniciar sessão com SSO',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -273,6 +273,7 @@ export default {
|
|||||||
taskListActions_title: null,
|
taskListActions_title: null,
|
||||||
taskList_title: null,
|
taskList_title: null,
|
||||||
team: null,
|
team: null,
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment:
|
thereIsNoPreviewAvailableForThisAttachment:
|
||||||
'Nu există nicio previzualizare disponibilă pentru acest atașament.',
|
'Nu există nicio previzualizare disponibilă pentru acest atașament.',
|
||||||
time: 'Timp',
|
time: 'Timp',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: null,
|
activeUsersLimitReached: null,
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'E-mail deja utilizat',
|
emailAlreadyInUse: 'E-mail deja utilizat',
|
||||||
emailOrUsername: 'E-mail sau nume de utilizator',
|
emailOrUsername: 'E-mail sau nume de utilizator',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: null,
|
invalidCredentials: null,
|
||||||
invalidEmailOrUsername: 'E-mail sau nume de utilizator introduse greșit',
|
invalidEmailOrUsername: 'E-mail sau nume de utilizator introduse greșit',
|
||||||
invalidPassword: 'Parola greșita',
|
invalidPassword: 'Parola greșita',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'Autentificarea',
|
logIn: 'Autentificarea',
|
||||||
logInWithSso: 'Autentificarea cu SSO',
|
logInWithSso: 'Autentificarea cu SSO',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -288,6 +288,7 @@ export default {
|
|||||||
taskListActions_title: 'Действия с списком задач',
|
taskListActions_title: 'Действия с списком задач',
|
||||||
taskList_title: 'Список задач',
|
taskList_title: 'Список задач',
|
||||||
team: 'Команда',
|
team: 'Команда',
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment: 'Предпросмотр для этого вложения недоступен.',
|
thereIsNoPreviewAvailableForThisAttachment: 'Предпросмотр для этого вложения недоступен.',
|
||||||
time: 'Время',
|
time: 'Время',
|
||||||
title: 'Название',
|
title: 'Название',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: 'Достигнут лимит активных пользователей',
|
activeUsersLimitReached: 'Достигнут лимит активных пользователей',
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'E-mail уже занят',
|
emailAlreadyInUse: 'E-mail уже занят',
|
||||||
emailOrUsername: 'E-mail или имя пользователя',
|
emailOrUsername: 'E-mail или имя пользователя',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: 'Недействительные учетные данные',
|
invalidCredentials: 'Недействительные учетные данные',
|
||||||
invalidEmailOrUsername: 'Неверный e-mail или имя пользователя',
|
invalidEmailOrUsername: 'Неверный e-mail или имя пользователя',
|
||||||
invalidPassword: 'Неверный пароль',
|
invalidPassword: 'Неверный пароль',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'Войти',
|
logIn: 'Войти',
|
||||||
logInWithSso: 'Войти с помощью единого входа',
|
logInWithSso: 'Войти с помощью единого входа',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -273,6 +273,7 @@ export default {
|
|||||||
taskListActions_title: null,
|
taskListActions_title: null,
|
||||||
taskList_title: null,
|
taskList_title: null,
|
||||||
team: null,
|
team: null,
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment: null,
|
thereIsNoPreviewAvailableForThisAttachment: null,
|
||||||
time: 'Čas',
|
time: 'Čas',
|
||||||
title: 'Názov',
|
title: 'Názov',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: null,
|
activeUsersLimitReached: null,
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'E-mail je už použitý',
|
emailAlreadyInUse: 'E-mail je už použitý',
|
||||||
emailOrUsername: 'E-mail alebo používateľské meno',
|
emailOrUsername: 'E-mail alebo používateľské meno',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: null,
|
invalidCredentials: null,
|
||||||
invalidEmailOrUsername: 'Nesprávny e-mail alebo používateľské meno',
|
invalidEmailOrUsername: 'Nesprávny e-mail alebo používateľské meno',
|
||||||
invalidPassword: 'Nesprávne heslo',
|
invalidPassword: 'Nesprávne heslo',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'Prihlásiť sa',
|
logIn: 'Prihlásiť sa',
|
||||||
logInWithSso: null,
|
logInWithSso: null,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -273,6 +273,7 @@ export default {
|
|||||||
taskListActions_title: null,
|
taskListActions_title: null,
|
||||||
taskList_title: null,
|
taskList_title: null,
|
||||||
team: null,
|
team: null,
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment: 'Нема прегледа доступног за овај прилог.',
|
thereIsNoPreviewAvailableForThisAttachment: 'Нема прегледа доступног за овај прилог.',
|
||||||
time: 'Време',
|
time: 'Време',
|
||||||
title: 'Наслов',
|
title: 'Наслов',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: null,
|
activeUsersLimitReached: null,
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'Е-пошта је већ у употреби',
|
emailAlreadyInUse: 'Е-пошта је већ у употреби',
|
||||||
emailOrUsername: 'Е-пошта или корисничко име',
|
emailOrUsername: 'Е-пошта или корисничко име',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: 'Неисправни акредитиви',
|
invalidCredentials: 'Неисправни акредитиви',
|
||||||
invalidEmailOrUsername: 'Неисправна е-пошта или корисничко име',
|
invalidEmailOrUsername: 'Неисправна е-пошта или корисничко име',
|
||||||
invalidPassword: 'Неисправна лозинка',
|
invalidPassword: 'Неисправна лозинка',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'Пријава',
|
logIn: 'Пријава',
|
||||||
logInWithSso: 'Пријава са УП',
|
logInWithSso: 'Пријава са УП',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -270,6 +270,7 @@ export default {
|
|||||||
taskListActions_title: null,
|
taskListActions_title: null,
|
||||||
taskList_title: null,
|
taskList_title: null,
|
||||||
team: null,
|
team: null,
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment: 'Nema pregleda dostupnog za ovaj prilog.',
|
thereIsNoPreviewAvailableForThisAttachment: 'Nema pregleda dostupnog za ovaj prilog.',
|
||||||
time: 'Vreme',
|
time: 'Vreme',
|
||||||
title: 'Naslov',
|
title: 'Naslov',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: null,
|
activeUsersLimitReached: null,
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'E-pošta je već u upotrebi',
|
emailAlreadyInUse: 'E-pošta je već u upotrebi',
|
||||||
emailOrUsername: 'E-pošta ili korisničko ime',
|
emailOrUsername: 'E-pošta ili korisničko ime',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: 'Neispravni akreditivi',
|
invalidCredentials: 'Neispravni akreditivi',
|
||||||
invalidEmailOrUsername: 'Neispravna e-pošta ili korisničko ime',
|
invalidEmailOrUsername: 'Neispravna e-pošta ili korisničko ime',
|
||||||
invalidPassword: 'Neispravna lozinka',
|
invalidPassword: 'Neispravna lozinka',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'Prijava',
|
logIn: 'Prijava',
|
||||||
logInWithSso: 'Prijava sa UP',
|
logInWithSso: 'Prijava sa UP',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -272,6 +272,7 @@ export default {
|
|||||||
taskListActions_title: null,
|
taskListActions_title: null,
|
||||||
taskList_title: null,
|
taskList_title: null,
|
||||||
team: null,
|
team: null,
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment: null,
|
thereIsNoPreviewAvailableForThisAttachment: null,
|
||||||
time: 'Tid',
|
time: 'Tid',
|
||||||
title: 'Titel',
|
title: 'Titel',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: null,
|
activeUsersLimitReached: null,
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'E-mail används redan',
|
emailAlreadyInUse: 'E-mail används redan',
|
||||||
emailOrUsername: 'E-mail eller användarnamn',
|
emailOrUsername: 'E-mail eller användarnamn',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: null,
|
invalidCredentials: null,
|
||||||
invalidEmailOrUsername: 'Ogiltig e-mail eller användarnamn',
|
invalidEmailOrUsername: 'Ogiltig e-mail eller användarnamn',
|
||||||
invalidPassword: 'Ogiltigt lösenord',
|
invalidPassword: 'Ogiltigt lösenord',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'Logga in',
|
logIn: 'Logga in',
|
||||||
logInWithSso: null,
|
logInWithSso: null,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -270,6 +270,7 @@ export default {
|
|||||||
taskListActions_title: null,
|
taskListActions_title: null,
|
||||||
taskList_title: null,
|
taskList_title: null,
|
||||||
team: null,
|
team: null,
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment: 'Bu ek için önizleme mevcut değil.',
|
thereIsNoPreviewAvailableForThisAttachment: 'Bu ek için önizleme mevcut değil.',
|
||||||
time: 'zaman',
|
time: 'zaman',
|
||||||
title: 'başlık',
|
title: 'başlık',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: null,
|
activeUsersLimitReached: null,
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'E-posta adresi zaten kullanımda',
|
emailAlreadyInUse: 'E-posta adresi zaten kullanımda',
|
||||||
emailOrUsername: 'E-posta adresi veya Kullanıcı adı',
|
emailOrUsername: 'E-posta adresi veya Kullanıcı adı',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: null,
|
invalidCredentials: null,
|
||||||
invalidEmailOrUsername: 'Geçersiz e-posta adresi veya kullanıcı adı',
|
invalidEmailOrUsername: 'Geçersiz e-posta adresi veya kullanıcı adı',
|
||||||
invalidPassword: 'Hatalı Şifre',
|
invalidPassword: 'Hatalı Şifre',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'Giriş Yap',
|
logIn: 'Giriş Yap',
|
||||||
logInWithSso: null,
|
logInWithSso: null,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -287,6 +287,7 @@ export default {
|
|||||||
taskListActions_title: 'Дії для списку завдань',
|
taskListActions_title: 'Дії для списку завдань',
|
||||||
taskList_title: 'Список завдань',
|
taskList_title: 'Список завдань',
|
||||||
team: 'Команда',
|
team: 'Команда',
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment: 'Для цього вкладення немає доступного перегляду.',
|
thereIsNoPreviewAvailableForThisAttachment: 'Для цього вкладення немає доступного перегляду.',
|
||||||
time: 'Час',
|
time: 'Час',
|
||||||
title: 'Назва',
|
title: 'Назва',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: 'Досягнуто ліміту активних користувачів',
|
activeUsersLimitReached: 'Досягнуто ліміту активних користувачів',
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'Електронна пошта вже використовується',
|
emailAlreadyInUse: 'Електронна пошта вже використовується',
|
||||||
emailOrUsername: "Електронна пошта або ім'я користувача",
|
emailOrUsername: "Електронна пошта або ім'я користувача",
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: 'Неправильні облікові дані',
|
invalidCredentials: 'Неправильні облікові дані',
|
||||||
invalidEmailOrUsername: "Неправильна електронна пошта або ім'я користувача",
|
invalidEmailOrUsername: "Неправильна електронна пошта або ім'я користувача",
|
||||||
invalidPassword: 'Неправильний пароль',
|
invalidPassword: 'Неправильний пароль',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'Увійти',
|
logIn: 'Увійти',
|
||||||
logInWithSso: 'Увійти за допомогою SSO',
|
logInWithSso: 'Увійти за допомогою SSO',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -269,6 +269,7 @@ export default {
|
|||||||
taskListActions_title: null,
|
taskListActions_title: null,
|
||||||
taskList_title: null,
|
taskList_title: null,
|
||||||
team: null,
|
team: null,
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment: null,
|
thereIsNoPreviewAvailableForThisAttachment: null,
|
||||||
time: 'Vaqt',
|
time: 'Vaqt',
|
||||||
title: 'Sarlavha',
|
title: 'Sarlavha',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: null,
|
activeUsersLimitReached: null,
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: 'E-mail allaqachon mavjud',
|
emailAlreadyInUse: 'E-mail allaqachon mavjud',
|
||||||
emailOrUsername: 'E-mail yoki foydalanuvchi nomi',
|
emailOrUsername: 'E-mail yoki foydalanuvchi nomi',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: null,
|
invalidCredentials: null,
|
||||||
invalidEmailOrUsername: "Noto'g'ri e-mail yoki foydalanuvchi nomi",
|
invalidEmailOrUsername: "Noto'g'ri e-mail yoki foydalanuvchi nomi",
|
||||||
invalidPassword: "Noto'g'ri parol",
|
invalidPassword: "Noto'g'ri parol",
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: 'Kirish',
|
logIn: 'Kirish',
|
||||||
logInWithSso: null,
|
logInWithSso: null,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -271,6 +271,7 @@ export default {
|
|||||||
taskListActions_title: '任务列表操作',
|
taskListActions_title: '任务列表操作',
|
||||||
taskList_title: '任务列表',
|
taskList_title: '任务列表',
|
||||||
team: '团队',
|
team: '团队',
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment: '此附件无法预览',
|
thereIsNoPreviewAvailableForThisAttachment: '此附件无法预览',
|
||||||
time: '时间',
|
time: '时间',
|
||||||
title: '标题',
|
title: '标题',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: '活跃用户数已达上限',
|
activeUsersLimitReached: '活跃用户数已达上限',
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: '邮箱已使用',
|
emailAlreadyInUse: '邮箱已使用',
|
||||||
emailOrUsername: '邮箱或用户名',
|
emailOrUsername: '邮箱或用户名',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: '无效凭证',
|
invalidCredentials: '无效凭证',
|
||||||
invalidEmailOrUsername: '无效的邮箱或用户名',
|
invalidEmailOrUsername: '无效的邮箱或用户名',
|
||||||
invalidPassword: '密码错误',
|
invalidPassword: '密码错误',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: '登录',
|
logIn: '登录',
|
||||||
logInWithSso: '使用SSO登录',
|
logInWithSso: '使用SSO登录',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -267,6 +267,7 @@ export default {
|
|||||||
taskListActions_title: null,
|
taskListActions_title: null,
|
||||||
taskList_title: null,
|
taskList_title: null,
|
||||||
team: null,
|
team: null,
|
||||||
|
terms: null,
|
||||||
thereIsNoPreviewAvailableForThisAttachment: '此附件無法預覽',
|
thereIsNoPreviewAvailableForThisAttachment: '此附件無法預覽',
|
||||||
time: '時間',
|
time: '時間',
|
||||||
title: '標題',
|
title: '標題',
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ export default {
|
|||||||
translation: {
|
translation: {
|
||||||
common: {
|
common: {
|
||||||
activeUsersLimitReached: null,
|
activeUsersLimitReached: null,
|
||||||
|
adminLoginRequiredToInitializeInstance: null,
|
||||||
emailAlreadyInUse: '郵箱已被使用',
|
emailAlreadyInUse: '郵箱已被使用',
|
||||||
emailOrUsername: '郵箱或使用者名稱',
|
emailOrUsername: '郵箱或使用者名稱',
|
||||||
|
iHaveReadAndAgreeToTheseTerms: null,
|
||||||
invalidCredentials: null,
|
invalidCredentials: null,
|
||||||
invalidEmailOrUsername: '無效的郵箱或使用者名稱',
|
invalidEmailOrUsername: '無效的郵箱或使用者名稱',
|
||||||
invalidPassword: '密碼錯誤',
|
invalidPassword: '密碼錯誤',
|
||||||
@@ -20,6 +22,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
action: {
|
action: {
|
||||||
|
cancelAndClose: null,
|
||||||
|
continue: null,
|
||||||
logIn: '登入',
|
logIn: '登入',
|
||||||
logInWithSso: '使用SSO登入',
|
logInWithSso: '使用SSO登入',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export default (state = initialState, { type, payload }) => {
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case ActionTypes.AUTHENTICATE__SUCCESS:
|
case ActionTypes.AUTHENTICATE__SUCCESS:
|
||||||
case ActionTypes.WITH_OIDC_AUTHENTICATE__SUCCESS:
|
case ActionTypes.WITH_OIDC_AUTHENTICATE__SUCCESS:
|
||||||
|
case ActionTypes.TERMS_ACCEPT__SUCCESS:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
accessToken: payload.accessToken,
|
accessToken: payload.accessToken,
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ export default (state = initialState, { type, payload }) => {
|
|||||||
};
|
};
|
||||||
case ActionTypes.AUTHENTICATE__SUCCESS:
|
case ActionTypes.AUTHENTICATE__SUCCESS:
|
||||||
case ActionTypes.WITH_OIDC_AUTHENTICATE__SUCCESS:
|
case ActionTypes.WITH_OIDC_AUTHENTICATE__SUCCESS:
|
||||||
|
case ActionTypes.TERMS_ACCEPT__SUCCESS:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
isInitializing: true,
|
isInitializing: true,
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ export default (state = initialState, { type, payload }) => {
|
|||||||
...state,
|
...state,
|
||||||
homeView: payload.value,
|
homeView: payload.value,
|
||||||
};
|
};
|
||||||
case ActionTypes.LOGOUT__ACCESS_TOKEN_INVALIDATE:
|
case ActionTypes.LOGOUT__ACCESS_TOKEN_REVOKE:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
isLogouting: true,
|
isLogouting: true,
|
||||||
|
|||||||
@@ -16,6 +16,14 @@ const initialState = {
|
|||||||
isSubmitting: false,
|
isSubmitting: false,
|
||||||
isSubmittingWithOidc: false,
|
isSubmittingWithOidc: false,
|
||||||
error: null,
|
error: null,
|
||||||
|
pendingToken: null,
|
||||||
|
step: null,
|
||||||
|
termsForm: {
|
||||||
|
payload: null,
|
||||||
|
isSubmitting: false,
|
||||||
|
isCancelling: false,
|
||||||
|
isLanguageUpdating: false,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// eslint-disable-next-line default-param-last
|
// eslint-disable-next-line default-param-last
|
||||||
@@ -41,14 +49,43 @@ export default (state = initialState, { type, payload }) => {
|
|||||||
};
|
};
|
||||||
case ActionTypes.AUTHENTICATE__SUCCESS:
|
case ActionTypes.AUTHENTICATE__SUCCESS:
|
||||||
case ActionTypes.WITH_OIDC_AUTHENTICATE__SUCCESS:
|
case ActionTypes.WITH_OIDC_AUTHENTICATE__SUCCESS:
|
||||||
|
case ActionTypes.TERMS_ACCEPT__SUCCESS:
|
||||||
|
case ActionTypes.TERMS_CANCEL__SUCCESS:
|
||||||
|
case ActionTypes.TERMS_CANCEL__FAILURE:
|
||||||
return initialState;
|
return initialState;
|
||||||
case ActionTypes.AUTHENTICATE__FAILURE:
|
case ActionTypes.AUTHENTICATE__FAILURE:
|
||||||
|
if (payload.terms) {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
data: initialState.data,
|
||||||
|
pendingToken: payload.error.pendingToken,
|
||||||
|
step: payload.error.step,
|
||||||
|
termsForm: {
|
||||||
|
...state.termsForm,
|
||||||
|
payload: payload.terms,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
isSubmitting: false,
|
isSubmitting: false,
|
||||||
error: payload.error,
|
error: payload.error,
|
||||||
};
|
};
|
||||||
case ActionTypes.WITH_OIDC_AUTHENTICATE__FAILURE:
|
case ActionTypes.WITH_OIDC_AUTHENTICATE__FAILURE:
|
||||||
|
if (payload.terms) {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
data: initialState.data,
|
||||||
|
pendingToken: payload.error.pendingToken,
|
||||||
|
step: payload.error.step,
|
||||||
|
termsForm: {
|
||||||
|
...state.termsForm,
|
||||||
|
payload: payload.terms,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
isSubmittingWithOidc: false,
|
isSubmittingWithOidc: false,
|
||||||
@@ -59,6 +96,53 @@ export default (state = initialState, { type, payload }) => {
|
|||||||
...state,
|
...state,
|
||||||
error: null,
|
error: null,
|
||||||
};
|
};
|
||||||
|
case ActionTypes.TERMS_ACCEPT:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
termsForm: {
|
||||||
|
...state.termsForm,
|
||||||
|
isSubmitting: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
case ActionTypes.TERMS_ACCEPT__FAILURE:
|
||||||
|
return {
|
||||||
|
...initialState,
|
||||||
|
error: payload.error,
|
||||||
|
};
|
||||||
|
case ActionTypes.TERMS_CANCEL:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
pendingToken: null,
|
||||||
|
termsForm: {
|
||||||
|
...state.termsForm,
|
||||||
|
isCancelling: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
case ActionTypes.TERMS_LANGUAGE_UPDATE:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
termsForm: {
|
||||||
|
...state.termsForm,
|
||||||
|
isLanguageUpdating: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
case ActionTypes.TERMS_LANGUAGE_UPDATE__SUCCESS:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
termsForm: {
|
||||||
|
...state.termsForm,
|
||||||
|
payload: payload.terms,
|
||||||
|
isLanguageUpdating: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
case ActionTypes.TERMS_LANGUAGE_UPDATE__FAILURE:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
termsForm: {
|
||||||
|
...state.termsForm,
|
||||||
|
isLanguageUpdating: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,11 +119,11 @@ export function* updateHomeView(value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function* logout(invalidateAccessToken) {
|
export function* logout(revokeAccessToken) {
|
||||||
yield call(removeAccessToken);
|
yield call(removeAccessToken);
|
||||||
|
|
||||||
if (invalidateAccessToken) {
|
if (revokeAccessToken) {
|
||||||
yield put(actions.logout.invalidateAccessToken());
|
yield put(actions.logout.revokeAccessToken());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
yield call(request, api.deleteCurrentAccessToken);
|
yield call(request, api.deleteCurrentAccessToken);
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ export default function* coreWatchers() {
|
|||||||
takeEvery(EntryActionTypes.HOME_VIEW_UPDATE, ({ payload: { value } }) =>
|
takeEvery(EntryActionTypes.HOME_VIEW_UPDATE, ({ payload: { value } }) =>
|
||||||
services.updateHomeView(value),
|
services.updateHomeView(value),
|
||||||
),
|
),
|
||||||
takeEvery(EntryActionTypes.LOGOUT, ({ payload: { invalidateAccessToken } }) =>
|
takeEvery(EntryActionTypes.LOGOUT, ({ payload: { revokeAccessToken } }) =>
|
||||||
services.logout(invalidateAccessToken),
|
services.logout(revokeAccessToken),
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,12 @@ export default function* loginSaga() {
|
|||||||
const watcherTasks = yield all(watchers.map((watcher) => fork(watcher)));
|
const watcherTasks = yield all(watchers.map((watcher) => fork(watcher)));
|
||||||
|
|
||||||
yield fork(services.initializeLogin);
|
yield fork(services.initializeLogin);
|
||||||
yield take([ActionTypes.AUTHENTICATE__SUCCESS, ActionTypes.WITH_OIDC_AUTHENTICATE__SUCCESS]);
|
|
||||||
|
yield take([
|
||||||
|
ActionTypes.AUTHENTICATE__SUCCESS,
|
||||||
|
ActionTypes.WITH_OIDC_AUTHENTICATE__SUCCESS,
|
||||||
|
ActionTypes.TERMS_ACCEPT__SUCCESS,
|
||||||
|
]);
|
||||||
|
|
||||||
yield cancel(watcherTasks);
|
yield cancel(watcherTasks);
|
||||||
yield call(services.goToRoot);
|
yield call(services.goToRoot);
|
||||||
|
|||||||
@@ -10,8 +10,10 @@ import { replace } from '../../../lib/redux-router';
|
|||||||
import selectors from '../../../selectors';
|
import selectors from '../../../selectors';
|
||||||
import actions from '../../../actions';
|
import actions from '../../../actions';
|
||||||
import api from '../../../api';
|
import api from '../../../api';
|
||||||
|
import i18n from '../../../i18n';
|
||||||
import { setAccessToken } from '../../../utils/access-token-storage';
|
import { setAccessToken } from '../../../utils/access-token-storage';
|
||||||
import Paths from '../../../constants/Paths';
|
import Paths from '../../../constants/Paths';
|
||||||
|
import AccessTokenSteps from '../../../constants/AccessTokenSteps';
|
||||||
|
|
||||||
export function* initializeLogin() {
|
export function* initializeLogin() {
|
||||||
const { item: config } = yield call(api.getConfig); // TODO: handle error
|
const { item: config } = yield call(api.getConfig); // TODO: handle error
|
||||||
@@ -26,7 +28,12 @@ export function* authenticate(data) {
|
|||||||
try {
|
try {
|
||||||
({ item: accessToken } = yield call(api.createAccessToken, data));
|
({ item: accessToken } = yield call(api.createAccessToken, data));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
yield put(actions.authenticate.failure(error));
|
let terms;
|
||||||
|
if (error.step === AccessTokenSteps.ACCEPT_TERMS) {
|
||||||
|
({ item: terms } = yield call(api.getTerms, error.termsType, i18n.resolvedLanguage));
|
||||||
|
}
|
||||||
|
|
||||||
|
yield put(actions.authenticate.failure(error, terms));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +113,12 @@ export function* authenticateWithOidcCallback() {
|
|||||||
nonce,
|
nonce,
|
||||||
}));
|
}));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
yield put(actions.authenticateWithOidc.failure(error));
|
let terms;
|
||||||
|
if (error.step === AccessTokenSteps.ACCEPT_TERMS) {
|
||||||
|
({ item: terms } = yield call(api.getTerms, error.termsType, i18n.resolvedLanguage));
|
||||||
|
}
|
||||||
|
|
||||||
|
yield put(actions.authenticateWithOidc.failure(error, terms));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,10 +130,70 @@ export function* clearAuthenticateError() {
|
|||||||
yield put(actions.clearAuthenticateError());
|
yield put(actions.clearAuthenticateError());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function* acceptTerms(signature) {
|
||||||
|
yield put(actions.acceptTerms(signature));
|
||||||
|
|
||||||
|
const { pendingToken } = yield select(selectors.selectAuthenticateForm);
|
||||||
|
|
||||||
|
let accessToken;
|
||||||
|
try {
|
||||||
|
({ item: accessToken } = yield call(api.acceptTerms, {
|
||||||
|
pendingToken,
|
||||||
|
signature,
|
||||||
|
}));
|
||||||
|
} catch (error) {
|
||||||
|
yield put(actions.acceptTerms.failure(error));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield call(setAccessToken, accessToken);
|
||||||
|
yield put(actions.acceptTerms.success(accessToken));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function* cancelTerms() {
|
||||||
|
const { pendingToken } = yield select(selectors.selectAuthenticateForm);
|
||||||
|
|
||||||
|
yield put(actions.cancelTerms());
|
||||||
|
|
||||||
|
try {
|
||||||
|
yield call(api.revokePendingToken, {
|
||||||
|
pendingToken,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
yield put(actions.cancelTerms.failure(error));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield put(actions.cancelTerms.success(pendingToken));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function* updateTermsLanguage(value) {
|
||||||
|
yield put(actions.updateTermsLanguage(value));
|
||||||
|
|
||||||
|
const {
|
||||||
|
termsForm: {
|
||||||
|
payload: { type },
|
||||||
|
},
|
||||||
|
} = yield select(selectors.selectAuthenticateForm);
|
||||||
|
|
||||||
|
let terms;
|
||||||
|
try {
|
||||||
|
({ item: terms } = yield call(api.getTerms, type, value));
|
||||||
|
} catch (error) {
|
||||||
|
yield put(actions.updateTermsLanguage.failure(error));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield put(actions.updateTermsLanguage.success(terms));
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
initializeLogin,
|
initializeLogin,
|
||||||
authenticate,
|
authenticate,
|
||||||
authenticateWithOidc,
|
authenticateWithOidc,
|
||||||
authenticateWithOidcCallback,
|
authenticateWithOidcCallback,
|
||||||
clearAuthenticateError,
|
clearAuthenticateError,
|
||||||
|
acceptTerms,
|
||||||
|
cancelTerms,
|
||||||
|
updateTermsLanguage,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,5 +15,12 @@ export default function* loginWatchers() {
|
|||||||
),
|
),
|
||||||
takeEvery(EntryActionTypes.WITH_OIDC_AUTHENTICATE, () => services.authenticateWithOidc()),
|
takeEvery(EntryActionTypes.WITH_OIDC_AUTHENTICATE, () => services.authenticateWithOidc()),
|
||||||
takeEvery(EntryActionTypes.AUTHENTICATE_ERROR_CLEAR, () => services.clearAuthenticateError()),
|
takeEvery(EntryActionTypes.AUTHENTICATE_ERROR_CLEAR, () => services.clearAuthenticateError()),
|
||||||
|
takeEvery(EntryActionTypes.TERMS_ACCEPT, ({ payload: { signature } }) =>
|
||||||
|
services.acceptTerms(signature),
|
||||||
|
),
|
||||||
|
takeEvery(EntryActionTypes.TERMS_CANCEL, () => services.cancelTerms()),
|
||||||
|
takeEvery(EntryActionTypes.TERMS_LANGUAGE_UPDATE, ({ payload: { value } }) =>
|
||||||
|
services.updateTermsLanguage(value),
|
||||||
|
),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
133
server/api/controllers/access-tokens/accept-terms.js
Normal file
133
server/api/controllers/access-tokens/accept-terms.js
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
/*!
|
||||||
|
* Copyright (c) 2024 PLANKA Software GmbH
|
||||||
|
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||||
|
*/
|
||||||
|
|
||||||
|
const { getRemoteAddress } = require('../../../utils/remote-address');
|
||||||
|
|
||||||
|
const { AccessTokenSteps } = require('../../../constants');
|
||||||
|
|
||||||
|
const Errors = {
|
||||||
|
INVALID_PENDING_TOKEN: {
|
||||||
|
invalidPendingToken: 'Invalid pending token',
|
||||||
|
},
|
||||||
|
INVALID_SIGNATURE: {
|
||||||
|
invalidSignature: 'Invalid signature',
|
||||||
|
},
|
||||||
|
ADMIN_LOGIN_REQUIRED_TO_INITIALIZE_INSTANCE: {
|
||||||
|
adminLoginRequiredToInitializeInstance: 'Admin login required to initialize instance',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
inputs: {
|
||||||
|
pendingToken: {
|
||||||
|
type: 'string',
|
||||||
|
maxLength: 1024,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
signature: {
|
||||||
|
type: 'string',
|
||||||
|
minLength: 64,
|
||||||
|
maxLength: 64,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
exits: {
|
||||||
|
invalidPendingToken: {
|
||||||
|
responseType: 'unauthorized',
|
||||||
|
},
|
||||||
|
invalidSignature: {
|
||||||
|
responseType: 'forbidden',
|
||||||
|
},
|
||||||
|
adminLoginRequiredToInitializeInstance: {
|
||||||
|
responseType: 'forbidden',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
async fn(inputs) {
|
||||||
|
const remoteAddress = getRemoteAddress(this.req);
|
||||||
|
const { httpOnlyToken } = this.req.cookies;
|
||||||
|
|
||||||
|
try {
|
||||||
|
payload = sails.helpers.utils.verifyJwtToken(inputs.pendingToken);
|
||||||
|
} catch (error) {
|
||||||
|
if (error.raw.name === 'TokenExpiredError') {
|
||||||
|
throw Errors.INVALID_PENDING_TOKEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
sails.log.warn(`Invalid pending token! (IP: ${remoteAddress})`);
|
||||||
|
throw Errors.INVALID_PENDING_TOKEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (payload.subject !== AccessTokenSteps.ACCEPT_TERMS) {
|
||||||
|
throw Errors.INVALID_PENDING_TOKEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
let session = await Session.qm.getOneUndeletedByPendingToken(inputs.pendingToken);
|
||||||
|
|
||||||
|
if (!session) {
|
||||||
|
sails.log.warn(`Invalid pending token! (IP: ${remoteAddress})`);
|
||||||
|
throw Errors.INVALID_PENDING_TOKEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session.httpOnlyToken && httpOnlyToken !== session.httpOnlyToken) {
|
||||||
|
throw Errors.INVALID_PENDING_TOKEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
let user = await User.qm.getOneById(session.userId, {
|
||||||
|
withDeactivated: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
throw Errors.INVALID_PENDING_TOKEN; // TODO: introduce separate error?
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!user.termsSignature) {
|
||||||
|
const termsSignature = sails.hooks.terms.getSignatureByUserRole(user.role);
|
||||||
|
|
||||||
|
if (inputs.signature !== termsSignature) {
|
||||||
|
throw Errors.INVALID_SIGNATURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
user = await User.qm.updateOne(user.id, {
|
||||||
|
termsSignature,
|
||||||
|
termsAcceptedAt: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = await Config.qm.getOneMain();
|
||||||
|
|
||||||
|
if (!config.isInitialized) {
|
||||||
|
if (user.role === User.Roles.ADMIN) {
|
||||||
|
await Config.qm.updateOneMain({
|
||||||
|
isInitialized: true,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw Errors.ADMIN_LOGIN_REQUIRED_TO_INITIALIZE_INSTANCE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { token: accessToken, payload: accessTokenPayload } = sails.helpers.utils.createJwtToken(
|
||||||
|
user.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
session = await Session.qm.updateOne(session.id, {
|
||||||
|
accessToken,
|
||||||
|
pendingToken: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (session.httpOnlyToken && !this.req.isSocket) {
|
||||||
|
sails.helpers.utils.setHttpOnlyTokenCookie(
|
||||||
|
session.httpOnlyToken,
|
||||||
|
accessTokenPayload,
|
||||||
|
this.res,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
item: accessToken,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -4,7 +4,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const bcrypt = require('bcrypt');
|
const bcrypt = require('bcrypt');
|
||||||
const { v4: uuid } = require('uuid');
|
|
||||||
|
|
||||||
const { isEmailOrUsername } = require('../../../utils/validators');
|
const { isEmailOrUsername } = require('../../../utils/validators');
|
||||||
const { getRemoteAddress } = require('../../../utils/remote-address');
|
const { getRemoteAddress } = require('../../../utils/remote-address');
|
||||||
@@ -22,6 +21,9 @@ const Errors = {
|
|||||||
USE_SINGLE_SIGN_ON: {
|
USE_SINGLE_SIGN_ON: {
|
||||||
useSingleSignOn: 'Use single sign-on',
|
useSingleSignOn: 'Use single sign-on',
|
||||||
},
|
},
|
||||||
|
TERMS_ACCEPTANCE_REQUIRED: {
|
||||||
|
termsAcceptanceRequired: 'Terms acceptance required',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
@@ -39,7 +41,6 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
withHttpOnlyToken: {
|
withHttpOnlyToken: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
defaultsTo: false,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -56,6 +57,12 @@ module.exports = {
|
|||||||
useSingleSignOn: {
|
useSingleSignOn: {
|
||||||
responseType: 'forbidden',
|
responseType: 'forbidden',
|
||||||
},
|
},
|
||||||
|
termsAcceptanceRequired: {
|
||||||
|
responseType: 'forbidden',
|
||||||
|
},
|
||||||
|
adminLoginRequiredToInitializeInstance: {
|
||||||
|
responseType: 'forbidden',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
async fn(inputs) {
|
async fn(inputs) {
|
||||||
@@ -90,26 +97,19 @@ module.exports = {
|
|||||||
: Errors.INVALID_CREDENTIALS;
|
: Errors.INVALID_CREDENTIALS;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { token: accessToken, payload: accessTokenPayload } = sails.helpers.utils.createJwtToken(
|
return sails.helpers.accessTokens.handleSteps
|
||||||
user.id,
|
.with({
|
||||||
);
|
user,
|
||||||
|
remoteAddress,
|
||||||
const httpOnlyToken = inputs.withHttpOnlyToken ? uuid() : null;
|
request: this.req,
|
||||||
|
response: this.res,
|
||||||
await Session.qm.createOne({
|
withHttpOnlyToken: inputs.withHttpOnlyToken,
|
||||||
accessToken,
|
})
|
||||||
httpOnlyToken,
|
.intercept('adminLoginRequiredToInitializeInstance', (error) => ({
|
||||||
remoteAddress,
|
adminLoginRequiredToInitializeInstance: error.raw,
|
||||||
userId: user.id,
|
}))
|
||||||
userAgent: this.req.headers['user-agent'],
|
.intercept('termsAcceptanceRequired', (error) => ({
|
||||||
});
|
termsAcceptanceRequired: error.raw,
|
||||||
|
}));
|
||||||
if (httpOnlyToken && !this.req.isSocket) {
|
|
||||||
sails.helpers.utils.setHttpOnlyTokenCookie(httpOnlyToken, accessTokenPayload, this.res);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
item: accessToken,
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,8 +3,6 @@
|
|||||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const { v4: uuid } = require('uuid');
|
|
||||||
|
|
||||||
const { getRemoteAddress } = require('../../../utils/remote-address');
|
const { getRemoteAddress } = require('../../../utils/remote-address');
|
||||||
|
|
||||||
const Errors = {
|
const Errors = {
|
||||||
@@ -17,6 +15,9 @@ const Errors = {
|
|||||||
INVALID_USERINFO_CONFIGURATION: {
|
INVALID_USERINFO_CONFIGURATION: {
|
||||||
invalidUserinfoConfiguration: 'Invalid userinfo configuration',
|
invalidUserinfoConfiguration: 'Invalid userinfo configuration',
|
||||||
},
|
},
|
||||||
|
TERMS_ACCEPTANCE_REQUIRED: {
|
||||||
|
termsAcceptanceRequired: 'Terms acceptance required',
|
||||||
|
},
|
||||||
EMAIL_ALREADY_IN_USE: {
|
EMAIL_ALREADY_IN_USE: {
|
||||||
emailAlreadyInUse: 'Email already in use',
|
emailAlreadyInUse: 'Email already in use',
|
||||||
},
|
},
|
||||||
@@ -45,7 +46,6 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
withHttpOnlyToken: {
|
withHttpOnlyToken: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
defaultsTo: false,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -59,6 +59,12 @@ module.exports = {
|
|||||||
invalidUserinfoConfiguration: {
|
invalidUserinfoConfiguration: {
|
||||||
responseType: 'unauthorized',
|
responseType: 'unauthorized',
|
||||||
},
|
},
|
||||||
|
termsAcceptanceRequired: {
|
||||||
|
responseType: 'forbidden',
|
||||||
|
},
|
||||||
|
adminLoginRequiredToInitializeInstance: {
|
||||||
|
responseType: 'forbidden',
|
||||||
|
},
|
||||||
emailAlreadyInUse: {
|
emailAlreadyInUse: {
|
||||||
responseType: 'conflict',
|
responseType: 'conflict',
|
||||||
},
|
},
|
||||||
@@ -89,26 +95,19 @@ module.exports = {
|
|||||||
.intercept('activeLimitReached', () => Errors.ACTIVE_USERS_LIMIT_REACHED)
|
.intercept('activeLimitReached', () => Errors.ACTIVE_USERS_LIMIT_REACHED)
|
||||||
.intercept('missingValues', () => Errors.MISSING_VALUES);
|
.intercept('missingValues', () => Errors.MISSING_VALUES);
|
||||||
|
|
||||||
const { token: accessToken, payload: accessTokenPayload } = sails.helpers.utils.createJwtToken(
|
return sails.helpers.accessTokens.handleSteps
|
||||||
user.id,
|
.with({
|
||||||
);
|
user,
|
||||||
|
remoteAddress,
|
||||||
const httpOnlyToken = inputs.withHttpOnlyToken ? uuid() : null;
|
request: this.req,
|
||||||
|
response: this.res,
|
||||||
await Session.qm.createOne({
|
withHttpOnlyToken: inputs.withHttpOnlyToken,
|
||||||
accessToken,
|
})
|
||||||
httpOnlyToken,
|
.intercept('adminLoginRequiredToInitializeInstance', (error) => ({
|
||||||
remoteAddress,
|
adminLoginRequiredToInitializeInstance: error.raw,
|
||||||
userId: user.id,
|
}))
|
||||||
userAgent: this.req.headers['user-agent'],
|
.intercept('termsAcceptanceRequired', (error) => ({
|
||||||
});
|
termsAcceptanceRequired: error.raw,
|
||||||
|
}));
|
||||||
if (httpOnlyToken && !this.req.isSocket) {
|
|
||||||
sails.helpers.utils.setHttpOnlyTokenCookie(httpOnlyToken, accessTokenPayload, this.res);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
item: accessToken,
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
49
server/api/controllers/access-tokens/revoke-pending-token.js
Normal file
49
server/api/controllers/access-tokens/revoke-pending-token.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*!
|
||||||
|
* Copyright (c) 2024 PLANKA Software GmbH
|
||||||
|
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||||
|
*/
|
||||||
|
|
||||||
|
const Errors = {
|
||||||
|
PENDING_TOKEN_NOT_FOUND: {
|
||||||
|
pendingTokenNotFound: 'Pending token not found',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
inputs: {
|
||||||
|
pendingToken: {
|
||||||
|
type: 'string',
|
||||||
|
maxLength: 1024,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
exits: {
|
||||||
|
pendingTokenNotFound: {
|
||||||
|
responseType: 'notFound',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
async fn(inputs) {
|
||||||
|
const { httpOnlyToken } = this.req.cookies;
|
||||||
|
let session = await Session.qm.getOneUndeletedByPendingToken(inputs.pendingToken);
|
||||||
|
|
||||||
|
if (!session) {
|
||||||
|
throw Errors.PENDING_TOKEN_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session.httpOnlyToken && httpOnlyToken !== session.httpOnlyToken) {
|
||||||
|
throw Errors.PENDING_TOKEN_NOT_FOUND; // Forbidden
|
||||||
|
}
|
||||||
|
|
||||||
|
session = await Session.qm.deleteOneById(session.id);
|
||||||
|
|
||||||
|
if (session.httpOnlyToken && !this.req.isSocket) {
|
||||||
|
sails.helpers.utils.clearHttpOnlyTokenCookie(this.res);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
item: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
26
server/api/controllers/terms/show.js
Normal file
26
server/api/controllers/terms/show.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*!
|
||||||
|
* Copyright (c) 2024 PLANKA Software GmbH
|
||||||
|
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
inputs: {
|
||||||
|
type: {
|
||||||
|
type: 'string',
|
||||||
|
isIn: Object.values(sails.hooks.terms.Types),
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
language: {
|
||||||
|
type: 'string',
|
||||||
|
isIn: User.LANGUAGES,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
async fn(inputs) {
|
||||||
|
const terms = await sails.hooks.terms.getPayload(inputs.type, inputs.language);
|
||||||
|
|
||||||
|
return {
|
||||||
|
item: terms,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user