Delete child annotations when deleting attachment
And fix a FK definition that could result in orphaned `items` rows without `itemAnnotations` rows after an attachment was deleted.
This commit is contained in:
parent
0bc6b2ccc6
commit
76d504c564
3 changed files with 52 additions and 12 deletions
|
@ -1440,12 +1440,22 @@ Zotero.Item.prototype._saveData = Zotero.Promise.coroutine(function* (env) {
|
|||
// Make sure parent is a regular item
|
||||
if (parentItemID) {
|
||||
let parentItem = yield Zotero.Items.getAsync(parentItemID);
|
||||
if (!parentItem.isRegularItem()
|
||||
// Allow embedded-image attachments under notes
|
||||
&& !(this.isEmbeddedImageAttachment() && parentItem.isNote())
|
||||
// Allow annotations under attachments
|
||||
&& !(this.isAnnotation() && parentItem.isFileAttachment())) {
|
||||
throw new Error(`Parent item ${parentItem.libraryKey} must be a regular item`);
|
||||
if (!parentItem.isRegularItem()) {
|
||||
// Allow embedded-image attachments under notes
|
||||
if (this.isEmbeddedImageAttachment()) {
|
||||
if (!parentItem.isNote()) {
|
||||
throw new Error(`Parent item ${parentItem.libraryKey} must a note`);
|
||||
}
|
||||
}
|
||||
// Allow annotations under attachments
|
||||
else if (this.isAnnotation()) {
|
||||
if (!parentItem.isFileAttachment()) {
|
||||
throw new Error(`Parent item ${parentItem.libraryKey} must be a file attachment`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new Error(`Parent item ${parentItem.libraryKey} must be a regular item`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4653,13 +4663,25 @@ Zotero.Item.prototype._eraseData = Zotero.Promise.coroutine(function* (env) {
|
|||
}
|
||||
}
|
||||
|
||||
// Zotero.Sync.EventListeners.ChangeListener needs to know if this was a storage file
|
||||
env.notifierData[this.id].storageDeleteLog = this.isStoredFileAttachment();
|
||||
|
||||
if (this.isFileAttachment()) {
|
||||
// Delete child annotations
|
||||
let sql = "SELECT itemID FROM itemAnnotations WHERE parentItemID=?";
|
||||
let toDelete = yield Zotero.DB.columnQueryAsync(sql, [this.id]);
|
||||
for (let i = 0; i < toDelete.length; i++) {
|
||||
let obj = yield this.ObjectsClass.getAsync(toDelete[i]);
|
||||
yield obj.erase({
|
||||
skipParentRefresh: true,
|
||||
skipEditCheck: env.options.skipEditCheck
|
||||
});
|
||||
}
|
||||
|
||||
// Delete last page index
|
||||
let id = this._getLastPageIndexSettingKey();
|
||||
yield Zotero.SyncedSettings.clear(Zotero.Libraries.userLibraryID, id);
|
||||
}
|
||||
|
||||
// Zotero.Sync.EventListeners.ChangeListener needs to know if this was a storage file
|
||||
env.notifierData[this.id].storageDeleteLog = this.isStoredFileAttachment();
|
||||
}
|
||||
// Delete cached file for image annotation
|
||||
else if (this.isAnnotation()) {
|
||||
|
|
|
@ -41,7 +41,7 @@ Zotero.Schema = new function(){
|
|||
|
||||
// If updating from this userdata version or later, don't show "Upgrading database…" and don't make
|
||||
// DB backup first. This should be set to false when breaking compatibility or making major changes.
|
||||
const minorUpdateFrom = false;
|
||||
const minorUpdateFrom = 112;
|
||||
|
||||
var _dbVersions = [];
|
||||
var _schemaVersions = [];
|
||||
|
@ -3250,6 +3250,24 @@ Zotero.Schema = new function(){
|
|||
yield Zotero.DB.queryAsync("CREATE INDEX itemAttachments_lastProcessedModificationTime ON itemAttachments(lastProcessedModificationTime)");
|
||||
}
|
||||
|
||||
else if (i == 113) {
|
||||
yield Zotero.DB.queryAsync("ALTER TABLE itemAnnotations RENAME TO itemAnnotationsOld");
|
||||
yield Zotero.DB.queryAsync("CREATE TABLE itemAnnotations (\n itemID INTEGER PRIMARY KEY,\n parentItemID INT NOT NULL,\n type INTEGER NOT NULL,\n text TEXT,\n comment TEXT,\n color TEXT,\n pageLabel TEXT,\n sortIndex TEXT NOT NULL,\n position TEXT NOT NULL,\n isExternal INT NOT NULL,\n FOREIGN KEY (itemID) REFERENCES items(itemID) ON DELETE CASCADE,\n FOREIGN KEY (parentItemID) REFERENCES itemAttachments(itemID)\n)");
|
||||
yield Zotero.DB.queryAsync("INSERT INTO itemAnnotations SELECT * FROM itemAnnotationsOld");
|
||||
yield Zotero.DB.queryAsync("DROP TABLE itemAnnotationsOld");
|
||||
yield Zotero.DB.queryAsync("CREATE INDEX itemAnnotations_parentItemID ON itemAnnotations(parentItemID)");
|
||||
|
||||
let annotationID = parseInt((yield Zotero.DB.valueQueryAsync(
|
||||
"SELECT itemTypeID FROM itemTypes WHERE typeName='annotation'"
|
||||
)) || -1);
|
||||
let syncObjectTypeID = yield Zotero.DB.valueQueryAsync("SELECT syncObjectTypeID FROM syncObjectTypes WHERE name='item'");
|
||||
let rows = yield Zotero.DB.queryAsync("SELECT libraryID, key FROM items WHERE itemTypeID=? AND itemID NOT IN (SELECT itemID FROM itemAnnotations)", annotationID);
|
||||
for (let row of rows) {
|
||||
yield Zotero.DB.queryAsync("REPLACE INTO syncDeleteLog (syncObjectTypeID, libraryID, key) VALUES (?, ?, ?)", [syncObjectTypeID, row.libraryID, row.key]);
|
||||
}
|
||||
yield Zotero.DB.queryAsync("DELETE FROM items WHERE itemTypeID=? AND itemID NOT IN (SELECT itemID FROM itemAnnotations)", annotationID);
|
||||
}
|
||||
|
||||
// If breaking compatibility or doing anything dangerous, clear minorUpdateFrom
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
-- 112
|
||||
-- 113
|
||||
|
||||
-- Copyright (c) 2009 Center for History and New Media
|
||||
-- George Mason University, Fairfax, Virginia, USA
|
||||
|
@ -127,7 +127,7 @@ CREATE TABLE itemAnnotations (
|
|||
position TEXT NOT NULL,
|
||||
isExternal INT NOT NULL,
|
||||
FOREIGN KEY (itemID) REFERENCES items(itemID) ON DELETE CASCADE,
|
||||
FOREIGN KEY (parentItemID) REFERENCES itemAttachments(itemID) ON DELETE CASCADE
|
||||
FOREIGN KEY (parentItemID) REFERENCES itemAttachments(itemID)
|
||||
);
|
||||
CREATE INDEX itemAnnotations_parentItemID ON itemAnnotations(parentItemID);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue