pull/6600/head
Laurent Cozic 2022-06-20 17:56:16 +01:00
parent 9047605637
commit a43d4593c5
6 changed files with 244 additions and 201 deletions

View File

@ -351,7 +351,7 @@ export default class JoplinDatabase extends Database {
// must be set in the synchronizer too.
// Note: v16 and v17 don't do anything. They were used to debug an issue.
const existingDatabaseVersions = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41];
const existingDatabaseVersions = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42];
let currentVersionIndex = existingDatabaseVersions.indexOf(fromVersion);
@ -910,6 +910,10 @@ export default class JoplinDatabase extends Database {
queries.push('ALTER TABLE `folders` ADD COLUMN icon TEXT NOT NULL DEFAULT ""');
}
if (targetVersion == 42) {
queries.push('ALTER TABLE `notes` ADD COLUMN is_shared_recursive INT NOT NULL DEFAULT 0');
}
const updateVersionQuery = { sql: 'UPDATE version SET version = ?', params: [targetVersion] };
queries.push(updateVersionQuery);

View File

@ -348,24 +348,55 @@ export default class Folder extends BaseItem {
}
public static async updateNoteShareIds() {
// Find all the notes where the share_id is not the same as the
// parent share_id because we only need to update those.
const rows = await this.db().selectAll(`
SELECT notes.id, folders.share_id, notes.parent_id
FROM notes
LEFT JOIN folders ON notes.parent_id = folders.id
WHERE notes.share_id != folders.share_id
`);
{
// Find all the notes where the share_id is not the same as the
// parent share_id because we only need to update those.
const rows = await this.db().selectAll(`
SELECT notes.id, folders.share_id, notes.parent_id
FROM notes
LEFT JOIN folders ON notes.parent_id = folders.id
WHERE notes.share_id != folders.share_id
`);
logger.debug('updateNoteShareIds: notes to update:', rows.length);
logger.debug('updateNoteShareIds: notes to update:', rows.length);
for (const row of rows) {
await Note.save({
id: row.id,
share_id: row.share_id || '',
parent_id: row.parent_id,
updated_time: Date.now(),
}, { autoTimestamp: false });
for (const row of rows) {
await Note.save({
id: row.id,
share_id: row.share_id || '',
parent_id: row.parent_id,
updated_time: Date.now(),
}, { autoTimestamp: false });
}
}
// Also applies recursively published notes
{
// Find all the notes where the share_id is not the same as the
// parent share_id because we only need to update those.
const rows = await this.db().selectAll(`
SELECT notes.id, folders.share_id, notes.parent_id, notes.body
FROM notes
WHERE notes.is_shared = 1 AND notes.is_shared_recursive = 1
`);
logger.debug('updateNoteShareIds: notes recursively published:', rows.length);
// for (const row of rows) {
// // await Note.save({
// // id: row.id,
// // share_id: row.share_id || '',
// // parent_id: row.parent_id,
// // updated_time: Date.now(),
// // }, { autoTimestamp: false });
// }
// TODO: should start from root notes - don't set is_recursive on children?
// TODO: when a child note is moved out of parent, how to know that is_shared should be cleared? - need share_root prop?
// or based on Share API objects? (passed to this function?)
// TODO: also unshare notes that have been unlinked (is_shared != parent.is_shared)
// TODO: avoid infinite loops
}
}
@ -625,7 +656,7 @@ export default class Folder extends BaseItem {
rootFolders.push(folder);
} else {
if (!idToFolders[folder.parent_id]) {
// It means the notebook is refering a folder that doesn't exist. In theory it shouldn't happen
// It means the notebook is referring a folder that doesn't exist. In theory it shouldn't happen
// but sometimes does - https://github.com/laurent22/joplin/issues/1068#issuecomment-450594708
rootFolders.push(folder);
} else {

View File

@ -52,6 +52,10 @@ export const defaultFolderIcon = () => {
// AUTO-GENERATED BY packages/tools/generate-database-types.js
/*
@ -59,225 +63,226 @@ export const defaultFolderIcon = () => {
* Rerun sql-ts to regenerate this file.
*/
export interface AlarmEntity {
"id"?: number | null
"note_id"?: string
"trigger_time"?: number
"type_"?: number
'id'?: number | null;
'note_id'?: string;
'trigger_time'?: number;
'type_'?: number;
}
export interface DeletedItemEntity {
"id"?: number | null
"item_type"?: number
"item_id"?: string
"deleted_time"?: number
"sync_target"?: number
"type_"?: number
'id'?: number | null;
'item_type'?: number;
'item_id'?: string;
'deleted_time'?: number;
'sync_target'?: number;
'type_'?: number;
}
export interface FolderEntity {
"id"?: string | null
"title"?: string
"created_time"?: number
"updated_time"?: number
"user_created_time"?: number
"user_updated_time"?: number
"encryption_cipher_text"?: string
"encryption_applied"?: number
"parent_id"?: string
"is_shared"?: number
"share_id"?: string
"master_key_id"?: string
"icon"?: string
"type_"?: number
'id'?: string | null;
'title'?: string;
'created_time'?: number;
'updated_time'?: number;
'user_created_time'?: number;
'user_updated_time'?: number;
'encryption_cipher_text'?: string;
'encryption_applied'?: number;
'parent_id'?: string;
'is_shared'?: number;
'share_id'?: string;
'master_key_id'?: string;
'icon'?: string;
'type_'?: number;
}
export interface ItemChangeEntity {
"id"?: number | null
"item_type"?: number
"item_id"?: string
"type"?: number
"created_time"?: number
"source"?: number
"before_change_item"?: string
"type_"?: number
'id'?: number | null;
'item_type'?: number;
'item_id'?: string;
'type'?: number;
'created_time'?: number;
'source'?: number;
'before_change_item'?: string;
'type_'?: number;
}
export interface KeyValueEntity {
"id"?: number | null
"key"?: string
"value"?: string
"type"?: number
"updated_time"?: number
"type_"?: number
'id'?: number | null;
'key'?: string;
'value'?: string;
'type'?: number;
'updated_time'?: number;
'type_'?: number;
}
export interface MigrationEntity {
"id"?: number | null
"number"?: number
"updated_time"?: number
"created_time"?: number
"type_"?: number
'id'?: number | null;
'number'?: number;
'updated_time'?: number;
'created_time'?: number;
'type_'?: number;
}
export interface NoteResourceEntity {
"id"?: number | null
"note_id"?: string
"resource_id"?: string
"is_associated"?: number
"last_seen_time"?: number
"type_"?: number
'id'?: number | null;
'note_id'?: string;
'resource_id'?: string;
'is_associated'?: number;
'last_seen_time'?: number;
'type_'?: number;
}
export interface NoteTagEntity {
"id"?: string | null
"note_id"?: string
"tag_id"?: string
"created_time"?: number
"updated_time"?: number
"user_created_time"?: number
"user_updated_time"?: number
"encryption_cipher_text"?: string
"encryption_applied"?: number
"is_shared"?: number
"type_"?: number
'id'?: string | null;
'note_id'?: string;
'tag_id'?: string;
'created_time'?: number;
'updated_time'?: number;
'user_created_time'?: number;
'user_updated_time'?: number;
'encryption_cipher_text'?: string;
'encryption_applied'?: number;
'is_shared'?: number;
'type_'?: number;
}
export interface NoteEntity {
"id"?: string | null
"parent_id"?: string
"title"?: string
"body"?: string
"created_time"?: number
"updated_time"?: number
"is_conflict"?: number
"latitude"?: number
"longitude"?: number
"altitude"?: number
"author"?: string
"source_url"?: string
"is_todo"?: number
"todo_due"?: number
"todo_completed"?: number
"source"?: string
"source_application"?: string
"application_data"?: string
"order"?: number
"user_created_time"?: number
"user_updated_time"?: number
"encryption_cipher_text"?: string
"encryption_applied"?: number
"markup_language"?: number
"is_shared"?: number
"share_id"?: string
"conflict_original_id"?: string
"master_key_id"?: string
"type_"?: number
'id'?: string | null;
'parent_id'?: string;
'title'?: string;
'body'?: string;
'created_time'?: number;
'updated_time'?: number;
'is_conflict'?: number;
'latitude'?: number;
'longitude'?: number;
'altitude'?: number;
'author'?: string;
'source_url'?: string;
'is_todo'?: number;
'todo_due'?: number;
'todo_completed'?: number;
'source'?: string;
'source_application'?: string;
'application_data'?: string;
'order'?: number;
'user_created_time'?: number;
'user_updated_time'?: number;
'encryption_cipher_text'?: string;
'encryption_applied'?: number;
'markup_language'?: number;
'is_shared'?: number;
'share_id'?: string;
'conflict_original_id'?: string;
'master_key_id'?: string;
'is_shared_recursive'?: number;
'type_'?: number;
}
export interface NotesNormalizedEntity {
"id"?: string
"title"?: string
"body"?: string
"user_created_time"?: number
"user_updated_time"?: number
"is_todo"?: number
"todo_completed"?: number
"parent_id"?: string
"latitude"?: number
"longitude"?: number
"altitude"?: number
"source_url"?: string
"todo_due"?: number
"type_"?: number
'id'?: string;
'title'?: string;
'body'?: string;
'user_created_time'?: number;
'user_updated_time'?: number;
'is_todo'?: number;
'todo_completed'?: number;
'parent_id'?: string;
'latitude'?: number;
'longitude'?: number;
'altitude'?: number;
'source_url'?: string;
'todo_due'?: number;
'type_'?: number;
}
export interface ResourceLocalStateEntity {
"id"?: number | null
"resource_id"?: string
"fetch_status"?: number
"fetch_error"?: string
"type_"?: number
'id'?: number | null;
'resource_id'?: string;
'fetch_status'?: number;
'fetch_error'?: string;
'type_'?: number;
}
export interface ResourceEntity {
"id"?: string | null
"title"?: string
"mime"?: string
"filename"?: string
"created_time"?: number
"updated_time"?: number
"user_created_time"?: number
"user_updated_time"?: number
"file_extension"?: string
"encryption_cipher_text"?: string
"encryption_applied"?: number
"encryption_blob_encrypted"?: number
"size"?: number
"is_shared"?: number
"share_id"?: string
"master_key_id"?: string
"type_"?: number
'id'?: string | null;
'title'?: string;
'mime'?: string;
'filename'?: string;
'created_time'?: number;
'updated_time'?: number;
'user_created_time'?: number;
'user_updated_time'?: number;
'file_extension'?: string;
'encryption_cipher_text'?: string;
'encryption_applied'?: number;
'encryption_blob_encrypted'?: number;
'size'?: number;
'is_shared'?: number;
'share_id'?: string;
'master_key_id'?: string;
'type_'?: number;
}
export interface ResourcesToDownloadEntity {
"id"?: number | null
"resource_id"?: string
"updated_time"?: number
"created_time"?: number
"type_"?: number
'id'?: number | null;
'resource_id'?: string;
'updated_time'?: number;
'created_time'?: number;
'type_'?: number;
}
export interface RevisionEntity {
"id"?: string | null
"parent_id"?: string
"item_type"?: number
"item_id"?: string
"item_updated_time"?: number
"title_diff"?: string
"body_diff"?: string
"metadata_diff"?: string
"encryption_cipher_text"?: string
"encryption_applied"?: number
"updated_time"?: number
"created_time"?: number
"type_"?: number
'id'?: string | null;
'parent_id'?: string;
'item_type'?: number;
'item_id'?: string;
'item_updated_time'?: number;
'title_diff'?: string;
'body_diff'?: string;
'metadata_diff'?: string;
'encryption_cipher_text'?: string;
'encryption_applied'?: number;
'updated_time'?: number;
'created_time'?: number;
'type_'?: number;
}
export interface SettingEntity {
"key"?: string | null
"value"?: string | null
"type_"?: number
'key'?: string | null;
'value'?: string | null;
'type_'?: number;
}
export interface SyncItemEntity {
"id"?: number | null
"sync_target"?: number
"sync_time"?: number
"item_type"?: number
"item_id"?: string
"sync_disabled"?: number
"sync_disabled_reason"?: string
"force_sync"?: number
"item_location"?: number
"type_"?: number
'id'?: number | null;
'sync_target'?: number;
'sync_time'?: number;
'item_type'?: number;
'item_id'?: string;
'sync_disabled'?: number;
'sync_disabled_reason'?: string;
'force_sync'?: number;
'item_location'?: number;
'type_'?: number;
}
export interface TableFieldEntity {
"id"?: number | null
"table_name"?: string
"field_name"?: string
"field_type"?: number
"field_default"?: string | null
"type_"?: number
'id'?: number | null;
'table_name'?: string;
'field_name'?: string;
'field_type'?: number;
'field_default'?: string | null;
'type_'?: number;
}
export interface TagEntity {
"id"?: string | null
"title"?: string
"created_time"?: number
"updated_time"?: number
"user_created_time"?: number
"user_updated_time"?: number
"encryption_cipher_text"?: string
"encryption_applied"?: number
"is_shared"?: number
"parent_id"?: string
"type_"?: number
'id'?: string | null;
'title'?: string;
'created_time'?: number;
'updated_time'?: number;
'user_created_time'?: number;
'user_updated_time'?: number;
'encryption_cipher_text'?: string;
'encryption_applied'?: number;
'is_shared'?: number;
'parent_id'?: string;
'type_'?: number;
}
export interface TagsWithNoteCountEntity {
"id"?: string | null
"title"?: string | null
"created_time"?: number | null
"updated_time"?: number | null
"note_count"?: any | null
"todo_completed_count"?: any | null
"type_"?: number
'id'?: string | null;
'title'?: string | null;
'created_time'?: number | null;
'updated_time'?: number | null;
'note_count'?: any | null;
'todo_completed_count'?: any | null;
'type_'?: number;
}
export interface VersionEntity {
"version"?: number
"table_fields_version"?: number
"type_"?: number
'version'?: number;
'table_fields_version'?: number;
'type_'?: number;
}

View File

@ -241,6 +241,7 @@ export default class ShareService {
id: note.id,
parent_id: note.parent_id,
is_shared: 1,
is_shared_recursive: recursive ? 1 : 0,
updated_time: Date.now(),
}, {
autoTimestamp: false,

View File

@ -27,6 +27,7 @@ export interface StateShare {
folder_id: string;
note_id: string;
master_key_id: string;
recursive: number;
user?: StateShareUserUser;
}

View File

@ -64,6 +64,7 @@ export default class ShareModel extends BaseModel<Share> {
if (object.owner_id) output.owner_id = object.owner_id;
if (object.note_id) output.note_id = object.note_id;
if (object.master_key_id) output.master_key_id = object.master_key_id;
if ('recursive' in object) output.recursive = object.recursive;
return output;
}