group.js (7890B)
1 /* 2 ***** BEGIN LICENSE BLOCK ***** 3 4 Copyright © 2009 Center for History and New Media 5 George Mason University, Fairfax, Virginia, USA 6 http://zotero.org 7 8 This file is part of Zotero. 9 10 Zotero is free software: you can redistribute it and/or modify 11 it under the terms of the GNU Affero General Public License as published by 12 the Free Software Foundation, either version 3 of the License, or 13 (at your option) any later version. 14 15 Zotero is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU Affero General Public License for more details. 19 20 You should have received a copy of the GNU Affero General Public License 21 along with Zotero. If not, see <http://www.gnu.org/licenses/>. 22 23 ***** END LICENSE BLOCK ***** 24 */ 25 26 "use strict"; 27 28 Zotero.Group = function (params = {}) { 29 params.libraryType = 'group'; 30 Zotero.Group._super.call(this, params); 31 32 Zotero.Utilities.assignProps(this, params, ['groupID', 'name', 'description', 33 'version']); 34 35 // Return a proxy so that we can disable the object once it's deleted 36 return new Proxy(this, { 37 get: function(obj, prop) { 38 if (obj._disabled && !(prop == 'libraryID' || prop == 'id')) { 39 throw new Error("Group (" + obj.libraryID + ") has been disabled"); 40 } 41 return obj[prop]; 42 } 43 }); 44 } 45 46 47 /** 48 * Non-prototype properties 49 */ 50 51 Zotero.defineProperty(Zotero.Group, '_dbColumns', { 52 value: Object.freeze(['name', 'description', 'version']) 53 }); 54 55 Zotero.Group._colToProp = function(c) { 56 return "_group" + Zotero.Utilities.capitalize(c); 57 } 58 59 Zotero.defineProperty(Zotero.Group, '_rowSQLSelect', { 60 value: Zotero.Library._rowSQLSelect + ", G.groupID, " 61 + Zotero.Group._dbColumns.map(c => "G." + c + " AS " + Zotero.Group._colToProp(c)).join(", ") 62 }); 63 64 Zotero.defineProperty(Zotero.Group, '_rowSQL', { 65 value: "SELECT " + Zotero.Group._rowSQLSelect 66 + " FROM groups G JOIN libraries L USING (libraryID)" 67 }); 68 69 Zotero.extendClass(Zotero.Library, Zotero.Group); 70 71 Zotero.defineProperty(Zotero.Group.prototype, '_objectType', { 72 value: 'group' 73 }); 74 75 Zotero.defineProperty(Zotero.Group.prototype, 'libraryTypes', { 76 value: Object.freeze(Zotero.Group._super.prototype.libraryTypes.concat(['group'])) 77 }); 78 79 Zotero.defineProperty(Zotero.Group.prototype, 'groupID', { 80 get: function() { return this._groupID; }, 81 set: function(v) { return this._groupID = v; } 82 }); 83 84 Zotero.defineProperty(Zotero.Group.prototype, 'id', { 85 get: function() { return this.groupID; }, 86 set: function(v) { return this.groupID = v; } 87 }); 88 89 Zotero.defineProperty(Zotero.Group.prototype, 'allowsLinkedFiles', { 90 value: false 91 }); 92 93 // Create accessors 94 (function() { 95 let accessors = ['name', 'description', 'version']; 96 for (let i=0; i<accessors.length; i++) { 97 let name = accessors[i]; 98 let prop = Zotero.Group._colToProp(name); 99 Zotero.defineProperty(Zotero.Group.prototype, name, { 100 get: function() { return this._get(prop); }, 101 set: function(v) { return this._set(prop, v); } 102 }) 103 } 104 })(); 105 106 Zotero.Group.prototype._isValidGroupProp = function(prop) { 107 let preffix = '_group'; 108 if (prop.indexOf(preffix) !== 0 || prop.length == preffix.length) { 109 return false; 110 } 111 112 let col = prop.substr(preffix.length); 113 col = col.charAt(0).toLowerCase() + col.substr(1); 114 115 return Zotero.Group._dbColumns.indexOf(col) != -1; 116 } 117 118 Zotero.Group.prototype._isValidProp = function(prop) { 119 return this._isValidGroupProp(prop) 120 || Zotero.Group._super.prototype._isValidProp.call(this, prop); 121 } 122 123 /* 124 * Populate group data from a database row 125 */ 126 Zotero.Group.prototype._loadDataFromRow = function(row) { 127 Zotero.Group._super.prototype._loadDataFromRow.call(this, row); 128 129 this._groupID = row.groupID; 130 this._groupName = row._groupName; 131 this._groupDescription = row._groupDescription; 132 this._groupVersion = row._groupVersion; 133 } 134 135 Zotero.Group.prototype._set = function(prop, val) { 136 switch(prop) { 137 case '_groupVersion': 138 let newVal = Number.parseInt(val, 10); 139 if (newVal != val) { 140 throw new Error(prop + ' must be an integer'); 141 } 142 val = newVal 143 144 if (val < 0) { 145 throw new Error(prop + ' must be non-negative'); 146 } 147 148 // Ensure that it is never decreasing 149 if (val < this._groupVersion) { 150 throw new Error(prop + ' cannot decrease'); 151 } 152 153 break; 154 case '_groupName': 155 case '_groupDescription': 156 if (typeof val != 'string') { 157 throw new Error(prop + ' must be a string'); 158 } 159 break; 160 } 161 162 return Zotero.Group._super.prototype._set.call(this, prop, val); 163 } 164 165 Zotero.Group.prototype._reloadFromDB = Zotero.Promise.coroutine(function* () { 166 let sql = Zotero.Group._rowSQL + " WHERE G.groupID=?"; 167 let row = yield Zotero.DB.rowQueryAsync(sql, [this.groupID]); 168 this._loadDataFromRow(row); 169 }); 170 171 Zotero.Group.prototype._initSave = Zotero.Promise.coroutine(function* (env) { 172 let proceed = yield Zotero.Group._super.prototype._initSave.call(this, env); 173 if (!proceed) return false; 174 175 if (!this._groupName) throw new Error("Group name not set"); 176 if (typeof this._groupDescription != 'string') throw new Error("Group description not set"); 177 if (!(this._groupVersion >= 0)) throw new Error("Group version not set"); 178 if (!this._groupID) throw new Error("Group ID not set"); 179 180 return true; 181 }); 182 183 Zotero.Group.prototype._saveData = Zotero.Promise.coroutine(function* (env) { 184 yield Zotero.Group._super.prototype._saveData.call(this, env); 185 186 let changedCols = [], params = []; 187 for (let i=0; i<Zotero.Group._dbColumns.length; i++) { 188 let col = Zotero.Group._dbColumns[i]; 189 let prop = Zotero.Group._colToProp(col); 190 191 if (!this._changed[prop]) continue; 192 193 changedCols.push(col); 194 params.push(this[prop]); 195 } 196 197 if (env.isNew) { 198 changedCols.push('groupID', 'libraryID'); 199 params.push(this.groupID, this.libraryID); 200 201 let sql = "INSERT INTO groups (" + changedCols.join(', ') + ") " 202 + "VALUES (" + Array(params.length).fill('?').join(', ') + ")"; 203 yield Zotero.DB.queryAsync(sql, params); 204 205 Zotero.Notifier.queue('add', 'group', this.groupID, env.notifierData); 206 } 207 else if (changedCols.length) { 208 let sql = "UPDATE groups SET " + changedCols.map(v => v + '=?').join(', ') 209 + " WHERE groupID=?"; 210 params.push(this.groupID); 211 yield Zotero.DB.queryAsync(sql, params); 212 213 if (!env.options.skipNotifier) { 214 Zotero.Notifier.queue('modify', 'group', this.groupID, env.notifierData); 215 } 216 } 217 else { 218 Zotero.debug("Group data did not change for group " + this.groupID, 5); 219 } 220 }); 221 222 Zotero.Group.prototype._finalizeSave = Zotero.Promise.coroutine(function* (env) { 223 yield Zotero.Group._super.prototype._finalizeSave.call(this, env); 224 225 if (env.isNew) { 226 Zotero.Groups.register(this); 227 } 228 }); 229 230 Zotero.Group.prototype._finalizeErase = Zotero.Promise.coroutine(function* (env) { 231 let notifierData = {}; 232 notifierData[this.groupID] = { 233 libraryID: this.libraryID 234 }; 235 Zotero.Notifier.queue('delete', 'group', this.groupID, notifierData); 236 237 Zotero.Groups.unregister(this.groupID); 238 239 yield Zotero.Group._super.prototype._finalizeErase.call(this, env); 240 }); 241 242 Zotero.Group.prototype.fromJSON = function (json, userID) { 243 if (json.name !== undefined) this.name = json.name; 244 if (json.description !== undefined) this.description = json.description; 245 246 var editable = false; 247 var filesEditable = false; 248 if (userID) { 249 ({ editable, filesEditable } = Zotero.Groups.getPermissionsFromJSON(json, userID)); 250 } 251 this.editable = editable; 252 this.filesEditable = filesEditable; 253 } 254 255 Zotero.Group.prototype._prepFieldChange = function (field) { 256 if (!this._changed) { 257 this._changed = {}; 258 } 259 this._changed[field] = true; 260 261 // Save a copy of the data before changing 262 // TODO: only save previous data if group exists 263 if (this.id && this.exists() && !this._previousData) { 264 //this._previousData = this.serialize(); 265 } 266 }