diff --git a/chrome/content/zotero/xpcom/annotations.js b/chrome/content/zotero/xpcom/annotations.js index 0e099b2523..34446bb56e 100644 --- a/chrome/content/zotero/xpcom/annotations.js +++ b/chrome/content/zotero/xpcom/annotations.js @@ -118,9 +118,16 @@ Zotero.Annotations = new function () { o.type = item.annotationType; o.isExternal = item.annotationIsExternal; var isAuthor = !item.createdByUserID || item.createdByUserID == Zotero.Users.getCurrentUserID(); - if (!o.isExternal && item.library.libraryType == 'group') { + var isGroup = item.library.libraryType == 'group'; + if (item.annotationAuthorName) { + o.authorName = item.annotationAuthorName; + } + else if (!o.isExternal && isGroup) { o.authorName = Zotero.Users.getName(item.createdByUserID); } + if (o.authorName && isGroup) { + o.lastModifiedByUser = Zotero.Users.getName(item.lastModifiedByUserID) + } o.readOnly = o.isExternal || !isAuthor; if (o.type == 'highlight') { o.text = item.annotationText; @@ -197,6 +204,7 @@ Zotero.Annotations = new function () { item._requireData('annotation'); item._requireData('annotationDeferred'); item.annotationType = json.type; + item.annotationAuthorName = json.authorName || ''; if (json.type == 'highlight') { item.annotationText = json.text; } diff --git a/chrome/content/zotero/xpcom/data/item.js b/chrome/content/zotero/xpcom/data/item.js index 1e45acceea..9d0ff58964 100644 --- a/chrome/content/zotero/xpcom/data/item.js +++ b/chrome/content/zotero/xpcom/data/item.js @@ -67,6 +67,7 @@ Zotero.Item = function(itemTypeOrID) { // loadAnnotation this._annotationType = null; + this._annotationAuthorName = null; this._annotationText = null; this._annotationImage = null; this._annotationComment = null; @@ -1847,6 +1848,7 @@ Zotero.Item.prototype._saveData = Zotero.Promise.coroutine(function* (env) { throw new Error(`Invalid annotation type '${type}'`); } + let authorName = this._getLatestField('annotationAuthorName'); let text = this._getLatestField('annotationText'); let comment = this._getLatestField('annotationComment'); let color = this._getLatestField('annotationColor'); @@ -1856,14 +1858,15 @@ Zotero.Item.prototype._saveData = Zotero.Promise.coroutine(function* (env) { let isExternal = this._getLatestField('annotationIsExternal'); let sql = "REPLACE INTO itemAnnotations " - + "(itemID, parentItemID, type, text, comment, color, pageLabel, sortIndex, position, isExternal) " - + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + "(itemID, parentItemID, type, authorName, text, comment, color, pageLabel, sortIndex, position, isExternal) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; yield Zotero.DB.queryAsync( sql, [ itemID, parentItemID, typeID, + authorName || null, text || null, comment || null, color || null, @@ -3706,7 +3709,7 @@ Zotero.Item.prototype.clearBestAttachmentState = function () { //////////////////////////////////////////////////////// // Main annotation properties (required for items list display) -for (let name of ['type', 'text', 'comment', 'color', 'pageLabel', 'sortIndex', 'isExternal']) { +for (let name of ['type', 'authorName', 'text', 'comment', 'color', 'pageLabel', 'sortIndex', 'isExternal']) { let field = 'annotation' + name[0].toUpperCase() + name.substr(1); Zotero.defineProperty(Zotero.Item.prototype, field, { get: function () { @@ -4948,6 +4951,7 @@ Zotero.Item.prototype.fromJSON = function (json, options = {}) { // case 'annotationType': case 'annotationType': + case 'annotationAuthorName': case 'annotationText': case 'annotationComment': case 'annotationColor': @@ -5224,6 +5228,7 @@ Zotero.Item.prototype.toJSON = function (options = {}) { if (this.isAnnotation()) { let type = this.annotationType; obj.annotationType = type; + obj.annotationAuthorName = this.annotationAuthorName || ''; if (type == 'highlight') { obj.annotationText = this.annotationText || ''; } diff --git a/chrome/content/zotero/xpcom/data/items.js b/chrome/content/zotero/xpcom/data/items.js index c4e4a0cd69..85906cd5fb 100644 --- a/chrome/content/zotero/xpcom/data/items.js +++ b/chrome/content/zotero/xpcom/data/items.js @@ -495,8 +495,8 @@ Zotero.Items = function() { this._loadAnnotations = async function (libraryID, ids, idSQL) { - var sql = "SELECT itemID, IA.parentItemID, IA.type, IA.text, IA.comment, IA.color, " - + "IA.sortIndex, IA.isExternal " + var sql = "SELECT itemID, IA.parentItemID, IA.type, IA.authorName, IA.text, IA.comment, " + + "IA.color, IA.sortIndex, IA.isExternal " + "FROM items JOIN itemAnnotations IA USING (itemID) " + "WHERE libraryID=?" + idSQL; var params = [libraryID]; @@ -537,11 +537,12 @@ Zotero.Items = function() { throw new Error(`Unknown annotation type id ${typeID}`); } item._annotationType = type; - item._annotationText = row.getResultByIndex(3); - item._annotationComment = row.getResultByIndex(4); - item._annotationColor = row.getResultByIndex(5); - item._annotationSortIndex = row.getResultByIndex(6); - item._annotationIsExternal = !!row.getResultByIndex(7); + item._annotationAuthorName = row.getResultByIndex(3); + item._annotationText = row.getResultByIndex(4); + item._annotationComment = row.getResultByIndex(5); + item._annotationColor = row.getResultByIndex(6); + item._annotationSortIndex = row.getResultByIndex(7); + item._annotationIsExternal = !!row.getResultByIndex(8); item._loaded.annotation = true; item._clearChanged('annotation'); diff --git a/chrome/content/zotero/xpcom/schema.js b/chrome/content/zotero/xpcom/schema.js index e3053a32a1..51ec46d76d 100644 --- a/chrome/content/zotero/xpcom/schema.js +++ b/chrome/content/zotero/xpcom/schema.js @@ -3422,6 +3422,14 @@ Zotero.Schema = new function(){ yield Zotero.DB.queryAsync("PRAGMA legacy_alter_table=OFF"); } + else if (i == 119) { + yield Zotero.DB.queryAsync("CREATE TABLE itemAnnotationsTemp (\n itemID INTEGER PRIMARY KEY,\n parentItemID INT NOT NULL,\n type INTEGER NOT NULL,\n authorName TEXT,\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 itemAnnotationsTemp SELECT itemID, parentItemID, type, '', text, comment, color, pageLabel, sortIndex, position, isExternal FROM itemAnnotations"); + yield Zotero.DB.queryAsync("DROP TABLE itemAnnotations"); + yield Zotero.DB.queryAsync("ALTER TABLE itemAnnotationsTemp RENAME TO itemAnnotations"); + yield Zotero.DB.queryAsync("CREATE INDEX itemAnnotations_parentItemID ON itemAnnotations(parentItemID)"); + } + // If breaking compatibility or doing anything dangerous, clear minorUpdateFrom } diff --git a/resource/schema/userdata.sql b/resource/schema/userdata.sql index 794fdddb86..a4f824c0e6 100644 --- a/resource/schema/userdata.sql +++ b/resource/schema/userdata.sql @@ -1,4 +1,4 @@ --- 117 +-- 119 -- Copyright (c) 2009 Center for History and New Media -- George Mason University, Fairfax, Virginia, USA @@ -224,6 +224,7 @@ CREATE TABLE itemAnnotations ( itemID INTEGER PRIMARY KEY, parentItemID INT NOT NULL, type INTEGER NOT NULL, + authorName TEXT, text TEXT, comment TEXT, color TEXT, diff --git a/test/tests/annotationsTest.js b/test/tests/annotationsTest.js index 701e193c98..dc555da1d6 100644 --- a/test/tests/annotationsTest.js +++ b/test/tests/annotationsTest.js @@ -256,6 +256,38 @@ describe("Zotero.Annotations", function() { skipEditCheck: true }); }); + + it("should generate an object for a highlight by another user modified by the current user in a group library", async function () { + await Zotero.Users.setName(1, 'My Name'); + await Zotero.Users.setName(12345, 'Their Name'); + + var annotation = await createAnnotation('highlight', groupAttachment); + annotation.createdByUserID = 12345; + annotation.lastModifiedByUserID = 1; + await annotation.saveTx({ + skipEditCheck: true + }); + var json = await Zotero.Annotations.toJSON(annotation); + + assert.equal(json.authorName, 'Their Name'); + assert.equal(json.lastModifiedByUser, 'My Name'); + + await annotation.eraseTx({ + skipEditCheck: true + }); + }); + + it("should generate an object for an annotation by another user in a personal library", async function () { + var annotation = await createAnnotation('highlight', attachment); + annotation.annotationAuthorName = 'First Last'; + await annotation.saveTx(); + + var json = await Zotero.Annotations.toJSON(annotation); + + assert.equal(json.authorName, 'First Last'); + + await annotation.eraseTx(); + }); });