Changeset - b55393bf9fb6
[Not reviewed]
spectrum/src/frontends/slack/SlackAPI.cpp
Show inline comments
 
@@ -19,12 +19,13 @@
 
 */
 

	
 
#include "SlackAPI.h"
 
#include "SlackFrontend.h"
 
#include "SlackUser.h"
 
#include "SlackRTM.h"
 
#include "SlackIdManager.h"
 

	
 
#include "transport/Transport.h"
 
#include "transport/HTTPRequest.h"
 
#include "transport/Util.h"
 

	
 
#include <boost/foreach.hpp>
 
@@ -67,15 +68,16 @@ DEFINE_LOGGER(logger, "SlackAPI");
 
#define STORE_STRING_OPTIONAL(FROM, NAME) rapidjson::Value &NAME##_tmp = FROM[#NAME]; \
 
	std::string NAME; \
 
	if (NAME##_tmp.IsString()) {  \
 
		 NAME = NAME##_tmp.GetString(); \
 
	}
 

	
 
SlackAPI::SlackAPI(Component *component, const std::string &token) : HTTPRequestQueue(component) {
 
SlackAPI::SlackAPI(Component *component, SlackIdManager *idManager, const std::string &token) : HTTPRequestQueue(component) {
 
	m_component = component;
 
	m_token = token;
 
	m_idManager = idManager;
 
}
 

	
 
SlackAPI::~SlackAPI() {
 
}
 

	
 
void SlackAPI::handleSendMessage(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data) {
 
@@ -350,38 +352,49 @@ std::string SlackAPI::SlackObjectToPlainText(const std::string &object, bool isC
 
		}
 
	}
 

	
 
	return ret;
 
}
 

	
 
void SlackAPI::handleSlackChannelInvite(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data, const std::string &channel, const std::string &user, CreateChannelCallback callback) {
 
void SlackAPI::handleSlackChannelInvite(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data, const std::string &channel, const std::string &userId, CreateChannelCallback callback) {
 
	callback(channel);
 
}
 

	
 
void SlackAPI::handleSlackChannelCreate(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data, const std::string &channel, const std::string &user, CreateChannelCallback callback) {
 
void SlackAPI::handleSlackChannelCreate(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data, const std::string &channel, const std::string &userId, CreateChannelCallback callback) {
 
	std::string channelId = getChannelId(req, ok, resp, data);
 
	if (channelId.empty()) {
 
		LOG4CXX_INFO(logger, "Error creating channel " << channel << ".");
 
		return;
 
	}
 

	
 
	channelsInvite(channelId, user, boost::bind(&SlackAPI::handleSlackChannelInvite, this, _1, _2, _3, _4, channelId, user, callback));
 
	channelsInvite(channelId, userId, boost::bind(&SlackAPI::handleSlackChannelInvite, this, _1, _2, _3, _4, channelId, userId, callback));
 
}
 

	
 
void SlackAPI::handleSlackChannelList(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data, const std::string &channel, const std::string &user, CreateChannelCallback callback) {
 
	std::map<std::string, SlackChannelInfo> channels;
 
void SlackAPI::handleSlackChannelList(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data, const std::string &channel, const std::string &userId, CreateChannelCallback callback) {
 
	std::map<std::string, SlackChannelInfo> &channels = m_idManager->getChannels();
 
	SlackAPI::getSlackChannelInfo(req, ok, resp, data, channels);
 

	
 
	if (channels.find(channel) != channels.end()) {
 
		channelsInvite(channel, user, boost::bind(&SlackAPI::handleSlackChannelInvite, this, _1, _2, _3, _4, channels[channel].id, user, callback));
 
		channelsInvite(channel, userId, boost::bind(&SlackAPI::handleSlackChannelInvite, this, _1, _2, _3, _4, channels[channel].id, userId, callback));
 
	}
 
	else {
 
		channelsCreate(channel, boost::bind(&SlackAPI::handleSlackChannelCreate, this, _1, _2, _3, _4, channel, user, callback));
 
		channelsCreate(channel, boost::bind(&SlackAPI::handleSlackChannelCreate, this, _1, _2, _3, _4, channel, userId, callback));
 
	}
 
}
 

	
 
void SlackAPI::createChannel(const std::string &channel, const std::string &user, CreateChannelCallback callback) {
 
	channelsList(boost::bind(&SlackAPI::handleSlackChannelList, this, _1, _2, _3, _4, channel, user, callback));
 
void SlackAPI::createChannel(const std::string &channel, const std::string &userId, CreateChannelCallback callback) {
 
	std::string channelId = m_idManager->getId(channel);
 
	if (channelId != channel) {
 
		if (m_idManager->hasMember(channelId, userId)) {
 
			callback(channelId);
 
		}
 
		else {
 
			channelsInvite(channel, userId, boost::bind(&SlackAPI::handleSlackChannelInvite, this, _1, _2, _3, _4, channelId, userId, callback));
 
		}
 
	}
 
	else {
 
		channelsList(boost::bind(&SlackAPI::handleSlackChannelList, this, _1, _2, _3, _4, channel, userId, callback));
 
	}
 
}
 

	
 

	
 
}
spectrum/src/frontends/slack/SlackAPI.h
Show inline comments
 
@@ -32,12 +32,13 @@
 

	
 
namespace Transport {
 

	
 
class Component;
 
class StorageBackend;
 
class HTTPRequest;
 
class SlackIdManager;
 

	
 
class SlackChannelInfo {
 
	public:
 
		SlackChannelInfo() {}
 
		virtual ~SlackChannelInfo() {}
 

	
 
@@ -65,13 +66,13 @@ class SlackUserInfo {
 
		bool isPrimaryOwner;
 
};
 

	
 

	
 
class SlackAPI : public HTTPRequestQueue {
 
	public:
 
		SlackAPI(Component *component, const std::string &token);
 
		SlackAPI(Component *component, SlackIdManager *idManager, const std::string &token);
 

	
 
		virtual ~SlackAPI();
 

	
 
		void usersList(HTTPRequest::Callback callback);
 
		std::string getOwnerId(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data);
 

	
 
@@ -101,10 +102,11 @@ class SlackAPI : public HTTPRequestQueue {
 
		void handleSlackChannelCreate(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data, const std::string &channel, const std::string &user, CreateChannelCallback callback);
 
		void handleSlackChannelList(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data, const std::string &channel, const std::string &user, CreateChannelCallback callback);
 
		void handleSlackChannelInvite(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data, const std::string &channel, const std::string &user, CreateChannelCallback callback);
 

	
 
	private:
 
		Component *m_component;
 
		SlackIdManager *m_idManager;
 
		std::string m_token;
 
};
 

	
 
}
spectrum/src/frontends/slack/SlackIdManager.cpp
Show inline comments
 
new file 100644
 
/**
 
 * XMPP - libpurple transport
 
 *
 
 * Copyright (C) 2009, Jan Kaluza <hanzz@soc.pidgin.im>
 
 *
 
 * This program is free software; you can redistribute it and/or modify
 
 * it under the terms of the GNU General Public License as published by
 
 * the Free Software Foundation; either version 2 of the License, or
 
 * (at your option) any later version.
 
 *
 
 * This program 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 General Public License for more details.
 
 *
 
 * You should have received a copy of the GNU General Public License
 
 * along with this program; if not, write to the Free Software
 
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
 
 */
 

	
 
#include "SlackIdManager.h"
 
#include "SlackFrontend.h"
 
#include "SlackUser.h"
 

	
 
#include "transport/Transport.h"
 
#include "transport/HTTPRequest.h"
 
#include "transport/Util.h"
 
#include "transport/WebSocketClient.h"
 

	
 
#include <boost/foreach.hpp>
 
#include <boost/make_shared.hpp>
 
#include <boost/lexical_cast.hpp>
 
#include <boost/algorithm/string.hpp>
 
#include <map>
 
#include <iterator>
 

	
 
namespace Transport {
 

	
 
DEFINE_LOGGER(logger, "SlackIdManager");
 

	
 
SlackIdManager::SlackIdManager() {
 

	
 
}
 

	
 
SlackIdManager::~SlackIdManager() {
 

	
 
}
 

	
 
const std::string &SlackIdManager::getName(const std::string &id) {
 
	if (m_users.find(id) == m_users.end()) {
 
		return id;
 
	}
 

	
 
	return m_users[id].name;
 
}
 

	
 
const std::string &SlackIdManager::getId(const std::string &name) {
 
	for (std::map<std::string, SlackChannelInfo>::const_iterator it = m_channels.begin(); it != m_channels.end(); ++it) {
 
		if (it->second.name == name) {
 
			return it->second.id;
 
		}
 
	}
 

	
 
	return name;
 
}
 

	
 
bool SlackIdManager::hasMember(const std::string &channelId, const std::string &userId) {
 
	if (m_channels.find(channelId) == m_channels.end()) {
 
		return false;
 
	}
 

	
 
	SlackChannelInfo &channel = m_channels[channelId];
 
	return std::find(channel.members.begin(), channel.members.end(), userId) != channel.members.end();
 
}
 

	
 

	
 
}
spectrum/src/frontends/slack/SlackIdManager.h
Show inline comments
 
new file 100644
 
/**
 
 * Spectrum 2 Slack Frontend
 
 *
 
 * Copyright (C) 2015, Jan Kaluza <hanzz.k@gmail.com>
 
 *
 
 * This program is free software; you can redistribute it and/or modify
 
 * it under the terms of the GNU General Public License as published by
 
 * the Free Software Foundation; either version 2 of the License, or
 
 * (at your option) any later version.
 
 *
 
 * This program 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 General Public License for more details.
 
 *
 
 * You should have received a copy of the GNU General Public License
 
 * along with this program; if not, write to the Free Software
 
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
 
 */
 

	
 
#pragma once
 

	
 
#include "SlackAPI.h"
 

	
 
#include "transport/StorageBackend.h"
 
#include "rapidjson/document.h"
 

	
 
#include <Swiften/Network/TLSConnectionFactory.h>
 
#include <Swiften/Network/HostAddressPort.h>
 
#include <Swiften/TLS/PlatformTLSFactories.h>
 
#include <Swiften/Network/DomainNameResolveError.h>
 
#include <Swiften/Network/DomainNameAddressQuery.h>
 
#include <Swiften/Network/DomainNameResolver.h>
 
#include <Swiften/Network/HostAddress.h>
 
#include <Swiften/Network/Connection.h>
 
#include <Swiften/Base/SafeByteArray.h>
 
#include "Swiften/Network/Timer.h"
 
#include "Swiften/Version.h"
 

	
 
#define HAVE_SWIFTEN_3  (SWIFTEN_VERSION >= 0x030000)
 

	
 
#if HAVE_SWIFTEN_3
 
#include <Swiften/TLS/TLSOptions.h>
 
#endif
 

	
 
#include <string>
 
#include <algorithm>
 
#include <map>
 

	
 
#include <boost/signal.hpp>
 

	
 
namespace Transport {
 

	
 
class SlackIdManager {
 
	public:
 
		SlackIdManager();
 

	
 
		virtual ~SlackIdManager();
 

	
 
		std::map<std::string, SlackUserInfo> &getUsers() {
 
			return m_users;
 
		}
 

	
 
		std::map<std::string, SlackChannelInfo> &getChannels() {
 
			return m_channels;
 
		}
 

	
 
		std::map<std::string, SlackImInfo> &getIMs() {
 
			return m_ims;
 
		}
 

	
 
		const std::string &getName(const std::string &id);
 
		const std::string &getId(const std::string &name);
 

	
 
		bool hasMember(const std::string &channelId, const std::string &userId);
 

	
 
		const std::string &getSelfName() {
 
			return m_selfName;
 
		}
 

	
 
		const std::string &getSelfId() {
 
			return m_selfId;
 
		}
 

	
 
		void setSelfName(const std::string &name) {
 
			m_selfName = name;
 
		}
 

	
 
		void setSelfId(const std::string &id) {
 
			m_selfId = id;
 
		}
 

	
 
	private:
 
		std::map<std::string, SlackChannelInfo> m_channels;
 
		std::map<std::string, SlackImInfo> m_ims;
 
		std::map<std::string, SlackUserInfo> m_users;
 
		std::string m_selfName;
 
		std::string m_selfId;
 
};
 

	
 
}
spectrum/src/frontends/slack/SlackRTM.cpp
Show inline comments
 
@@ -18,12 +18,13 @@
 
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
 
 */
 

	
 
#include "SlackRTM.h"
 
#include "SlackFrontend.h"
 
#include "SlackUser.h"
 
#include "SlackIdManager.h"
 

	
 
#include "transport/Transport.h"
 
#include "transport/HTTPRequest.h"
 
#include "transport/Util.h"
 
#include "transport/WebSocketClient.h"
 

	
 
@@ -35,28 +36,29 @@
 
#include <iterator>
 

	
 
namespace Transport {
 

	
 
DEFINE_LOGGER(logger, "SlackRTM");
 

	
 
SlackRTM::SlackRTM(Component *component, StorageBackend *storageBackend, UserInfo uinfo) : m_uinfo(uinfo) {
 
SlackRTM::SlackRTM(Component *component, StorageBackend *storageBackend, SlackIdManager *idManager, UserInfo uinfo) : m_uinfo(uinfo) {
 
	m_component = component;
 
	m_storageBackend = storageBackend;
 
	m_counter = 0;
 
	m_started = false;
 
	m_idManager = idManager;
 
	m_client = new WebSocketClient(component);
 
	m_client->onPayloadReceived.connect(boost::bind(&SlackRTM::handlePayloadReceived, this, _1));
 
	m_client->onWebSocketConnected.connect(boost::bind(&SlackRTM::handleWebSocketConnected, this));
 

	
 
	m_pingTimer = m_component->getNetworkFactories()->getTimerFactory()->createTimer(20000);
 
	m_pingTimer->onTick.connect(boost::bind(&SlackRTM::sendPing, this));
 

	
 
	int type = (int) TYPE_STRING;
 
	m_storageBackend->getUserSetting(m_uinfo.id, "bot_token", type, m_token);
 

	
 
	m_api = new SlackAPI(component, m_token);
 
	m_api = new SlackAPI(component, m_idManager, m_token);
 

	
 
	std::string url = "https://slack.com/api/rtm.start?";
 
	url += "token=" + Util::urlencode(m_token);
 

	
 
	HTTPRequest *req = new HTTPRequest(THREAD_POOL(m_component), HTTPRequest::Get, url, boost::bind(&SlackRTM::handleRTMStart, this, _1, _2, _3, _4));
 
	req->execute();
 
@@ -143,20 +145,12 @@ void SlackRTM::sendPing() {
 
	m_counter++;
 
	std::string msg = "{\"id\": " + boost::lexical_cast<std::string>(m_counter) + ", \"type\": \"ping\"}";
 
	m_client->write(msg);
 
	m_pingTimer->start();
 
}
 

	
 
const std::string &SlackRTM::getUserName(const std::string &id) {
 
	if (m_users.find(id) == m_users.end()) {
 
		return id;
 
	}
 

	
 
	return m_users[id].name;
 
}
 

	
 
void SlackRTM::handleRTMStart(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data) {
 
	if (!ok) {
 
		LOG4CXX_ERROR(logger, req->getError());
 
		LOG4CXX_ERROR(logger, data);
 
		return;
 
	}
 
@@ -179,26 +173,26 @@ void SlackRTM::handleRTMStart(HTTPRequest *req, bool ok, rapidjson::Document &re
 
	if (!selfName.IsString()) {
 
		LOG4CXX_ERROR(logger, "No 'name' string in the reply.");
 
		LOG4CXX_ERROR(logger, data);
 
		return;
 
	}
 

	
 
	m_selfName = selfName.GetString();
 
	m_idManager->setSelfName(selfName.GetString());
 

	
 
	rapidjson::Value &selfId = self["id"];
 
	if (!selfId.IsString()) {
 
		LOG4CXX_ERROR(logger, "No 'id' string in the reply.");
 
		LOG4CXX_ERROR(logger, data);
 
		return;
 
	}
 

	
 
	m_selfId = selfId.GetString();
 
	m_idManager->setSelfId(selfId.GetString());
 

	
 
	SlackAPI::getSlackChannelInfo(req, ok, resp, data, m_channels);
 
	SlackAPI::getSlackImInfo(req, ok, resp, data, m_ims);
 
	SlackAPI::getSlackUserInfo(req, ok, resp, data, m_users);
 
	SlackAPI::getSlackChannelInfo(req, ok, resp, data, m_idManager->getChannels());
 
	SlackAPI::getSlackImInfo(req, ok, resp, data, m_idManager->getIMs());
 
	SlackAPI::getSlackUserInfo(req, ok, resp, data, m_idManager->getUsers());
 

	
 
	std::string u = url.GetString();
 
	LOG4CXX_INFO(logger, "Started RTM, WebSocket URL is " << u);
 
	LOG4CXX_INFO(logger, data);
 

	
 
	m_client->connectServer(u);
spectrum/src/frontends/slack/SlackRTM.h
Show inline comments
 
@@ -53,69 +53,46 @@ namespace Transport {
 

	
 
class Component;
 
class StorageBackend;
 
class HTTPRequest;
 
class WebSocketClient;
 
class SlackAPI;
 
class SlackIdManager;
 

	
 
class SlackRTM {
 
	public:
 
		SlackRTM(Component *component, StorageBackend *storageBackend, UserInfo uinfo);
 
		SlackRTM(Component *component, StorageBackend *storageBackend, SlackIdManager *idManager, UserInfo uinfo);
 

	
 
		virtual ~SlackRTM();
 

	
 
		void sendPing();
 

	
 
		void sendMessage(const std::string &channel, const std::string &message);
 

	
 
		boost::signal<void ()> onRTMStarted;
 

	
 
		std::map<std::string, SlackUserInfo> &getUsers() {
 
			return m_users;
 
		}
 

	
 
		std::map<std::string, SlackChannelInfo> &getChannels() {
 
			return m_channels;
 
		}
 

	
 
		SlackAPI *getAPI() {
 
			return m_api;
 
		}
 

	
 
		boost::signal<void (const std::string &channel, const std::string &user, const std::string &text, const std::string &ts)> onMessageReceived;
 

	
 
		const std::string &getUserName(const std::string &id);
 

	
 
		const std::string &getSelfName() {
 
			return m_selfName;
 
		}
 

	
 
		const std::string &getSelfId() {
 
			return m_selfId;
 
		}
 

	
 
	private:
 
		void handlePayloadReceived(const std::string &payload);
 
		void handleRTMStart(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data);
 
		void handleWebSocketConnected();
 
		void handleWebSocketDisconnected(const boost::optional<Swift::Connection::Error> &error);
 

	
 
	private:
 
		std::map<std::string, SlackChannelInfo> m_channels;
 
		std::map<std::string, SlackImInfo> m_ims;
 
		std::map<std::string, SlackUserInfo> m_users;
 
		std::string m_selfName;
 
		std::string m_selfId;
 

	
 
	private:
 
		Component *m_component;
 
		StorageBackend *m_storageBackend;
 
		UserInfo m_uinfo;
 
		WebSocketClient *m_client;
 
		std::string m_token;
 
		unsigned long m_counter;
 
		Swift::Timer::ref m_pingTimer;
 
		SlackAPI *m_api;
 
		bool m_started;
 
		SlackIdManager *m_idManager;
 
};
 

	
 
}
spectrum/src/frontends/slack/SlackSession.cpp
Show inline comments
 
@@ -20,12 +20,13 @@
 

	
 
#include "SlackSession.h"
 
#include "SlackFrontend.h"
 
#include "SlackUser.h"
 
#include "SlackRTM.h"
 
#include "SlackRosterManager.h"
 
#include "SlackIdManager.h"
 

	
 
#include "transport/Transport.h"
 
#include "transport/HTTPRequest.h"
 
#include "transport/Util.h"
 
#include "transport/Buddy.h"
 
#include "transport/Config.h"
 
@@ -47,28 +48,31 @@ namespace Transport {
 
DEFINE_LOGGER(logger, "SlackSession");
 

	
 
SlackSession::SlackSession(Component *component, StorageBackend *storageBackend, UserInfo uinfo) : m_uinfo(uinfo), m_user(NULL), m_disconnected(false) {
 
	m_component = component;
 
	m_storageBackend = storageBackend;
 

	
 
	m_rtm = new SlackRTM(component, storageBackend, uinfo);
 
	m_idManager = new SlackIdManager();
 

	
 
	m_rtm = new SlackRTM(component, storageBackend, m_idManager, uinfo);
 
	m_rtm->onRTMStarted.connect(boost::bind(&SlackSession::handleRTMStarted, this));
 
	m_rtm->onMessageReceived.connect(boost::bind(&SlackSession::handleMessageReceived, this, _1, _2, _3, _4, false));
 

	
 
	m_onlineBuddiesTimer = m_component->getNetworkFactories()->getTimerFactory()->createTimer(20000);
 
	m_onlineBuddiesTimer->onTick.connect(boost::bind(&SlackSession::sendOnlineBuddies, this));
 

	
 
	int type = (int) TYPE_STRING;
 
	std::string token;
 
	m_storageBackend->getUserSetting(m_uinfo.id, "access_token", type, token);
 
	m_api = new SlackAPI(m_component, token);
 
	m_api = new SlackAPI(m_component, m_idManager, token);
 
}
 

	
 
SlackSession::~SlackSession() {
 
	delete m_rtm;
 
	delete m_api;
 
	delete m_idManager;
 
	m_onlineBuddiesTimer->stop();
 
}
 

	
 
void SlackSession::sendOnlineBuddies() {
 
	if (!m_user) {
 
		return;
 
@@ -181,13 +185,13 @@ void SlackSession::handleJoinRoomCreated(const std::string &channelId, std::vect
 

	
 
	m_onlineBuddiesTimer->start();
 
}
 

	
 
void SlackSession::handleJoinMessage(const std::string &message, std::vector<std::string> &args, bool quiet) {
 
	LOG4CXX_INFO(logger, args[1] << ": Going to join the room, checking the ID of channel " << args[5]);
 
	m_api->createChannel(args[5], m_rtm->getSelfId(), boost::bind(&SlackSession::handleJoinRoomCreated, this, _1, args));
 
	m_api->createChannel(args[5], m_idManager->getSelfId(), boost::bind(&SlackSession::handleJoinRoomCreated, this, _1, args));
 
}
 

	
 
void SlackSession::handleSlackChannelCreated(const std::string &channelId) {
 
	m_slackChannel = channelId;
 

	
 
	Swift::Presence::ref presence = Swift::Presence::create();
 
@@ -195,43 +199,20 @@ void SlackSession::handleSlackChannelCreated(const std::string &channelId) {
 
	presence->setTo(m_component->getJID());
 
	presence->setType(Swift::Presence::Available);
 
	presence->addPayload(boost::shared_ptr<Swift::Payload>(new Swift::MUCPayload()));
 
	m_component->getFrontend()->onPresenceReceived(presence);
 
}
 

	
 
void SlackSession::handleLeaveMessage(const std::string &message, std::vector<std::string> &args, bool quiet) {
 
	// .spectrum2 leave.room channel
 
	std::string slackChannel = SlackAPI::SlackObjectToPlainText(args[2], true);
 
	std::string to = m_channel2jid[slackChannel];
 
void SlackSession::leaveRoom(const std::string &channel) {
 
	std::string channelId = m_idManager->getId(channel);
 
	std::string to = m_channel2jid[channel];
 
	if (to.empty()) {
 
		m_rtm->sendMessage(m_ownerChannel, "Spectrum 2 is not configured to transport this Slack channel.");
 
		return;
 
	}
 

	
 
	std::string rooms = "";
 
	int type = (int) TYPE_STRING;
 
	m_storageBackend->getUserSetting(m_uinfo.id, "rooms", type, rooms);
 

	
 
	std::vector<std::string> commands;
 
	boost::split(commands, rooms, boost::is_any_of("\n"));
 
	rooms = "";
 

	
 
	BOOST_FOREACH(const std::string &command, commands) {
 
		if (command.size() > 5) {
 
			std::vector<std::string> args2;
 
			boost::split(args2, command, boost::is_any_of(" "));
 
			if (args2.size() == 6) {
 
				if (slackChannel != SlackAPI::SlackObjectToPlainText(args2[5], true)) {
 
					rooms += command + "\n";
 
				}
 
			}
 
		}
 
	}
 

	
 
	m_storageBackend->updateUserSetting(m_uinfo.id, "rooms", rooms);
 

	
 
	Swift::Presence::ref presence = Swift::Presence::create();
 
	presence->setFrom(Swift::JID("", m_uinfo.jid, "default"));
 
	presence->setTo(Swift::JID(to + "/" + m_uinfo.uin));
 
	presence->setType(Swift::Presence::Unavailable);
 
	presence->addPayload(boost::shared_ptr<Swift::Payload>(new Swift::MUCPayload()));
 
	m_component->getFrontend()->onPresenceReceived(presence);
 
@@ -261,22 +242,22 @@ void SlackSession::handleRegisterMessage(const std::string &message, std::vector
 
	}
 
}
 

	
 
void SlackSession::handleMessageReceived(const std::string &channel, const std::string &user, const std::string &message, const std::string &ts, bool quiet) {
 
	if (m_ownerChannel != channel) {
 
		std::string to = m_channel2jid[channel];
 
		if (m_rtm->getUserName(user) == m_rtm->getSelfName()) {
 
		if (m_idManager->getName(user) == m_idManager->getSelfName()) {
 
			return;
 
		}
 

	
 
		if (!to.empty()) {
 
			boost::shared_ptr<Swift::Message> msg(new Swift::Message());
 
			msg->setType(Swift::Message::Groupchat);
 
			msg->setTo(to);
 
			msg->setFrom(Swift::JID("", m_uinfo.jid, "default"));
 
			msg->setBody("<" + m_rtm->getUserName(user) + "> " + message);
 
			msg->setBody("<" + m_idManager->getName(user) + "> " + message);
 
			m_component->getFrontend()->onMessageReceived(msg);
 
		}
 
		else {
 
			// When changing the purpose, we do not want to spam to room with the info,
 
			// so remove the purpose message.
 
// 			if (message.find("set the channel purpose") != std::string::npos) {
 
@@ -306,13 +287,13 @@ void SlackSession::handleMessageReceived(const std::string &channel, const std::
 
					continue;
 
				}
 

	
 
				boost::shared_ptr<Swift::Message> msg(new Swift::Message());
 
				msg->setTo(b->getJID());
 
				msg->setFrom(Swift::JID("", m_uinfo.jid, "default"));
 
				msg->setBody("<" + m_rtm->getUserName(user) + "> " + message);
 
				msg->setBody("<" + m_idManager->getName(user) + "> " + message);
 
				m_component->getFrontend()->onMessageReceived(msg);
 
			}
 
		}
 
		return;
 
	}
 

	
 
@@ -325,13 +306,13 @@ void SlackSession::handleMessageReceived(const std::string &channel, const std::
 
	}
 

	
 
	if (args[1] == "join.room" && args.size() == 6) {
 
		handleJoinMessage(message, args, quiet);
 
	}
 
	else if (args[1] == "leave.room" && args.size() == 3) {
 
		handleLeaveMessage(message, args, quiet);
 
// 		handleLeaveMessage(message, args, quiet);
 
	}
 
	else if (args[1] == "register" && args.size() == 5) {
 
		handleRegisterMessage(message, args, quiet);
 
	}
 
	else if (args[1] == "set_main_channel" && args.size() == 3) {
 
		std::string slackChannel = SlackAPI::SlackObjectToPlainText(args[2], true);
 
@@ -432,13 +413,13 @@ void SlackSession::handleImOpen(HTTPRequest *req, bool ok, rapidjson::Document &
 
			msg += "To get full list of available commands, executa `.spectrum2 help`\\n";
 
			m_rtm->sendMessage(m_ownerChannel, msg);
 
		}
 
		else {
 
			m_storageBackend->getUserSetting(m_uinfo.id, "slack_channel", type, m_slackChannel);
 
			if (!m_slackChannel.empty()) {
 
				m_api->createChannel(m_slackChannel, m_rtm->getSelfId(), boost::bind(&SlackSession::handleSlackChannelCreated, this, _1));
 
				m_api->createChannel(m_slackChannel, m_idManager->getSelfId(), boost::bind(&SlackSession::handleSlackChannelCreated, this, _1));
 
			}
 
			else {
 
				std::string msg;
 
				msg =  "Hi, it seems you have enabled Spectrum 2 transport for your Team. As a Team owner, you should now configure it:\\n";
 
				msg += "1. At first, create new channel in which you want this Spectrum 2 transport to send the messages, or choose the existing one.\\n";
 
				msg += "2. Invite this Spectrum 2 bot into this channel.\\n";
 
@@ -462,13 +443,13 @@ void SlackSession::handleImOpen(HTTPRequest *req, bool ok, rapidjson::Document &
 
			}
 
		}
 
	}
 
}
 

	
 
void SlackSession::handleRTMStarted() {
 
	std::map<std::string, SlackUserInfo> &users = m_rtm->getUsers();
 
	std::map<std::string, SlackUserInfo> &users = m_idManager->getUsers();
 
	for (std::map<std::string, SlackUserInfo>::iterator it = users.begin(); it != users.end(); it++) {
 
		SlackUserInfo &info = it->second;
 
		if (info.isPrimaryOwner) {
 
			m_ownerId = it->first;
 
			break;
 
		}
spectrum/src/frontends/slack/SlackSession.h
Show inline comments
 
@@ -37,12 +37,13 @@ namespace Transport {
 
class Component;
 
class StorageBackend;
 
class HTTPRequest;
 
class SlackRTM;
 
class SlackAPI;
 
class User;
 
class SlackIdManager;
 

	
 
class SlackSession {
 
	public:
 
		SlackSession(Component *component, StorageBackend *storageBackend, UserInfo uinfo);
 

	
 
		virtual ~SlackSession();
 
@@ -58,13 +59,13 @@ class SlackSession {
 
		void setUser(User *user);
 

	
 
		void handleDisconnected();
 
		void handleConnected();
 

	
 
		void handleJoinMessage(const std::string &message, std::vector<std::string> &args, bool quiet = false);
 
		void handleLeaveMessage(const std::string &message, std::vector<std::string> &args, bool quiet = false);
 
		void leaveRoom(const std::string &channel);
 
		void handleRegisterMessage(const std::string &message, std::vector<std::string> &args, bool quiet = false);
 

	
 
	private:
 
		void handleRTMStarted();
 
		void handleMessageReceived(const std::string &channel, const std::string &user, const std::string &message, const std::string &ts, bool quiet);
 
		void handleImOpen(HTTPRequest *req, bool ok, rapidjson::Document &resp, const std::string &data);
 
@@ -87,9 +88,10 @@ class SlackSession {
 
		User *m_user;
 
		Swift::Timer::ref m_onlineBuddiesTimer;
 
		std::map<std::string, std::string> m_onlineBuddies;
 
		bool m_disconnected;
 
		std::string m_ownerId;
 
		SlackAPI *m_api;
 
		SlackIdManager *m_idManager;
 
};
 

	
 
}
spectrum/src/frontends/slack/SlackUserManager.cpp
Show inline comments
 
@@ -182,14 +182,13 @@ bool SlackUserManager::handleAdminMessage(Swift::Message::ref message) {
 
			}
 

	
 
			m_storageBackend->updateUserSetting(uinfo.id, "rooms", rooms);
 

	
 
			SlackUser *user = static_cast<SlackUser *>(getUser(args[1]));
 
			if (user) {
 
				// TODO
 
// 				user->getSession()->handleJoinMessage("", args, true);
 
				user->getSession()->leaveRoom(args[2]);
 
			}
 
			message->setBody("Left the room");
 
			return true;
 
		}
 
	}
 
	return false;
spectrum_manager/src/APIServer.cpp
Show inline comments
 
@@ -303,12 +303,39 @@ void APIServer::serve_instances_join_room(Server *server, Server::session *sessi
 
	}
 
	else {
 
		send_ack(conn, false, response);
 
	}
 
}
 

	
 
void APIServer::serve_instances_leave_room(Server *server, Server::session *session, struct mg_connection *conn, struct http_message *hm) {
 
	std::string uri(hm->uri.p, hm->uri.len);
 
	std::string instance = uri.substr(uri.rfind("/") + 1);
 

	
 
	UserInfo info;
 
	m_storage->getUser(session->user, info);
 

	
 
	std::string username = "";
 
	int type = (int) TYPE_STRING;
 
	m_storage->getUserSetting(info.id, instance, type, username);
 

	
 
	if (username.empty()) {
 
		send_ack(conn, true, "You are not registered to this Spectrum 2 instance.");
 
		return;
 
	}
 

	
 
	std::string frontend_room = get_http_var(hm, "frontend_room");
 
	std::string response = server->send_command(instance, "leave_room " + username + " " + frontend_room);
 

	
 
	if (response.find("Left the room") == std::string::npos) {
 
		send_ack(conn, true, response);
 
	}
 
	else {
 
		send_ack(conn, false, response);
 
	}
 
}
 

	
 
void APIServer::serve_instances_join_room_form(Server *server, Server::session *session, struct mg_connection *conn, struct http_message *hm) {
 
	// So far we support just Slack here. For XMPP, it is up to user to initiate the join room request.
 
	Document json;
 
	json.SetObject();
 
	json.AddMember("error", 0, json.GetAllocator());
 
	json.AddMember("name_label", "Nickname in 3rd-party room", json.GetAllocator());
 
@@ -433,12 +460,15 @@ void APIServer::handleRequest(Server *server, Server::session *sess, struct mg_c
 
	else if (has_prefix(&hm->uri, "/api/v1/instances/join_room/")) {
 
		serve_instances_join_room(server, sess, conn, hm);
 
	}
 
	else if (has_prefix(&hm->uri, "/api/v1/instances/list_rooms/")) {
 
		serve_instances_list_rooms(server, sess, conn, hm);
 
	}
 
	else if (has_prefix(&hm->uri, "/api/v1/instances/leave_room/")) {
 
		serve_instances_leave_room(server, sess, conn, hm);
 
	}
 
	else if (has_prefix(&hm->uri, "/api/v1/users/remove/")) {
 
		serve_users_remove(server, sess, conn, hm);
 
	}
 
	else if (mg_vcmp(&hm->uri, "/api/v1/users/add") == 0) {
 
		serve_users_add(server, sess, conn, hm);
 
	}
spectrum_manager/src/APIServer.h
Show inline comments
 
@@ -58,12 +58,13 @@ class APIServer {
 
		void serve_instances_unregister(Server *server, Server::session *sess, struct mg_connection *conn, struct http_message *hm);
 
		void serve_instances_register(Server *server, Server::session *sess, struct mg_connection *conn, struct http_message *hm);
 
		void serve_instances_register_form(Server *server, Server::session *sess, struct mg_connection *conn, struct http_message *hm);
 
		void serve_instances_list_rooms(Server *server, Server::session *sess, struct mg_connection *conn, struct http_message *hm);
 
		void serve_instances_join_room(Server *server, Server::session *sess, struct mg_connection *conn, struct http_message *hm);
 
		void serve_instances_join_room_form(Server *server, Server::session *sess, struct mg_connection *conn, struct http_message *hm);
 
		void serve_instances_leave_room(Server *server, Server::session *sess, struct mg_connection *conn, struct http_message *hm);
 
		void serve_users(Server *server, Server::session *sess, struct mg_connection *conn, struct http_message *hm);
 
		void serve_users_add(Server *server, Server::session *sess, struct mg_connection *conn, struct http_message *hm);
 
		void serve_users_remove(Server *server, Server::session *sess, struct mg_connection *conn, struct http_message *hm);
 
		void send_json(struct mg_connection *conn, const Document &d);
 
		void send_ack(struct mg_connection *conn, bool error, const std::string &message);
 

	
0 comments (0 inline, 0 general)