Completed
Push — master ( 1f89ca...fd92ed )
by Lukas
12s
created

js/service/davservice.js (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
/**
2
 * @author Christoph Wurst <[email protected]>
3
 *
4
 * Mail
5
 *
6
 * This code is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU Affero General Public License, version 3,
8
 * as published by the Free Software Foundation.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
 * GNU Affero General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Affero General Public License, version 3,
16
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
17
 *
18
 */
19
20
define(function(require) {
21
	'use strict';
22
23
	var _ = require('underscore');
24
	var $ = require('jquery');
25
	var Backbone = require('backbone');
26
	var dav = require('davclient');
27
	var ical = require('ical');
28
	var OC = require('OC');
29
	var Radio = require('radio');
30
	var Calendar = require('models/dav/calendar');
31
32
	Radio.dav.reply('calendars', getUserCalendars);
33
	Radio.dav.reply('calendar:import', importCalendarEvent);
34
35
	var client = new dav.Client({
36
		baseUrl: OC.linkToRemote('dav/calendars'),
37
		xmlNamespaces: {
38
			'DAV:': 'd',
39
			'urn:ietf:params:xml:ns:caldav': 'c',
40
			'http://apple.com/ns/ical/': 'aapl',
41
			'http://owncloud.org/ns': 'oc',
42
			'http://calendarserver.org/ns/': 'cs'
43
		}
44
	});
45
	var props = [
46
		'{DAV:}displayname',
47
		'{urn:ietf:params:xml:ns:caldav}calendar-description',
48
		'{urn:ietf:params:xml:ns:caldav}calendar-timezone',
49
		'{http://apple.com/ns/ical/}calendar-order',
50
		'{http://apple.com/ns/ical/}calendar-color',
51
		'{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set',
52
		'{http://owncloud.org/ns}calendar-enabled',
53
		'{DAV:}acl',
54
		'{DAV:}owner',
55
		'{http://owncloud.org/ns}invite'
56
	];
57
58
	function getResponseCodeFromHTTPResponse(t) {
59
		return parseInt(t.split(' ')[1]);
60
	}
61
62
	function getACLFromResponse(properties) {
63
		var canWrite = false;
64
		var acl = properties['{DAV:}acl'];
65
		if (acl) {
66
			for (var k = 0; k < acl.length; k++) {
67
				var href = acl[k].getElementsByTagNameNS('DAV:', 'href');
68
				if (href.length === 0) {
69
					continue;
70
				}
71
				href = href[0].textContent;
72
				var writeNode = acl[k].getElementsByTagNameNS('DAV:', 'write');
73
				if (writeNode.length > 0) {
74
					canWrite = true;
75
				}
76
			}
77
		}
78
		properties.canWrite = canWrite;
79
	}
80
	;
0 ignored issues
show
This semicolons seems to be unnecessary.
Loading history...
81
82
	function getCalendarData(properties) {
83
		getACLFromResponse(properties);
84
85
		var data = {
86
			displayname: properties['{DAV:}displayname'],
87
			color: properties['{http://apple.com/ns/ical/}calendar-color'],
88
			order: properties['{http://apple.com/ns/ical/}calendar-order'],
89
			components: {
90
				vevent: false
91
			},
92
			writable: properties.canWrite
93
		};
94
95
		var components = properties['{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set'] || [];
96
		for (var i = 0; i < components.length; i++) {
97
			var name = components[i].attributes.getNamedItem('name').textContent.toLowerCase();
98
			if (data.components.hasOwnProperty(name)) {
99
				data.components[name] = true;
100
			}
101
		}
102
103
		return data;
104
	}
105
106
	function getUserCalendars() {
107
		var defer = $.Deferred();
108
		var url = OC.linkToRemote('dav/calendars') + '/' + OC.currentUser + '/';
109
110
		client.propFind(url, props, 1, {
111
			'requesttoken': OC.requestToken
112
		}).then(function(data) {
113
			var calendars = new Backbone.Collection();
114
115
			_.each(data.body, function(cal) {
116
				if (cal.propStat.length < 1) {
117
					return;
118
				}
119
				if (getResponseCodeFromHTTPResponse(cal.propStat[0].status) === 200) {
120
					var properties = getCalendarData(cal.propStat[0].properties);
121
					if (properties && properties.components.vevent && properties.writable === true) {
122
						properties.url = cal.href;
123
						calendars.push(new Calendar(properties));
124
					}
125
				}
126
			});
127
			defer.resolve(calendars);
128
		}, function() {
129
			defer.reject();
130
		});
131
132
		return defer.promise();
133
	}
134
135
	function getRandomString() {
136
		var str = '';
137
		for (var i = 0; i < 7; i++) {
138
			str += Math.random().toString(36).substring(7);
139
		}
140
		return str;
141
	}
142
143
	function createICalElement() {
144
		var root = new ical.Component(['vcalendar', [], []]);
145
146
		root.updatePropertyWithValue('prodid', '-//' + OC.theme.name + ' Mail');
147
148
		return root;
149
	}
150
151
	function splitCalendar(data) {
152
		var timezones = [];
153
		var allObjects = {};
154
		var jCal = ical.parse(data);
155
		var components = new ical.Component(jCal);
156
157
		var vtimezones = components.getAllSubcomponents('vtimezone');
158
		_.each(vtimezones, function(vtimezone) {
159
			timezones.push(vtimezone);
160
		});
161
162
		var componentNames = ['vevent', 'vjournal', 'vtodo'];
163
		_.each(componentNames, function(componentName) {
164
			var vobjects = components.getAllSubcomponents(componentName);
165
			allObjects[componentName] = {};
166
167
			_.each(vobjects, function(vobject) {
168
				var uid = vobject.getFirstPropertyValue('uid');
169
				allObjects[componentName][uid] = allObjects[componentName][uid] || [];
170
				allObjects[componentName][uid].push(vobject);
171
			});
172
		});
173
174
		var split = [];
175
		_.each(componentNames, function(componentName) {
176
			split[componentName] = [];
177
			_.each(allObjects[componentName], function(objects) {
178
				var component = createICalElement();
179
				_.each(timezones, function(timezone) {
180
					component.addSubcomponent(timezone);
181
				});
182
				_.each(objects, function(object) {
183
					component.addSubcomponent(object);
184
				});
185
				split[componentName].push(component.toString());
186
			});
187
		});
188
189
		return {
190
			name: components.getFirstPropertyValue('x-wr-calname'),
191
			color: components.getFirstPropertyValue('x-apple-calendar-color'),
192
			split: split
193
		};
194
	}
195
196
	function importCalendarEvent(url, data) {
197
		var defer = $.Deferred();
198
		var xhrs = [];
199
200
		var file = splitCalendar(data);
201
202
		var componentNames = ['vevent', 'vjournal', 'vtodo'];
203
		_.each(componentNames, function(componentName) {
204
			_.each(file.split[componentName], function(component) {
205
				xhrs.push($.ajax({
206
					url: url + getRandomString(),
207
					method: 'PUT',
208
					contentType: 'text/calendar; charset=utf-8',
209
					data: component,
210
					error: function() {
211
						defer.reject();
212
					}
213
				}));
214
			});
215
		});
216
217
		$.when.apply($, xhrs).done(function() {
218
			defer.resolve();
219
		});
220
221
		return defer.promise();
222
	}
223
});
224