jsdav-ext
Version:
jsDAV allows you to easily add WebDAV support to a NodeJS application. jsDAV is meant to cover the entire standard, and attempts to allow integration using an easy to understand API.
287 lines (263 loc) • 8.43 kB
JavaScript
/*
* @package jsDAV
* @subpackage CardDAV
* @copyright Copyright(c) 2013 Mike de Boer. <info AT mikedeboer DOT nl>
* @author Mike de Boer <info AT mikedeboer DOT nl>
* @license http://github.com/mikedeboer/jsDAV/blob/master/LICENSE MIT License
*/
;
var jsDAV_Collection = require("./../DAV/collection");
var jsCardDAV_iAddressBook = require("./interfaces/iAddressBook");
var jsDAV_iProperties = require("./../DAV/interfaces/iProperties");
var jsDAVACL_iAcl = require("./../DAVACL/interfaces/iAcl");
var jsCardDAV_Card = require("./card");
var Exc = require("./../shared/exceptions");
/**
* The AddressBook class represents a CardDAV addressbook, owned by a specific user
*
* The AddressBook can contain multiple vcards
*/
var jsCardDAV_AddressBook = module.exports = jsDAV_Collection.extend(jsCardDAV_iAddressBook, jsDAV_iProperties, jsDAVACL_iAcl, {
/**
* This is an array with addressbook information
*
* @var array
*/
addressBookInfo: {},
/**
* CardDAV backend
*
* @var jsCardDAV_iBackend
*/
carddavBackend: null,
/**
* Constructor
*
* @param jsCardDAV_iBackend carddavBackend
* @param {Object} addressBookInfo
*/
initialize: function(carddavBackend, addressBookInfo) {
this.carddavBackend = carddavBackend;
this.addressBookInfo = addressBookInfo;
},
/**
* Returns the name of the addressbook
*
* @return string
*/
getName: function() {
return this.addressBookInfo.uri;
},
/**
* Returns a card
*
* @param {String} name
* @return \ICard
*/
getChild: function(name, callback) {
var self = this;
this.carddavBackend.getCard(this.addressBookInfo.id, name, function(err, obj) {
if (!obj)
return callback(new Exc.NotFound("Card not found"));
callback(null, jsCardDAV_Card.new(self.carddavBackend, self.addressBookInfo, obj));
});
},
/**
* Returns the full list of cards
*
* @return array
*/
getChildren: function(callback) {
var self = this;
this.carddavBackend.getCards(this.addressBookInfo.id, function(err, objs) {
if (err)
return callback(err);
var children = objs.map(function(obj) {
return jsCardDAV_Card.new(self.carddavBackend, self.addressBookInfo, obj);
});
callback(null, children);
});
},
/**
* Creates a new directory
*
* We actually block this, as subdirectories are not allowed in addressbooks.
*
* @param {String} name
* @return void
*/
createDirectory: function(name, callback) {
callback(new Exc.MethodNotAllowed("Creating collections in addressbooks is not allowed"));
},
/**
* Creates a new file
*
* The contents of the new file must be a valid VCARD.
*
* This method may return an ETag.
*
* @param {String} name
* @param resource vcardData
* @return string|null
*/
createFile: function(name, vcardData, enc, callback) {
if (Buffer.isBuffer(vcardData))
vcardData = vcardData.toString("utf8");
this.carddavBackend.createCard(this.addressBookInfo.id, name, vcardData, callback);
},
/**
* Deletes the entire addressbook.
*
* @return void
*/
"delete": function(callback) {
this.carddavBackend.deleteAddressBook(this.addressBookInfo.id, callback);
},
/**
* Renames the addressbook
*
* @param {String} newName
* @return void
*/
setName: function(newName, callback) {
callback(new Exc.MethodNotAllowed("Renaming addressbooks is not yet supported"));
},
/**
* Returns the last modification date as a unix timestamp.
*
* @return void
*/
getLastModified: function(callback) {
callback(null, null);
},
/**
* Updates properties on this node,
*
* The properties array uses the propertyName in clark-notation as key,
* and the array value for the property value. In the case a property
* should be deleted, the property value will be null.
*
* This method must be atomic. If one property cannot be changed, the
* entire operation must fail.
*
* If the operation was successful, true can be returned.
* If the operation failed, false can be returned.
*
* Deletion of a non-existent property is always successful.
*
* Lastly, it is optional to return detailed information about any
* failures. In this case an array should be returned with the following
* structure:
*
* {
* "403" : {
* "{DAV:}displayname" : null,
* },
* "424" : {
* "{DAV:}owner" : null,
* }
* }
*
* In this example it was forbidden to update {DAV:}displayname.
* (403 Forbidden), which in turn also caused {DAV:}owner to fail
* (424 Failed Dependency) because the request needs to be atomic.
*
* @param {Object} mutations
* @return bool|array
*/
updateProperties: function(mutations, callback) {
this.carddavBackend.updateAddressBook(this.addressBookInfo.id, mutations, callback);
},
/**
* Returns a list of properties for this nodes.
*
* The properties list is a list of propertynames the client requested,
* encoded in clark-notation {xmlnamespace}tagname
*
* If the array is empty, it means 'all properties' were requested.
*
* @param {Array} properties
* @return array
*/
getProperties: function(properties, callback) {
var response = {};
var self = this;
properties.forEach(function(propertyName) {
if (self.addressBookInfo[propertyName])
response[propertyName] = self.addressBookInfo[propertyName];
});
callback(null, response);
},
/**
* Returns the owner principal
*
* This must be a url to a principal, or null if there's no owner
*
* @return string|null
*/
getOwner: function() {
return this.addressBookInfo.principaluri;
},
/**
* Returns a group principal
*
* This must be a url to a principal, or null if there's no owner
*
* @return string|null
*/
getGroup: function() {
return null;
},
/**
* Returns a list of ACE's for this node.
*
* Each ACE has the following properties:
* * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
* currently the only supported privileges
* * 'principal', a url to the principal who owns the node
* * 'protected' (optional), indicating that this ACE is not allowed to
* be updated.
*
* @return array
*/
getACL: function() {
return [
{
"privilege" : "{DAV:}read",
"principal" : this.addressBookInfo.principaluri,
"protected" : true
},
{
"privilege" : "{DAV:}write",
"principal" : this.addressBookInfo.principaluri,
"protected" : true
}
];
},
/**
* Updates the ACL
*
* This method will receive a list of new ACE's.
*
* @param {Array} acl
* @return void
*/
setACL: function(acl, callback) {
callback(new Exc.MethodNotAllowed("Changing ACL is not yet supported"));
},
/**
* Returns the list of supported privileges for this node.
*
* The returned data structure is a list of nested privileges.
* See jsDAVACL_Plugin.getDefaultSupportedPrivilegeSet for a simple
* standard structure.
*
* If null is returned from this method, the default privilege set is used,
* which is fine for most common usecases.
*
* @return array|null
*/
getSupportedPrivilegeSet: function() {
return null;
}
});