VulpesOS/gaia/apps/calendar/js/bridge.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

285 lines
7.8 KiB
JavaScript
Executable file

define(function(require, exports) {
'use strict';
var EventEmitter2 = require('ext/eventemitter2');
var co = require('ext/co');
var core = require('core');
var dayObserver = require('day_observer');
var nextTick = require('common/next_tick');
var object = require('common/object');
/**
* Fetch all the data needed to display the busytime information on the event
* views based on the busytimeId
*/
exports.fetchRecord = function(busytimeId) {
return co(function *() {
var record = yield dayObserver.findAssociated(busytimeId);
var eventStore = core.storeFactory.get('Event');
var owners = yield eventStore.ownersOf(record.event);
var provider = core.providerFactory.get(owners.account.providerType);
var capabilities = yield provider.eventCapabilities(record.event);
record.calendar = owners.calendar;
record.account = owners.account;
record.capabilities = capabilities;
return record;
});
};
/**
* Fetch all the calendars from database and emits a new event every time the
* values changes.
*
* @returns {ClientStream}
*/
exports.observeCalendars = function() {
// TODO: replace with real threads.client.stream when we get db into worker
var stream = new FakeClientStream();
var calendarStore = core.storeFactory.get('Calendar');
var getAllAndWrite = co.wrap(function *() {
// calendarStore.all() returns an object! we convert into an array since
// that is easier to render/manipulate
var calendars = yield calendarStore.all();
var data = yield object.map(
calendars,
co.wrap(function *(id, calendar) {
var caps;
try {
var provider = yield calendarStore.providerFor(calendar);
caps = provider.calendarCapabilities(calendar);
} catch (error) {
console.error(error);
return false;
}
return { calendar: calendar, capabilities: caps };
})
);
stream.write(data.filter(element => !!element));
});
calendarStore.on('add', getAllAndWrite);
calendarStore.on('remove', getAllAndWrite);
calendarStore.on('update', getAllAndWrite);
stream.cancel = function() {
calendarStore.off('add', getAllAndWrite);
calendarStore.off('remove', getAllAndWrite);
calendarStore.off('update', getAllAndWrite);
stream._cancel();
};
nextTick(getAllAndWrite);
return stream;
};
exports.updateCalendar = function(calendar) {
var calendarStore = core.storeFactory.get('Calendar');
return calendarStore.persist(calendar);
};
exports.createEvent = function(event) {
return persistEvent(event, 'create', 'canCreate');
};
exports.updateEvent = function(event) {
return persistEvent(event, 'update', 'canUpdate');
};
exports.deleteEvent = function(event) {
return persistEvent(event, 'delete', 'canDelete');
};
var persistEvent = co.wrap(function *(event, action, capability) {
event = event.data || event;
try {
var eventStore = core.storeFactory.get('Event');
var provider = yield eventStore.providerFor(event);
var caps = yield provider.eventCapabilities(event);
if (!caps[capability]) {
return Promise.reject(new Error(`Can't ${action} event`));
}
return provider[action + 'Event'](event);
} catch(err) {
console.error(
`${action} Error for event "${event._id}" ` +
`on calendar "${event.calendarId}"`
);
console.error(err);
return Promise.reject(err);
}
});
exports.getSetting = function(id) {
var settingStore = core.storeFactory.get('Setting');
return settingStore.getValue(id);
};
exports.setSetting = function(id, value) {
var settingStore = core.storeFactory.get('Setting');
return settingStore.set(id, value);
};
exports.observeSetting = function(id) {
var stream = new FakeClientStream();
var settingStore = core.storeFactory.get('Setting');
var writeOnChange = function(value) {
stream.write(value);
};
settingStore.on(`${id}Change`, writeOnChange);
stream.cancel = function() {
settingStore.off(`${id}Change`, writeOnChange);
stream._cancel();
};
exports.getSetting(id).then(writeOnChange);
return stream;
};
exports.getAccount = function(id) {
var accountStore = core.storeFactory.get('Account');
return accountStore.get(id);
};
exports.deleteAccount = function(id) {
var accountStore = core.storeFactory.get('Account');
return accountStore.remove(id);
};
/**
* Sends a request to create an account.
*
* @param {Calendar.Models.Account} model account details.
*/
exports.createAccount = co.wrap(function *(model) {
var storeFactory = core.storeFactory;
var accountStore = storeFactory.get('Account');
var calendarStore = storeFactory.get('Calendar');
// begin by persisting the account
var [, result] = yield accountStore.verifyAndPersist(model);
// finally sync the account so when
// we exit the request the user actually
// has some calendars. This should not take
// too long (compared to event sync).
yield accountStore.sync(result);
// begin sync of calendars
var calendars = yield calendarStore.remotesByAccount(result._id);
// note we don't wait for any of this to complete
// we just begin the sync and let the event handlers
// on the sync controller do the work.
for (var key in calendars) {
core.syncController.calendar(
result,
calendars[key]
);
}
return result;
});
exports.observeAccounts = function() {
var stream = new FakeClientStream();
var accountStore = core.storeFactory.get('Account');
var getAllAndWrite = co.wrap(function *() {
try {
var accounts = yield accountStore.all();
var data = object.map(accounts, (id, account) => {
return {
account: account,
provider: core.providerFactory.get(account.providerType)
};
});
stream.write(data);
} catch(err) {
console.error(`Error fetching accounts: ${err.message}`);
}
});
accountStore.on('add', getAllAndWrite);
accountStore.on('remove', getAllAndWrite);
accountStore.on('update', getAllAndWrite);
stream.cancel = function() {
accountStore.off('add', getAllAndWrite);
accountStore.off('remove', getAllAndWrite);
accountStore.off('update', getAllAndWrite);
stream._cancel();
};
nextTick(getAllAndWrite);
return stream;
};
exports.observeDay = function(date) {
var stream = new FakeClientStream();
var emit = stream.write.bind(stream);
stream.cancel = function() {
dayObserver.off(date, emit);
stream._cancel();
};
// FIXME: nextTick only really needed because dayObserver dispatches the
// first callback synchronously, easier to solve it here than to change
// dayObserver; we can remove this nextTick call after moving to threads.js
// (since it will always be async)
nextTick(() => dayObserver.on(date, emit));
return stream;
};
/**
* Returns a list of available presets filtered by
* the currently used presets in the database.
* (can't create multiple local calendars)
*/
exports.availablePresets = function(presetList) {
var accountStore = core.storeFactory.get('Account');
return accountStore.availablePresets(presetList);
};
/**
* FakeClientStream is used as a temporary solution while we move all the db
* calls into the worker. In the end all the methods inside this file will be
* transfered into the "backend/calendar_service.js" and we will simply call
* the `threads.client('calendar')` API
*/
function FakeClientStream() {
this._emitter = new EventEmitter2();
this._enabled = true;
}
FakeClientStream.prototype.write = function(data) {
this._enabled && this._emitter.emit('data', data);
};
FakeClientStream.prototype.listen = function(callback) {
this._enabled && this._emitter.on('data', callback);
};
FakeClientStream.prototype.unlisten = function(callback) {
this._enabled && this._emitter.off('data', callback);
};
FakeClientStream.prototype._cancel = function() {
this._emitter.removeAllListeners();
this._enabled = false;
};
});