diff options
Diffstat (limited to 'server')
| -rw-r--r-- | server/src/.cvsignore | 3 | ||||
| -rw-r--r-- | server/src/Makefile.am | 4 | ||||
| -rw-r--r-- | server/src/admin_connection.cc | 36 | ||||
| -rw-r--r-- | server/src/admin_connection.h | 2 | ||||
| -rw-r--r-- | server/src/admin_export.cc | 273 | ||||
| -rw-r--r-- | server/src/admin_export.h | 37 | ||||
| -rw-r--r-- | server/src/httpd.cc | 8 | 
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);    }  | 
