From dc8ce87a26aaeeec655530e2960561498e61c94a Mon Sep 17 00:00:00 2001
From: Vincent Petry <pvince81@owncloud.com>
Date: Mon, 2 Nov 2015 14:17:49 +0100
Subject: [PATCH] Query tags/favorite through Webdav in file list

---
 apps/files/js/filelist.js   | 32 ++++++++++++++++---
 apps/files/js/tagsplugin.js | 32 +++++++++++++++++++
 core/js/files/client.js     | 63 +++++++++++++++++++++++++++++++------
 core/js/files/fileinfo.js   |  5 ++-
 4 files changed, 118 insertions(+), 14 deletions(-)

diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js
index 2c97816df0..83c7e147d4 100644
--- a/apps/files/js/filelist.js
+++ b/apps/files/js/filelist.js
@@ -1376,6 +1376,13 @@
 			}
 		},
 
+		/**
+		 * Returns list of webdav properties to request
+		 */
+		_getWebdavProperties: function() {
+			return this.filesClient.getPropfindProperties();
+		},
+
 		/**
 		 * Reloads the file list using ajax call
 		 *
@@ -1390,7 +1397,12 @@
 			this._currentFileModel = null;
 			this.$el.find('.select-all').prop('checked', false);
 			this.showMask();
-			this._reloadCall = this.filesClient.getFolderContents(this.getCurrentDirectory(), {includeParent: true});
+			this._reloadCall = this.filesClient.getFolderContents(
+				this.getCurrentDirectory(), {
+					includeParent: true,
+					properties: this._getWebdavProperties()
+				}
+			);
 			if (this._detailsView) {
 				// close sidebar
 				this._updateDetailsView(null);
@@ -1939,7 +1951,11 @@
 				)
 				.done(function() {
 					// TODO: error handling / conflicts
-					self.filesClient.getFileInfo(targetPath)
+					self.filesClient.getFileInfo(
+							targetPath, {
+								properties: self._getWebdavProperties()
+							}
+						)
 						.then(function(status, data) {
 							self.add(data, {animate: true, scrollTo: true});
 							deferred.resolve(status, data);
@@ -1989,7 +2005,11 @@
 
 			this.filesClient.createDirectory(targetPath)
 				.done(function(createStatus) {
-					self.filesClient.getFileInfo(targetPath)
+					self.filesClient.getFileInfo(
+							targetPath, {
+								properties: self._getWebdavProperties()
+							}
+						)
 						.done(function(status, data) {
 							self.add(data, {animate: true, scrollTo: true});
 							deferred.resolve(status, data);
@@ -2002,7 +2022,11 @@
 				.fail(function(createStatus) {
 					// method not allowed, folder might exist already
 					if (createStatus === 405) {
-						self.filesClient.getFileInfo(targetPath)
+						self.filesClient.getFileInfo(
+								targetPath, {
+									properties: self._getWebdavProperties()
+								}
+							)
 							.done(function(status, data) {
 								// add it to the list, for completeness
 								self.add(data, {animate: true, scrollTo: true});
diff --git a/apps/files/js/tagsplugin.js b/apps/files/js/tagsplugin.js
index 23945d5260..81b22e34cc 100644
--- a/apps/files/js/tagsplugin.js
+++ b/apps/files/js/tagsplugin.js
@@ -161,6 +161,38 @@
 				fileInfo.tags = tags;
 				return fileInfo;
 			};
+
+			var NS_OC = 'http://owncloud.org/ns';
+
+			var oldGetWebdavProperties = fileList._getWebdavProperties;
+			fileList._getWebdavProperties = function() {
+				var props = oldGetWebdavProperties.apply(this, arguments);
+				props.push('{' + NS_OC + '}tags');
+				props.push('{' + NS_OC + '}favorite');
+				return props;
+			};
+
+			fileList.filesClient.addFileInfoParser(function(response) {
+				var data = {};
+				var props = response.propStat[0].properties;
+				var tags = props['{' + NS_OC + '}tags'];
+				var favorite = props['{' + NS_OC + '}favorite'];
+				if (tags && tags.length) {
+					tags = _.chain(tags).filter(function(xmlvalue) {
+						return (xmlvalue.namespaceURI === NS_OC && xmlvalue.nodeName.split(':')[1] === 'tag');
+					}).map(function(xmlvalue) {
+						return xmlvalue.textContent || xmlvalue.text;
+					}).value();
+				}
+				if (tags) {
+					data.tags = tags;
+				}
+				if (favorite && parseInt(favorite, 10) !== 0) {
+					data.tags = data.tags || [];
+					data.tags.push(OC.TAG_FAVORITE);
+				}
+				return data;
+			});
 		},
 
 		attach: function(fileList) {
diff --git a/core/js/files/client.js b/core/js/files/client.js
index 9bb7bb999f..5ee90d2d52 100644
--- a/core/js/files/client.js
+++ b/core/js/files/client.js
@@ -125,10 +125,17 @@
 		/**
 		 * Client from the library
 		 *
-		 * @type nl.sara.webdav.Client
+		 * @type dav.Client
 		 */
 		_client: null,
 
+		/**
+		 * Array of file info parsing functions.
+		 *
+		 * @type Array<OC.Files.Client~parseFileInfo>
+		 */
+		_fileInfoParsers: [],
+
 		/**
 		 * Returns the configured XHR provider for davclient
 		 * @return {XMLHttpRequest}
@@ -273,8 +280,7 @@
 				id: this._parseFileId(props['{' + Client.NS_OWNCLOUD + '}id']),
 				path: OC.dirname(path) || '/',
 				name: OC.basename(path),
-				mtime: new Date(props['{' + Client.NS_DAV + '}getlastmodified']),
-				_props: props
+				mtime: new Date(props['{' + Client.NS_DAV + '}getlastmodified'])
 			};
 
 			var etagProp = props['{' + Client.NS_DAV + '}getetag'];
@@ -350,6 +356,11 @@
 				}
 			}
 
+			// extend the parsed data using the custom parsers
+			_.each(this._fileInfoParsers, function(parserFunction) {
+				_.extend(data, parserFunction(response) || {});
+			});
+
 			return new FileInfo(data);
 		},
 
@@ -381,7 +392,7 @@
 		 *
 		 * @return {Array.<Object>} array of properties
 		 */
-		_getPropfindProperties: function() {
+		getPropfindProperties: function() {
 			if (!this._propfindProperties) {
 				this._propfindProperties = _.map(Client._PROPFIND_PROPERTIES, function(propDef) {
 					return '{' + propDef[0] + '}' + propDef[1];
@@ -397,6 +408,7 @@
 		 * @param {Object} [options] options
 		 * @param {boolean} [options.includeParent=false] set to true to keep
 		 * the parent folder in the result list
+		 * @param {Array} [options.properties] list of Webdav properties to retrieve
 		 *
 		 * @return {Promise} promise
 		 */
@@ -404,14 +416,21 @@
 			if (!path) {
 				path = '';
 			}
+			options = options || {};
 			var self = this;
 			var deferred = $.Deferred();
 			var promise = deferred.promise();
+			var properties;
+			if (_.isUndefined(options.properties)) {
+				properties = this.getPropfindProperties();
+			} else {
+				properties = options.properties;
+			}
 
 			// TODO: headers
 			this._client.propFind(
 				this._buildUrl(path),
-				this._getPropfindProperties(),
+				properties,
 				1
 			).then(function(result) {
 				if (self._isSuccessStatus(result.status)) {
@@ -432,23 +451,29 @@
 		 * Returns the file info of a given path.
 		 *
 		 * @param {String} path path
-		 * @param {Array} [properties] list of webdav properties to
-		 * retrieve
+		 * @param {Array} [options.properties] list of Webdav properties to retrieve
 		 *
 		 * @return {Promise} promise
 		 */
-		getFileInfo: function(path) {
+		getFileInfo: function(path, options) {
 			if (!path) {
 				path = '';
 			}
+			options = options || {};
 			var self = this;
 			var deferred = $.Deferred();
 			var promise = deferred.promise();
+			var properties;
+			if (_.isUndefined(options.properties)) {
+				properties = this.getPropfindProperties();
+			} else {
+				properties = options.properties;
+			}
 
 			// TODO: headers
 			this._client.propFind(
 				this._buildUrl(path),
-				this._getPropfindProperties(),
+				properties,
 				0
 			).then(
 				function(result) {
@@ -633,10 +658,30 @@
 				}
 			);
 			return promise;
+		},
+
+		/**
+		 * Add a file info parser function
+		 *
+		 * @param {OC.Files.Client~parseFileInfo>}
+		 */
+		addFileInfoParser: function(parserFunction) {
+			this._fileInfoParsers.push(parserFunction);
 		}
 
 	};
 
+	/**
+	 * File info parser function
+	 *
+	 * This function receives a list of Webdav properties as input and
+	 * should return a hash array of parsed properties, if applicable.
+	 *
+	 * @callback OC.Files.Client~parseFileInfo
+	 * @param {Object} XML Webdav properties
+     * @return {Array} array of parsed property values
+	 */
+
 	if (!OC.Files) {
 		/**
 		 * @namespace OC.Files
diff --git a/core/js/files/fileinfo.js b/core/js/files/fileinfo.js
index 95af07b799..c4a9eeb3d7 100644
--- a/core/js/files/fileinfo.js
+++ b/core/js/files/fileinfo.js
@@ -34,7 +34,6 @@
 		this.mimetype = data.mimetype || 'application/octet-stream';
 		this.mountType = data.mountType;
 		this.icon = data.icon;
-		this._props = data._props;
 
 		if (data.type) {
 			this.type = data.type;
@@ -44,6 +43,10 @@
 			this.type = 'file';
 		}
 
+		if (data.tags) {
+			this.tags = data.tags;
+		}
+
 		if (!this.mimetype) {
 			if (this.type === 'dir') {
 				this.mimetype = 'httpd/unix-directory';
-- 
GitLab