Web interface: Working adding and removing users

This commit is contained in:
Jan Kaluza 2016-01-21 07:40:18 +01:00
parent 91fae24a09
commit 6fdc1635e4
11 changed files with 7424 additions and 321 deletions

View file

@ -246,6 +246,75 @@ void APIServer::serve_instances_register_form(Server *server, Server::session *s
send_json(conn, json);
}
void APIServer::serve_users(Server *server, Server::session *session, struct mg_connection *conn, struct http_message *hm) {
ALLOW_ONLY_ADMIN();
Document json;
json.SetObject();
json.AddMember("error", 0, json.GetAllocator());
std::vector<std::string> list;
m_storage->getUsers(list);
Value users(kArrayType);
BOOST_FOREACH(std::string &id, list) {
Value user;
user.SetObject();
user.AddMember("username", id.c_str(), json.GetAllocator());
users.PushBack(user, json.GetAllocator());
}
json.AddMember("users", users, json.GetAllocator());
send_json(conn, json);
}
void APIServer::serve_users_add(Server *server, Server::session *session, struct mg_connection *conn, struct http_message *hm) {
std::string user = get_http_var(hm, "username");
std::string password = get_http_var(hm, "password");
if (!user.empty() && !password.empty()) {
if (m_storage) {
UserInfo dummy;
bool registered = m_storage->getUser(user, dummy);
if (!registered) {
UserInfo info;
info.jid = user;
info.password = password;
m_storage->setUser(info);
}
else {
send_ack(conn, true, "This user is already registered");
return;
}
}
else {
send_ack(conn, false, "Storage backend is not configured.");
}
}
else {
send_ack(conn, true, "Username or password has not been provided.");
return;
}
send_ack(conn, false, "");
}
void APIServer::serve_users_remove(Server *server, Server::session *session, struct mg_connection *conn, struct http_message *hm) {
ALLOW_ONLY_ADMIN();
std::string uri(hm->uri.p, hm->uri.len);
std::string user = uri.substr(uri.rfind("/") + 1);
if (!m_storage) {
return;
}
UserInfo info;
m_storage->getUser(user, info);
m_storage->removeUser(info.id);
send_ack(conn, false, "");
}
void APIServer::handleRequest(Server *server, Server::session *sess, struct mg_connection *conn, struct http_message *hm) {
if (has_prefix(&hm->uri, "/api/v1/instances/start/")) {
serve_instances_start(server, sess, conn, hm);
@ -262,6 +331,15 @@ void APIServer::handleRequest(Server *server, Server::session *sess, struct mg_c
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/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);
}
else if (mg_vcmp(&hm->uri, "/api/v1/users") == 0) {
serve_users(server, sess, conn, hm);
}
else if (mg_vcmp(&hm->uri, "/api/v1/instances") == 0) {
serve_instances(server, sess, conn, hm);
}

View file

@ -58,6 +58,9 @@ 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_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);

View file

@ -8,8 +8,8 @@
<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">
<script src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>
<script src="/js/jquery.js"></script>
<script src="/js/jquery-ui.js"></script>
<script src="/js/jquery.cookie.js"></script>
<script src="/js/app.js"></script>
<title>Spectrum 2</title>

View file

@ -50,6 +50,34 @@ function show_instances() {
});
}
function show_users() {
var admin = $.cookie("admin") == "1";
if (!admin) {
$("#main_content").html("<h2>List of Spectrum 2 users</h2><p>Only administrator can list the users.</p>");
return;
}
$.get($.cookie("base_location") + "api/v1/users", function(data) {
$("#main_content").html("<h2>List of Spectrum 2 users</h2><p>You can add new users <a href=\"register.shtml?back_to_list=1\">here</a>.</p><table id='main_result'><tr><th>Name<th>Actions</th></tr>");
$.each(data.users, function(i, user) {
var row = '<tr>'
row += '<td>' + user.username + '</td>'
row += '<td><a class="button_command" href="' + $.cookie("base_location") + 'api/v1/users/remove/' + user.username + '">remove</a></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');
var url = $(this).attr('href');
$.get(url, function(data) {
show_users();
});
})
});
});
}
function getQueryParams(qs) {
qs = qs.split('+').join(' ');
@ -79,7 +107,12 @@ function fill_instances_register_form() {
};
$.post($.cookie("base_location") + "api/v1/instances/register/" + $("#instance").val(), postdata, function(data) {
window.location.replace("index.shtml");
if (data.oauth2_url) {
window.location.replace(data.oauth2_url);
}
else {
window.location.replace("index.shtml");
}
});
})
@ -94,3 +127,25 @@ function fill_instances_register_form() {
});
}
function fill_users_register_form() {
$(".button").click(function(e) {
e.preventDefault();
$(this).parent().empty().progressbar( {value: false} ).css('height', '1em');
var postdata ={
"username": $("#username").val(),
"password": $("#password").val()
};
$.post($.cookie("base_location") + "api/v1/users/add", postdata, function(data) {
var query = getQueryParams(document.location.search);
if (query.back_to_list == "1") {
window.location.replace("list.shtml");
}
else {
window.location.replace("../login/");
}
});
})
}

File diff suppressed because one or more lines are too long

7179
spectrum_manager/src/html/js/jquery.js vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -34,7 +34,7 @@
<div id="main_content_wrap" class="outer">
<section id="main_content" class="inner">
<p>If you don't have Spectrum 2 master account yet, you can <a href="/users">Register it here</a>. You will be able to manager your Spectrum 2 IM transports after that.</p>
<p>If you don't have Spectrum 2 master account yet, you can <a href="/users/register.shtml">Register it here</a>. You will be able to manager your Spectrum 2 IM transports after that.</p>
<form action="/authorize" class="basic-grey" method="POST">
<h1>Login form

View file

@ -0,0 +1,9 @@
<!--#include virtual="/header.shtml" -->
<script type="text/javascript">
$(function() {
show_users();
});
</script>
<!--#include virtual="/footer.shtml" -->

View file

@ -0,0 +1,28 @@
<!--#include virtual="/header.shtml" -->
<h2>Register new Spectrum 2 maanger account</h2>
<form action="/api/v1/users/add" class="basic-grey" method="POST">
<h1>Register user
<span>Register new user to Spectrum 2 manager web interface.</span>
</h1>
<label>
<span>Username:</span>
<input type="text" id="username" name="username" placeholder="Username"></textarea>
</label>
<label><span>Password:</span>
<input type="password" id="password" name="password" placeholder="Password"></textarea>
</label>
<label>
<span>&nbsp;</span>
<input type="submit" class="button" value="Add user" />
</label>
</form><br/>
<script type="text/javascript">
$(function() {
fill_users_register_form();
});
</script>
<!--#include virtual="/footer.shtml" -->

View file

@ -300,69 +300,69 @@ std::string Server::send_command(const std::string &jid, const std::string &cmd)
return response;
}
void Server::serve_onlineusers(struct mg_connection *conn, struct http_message *hm) {
Server:session *session = get_session(hm);
if (!session->admin) {
redirect_to(conn, hm, "/");
return;
}
std::string html;
std::string jid = get_http_var(hm, "jid");
html += std::string("<h2>") + jid + " online users</h2><table><tr><th>JID<th>Command</th></tr>";
Swift::SimpleEventLoop eventLoop;
Swift::BoostNetworkFactories networkFactories(&eventLoop);
ask_local_server(m_config, networkFactories, jid, "online_users");
eventLoop.runUntilEvents();
while(get_response().empty()) {
eventLoop.runUntilEvents();
}
std::string response = get_response();
std::vector<std::string> users;
boost::split(users, response, boost::is_any_of("\n"));
BOOST_FOREACH(std::string &user, users) {
html += "<tr><td>" + user + "</td><td></td></tr>";
}
html += "</table><a href=\"/\">Back to main page</a>";
html += "</body></html>";
print_html(conn, hm, html);
}
void Server::serve_cmd(struct mg_connection *conn, struct http_message *hm) {
Server:session *session = get_session(hm);
if (!session->admin) {
redirect_to(conn, hm, "/");
return;
}
std::string html;
std::string jid = get_http_var(hm, "jid");
std::string cmd = get_http_var(hm, "cmd");
html += std::string("<h2>") + jid + " command result</h2>";
Swift::SimpleEventLoop eventLoop;
Swift::BoostNetworkFactories networkFactories(&eventLoop);
ask_local_server(m_config, networkFactories, jid, cmd);
while(get_response().empty()) {
eventLoop.runUntilEvents();
}
std::string response = get_response();
html += "<pre>" + response + "</pre>";
html += "<a href=\"/\">Back to main page</a>";
html += "</body></html>";
print_html(conn, hm, html);
}
// void Server::serve_onlineusers(struct mg_connection *conn, struct http_message *hm) {
// Server:session *session = get_session(hm);
// if (!session->admin) {
// redirect_to(conn, hm, "/");
// return;
// }
//
// std::string html;
// std::string jid = get_http_var(hm, "jid");
//
// html += std::string("<h2>") + jid + " online users</h2><table><tr><th>JID<th>Command</th></tr>";
//
// Swift::SimpleEventLoop eventLoop;
// Swift::BoostNetworkFactories networkFactories(&eventLoop);
//
// ask_local_server(m_config, networkFactories, jid, "online_users");
// eventLoop.runUntilEvents();
// while(get_response().empty()) {
// eventLoop.runUntilEvents();
// }
//
// std::string response = get_response();
// std::vector<std::string> users;
// boost::split(users, response, boost::is_any_of("\n"));
//
// BOOST_FOREACH(std::string &user, users) {
// html += "<tr><td>" + user + "</td><td></td></tr>";
// }
//
// html += "</table><a href=\"/\">Back to main page</a>";
// html += "</body></html>";
// print_html(conn, hm, html);
// }
//
// void Server::serve_cmd(struct mg_connection *conn, struct http_message *hm) {
// Server:session *session = get_session(hm);
// if (!session->admin) {
// redirect_to(conn, hm, "/");
// return;
// }
//
// std::string html;
// std::string jid = get_http_var(hm, "jid");
// std::string cmd = get_http_var(hm, "cmd");
//
// html += std::string("<h2>") + jid + " command result</h2>";
//
// Swift::SimpleEventLoop eventLoop;
// Swift::BoostNetworkFactories networkFactories(&eventLoop);
//
// ask_local_server(m_config, networkFactories, jid, cmd);
// while(get_response().empty()) {
// eventLoop.runUntilEvents();
// }
//
// std::string response = get_response();
//
// html += "<pre>" + response + "</pre>";
//
// html += "<a href=\"/\">Back to main page</a>";
// html += "</body></html>";
// print_html(conn, hm, html);
// }
void Server::serve_logout(struct mg_connection *conn, struct http_message *hm) {
std::string host;
@ -498,236 +498,6 @@ void Server::serve_users(struct mg_connection *conn, struct http_message *hm) {
print_html(conn, hm, html);
}
void Server::serve_instances_start(struct mg_connection *conn, struct http_message *hm) {
Server:session *session = get_session(hm);
if (!session->admin) {
redirect_to(conn, hm, "/");
return;
}
std::string html;
std::string jid = get_http_var(hm, "jid");
if (jid.empty()) {
redirect_to(conn, hm, "/");
return;
}
start_instances(m_config, jid);
html += "<h2>Starting Spectrum 2 instance</h2>";
html += "<b>" + get_response() + "</b><br/><a href=\"/\">Back to main page</a>";
print_html(conn, hm, html);
}
void Server::serve_instances_stop(struct mg_connection *conn, struct http_message *hm) {
Server:session *session = get_session(hm);
if (!session->admin) {
redirect_to(conn, hm, "/");
return;
}
std::string html;
std::string jid = get_http_var(hm, "jid");
stop_instances(m_config, jid);
html += "<b>" + get_response() + "</b><br/><a href=\"/\">Back to main page</a>";
html += "</body></html>";
print_html(conn, hm, html);
}
void Server::serve_instance(struct mg_connection *conn, struct http_message *hm, const std::string &jid) {
std::string html = "<h2>Spectrum 2 instance: " + jid + "</h2>";
print_html(conn, hm, html);
}
void Server::serve_instances_unregister(struct mg_connection *conn, struct http_message *hm) {
std::string instance = get_http_var(hm, "instance");
if (instance.empty()) {
serve_instances(conn, hm);
return;
}
Server:session *session = get_session(hm);
UserInfo info;
m_storage->getUser(session->user, info);
std::string value = "";
int type = (int) TYPE_STRING;
m_storage->getUserSetting(info.id, instance, type, value);
if (!value.empty()) {
std::string response = send_command(instance, "unregister " + value);
if (!response.empty()) {
value = "";
m_storage->updateUserSetting(info.id, instance, value);
}
}
redirect_to(conn, hm, "/instances");
}
void Server::serve_instances_register(struct mg_connection *conn, struct http_message *hm) {
std::string instance = get_http_var(hm, "instance");
if (instance.empty()) {
serve_instances(conn, hm);
return;
}
std::string jid = get_http_var(hm, "jid");
std::string uin = get_http_var(hm, "uin");
std::string password = get_http_var(hm, "password");
Server:session *session = get_session(hm);
UserInfo info;
m_storage->getUser(session->user, info);
if (jid.empty() || uin.empty() || password.empty()) {
std::string response = send_command(instance, "registration_fields");
std::vector<std::string> fields;
boost::split(fields, response, boost::is_any_of("\n"));
if (fields.size() < 3) {
fields.clear();
fields.push_back("Jabber ID");
fields.push_back("3rd-party network username");
fields.push_back("3rd-party network password");
}
std::string html = "<h2>Register Spectrum 2 instance</h2>";
html += "<form action=\"/instances/register\" class=\"basic-grey\" method=\"POST\"> \
<h1>Register Spectrum 2 instance \
<span>Write the " + fields[0] + ", " + fields[1] + " and " + fields[2] + ".</span> \
</h1> \
<label> \
<span>" + fields[0] + ":</span> \
<input type=\"text\" id=\"jid\" name=\"jid\" placeholder=\""+ fields[0] +"\"></textarea> \
</label> \
<label> \
<span>" + fields[1] + ":</span> \
<input type=\"text\" id=\"uin\" name=\"uin\" placeholder=\"" + fields[1] + "\"></textarea> \
</label> \
<label><span>" + fields[2] + ":</span> \
<input type=\"password\" id=\"password\" name=\"password\" placeholder=\"" + fields[2] + "\"></textarea> \
</label> \
<label> \
<span>&nbsp;</span> \
<input type=\"submit\" class=\"button\" value=\"Register\" />\
</label> \
<input type=\"hidden\" name=\"instance\" value=\"" + instance + "\"></input> \
</form><br/>";
print_html(conn, hm, html);
}
else {
std::string response = send_command(instance, "register " + jid + " " + uin + " " + password);
if (!response.empty()) {
std::string value = jid;
int type = (int) TYPE_STRING;
m_storage->updateUserSetting(info.id, instance, value);
}
response = send_command(instance, "get_oauth2_url " + jid);
if (!response.empty()) {
redirect_to(conn, hm, response.c_str());
return;
}
redirect_to(conn, hm, "/instances");
}
}
void Server::serve_instances(struct mg_connection *conn, struct http_message *hm) {
std::string jid = get_http_var(hm, "jid");
if (!jid.empty()) {
serve_instance(conn, hm, jid);
return;
}
std::vector<std::string> list = show_list(m_config, false);
std::string html = "<h2>List of Spectrum 2 instances</h2>";
Server:session *session = get_session(hm);
if (session->admin) {
if (list.empty()) {
html += "<p>There are no Spectrum 2 instances yet. You can create new instance by adding configuration files into <pre>/etc/spectrum2/transports</pre> directory. You can then maintain the Spectrum 2 instance here.</p>";
}
else {
html += "<table><tr><th>Hostname<th>Status</th><th>Command</th><th>Run command</th></tr>";
BOOST_FOREACH(std::string &instance, list) {
html += "<tr>";
html += "<td><a href=\"/instances?jid=" + instance + "\">" + instance + "</a></td>";
std::string response = send_command(instance, "status");
if (response.empty()) {
response = "Cannot get the server status";
}
html += "<td>" + response + "</td>";
if (response.find("Running") == 0) {
html += "<td><a href=\"/instances/stop?jid=" + instance + "\">Stop</a></td>";
html += "<td><form action=\"/cmd\">";
html += "<input type=\"hidden\" name=\"jid\" value=\"" + instance + "\"></input>";
html += "<input type=\"text\" name=\"cmd\"></input>";
html += "<input type=\"submit\" value=\"Run\"></input>";
html += "</form></td>";
}
else {
html += "<td><a href=\"/instances/start?jid=" + instance + "\">Start</a></td>";
html += "<td></td>";
}
html += "</tr>";
}
html += "</table>";
}
}
else {
UserInfo info;
m_storage->getUser(session->user, info);
if (list.empty()) {
html += "<p>There are no Spectrum 2 instances yet.</p>";
}
else {
html += "<table><tr><th>Hostname<th>Status</th><th>Action</th></tr>";
BOOST_FOREACH(std::string &instance, list) {
html += "<tr>";
html += "<td><a href=\"/instances?jid=" + instance + "\">" + instance + "</a></td>";
std::string response = send_command(instance, "status");
if (response.empty()) {
response = "Cannot get the server status";
}
if (response.find("Running") == 0) {
std::string value = "";
int type = (int) TYPE_STRING;
m_storage->getUserSetting(info.id, instance, type, value);
if (!value.empty()) {
html += "<td>Running. Registered as " + value + "</td>";
html += "<td><a href=\"/instances/unregister?instance=" + instance + "\">Unregister</a></td>";
}
else {
html += "<td>Running. No account registered yet.</td>";
html += "<td><a href=\"/instances/register?instance=" + instance + "\">Register</a></td>";
}
}
else {
html += "<td>" + response + "</td>";
html += "<td>No available action</td>";
}
html += "</tr>";
}
html += "</table>";
}
}
print_html(conn, hm, html);
}
void Server::serve_oauth2(struct mg_connection *conn, struct http_message *hm) {
std::cout << "OAUTH2 handler\n";
}
@ -757,24 +527,8 @@ void Server::event_handler(struct mg_connection *conn, int ev, void *p) {
redirect_to(conn, hm, "/login");
} else if (mg_vcmp(&hm->uri, "/authorize") == 0) {
authorize(conn, hm);
// } else if (mg_vcmp(&hm->uri, "/") == 0) {
// serve_instances(conn, hm);
} else if (mg_vcmp(&hm->uri, "/logout") == 0) {
serve_logout(conn, hm);
// } else if (mg_vcmp(&hm->uri, "/instances") == 0) {
// serve_instances(conn, hm);
// } else if (mg_vcmp(&hm->uri, "/onlineusers") == 0) {
// serve_onlineusers(conn, hm);
// } else if (mg_vcmp(&hm->uri, "/cmd") == 0) {
// serve_cmd(conn, hm);
// } else if (mg_vcmp(&hm->uri, "/instances/start") == 0) {
// serve_instances_start(conn, hm);
// } else if (mg_vcmp(&hm->uri, "/instances/stop") == 0) {
// serve_instances_stop(conn, hm);
// } else if (mg_vcmp(&hm->uri, "/instances/register") == 0) {
// serve_instances_register(conn, hm);
// } else if (mg_vcmp(&hm->uri, "/instances/unregister") == 0) {
// serve_instances_unregister(conn, hm);
// } else if (mg_vcmp(&hm->uri, "/users") == 0) {
// serve_users(conn, hm);
// } else if (mg_vcmp(&hm->uri, "/users/add") == 0) {

View file

@ -66,18 +66,10 @@ class Server {
std::string send_command(const std::string &jid, const std::string &cmd);
private:
void serve_instance(struct mg_connection *conn, struct http_message *hm, const std::string &jid);
void serve_instances(struct mg_connection *conn, struct http_message *hm);
void serve_instances_start(struct mg_connection *conn, struct http_message *hm);
void serve_instances_stop(struct mg_connection *conn, struct http_message *hm);
void serve_instances_register(struct mg_connection *conn, struct http_message *hm);
void serve_instances_unregister(struct mg_connection *conn, struct http_message *hm);
void serve_users(struct mg_connection *conn, struct http_message *hm);
void serve_users_add(struct mg_connection *conn, struct http_message *hm);
void serve_users_remove(struct mg_connection *conn, struct http_message *hm);
void serve_logout(struct mg_connection *conn, struct http_message *hm);
void serve_onlineusers(struct mg_connection *conn, struct http_message *hm);
void serve_cmd(struct mg_connection *conn, struct http_message *hm);
void serve_oauth2(struct mg_connection *conn, struct http_message *hm);
void print_html(struct mg_connection *conn, struct http_message *hm, const std::string &html);