1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-01-17 18:44:45 +02:00

Merge branch 'dev' into release-2.6

This commit is contained in:
Laurent Cozic 2021-12-16 13:54:32 +01:00
commit b903542aed
9 changed files with 39 additions and 14 deletions

View File

@ -38,8 +38,9 @@ export async function getDeviceTimeDrift(): Promise<number> {
break;
} catch (error) {
if (tryCount >= maxTries) {
error.message = `Cannot retrieve the network time: ${error.message}`;
throw error;
const newError = typeof error === 'string' ? new Error(error) : error;
newError.message = `Cannot retrieve the network time from ${server.domain}:${server.port}: ${newError.message}`;
throw newError;
} else {
await time.msleep(tryCount * 1000);
}

View File

@ -23,6 +23,7 @@ import setupCommands from './utils/setupCommands';
import { RouteResponseFormat, routeResponseFormat } from './utils/routeUtils';
import { parseEnv } from './env';
import storageConnectionCheck from './utils/storageConnectionCheck';
import { setLocale } from '@joplin/lib/locale';
interface Argv {
env?: Env;
@ -254,11 +255,15 @@ async function main() {
if (config().maxTimeDrift) {
const timeDrift = await getDeviceTimeDrift();
if (Math.abs(timeDrift) > config().maxTimeDrift) {
throw new Error(`The device time drift is ${timeDrift}ms (Max allowed: ${config().maxTimeDrift}ms) - cannot continue as it could cause data loss and conflicts on the sync clients. You may increase env var MAX_TIME_DRIFT to pass the check.`);
throw new Error(`The device time drift is ${timeDrift}ms (Max allowed: ${config().maxTimeDrift}ms) - cannot continue as it could cause data loss and conflicts on the sync clients. You may increase env var MAX_TIME_DRIFT to pass the check, or set to 0 to disabled the check.`);
}
appLogger().info(`NTP time offset: ${timeDrift}ms`);
} else {
appLogger().info('Skipping NTP time check because MAX_TIME_DRIFT is 0.');
}
setLocale('en_GB');
appLogger().info('Running in Docker:', runningInDocker());
appLogger().info('Public base URL:', config().baseUrl);
appLogger().info('API base URL:', config().apiBaseUrl);

View File

@ -16,7 +16,7 @@ describe('index_changes', function() {
});
test('should list changes', async function() {
const { user: user1, session: session1 } = await createUserAndSession(1);
const { user: user1, session: session1 } = await createUserAndSession(1, true);
const items: any = {};
for (let i = 1; i <= 150; i++) {

View File

@ -9,10 +9,13 @@ import defaultView from '../../utils/defaultView';
import { View } from '../../services/MustacheService';
import { makeTablePagination, Table, Row, makeTableView } from '../../utils/views/table';
import config, { showItemUrls } from '../../config';
import { ErrorForbidden } from '../../utils/errors';
const router = new Router(RouteType.Web);
router.get('changes', async (_path: SubPath, ctx: AppContext) => {
if (!ctx.joplin.owner.is_admin) throw new ErrorForbidden();
const pagination = makeTablePagination(ctx.query, 'updated_time', PaginationOrderDir.DESC);
const paginatedChanges = await ctx.joplin.models.change().allByUser(ctx.joplin.owner.id, pagination);
const items = await ctx.joplin.models.item().loadByIds(paginatedChanges.items.map(i => i.item_id), { fields: ['id'] });

View File

@ -16,7 +16,7 @@ describe('index_items', function() {
});
test('should list the user items', async function() {
const { user: user1, session: session1 } = await createUserAndSession(1);
const { user: user1, session: session1 } = await createUserAndSession(1, true);
const items: any = {};
for (let i = 1; i <= 150; i++) {

View File

@ -2,7 +2,7 @@ import { SubPath, respondWithItemContent } from '../../utils/routeUtils';
import Router from '../../utils/Router';
import { RouteType } from '../../utils/types';
import { AppContext } from '../../utils/types';
import { ErrorNotFound } from '../../utils/errors';
import { ErrorForbidden, ErrorNotFound } from '../../utils/errors';
import config, { showItemUrls } from '../../config';
import { formatDateTime } from '../../utils/time';
import defaultView from '../../utils/defaultView';
@ -14,6 +14,8 @@ import { formatBytes } from '../../utils/bytes';
const router = new Router(RouteType.Web);
router.get('items', async (_path: SubPath, ctx: AppContext) => {
if (!ctx.joplin.owner.is_admin) throw new ErrorForbidden();
const pagination = makeTablePagination(ctx.query, 'name', PaginationOrderDir.ASC);
const paginatedItems = await ctx.joplin.models.item().children(ctx.joplin.owner.id, '', pagination, { fields: ['id', 'name', 'updated_time', 'mime_type', 'content_size'] });

View File

@ -8,6 +8,7 @@ import { User } from '../services/database/types';
import { makeUrl, UrlType } from '../utils/routeUtils';
import MarkdownIt = require('markdown-it');
import { headerAnchor } from '@joplin/renderer';
import { _ } from '@joplin/lib/locale';
export interface RenderOptions {
partials?: any;
@ -191,6 +192,15 @@ export default class MustacheService {
const layoutView: any = {
global: globalParams,
s: {
home: _('Home'),
users: _('Users'),
items: _('Items'),
log: _('Log'),
tasks: _('Tasks'),
help: _('Help'),
logout: _('Logout'),
},
pageName: view.name,
pageTitle: view.titleOverride ? view.title : `${config().appName} - ${view.title}`,
contentHtml: contentHtml,

View File

@ -5,6 +5,6 @@ const generate = require('nanoid/generate');
// > On the other hand, 128 bits (between 21 and 22 characters
// > alphanumeric) is beyond the reach of brute-force attacks pretty much
// > indefinitely
export default function uuidgen(length: number = 32): string {
export default function uuidgen(length: number = 22): string {
return generate('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', length);
}

View File

@ -10,23 +10,27 @@
{{#global.owner}}
<div class="navbar-menu is-active">
<div class="navbar-start">
<a class="navbar-item" href="{{{global.baseUrl}}}/home">Home</a>
<a class="navbar-item" href="{{{global.baseUrl}}}/home">{{s.home}}</a>
{{#global.owner.is_admin}}
<a class="navbar-item" href="{{{global.baseUrl}}}/users">Users</a>
<a class="navbar-item" href="{{{global.baseUrl}}}/users">{{s.users}}</a>
{{/global.owner.is_admin}}
<a class="navbar-item" href="{{{global.baseUrl}}}/items">Items</a>
<a class="navbar-item" href="{{{global.baseUrl}}}/changes">Log</a>
{{#global.owner.is_admin}}
<a class="navbar-item" href="{{{global.baseUrl}}}/tasks">Tasks</a>
<a class="navbar-item" href="{{{global.baseUrl}}}/items">{{s.items}}</a>
{{/global.owner.is_admin}}
{{#global.owner.is_admin}}
<a class="navbar-item" href="{{{global.baseUrl}}}/changes">{{s.log}}</a>
{{/global.owner.is_admin}}
{{#global.owner.is_admin}}
<a class="navbar-item" href="{{{global.baseUrl}}}/tasks">{{s.tasks}}</a>
{{/global.owner.is_admin}}
</div>
<div class="navbar-end">
{{#global.isJoplinCloud}}
<a class="navbar-item" href="{{{global.baseUrl}}}/help">Help</a>
<a class="navbar-item" href="{{{global.baseUrl}}}/help">{{s.help}}</a>
{{/global.isJoplinCloud}}
<div class="navbar-item">
<form method="post" action="{{{global.baseUrl}}}/logout">
<button class="button is-dark">Logout</button>
<button class="button is-dark">{{s.logout}}</button>
</form>
</div>
<div class="navbar-item">