Libtransport, Web Interface: Rewrite the AdminInterface to support pluggable commands - use this API in Web Interface instead of coding one page per command.
This commit is contained in:
parent
2c338a2447
commit
84ea5f3249
30 changed files with 2238 additions and 7966 deletions
|
@ -32,6 +32,7 @@ class StorageBackend;
|
|||
class UserManager;
|
||||
class NetworkPluginServer;
|
||||
class UserRegistration;
|
||||
class AdminInterfaceCommand;
|
||||
|
||||
class AdminInterface {
|
||||
public:
|
||||
|
@ -41,15 +42,18 @@ class AdminInterface {
|
|||
|
||||
void handleQuery(Swift::Message::ref message);
|
||||
|
||||
private:
|
||||
void addCommand(AdminInterfaceCommand *command);
|
||||
|
||||
void handleMessageReceived(Swift::Message::ref message);
|
||||
|
||||
private:
|
||||
|
||||
Component *m_component;
|
||||
StorageBackend *m_storageBackend;
|
||||
UserManager *m_userManager;
|
||||
NetworkPluginServer *m_server;
|
||||
UserRegistration *m_userRegistration;
|
||||
time_t m_start;
|
||||
std::map<std::string, AdminInterfaceCommand *> m_commands;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
129
include/transport/AdminInterfaceCommand.h
Normal file
129
include/transport/AdminInterfaceCommand.h
Normal file
|
@ -0,0 +1,129 @@
|
|||
/**
|
||||
* libtransport -- C++ library for easy XMPP Transports development
|
||||
*
|
||||
* Copyright (C) 2016, 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 <string>
|
||||
#include <map>
|
||||
|
||||
#include "Swiften/Elements/Message.h"
|
||||
#include "transport/StorageBackend.h"
|
||||
|
||||
namespace Transport {
|
||||
|
||||
class User;
|
||||
|
||||
class AdminInterfaceCommand {
|
||||
public:
|
||||
typedef enum {
|
||||
GlobalContext,
|
||||
UserContext
|
||||
} Context;
|
||||
|
||||
typedef enum {
|
||||
None = 0,
|
||||
Get = 1,
|
||||
Set = 2,
|
||||
Execute = 4
|
||||
} Actions;
|
||||
|
||||
typedef enum {
|
||||
AdminMode,
|
||||
UserMode
|
||||
} AccessMode;
|
||||
|
||||
typedef enum {
|
||||
General,
|
||||
Users,
|
||||
Messages,
|
||||
Frontend,
|
||||
Backends,
|
||||
Memory
|
||||
} Category;
|
||||
|
||||
class Arg {
|
||||
public:
|
||||
Arg(const std::string &_name, const std::string &_label, const std::string &_example) :
|
||||
name(_name), label(_label), example(_example) {}
|
||||
~Arg() {}
|
||||
|
||||
std::string name;
|
||||
std::string label;
|
||||
std::string example;
|
||||
};
|
||||
|
||||
AdminInterfaceCommand(const std::string &name, Category category, Context context, AccessMode accessMode, Actions actions);
|
||||
|
||||
virtual ~AdminInterfaceCommand() { }
|
||||
|
||||
void setDescription(const std::string &desc) {
|
||||
m_desc = desc;
|
||||
}
|
||||
|
||||
const std::string &getDescription() {
|
||||
return m_desc;
|
||||
}
|
||||
|
||||
const std::string &getName() {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
Actions getActions() {
|
||||
return m_actions;
|
||||
}
|
||||
|
||||
Category getCategory() {
|
||||
return m_category;
|
||||
}
|
||||
|
||||
const std::string getCategoryName(Category category);
|
||||
|
||||
Context getContext() {
|
||||
return m_context;
|
||||
}
|
||||
|
||||
AccessMode getAccessMode() {
|
||||
return m_accessMode;
|
||||
}
|
||||
|
||||
void addArg(const std::string &name, const std::string &label, const std::string &example = "") {
|
||||
Arg arg(name, label, example);
|
||||
m_args.push_back(arg);
|
||||
}
|
||||
|
||||
const std::list<Arg> &getArgs() {
|
||||
return m_args;
|
||||
}
|
||||
|
||||
virtual std::string handleSetRequest(UserInfo &uinfo, User *user, std::vector<std::string> &args);
|
||||
virtual std::string handleGetRequest(UserInfo &uinfo, User *user, std::vector<std::string> &args);
|
||||
virtual std::string handleExecuteRequest(UserInfo &uinfo, User *user, std::vector<std::string> &args);
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
Category m_category;
|
||||
Context m_context;
|
||||
AccessMode m_accessMode;
|
||||
Actions m_actions;
|
||||
std::string m_desc;
|
||||
std::list<Arg> m_args;
|
||||
};
|
||||
|
||||
}
|
|
@ -94,7 +94,6 @@ class Frontend {
|
|||
virtual std::string setOAuth2Code(const std::string &code, const std::string &state) { return "OAuth2 code is not needed for this frontend."; }
|
||||
virtual std::string getOAuth2URL(const std::vector<std::string> &args) { return ""; }
|
||||
virtual std::string getRegistrationFields() { return "Jabber ID\n3rd-party network username\n3rd-party network password"; }
|
||||
virtual bool handleAdminMessage(Swift::Message::ref /*message*/) { return false; }
|
||||
|
||||
virtual bool isRawXMLEnabled() { return false; }
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ namespace Transport {
|
|||
class Factory;
|
||||
class Config;
|
||||
class UserManager;
|
||||
class AdminInterface;
|
||||
|
||||
class Component {
|
||||
public:
|
||||
|
@ -108,6 +109,8 @@ namespace Transport {
|
|||
boost::signal<void (Swift::Presence::ref presence)> onUserPresenceReceived;
|
||||
|
||||
boost::signal<void (boost::shared_ptr<Swift::IQ>)> onRawIQReceived;
|
||||
|
||||
boost::signal<void ()> onAdminInterfaceSet;
|
||||
|
||||
void handlePresence(Swift::Presence::ref presence);
|
||||
void handleConnected();
|
||||
|
@ -121,6 +124,15 @@ namespace Transport {
|
|||
|
||||
PresenceOracle *getPresenceOracle();
|
||||
|
||||
void setAdminInterface(AdminInterface *adminInterface) {
|
||||
m_adminInterface = adminInterface;
|
||||
onAdminInterfaceSet();
|
||||
}
|
||||
|
||||
AdminInterface *getAdminInterface() {
|
||||
return m_adminInterface;
|
||||
}
|
||||
|
||||
private:
|
||||
void handleDiscoInfoResponse(boost::shared_ptr<Swift::DiscoInfo> info, Swift::ErrorPayload::ref error, const Swift::JID& jid);
|
||||
void handleCapsChanged(const Swift::JID& jid);
|
||||
|
@ -139,6 +151,7 @@ namespace Transport {
|
|||
Factory *m_factory;
|
||||
Swift::EventLoop *m_loop;
|
||||
Frontend *m_frontend;
|
||||
AdminInterface *m_adminInterface;
|
||||
|
||||
friend class User;
|
||||
friend class UserRegistration;
|
||||
|
|
File diff suppressed because it is too large
Load diff
120
libtransport/AdminInterfaceCommand.cpp
Normal file
120
libtransport/AdminInterfaceCommand.cpp
Normal file
|
@ -0,0 +1,120 @@
|
|||
/**
|
||||
* libtransport -- C++ library for easy XMPP Transports development
|
||||
*
|
||||
* Copyright (C) 2011, 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
|
||||
*/
|
||||
|
||||
#include "transport/AdminInterfaceCommand.h"
|
||||
#include "transport/User.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#include <Swiften/Version.h>
|
||||
#define HAVE_SWIFTEN_3 (SWIFTEN_VERSION >= 0x030000)
|
||||
|
||||
namespace Transport {
|
||||
|
||||
AdminInterfaceCommand::AdminInterfaceCommand(const std::string &name, Category category, Context context, AccessMode accessMode, Actions actions) {
|
||||
m_name = name;
|
||||
m_category = category;
|
||||
m_context = context;
|
||||
m_accessMode = accessMode;
|
||||
m_actions = actions;
|
||||
}
|
||||
|
||||
const std::string AdminInterfaceCommand::getCategoryName(Category category) {
|
||||
switch (category) {
|
||||
case AdminInterfaceCommand::General:
|
||||
return "General";
|
||||
case AdminInterfaceCommand::Users:
|
||||
return "Users";
|
||||
case AdminInterfaceCommand::Messages:
|
||||
return "Messages";
|
||||
case AdminInterfaceCommand::Frontend:
|
||||
return "Frontend";
|
||||
case AdminInterfaceCommand::Backends:
|
||||
return "Backends";
|
||||
case AdminInterfaceCommand::Memory:
|
||||
return "Memory";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
std::string AdminInterfaceCommand::handleSetRequest(UserInfo &uinfo, User *user, std::vector<std::string> &args) {
|
||||
if ((m_actions & Set) == 0) {
|
||||
return "Error: This variable cannot be set.";
|
||||
}
|
||||
|
||||
if (user && (m_accessMode & AdminMode) != 0) {
|
||||
return "Error: You do not have rights to set this variable.";
|
||||
}
|
||||
|
||||
if ((!user && uinfo.id == -1) && (m_context & UserContext)) {
|
||||
return "Error: This variable can be set only in user context.";
|
||||
}
|
||||
|
||||
if (args.empty()) {
|
||||
return "Error: Value is missing.";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string AdminInterfaceCommand::handleGetRequest(UserInfo &uinfo, User *user, std::vector<std::string> &args) {
|
||||
if ((m_actions & Get) == 0) {
|
||||
return "Error: This variable cannot be get.";
|
||||
}
|
||||
|
||||
if (user && (m_accessMode & AdminMode) != 0) {
|
||||
return "Error: You do not have rights to get this variable.";
|
||||
}
|
||||
|
||||
if ((!user && uinfo.id == -1) && (m_context & UserContext)) {
|
||||
return "Error: This variable can be get only in user context.";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string AdminInterfaceCommand::handleExecuteRequest(UserInfo &uinfo, User *user, std::vector<std::string> &args) {
|
||||
if ((m_actions & Execute) == 0) {
|
||||
return "Error: This is not a command, but a variable.";
|
||||
}
|
||||
|
||||
if (user && (m_accessMode & AdminMode) != 0) {
|
||||
return "Error: You do not have rights to execute this command.";
|
||||
}
|
||||
|
||||
if ((!user && uinfo.id == -1) && (m_context & UserContext)) {
|
||||
return "Error: This command can be executed only in user context.";
|
||||
}
|
||||
|
||||
if (m_args.size() > args.size()) {
|
||||
return "Error: Argument is missing.";
|
||||
}
|
||||
|
||||
if (m_args.size() < args.size()) {
|
||||
return "Error: Too many arguments.";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
|
@ -38,6 +38,7 @@ DEFINE_LOGGER(logger_xml, "Component.RAW");
|
|||
Component::Component(Frontend *frontend, Swift::EventLoop *loop, Swift::NetworkFactories *factories, Config *config, Factory *factory, Transport::UserRegistry *userRegistry) {
|
||||
m_frontend = frontend;
|
||||
m_userRegistry = NULL;
|
||||
m_adminInterface = NULL;
|
||||
m_reconnectCount = 0;
|
||||
m_config = config;
|
||||
m_factory = factory;
|
||||
|
|
|
@ -127,17 +127,13 @@ std::string SlackFrontend::getOAuth2URL(const std::vector<std::string> &args) {
|
|||
|
||||
std::string SlackFrontend::getRegistrationFields() {
|
||||
std::string fields = "Main Slack channel";
|
||||
if (CONFIG_BOOL(m_config, "registration.needRegistration")) {
|
||||
if (CONFIG_BOOL_DEFAULTED(m_config, "registration.needRegistration", true)) {
|
||||
fields += "\n" + CONFIG_STRING(m_config, "registration.username_label") + "\n";
|
||||
fields += CONFIG_STRING(m_config, "registration.password_label");
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
bool SlackFrontend::handleAdminMessage(Swift::Message::ref message) {
|
||||
return static_cast<SlackUserManager *>(m_userManager)->handleAdminMessage(message);
|
||||
}
|
||||
|
||||
void SlackFrontend::disconnectFromServer() {
|
||||
|
||||
}
|
||||
|
|
|
@ -68,7 +68,6 @@ namespace Transport {
|
|||
virtual std::string setOAuth2Code(const std::string &code, const std::string &state);
|
||||
virtual std::string getOAuth2URL(const std::vector<std::string> &args);
|
||||
virtual std::string getRegistrationFields();
|
||||
virtual bool handleAdminMessage(Swift::Message::ref message);
|
||||
|
||||
void handleMessage(boost::shared_ptr<Swift::Message> message);
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
#include "transport/StorageBackend.h"
|
||||
#include "transport/Logging.h"
|
||||
#include "transport/Config.h"
|
||||
#include "transport/AdminInterface.h"
|
||||
#include "transport/AdminInterfaceCommand.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
@ -40,18 +42,176 @@ namespace Transport {
|
|||
|
||||
DEFINE_LOGGER(logger, "SlackUserManager");
|
||||
|
||||
class ListRoomsCommand : public AdminInterfaceCommand {
|
||||
public:
|
||||
|
||||
ListRoomsCommand(StorageBackend *storageBackend) : AdminInterfaceCommand("list_rooms",
|
||||
AdminInterfaceCommand::Frontend,
|
||||
AdminInterfaceCommand::UserContext,
|
||||
AdminInterfaceCommand::UserMode,
|
||||
AdminInterfaceCommand::Execute) {
|
||||
m_storageBackend = storageBackend;
|
||||
setDescription("List connected rooms");
|
||||
}
|
||||
|
||||
virtual std::string handleExecuteRequest(UserInfo &uinfo, User *user, std::vector<std::string> &args) {
|
||||
std::string ret = AdminInterfaceCommand::handleExecuteRequest(uinfo, user, args);
|
||||
if (!ret.empty()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (uinfo.id == -1) {
|
||||
return "Error: Unknown user";
|
||||
}
|
||||
|
||||
std::string rooms = "";
|
||||
int type = (int) TYPE_STRING;
|
||||
m_storageBackend->getUserSetting(uinfo.id, "rooms", type, rooms);
|
||||
return rooms;
|
||||
}
|
||||
|
||||
private:
|
||||
StorageBackend *m_storageBackend;
|
||||
};
|
||||
|
||||
class JoinRoomCommand : public AdminInterfaceCommand {
|
||||
public:
|
||||
|
||||
JoinRoomCommand(StorageBackend *storageBackend, Config *cfg) : AdminInterfaceCommand("join_room",
|
||||
AdminInterfaceCommand::Frontend,
|
||||
AdminInterfaceCommand::UserContext,
|
||||
AdminInterfaceCommand::UserMode,
|
||||
AdminInterfaceCommand::Execute) {
|
||||
m_storageBackend = storageBackend;
|
||||
setDescription("Join the room");
|
||||
|
||||
std::string legacyRoomLabel = CONFIG_STRING_DEFAULTED(cfg, "service.join_room_room_label", "3rd-party room name");
|
||||
if (legacyRoomLabel[0] == '%') {
|
||||
legacyRoomLabel[0] = '#';
|
||||
}
|
||||
|
||||
std::string legacyRoomExample = CONFIG_STRING_DEFAULTED(cfg, "service.join_room_room_example", "3rd-party room name");
|
||||
if (legacyRoomExample[0] == '%') {
|
||||
legacyRoomExample[0] = '#';
|
||||
}
|
||||
|
||||
addArg("nickname",
|
||||
CONFIG_STRING_DEFAULTED(cfg, "service.join_room_nickname_label", "Nickname in 3rd-party room"),
|
||||
CONFIG_STRING_DEFAULTED(cfg, "service.join_room_nickname_example", "BotNickname"));
|
||||
addArg("legacy_room", legacyRoomLabel, legacyRoomExample);
|
||||
addArg("legacy_server",
|
||||
CONFIG_STRING_DEFAULTED(cfg, "service.join_room_server_label", "3rd-party server"),
|
||||
CONFIG_STRING_DEFAULTED(cfg, "service.join_room_server_example", "3rd.party.server.org"));
|
||||
addArg("slack_channel", "Slack Chanel", "mychannel");
|
||||
}
|
||||
|
||||
virtual std::string handleExecuteRequest(UserInfo &uinfo, User *u, std::vector<std::string> &args) {
|
||||
std::string ret = AdminInterfaceCommand::handleExecuteRequest(uinfo, u, args);
|
||||
if (!ret.empty()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (uinfo.id == -1) {
|
||||
return "Error: Unknown user";
|
||||
}
|
||||
|
||||
std::string rooms = "";
|
||||
int type = (int) TYPE_STRING;
|
||||
m_storageBackend->getUserSetting(uinfo.id, "rooms", type, rooms);
|
||||
// 'unknown' is here to stay compatible in args.size() with older version.
|
||||
rooms += "connected room " + args[0] + " " + args[1] + " " + args[2] + " " + args[3] + "\n";
|
||||
m_storageBackend->updateUserSetting(uinfo.id, "rooms", rooms);
|
||||
|
||||
SlackUser *user = static_cast<SlackUser *>(u);
|
||||
if (user) {
|
||||
user->getSession()->handleJoinMessage("", args, true);
|
||||
}
|
||||
return "Joined the room";
|
||||
}
|
||||
|
||||
private:
|
||||
StorageBackend *m_storageBackend;
|
||||
};
|
||||
|
||||
class LeaveRoomCommand : public AdminInterfaceCommand {
|
||||
public:
|
||||
|
||||
LeaveRoomCommand(StorageBackend *storageBackend) : AdminInterfaceCommand("leave_room",
|
||||
AdminInterfaceCommand::Frontend,
|
||||
AdminInterfaceCommand::UserContext,
|
||||
AdminInterfaceCommand::UserMode,
|
||||
AdminInterfaceCommand::Execute) {
|
||||
m_storageBackend = storageBackend;
|
||||
setDescription("Leave the room");
|
||||
|
||||
addArg("slack_channel", "Slack Chanel", "mychannel");
|
||||
}
|
||||
|
||||
virtual std::string handleExecuteRequest(UserInfo &uinfo, User *u, std::vector<std::string> &args) {
|
||||
std::string ret = AdminInterfaceCommand::handleExecuteRequest(uinfo, u, args);
|
||||
if (!ret.empty()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (uinfo.id == -1) {
|
||||
return "Error: Unknown user";
|
||||
}
|
||||
|
||||
std::string rooms = "";
|
||||
int type = (int) TYPE_STRING;
|
||||
m_storageBackend->getUserSetting(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 (args[0] != args2[5]) {
|
||||
rooms += command + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_storageBackend->updateUserSetting(uinfo.id, "rooms", rooms);
|
||||
|
||||
SlackUser *user = static_cast<SlackUser *>(u);
|
||||
if (user) {
|
||||
user->getSession()->leaveRoom(args[0]);
|
||||
}
|
||||
return "Left the room";
|
||||
}
|
||||
|
||||
private:
|
||||
StorageBackend *m_storageBackend;
|
||||
};
|
||||
|
||||
SlackUserManager::SlackUserManager(Component *component, UserRegistry *userRegistry, StorageBackend *storageBackend) : UserManager(component, userRegistry, storageBackend) {
|
||||
m_component = component;
|
||||
m_storageBackend = storageBackend;
|
||||
m_userRegistration = new SlackUserRegistration(component, this, storageBackend);
|
||||
|
||||
onUserCreated.connect(boost::bind(&SlackUserManager::handleUserCreated, this, _1));
|
||||
m_component->onAdminInterfaceSet.connect(boost::bind(&SlackUserManager::handleAdminInterfaceSet, this));
|
||||
}
|
||||
|
||||
SlackUserManager::~SlackUserManager() {
|
||||
delete m_userRegistration;
|
||||
}
|
||||
|
||||
void SlackUserManager::handleAdminInterfaceSet() {
|
||||
AdminInterface *adminInterface = m_component->getAdminInterface();
|
||||
if (adminInterface) {
|
||||
adminInterface->addCommand(new ListRoomsCommand(m_storageBackend));
|
||||
adminInterface->addCommand(new JoinRoomCommand(m_storageBackend, m_component->getConfig()));
|
||||
adminInterface->addCommand(new LeaveRoomCommand(m_storageBackend));
|
||||
}
|
||||
}
|
||||
|
||||
void SlackUserManager::reconnectUser(const std::string &user) {
|
||||
UserInfo uinfo;
|
||||
if (!m_storageBackend->getUser(user, uinfo)) {
|
||||
|
@ -109,121 +269,5 @@ void SlackUserManager::handleUserCreated(User *user) {
|
|||
static_cast<SlackUser *>(user)->getSession()->handleConnected();
|
||||
}
|
||||
|
||||
bool SlackUserManager::handleAdminMessage(Swift::Message::ref message) {
|
||||
#if HAVE_SWIFTEN_3
|
||||
std::string body = message->getBody().get_value_or("");
|
||||
#else
|
||||
std::string body = message->getBody();
|
||||
#endif
|
||||
|
||||
if (body.find("list_rooms") == 0) {
|
||||
std::vector<std::string> args;
|
||||
boost::split(args, body, boost::is_any_of(" "));
|
||||
if (args.size() == 2) {
|
||||
UserInfo uinfo;
|
||||
if (!m_storageBackend->getUser(args[1], uinfo)) {
|
||||
message->setBody("Error: Unknown user");
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string rooms = "";
|
||||
int type = (int) TYPE_STRING;
|
||||
m_storageBackend->getUserSetting(uinfo.id, "rooms", type, rooms);
|
||||
|
||||
message->setBody(rooms);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (body.find("join_room_fields") == 0) {
|
||||
std::string ret;
|
||||
|
||||
Config *cfg = m_component->getConfig();
|
||||
ret += CONFIG_STRING_DEFAULTED(cfg, "service.join_room_nickname_label", "Nickname in 3rd-party room") + "\n";
|
||||
std::string room_name = CONFIG_STRING_DEFAULTED(cfg, "service.join_room_room_label", "3rd-party room name");
|
||||
if (room_name[0] == '%') {
|
||||
room_name[0] = '#';
|
||||
}
|
||||
ret += room_name + "\n";
|
||||
ret += CONFIG_STRING_DEFAULTED(cfg, "service.join_room_server_label", "3rd-party server") + "\n";
|
||||
ret += "Slack Channel\n";
|
||||
ret += CONFIG_STRING_DEFAULTED(cfg, "service.join_room_nickname_example", "BotNickname") + "\n";
|
||||
room_name = CONFIG_STRING_DEFAULTED(cfg, "service.join_room_room_example", "3rd-party room name");
|
||||
if (room_name[0] == '%') {
|
||||
room_name[0] = '#';
|
||||
}
|
||||
ret += room_name + "\n";
|
||||
ret += CONFIG_STRING_DEFAULTED(cfg, "service.join_room_server_example", "3rd.party.server.org") + "\n";
|
||||
ret += "mychannel";
|
||||
|
||||
message->setBody(ret);
|
||||
return true;
|
||||
}
|
||||
else if (body.find("join_room ") == 0) {
|
||||
std::vector<std::string> args;
|
||||
boost::split(args, body, boost::is_any_of(" "));
|
||||
if (args.size() == 6) {
|
||||
UserInfo uinfo;
|
||||
if (!m_storageBackend->getUser(args[1], uinfo)) {
|
||||
message->setBody("Error: Unknown user");
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string rooms = "";
|
||||
int type = (int) TYPE_STRING;
|
||||
m_storageBackend->getUserSetting(uinfo.id, "rooms", type, rooms);
|
||||
rooms += body + "\n";
|
||||
m_storageBackend->updateUserSetting(uinfo.id, "rooms", rooms);
|
||||
|
||||
SlackUser *user = static_cast<SlackUser *>(getUser(args[1]));
|
||||
if (user) {
|
||||
user->getSession()->handleJoinMessage("", args, true);
|
||||
}
|
||||
message->setBody("Joined the room");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (body.find("leave_room ") == 0) {
|
||||
std::vector<std::string> args;
|
||||
boost::split(args, body, boost::is_any_of(" "));
|
||||
if (args.size() == 3) {
|
||||
UserInfo uinfo;
|
||||
if (!m_storageBackend->getUser(args[1], uinfo)) {
|
||||
message->setBody("Error: Unknown user");
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string rooms = "";
|
||||
int type = (int) TYPE_STRING;
|
||||
m_storageBackend->getUserSetting(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 (args[2] != args2[5]) {
|
||||
rooms += command + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_storageBackend->updateUserSetting(uinfo.id, "rooms", rooms);
|
||||
|
||||
SlackUser *user = static_cast<SlackUser *>(getUser(args[1]));
|
||||
if (user) {
|
||||
user->getSession()->leaveRoom(args[2]);
|
||||
}
|
||||
message->setBody("Left the room");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -62,10 +62,9 @@ class SlackUserManager : public UserManager {
|
|||
SlackSession *moveTempSession(const std::string &user);
|
||||
void moveTempSession(const std::string &user, SlackSession *session);
|
||||
|
||||
bool handleAdminMessage(Swift::Message::ref message);
|
||||
|
||||
private:
|
||||
void handleUserCreated(User *user);
|
||||
void handleAdminInterfaceSet();
|
||||
|
||||
private:
|
||||
Component *m_component;
|
||||
|
|
|
@ -275,6 +275,7 @@ int mainloop() {
|
|||
|
||||
AdminInterface adminInterface(&transport, userManager, &plugin, storageBackend, userRegistration);
|
||||
plugin.setAdminInterface(&adminInterface);
|
||||
transport.setAdminInterface(&adminInterface);
|
||||
|
||||
eventLoop_ = &eventLoop;
|
||||
|
||||
|
|
|
@ -16,6 +16,10 @@
|
|||
#include "rapidjson/stringbuffer.h"
|
||||
#include "rapidjson/writer.h"
|
||||
|
||||
#include <boost/tokenizer.hpp>
|
||||
using boost::tokenizer;
|
||||
using boost::escaped_list_separator;
|
||||
|
||||
#define ALLOW_ONLY_ADMIN() if (!session->admin) { \
|
||||
send_ack(conn, true, "Only administrators can do this API call."); \
|
||||
return; \
|
||||
|
@ -138,58 +142,6 @@ void APIServer::serve_instances(Server *server, Server::session *session, struct
|
|||
send_json(conn, json);
|
||||
}
|
||||
|
||||
void APIServer::serve_instances_list_rooms(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 response = server->send_command(instance, "list_rooms " + username);
|
||||
|
||||
std::vector<std::string> commands;
|
||||
boost::split(commands, response, boost::is_any_of("\n"));
|
||||
|
||||
Document json;
|
||||
json.SetObject();
|
||||
json.AddMember("error", 0, json.GetAllocator());
|
||||
json.AddMember("name_label", "Nickname in 3rd-party room", json.GetAllocator());
|
||||
json.AddMember("legacy_room_label", "3rd-party room name", json.GetAllocator());
|
||||
json.AddMember("legacy_server_label", "3rd-party server", json.GetAllocator());
|
||||
json.AddMember("frontend_room_label", "Slack channel", json.GetAllocator());
|
||||
|
||||
std::vector<std::vector<std::string> > tmp;
|
||||
Value rooms(kArrayType);
|
||||
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) {
|
||||
tmp.push_back(args2);
|
||||
Value room;
|
||||
room.SetObject();
|
||||
room.AddMember("name", tmp.back()[2].c_str(), json.GetAllocator());
|
||||
room.AddMember("legacy_room", tmp.back()[3].c_str(), json.GetAllocator());
|
||||
room.AddMember("legacy_server", tmp.back()[4].c_str(), json.GetAllocator());
|
||||
room.AddMember("frontend_room", tmp.back()[5].c_str(), json.GetAllocator());
|
||||
rooms.PushBack(room, json.GetAllocator());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
json.AddMember("rooms", rooms, json.GetAllocator());
|
||||
send_json(conn, json);
|
||||
}
|
||||
|
||||
void APIServer::serve_instances_start(Server *server, Server::session *session, struct mg_connection *conn, struct http_message *hm) {
|
||||
ALLOW_ONLY_ADMIN();
|
||||
|
||||
|
@ -225,6 +177,10 @@ void APIServer::serve_instances_unregister(Server *server, Server::session *sess
|
|||
int type = (int) TYPE_STRING;
|
||||
m_storage->getUserSetting(info.id, instance, type, username);
|
||||
|
||||
if (username.empty() && session->admin) {
|
||||
username = get_http_var(hm, "command_arg0");
|
||||
}
|
||||
|
||||
if (!username.empty()) {
|
||||
std::string response = server->send_command(instance, "unregister " + username);
|
||||
if (!response.empty()) {
|
||||
|
@ -275,7 +231,7 @@ void APIServer::serve_instances_register(Server *server, Server::session *sessio
|
|||
else {
|
||||
// Check if the frontend wants to use OAuth2 (Slack for example).
|
||||
std::string response = server->send_command(instance, "get_oauth2_url " + jid + " " + uin + " " + password);
|
||||
if (!response.empty()) {
|
||||
if (!response.empty() && response.find("Error:") != 0) {
|
||||
Document json;
|
||||
json.SetObject();
|
||||
json.AddMember("error", false, json.GetAllocator());
|
||||
|
@ -288,6 +244,7 @@ void APIServer::serve_instances_register(Server *server, Server::session *sessio
|
|||
std::string value = jid;
|
||||
int type = (int) TYPE_STRING;
|
||||
m_storage->updateUserSetting(info.id, instance, value);
|
||||
send_ack(conn, false, response);
|
||||
}
|
||||
else {
|
||||
send_ack(conn, true, response);
|
||||
|
@ -297,7 +254,32 @@ void APIServer::serve_instances_register(Server *server, Server::session *sessio
|
|||
}
|
||||
}
|
||||
|
||||
void APIServer::serve_instances_join_room(Server *server, Server::session *session, struct mg_connection *conn, struct http_message *hm) {
|
||||
|
||||
|
||||
// void APIServer::serve_instances_register_form(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);
|
||||
//
|
||||
// std::string response = server->send_command(instance, "registration_fields");
|
||||
// std::vector<std::string> fields;
|
||||
// boost::split(fields, response, boost::is_any_of("\n"));
|
||||
//
|
||||
// if (fields.empty()) {
|
||||
// fields.push_back("Jabber ID");
|
||||
// fields.push_back("3rd-party network username");
|
||||
// fields.push_back("3rd-party network password");
|
||||
// }
|
||||
//
|
||||
// Document json;
|
||||
// json.SetObject();
|
||||
// json.AddMember("error", 0, json.GetAllocator());
|
||||
// json.AddMember("username_label", fields[0].c_str(), json.GetAllocator());
|
||||
// json.AddMember("legacy_username_label", fields.size() >= 2 ? fields[1].c_str() : "", json.GetAllocator());
|
||||
// json.AddMember("password_label", fields.size() >= 3 ? fields[2].c_str() : "", json.GetAllocator());
|
||||
// send_json(conn, json);
|
||||
// }
|
||||
|
||||
void APIServer::serve_instances_commands(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);
|
||||
|
||||
|
@ -308,29 +290,61 @@ void APIServer::serve_instances_join_room(Server *server, Server::session *sessi
|
|||
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 response = server->send_command(instance, "commands");
|
||||
|
||||
std::vector<std::string> commands;
|
||||
boost::split(commands, response, boost::is_any_of("\n"));
|
||||
|
||||
Document json;
|
||||
json.SetObject();
|
||||
json.AddMember("error", 0, json.GetAllocator());
|
||||
|
||||
std::vector<std::vector<std::string> > tmp;
|
||||
Value cmds(kArrayType);
|
||||
BOOST_FOREACH(const std::string &command, commands) {
|
||||
escaped_list_separator<char> els('\\', ' ', '\"');
|
||||
tokenizer<escaped_list_separator<char> > tok(command, els);
|
||||
|
||||
std::vector<std::string> tokens;
|
||||
for(tokenizer<escaped_list_separator<char> >::iterator beg=tok.begin(); beg!=tok.end(); ++beg) {
|
||||
tokens.push_back(*beg);
|
||||
}
|
||||
|
||||
if (tokens.size() != 9) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!session->admin && tokens[6] == "Admin") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip command which needs registered users.
|
||||
if (!session->admin && username.empty() && tokens[8] == "User") {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Skip 'register' command when user is registered.
|
||||
if (!session->admin && !username.empty() && tokens[0] == "register") {
|
||||
continue;
|
||||
}
|
||||
|
||||
tmp.push_back(tokens);
|
||||
|
||||
Value cmd;
|
||||
cmd.SetObject();
|
||||
cmd.AddMember("name", tokens[0].c_str(), json.GetAllocator());
|
||||
cmd.AddMember("desc", tokens[2].c_str(), json.GetAllocator());
|
||||
cmd.AddMember("category", tokens[4].c_str(), json.GetAllocator());
|
||||
cmd.AddMember("context", tokens[8].c_str(), json.GetAllocator());
|
||||
cmds.PushBack(cmd, json.GetAllocator());
|
||||
}
|
||||
|
||||
std::string name = get_http_var(hm, "name");
|
||||
boost::replace_all(name, " ", "_");
|
||||
std::string legacy_room = get_http_var(hm, "legacy_room");
|
||||
std::string legacy_server = get_http_var(hm, "legacy_server");
|
||||
std::string frontend_room = get_http_var(hm, "frontend_room");
|
||||
|
||||
std::string response = server->send_command(instance, "join_room " +
|
||||
username + " " + name + " " + legacy_room + " " + legacy_server + " " + frontend_room);
|
||||
|
||||
if (response.find("Joined the room") == std::string::npos) {
|
||||
send_ack(conn, true, response);
|
||||
}
|
||||
else {
|
||||
send_ack(conn, false, response);
|
||||
}
|
||||
json.AddMember("commands", cmds, json.GetAllocator());
|
||||
send_json(conn, json);
|
||||
}
|
||||
|
||||
void APIServer::serve_instances_leave_room(Server *server, Server::session *session, struct mg_connection *conn, struct http_message *hm) {
|
||||
void APIServer::serve_instances_variables(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);
|
||||
|
||||
|
@ -341,78 +355,231 @@ void APIServer::serve_instances_leave_room(Server *server, Server::session *sess
|
|||
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.");
|
||||
std::string response = server->send_command(instance, "variables");
|
||||
|
||||
std::vector<std::string> commands;
|
||||
boost::split(commands, response, boost::is_any_of("\n"));
|
||||
|
||||
Document json;
|
||||
json.SetObject();
|
||||
json.AddMember("error", 0, json.GetAllocator());
|
||||
|
||||
std::vector<std::vector<std::string> > tmp;
|
||||
Value cmds(kArrayType);
|
||||
BOOST_FOREACH(const std::string &command, commands) {
|
||||
escaped_list_separator<char> els('\\', ' ', '\"');
|
||||
tokenizer<escaped_list_separator<char> > tok(command, els);
|
||||
|
||||
std::vector<std::string> tokens;
|
||||
for(tokenizer<escaped_list_separator<char> >::iterator beg=tok.begin(); beg!=tok.end(); ++beg) {
|
||||
tokens.push_back(*beg);
|
||||
}
|
||||
|
||||
if (tokens.size() != 13) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!session->admin && tokens[10] == "Admin") {
|
||||
continue;
|
||||
}
|
||||
|
||||
tmp.push_back(tokens);
|
||||
|
||||
Value cmd;
|
||||
cmd.SetObject();
|
||||
cmd.AddMember("name", tokens[0].c_str(), json.GetAllocator());
|
||||
cmd.AddMember("desc", tokens[2].c_str(), json.GetAllocator());
|
||||
cmd.AddMember("value", tokens[4].c_str(), json.GetAllocator());
|
||||
cmd.AddMember("read_only", tokens[6].c_str(), json.GetAllocator());
|
||||
cmd.AddMember("category", tokens[8].c_str(), json.GetAllocator());
|
||||
cmd.AddMember("context", tokens[12].c_str(), json.GetAllocator());
|
||||
cmds.PushBack(cmd, json.GetAllocator());
|
||||
}
|
||||
|
||||
json.AddMember("variables", cmds, json.GetAllocator());
|
||||
send_json(conn, json);
|
||||
}
|
||||
|
||||
|
||||
void APIServer::serve_instances_command_args(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);
|
||||
std::string command = get_http_var(hm, "command");
|
||||
boost::trim(command);
|
||||
|
||||
std::string response = server->send_command(instance, "commands");
|
||||
|
||||
bool found = false;
|
||||
bool userContext = false;
|
||||
std::vector<std::string> commands;
|
||||
boost::split(commands, response, boost::is_any_of("\n"));
|
||||
BOOST_FOREACH(const std::string &cmd, commands) {
|
||||
escaped_list_separator<char> els('\\', ' ', '\"');
|
||||
tokenizer<escaped_list_separator<char> > tok(cmd, els);
|
||||
|
||||
std::vector<std::string> tokens;
|
||||
for(tokenizer<escaped_list_separator<char> >::iterator beg=tok.begin(); beg!=tok.end(); ++beg) {
|
||||
tokens.push_back(*beg);
|
||||
}
|
||||
|
||||
if (tokens.size() != 9) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::cout << tokens[0] << " " << command << "\n";
|
||||
if (tokens[0] != command) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!session->admin && tokens[6] == "Admin") {
|
||||
send_ack(conn, false, "Only admin is able to query this command.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (tokens[8] == "User") {
|
||||
userContext = true;
|
||||
}
|
||||
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
command = "unknown";
|
||||
}
|
||||
|
||||
response = server->send_command(instance, "args " + command);
|
||||
if (response.find("Error:") == 0) {
|
||||
send_ack(conn, false, response);
|
||||
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);
|
||||
std::vector<std::string> args;
|
||||
boost::split(args, response, boost::is_any_of("\n"));
|
||||
|
||||
Document json;
|
||||
json.SetObject();
|
||||
json.AddMember("error", 0, json.GetAllocator());
|
||||
|
||||
std::vector<std::vector<std::string> > tmp;
|
||||
Value argList(kArrayType);
|
||||
|
||||
if (userContext && session->admin) {
|
||||
Value arg;
|
||||
arg.SetObject();
|
||||
arg.AddMember("name", "username", json.GetAllocator());
|
||||
arg.AddMember("label", "Username", json.GetAllocator());
|
||||
arg.AddMember("example", "", json.GetAllocator());
|
||||
argList.PushBack(arg, json.GetAllocator());
|
||||
}
|
||||
else {
|
||||
|
||||
BOOST_FOREACH(const std::string &argument, args) {
|
||||
escaped_list_separator<char> els('\\', ' ', '\"');
|
||||
tokenizer<escaped_list_separator<char> > tok(argument, els);
|
||||
|
||||
std::vector<std::string> tokens;
|
||||
for(tokenizer<escaped_list_separator<char> >::iterator beg=tok.begin(); beg!=tok.end(); ++beg) {
|
||||
tokens.push_back(*beg);
|
||||
}
|
||||
|
||||
if (tokens.size() != 5) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tmp.push_back(tokens);
|
||||
|
||||
Value arg;
|
||||
arg.SetObject();
|
||||
arg.AddMember("name", tokens[0].c_str(), json.GetAllocator());
|
||||
arg.AddMember("label", tokens[2].c_str(), json.GetAllocator());
|
||||
arg.AddMember("example", tokens[4].c_str(), json.GetAllocator());
|
||||
argList.PushBack(arg, json.GetAllocator());
|
||||
}
|
||||
|
||||
json.AddMember("args", argList, json.GetAllocator());
|
||||
send_json(conn, json);
|
||||
}
|
||||
|
||||
|
||||
void APIServer::serve_instances_execute(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);
|
||||
std::string command = get_http_var(hm, "command");
|
||||
boost::trim(command);
|
||||
|
||||
std::string response = server->send_command(instance, "commands");
|
||||
|
||||
bool found = false;
|
||||
bool userContext = false;
|
||||
std::vector<std::string> commands;
|
||||
boost::split(commands, response, boost::is_any_of("\n"));
|
||||
BOOST_FOREACH(const std::string &cmd, commands) {
|
||||
escaped_list_separator<char> els('\\', ' ', '\"');
|
||||
tokenizer<escaped_list_separator<char> > tok(cmd, els);
|
||||
|
||||
std::vector<std::string> tokens;
|
||||
for(tokenizer<escaped_list_separator<char> >::iterator beg=tok.begin(); beg!=tok.end(); ++beg) {
|
||||
tokens.push_back(*beg);
|
||||
}
|
||||
|
||||
if (tokens.size() != 9) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::cout << tokens[0] << " " << command << "\n";
|
||||
if (tokens[0] != command) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!session->admin && tokens[6] == "Admin") {
|
||||
send_ack(conn, false, "Only admin is able to execute.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (tokens[8] == "User") {
|
||||
userContext = true;
|
||||
}
|
||||
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
command = "unknown";
|
||||
}
|
||||
|
||||
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 (userContext && !session->admin) {
|
||||
if (username.empty()) {
|
||||
send_ack(conn, false, "Error: You are not registered to this transport instance.");
|
||||
return;
|
||||
}
|
||||
|
||||
command += " " + username;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
std::string var = get_http_var(hm, std::string(std::string("command_arg") + boost::lexical_cast<std::string>(i)).c_str());
|
||||
if (!var.empty()) {
|
||||
command += " " + var;
|
||||
}
|
||||
}
|
||||
|
||||
response = server->send_command(instance, command);
|
||||
boost::replace_all(response, "\n", "<br/>");
|
||||
if (response.find("Error:") == 0) {
|
||||
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) {
|
||||
std::string uri(hm->uri.p, hm->uri.len);
|
||||
std::string instance = uri.substr(uri.rfind("/") + 1);
|
||||
|
||||
// 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());
|
||||
|
||||
std::string response = server->send_command(instance, "join_room_fields");
|
||||
std::vector<std::string> fields;
|
||||
boost::split(fields, response, boost::is_any_of("\n"));
|
||||
|
||||
if (fields.size() != 8) {
|
||||
fields.push_back("Nickname in 3rd-party room");
|
||||
fields.push_back("3rd-party room name");
|
||||
fields.push_back("3rd-party server");
|
||||
fields.push_back("Slack Channel");
|
||||
fields.push_back("BotNickname");
|
||||
fields.push_back("room_name");
|
||||
fields.push_back("3rd.party.server.org");
|
||||
fields.push_back("mychannel");
|
||||
else {
|
||||
send_ack(conn, true, response);
|
||||
}
|
||||
|
||||
json.AddMember("name_label", fields[0].c_str(), json.GetAllocator());
|
||||
json.AddMember("legacy_room_label", fields[1].c_str(), json.GetAllocator());
|
||||
json.AddMember("legacy_server_label", fields[2].c_str(), json.GetAllocator());
|
||||
json.AddMember("frontend_room_label", fields[3].c_str(), json.GetAllocator());
|
||||
json.AddMember("name_example", fields[4].c_str(), json.GetAllocator());
|
||||
json.AddMember("legacy_room_example", fields[5].c_str(), json.GetAllocator());
|
||||
json.AddMember("legacy_server_example", fields[6].c_str(), json.GetAllocator());
|
||||
json.AddMember("frontend_room_example", fields[7].c_str(), json.GetAllocator());
|
||||
send_json(conn, json);
|
||||
}
|
||||
|
||||
void APIServer::serve_instances_register_form(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);
|
||||
|
||||
std::string response = server->send_command(instance, "registration_fields");
|
||||
std::vector<std::string> fields;
|
||||
boost::split(fields, response, boost::is_any_of("\n"));
|
||||
|
||||
if (fields.empty()) {
|
||||
fields.push_back("Jabber ID");
|
||||
fields.push_back("3rd-party network username");
|
||||
fields.push_back("3rd-party network password");
|
||||
}
|
||||
|
||||
Document json;
|
||||
json.SetObject();
|
||||
json.AddMember("error", 0, json.GetAllocator());
|
||||
json.AddMember("username_label", fields[0].c_str(), json.GetAllocator());
|
||||
json.AddMember("legacy_username_label", fields.size() >= 2 ? fields[1].c_str() : "", json.GetAllocator());
|
||||
json.AddMember("password_label", fields.size() >= 3 ? fields[2].c_str() : "", json.GetAllocator());
|
||||
send_json(conn, json);
|
||||
}
|
||||
|
||||
void APIServer::serve_users(Server *server, Server::session *session, struct mg_connection *conn, struct http_message *hm) {
|
||||
|
@ -494,23 +661,20 @@ void APIServer::handleRequest(Server *server, Server::session *sess, struct mg_c
|
|||
else if (has_prefix(&hm->uri, "/api/v1/instances/unregister/")) {
|
||||
serve_instances_unregister(server, sess, conn, hm);
|
||||
}
|
||||
else if (has_prefix(&hm->uri, "/api/v1/instances/register_form/")) {
|
||||
serve_instances_register_form(server, sess, conn, hm);
|
||||
}
|
||||
else if (has_prefix(&hm->uri, "/api/v1/instances/register/")) {
|
||||
serve_instances_register(server, sess, conn, hm);
|
||||
}
|
||||
else if (has_prefix(&hm->uri, "/api/v1/instances/join_room_form/")) {
|
||||
serve_instances_join_room_form(server, sess, conn, hm);
|
||||
else if (has_prefix(&hm->uri, "/api/v1/instances/commands/")) {
|
||||
serve_instances_commands(server, sess, conn, hm);
|
||||
}
|
||||
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/variables/")) {
|
||||
serve_instances_variables(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/command_args/")) {
|
||||
serve_instances_command_args(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/instances/execute/")) {
|
||||
serve_instances_execute(server, sess, conn, hm);
|
||||
}
|
||||
else if (has_prefix(&hm->uri, "/api/v1/users/remove/")) {
|
||||
serve_users_remove(server, sess, conn, hm);
|
||||
|
|
|
@ -56,12 +56,11 @@ class APIServer {
|
|||
void serve_instances_start(Server *server, Server::session *sess, struct mg_connection *conn, struct http_message *hm);
|
||||
void serve_instances_stop(Server *server, Server::session *sess, struct mg_connection *conn, struct http_message *hm);
|
||||
void serve_instances_unregister(Server *server, Server::session *sess, struct mg_connection *conn, struct http_message *hm);
|
||||
void serve_instances_commands(Server *server, Server::session *sess, struct mg_connection *conn, struct http_message *hm);
|
||||
void serve_instances_variables(Server *server, Server::session *sess, struct mg_connection *conn, struct http_message *hm);
|
||||
void serve_instances_command_args(Server *server, Server::session *sess, struct mg_connection *conn, struct http_message *hm);
|
||||
void serve_instances_execute(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);
|
||||
|
|
5
spectrum_manager/src/html/bootstrap.min.css
vendored
Normal file
5
spectrum_manager/src/html/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -5,6 +5,7 @@
|
|||
<meta http-equiv="X-UA-Compatible" content="chrome=1">
|
||||
<meta name="description" content="Spectrum 2 : Spectrum 2 IM transports">
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/bootstrap.min.css">
|
||||
<link href="/style.css" rel="stylesheet" type="text/css" media="all">
|
||||
<link href="/form.css" rel="stylesheet" type="text/css" media="all">
|
||||
<link href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet" type="text/css" media="all">
|
||||
|
@ -12,6 +13,8 @@
|
|||
<script src="/js/jquery-ui.js"></script>
|
||||
<script src="/js/jquery.cookie.js"></script>
|
||||
<script src="/js/config.js"></script>
|
||||
<script src="/js/bootstrap.min.js"></script>
|
||||
<script src="/js/bootbox.min.js"></script>
|
||||
<script src="/js/app.js"></script>
|
||||
<title>Spectrum 2</title>
|
||||
</head>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
show_list_rooms();
|
||||
show_instance();
|
||||
});
|
||||
</script>
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
<!--#include virtual="/header.shtml" -->
|
||||
|
||||
<h2>Join room</h2>
|
||||
<form action="/api/v1/instances/join_room" class="basic-grey" method="POST">
|
||||
<h1>Join room
|
||||
<span id="description">Join the room using this Spectrum 2 instance.</span>
|
||||
</h1>
|
||||
<label>
|
||||
<span id="name_desc"></span>
|
||||
<input type="text" id="name" name="name" placeholder=""></textarea>
|
||||
</label>
|
||||
<label>
|
||||
<span id="legacy_room_desc"></span>
|
||||
<input type="text" id="legacy_room" name="legacy_name" placeholder=""></textarea>
|
||||
</label>
|
||||
<label>
|
||||
<span id="legacy_server_desc"></span>
|
||||
<input type="text" id="legacy_server" name="legacy_server" placeholder=""></textarea>
|
||||
</label>
|
||||
<label>
|
||||
<span id="frontend_room_desc"></span>
|
||||
<input type="text" id="frontend_room" name="frontend_room" placeholder=""></textarea>
|
||||
</label>
|
||||
<label>
|
||||
<span> </span>
|
||||
<input type="submit" class="button_command" value="Join room" />
|
||||
</label>
|
||||
<input type="hidden" name="instance" id="instance" value=""></input>
|
||||
</form><br/>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
fill_instances_join_room_form();
|
||||
});
|
||||
</script>
|
||||
|
||||
<!--#include virtual="/footer.shtml" -->
|
|
@ -1,32 +0,0 @@
|
|||
<!--#include virtual="/header.shtml" -->
|
||||
|
||||
<h2>Register Spectrum 2 instance</h2>
|
||||
<form action="/api/v1/instances/register" class="basic-grey" method="POST">
|
||||
<h1>Register Spectrum 2 instance
|
||||
<span id="description"></span>
|
||||
</h1>
|
||||
<label>
|
||||
<span id="jid_desc"></span>
|
||||
<input type="text" id="jid" name="jid" placeholder=""></textarea>
|
||||
</label>
|
||||
<label id="uin_label">
|
||||
<span id="uin_desc"></span>
|
||||
<input type="text" id="uin" name="uin" placeholder=""></textarea>
|
||||
</label>
|
||||
<label id="password_label"><span id="password_desc"></span>
|
||||
<input type="password" id="password" name="password" placeholder=""></textarea>
|
||||
</label>
|
||||
<label>
|
||||
<span> </span>
|
||||
<input type="submit" class="button_command" value="Register" />
|
||||
</label>
|
||||
<input type="hidden" name="instance" id="instance" value=""></input>
|
||||
</form><br/>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
fill_instances_register_form();
|
||||
});
|
||||
</script>
|
||||
|
||||
<!--#include virtual="/footer.shtml" -->
|
|
@ -14,16 +14,20 @@ function getQueryParams(qs) {
|
|||
|
||||
function show_instances() {
|
||||
$.get($.cookie("base_location") + "api/v1/instances", function(data) {
|
||||
$("#main_content").html("<h2>List of Spectrum 2 instances</h2><table id='main_result'><tr><th>Name<th>Status</th><th>Actions</th></tr>");
|
||||
|
||||
var admin = $.cookie("admin") == "1";
|
||||
if (admin) {
|
||||
$("#main_content").html("<h2>List of Spectrum 2 instances</h2><table id='main_result'><tr><th>Name<th>Status</th><th>Actions</th></tr></table>");
|
||||
}
|
||||
else {
|
||||
$("#main_content").html("<h2>List of Spectrum 2 instances</h2><table id='main_result'><tr><th>Name<th>Status</th></tr></table>");
|
||||
}
|
||||
|
||||
$.each(data.instances, function(i, instance) {
|
||||
if (instance.running) {
|
||||
if (admin) {
|
||||
var command = instance.running ? "stop" : "start";
|
||||
}
|
||||
else {
|
||||
var command = instance.registered ? "unregister" : "register";
|
||||
if (instance.registered) {
|
||||
instance.status += "<br/>Registered as " + instance.username;
|
||||
}
|
||||
|
@ -36,68 +40,37 @@ function show_instances() {
|
|||
var command = "";
|
||||
}
|
||||
var row = '<tr>'
|
||||
row += '<td>' + instance.name + '</td>'
|
||||
row += '<td><a href="instance.shtml?id=' + instance.id + '">' + instance.name + '</a></td>'
|
||||
row += '<td>' + instance.status + '</td>'
|
||||
if (admin) {
|
||||
if (command == "") {
|
||||
row += '<td></td></tr>';
|
||||
$("#main_result > tbody:last-child").append(row);
|
||||
}
|
||||
else {
|
||||
row += '<td>';
|
||||
row += '<a class="button_command" href="' + $.cookie("base_location") + 'api/v1/instances/' + command + '/' + instance.id + '">' + command + '</a>';
|
||||
row += '</td></tr>';
|
||||
$("#main_result > tbody:last-child").append(row);
|
||||
$(".button_command").click(function(e) {
|
||||
e.preventDefault();
|
||||
$(this).parent().empty().progressbar( {value: false} ).css('height', '1em');
|
||||
|
||||
if (command == 'register') {
|
||||
row += '<td><a href="' + $.cookie("base_location") + 'instances/register.shtml?id=' + instance.id + '">' + command + '</a>' + '</td></tr>';
|
||||
$("#main_result > tbody:last-child").append(row);
|
||||
}
|
||||
else if (command == "") {
|
||||
row += '<td></td></tr>';
|
||||
$("#main_result > tbody:last-child").append(row);
|
||||
var url = $(this).attr('href');
|
||||
$.get(url, function(data) {
|
||||
show_instances();
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
else {
|
||||
row += '<td>';
|
||||
if (command == 'unregister' && instance.frontend == "slack") {
|
||||
row += '<a href="' + $.cookie("base_location") + 'instances/join_room.shtml?id=' + instance.id + '">Join room</a> | ';
|
||||
row += '<a href="' + $.cookie("base_location") + 'instances/list_rooms.shtml?id=' + instance.id + '">List joined rooms</a> | ';
|
||||
}
|
||||
row += '<a class="button_command" href="' + $.cookie("base_location") + 'api/v1/instances/' + command + '/' + instance.id + '">' + command + '</a>';
|
||||
row += '</td></tr>';
|
||||
row += '</tr>';
|
||||
$("#main_result > tbody:last-child").append(row);
|
||||
$(".button_command").click(function(e) {
|
||||
e.preventDefault();
|
||||
$(this).parent().empty().progressbar( {value: false} ).css('height', '1em');
|
||||
|
||||
var url = $(this).attr('href');
|
||||
$.get(url, function(data) {
|
||||
show_instances();
|
||||
});
|
||||
})
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function show_list_rooms() {
|
||||
var query = getQueryParams(document.location.search);
|
||||
$.get($.cookie("base_location") + "api/v1/instances/list_rooms/" + query.id, function(data) {
|
||||
$("#main_content").html("<h2>Joined rooms</h2><table id='main_result'><tr><th>" + data.frontend_room_label + "</th><th>" + data.legacy_room_label + "</th><th>" + data.legacy_server_label + "</th><th>" + data.name_label + "</th><th>Actions</th></tr>");
|
||||
|
||||
$.each(data.rooms, function(i, room) {
|
||||
var row = '<tr>';
|
||||
row += '<td>' + room.frontend_room + '</td>';
|
||||
row += '<td>' + room.legacy_room + '</td>';
|
||||
row += '<td>' + room.legacy_server + '</td>';
|
||||
row += '<td>' + room.name + '</td>';
|
||||
row += '<td><a class="button_command" href="' + $.cookie("base_location") + 'api/v1/instances/leave_room/' + query.id + '?frontend_room=' + encodeURIComponent(room.frontend_room) + '">Leave</a></td>';
|
||||
row += '</tr>';
|
||||
|
||||
$("#main_result > tbody:last-child").append(row);
|
||||
$(".button_command").click(function(e) {
|
||||
e.preventDefault();
|
||||
$(this).parent().empty().progressbar( {value: false} ).css('height', '1em');
|
||||
|
||||
var url = $(this).attr('href');
|
||||
$.get(url, function(data) {
|
||||
show_list_rooms();
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function show_users() {
|
||||
var admin = $.cookie("admin") == "1";
|
||||
if (!admin) {
|
||||
|
@ -126,85 +99,6 @@ function show_users() {
|
|||
});
|
||||
}
|
||||
|
||||
function fill_instances_join_room_form() {
|
||||
var query = getQueryParams(document.location.search);
|
||||
$("#instance").attr("value", query.id);
|
||||
|
||||
$(".button_command").click(function(e) {
|
||||
e.preventDefault();
|
||||
$(this).parent().empty().progressbar( {value: false} ).css('height', '1em');
|
||||
|
||||
var postdata ={
|
||||
"name": $("#name").val(),
|
||||
"legacy_room": $("#legacy_room").val(),
|
||||
"legacy_server": $("#legacy_server").val(),
|
||||
"frontend_room": $("#frontend_room").val()
|
||||
};
|
||||
|
||||
$.post($.cookie("base_location") + "api/v1/instances/join_room/" + $("#instance").val(), postdata, function(data) {
|
||||
window.location.replace("index.shtml");
|
||||
});
|
||||
})
|
||||
|
||||
$.get($.cookie("base_location") + "api/v1/instances/join_room_form/" + query.id, function(data) {
|
||||
$("#name_desc").html(data.name_label + ":");
|
||||
$("#legacy_room_desc").html(data.legacy_room_label + ":");
|
||||
$("#legacy_server_desc").html(data.legacy_server_label + ":");
|
||||
$("#frontend_room_desc").html(data.frontend_room_label + ":");
|
||||
|
||||
$("#name").attr("placeholder", data.name_example);
|
||||
$("#legacy_room").attr("placeholder", data.legacy_room_example);
|
||||
$("#legacy_server").attr("placeholder", data.legacy_server_example);
|
||||
$("#frontend_room").attr("placeholder", data.frontend_room_example);
|
||||
});
|
||||
}
|
||||
|
||||
function fill_instances_register_form() {
|
||||
var query = getQueryParams(document.location.search);
|
||||
$("#instance").attr("value", query.id);
|
||||
|
||||
$(".button_command").click(function(e) {
|
||||
e.preventDefault();
|
||||
$(this).parent().empty().progressbar( {value: false} ).css('height', '1em');
|
||||
|
||||
var postdata ={
|
||||
"jid": $("#jid").val(),
|
||||
"uin": $("#uin").val(),
|
||||
"password": $("#password").val()
|
||||
};
|
||||
|
||||
$.post($.cookie("base_location") + "api/v1/instances/register/" + $("#instance").val(), postdata, function(data) {
|
||||
if (data.oauth2_url) {
|
||||
window.location.replace(data.oauth2_url);
|
||||
}
|
||||
else {
|
||||
window.location.replace("index.shtml");
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
$.get($.cookie("base_location") + "api/v1/instances/register_form/" + query.id, function(data) {
|
||||
$("#jid_desc").html(data.username_label + ":");
|
||||
$("#jid").attr("placeholder", data.username_label);
|
||||
|
||||
if (data.legacy_username_label.length == 0) {
|
||||
$('#uin_label').hide();
|
||||
}
|
||||
else {
|
||||
$("#uin_desc").html(data.legacy_username_label + ":");
|
||||
$("#uin").attr("placeholder", data.legacy_username_label);
|
||||
}
|
||||
|
||||
if (data.password_label.length == 0) {
|
||||
$('#password_label').hide();
|
||||
}
|
||||
else {
|
||||
$("#password_desc").html(data.password_label + ":");
|
||||
$("#password").attr("placeholder", data.password_label);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function fill_users_register_form() {
|
||||
$(".button").click(function(e) {
|
||||
e.preventDefault();
|
||||
|
@ -231,3 +125,154 @@ function fill_users_register_form() {
|
|||
})
|
||||
}
|
||||
|
||||
function execute_command(instance, command) {
|
||||
$.get($.cookie("base_location") + 'api/v1/instances/command_args/' + instance + '?command=' + command, function(data) {
|
||||
var form = '<div class="row">';
|
||||
|
||||
if (data.args.length != 0) {
|
||||
form += '<div class="col-md-12"><form class="form-horizontal">';
|
||||
$.each(data.args, function(i, arg) {
|
||||
form += '<div class="form-group">';
|
||||
form += '<label class="col-md-4 control-label" for="' + arg.name + '">' + arg.label + ':</label>';
|
||||
form += '<div class="col-md-4">';
|
||||
form += '<input id="command_arg' + i + '" name="command_arg' + i + '" type="text" placeholder="' + arg.example + '" class="form-control input-md"/>';
|
||||
form += '</div></div>';
|
||||
console.log('command_arg' + i );
|
||||
});
|
||||
}
|
||||
else {
|
||||
form += '<div><form class="form-horizontal">';
|
||||
form += '<div class="form-group">';
|
||||
form += '<label class="control-label">No arguments needed for this command, you can just execute it.</label>';
|
||||
form += '</div>';
|
||||
}
|
||||
|
||||
form += '</form></div></div>'
|
||||
|
||||
bootbox.dialog({
|
||||
title: "Command execution: " + command + ".",
|
||||
message: form,
|
||||
buttons: {
|
||||
cancel: {
|
||||
label: "Cancel",
|
||||
className: "btn-cancel"
|
||||
},
|
||||
success: {
|
||||
label: "Execute",
|
||||
className: "btn-success",
|
||||
callback: function () {
|
||||
if (command == "register") {
|
||||
var postdata = {};
|
||||
if ($("#command_arg0").val()) {
|
||||
postdata["jid"] = $("#command_arg0").val();
|
||||
}
|
||||
if ($("#command_arg1").val()) {
|
||||
postdata["uin"] = $("#command_arg1").val();
|
||||
}
|
||||
if ($("#command_arg2").val()) {
|
||||
postdata["password"] = $("#command_arg2").val();
|
||||
}
|
||||
|
||||
$.post($.cookie("base_location") + "api/v1/instances/register/" + instance, postdata, function(data) {
|
||||
if (data.oauth2_url) {
|
||||
window.location.replace(data.oauth2_url);
|
||||
}
|
||||
else {
|
||||
var dialog = bootbox.dialog({
|
||||
title: "Command result: " + command + ".",
|
||||
message: "<pre>" + data.message + "</pre>",
|
||||
buttons: {
|
||||
success: {
|
||||
label: "OK",
|
||||
className: "btn-success",
|
||||
callback: function () {
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
dialog.find("div.modal-dialog").addClass("largeWidth");
|
||||
dialog.find("div.modal-body").addClass("maxHeight");
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (command == "unregister") {
|
||||
var posturl = $.cookie("base_location") + "api/v1/instances/unregister/" + instance;
|
||||
}
|
||||
else {
|
||||
var posturl = $.cookie("base_location") + "api/v1/instances/execute/" + instance + "?command=" + command;
|
||||
}
|
||||
var postdata = {}
|
||||
for (i = 0; i < 10; i++) {
|
||||
var val = $('#command_arg' + i).val();
|
||||
if (val) {
|
||||
postdata["command_arg" + i] = val;
|
||||
}
|
||||
}
|
||||
$.post(posturl, postdata, function(data) {
|
||||
var dialog = bootbox.dialog({
|
||||
title: "Command result: " + command + ".",
|
||||
message: "<pre>" + data.message + "</pre>",
|
||||
buttons: {
|
||||
success: {
|
||||
label: "OK",
|
||||
className: "btn-success",
|
||||
callback: function () {
|
||||
if (command == "unregister") {
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
dialog.find("div.modal-dialog").addClass("largeWidth");
|
||||
dialog.find("div.modal-body").addClass("maxHeight");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function show_instance() {
|
||||
var query = getQueryParams(document.location.search);
|
||||
|
||||
$("#main_content").html("<h2>Instance: " + query.id + "</h2><h4>Available commands:</h4><table id='commands'><tr><th>Name<th>Category</th><th>Description</th></tr></table><h4>Available variables:</h4><table id='variables'><tr><th>Name<th>Value</th><th>Read-only</th><th>Desc</th></tr></table>");
|
||||
|
||||
$.get($.cookie("base_location") + "api/v1/instances/commands/" + query.id, function(data) {
|
||||
$.each(data.commands, function(i, command) {
|
||||
var row = '<tr>'
|
||||
row += '<td><a class="button_command" command="' + command.name + '" instance="' + query.id + '" href="' + $.cookie("base_location") + 'api/v1/instances/command_args/' + query.id + '?command=' + command.name +'">' + command.name + '</a></td>';
|
||||
row += '<td>' + command.category + '</td>';
|
||||
row += '<td>' + command.desc + '</td>';
|
||||
row += '</tr>';
|
||||
$("#commands > tbody:last-child").append(row);
|
||||
});
|
||||
|
||||
$(".button_command").click(function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var command = $(this).attr('command');
|
||||
var instance = $(this).attr('instance');
|
||||
execute_command(instance, command);
|
||||
})
|
||||
});
|
||||
|
||||
$.get($.cookie("base_location") + "api/v1/instances/variables/" + query.id, function(data) {
|
||||
$.each(data.variables, function(i, variable) {
|
||||
var row = '<tr>'
|
||||
row += '<td>' + variable.name + '</td>';
|
||||
row += '<td>' + variable.value + '</td>';
|
||||
row += '<td>' + variable.read_only + '</td>';
|
||||
row += '<td>' + variable.desc + '</td>';
|
||||
row += '</tr>';
|
||||
$("#variables > tbody:last-child").append(row);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
6
spectrum_manager/src/html/js/bootbox.min.js
vendored
Normal file
6
spectrum_manager/src/html/js/bootbox.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7
spectrum_manager/src/html/js/bootstrap.min.js
vendored
Normal file
7
spectrum_manager/src/html/js/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
spectrum_manager/src/html/js/config.js
Normal file
1
spectrum_manager/src/html/js/config.js
Normal file
|
@ -0,0 +1 @@
|
|||
var BaseLocation = "/spectrum/";
|
7184
spectrum_manager/src/html/js/jquery.js
vendored
7184
spectrum_manager/src/html/js/jquery.js
vendored
File diff suppressed because one or more lines are too long
|
@ -463,3 +463,14 @@ Small Device Styles
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
.largeWidth {
|
||||
margin: 0 auto;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.maxHeight {
|
||||
max-height: 500px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
|
|
|
@ -446,6 +446,7 @@ void Server::event_handler(struct mg_connection *conn, int ev, void *p) {
|
|||
boost::replace_all(resp, "src=\"/", std::string("src=\"") + CONFIG_STRING(m_config, "service.base_location"));
|
||||
boost::replace_all(resp, "action=\"/", std::string("action=\"") + CONFIG_STRING(m_config, "service.base_location"));
|
||||
strcpy(conn->send_mbuf.buf, resp.c_str());
|
||||
conn->send_mbuf.len = resp.size();
|
||||
mbuf_trim(&conn->send_mbuf);
|
||||
return;
|
||||
}
|
||||
|
|
132
tests/libtransport/AdminInterface.cpp
Normal file
132
tests/libtransport/AdminInterface.cpp
Normal file
|
@ -0,0 +1,132 @@
|
|||
#include <cppunit/TestFixture.h>
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
#include <Swiften/Swiften.h>
|
||||
#include <Swiften/EventLoop/DummyEventLoop.h>
|
||||
#include <Swiften/Server/Server.h>
|
||||
#include <Swiften/Network/DummyNetworkFactories.h>
|
||||
#include <Swiften/Network/DummyConnectionServer.h>
|
||||
#include "Swiften/Server/ServerStanzaChannel.h"
|
||||
#include "Swiften/Server/ServerFromClientSession.h"
|
||||
#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h"
|
||||
#include "BasicSlackTest.h"
|
||||
#include "transport/AdminInterface.h"
|
||||
|
||||
#if !HAVE_SWIFTEN_3
|
||||
#define get_value_or(X) substr()
|
||||
#endif
|
||||
|
||||
using namespace Transport;
|
||||
|
||||
class AdminInterfaceTest : public CPPUNIT_NS :: TestFixture, public BasicSlackTest {
|
||||
CPPUNIT_TEST_SUITE(AdminInterfaceTest);
|
||||
CPPUNIT_TEST(helpCommand);
|
||||
CPPUNIT_TEST(statusCommand);
|
||||
CPPUNIT_TEST(joinRoomArgs);
|
||||
CPPUNIT_TEST(getOAuth2URLCommand);
|
||||
CPPUNIT_TEST(unknownCommand);
|
||||
CPPUNIT_TEST(listJoinLeaveRoomsCommand);
|
||||
CPPUNIT_TEST(badArgCount);
|
||||
CPPUNIT_TEST(commandsCommand);
|
||||
CPPUNIT_TEST(variablesCommand);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
AdminInterface *admin;
|
||||
NetworkPluginServer *serv;
|
||||
|
||||
void setUp (void) {
|
||||
setMeUp();
|
||||
serv = new NetworkPluginServer(component, cfg, userManager, NULL);
|
||||
admin = new AdminInterface(component, userManager, serv, storage, NULL);
|
||||
component->setAdminInterface(admin);
|
||||
}
|
||||
|
||||
void tearDown (void) {
|
||||
delete admin;
|
||||
delete serv;
|
||||
tearMeDown();
|
||||
}
|
||||
|
||||
std::string sendAdminMessage(const std::string &cmd) {
|
||||
Swift::Message::ref msg = boost::shared_ptr<Swift::Message>(new Swift::Message());
|
||||
msg->setFrom(Swift::JID("me@localhost"));
|
||||
msg->setTo(Swift::JID("localhost"));
|
||||
msg->setBody(cmd);
|
||||
|
||||
admin->handleMessageReceived(msg);
|
||||
return msg->getBody().get_value_or("");
|
||||
}
|
||||
|
||||
void helpCommand() {
|
||||
std::string resp = sendAdminMessage("help");
|
||||
CPPUNIT_ASSERT(resp.find(" VAR status - Shows instance status\n") != std::string::npos);
|
||||
}
|
||||
|
||||
void statusCommand() {
|
||||
std::string resp = sendAdminMessage("status");
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("Running (0 users connected using 0 backends)"), resp);
|
||||
}
|
||||
|
||||
void joinRoomArgs() {
|
||||
std::string resp = sendAdminMessage("args join_room");
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("nickname - \"Nickname in 3rd-party room\" Example: \"BotNickname\"\n"
|
||||
"legacy_room - \"3rd-party room name\" Example: \"3rd-party room name\"\n"
|
||||
"legacy_server - \"3rd-party server\" Example: \"3rd.party.server.org\"\n"
|
||||
"slack_channel - \"Slack Chanel\" Example: \"mychannel\"\n"), resp);
|
||||
}
|
||||
|
||||
void getOAuth2URLCommand() {
|
||||
std::string resp = sendAdminMessage("get_oauth2_url x y z");
|
||||
CPPUNIT_ASSERT(resp.find("https://slack.com/oauth/authorize?client_id=&scope=channels%3Aread%20channels%3Awrite%20team%3Aread%20im%3Aread%20im%3Awrite%20chat%3Awrite%3Abot%20bot&redirect_uri=https%3A%2F%2Fslack.spectrum.im%2Foauth2%2Flocalhost&state=") != std::string::npos);
|
||||
}
|
||||
|
||||
void unknownCommand() {
|
||||
std::string resp = sendAdminMessage("unknown_command test");
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("Error: Unknown variable or command"), resp);
|
||||
}
|
||||
|
||||
void listJoinLeaveRoomsCommand() {
|
||||
addUser();
|
||||
|
||||
std::string resp = sendAdminMessage("list_rooms user@localhost");
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(""), resp);
|
||||
|
||||
resp = sendAdminMessage("join_room user@localhost SlackBot spectrum conference.spectrum.im slack_channel");
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("Joined the room"), resp);
|
||||
|
||||
resp = sendAdminMessage("list_rooms user@localhost");
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("connected room SlackBot spectrum conference.spectrum.im slack_channel\n"), resp);
|
||||
|
||||
resp = sendAdminMessage("leave_room user@localhost slack_channel");
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("Left the room"), resp);
|
||||
|
||||
resp = sendAdminMessage("list_rooms user@localhost");
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(""), resp);
|
||||
}
|
||||
|
||||
void badArgCount() {
|
||||
addUser();
|
||||
std::string resp;
|
||||
resp = sendAdminMessage("join_room user@localhost SlackBot spectrum conference.spectrum.im slack_channel unknown");
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("Error: Too many arguments."), resp);
|
||||
|
||||
resp = sendAdminMessage("join_room user@localhost SlackBot spectrum conference.spectrum.im");
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("Error: Argument is missing."), resp);
|
||||
}
|
||||
|
||||
void commandsCommand() {
|
||||
addUser();
|
||||
std::string resp;
|
||||
resp = sendAdminMessage("commands");
|
||||
CPPUNIT_ASSERT(resp.find("join_room - \"Join the room\" Category: Frontend AccesMode: User Context: User") != std::string::npos);
|
||||
}
|
||||
|
||||
void variablesCommand() {
|
||||
addUser();
|
||||
std::string resp;
|
||||
resp = sendAdminMessage("variables");
|
||||
CPPUNIT_ASSERT(resp.find("backends_count - \"Number of active backends\" Value: \"0\" Read-only: true") != std::string::npos);
|
||||
}
|
||||
};
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION (AdminInterfaceTest);
|
|
@ -34,7 +34,7 @@
|
|||
using namespace Transport;
|
||||
|
||||
void BasicSlackTest::setMeUp (void) {
|
||||
std::istringstream ifs("service.server_mode = 1\nservice.jid=localhost\nservice.more_resources=1\n");
|
||||
std::istringstream ifs("service.server_mode = 1\nservice.jid=localhost\nservice.more_resources=1\nservice.admin_jid=me@localhost\n");
|
||||
cfg = new Config();
|
||||
cfg->load(ifs);
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
|
||||
using namespace Transport;
|
||||
|
||||
class BasicSlackTest : public Swift::XMPPParserClient {
|
||||
class BasicSlackTest {
|
||||
|
||||
public:
|
||||
void setMeUp (void);
|
||||
|
|
|
@ -35,7 +35,7 @@ using namespace Transport;
|
|||
|
||||
void BasicTest::setMeUp (void) {
|
||||
streamEnded = false;
|
||||
std::istringstream ifs("service.server_mode = 1\nservice.jid=localhost\nservice.more_resources=1\n");
|
||||
std::istringstream ifs("service.server_mode = 1\nservice.jid=localhost\nservice.more_resources=1\nservice.admin_jid=me@localhost\n");
|
||||
cfg = new Config();
|
||||
cfg->load(ifs);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue