summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordeva <deva>2011-02-14 10:43:17 +0000
committerdeva <deva>2011-02-14 10:43:17 +0000
commitdc8cfaa08168fdd332faded2f78679a2a1904fbe (patch)
tree27d9939d1e8c57f98e819c25ae1a0021c1b97435
parentc1f0cdeb919864e0f93fcfecb8c27d889b473acb (diff)
'Ported' export functionality from macrotool.
-rw-r--r--server/src/.cvsignore3
-rw-r--r--server/src/Makefile.am4
-rw-r--r--server/src/admin_connection.cc36
-rw-r--r--server/src/admin_connection.h2
-rw-r--r--server/src/admin_export.cc273
-rw-r--r--server/src/admin_export.h37
-rw-r--r--server/src/httpd.cc8
7 files changed, 354 insertions, 9 deletions
diff --git a/server/src/.cvsignore b/server/src/.cvsignore
index 84de0d4..d9614bd 100644
--- a/server/src/.cvsignore
+++ b/server/src/.cvsignore
@@ -5,4 +5,7 @@ Makefile
.deps
test_*
tests.make
+*.gcov
+*.gcno
+*.gcda
Makefile.am.test \ No newline at end of file
diff --git a/server/src/Makefile.am b/server/src/Makefile.am
index bf5326a..8d7a0de 100644
--- a/server/src/Makefile.am
+++ b/server/src/Makefile.am
@@ -13,6 +13,9 @@ pracrod_CXXFLAGS = $(PQXX_CXXFLAGS) $(CONFIG_CXXFLAGS) \
pracrod_SOURCES = \
pracrod.cc \
admin_connection.cc \
+ admin_export.cc \
+ macrotool/fieldnamescanner.cc \
+ macrotool/util.cc \
admin_rc.cc \
artefact.cc \
client_connection.cc \
@@ -67,6 +70,7 @@ pracrod_SOURCES = \
EXTRA_DIST = \
artefact.h \
admin_connection.h \
+ admin_export.h \
admin_rc.h \
client_connection.h \
configuration.h \
diff --git a/server/src/admin_connection.cc b/server/src/admin_connection.cc
index e8c5b02..e470946 100644
--- a/server/src/admin_connection.cc
+++ b/server/src/admin_connection.cc
@@ -28,6 +28,7 @@
#include "admin_connection.h"
#include "admin_rc.h"
+#include "admin_export.h"
#include "debug.h"
@@ -55,7 +56,10 @@ static std::string admin_listactivesessions(Environment &env)
std::vector<std::string> act = env.sessions.activeSessions();
std::vector<std::string>::iterator i = act.begin();
while(i != act.end()) {
- str += "Session " + *i + "\n";
+ Session *s = env.sessions.session(*i);
+ SessionAutolock lock(*s);
+ str += "Session " + *i + ": "+s->templ+" on "+s->patientid+" "+
+ std::string(s->active()?"[active]":"[idle]")+"\n";
i++;
}
@@ -80,6 +84,8 @@ AdminConnection::~AdminConnection() {}
bool AdminConnection::handle(const char *data, size_t size)
{
+ status = 200; // OK
+
if(data == NULL && size == 0) {
DEBUG(admin, "URI: %s\n", uri.c_str());
@@ -89,6 +95,7 @@ bool AdminConnection::handle(const char *data, size_t size)
"<strong>/sessionunlock?id=<em>[ID]</em></strong> unlock session with [ID] as its session id.\n"
"<strong>/listactivesessions</strong> lists all active sessions on the server.\n"
"<strong>/flushsessions</strong> flushes all active sessions to disc.\n"
+ "<strong>/export?template=<em>[TEMPLATE]</em></strong> export template with name [TEMPLATE] to a\n csf file (comma seperated file, that can be opened in OOCalc or Excel).\n"
+ admin_rc("footer");
return true;
}
@@ -106,17 +113,31 @@ bool AdminConnection::handle(const char *data, size_t size)
}
if(uri == "/flushsessions") {
- reply = admin_header(uri) + admin_flush(env)
- + admin_rc("footer");
+ reply = admin_header(uri) + admin_flush(env) + admin_rc("footer");
+ return true;
+ }
+
+ if(uri == "/export" && args.find("template") != args.end()) {
+ bool ok;
+ std::string res = admin_export(env, args["template"], &ok);
+ if(!ok) reply = admin_header(uri) + res + admin_rc("footer");
+ else {
+ reply = res;
+ hdrs["Content-Type"] = "text/csv; charset=UTF-8";
+ hdrs["Content-Disposition"] = "attachment; filename=\""+args["template"]+".csv\"";
+ }
return true;
}
if(uri == "/favicon.ico") {
+ hdrs["Content-Type"] = "image/ico";
reply = admin_rc("favicon");
return true;
}
- reply = "'" + uri + "' not recognised as a valid command.";
+ reply = admin_header(uri) +
+ "'" + uri + "' not recognised as a valid command."
+ + admin_rc("footer");
return true;
}
@@ -125,11 +146,10 @@ bool AdminConnection::handle(const char *data, size_t size)
void AdminConnection::getReply(Httpd::Reply &r)
{
- headers_t hdrs;
- if(uri == "/favicon.ico") hdrs["Content-Type"] = "image/ico";
- else hdrs["Content-Type"] = "text/html; charset=UTF-8";
+ if(hdrs.find("Content-Type") == hdrs.end())
+ hdrs["Content-Type"] = "text/html; charset=UTF-8";
r.data = reply;
r.headers = hdrs;
- r.status = 200; // http 'OK'
+ r.status = status; // http 'OK'
}
diff --git a/server/src/admin_connection.h b/server/src/admin_connection.h
index 1533d79..4a413a6 100644
--- a/server/src/admin_connection.h
+++ b/server/src/admin_connection.h
@@ -47,6 +47,8 @@ private:
headers_t args;
std::string uri;
+ int status;
+ headers_t hdrs;
std::string reply;
};
diff --git a/server/src/admin_export.cc b/server/src/admin_export.cc
new file mode 100644
index 0000000..9475bc3
--- /dev/null
+++ b/server/src/admin_export.cc
@@ -0,0 +1,273 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * admin_export.cc
+ *
+ * Fri Feb 11 11:43:13 CET 2011
+ * Copyright 2011 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "admin_export.h"
+
+#include <config.h>
+#include <stdio.h>
+#include "debug.h"
+
+#ifndef WITHOUT_DB
+
+#include <stdlib.h>
+#include <pqxx/pqxx>
+
+#include "macrotool/fieldnamescanner.h"
+#include "configuration.h"
+
+#define SEP "\t"
+
+static std::string escape(std::string &str)
+{
+ std::string out = "\"";
+ std::string::iterator i = str.begin();
+ while(i != str.end()) {
+ if(*i == '\"') out += "''";
+ else out += *i;
+ i++;
+ }
+ out += "\"";
+ return out;
+}
+
+class File {
+public:
+ File(fieldnames_t &f, pqxx::work &w)
+ : work(w), fieldnames(f)
+ {
+ // name += ".csf";
+ // fp = fopen(name.c_str(), "w");
+
+ pos["id"] = 0;
+ pos["patientid"] = 1;
+ pos["time"] = 2;
+ pos["template"] = 3;
+
+ //printf("%s\n", n.c_str());
+
+ size_t idx = 4;
+ fieldnames_t::iterator i = f.begin();
+ while(i != f.end()) {
+ //printf("%s ", i->c_str());
+ pos[*i] = idx;
+ idx++;
+ i++;
+ }
+ // printf("\n");
+
+ output_header();
+ }
+
+ ~File()
+ {
+ // if(fp) fclose(fp);
+ }
+
+ void output_header()
+ {
+ beginrow();
+ addcell("id", "ID");
+ addcell("patientid", "Patient");
+ addcell("time", "Time");
+ addcell("template", "Template");
+
+ {
+ pqxx::result result =
+ work.exec("SELECT DISTINCT ON(name) name, caption FROM fieldnames"
+ " WHERE extract='true';");
+ pqxx::result::const_iterator ri = result.begin();
+ for(unsigned int r = 0; r < result.size(); r++) {
+ pqxx::result::tuple tuple = result.at(r);
+ std::string name = tuple.at(0).c_str();
+ std::string caption = tuple.at(1).c_str();
+ addcell(name, caption);
+ }
+ }
+
+ endrow();
+ }
+
+ void beginrow()
+ {
+ cells.clear();
+ cells.insert(cells.begin(), pos.size(), "");
+ }
+
+ void addcell(std::string key, std::string value)
+ {
+ if(pos.find(key) == pos.end()) return;
+ cells[pos[key]] = value;
+ }
+
+ void endrow()
+ {
+ std::vector<std::string>::iterator i = cells.begin();
+ while(i != cells.end()) {
+ result += escape(*i) + SEP;
+ i++;
+ }
+ result += "\n";
+ }
+
+ std::string result;
+
+private:
+ pqxx::work &work;
+ std::map<std::string, int> pos;
+ std::vector<std::string> cells;
+ std::string name;
+ fieldnames_t &fieldnames;
+};
+
+
+static std::string do_export(std::string templ, bool *ok)
+{
+ if(Conf::database_backend != "pgsql") {
+ *ok = false;
+ return "ERROR: Export only available for the pgsql database backend.\n";
+ }
+
+ std::string host = Conf::database_addr;
+ std::string port = "";//Conf::database_port;
+ std::string user = Conf::database_user;;
+ std::string passwd = Conf::database_passwd;
+ std::string dbname = "";//Conf::database_database;
+
+ std::string cs;
+ if(host.size()) cs += " host=" + host;
+ if(port.size()) cs += " port=" + port;
+ if(user.size()) cs += " user=" + user;
+ if(passwd.size()) cs += " password=" + passwd;
+ cs += " dbname=" + (dbname.size() ? dbname : "pracro");
+
+ pqxx::connection conn(cs);
+ pqxx::work work(conn);
+
+ std::set<std::string> filter;
+
+ {
+ pqxx::result result =
+ work.exec("SELECT DISTINCT name FROM fieldnames"
+ " WHERE extract='true';");
+ pqxx::result::const_iterator ri = result.begin();
+ for(unsigned int r = 0; r < result.size(); r++) {
+ pqxx::result::tuple tuple = result.at(r);
+ std::string name = tuple.at(0).c_str();
+ filter.insert(name);
+ //printf("filter: '%s'\n", name.c_str());
+ }
+ }
+
+ templates_t t = scanfieldnames(filter);
+ /*
+ templates_t::iterator ti = t.begin();
+ while(ti != t.end()) {
+ printf("%s\n", ti->first.c_str());
+ fieldnames_t::iterator fi = ti->second.begin();
+ while(fi != ti->second.end()) {
+ printf("\t%s\n", (*fi).c_str());
+ fi++;
+ }
+ ti++;
+ }
+ */
+
+ File file(t[templ], work);
+
+ {
+ pqxx::result result =
+ work.exec("SELECT * FROM commits WHERE template='"+templ+"'"
+ " AND status='committed' ORDER BY patientid, timestamp;");
+ pqxx::result::const_iterator ri = result.begin();
+ for(unsigned int r = 0; r < result.size(); r++) {
+ pqxx::result::tuple tuple = result.at(r);
+ std::string patientid = tuple.at(0).c_str();
+ std::string templ = tuple.at(1).c_str();
+ std::string version = tuple.at(2).c_str();
+ std::string timestamp = tuple.at(3).c_str();
+ std::string uid = tuple.at(4).c_str();
+ std::string status = tuple.at(5).c_str();
+
+ file.beginrow();
+ file.addcell("id", uid);
+ file.addcell("patientid", patientid);
+ file.addcell("template", templ);
+ time_t t = atol(timestamp.c_str());
+ std::string timestr = ctime(&t);
+ if(timestr[timestr.size() - 1] == '\n')
+ timestr = timestr.substr(0, timestr.size() - 1);
+ file.addcell("time", timestr.c_str());
+
+ DEBUG(export, "%s %s %s\n",
+ timestamp.c_str(), patientid.c_str(), templ.c_str());
+
+ {
+ pqxx::result result =
+ work.exec("SELECT f.name, f.value"
+ " FROM transactions t, fields f, fieldnames n"
+ " WHERE t.cid='"+uid+"' AND f.transaction=t.uid"
+ " AND f.name=n.name AND n.extract='true'"
+ " ORDER BY t.timestamp;");
+ pqxx::result::const_iterator ri = result.begin();
+ for(unsigned int r = 0; r < result.size(); r++) {
+ pqxx::result::tuple tuple = result.at(r);
+ std::string name = tuple.at(0).c_str();
+ std::string value = tuple.at(1).c_str();
+
+ file.addcell(name, value);
+
+ }
+ }
+
+ file.endrow();
+ }
+ }
+
+ *ok = true;
+ return file.result;
+}
+
+#endif/* WITHOUT_DB */
+
+std::string admin_export(Environment &env, std::string templ, bool *ok)
+{
+ return do_export(templ, ok);
+}
+
+#ifdef TEST_ADMIN_EXPORT
+//deps:
+//cflags:
+//libs:
+#include "test.h"
+
+TEST_BEGIN;
+
+// TODO: Put some testcode here (see test.h for usable macros).
+
+TEST_END;
+
+#endif/*TEST_ADMIN_EXPORT*/
diff --git a/server/src/admin_export.h b/server/src/admin_export.h
new file mode 100644
index 0000000..69c7a36
--- /dev/null
+++ b/server/src/admin_export.h
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * admin_export.h
+ *
+ * Fri Feb 11 11:43:13 CET 2011
+ * Copyright 2011 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#ifndef __PRACRO_ADMIN_EXPORT_H__
+#define __PRACRO_ADMIN_EXPORT_H__
+
+#include <string>
+
+#include "environment.h"
+
+std::string admin_export(Environment &env, std::string templ, bool *ok);
+
+#endif/*__PRACRO_ADMIN_EXPORT_H__*/
diff --git a/server/src/httpd.cc b/server/src/httpd.cc
index ce1a1ce..185ad9d 100644
--- a/server/src/httpd.cc
+++ b/server/src/httpd.cc
@@ -117,7 +117,13 @@ static int request_handler(void *cls,
i++;
}
- ret = MHD_queue_response(con, reply.status, rsp);
+ bool authfailed = true;
+ if(authfailed) {
+ ret = MHD_queue_basic_auth_fail_response(con, "my realm", rsp);
+ } else {
+ ret = MHD_queue_response(con, reply.status, rsp);
+ }
+
MHD_destroy_response(rsp);
}