From 464e0f8115e3b5b01b6110ddc7a73274164c8584 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 22 Dec 2010 13:56:19 -0800 Subject: [PATCH 1/5] Don't trust text/xml mime types; generic content detection gives useless stuff like that on SVG images! Todo: replace the extension check in this case with better content-based checks. --- lib/mediafile.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/mediafile.php b/lib/mediafile.php index a41d7c76b5..caa902de5d 100644 --- a/lib/mediafile.php +++ b/lib/mediafile.php @@ -362,7 +362,9 @@ class MediaFile // we'll try detecting a type from its extension... $unclearTypes = array('application/octet-stream', 'application/vnd.ms-office', - 'application/zip'); + 'application/zip', + // TODO: for XML we could do better content-based sniffing too + 'text/xml'); if ($originalFilename && (!$filetype || in_array($filetype, $unclearTypes))) { $type = $mte->getMIMEType($originalFilename); From d5c2b0d21695f2ae661fa7ef4bbfbe9db0f66925 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 22 Dec 2010 14:55:13 -0800 Subject: [PATCH 2/5] When queueing is off, restore runs immediately. Indicate that we've already finished processing on the success page in this case; otherwise continue to show the 'will take a few minutes' message. --- actions/restoreaccount.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/actions/restoreaccount.php b/actions/restoreaccount.php index 5c8e4a12c1..8cf220a424 100644 --- a/actions/restoreaccount.php +++ b/actions/restoreaccount.php @@ -48,6 +48,7 @@ if (!defined('STATUSNET')) { class RestoreaccountAction extends Action { private $success = false; + private $inprogress = false; /** * Returns the title of the page @@ -208,8 +209,13 @@ class RestoreaccountAction extends Action $qm = QueueManager::get(); $qm->enqueue(array(common_current_user(), $xml, false), 'feedimp'); - $this->success = true; - + if ($qm instanceof UnQueueManager) { + // No active queuing means we've actually just completed the job! + $this->success = true; + } else { + // We've fed data into background queues, and it's probably still running. + $this->inprogress = true; + } $this->showPage(); } catch (Exception $e) { @@ -228,6 +234,9 @@ class RestoreaccountAction extends Action function showContent() { if ($this->success) { + $this->element('p', null, + _('Feed has been restored. Your old posts should now appear in search and your profile page.')); + } else if ($this->inprogress) { $this->element('p', null, _('Feed will be restored. Please wait a few minutes for results.')); } else { From 8babcc2ad21f70745ce261476ffe74b42603419a Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 22 Dec 2010 15:04:50 -0800 Subject: [PATCH 3/5] Makefile to compress LinkPreview's js --- plugins/LinkPreview/Makefile | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 plugins/LinkPreview/Makefile diff --git a/plugins/LinkPreview/Makefile b/plugins/LinkPreview/Makefile new file mode 100644 index 0000000000..6c8a03e94b --- /dev/null +++ b/plugins/LinkPreview/Makefile @@ -0,0 +1,11 @@ +.fake: all clean + +TARGETS=linkpreview.min.js + +all: $(TARGETS) + +clean: + rm -f $(TARGETS) + +linkpreview.min.js: linkpreview.js + yui-compressor $< -o $@ From e0606d3eca761bda5fb804f6522028280d3396e8 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Wed, 22 Dec 2010 15:20:07 -0800 Subject: [PATCH 4/5] Break xbImportNode.js and geometa.js back out of util.js; the Makefile in js has been updated to combine them with util.js source when building util.min.js Revert "combine our standard scripts into one big script" This reverts parts of commit 0c5ca46ba3a070803d993b0244fcc69d33875ebd. --- js/Makefile | 5 +- js/geometa.js | 217 ++++++++++++++++++++++++++++++++++++ js/util.js | 269 --------------------------------------------- js/xbImportNode.js | 47 ++++++++ 4 files changed, 267 insertions(+), 271 deletions(-) create mode 100644 js/geometa.js create mode 100644 js/xbImportNode.js diff --git a/js/Makefile b/js/Makefile index 00e4347141..e7ae44e421 100644 --- a/js/Makefile +++ b/js/Makefile @@ -1,11 +1,12 @@ .fake: all clean TARGETS=util.min.js +SOURCES=util.js xbImportNode.js geometa.js all: $(TARGETS) clean: rm -f $(TARGETS) -util.min.js: util.js - yui-compressor $< -o $@ +util.min.js: $(SOURCES) + cat $+ | yui-compressor --type js > $@ diff --git a/js/geometa.js b/js/geometa.js new file mode 100644 index 0000000000..bba59b4486 --- /dev/null +++ b/js/geometa.js @@ -0,0 +1,217 @@ +// A shim to implement the W3C Geolocation API Specification using Gears or the Ajax API +if (typeof navigator.geolocation == "undefined" || navigator.geolocation.shim ) { (function(){ + +// -- BEGIN GEARS_INIT +(function() { + // We are already defined. Hooray! + if (window.google && google.gears) { + return; + } + + var factory = null; + + // Firefox + if (typeof GearsFactory != 'undefined') { + factory = new GearsFactory(); + } else { + // IE + try { + factory = new ActiveXObject('Gears.Factory'); + // privateSetGlobalObject is only required and supported on WinCE. + if (factory.getBuildInfo().indexOf('ie_mobile') != -1) { + factory.privateSetGlobalObject(this); + } + } catch (e) { + // Safari + if ((typeof navigator.mimeTypes != 'undefined') && navigator.mimeTypes["application/x-googlegears"]) { + factory = document.createElement("object"); + factory.style.display = "none"; + factory.width = 0; + factory.height = 0; + factory.type = "application/x-googlegears"; + document.documentElement.appendChild(factory); + } + } + } + + // *Do not* define any objects if Gears is not installed. This mimics the + // behavior of Gears defining the objects in the future. + if (!factory) { + return; + } + + // Now set up the objects, being careful not to overwrite anything. + // + // Note: In Internet Explorer for Windows Mobile, you can't add properties to + // the window object. However, global objects are automatically added as + // properties of the window object in all browsers. + if (!window.google) { + google = {}; + } + + if (!google.gears) { + google.gears = {factory: factory}; + } +})(); +// -- END GEARS_INIT + +var GearsGeoLocation = (function() { + // -- PRIVATE + var geo = google.gears.factory.create('beta.geolocation'); + + var wrapSuccess = function(callback, self) { // wrap it for lastPosition love + return function(position) { + callback(position); + self.lastPosition = position; + }; + }; + + // -- PUBLIC + return { + shim: true, + + type: "Gears", + + lastPosition: null, + + getCurrentPosition: function(successCallback, errorCallback, options) { + var self = this; + var sc = wrapSuccess(successCallback, self); + geo.getCurrentPosition(sc, errorCallback, options); + }, + + watchPosition: function(successCallback, errorCallback, options) { + geo.watchPosition(successCallback, errorCallback, options); + }, + + clearWatch: function(watchId) { + geo.clearWatch(watchId); + }, + + getPermission: function(siteName, imageUrl, extraMessage) { + geo.getPermission(siteName, imageUrl, extraMessage); + } + + }; +}); + +var AjaxGeoLocation = (function() { + // -- PRIVATE + var loading = false; + var loadGoogleLoader = function() { + if (!hasGoogleLoader() && !loading) { + loading = true; + var s = document.createElement('script'); + s.src = (document.location.protocol == "https:"?"https://":"http://") + 'www.google.com/jsapi?callback=_google_loader_apiLoaded'; + s.type = "text/javascript"; + document.getElementsByTagName('body')[0].appendChild(s); + } + }; + + var queue = []; + var addLocationQueue = function(callback) { + queue.push(callback); + }; + + var runLocationQueue = function() { + if (hasGoogleLoader()) { + while (queue.length > 0) { + var call = queue.pop(); + call(); + } + } + }; + + window['_google_loader_apiLoaded'] = function() { + runLocationQueue(); + }; + + var hasGoogleLoader = function() { + return (window['google'] && google['loader']); + }; + + var checkGoogleLoader = function(callback) { + if (hasGoogleLoader()) { return true; } + + addLocationQueue(callback); + + loadGoogleLoader(); + + return false; + }; + + loadGoogleLoader(); // start to load as soon as possible just in case + + // -- PUBLIC + return { + shim: true, + + type: "ClientLocation", + + lastPosition: null, + + getCurrentPosition: function(successCallback, errorCallback, options) { + var self = this; + if (!checkGoogleLoader(function() { + self.getCurrentPosition(successCallback, errorCallback, options); + })) { return; } + + if (google.loader.ClientLocation) { + var cl = google.loader.ClientLocation; + + var position = { + coords: { + latitude: cl.latitude, + longitude: cl.longitude, + altitude: null, + accuracy: 43000, // same as Gears accuracy over wifi? + altitudeAccuracy: null, + heading: null, + speed: null + }, + // extra info that is outside of the bounds of the core API + address: { + city: cl.address.city, + country: cl.address.country, + country_code: cl.address.country_code, + region: cl.address.region + }, + timestamp: new Date() + }; + + successCallback(position); + + this.lastPosition = position; + } else if (errorCallback === "function") { + errorCallback({ code: 3, message: "Using the Google ClientLocation API and it is not able to calculate a location."}); + } + }, + + watchPosition: function(successCallback, errorCallback, options) { + this.getCurrentPosition(successCallback, errorCallback, options); + + var self = this; + var watchId = setInterval(function() { + self.getCurrentPosition(successCallback, errorCallback, options); + }, 10000); + + return watchId; + }, + + clearWatch: function(watchId) { + clearInterval(watchId); + }, + + getPermission: function(siteName, imageUrl, extraMessage) { + // for now just say yes :) + return true; + } + + }; +}); + +// If you have Gears installed use that, else use Ajax ClientLocation +navigator.geolocation = (window.google && google.gears) ? GearsGeoLocation() : AjaxGeoLocation(); + +})(); +} diff --git a/js/util.js b/js/util.js index d929e91e2e..eace1778e2 100644 --- a/js/util.js +++ b/js/util.js @@ -1242,272 +1242,3 @@ $(document).ready(function(){ SN.Init.Login(); } }); - -// Formerly in xbImportNode.js -// @fixme put it back there -- since we're minifying we can concat in the makefile now - -/* is this stuff defined? */ -if (!document.ELEMENT_NODE) { - document.ELEMENT_NODE = 1; - document.ATTRIBUTE_NODE = 2; - document.TEXT_NODE = 3; - document.CDATA_SECTION_NODE = 4; - document.ENTITY_REFERENCE_NODE = 5; - document.ENTITY_NODE = 6; - document.PROCESSING_INSTRUCTION_NODE = 7; - document.COMMENT_NODE = 8; - document.DOCUMENT_NODE = 9; - document.DOCUMENT_TYPE_NODE = 10; - document.DOCUMENT_FRAGMENT_NODE = 11; - document.NOTATION_NODE = 12; -} - -document._importNode = function(node, allChildren) { - /* find the node type to import */ - switch (node.nodeType) { - case document.ELEMENT_NODE: - /* create a new element */ - var newNode = document.createElement(node.nodeName); - /* does the node have any attributes to add? */ - if (node.attributes && node.attributes.length > 0) - /* add all of the attributes */ - for (var i = 0, il = node.attributes.length; i < il;) { - if (node.attributes[i].nodeName == 'class') { - newNode.className = node.getAttribute(node.attributes[i++].nodeName); - } else { - newNode.setAttribute(node.attributes[i].nodeName, node.getAttribute(node.attributes[i++].nodeName)); - } - } - /* are we going after children too, and does the node have any? */ - if (allChildren && node.childNodes && node.childNodes.length > 0) - /* recursively get all of the child nodes */ - for (var i = 0, il = node.childNodes.length; i < il;) - newNode.appendChild(document._importNode(node.childNodes[i++], allChildren)); - return newNode; - break; - case document.TEXT_NODE: - case document.CDATA_SECTION_NODE: - case document.COMMENT_NODE: - return document.createTextNode(node.nodeValue); - break; - } -}; - -// @fixme put this next bit back too -- since we're minifying we can concat in the makefile now -// A shim to implement the W3C Geolocation API Specification using Gears or the Ajax API -if (typeof navigator.geolocation == "undefined" || navigator.geolocation.shim ) { (function(){ - -// -- BEGIN GEARS_INIT -(function() { - // We are already defined. Hooray! - if (window.google && google.gears) { - return; - } - - var factory = null; - - // Firefox - if (typeof GearsFactory != 'undefined') { - factory = new GearsFactory(); - } else { - // IE - try { - factory = new ActiveXObject('Gears.Factory'); - // privateSetGlobalObject is only required and supported on WinCE. - if (factory.getBuildInfo().indexOf('ie_mobile') != -1) { - factory.privateSetGlobalObject(this); - } - } catch (e) { - // Safari - if ((typeof navigator.mimeTypes != 'undefined') && navigator.mimeTypes["application/x-googlegears"]) { - factory = document.createElement("object"); - factory.style.display = "none"; - factory.width = 0; - factory.height = 0; - factory.type = "application/x-googlegears"; - document.documentElement.appendChild(factory); - } - } - } - - // *Do not* define any objects if Gears is not installed. This mimics the - // behavior of Gears defining the objects in the future. - if (!factory) { - return; - } - - // Now set up the objects, being careful not to overwrite anything. - // - // Note: In Internet Explorer for Windows Mobile, you can't add properties to - // the window object. However, global objects are automatically added as - // properties of the window object in all browsers. - if (!window.google) { - google = {}; - } - - if (!google.gears) { - google.gears = {factory: factory}; - } -})(); -// -- END GEARS_INIT - -var GearsGeoLocation = (function() { - // -- PRIVATE - var geo = google.gears.factory.create('beta.geolocation'); - - var wrapSuccess = function(callback, self) { // wrap it for lastPosition love - return function(position) { - callback(position); - self.lastPosition = position; - }; - }; - - // -- PUBLIC - return { - shim: true, - - type: "Gears", - - lastPosition: null, - - getCurrentPosition: function(successCallback, errorCallback, options) { - var self = this; - var sc = wrapSuccess(successCallback, self); - geo.getCurrentPosition(sc, errorCallback, options); - }, - - watchPosition: function(successCallback, errorCallback, options) { - geo.watchPosition(successCallback, errorCallback, options); - }, - - clearWatch: function(watchId) { - geo.clearWatch(watchId); - }, - - getPermission: function(siteName, imageUrl, extraMessage) { - geo.getPermission(siteName, imageUrl, extraMessage); - } - - }; -}); - -var AjaxGeoLocation = (function() { - // -- PRIVATE - var loading = false; - var loadGoogleLoader = function() { - if (!hasGoogleLoader() && !loading) { - loading = true; - var s = document.createElement('script'); - s.src = (document.location.protocol == "https:"?"https://":"http://") + 'www.google.com/jsapi?callback=_google_loader_apiLoaded'; - s.type = "text/javascript"; - document.getElementsByTagName('body')[0].appendChild(s); - } - }; - - var queue = []; - var addLocationQueue = function(callback) { - queue.push(callback); - }; - - var runLocationQueue = function() { - if (hasGoogleLoader()) { - while (queue.length > 0) { - var call = queue.pop(); - call(); - } - } - }; - - window['_google_loader_apiLoaded'] = function() { - runLocationQueue(); - }; - - var hasGoogleLoader = function() { - return (window['google'] && google['loader']); - }; - - var checkGoogleLoader = function(callback) { - if (hasGoogleLoader()) { return true; } - - addLocationQueue(callback); - - loadGoogleLoader(); - - return false; - }; - - loadGoogleLoader(); // start to load as soon as possible just in case - - // -- PUBLIC - return { - shim: true, - - type: "ClientLocation", - - lastPosition: null, - - getCurrentPosition: function(successCallback, errorCallback, options) { - var self = this; - if (!checkGoogleLoader(function() { - self.getCurrentPosition(successCallback, errorCallback, options); - })) { return; } - - if (google.loader.ClientLocation) { - var cl = google.loader.ClientLocation; - - var position = { - coords: { - latitude: cl.latitude, - longitude: cl.longitude, - altitude: null, - accuracy: 43000, // same as Gears accuracy over wifi? - altitudeAccuracy: null, - heading: null, - speed: null - }, - // extra info that is outside of the bounds of the core API - address: { - city: cl.address.city, - country: cl.address.country, - country_code: cl.address.country_code, - region: cl.address.region - }, - timestamp: new Date() - }; - - successCallback(position); - - this.lastPosition = position; - } else if (errorCallback === "function") { - errorCallback({ code: 3, message: "Using the Google ClientLocation API and it is not able to calculate a location."}); - } - }, - - watchPosition: function(successCallback, errorCallback, options) { - this.getCurrentPosition(successCallback, errorCallback, options); - - var self = this; - var watchId = setInterval(function() { - self.getCurrentPosition(successCallback, errorCallback, options); - }, 10000); - - return watchId; - }, - - clearWatch: function(watchId) { - clearInterval(watchId); - }, - - getPermission: function(siteName, imageUrl, extraMessage) { - // for now just say yes :) - return true; - } - - }; -}); - -// If you have Gears installed use that, else use Ajax ClientLocation -navigator.geolocation = (window.google && google.gears) ? GearsGeoLocation() : AjaxGeoLocation(); - -})(); -} diff --git a/js/xbImportNode.js b/js/xbImportNode.js new file mode 100644 index 0000000000..f600a4789e --- /dev/null +++ b/js/xbImportNode.js @@ -0,0 +1,47 @@ +/* is this stuff defined? */ +if (!document.ELEMENT_NODE) { + document.ELEMENT_NODE = 1; + document.ATTRIBUTE_NODE = 2; + document.TEXT_NODE = 3; + document.CDATA_SECTION_NODE = 4; + document.ENTITY_REFERENCE_NODE = 5; + document.ENTITY_NODE = 6; + document.PROCESSING_INSTRUCTION_NODE = 7; + document.COMMENT_NODE = 8; + document.DOCUMENT_NODE = 9; + document.DOCUMENT_TYPE_NODE = 10; + document.DOCUMENT_FRAGMENT_NODE = 11; + document.NOTATION_NODE = 12; +} + +document._importNode = function(node, allChildren) { + /* find the node type to import */ + switch (node.nodeType) { + case document.ELEMENT_NODE: + /* create a new element */ + var newNode = document.createElement(node.nodeName); + /* does the node have any attributes to add? */ + if (node.attributes && node.attributes.length > 0) + /* add all of the attributes */ + for (var i = 0, il = node.attributes.length; i < il;) { + if (node.attributes[i].nodeName == 'class') { + newNode.className = node.getAttribute(node.attributes[i++].nodeName); + } else { + newNode.setAttribute(node.attributes[i].nodeName, node.getAttribute(node.attributes[i++].nodeName)); + } + } + /* are we going after children too, and does the node have any? */ + if (allChildren && node.childNodes && node.childNodes.length > 0) + /* recursively get all of the child nodes */ + for (var i = 0, il = node.childNodes.length; i < il;) + newNode.appendChild(document._importNode(node.childNodes[i++], allChildren)); + return newNode; + break; + case document.TEXT_NODE: + case document.CDATA_SECTION_NODE: + case document.COMMENT_NODE: + return document.createTextNode(node.nodeValue); + break; + } +}; + From a85bbd908821fb09de6a291a167ab19902cb2ed2 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 27 Dec 2010 20:49:08 -0800 Subject: [PATCH 5/5] Add a user parameter to atom pub api events --- EVENTS.txt | 2 ++ actions/apitimelineuser.php | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/EVENTS.txt b/EVENTS.txt index 65265cdf0f..521f568efe 100644 --- a/EVENTS.txt +++ b/EVENTS.txt @@ -969,9 +969,11 @@ EndRevokeRole: when a role has been revoked StartAtomPubNewActivity: When a new activity comes in through Atom Pub API - &$activity: received activity +- $user: user publishing the entry EndAtomPubNewActivity: When a new activity comes in through Atom Pub API - $activity: received activity +- $user: user publishing the entry - $notice: notice that was created StartXrdActionAliases: About to set aliases for the XRD object for a user diff --git a/actions/apitimelineuser.php b/actions/apitimelineuser.php index 42988a00f6..1573f74897 100644 --- a/actions/apitimelineuser.php +++ b/actions/apitimelineuser.php @@ -324,7 +324,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction $activity = new Activity($dom->documentElement); - if (Event::handle('StartAtomPubNewActivity', array(&$activity))) { + if (Event::handle('StartAtomPubNewActivity', array(&$activity, $this->user))) { if ($activity->verb != ActivityVerb::POST) { // TRANS: Client error displayed when not using the POST verb. @@ -347,7 +347,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction $saved = $this->postNote($activity); - Event::handle('EndAtomPubNewActivity', array($activity, $saved)); + Event::handle('EndAtomPubNewActivity', array($activity, $this->user, $saved)); } if (!empty($saved)) {