view storage.js @ 34:dcf1f09f8cee

Add message to publish module and various fixes.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Fri, 05 Nov 2010 15:31:13 +0100
parents 62cbb1c49bc5
children 6697f394301f
line wrap: on
line source

/*
 *  Copyright (C) 2010  Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
 *
 *  This file is part of PSĜS, a PubSub server written in JavaScript.
 *
 *  PSĜS is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License.
 *
 *  PSĜS is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with PSĜS.  If not, see <http://www.gnu.org/licenses/>.
 */

var fs = require('fs');
var sha1hex = require('sha1').hex;
require('./iso8601');
var errors = require('./errors');
var config = require('./configuration');
var service_configuration = config.service_configuration;
var Configuration = config.Configuration;
var utils = require('./util');
var toBareJID = utils.toBareJID;

var nodes = require('./nodes');
var Node = nodes.Node;
var Item = nodes.Item;

var storage = exports;

var backend = require('./backends/' + config.backend);
storage.load = backend.load;
storage.save = backend.save;

storage.createNode = function(nodeID, params) {
	for (var i in backend.list)
		if (i == nodeID)
			return errors.owner.create.nodeid_already_exists.n;

	backend.list[nodeID] = new Node(params);
	storage.save();
	return errors.success;
};

storage.getMetadata = function(nodeID) {
	var node = storage.getNode(nodeID);
	if (typeof node == 'number')
		return node;

	if (!config.enabled('meta-data'))
		return {};

	var md = {};
	for (var i in service_configuration.node_metadata) {
		if (i == 'FORM_TYPE')
			continue;

		if (node.configuration[i])
			md[i] = node.configuration[i];
		else if (node.metadata[i])
			md[i] = node.metadata[i];
		else if (i == 'pubsub#owner')
			md[i] = node.owner;
	}
	return md;
};

storage.getConfiguration = function(nodeID) {
	var node = storage.getNode(nodeID);
	if (typeof node == 'number')
		return node;

	if (config.enabled('config-node'))
		return node.configuration;

	return {}; //FIXME
};

storage.configure = function(nodeID, params) {
	var node = storage.getNode(nodeID);
	if (typeof node == 'number')
		return node;

	if (!config.enabled('config-node'))
		return 42; //FIXME

	for (var i in params)
		if (service_configuration.node_config[i])
			node.configuration[i] = params[i];

	storage.save();
	return errors.success;
};

storage.configureSubscription = function(nodeID, jid, params) {
	var node = storage.getNode(nodeID);
	if (typeof node == 'number')
		return node;

	if (!config.enabled('subscription-options'))
		return 42; //FIXME

	var options = node.subscribers[jid].options;
	if (!options)
		return 42; //FIXME

	for (var i in params)
		if (service_configuration.subscribe_options[i])
			options[i] = params[i];

	storage.save();
	return errors.success;
};

storage.getChildren = function(node) {
	var n;
	var items = {};
	if (node)
		n = storage.getNode(node).items;
	else
		n = backend.list;

	for (var i in n) {
		var type;
		if (n[i].content)
			type = 'item';
		else
			type = 'node';
		items[i] = type;
	}
	return items;
};

storage.getNode = function(nodeID) {
	if (backend.list[nodeID])
		return backend.list[nodeID];
	return errors.node_does_not_exist.n;
};

storage.existsNode = function(nodeID) {
	if (backend.list[nodeID])
		return true;
	return false;
};

storage.purgeNode = function(nodeID) {
	var node = storage.getNode(nodeID);
	if (typeof n == 'number')
		return node;

	var notifs = storage.getSubscriptionsFromNodeID(nodeID);

	var item = storage.getLastItem(nodeID);
	if (typeof item == 'number') {
		node.items = {};
	} else {
		items = node.items[item];
		node.items = {};
		node.items[item] = items;
	}

	storage.save();
	return notifs;
};

storage.deleteNodeWithRedirect = function(nodeID, uri) {
	var del = storage.deleteNode(nodeID);
	if (typeof del == 'number')
		return del;

	backend.list[nodeID] = uri;
	storage.save();
	return errors.success;
};

storage.deleteNode = function(nodeID) {
	var node = storage.getNode(nodeID);
	if (typeof n == 'number')
		return node;

	var notifs = {};
	for (var i in node.subscribers)
		notifs[i] = {};
	for (var i in node.owner)
		notifs[node.owner[i]] = {};
	if (config.enabled('publisher-affiliation'))
		for (var i in node.publisher)
			notifs[node.publisher[i]] = {};
	if (config.enabled('publish-only-affiliation'))
		for (var i in node.publishOnly)
			notifs[node.publishOnly[i]] = {};

	delete backend.list[nodeID];
	storage.save();
	return notifs;
};

storage.setItem = function(nodeID, itemID, content) {
	var node = storage.getNode(nodeID);
	if (typeof node == 'number')
		return node;

	if (typeof itemID != 'string')
		itemID = utils.makeRandomId();

	i = node.setItem(itemID, content);
	if (content)
		i.content = content;

	storage.save();
	return storage.getSubscriptionsFromNodeID(nodeID)
};

storage.deleteItem = function(nodeID, itemID) {
	var node = storage.getNode(nodeID);
	if (typeof node == 'number')
		return node;

	if (typeof itemID != 'string')
		return errors.pub.retract.item_or_itemid_required.n;

	item = node.setItem(itemID);
	if (typeof item == 'number')
		return item;

	storage.save();
	return storage.getSubscriptionsFromNodeID(nodeID)
};

storage.getItems = function(nodeID) {
	var node;
	if (typeof nodeID == 'string')
		node = storage.getNode(nodeID);
	else
		node = nodeID;

	if (typeof node == 'number')
		return node;

	return node.items;
};

storage.getLastItem = function(nodeID, number) {
	var items = storage.getItems(nodeID);
	if (typeof items == 'number')
		return items;

	if (items == {})
		return 42; //FIXME

	if (number) {
		var last = [];
		var j = 0;
		for (var i in items) {
			last.push({name: i, date: items[i].date, content: items[i].content});
			j++;
		}
		if (j < number)
			return last;

		var cmp = function(a, b) {
			return b.date - a.date;
		}
		last = last.sort(cmp).slice(0, number);
	} else {
		var last;
		for (var i in items)
			if ((typeof last == 'undefined') || (items[i].date >= items[last].date))
				last = i;
	}

	if (last)
		return last;
	return 42; //FIXME
};

storage.existsItem = function(nodeID, itemID) {
	var items = storage.getItems(nodeID);
	if (typeof items == 'number')
		return items;

	for (var i in items)
		if (i == itemID)
			return items[i];
	return false;
};

storage.getItem = function(nodeID, itemID) {
	var items = storage.getItems(nodeID);
	if (typeof items == 'number')
		return items;

	if (items[itemID])
		return items[itemID].content;

	return errors.success;
};

storage.getSubscription = function(jid, nodeID) {
	var subs = {};
	if (nodeID) {
		var node = storage.getNode(nodeID);
		for (var sub in node.subscribers)
			if (toBareJID(sub) == jid)
				return node.subscribers[sub]
	} else {
		for (var node in backend.list) {
			for (var sub in backend.list[node].subscribers) {
				if (toBareJID(sub) == jid)
					subs[node] = backend.list[node].subscribers[sub];
			}
		}
	}
	return subs;
};

storage.getSubscriptionsFromNodeID = function(nodeID) {
	var node;
	if (typeof nodeID == 'string') {
		node = storage.getNode(nodeID);
		if (typeof node == 'number')
			return node;
	} else
		node = nodeID;

	var subs = {};
	for (var sub in node.subscribers) {
		if (typeof sub == 'string') {
			var subscription = {subid: node.subscribers[sub].subid, type: node.subscribers[sub].type};
			if (node.subscribers[sub].options)
				subscription.options = node.subscribers[sub].options;
			subs[sub] = subscription;
		}
	}
	return subs;
};

storage.subscribe = function(nodeID, jid, type, params) {
	if (!config.enabled('subscribe'))
		return errors.sub.subscribe.not_supported.n;

	var node = storage.getNode(nodeID);
	if (typeof node == 'number')
		return node;

	if (typeof type == 'undefined')
		type = 'subscribed';

	if (type == 'none') {
		if (!node.subscribers[jid])
			return errors.sub.unsubscribe.no_such_subscriber.n;
	}

	var subid = node.setSubscriber(jid, type, null, params);
	storage.save();
	return {subid: subid, type: type};
};

storage.setAffiliation = function(nodeID, jid, affil) {
	var node = storage.getNode(nodeID);
	if (typeof node == 'number')
		return node;

	if (affil == 'owner')
		node.owner.push(jid);
	else if (config.enabled('publisher-affiliation') && affil == 'publisher')
		node.publisher.push(jid);
	else if (config.enabled('publish-only-affiliation') && affil == 'publish-only')
		node.publishOnly.push(jid);
	else if (config.enabled('member-affiliation') && affil == 'member')
		node.member.push(jid);
	else if (config.enabled('outcast-affiliation') && affil == 'outcast')
		node.outcast.push(jid);

	storage.save();
	return errors.success;
};

storage.getAffiliation = function(jid, nodeID) {
	var node;
	if (typeof nodeID == 'string') {
		node = storage.getNode(nodeID);
		if (typeof node == 'number')
			return node;
	} else
		node = nodeID;

	for (var affil in config.owner)
		if (typeof affil == 'string' && node.owner[affil] == jid)
			return 'super-owner';
	for (var affil in node.owner)
		if (typeof affil == 'string' && node.owner[affil] == jid)
			return 'owner';
	if (config.enabled('publisher-affiliation'))
		for (var affil in node.publisher)
			if (typeof affil == 'string' && node.publisher[affil] == jid)
				return 'publisher';
	if (config.enabled('publish-only-affiliation'))
		for (var affil in node.publishOnly)
			if (typeof affil == 'string' && node.publishOnly[affil] == jid)
				return 'publish-only';
	if (config.enabled('member-affiliation'))
		for (var affil in node.member)
			if (typeof affil == 'string' && node.member[affil] == jid)
				return 'member';
	if (config.enabled('outcast-affiliation'))
		for (var affil in node.outcast)
			if (typeof affil == 'string' && node.outcast[affil] == jid)
				return 'outcast';
	return 'none';
};

storage.getAffiliationsFromJID = function(jid) {
	var affils = {};
	for (var nodeID in backend.list) {
		var node = backend.list[nodeID];
		for (var affil in config.owner)
			if (typeof affil == 'string' && config.owner[affil] == jid) {
				affils[nodeID] = 'super-owner';
				break;
			}
		for (var affil in node.owner)
			if (typeof affil == 'string' && node.owner[affil] == jid) {
				affils[nodeID] = 'owner';
				break;
			}
		if (config.enabled('publisher-affiliation'))
			for (var affil in node.publisher)
				if (typeof affil == 'string' && node.publisher[affil] == jid) {
					affils[nodeID] = 'publisher';
					break;
				}
		if (config.enabled('publish-only-affiliation'))
			for (var affil in node.publishOnly)
				if (typeof affil == 'string' && node.publishOnly[affil] == jid) {
					affils[nodeID] = 'publish-only';
					break;
				}
		if (config.enabled('member-affiliation'))
			for (var affil in node.member)
				if (typeof affil == 'string' && node.member[affil] == jid) {
					affils[nodeID] = 'member';
					break;
				}
		if (config.enabled('outcast-affiliation'))
			for (var affil in node.outcast)
				if (typeof affil == 'string' && node.outcast[affil] == jid) {
					affils[nodeID] = 'outcast';
					break;
				}
	}
	return affils;
};

storage.getAffiliationsFromNodeID = function(nodeID) {
	var node;
	if (typeof nodeID == 'string') {
		node = storage.getNode(nodeID);
		if (typeof node == 'number')
			return node;
	} else
		node = nodeID;

	var affils = {};
	for (var jid in config.owner)
		if (typeof jid == 'string')
			affils[config.owner[jid]] = 'super-owner';
	for (var jid in node.owner)
		if (typeof jid == 'string')
			affils[node.owner[jid]] = 'owner';
	if (config.enabled('publisher-affiliation'))
		for (var jid in node.publisher)
			if (typeof jid == 'string')
				affils[node.publisher[jid]] = 'publisher';
	if (config.enabled('publish-only-affiliation'))
		for (var jid in node.publishOnly)
			if (typeof jid == 'string')
				affils[node.publishOnly[jid]] = 'publish-only';
	if (config.enabled('member-affiliation'))
		for (var jid in node.member)
			if (typeof jid == 'string')
				affils[node.member[jid]] = 'member';
	if (config.enabled('outcast-affiliation'))
		for (var jid in node.outcast)
			if (typeof jid == 'string')
				affils[node.outcast[jid]] = 'outcast';
	return affils;
};

storage.debug = function() {
	console.log('\033[1;33m' + require('sys').inspect(backend.list, null, null) + '\033[0m');
};