aboutsummaryrefslogtreecommitdiffstats
path: root/trunk/etherpad/src/etherpad/pad/padusers.js
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/etherpad/src/etherpad/pad/padusers.js')
-rw-r--r--trunk/etherpad/src/etherpad/pad/padusers.js397
1 files changed, 397 insertions, 0 deletions
diff --git a/trunk/etherpad/src/etherpad/pad/padusers.js b/trunk/etherpad/src/etherpad/pad/padusers.js
new file mode 100644
index 0000000..f04f0eb
--- /dev/null
+++ b/trunk/etherpad/src/etherpad/pad/padusers.js
@@ -0,0 +1,397 @@
+/**
+ * Copyright 2009 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS-IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import("sqlbase.sqlobj");
+import("fastJSON");
+import("stringutils");
+import("jsutils.eachProperty");
+import("sync");
+import("etherpad.sessions");
+import("etherpad.pro.pro_utils");
+import("etherpad.pro.pro_accounts");
+import("etherpad.pro.pro_accounts.getSessionProAccount");
+import("etherpad.pro.domains");
+import("stringutils.randomHash");
+
+var _table = cachedSqlTable('pad_guests', 'pad_guests',
+ ['id', 'privateKey', 'userId'], processGuestRow);
+function processGuestRow(row) {
+ row.data = fastJSON.parse(row.data);
+}
+
+function notifySignIn() {
+ /*if (pro_accounts.isAccountSignedIn()) {
+ var proId = getUserId();
+ var guestId = _getGuestUserId();
+
+ var guestUser = _getGuestByKey('userId', guestId);
+ if (guestUser) {
+ var mods = {};
+ mods.data = guestUser.data;
+ // associate guest with proId
+ mods.data.replacement = proId;
+ // de-associate ET cookie with guest, otherwise
+ // the ET cookie would provide a semi-permanent way
+ // to effect changes under the pro account's name!
+ mods.privateKey = "replaced$"+_randomString(20);
+ _updateGuest('userId', guestId, mods);
+ }
+ }*/
+}
+
+function notifyActive() {
+ if (isGuest(getUserId())) {
+ _updateGuest('userId', getUserId(), {});
+ }
+}
+
+function notifyUserData(userData) {
+ var uid = getUserId();
+ if (isGuest(uid)) {
+ var data = _getGuestByKey('userId', uid).data;
+ if (userData.name) {
+ data.name = userData.name;
+ }
+ _updateGuest('userId', uid, {data: data});
+ }
+}
+
+function getUserId() {
+ if (pro_accounts.isAccountSignedIn()) {
+ return "p."+(getSessionProAccount().id);
+ }
+ else {
+ return getGuestUserId();
+ }
+}
+
+function getUserName() {
+ var uid = getUserId();
+ if (isGuest(uid)) {
+ var fromSession = sessions.getSession().guestDisplayName;
+ return fromSession || _getGuestByKey('userId', uid).data.name || null;
+ }
+ else {
+ return getSessionProAccount().fullName;
+ }
+}
+
+function getAccountIdForProAuthor(uid) {
+ if (uid.indexOf("p.") == 0) {
+ return Number(uid.substring(2));
+ }
+ else {
+ return -1;
+ }
+}
+
+function getNameForUserId(uid) {
+ if (isGuest(uid)) {
+ return _getGuestByKey('userId', uid).data.name || null;
+ }
+ else {
+ var accountNum = getAccountIdForProAuthor(uid);
+ if (accountNum < 0) {
+ return null;
+ }
+ else {
+ return pro_accounts.getAccountById(accountNum).fullName;
+ }
+ }
+}
+
+function isGuest(userId) {
+ return /^g/.test(userId);
+}
+
+function getGuestUserId() {
+ // cache the userId in the requestCache,
+ // for efficiency and consistency
+ var c = appjet.requestCache;
+ if (c.padGuestUserId === undefined) {
+ c.padGuestUserId = _computeGuestUserId();
+ }
+ return c.padGuestUserId;
+}
+
+function _getGuestTrackerId() {
+ // get ET cookie
+ var tid = sessions.getTrackingId();
+ if (tid == '-') {
+ // no tracking cookie? not a normal request?
+ return null;
+ }
+
+ // get domain ID
+ var domain = "-";
+ if (pro_utils.isProDomainRequest()) {
+ // e.g. "3"
+ domain = String(domains.getRequestDomainId());
+ }
+
+ // combine them
+ return domain+"$"+tid;
+}
+
+function _insertGuest(obj) {
+ // only requires 'userId' in obj
+
+ obj.createdDate = new Date;
+ obj.lastActiveDate = new Date;
+ if (! obj.data) {
+ obj.data = {};
+ }
+ if ((typeof obj.data) == "object") {
+ obj.data = fastJSON.stringify(obj.data);
+ }
+ if (! obj.privateKey) {
+ // private keys must be unique
+ obj.privateKey = "notracker$"+_randomString(20);
+ }
+
+ return _table.insert(obj);
+}
+
+function _getGuestByKey(keyColumn, value) {
+ return _table.getByKey(keyColumn, value);
+}
+
+function _updateGuest(keyColumn, value, obj) {
+ var obj2 = {};
+ eachProperty(obj, function(k,v) {
+ if (k == "data" && (typeof v) == "object") {
+ obj2.data = fastJSON.stringify(v);
+ }
+ else {
+ obj2[k] = v;
+ }
+ });
+
+ obj2.lastActiveDate = new Date;
+
+ _table.updateByKey(keyColumn, value, obj2);
+}
+
+function _newGuestUserId() {
+ return "g."+_randomString(16);
+}
+
+function _computeGuestUserId() {
+ // always returns some userId
+
+ var privateKey = _getGuestTrackerId();
+
+ if (! privateKey) {
+ // no tracking cookie, pretend there is one
+ privateKey = randomHash(16);
+ }
+
+ var userFromTracker = _table.getByKey('privateKey', privateKey);
+ if (userFromTracker) {
+ // we know this guy
+ return userFromTracker.userId;
+ }
+
+ // generate userId
+ var userId = _newGuestUserId();
+ var guest = {userId:userId, privateKey:privateKey};
+ var data = {};
+ guest.data = data;
+
+ var prefsCookieData = _getPrefsCookieData();
+ if (prefsCookieData) {
+ // found an old prefs cookie with an old userId
+ var oldUserId = prefsCookieData.userId;
+ // take the name and preferences
+ if ('name' in prefsCookieData) {
+ data.name = prefsCookieData.name;
+ }
+ /*['fullWidth','viewZoom'].forEach(function(pref) {
+ if (pref in prefsCookieData) {
+ data.prefs[pref] = prefsCookieData[pref];
+ }
+ });*/
+ }
+
+ _insertGuest(guest);
+ return userId;
+}
+
+function _getPrefsCookieData() {
+ // get userId from old prefs cookie if possible,
+ // but don't allow modern usernames
+
+ var prefsCookie = request.cookies['prefs'];
+ if (! prefsCookie) {
+ return null;
+ }
+ if (prefsCookie.charAt(0) != '%') {
+ return null;
+ }
+ try {
+ var cookieData = fastJSON.parse(unescape(prefsCookie));
+ // require one to three digits followed by dot at beginning of userId
+ if (/^[0-9]{1,3}\./.test(String(cookieData.userId))) {
+ return cookieData;
+ }
+ }
+ catch (e) {
+ return null;
+ }
+
+ return null;
+}
+
+function _randomString(len) {
+ // use only numbers and lowercase letters
+ var pieces = [];
+ for(var i=0;i<len;i++) {
+ pieces.push(Math.floor(Math.random()*36).toString(36).slice(-1));
+ }
+ return pieces.join('');
+}
+
+
+function cachedSqlTable(cacheName, tableName, keyColumns, processFetched) {
+ // Keeps a cache of sqlobj rows for the case where
+ // you want to select one row at a time by a single column
+ // at a time, taken from some set of key columns.
+ // The cache maps (keyColumn, value), e.g. ("id", 4) or
+ // ("secondaryKey", "foo123"), to an object, and each
+ // object is either present for all keyColumns
+ // (e.g. "id", "secondaryKey") or none.
+
+ if ((typeof keyColumns) == "string") {
+ keyColumns = [keyColumns];
+ }
+ processFetched = processFetched || (function(o) {});
+
+ function getCache() {
+ // this function is normally fast, only slow when cache
+ // needs to be created for the first time
+ var cache = appjet.cache[cacheName];
+ if (cache) {
+ return cache;
+ }
+ else {
+ // initialize in a synchronized block (double-checked locking);
+ // uses same lock as cache_utils.syncedWithCache would use.
+ sync.doWithStringLock("cache/"+cacheName, function() {
+ if (! appjet.cache[cacheName]) {
+ // values expire after 10 minutes
+ appjet.cache[cacheName] =
+ new net.appjet.common.util.ExpiringMapping(10*60*1000);
+ }
+ });
+ return appjet.cache[cacheName];
+ }
+ }
+
+ function cacheKey(keyColumn, value) {
+ // e.g. "id$4"
+ return keyColumn+"$"+String(value);
+ }
+
+ function getFromCache(keyColumn, value) {
+ return getCache().get(cacheKey(keyColumn, value));
+ }
+ function putInCache(obj) {
+ var cache = getCache();
+ // put in cache, keyed on all keyColumns we care about
+ keyColumns.forEach(function(keyColumn) {
+ cache.put(cacheKey(keyColumn, obj[keyColumn]), obj);
+ });
+ }
+ function touchInCache(obj) {
+ var cache = getCache();
+ keyColumns.forEach(function(keyColumn) {
+ cache.touch(cacheKey(keyColumn, obj[keyColumn]));
+ });
+ }
+ function removeObjFromCache(obj) {
+ var cache = getCache();
+ keyColumns.forEach(function(keyColumn) {
+ cache.remove(cacheKey(keyColumn, obj[keyColumn]));
+ });
+ }
+ function removeFromCache(keyColumn, value) {
+ var cached = getFromCache(keyColumn, value);
+ if (cached) {
+ removeObjFromCache(cached);
+ }
+ }
+
+ var self = {
+ clearCache: function() {
+ getCache().clear();
+ },
+ getByKey: function(keyColumn, value) {
+ // get cached object, if any
+ var cached = getFromCache(keyColumn, value);
+ if (! cached) {
+ // nothing in cache for this query, fetch from SQL
+ var keyToValue = {};
+ keyToValue[keyColumn] = value;
+ var fetched = sqlobj.selectSingle(tableName, keyToValue);
+ if (fetched) {
+ processFetched(fetched);
+ // fetched something, stick it in the cache
+ putInCache(fetched);
+ }
+ return fetched;
+ }
+ else {
+ // touch cached object and return
+ touchInCache(cached);
+ return cached;
+ }
+ },
+ updateByKey: function(keyColumn, value, obj) {
+ var keyToValue = {};
+ keyToValue[keyColumn] = value;
+ sqlobj.updateSingle(tableName, keyToValue, obj);
+ // remove old object from caches but
+ // don't put obj in cache, because it
+ // is likely a partial object
+ removeFromCache(keyColumn, value);
+ },
+ insert: function(obj) {
+ var returnVal = sqlobj.insert(tableName, obj);
+ // remove old object from caches but
+ // don't put obj in the cache; it doesn't
+ // have all values, e.g. for auto-generated ids
+ removeObjFromCache(obj);
+ return returnVal;
+ },
+ deleteByKey: function(keyColumn, value) {
+ var keyToValue = {};
+ keyToValue[keyColumn] = value;
+ sqlobj.deleteRows(tableName, keyToValue);
+ removeFromCache(keyColumn, value);
+ }
+ };
+ return self;
+}
+
+function _getClientIp() {
+ return (request.isDefined && request.clientIp) || '';
+}
+
+function getUserIdCreatedDate(userId) {
+ var record = sqlobj.selectSingle('pad_cookie_userids', {id: userId});
+ if (! record) { return; } // hm. weird case.
+ return record.createdDate;
+}