1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 2010, 2011, 2013, 2014, 2016 Synacor, Inc.
  5  *
  6  * The contents of this file are subject to the Common Public Attribution License Version 1.0 (the "License");
  7  * you may not use this file except in compliance with the License.
  8  * You may obtain a copy of the License at: https://www.zimbra.com/license
  9  * The License is based on the Mozilla Public License Version 1.1 but Sections 14 and 15
 10  * have been added to cover use of software over a computer network and provide for limited attribution
 11  * for the Original Developer. In addition, Exhibit A has been modified to be consistent with Exhibit B.
 12  *
 13  * Software distributed under the License is distributed on an "AS IS" basis,
 14  * WITHOUT WARRANTY OF ANY KIND, either express or implied.
 15  * See the License for the specific language governing rights and limitations under the License.
 16  * The Original Code is Zimbra Open Source Web Client.
 17  * The Initial Developer of the Original Code is Zimbra, Inc.  All rights to the Original Code were
 18  * transferred by Zimbra, Inc. to Synacor, Inc. on September 14, 2015.
 19  *
 20  * All portions of the code are Copyright (C) 2010, 2011, 2013, 2014, 2016 Synacor, Inc. All Rights Reserved.
 21  * ***** END LICENSE BLOCK *****
 22  */
 23 
 24 ZmTaskMgr = function(container) {
 25 	this._container = container;
 26 	//this.clearCache();
 27 
 28 	this._listeners = {};
 29 	this._folderNames = {};
 30 
 31 };
 32 
 33 ZmTaskMgr.prototype = new ZmCalMgr;
 34 ZmTaskMgr.prototype.constructor = ZmTaskMgr;
 35 
 36 ZmTaskMgr.prototype.toString =
 37 function() {
 38 	return "ZmTaskMgr";
 39 };
 40 
 41 ZmTaskMgr.prototype._refreshCallback =
 42 function(list) {
 43 	this.getReminderController()._refreshCallback(list);
 44 };
 45 
 46 ZmTaskMgr.prototype.getReminderController =
 47 function() {
 48 	if (!this._reminderController) {
 49 		this._reminderController = new ZmReminderController(this, "task");
 50 	}
 51 	return this._reminderController;
 52 };
 53 
 54 ZmTaskMgr.prototype.getCalViewController =
 55 function() {
 56 	var taskController = AjxDispatcher.run("GetTaskController");
 57 	return taskController;
 58 };
 59 
 60 ZmTaskMgr.prototype._miniCalMouseOutDayCallback =
 61 function(control) {
 62 	this._currentMouseOverDay = null;
 63 };
 64 
 65 ZmTaskMgr.prototype.getApptSummaries =
 66 function(params) {
 67 	var apptVec = this.setSearchParams(params);
 68 
 69 	if (apptVec != null && (apptVec instanceof AjxVector)) {
 70 		return apptVec;
 71 	}
 72 
 73 	// this array will hold a list of tasks as we collect them from the server
 74 	this._rawTasks = [];
 75 
 76 	if (params.callback) {
 77 		this._search(params);
 78 	} else {
 79 		return this._search(params);
 80 	}
 81 };
 82 
 83 ZmTaskMgr.prototype.setSearchParams =
 84 function(params) {
 85 	if (!(params.folderIds instanceof Array)) {
 86 		params.folderIds = [params.folderIds];
 87 	} else if (params.folderIds.length == 0) {
 88 		var newVec = new AjxVector();
 89 		if (params.callback) {
 90 			params.callback.run(newVec);
 91 		}
 92 		return newVec;
 93 	}
 94 
 95 	var folderIdMapper = {};
 96 	var query = "";
 97 	for (var i=0; i < params.folderIds.length; i++) {
 98 		var fid = params.folderIds[i];
 99 		var systemFolderId = appCtxt.getActiveAccount().isMain
100 			? fid : ZmOrganizer.getSystemId(fid);
101 
102 		// map remote folder ids into local ones while processing search since
103 		// server wont do it for us (see bug 7083)
104 		var folder = appCtxt.getById(systemFolderId);
105 		var rid = folder ? folder.getRemoteId() : systemFolderId;
106 		folderIdMapper[rid] = systemFolderId;
107 
108 		if (query.length) {
109 			query += " OR ";
110 		}
111 		var idText = AjxUtil.isNumeric(fid) ? fid : ['"', fid, '"'].join("");
112 		query += "inid:" + idText;
113 
114 	}
115 	params.queryHint = query;
116 	params.folderIdMapper = folderIdMapper;
117 	params.offset = 0;
118 };
119 
120 ZmTaskMgr.prototype._search =
121 function(params) {
122 	var jsonObj = {SearchRequest:{_jsns:"urn:zimbraMail"}};
123 	var request = jsonObj.SearchRequest;
124 
125 	this._setSoapParams(request, params);
126 
127 	var accountName = appCtxt.multiAccounts ? appCtxt.accountList.mainAccount.name : null;
128 	if (params.callback) {
129 		appCtxt.getAppController().sendRequest({
130 			jsonObj: jsonObj,
131 			asyncMode: true,
132 			callback: (new AjxCallback(this, this._getApptSummariesResponse, [params])),
133 			noBusyOverlay: params.noBusyOverlay,
134 			accountName: accountName
135 		});
136 	} else {
137 		var response = appCtxt.getAppController().sendRequest({jsonObj: jsonObj, accountName: accountName});
138 		var result = new ZmCsfeResult(response, false);
139 		return this._getApptSummariesResponse(params, result);
140 	}
141 };
142 
143 ZmTaskMgr.prototype._setSoapParams =
144 function(request, params) {
145 	request.sortBy = "none";
146 	request.limit = "500";
147 	//request.calExpandInstStart = params.start;
148 	//request.calExpandInstEnd = params.end;
149 	request.types = ZmSearch.TYPE[ZmItem.TASK];
150 	request.offset = params.offset;
151 
152 	var query = params.query;
153 	if (params.queryHint) {
154 		query = (query != null)
155 			? (query + " (" + params.queryHint + ")")
156 			: params.queryHint;
157 	}
158 	request.query = {_content:query};
159 };
160 
161 
162 ZmTaskMgr.prototype._getApptSummariesResponse =
163 function(params, result) {
164 	// TODO: mark both as needing refresh?
165 	if (!result) { return; }
166 
167 	var callback = params.callback;
168 	var resp;
169 	try {
170 		resp = result.getResponse();
171 	} catch (ex) {
172 		if (callback) {
173 			callback.run(new AjxVector());
174 		}
175 		return;
176 	}
177 
178 	var searchResp = resp.SearchResponse;
179 	var newList = this.processSearchResponse(searchResp, params);
180 	if (newList == null) { return; }
181 
182 	if (callback) {
183 		callback.run(newList, params.query);
184 	} else {
185 		return newList;
186 	}
187 };
188 
189 ZmTaskMgr.prototype.processSearchResponse =
190 function(searchResp, params) {
191 	if(!searchResp) { return; }
192 
193 	if (searchResp && searchResp.task && searchResp.task.length) {
194 		this._rawTasks = this._rawTasks != null
195 			? this._rawTasks.concat(searchResp.task)
196 			: searchResp.task;
197 
198 		// if "more" flag set, keep requesting more appts
199 		if (searchResp.more) {
200 			var lastAppt = searchResp.task[searchResp.task.length-1];
201 			if (lastAppt) {
202 				params.offset += 500;
203 				this._search(params);
204 				return;
205 			}
206 		}
207 	}
208 
209 	var newList = new AjxVector();
210 	if (this._rawTasks && this._rawTasks.length) {
211 		//this._list = new ZmList(ZmItem.TASK);
212 		for (var i = 0; i < this._rawTasks.length; i++) {
213 			DBG.println(AjxDebug.DBG2, "task[j]:" + this._rawTasks[i].name);
214 			var taskNode = this._rawTasks[i];
215 			////var instances = taskNode ? taskNode.inst : null;
216 			////if (instances) {
217             //var args = {list:this._list};
218             // Pass null as the list - otherwise the list, created above and used nowhere else
219             // for viewing will be the one associated with teh
220             var args = {list:null};
221 				////for (var j = 0; j < instances.length; j++) {
222 					var task = ZmTask.createFromDom(taskNode, args, null);
223 					DBG.println(AjxDebug.DBG2, "lite task :" + task);
224 					if (task) newList.add(task);
225 				////}
226 			////}
227 
228             // Accumulate this list to be processed by the reminderController callback
229             newList.add(task);
230 		}
231 
232 	}
233 	return newList;
234 };
235 
236 ZmTaskMgr.prototype.getCalendarName =
237 function(folderId) {
238 	var app = appCtxt.getApp(ZmApp.TASKS);
239 	return app.getTaskFolderName(folderId);
240 };
241 
242 
243 ZmTaskMgr.prototype.getCheckedCalendarFolderIds =
244 function(localOnly) {
245 	var app = appCtxt.getApp(ZmApp.TASKS);
246 	return app.getTaskFolderIds(localOnly);
247 };
248 
249 ZmTaskMgr.prototype._handleError =
250 function(ex) {
251 	if (ex.code == 'mail.INVITE_OUT_OF_DATE' ||	ex.code == 'mail.NO_SUCH_APPT') {
252 		var msgDialog = appCtxt.getMsgDialog();
253 		msgDialog.setMessage(ZmMsg.apptOutOfDate, DwtMessageDialog.INFO_STYLE);
254 		msgDialog.popup();
255 		return true;
256 	}
257 	return false;
258 };
259 
260 
261 ZmTaskMgr.prototype.getQuickReminderSearchTimeRange =
262 function() {
263 	var endOfDay = new Date();
264 	endOfDay.setHours(23,59,59,999);
265 
266 	var end = new Date(endOfDay.getTime());
267 
268 	var start = endOfDay;
269 	start.setHours(0,0,0, 0);
270 
271 	return { start: start.getTime(), end: end.getTime() };
272 };
273 
274 ZmTaskMgr.prototype.showQuickReminder =
275 function() {
276     var params = this.getQuickReminderParams();
277     this.getApptSummaries(params);
278 };
279 
280 ZmTaskMgr.prototype.getQuickReminderParams =
281 function() {
282 
283 	var timeRange = this.getQuickReminderSearchTimeRange();
284 	return {
285 		start: timeRange.start,
286 		end: timeRange.end,
287 		fanoutAllDay: false,
288 		folderIds: this.getCheckedCalendarFolderIds(true),
289 		callback: (new AjxCallback(this, this._quickReminderCallback)),
290 		includeReminders: true
291 	};
292 };
293 
294 ZmTaskMgr.prototype._quickReminderCallback =
295 function(list) {
296     var newList = new AjxVector();
297     this._cacheMap = {};
298     var size = list.size();
299 
300     var currentTime  = (new Date()).getTime();
301 
302     for (var i = 0; i < size; i++) {
303         var appt = list.get(i);
304         var id = appt.id;
305         if (!this._cacheMap[id]) {
306             this._cacheMap[id] = appt;
307             if(appt.isAllDayEvent()) continue;
308             var diff = appt.getStartTime() - currentTime;
309             var isUpcomingEvent = (diff >= 0 && diff <= AjxDateUtil.MSEC_PER_HOUR)
310             if((currentTime >= appt.getStartTime() && currentTime <= appt.getEndTime()) || isUpcomingEvent) {
311                 appt.isUpcomingEvent = isUpcomingEvent;
312                 newList.add(appt);
313             }
314         }
315     }
316 
317     var qDlg = this.getQuickReminderDialog();
318     qDlg.initialize(newList);
319     qDlg.popup();
320 };
321 
322 
323 /**
324  * Gets the quick reminder dialog.
325  *
326  * @return	{ZmQuickReminderDialog}	the dialog
327  */
328 ZmTaskMgr.prototype.getQuickReminderDialog =
329 function() {
330 	if (this._reminderDialog == null) {
331 		this._reminderDialog = new ZmQuickReminderDialog(appCtxt.getShell(), this, this._calController);
332 	}
333 	return this._reminderDialog;
334 };
335