1
0
mirror of https://github.com/laurent22/joplin.git synced 2026-01-14 00:29:38 +02:00

Compare commits

..

2 Commits

Author SHA1 Message Date
Laurent Cozic
058bd3c2f6 log 2021-10-23 17:05:28 +01:00
Laurent Cozic
c101555773 delete old changes 2021-10-23 16:34:39 +01:00
34 changed files with 5913 additions and 9632 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 470 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -2,12 +2,11 @@
<div class="container">
<div class="row">
<div class="col-12 col-md-12 social-links">
<a href="https://twitter.com/joplinapp" title="Joplin Twitter feed"><i class="fab fa-twitter"></i></a>
<a href="https://mastodon.social/@joplinapp" title="Joplin Mastodon feed"><i class="fab fa-mastodon"></i></a>
<a href="https://www.patreon.com/joplin" title="Joplin Patreon"><i class="fab fa-patreon"></i></a>
<a href="https://discordapp.com/invite/d2HMPwE" title="Joplin Discord chat"><i class="fab fa-discord"></i></a>
<a href="https://www.reddit.com/r/joplinapp/" title="Joplin Subreddit"><i class="fab fa-reddit"></i></a>
<a href="https://github.com/laurent22/joplin/" title="Joplin GitHub repository"><i class="fab fa-github"></i></a>
<a href="https://twitter.com/joplinapp" title="Twitter feed"><i class="fab fa-twitter"></i></a>
<a href="https://github.com/laurent22/joplin/" title="GitHub repository"><i class="fab fa-github"></i></a>
<a href="https://www.patreon.com/joplin" title="Patreon blog"><i class="fab fa-patreon"></i></a>
<a href="https://discordapp.com/invite/d2HMPwE" title="Discord chat"><i class="fab fa-discord"></i></a>
<a href="https://www.reddit.com/r/joplinapp/" title="Subreddit"><i class="fab fa-reddit"></i></a>
</div>
</div>

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 730 KiB

After

Width:  |  Height:  |  Size: 498 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 141 KiB

After

Width:  |  Height:  |  Size: 102 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 898 KiB

After

Width:  |  Height:  |  Size: 410 KiB

View File

@@ -58,18 +58,18 @@ COPY --chown=$user:$user packages/fork-htmlparser2 ./packages/fork-htmlparser2
RUN npm run bootstrap
# We have a separate step for the server files because they are more likely to
# change. And we need all the server files because there is a postinstall
# script.
# change.
COPY --chown=$user:$user packages/server ./packages/server
COPY --chown=$user:$user packages/server/package*.json ./packages/server/
RUN npm run bootstrapServerOnly
# Now copy the source files. Put lib last as it's more likely to change.
# Now copy the source files. Put lib and server last as they are more likely to change.
COPY --chown=$user:$user packages/fork-sax ./packages/fork-sax
COPY --chown=$user:$user packages/renderer ./packages/renderer
COPY --chown=$user:$user packages/tools ./packages/tools
COPY --chown=$user:$user packages/lib ./packages/lib
COPY --chown=$user:$user packages/server ./packages/server
# Finally build everything, in particular the TypeScript files.

View File

@@ -476,11 +476,11 @@ Please see the [donation page](https://github.com/laurent22/joplin/blob/dev/read
Name | Description
--- | ---
[Support Forum](https://discourse.joplinapp.org/) | This is the main place for general discussion about Joplin, user support, software development questions, and to discuss new features. Also where the latest beta versions are released and discussed.
[Twitter feed](https://twitter.com/joplinapp) | Follow us on Twitter
[Mastodon feed](https://mastodon.social/@joplinapp) | Follow us on Mastodon
[Patreon page](https://www.patreon.com/joplin) |The latest news are often posted there
[Discord server](https://discordapp.com/invite/d2HMPwE) | Our chat server
[Sub-reddit](https://www.reddit.com/r/joplinapp/) | Also a good place to get help
[Discord server](https://discordapp.com/invite/d2HMPwE) | Our chat server
[Patreon page](https://www.patreon.com/joplin) |The latest news are often posted there
[Mastodon feed](https://mastodon.social/@joplinapp) | Follow us on Mastodon
[Twitter feed](https://twitter.com/joplinapp) | Follow us on Twitter
# Contributing

View File

@@ -1,12 +1,12 @@
{
"name": "@joplin/server",
"version": "2.5.4",
"version": "2.5.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@joplin/server",
"version": "2.5.4",
"version": "2.5.2",
"dependencies": {
"@fortawesome/fontawesome-free": "^5.15.1",
"@joplin/lib": "~2.4",

View File

@@ -1,6 +1,6 @@
{
"name": "@joplin/server",
"version": "2.5.4",
"version": "2.5.2",
"private": true,
"scripts": {
"start-dev": "nodemon --config nodemon.json --ext ts,js,mustache,css,tsx dist/app.js --env dev",

View File

@@ -21,7 +21,6 @@ import apiVersionHandler from './middleware/apiVersionHandler';
import clickJackingHandler from './middleware/clickJackingHandler';
import deleteOldChanges from './commands/deleteOldChanges';
import newModelFactory from './models/factory';
import deleteOldChanges90 from './commands/deleteOldChanges90';
interface Argv {
env?: Env;
@@ -35,7 +34,6 @@ interface Argv {
createDb?: boolean;
envFile?: string;
deleteOldChanges?: boolean;
deleteOldChanges90?: boolean;
}
const argv: Argv = yargsArgv as any;
@@ -245,20 +243,13 @@ async function main() {
await disconnectDb(db);
} else if (argv.createDb) {
await createDb(config().database);
} else if (argv.deleteOldChanges || argv.deleteOldChanges90) {
} else if (argv.deleteOldChanges) {
// Eventually all commands should be started in a more generic way. All
// should go under /commands, and they will receive a context object
// with an intialized models property.
//
// Also should use yargs command system.
const connectionCheck = await waitForConnection(config().database);
const models = newModelFactory(connectionCheck.connection, config());
if (argv.deleteOldChanges90) {
await deleteOldChanges90({ models });
} else {
await deleteOldChanges({ models });
}
await deleteOldChanges({ models });
} else {
runCommandAndExitApp = false;

View File

@@ -1,6 +0,0 @@
import { Day } from '../utils/time';
import { CommandContext } from '../utils/types';
export default async function(ctx: CommandContext) {
await ctx.models.change().deleteOldChanges(90 * Day);
}

View File

@@ -1,6 +1,6 @@
import { createUserAndSession, beforeAllDb, afterAllTests, beforeEachDb, models, expectThrow, createFolder, createItemTree3, expectNotThrow, createNote, updateNote } from '../utils/testing/testUtils';
import { ChangeType } from '../services/database/types';
import { Day, msleep } from '../utils/time';
import { msleep } from '../utils/time';
import { ChangePagination } from './ChangeModel';
import { SqliteMaxVariableNum } from '../db';
@@ -192,24 +192,19 @@ describe('ChangeModel', function() {
//
// https://www.timeanddate.com/date/dateadd.html
const changeTtl = (180 + 1) * Day;
const { session: session1 } = await createUserAndSession(1);
const { session: session2 } = await createUserAndSession(2);
jest.useFakeTimers('modern');
const t1 = new Date('2020-01-01').getTime();
jest.setSystemTime(t1);
jest.setSystemTime(new Date('2020-01-01').getTime());
const note1 = await createNote(session1.id, {});
const t2 = new Date('2020-01-10').getTime();
jest.setSystemTime(t2);
jest.setSystemTime(new Date('2020-01-10').getTime());
const note2 = await createNote(session2.id, {});
await updateNote(session1.id, { id: note1.jop_id });
const t3 = new Date('2020-01-20').getTime();
jest.setSystemTime(t3);
jest.setSystemTime(new Date('2020-01-20').getTime());
await updateNote(session1.id, { id: note1.jop_id });
const t4 = new Date('2020-01-30').getTime();
@@ -230,9 +225,9 @@ describe('ChangeModel', function() {
await models().change().deleteOldChanges();
expect(await models().change().count()).toBe(7);
// 180 days after T4, it should delete all U1 updates events except for
// the last one
jest.setSystemTime(new Date(t4 + changeTtl).getTime());
// 90 days later, it should delete all U1 updates events except for the
// last one
jest.setSystemTime(new Date('2020-05-01').getTime());
await models().change().deleteOldChanges();
expect(await models().change().count()).toBe(5);
{
@@ -246,13 +241,13 @@ describe('ChangeModel', function() {
// Between T5 and T6, 90 days later - nothing should happen because
// there's only one note 2 change that is older than 90 days at this
// point.
jest.setSystemTime(new Date(t5 + changeTtl).getTime());
jest.setSystemTime(new Date('2020-05-15').getTime());
await models().change().deleteOldChanges();
expect(await models().change().count()).toBe(5);
// After T6, more than 90 days later - now the change at T5 should be
// deleted, keeping only the change at T6.
jest.setSystemTime(new Date(t6 + changeTtl).getTime());
jest.setSystemTime(new Date('2020-05-25').getTime());
await models().change().deleteOldChanges();
expect(await models().change().count()).toBe(4);
{

View File

@@ -10,7 +10,7 @@ import { PaginatedResults, Pagination, PaginationOrderDir } from './utils/pagina
const logger = Logger.create('ChangeModel');
export const defaultChangeTtl = 180 * Day;
export const changeTtl = 90 * Day;
export interface DeltaChange extends Change {
jop_updated_time?: number;
@@ -309,9 +309,8 @@ export default class ChangeModel extends BaseModel<Change> {
return output;
}
public async deleteOldChanges(ttl: number = null) {
ttl = ttl === null ? defaultChangeTtl : ttl;
const cutOffDate = Date.now() - ttl;
public async deleteOldChanges() {
const cutOffDate = Date.now() - changeTtl;
const limit = 1000;
const doneItemIds: Uuid[] = [];

View File

@@ -1,10 +1,5 @@
# Joplin Server Changelog
## [server-v2.5.4](https://github.com/laurent22/joplin/releases/tag/server-v2.5.4) - 2021-10-23T19:09:45Z
- New: Added tool to delete old changes (169b585)
- Fixed: Fixed issue when a notebook is shared, then unshared, then shared again (47fc51e)
## [server-v2.5.2](https://github.com/laurent22/joplin/releases/tag/server-v2.5.2) - 2021-10-07T13:36:27Z
- New: Add support for promotion codes (5b58811)

View File

@@ -49,32 +49,6 @@ When syncing from the start, there will be many "create" events for files that a
## Regarding the deletion of old change events
**2021-10-22**
### Handling UPDATE events
**Update events** older than x days (currently 180 days) will be automatically compressed, by deleting all events except the latest one. For example, if a note has been modified on July 2, July 7 and July 15, only the July 15 event will be kept.
It means that a client that has not synced for more than 180 days is likely to get a "resyncRequired" error code if the sync cursor they had correspond to a change that has been deleted. When that happens a full sync will start from the beginning.
This side effect is considered acceptable because:
- It is unlikely that a client won't be synced for more than 180 days.
- No data loss will occur.
- The need to do a full sync again, while annoying, is not a major issue in most cases.
### Handling CREATE and DELETE events
Currently **Create** and **Delete** events are not automatically deleted. This is because clients build their data based on the Create/Update/Delete events so if we delete the CREATE events, certain notes will no longer be created on new clients.
A possible solution would be to have this kind of logic client side: When a sync cursor is invalid, do a full sync, which will not rely on /delta but on the basicDelta() function as used for file system or webdav sync. It will simply compare what's on the server with what's on the client and do the sync like this. Once it's done, it can start using /delta again. Advantage if that it can be done using basicDelta(). Disadvantage is that it's not possible accurately enumerate the server content that way, since new items can be created or deleted during that basicDelta process.
A possibly more reliable technique would be to delete all Create/Delete event pairs. Doing so won't affect new clients - which simply won't get any CREATE event, since the item has been deleted anyway. It will affect clients that did not sync for a long time because they won't be notified that an item has been deleted - but that's probably an acceptable side effect. The main trouble will be the shared notes and notebooks - we'd need to make sure that when we delete something from a user it doesn't incorrectly delete it from another user (I don't think it would, but that will need to be considered).
**2021-01-01**
**Obsolete**
Keeping all change events permanently would represent a lot of data, however it might be necessary. Without it, it won't be possible for a client to know what file has been deleted and thus a client that has not synced for a long time will keep its files permanently.
So most likely we'll always keep the change events. However, we could compress the old ones to just "create" and "delete" events. All "update" events are not needed. And for a file that has been deleted, we don't need to keep the "create" event.