summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/client.pro6
-rw-r--r--client/collapser.cc2
-rw-r--r--client/docgen/doc.h3
-rw-r--r--client/docgen/docgen.cc87
-rw-r--r--client/docgen/generate.cc40
-rw-r--r--client/docgen/parse.cc18
-rw-r--r--client/docgen/style.css5
-rw-r--r--client/luadb.cc8
-rw-r--r--client/luadb.h53
-rw-r--r--client/luapraxisd.cc10
-rw-r--r--client/mainwindow.cc19
-rw-r--r--client/pcpviewer/pcpviewer.cc3
-rw-r--r--client/pracro_dk.ts82
-rw-r--r--client/praxisd.cc2
-rw-r--r--client/widgets/altcombobox.cc6
-rw-r--r--client/widgets/altcombobox.h3
-rw-r--r--client/widgets/button.h1
-rw-r--r--client/widgets/checkbox.h1
-rw-r--r--client/widgets/checkgroupbox.h1
-rw-r--r--client/widgets/combobox.cc13
-rw-r--r--client/widgets/combobox.h1
-rw-r--r--client/widgets/datetime.h1
-rw-r--r--client/widgets/groupbox.h1
-rw-r--r--client/widgets/label.h1
-rw-r--r--client/widgets/lineedit.h1
-rw-r--r--client/widgets/listbox.h1
-rw-r--r--client/widgets/metawidget.h1
-rw-r--r--client/widgets/multilist.h1
-rw-r--r--client/widgets/radiobuttons.h1
-rw-r--r--client/widgets/textedit.h1
-rw-r--r--client/widgets/widget.h1
-rw-r--r--client/widgets/window.h1
-rw-r--r--server/configure.in6
-rw-r--r--server/src/Makefile.am8
-rw-r--r--server/src/admin_connection.cc137
-rw-r--r--server/src/admin_connection.h3
-rw-r--r--server/src/admin_export.cc21
-rw-r--r--server/src/client_connection.cc61
-rw-r--r--server/src/client_connection.h7
-rw-r--r--server/src/connection.h3
-rw-r--r--server/src/daemon.cc4
-rw-r--r--server/src/debug.cc48
-rw-r--r--server/src/debug.h1
-rw-r--r--server/src/httpd.cc20
-rw-r--r--server/src/journal.cc24
-rw-r--r--server/src/journal.h16
-rw-r--r--server/src/journal_commit.cc1
-rw-r--r--server/src/journal_uploadserver.cc26
-rw-r--r--server/src/journal_uploadserver.h2
-rw-r--r--server/src/luaoncommit.cc70
-rw-r--r--server/src/luaoncommit.h (renamed from server/src/resumeparser.h)27
-rw-r--r--server/src/luapraxisd.cc455
-rw-r--r--server/src/luapraxisd.h215
-rw-r--r--server/src/luaquerymapper.cc46
-rw-r--r--server/src/luaresume.cc121
-rw-r--r--server/src/luaresume.h18
-rw-r--r--server/src/luascript.cc317
-rw-r--r--server/src/luascript.h93
-rw-r--r--server/src/macroparser.cc37
-rw-r--r--server/src/macroparser.h5
-rw-r--r--server/src/mutex.cc14
-rw-r--r--server/src/mutex.h4
-rw-r--r--server/src/pracrod.cc14
-rw-r--r--server/src/pracrodaopgsql.cc66
-rw-r--r--server/src/praxisd.cc129
-rw-r--r--server/src/praxisd.h78
-rw-r--r--server/src/resumeparser.cc81
-rw-r--r--server/src/saxparser.cc2
-rw-r--r--server/src/server.cc13
-rw-r--r--server/src/session.cc86
-rw-r--r--server/src/session.h18
-rw-r--r--server/src/sessionheaderparser.cc182
-rw-r--r--server/src/sessionheaderparser.h101
-rw-r--r--server/src/sessionparser.cc71
-rw-r--r--server/src/sessionparser.h10
-rw-r--r--server/src/sessionserialiser.cc132
-rw-r--r--server/src/sessionserialiser.h5
-rw-r--r--server/src/template.h3
-rw-r--r--server/src/templateparser.cc49
-rw-r--r--server/src/templateparser.h3
-rw-r--r--server/src/transactionhandler.cc71
-rw-r--r--server/src/transactionhandler.h10
82 files changed, 2725 insertions, 584 deletions
diff --git a/client/client.pro b/client/client.pro
index e002942..5e16942 100644
--- a/client/client.pro
+++ b/client/client.pro
@@ -16,15 +16,15 @@ debug {
DEFINES+=USE_DEBUG
}
-DEFINES+=VERSION=\\\"2.2.1\\\"
+DEFINES+=VERSION=\\\"2.2.2\\\"
win32 {
- LIBPATH += lua/lib
+ QMAKE_LIBDIR += lua/lib
INCLUDEPATH += lua/include
LIBS += -llua51
DEFINES += HOST_WIN32
# debug {
- CONFIG += console
+ CONFIG +=
# }
}
diff --git a/client/collapser.cc b/client/collapser.cc
index 2057a0e..abbe295 100644
--- a/client/collapser.cc
+++ b/client/collapser.cc
@@ -32,7 +32,7 @@
#include "debug.h"
-#define ANIM_TIME 100 // ms
+#define ANIM_TIME 200 // ms
#define ANIM_INTERVAL 50 // ms
Collapser::Collapser(QWidget *current, QScrollArea *scroll)
diff --git a/client/docgen/doc.h b/client/docgen/doc.h
index ae693f5..5678476 100644
--- a/client/docgen/doc.h
+++ b/client/docgen/doc.h
@@ -69,6 +69,9 @@ public:
QString title;
QString name;
QString tag;
+ bool serverside;
+ bool clientside;
+ QString classname;
QString extends;
bool container;
QString description;
diff --git a/client/docgen/docgen.cc b/client/docgen/docgen.cc
index e4af0a3..4eb2e08 100644
--- a/client/docgen/docgen.cc
+++ b/client/docgen/docgen.cc
@@ -32,6 +32,7 @@
#include <QDir>
#include <QMap>
#include <QDate>
+#include <QFileInfo>
#include <stdio.h>
@@ -39,7 +40,9 @@
#include "parse.h"
#include "generate.h"
-#define INPUT "../widgets"
+#define WIDGETS_DIR "../widgets"
+#define SERVER_DIR "../../server/src"
+#define CLIENT_DIR ".."
#define OUTPUT "html"
QString output;
@@ -94,16 +97,46 @@ void writeIndex(QMap<QString, Doc> &docs)
out += "<h1>Pracro "VERSION" Documentation</h1>\n";
out += "<h2>Overview</h2>\n";
+ out += "<h3>Clientside</h3>\n";
+ out += "<h4>Widgets</h4>\n";
out += "<ul>\n";
QMap<QString, Doc>::iterator i = docs.begin();
while(i != docs.end()) {
Doc &doc = *i;
- out += "<li><a href=\""+doc.name+".html\">["+doc.name+"]</a> - "+
- doc.title+"</li>\n";
+ if(doc.tag != "") {
+ out += "<li><a href=\""+doc.name+".html\">["+doc.name+"]</a> - "+
+ doc.title+"</li>\n";
+ }
+ i++;
+ }
+ out += "</ul>\n";
+ out += "<h4>Classes</h4>\n";
+ out += "<ul>\n";
+ i = docs.begin();
+ while(i != docs.end()) {
+ Doc &doc = *i;
+ if(doc.classname != "" && doc.clientside) {
+ out += "<li><a href=\""+doc.name+".html\">["+doc.name+"]</a> - "+
+ doc.title+"</li>\n";
+ }
i++;
}
out += "</ul>\n";
+ out += "<h3>Serverside</h3>\n";
+ out += "<ul>\n";
+ i = docs.begin();
+ while(i != docs.end()) {
+ Doc &doc = *i;
+ if(doc.classname != "" && doc.serverside) {
+ out += "<li><a href=\""+doc.name+".html\">["+doc.name+"]</a> - "+
+ doc.title+"</li>\n";
+ }
+ i++;
+ }
+ out += "</ul>\n";
+
+
QFile::remove(output + "/index.html");
QFile ofile(output + "/index.html");
ofile.open(QIODevice::ReadWrite | QIODevice::Text);
@@ -133,15 +166,47 @@ int main(int argc, char *argv[])
QFile::remove(output + "/style.css");
QFile::copy("style.css", output + "/style.css");
- QDir dir(INPUT);
- QStringList filter; filter << "*.h";
- dir.setNameFilters(filter);
+ QStringList files;
+
+ // Widgets
+ {
+ QDir dir(WIDGETS_DIR);
+ QStringList filter; filter << "*.h";
+ dir.setNameFilters(filter);
+ if(!dir.exists()) return 1;
+ QFileInfoList inflst = dir.entryInfoList(QDir::Files);
+ foreach(QFileInfo inf, inflst) {
+ files.append(inf.absoluteFilePath());
+ }
+ }
+
+ // Client
+ {
+ QDir dir(CLIENT_DIR);
+ QStringList filter; filter << "*.h";
+ dir.setNameFilters(filter);
+ if(!dir.exists()) return 1;
+ QFileInfoList inflst = dir.entryInfoList(QDir::Files);
+ foreach(QFileInfo inf, inflst) {
+ files.append(inf.absoluteFilePath());
+ }
+ }
+
+ // Server
+ {
+ QDir dir(SERVER_DIR);
+ QStringList filter; filter << "*.h";
+ dir.setNameFilters(filter);
+ if(!dir.exists()) return 1;
+ QFileInfoList inflst = dir.entryInfoList(QDir::Files);
+ foreach(QFileInfo inf, inflst) {
+ files.append(inf.absoluteFilePath());
+ }
+ }
- if(!dir.exists()) return 1;
- QStringList l = dir.entryList(QDir::Files);
- foreach(QString file, l) {
- Doc doc = parse(QString(INPUT) + "/" + file);
- if(doc.title != "" || doc.tag != "")
+ foreach(QString file, files) {
+ Doc doc = parse(file);
+ if(doc.title != "" || doc.tag != "" || doc.classname != "")
docs[doc.name] = doc;
}
diff --git a/client/docgen/generate.cc b/client/docgen/generate.cc
index b521f1f..f418b24 100644
--- a/client/docgen/generate.cc
+++ b/client/docgen/generate.cc
@@ -219,6 +219,18 @@ QString generate(Doc &doc, QMap<QString, QVector<Method> > &meths,
highlight("<" + doc.tag + " />", xml) + "</pre></div>\n";
}
+ if(doc.serverside)
+ out += " <div class=\"availablility\">Available serverside.</div>\n";
+
+ if(doc.clientside)
+ out += " <div class=\"availablility\">Available clientside.</div>\n";
+
+
+ if(doc.classname != "" ){
+ out += " <div class=\"classname\">Class<pre class=\"code\">" +
+ doc.classname + "</pre></div>\n";
+ }
+
if(doc.container) {
out += " <div class=\"container\">Widget is a container.</div>\n";
}
@@ -248,21 +260,23 @@ QString generate(Doc &doc, QMap<QString, QVector<Method> > &meths,
out += generateExamples(doc.examples, xml);
- out += " <h2>Attributes</h2>\n";
- out += " <div class=\"attributes\">\n";
- if(doc.attributes.size()) {
- out += generateAttributes(doc.attributes);
- }
+ if(doc.tag != "") {
+ out += " <h2>Attributes</h2>\n";
+ out += " <div class=\"attributes\">\n";
+ if(doc.attributes.size()) {
+ out += generateAttributes(doc.attributes);
+ }
- QMap<QString, QVector<Attribute> >::iterator i = atts.begin();
- while(i != atts.end()) {
- out += " <h3>Attributes inherited from <a href=\"" + i.key() +
- ".html\">"+i.key()+"</a>:</h3>\n";
- out += generateAttributes(i.value());
- i++;
+ QMap<QString, QVector<Attribute> >::iterator i = atts.begin();
+ while(i != atts.end()) {
+ out += " <h3>Attributes inherited from <a href=\"" + i.key() +
+ ".html\">"+i.key()+"</a>:</h3>\n";
+ out += generateAttributes(i.value());
+ i++;
+ }
+ out += " </div>\n";
}
- out += " </div>\n";
-
+
out += generateMethodOverview(doc, meths);
out += " <h2>Methods</h2>\n";
diff --git a/client/docgen/parse.cc b/client/docgen/parse.cc
index 64c2aa7..0354f57 100644
--- a/client/docgen/parse.cc
+++ b/client/docgen/parse.cc
@@ -89,6 +89,8 @@ Doc parse(QString filename)
{
Doc doc;
doc.container = false;
+ doc.serverside = false;
+ doc.clientside = false;
QFileInfo fi(filename);
QString name = fi.fileName();
@@ -134,10 +136,26 @@ Doc parse(QString filename)
continue;
}
+ if(state == none && line.left(6) == "@class") {
+ doc.classname = line.right(line.length() - line.indexOf(" ") - 1);
+ doc.name = doc.classname;
+ continue;
+ }
+
if(state == none && line.left(8) == "@extends") {
doc.extends = line.right(line.length() - line.indexOf(" ") - 1);
continue;
}
+
+ if(state == none && line.left(11) == "@serverside") {
+ doc.serverside = true;
+ continue;
+ }
+
+ if(state == none && line.left(11) == "@clientside") {
+ doc.clientside = true;
+ continue;
+ }
if(state == none && line.left(11) == "@screenshot") {
Screenshot s;
diff --git a/client/docgen/style.css b/client/docgen/style.css
index e938648..17f087e 100644
--- a/client/docgen/style.css
+++ b/client/docgen/style.css
@@ -26,6 +26,11 @@ a:hover {
}
.doc .tagname {
+ font-size: 1.5em;
+ text-align: center;
+}
+.doc .classname {
+ font-size: 1.5em;
text-align: center;
}
.doc .extends {}
diff --git a/client/luadb.cc b/client/luadb.cc
index 317831f..a848f36 100644
--- a/client/luadb.cc
+++ b/client/luadb.cc
@@ -77,7 +77,7 @@ typedef struct db_userdata {
DB *db;
} db_userdata;
-static int db_value(lua_State *L)
+int db_value(lua_State *L)
{
db_userdata *dbu;
@@ -91,7 +91,7 @@ static int db_value(lua_State *L)
return 1;
}
-static int db_exec(lua_State *L)
+int db_exec(lua_State *L)
{
db_userdata *dbu;
@@ -105,7 +105,7 @@ static int db_exec(lua_State *L)
return 0;
}
-static int db_next(lua_State *L)
+int db_next(lua_State *L)
{
db_userdata *dbu;
@@ -119,7 +119,7 @@ static int db_next(lua_State *L)
return 1;
}
-static int db_new(lua_State *L)
+int db_new(lua_State *L)
{
const char *driver = luaL_checkstring(L, 1);
const char *host = luaL_checkstring(L, 2);
diff --git a/client/luadb.h b/client/luadb.h
index a87baf5..91c8777 100644
--- a/client/luadb.h
+++ b/client/luadb.h
@@ -30,6 +30,59 @@
#include <lua.hpp>
+/***
+ * Database Class
+ * @class DB
+ * @clientside
+ * The DB class connects and handles communication with the an SQL server using
+ * the QDatabase API.
+ */
+
+/***
+ * @method object DB.new(string driver, string host, string database, string user, string password, int port)
+ * Create a new DB connection object.
+ * @param driver A string containing the QT SQL driver name. QPSQL: postgresql
+ * driver.
+ * @param host The hostname to connect to.
+ * @param database The database to open.
+ * @param user The username to use for authentication.
+ * @param password The password to use for authentication.
+ * @param port The port to connect to.
+ * @return The newly created communication object.
+ * @example Create a new database object:
+ * px = DB.new('QPSQL', 'localhost', 'mydb', 'user01', 'verysecret', '5432')
+ */
+int db_new(lua_State *L);
+
+/***
+ * @method nil exec(string query)
+ * Execute an SQL query.
+ * @param query A string containing the SQL query to execute.
+ */
+int db_exec(lua_State *L);
+
+/***
+ * @method string value(int index)
+ * Get current value from the result of the last query.
+ * @param index The column index number to use for the value retrieval.
+ * @return A string containing the value in the result cell.
+ */
+int db_value(lua_State *L);
+
+/***
+ * @method boolean next()
+ * Iterate to next row in result set.
+ * @return true if another row is availble, false if the end of the list has
+ * been reached.
+ * @example Iterate through a result list and print the value in column 0 in each row:
+ * while db:next()
+ * do
+ * local item = db:value(0)
+ * print(item)
+ * end
+ */
+int db_next(lua_State *L);
+
void register_db(lua_State *L);
#endif/*__PRACRO_LUADB_H__*/
diff --git a/client/luapraxisd.cc b/client/luapraxisd.cc
index 11d619e..00ed961 100644
--- a/client/luapraxisd.cc
+++ b/client/luapraxisd.cc
@@ -72,7 +72,9 @@ static int px_getcave(lua_State *L)
int top = lua_gettop(L);
for(int i = 0; i < cavelist.size(); i++) {
- lua_pushstring(L, QString::fromUtf8(cavelist[i].toStdString().c_str()).toStdString().c_str());
+ QString c = cavelist[i];
+ DEBUG(cavelist, "CAVE '%s'\n", c.toStdString().c_str());
+ lua_pushstring(L, c.toStdString().c_str());
lua_rawseti(L, top, i);
}
@@ -85,7 +87,7 @@ static int px_cavelist(lua_State *L)
pxu = (px_userdata *)luaL_checkudata(L, 1, "Praxisd");
luaL_argcheck(L, pxu, 1, "Praxisd expected");
- QVector<cave_t> cavelist = pxu->px->diverse_get_cave("");
+ QVector<cave_t> cavelist = pxu->px->diverse_get_cave("C");
if(pxu->px->hasError()) {
lua_pushstring(L, pxu->px->errorString().toStdString().c_str());
lua_error(L);
@@ -96,7 +98,9 @@ static int px_cavelist(lua_State *L)
int top = lua_gettop(L);
for(size_t i = 0; i < (size_t)cavelist.size(); i++) {
- lua_pushstring(L, QString::fromUtf8(cavelist[i].cave.toStdString().c_str()).toStdString().c_str());
+ QString c = cavelist[i].cave;
+ DEBUG(cavelist, "CAVE '%s'\n", c.toStdString().c_str());
+ lua_pushstring(L, c.toStdString().c_str());
lua_rawseti(L, top, i);
}
diff --git a/client/mainwindow.cc b/client/mainwindow.cc
index 9e62e5d..756f759 100644
--- a/client/mainwindow.cc
+++ b/client/mainwindow.cc
@@ -172,7 +172,7 @@ void MainWindow::closeCommit()
return;
}
netcom.commit();
- isStored = true;
+ // isStored = true;
closing = true;
}
@@ -186,7 +186,7 @@ void MainWindow::closeNoCommit()
return;
}
netcom.nocommit();
- isStored = true;
+ // isStored = true;
closing = true;
}
@@ -210,7 +210,7 @@ void MainWindow::closeDiscard()
if(res == MessageBox::Yes) {
netcom.discard();
- isStored = true;
+ // isStored = true;
closing = true;
}
}
@@ -233,7 +233,7 @@ void MainWindow::closeEvent(QCloseEvent *event)
== MessageBox::Yes) {
if(!isStored) {
netcom.discard();
- isStored = true;
+ // isStored = true;
closing = true;
event->ignore();
return;
@@ -343,6 +343,9 @@ void MainWindow::updateMacros(QDomNodeList &nodes)
break;
}
}
+
+ QVBoxLayout *l = (QVBoxLayout*)central->layout();
+ l->addStretch(1);
}
}
@@ -391,8 +394,6 @@ void MainWindow::setTemplate(QString name)
void MainWindow::handle(QDomDocument &doc)
{
- if(closing) close();
-
DEBUG(mainwindow, "Handle %s\n",
doc.toString().toStdString().c_str());
@@ -403,6 +404,7 @@ void MainWindow::handle(QDomDocument &doc)
if(element.tagName() == "error") {
showError("Pracro Server Error", element.text());
+ closing = false;
continue;
}
@@ -433,4 +435,9 @@ void MainWindow::handle(QDomDocument &doc)
}
}
+
+ if(closing) {
+ isStored = true;
+ close();
+ }
}
diff --git a/client/pcpviewer/pcpviewer.cc b/client/pcpviewer/pcpviewer.cc
index 5853e0a..ea59edb 100644
--- a/client/pcpviewer/pcpviewer.cc
+++ b/client/pcpviewer/pcpviewer.cc
@@ -42,6 +42,9 @@
PCPViewer::PCPViewer(QString patientid) : praxisd("sarge", 10000)
{
+ setWindowTitle(tr("Pracro Patient View"));
+ setWindowIcon(QIcon(":/icons/icon.png"));
+
this->patientid = patientid;
setLayout(new QVBoxLayout());
diff --git a/client/pracro_dk.ts b/client/pracro_dk.ts
index 9c7fd40..2582280 100644
--- a/client/pracro_dk.ts
+++ b/client/pracro_dk.ts
@@ -2,6 +2,19 @@
<!DOCTYPE TS>
<TS version="2.0" language="da_DK">
<context>
+ <name>AboutBox</name>
+ <message>
+ <location filename="aboutbox.cc" line="40"/>
+ <source>About Pracro</source>
+ <translation>Om Pracro</translation>
+ </message>
+ <message>
+ <location filename="aboutbox.cc" line="72"/>
+ <source>&lt;h1&gt;Pracro Client&lt;/h1&gt;&lt;h2&gt;v.</source>
+ <translation>&lt;h1&gt;Pracro Client&lt;/h1&gt;&lt;h2&gt;v.</translation>
+ </message>
+</context>
+<context>
<name>DBWidget</name>
<message>
<source>Write something in the searchfield</source>
@@ -53,43 +66,43 @@ et CPR nummer på 10 cifre.</translation>
<context>
<name>MacroWindow</name>
<message>
- <location filename="macrowindow.cc" line="177"/>
+ <location filename="macrowindow.cc" line="181"/>
<source>Error</source>
<translation>Der er sket en fejl</translation>
</message>
<message>
- <location filename="macrowindow.cc" line="178"/>
+ <location filename="macrowindow.cc" line="182"/>
<source>The macro </source>
<translation>Makroen </translation>
</message>
<message>
- <location filename="macrowindow.cc" line="179"/>
+ <location filename="macrowindow.cc" line="183"/>
<source> was not filled out correctly, please try again.
</source>
<translation> er ikke.udfyldt korrekt. Prøv igen.</translation>
</message>
<message>
- <location filename="macrowindow.cc" line="213"/>
+ <location filename="macrowindow.cc" line="219"/>
<source>Save the macro changes?</source>
<translation>Gem makro ændringer?</translation>
</message>
<message>
- <location filename="macrowindow.cc" line="214"/>
+ <location filename="macrowindow.cc" line="220"/>
<source>you have choosen to close the macro </source>
<translation>Du har valgt at lukke makroen </translation>
</message>
<message>
- <location filename="macrowindow.cc" line="216"/>
+ <location filename="macrowindow.cc" line="222"/>
<source>do you want to save before closing?</source>
<translation>ønsker du at gemme dine ændringer først?</translation>
</message>
<message>
- <location filename="macrowindow.cc" line="241"/>
+ <location filename="macrowindow.cc" line="247"/>
<source>Close first</source>
<translation>Luk først</translation>
</message>
<message>
- <location filename="macrowindow.cc" line="242"/>
+ <location filename="macrowindow.cc" line="248"/>
<source>Close other one first.</source>
<translation>Luk den åbne makro først.</translation>
</message>
@@ -97,26 +110,26 @@ et CPR nummer på 10 cifre.</translation>
<context>
<name>MainWindow</name>
<message>
- <location filename="mainwindow.cc" line="112"/>
+ <location filename="mainwindow.cc" line="124"/>
<source>Close and commit</source>
<translation>Gem i journal</translation>
</message>
<message>
- <location filename="mainwindow.cc" line="115"/>
+ <location filename="mainwindow.cc" line="127"/>
<source>Close no commit</source>
<translation>Gem som kladde</translation>
</message>
<message>
- <location filename="mainwindow.cc" line="150"/>
- <location filename="mainwindow.cc" line="162"/>
- <location filename="mainwindow.cc" line="174"/>
+ <location filename="mainwindow.cc" line="168"/>
+ <location filename="mainwindow.cc" line="180"/>
+ <location filename="mainwindow.cc" line="192"/>
<source>Close first.</source>
<translation>Luk først.</translation>
</message>
<message>
- <location filename="mainwindow.cc" line="151"/>
- <location filename="mainwindow.cc" line="163"/>
- <location filename="mainwindow.cc" line="175"/>
+ <location filename="mainwindow.cc" line="169"/>
+ <location filename="mainwindow.cc" line="181"/>
+ <location filename="mainwindow.cc" line="193"/>
<source>Close open macros first.</source>
<translation>Luk åbne makroer først.</translation>
</message>
@@ -133,14 +146,14 @@ et CPR nummer på 10 cifre.</translation>
<translation type="obsolete">Denne session bliver husket på denne specifikke maskine. For at genåbne på et senere tidspunkt, skal du blot genåbne på samme patient.</translation>
</message>
<message>
- <location filename="mainwindow.cc" line="181"/>
- <location filename="mainwindow.cc" line="203"/>
+ <location filename="mainwindow.cc" line="199"/>
+ <location filename="mainwindow.cc" line="221"/>
<source>Discard</source>
<translation>Kassér</translation>
</message>
<message>
- <location filename="mainwindow.cc" line="182"/>
- <location filename="mainwindow.cc" line="204"/>
+ <location filename="mainwindow.cc" line="200"/>
+ <location filename="mainwindow.cc" line="222"/>
<source>This session will &lt;strong&gt;NOT&lt;/strong&gt; be stored in the journal.&lt;br/&gt;Are you sure you want to continue?</source>
<translation>Dette vil slette alle indtastede data. Denne session vil &lt;strong&gt;IKKE&lt;/strong&gt; blive gemt i journalen hvis du fortsætter. Fortsætter du kan dataene &lt;strong&gt;IKKE&lt;/strong&gt; gendannes.&lt;br/&gt;Er du sikker på du vil fortsætte?</translation>
</message>
@@ -158,6 +171,25 @@ et CPR nummer på 10 cifre.</translation>
<oldsource>Remove form list</oldsource>
<translation>Fjern fra listen</translation>
</message>
+ <message>
+ <location filename="widgets/multilist.cc" line="133"/>
+ <source>Inner widget changed.</source>
+ <translation>Data er ændret</translation>
+ </message>
+ <message>
+ <location filename="widgets/multilist.cc" line="134"/>
+ <source>The inner widget changed, and you didn&apos;t add it to the list.
+Do you want to continue and discard the change?</source>
+ <translation>Der er indtastet data, som ikke er tilføjet til listen. Ønsker du at fortsætte og glemme disse data?</translation>
+ </message>
+</context>
+<context>
+ <name>PCPViewer</name>
+ <message>
+ <location filename="pcpviewer/pcpviewer.cc" line="45"/>
+ <source>Pracro Patient View</source>
+ <translation>Pracro Patient Oversigt</translation>
+ </message>
</context>
<context>
<name>QObject</name>
@@ -252,9 +284,17 @@ et CPR nummer på 10 cifre.</translation>
<translation>Ignorér</translation>
</message>
<message>
- <location filename="macro.cc" line="121"/>
+ <location filename="macro.cc" line="122"/>
<source>Depends on: </source>
<translation>Afhænger af: </translation>
</message>
</context>
+<context>
+ <name>Template</name>
+ <message>
+ <location filename="template.cc" line="54"/>
+ <source>Open</source>
+ <translation>Ã…bn</translation>
+ </message>
+</context>
</TS>
diff --git a/client/praxisd.cc b/client/praxisd.cc
index 161b471..2fbaddc 100644
--- a/client/praxisd.cc
+++ b/client/praxisd.cc
@@ -221,7 +221,7 @@ void Praxisd::replyFinished(QNetworkReply *reply)
break;
}
} else {
- emit networkError(reply->errorString());
+ emit networkError(reply->errorString() + " - " + reply->readAll());
}
replytypes.erase(replytypes.find(reply));
}
diff --git a/client/widgets/altcombobox.cc b/client/widgets/altcombobox.cc
index 9956fff..082601a 100644
--- a/client/widgets/altcombobox.cc
+++ b/client/widgets/altcombobox.cc
@@ -107,6 +107,12 @@ AltComboBox::~AltComboBox()
{
}
+bool AltComboBox::setKeyboardFocus()
+{
+ combobox->setFocus();
+ return true;
+}
+
QComboBox *AltComboBox::qcombobox()
{
return combobox;
diff --git a/client/widgets/altcombobox.h b/client/widgets/altcombobox.h
index e6a21d7..73dee10 100644
--- a/client/widgets/altcombobox.h
+++ b/client/widgets/altcombobox.h
@@ -43,6 +43,7 @@
/***
* ComboBox Widget with Alternate Value
* @tag altcombobox
+ * @clientside
* @extends combobox
* @screenshot Example: altitem selected.
* <altcombobox name="ex" layout="vbox" value="altitem" type="select">
@@ -94,6 +95,8 @@ public:
QComboBox *qcombobox();
+ bool setKeyboardFocus();
+
public slots:
void comboChanged();
void onChildChange();
diff --git a/client/widgets/button.h b/client/widgets/button.h
index 0bd7db9..d9053a6 100644
--- a/client/widgets/button.h
+++ b/client/widgets/button.h
@@ -34,6 +34,7 @@
/***
* PushButton Widget
* @tag button
+ * @clientside
* @screenshot Example button
* <button caption="Click me"/>
* @screenshot Example cancel button
diff --git a/client/widgets/checkbox.h b/client/widgets/checkbox.h
index ce31a62..5fef7cb 100644
--- a/client/widgets/checkbox.h
+++ b/client/widgets/checkbox.h
@@ -38,6 +38,7 @@
/***
* CheckBox Widget
* @tag checkbox
+ * @clientside
* @screenshot An example checkbox
* <checkbox name="example" truevalue="true" falsevalue="false" value="true"
* caption="A simple checkbox"/>
diff --git a/client/widgets/checkgroupbox.h b/client/widgets/checkgroupbox.h
index 5dfa7fb..96056a4 100644
--- a/client/widgets/checkgroupbox.h
+++ b/client/widgets/checkgroupbox.h
@@ -41,6 +41,7 @@
/***
* Checkable GroupBox Widget
* @tag checkgroupbox
+ * @clientside
* @extends checkbox
* @screenshot Example 1: type="framed"
* <checkgroupbox name="example" caption="Example" type="framed" layout="vbox"
diff --git a/client/widgets/combobox.cc b/client/widgets/combobox.cc
index eed2d10..935f620 100644
--- a/client/widgets/combobox.cc
+++ b/client/widgets/combobox.cc
@@ -93,6 +93,8 @@ ComboBox::ComboBox(QDomNode &node, MacroWindow *macrowindow)
// Make empty default selection.
combobox->setCurrentIndex(-1);
+ combobox->installEventFilter(this);
+
QDomElement elem = node.toElement();
combotype = SELECT;
@@ -213,15 +215,26 @@ void ComboBox::changed()
emit eventOnChange();
}
+#include <QKeyEvent>
bool ComboBox::eventFilter(QObject *obj, QEvent *event)
{
if(ignoreChangeEvents == true) return false;
+
if(combotype == SELECT) {
if(event->type() == QEvent::MouseButtonRelease) {
if(enabled()) combobox->showPopup();
}
}
+ if(event->type() == QEvent::KeyPress) {
+ QKeyEvent *ke = (QKeyEvent*)event;
+ // printf("KEY: %d\n", ke->key());
+ // if(ke->key() == Qt::Key_Up || ke->key() == Qt::Key_Down) {
+ if(ke->key() == Qt::Key_Space) {
+ if(enabled()) combobox->showPopup();
+ }
+ }
+
return QObject::eventFilter(obj, event);
}
diff --git a/client/widgets/combobox.h b/client/widgets/combobox.h
index bf61b1a..448a0ff 100644
--- a/client/widgets/combobox.h
+++ b/client/widgets/combobox.h
@@ -40,6 +40,7 @@
/***
* ComboBox Widget
* @tag combobox
+ * @clientside
* @screenshot Example
* <combobox name="ex" layout="vbox" value="item" type="select">
* <item caption="Item" value="item"/>
diff --git a/client/widgets/datetime.h b/client/widgets/datetime.h
index 84df018..a36d87b 100644
--- a/client/widgets/datetime.h
+++ b/client/widgets/datetime.h
@@ -35,6 +35,7 @@
/***
* Date and Time Widget
* @tag datetime
+ * @clientside
* @screenshot Example with fuzziness="1" and value="1234567890"
* <datetime name="x" fuzziness="1" value="1234567890"/>
* @screenshot Example with fuzziness="7" and value="1234567890"
diff --git a/client/widgets/groupbox.h b/client/widgets/groupbox.h
index 58e52bb..9198a5a 100644
--- a/client/widgets/groupbox.h
+++ b/client/widgets/groupbox.h
@@ -37,6 +37,7 @@
/***
* Layout or Frame Widget
* @tag frame
+ * @clientside
* @screenshot Example with caption.
* <frame caption="Caption" layout="vbox">
* <label caption="Label"/>
diff --git a/client/widgets/label.h b/client/widgets/label.h
index b303d0d..eae97b8 100644
--- a/client/widgets/label.h
+++ b/client/widgets/label.h
@@ -34,6 +34,7 @@
/***
* Label Widget
* @tag label
+ * @clientside
* @screenshot Example
* <label width="300" caption="A nice label with a caption"/>
* @extends widget
diff --git a/client/widgets/lineedit.h b/client/widgets/lineedit.h
index 08230a6..d482c15 100644
--- a/client/widgets/lineedit.h
+++ b/client/widgets/lineedit.h
@@ -39,6 +39,7 @@
/***
* Line Edit Widget
* @tag lineedit
+ * @clientside
* @screenshot Example
* <lineedit name="myname" value="some text"/>
* @extends widget
diff --git a/client/widgets/listbox.h b/client/widgets/listbox.h
index 82c5dfc..f9d967a 100644
--- a/client/widgets/listbox.h
+++ b/client/widgets/listbox.h
@@ -38,6 +38,7 @@
/***
* ListBox Widget
+ * @clientside
* @tag listbox
* @screenshot Example
* <listbox name="x" value="item1">
diff --git a/client/widgets/metawidget.h b/client/widgets/metawidget.h
index c6bf5d0..c6a7224 100644
--- a/client/widgets/metawidget.h
+++ b/client/widgets/metawidget.h
@@ -36,6 +36,7 @@
/***
* Meta Widget
+ * @clientside
* @extends widget
* @tag metawidget
* @screenshot An example of a metawidget with two inner widgets. The metawidget is not in itself visible.
diff --git a/client/widgets/multilist.h b/client/widgets/multilist.h
index f7da8fa..a7c5332 100644
--- a/client/widgets/multilist.h
+++ b/client/widgets/multilist.h
@@ -37,6 +37,7 @@
/***
* Multi List Widget
* @tag multilist
+ * @clientside
* @container
* @screenshot Example of multilist containing a metawidget.
* <multilist name="x" layout="vbox" innerwidget="in" value="Abc: Def
diff --git a/client/widgets/radiobuttons.h b/client/widgets/radiobuttons.h
index 4b9ce67..e09d4e8 100644
--- a/client/widgets/radiobuttons.h
+++ b/client/widgets/radiobuttons.h
@@ -35,6 +35,7 @@
/***
* Radio Button Group Widget
* @tag radiobuttons
+ * @clientside
* @extends widget
* @screenshot Example with four radiobuttons
* <radiobuttons name="x" value="item2">
diff --git a/client/widgets/textedit.h b/client/widgets/textedit.h
index 542dd6f..fbbb040 100644
--- a/client/widgets/textedit.h
+++ b/client/widgets/textedit.h
@@ -35,6 +35,7 @@
/***
* Multiline Text Edit Widget
* @tag textedit
+ * @clientside
* @screenshot Example of a textedit.
* <textedit name="x" value="This is a multiline textfield.
* It may contain all text in the universe, it will simply add a scrollbar."/>
diff --git a/client/widgets/widget.h b/client/widgets/widget.h
index 6199aa4..f2bf278 100644
--- a/client/widgets/widget.h
+++ b/client/widgets/widget.h
@@ -44,6 +44,7 @@
/***
* Virtual Base Widget
* This tag is purely virtual. It is inherited by all other widgets.
+ * @clientside
* @att name The name of the widget. This is also the name used by the scripts.
* @att value The initial value of the widget. It is overwritten if there is a
* map with a recent value or if the database contains a recent value.
diff --git a/client/widgets/window.h b/client/widgets/window.h
index ea3af0a..8fb5c59 100644
--- a/client/widgets/window.h
+++ b/client/widgets/window.h
@@ -34,6 +34,7 @@
* Widgets Outer Container
* @tag widgets
* @container
+ * @clientside
* This is the outer tag of the macro widgets.
* @att caption This is the name that will be shown in the macro.
* @att layout this is the layout that is used by the macro. It can be one of
diff --git a/server/configure.in b/server/configure.in
index 63e2e24..e65ac33 100644
--- a/server/configure.in
+++ b/server/configure.in
@@ -2,7 +2,7 @@
AC_INIT(src/pracrod.cc)
-VERSION="2.2.0"
+VERSION="2.2.2"
AM_INIT_AUTOMAKE( pracrod, $VERSION )
dnl ======================
@@ -95,7 +95,9 @@ else
dnl ======================
dnl Check for libpqxx
dnl ======================
- PKG_CHECK_MODULES(PQXX, libpqxx >= 2.6.8)
+ PKG_CHECK_MODULES(PQXX, libpqxx >= 4.0,
+ [AC_DEFINE_UNQUOTED([USE_NEW_PQXX], [1], [Use new pqx api])],
+ [PKG_CHECK_MODULES(PQXX, libpqxx >= 2.6.8)] )
fi
dnl ======================
diff --git a/server/src/Makefile.am b/server/src/Makefile.am
index 167f4e4..c852eb0 100644
--- a/server/src/Makefile.am
+++ b/server/src/Makefile.am
@@ -36,6 +36,8 @@ pracrod_SOURCES = \
journal.cc \
journal_uploadserver.cc \
log.cc \
+ luascript.cc \
+ luaoncommit.cc \
luapraxisd.cc \
luaquerymapper.cc \
luaresume.cc \
@@ -51,11 +53,11 @@ pracrod_SOURCES = \
queryhandlerpentominos.cc \
queryhandlerpracro.cc \
queryparser.cc \
- resumeparser.cc \
saxparser.cc \
semaphore.cc \
server.cc \
session.cc \
+ sessionheaderparser.cc \
sessionparser.cc \
sessionserialiser.cc \
templatelist.cc \
@@ -97,6 +99,8 @@ EXTRA_DIST = \
journal.h \
journal_uploadserver.h \
log.h \
+ luascript.h \
+ luaoncommit.h \
luapraxisd.h \
luaquerymapper.h \
luaresume.h \
@@ -114,11 +118,11 @@ EXTRA_DIST = \
queryhandlerpracro.h \
queryparser.h \
queryresult.h \
- resumeparser.h \
saxparser.h \
semaphore.h \
server.h \
session.h \
+ sessionheaderparser.h \
sessionparser.h \
sessionserialiser.h \
template.h \
diff --git a/server/src/admin_connection.cc b/server/src/admin_connection.cc
index fac52a1..76c88ea 100644
--- a/server/src/admin_connection.cc
+++ b/server/src/admin_connection.cc
@@ -35,6 +35,7 @@
#include "debug.h"
#include "configuration.h"
+#include "sessionserialiser.h"
static std::string admin_sessionunlock(Environment &env, std::string id)
{
@@ -59,18 +60,28 @@ static std::string admin_listactivesessions(Environment &env)
{
std::string str;
- std::vector<std::string> act = env.sessions.activeSessions();
- std::vector<std::string>::iterator i = act.begin();
+ std::vector<Sessions::SessionInfo> act = env.sessions.activeSessions();
+ std::vector<Sessions::SessionInfo>::iterator i = act.begin();
while(i != act.end()) {
- // NOTE: Returned session is returned in locked state!
- Session *s = NULL;
- SessionAutounlock l(&s);
- s = env.sessions.lockedSession(*i);
- str += "Session " + *i + ": "+s->templ+" on "+s->patientid+" "+
- std::string(s->idle()?"[idle]":"[active]")+"\n";
+ str += "Session " + i->id + ": "+i->templ+" on "+i->patientid+" "+
+ std::string(i->idle?"[idle]":"[active]")+"\n";
i++;
}
+ SessionSerialiser ser(&env, Conf::session_path);
+ std::map<std::string, SessionHeaderParser::Header> files = ser.sessionFiles();
+
+ std::map<std::string, SessionHeaderParser::Header>::iterator j = files.begin();
+ while(j != files.end()) {
+ std::string file = j->first;
+ SessionHeaderParser::Header header = j->second;
+
+ str += "Session " + header.id + ": " + header.templ + " on "
+ + header.patientid + " [session file: " + file + "]\n";
+
+ j++;
+ }
+
return str;
}
@@ -90,70 +101,68 @@ AdminConnection::AdminConnection(Environment &e, headers_t a, std::string u)
AdminConnection::~AdminConnection() {}
-bool AdminConnection::handle(const char *data, size_t size)
+bool AdminConnection::data(const char *, size_t) { return true; }
+
+bool AdminConnection::handle()
{
status = 200; // OK
- if(data == NULL && size == 0) {
- DEBUG(admin, "URI: %s\n", uri.c_str());
-
- if(uri == "/") {
- reply = admin_header(uri) +
- "Command list:\n"
- "<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;
- }
-
- if(uri == "/sessionunlock" && args.find("id") != args.end()) {
- reply = admin_header(uri) + admin_sessionunlock(env, args["id"])
- + admin_rc("footer");
- return true;
- }
-
- if(uri == "/listactivesessions") {
- reply = admin_header(uri) + admin_listactivesessions(env)
- + admin_rc("footer");
- return true;
- }
-
- if(uri == "/flushsessions") {
- reply = admin_header(uri) + admin_flush(env) + admin_rc("footer");
- return true;
- }
-
- if(uri == "/export" && args.find("template") != args.end()) {
- time_t from = 0;
- if(args.find("from") != args.end()) from = atoi(args["from"].c_str());
-
- time_t to = time(NULL);
- if(args.find("to") != args.end()) to = atoi(args["to"].c_str());
- bool ok;
- std::string res = admin_export(env, args["template"], &ok, from, to);
- 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;
- }
+ DEBUG(admin, "URI: %s\n", uri.c_str());
- reply = admin_header(uri) +
- "'" + uri + "' not recognised as a valid command."
+ if(uri == "/") {
+ reply = admin_header(uri) +
+ "Command list:\n"
+ "<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;
+ }
+
+ if(uri == "/sessionunlock" && args.find("id") != args.end()) {
+ reply = admin_header(uri) + admin_sessionunlock(env, args["id"])
+ + admin_rc("footer");
+ return true;
+ }
+
+ if(uri == "/listactivesessions") {
+ reply = admin_header(uri) + admin_listactivesessions(env)
+ admin_rc("footer");
return true;
}
+
+ if(uri == "/flushsessions") {
+ reply = admin_header(uri) + admin_flush(env) + admin_rc("footer");
+ return true;
+ }
+
+ if(uri == "/export" && args.find("template") != args.end()) {
+ time_t from = 0;
+ if(args.find("from") != args.end()) from = atoi(args["from"].c_str());
+
+ time_t to = time(NULL);
+ if(args.find("to") != args.end()) to = atoi(args["to"].c_str());
+ bool ok;
+ std::string res = admin_export(env, args["template"], &ok, from, to);
+ 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 = admin_header(uri) +
+ "'" + uri + "' not recognised as a valid command."
+ + admin_rc("footer");
return true;
}
diff --git a/server/src/admin_connection.h b/server/src/admin_connection.h
index 4a413a6..591c128 100644
--- a/server/src/admin_connection.h
+++ b/server/src/admin_connection.h
@@ -38,7 +38,8 @@ public:
AdminConnection(Environment &e, headers_t args, std::string uri);
~AdminConnection();
- bool handle(const char *data, size_t size);
+ bool data(const char *data, size_t size);
+ bool handle();
void getReply(Httpd::Reply &reply);
diff --git a/server/src/admin_export.cc b/server/src/admin_export.cc
index 0aa290c..3bdfcf6 100644
--- a/server/src/admin_export.cc
+++ b/server/src/admin_export.cc
@@ -41,6 +41,13 @@
#define SEP "\t"
+#ifdef USE_NEW_PQXX
+#include <pqxx/tuple.hxx>
+typedef pqxx::tuple tuple_t;
+#else
+typedef pqxx::result::tuple tuple_t;
+#endif
+
static std::string escape(std::string &str)
{
std::string out = "\"";
@@ -91,7 +98,7 @@ public:
" 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);
+ tuple_t tuple = result.at(r);
std::string name = tuple.at(0).c_str();
std::string caption = tuple.at(1).c_str();
addcell(name, caption);
@@ -166,7 +173,7 @@ static std::string do_export(Environment &env, std::string templ, bool *ok,
" 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);
+ tuple_t tuple = result.at(r);
std::string name = tuple.at(0).c_str();
filter.insert(name);
//printf("filter: '%s'\n", name.c_str());
@@ -209,7 +216,7 @@ static std::string do_export(Environment &env, std::string templ, bool *ok,
pqxx::result result = work.exec(q);
pqxx::result::const_iterator ri = result.begin();
for(unsigned int r = 0; r < result.size(); r++) {
- pqxx::result::tuple tuple = result.at(r);
+ tuple_t 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();
@@ -239,7 +246,7 @@ static std::string do_export(Environment &env, std::string templ, bool *ok,
" 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);
+ tuple_t tuple = result.at(r);
std::string name = tuple.at(0).c_str();
std::string value = tuple.at(1).c_str();
@@ -269,9 +276,9 @@ std::string admin_export(Environment &env, std::string templ, bool *ok,
}
#ifdef TEST_ADMIN_EXPORT
-//deps: environment.cc connectionpool.cc mutex.cc semaphore.cc configuration.cc entitylist.cc artefact.cc database.cc pracrodao.cc pracrodaotest.cc pracrodaopgsql.cc templatelist.cc macrolist.cc debug.cc macroheaderparser.cc exception.cc log.cc saxparser.cc templateheaderparser.cc versionstr.cc inotify.cc session.cc sessionserialiser.cc journal.cc journal_uploadserver.cc journal_commit.cc xml_encode_decode.cc sessionparser.cc fieldnamescanner.cc util.cc macroparser.cc templateparser.cc
-//cflags: -I.. -DWITHOUT_ARTEFACT $(PQXX_CFLAGS) $(EXPAT_CFLAGS)
-//libs: $(PQXX_LIBS) $(EXPAT_LIBS)
+//deps: environment.cc connectionpool.cc mutex.cc semaphore.cc configuration.cc entitylist.cc artefact.cc database.cc pracrodao.cc pracrodaotest.cc pracrodaopgsql.cc templatelist.cc macrolist.cc debug.cc macroheaderparser.cc exception.cc log.cc saxparser.cc templateheaderparser.cc versionstr.cc inotify.cc session.cc sessionserialiser.cc journal.cc journal_uploadserver.cc journal_commit.cc xml_encode_decode.cc sessionparser.cc fieldnamescanner.cc util.cc macroparser.cc templateparser.cc courselist.cc luascript.cc sessionheaderparser.cc courseparser.cc luautil.cc luapraxisd.cc praxisd.cc
+//cflags: -I.. -DWITHOUT_ARTEFACT $(PQXX_CFLAGS) $(EXPAT_CFLAGS) $(PTHREAD_CFLAGS) $(LUA_CFLAGS) $(CURL_CFLAGS)
+//libs: $(PQXX_LIBS) $(EXPAT_LIBS) $(PTHREAD_LIBS) $(LUA_LIBS) $(CURL_LIBS)
#include "test.h"
TEST_BEGIN;
diff --git a/server/src/client_connection.cc b/server/src/client_connection.cc
index 075dc46..c3de7b0 100644
--- a/server/src/client_connection.cc
+++ b/server/src/client_connection.cc
@@ -85,7 +85,7 @@ ClientConnection::ClientConnection(Environment &e, headers_t headers,
did_commit = false;
#endif
- parser_complete = false;
+ parser_complete = true;
}
ClientConnection::~ClientConnection()
@@ -108,6 +108,7 @@ void ClientConnection::nocommit(Session *session)
}
void ClientConnection::commit(Session *session)
+ throw(LUAScript::Exception, Journal::Exception)
{
if(docommit) {
if(session->isReadonly()) { // Commit of an empty session discards it.
@@ -117,7 +118,13 @@ void ClientConnection::commit(Session *session)
DEBUG(connection, "Commit (%s)\n", session->id().c_str());
std::string sid = session->id();
- session->commit();
+ try {
+ session->commit();
+ } catch(LUAScript::Exception &e) {
+ throw e;
+ } catch(Journal::Exception &e) {
+ throw e;
+ }
env.sessions.deleteSession(sid);
sessionid = "";
docommit = false;
@@ -139,8 +146,19 @@ void ClientConnection::discard(Session *session)
}
}
-bool ClientConnection::handle(const char *data, size_t size)
+bool ClientConnection::data(const char *data, size_t size)
{
+ DEBUG(connection, "data(%p %d)\n", data, size);
+
+ parser_complete = parser.parse(data, size);
+
+ return true;
+}
+
+bool ClientConnection::handle()
+{
+ DEBUG(connection, "handle\n");
+
if(patientid == "") {
response = error_box(xml_encode("Missing patientid."));
parser_complete = true;
@@ -189,33 +207,28 @@ bool ClientConnection::handle(const char *data, size_t size)
sessionid = session->id();
- try {
+ // Force session discard on empty template name.
+ if(templ == "") dodiscard = true;
- if((!data || !size) && (docommit || donocommit || dodiscard)) {
- parser_complete = true;
- commit(session);
- nocommit(session);
- discard(session);
- return true;
+ try {
+ if(parser_complete) {
+ response = handleTransaction(request, transaction, env, *session);
}
- // Force session discard on empty template name.
- if(templ == "") dodiscard = true;
-
- if(size == 0 || parser.parse(data, size)) {
- parser_complete = true;
-
- {
- //SessionAutolock lock(session);
- response = handleTransaction(request, transaction, env, *session);
- }
-
+ try {
commit(session);
- nocommit(session);
- discard(session);
-
+ } catch(LUAScript::Exception &e) {
+ response = error_box(xml_encode(e.msg));
+ return true;
+ } catch(Journal::Exception &e) {
+ response = error_box(xml_encode(e.msg));
return true;
}
+ nocommit(session);
+ discard(session);
+
+ return true;
+
} catch(...) {
ERR(connection, "Failed to parse data!\n");
response = error_box(xml_encode("XML Parse error."));
diff --git a/server/src/client_connection.h b/server/src/client_connection.h
index e64dcad..0bfa2e4 100644
--- a/server/src/client_connection.h
+++ b/server/src/client_connection.h
@@ -36,6 +36,8 @@
#include "transaction.h"
#include "transactionparser.h"
+#include "luascript.h"
+
class Session;
class ClientConnection : public Connection {
@@ -49,12 +51,13 @@ public:
headers_t args, std::string uri);
~ClientConnection();
- bool handle(const char *data, size_t size);
+ bool data(const char *data, size_t size);
+ bool handle();
void getReply(Httpd::Reply &reply);
private:
- void commit(Session *session);
+ void commit(Session *session) throw(LUAScript::Exception, Journal::Exception);
void nocommit(Session *session);
void discard(Session *session);
diff --git a/server/src/connection.h b/server/src/connection.h
index b7d17f4..098c735 100644
--- a/server/src/connection.h
+++ b/server/src/connection.h
@@ -36,7 +36,8 @@ class Connection {
public:
virtual ~Connection() {}
- virtual bool handle(const char *data, size_t size) = 0;
+ virtual bool data(const char *data, size_t size) = 0;
+ virtual bool handle() = 0;
virtual void getReply(Httpd::Reply &reply) = 0;
};
diff --git a/server/src/daemon.cc b/server/src/daemon.cc
index 938170c..e8e08ee 100644
--- a/server/src/daemon.cc
+++ b/server/src/daemon.cc
@@ -134,6 +134,10 @@ int Daemon::run(const char *user, const char* group, bool detach,
} else {
fprintf(fp, "%lu", (unsigned long int)pid);
fclose(fp);
+ /*
+ fprintf(stderr, "Wrote pid %lu to file \"%s\"",
+ (unsigned long int)pid, pidfile.c_str());
+ */
}
}
diff --git a/server/src/debug.cc b/server/src/debug.cc
index fa83a80..e42baae 100644
--- a/server/src/debug.cc
+++ b/server/src/debug.cc
@@ -34,6 +34,17 @@
#include "log.h"
+#include <pthread.h>
+
+#include "mutex.h"
+
+static Mutex mutex;
+
+static unsigned int gettid()
+{
+ return (unsigned int)pthread_self();
+}
+
static FILE *logfp = stderr;
#define NELEM(x) (sizeof(x)/sizeof((x)[0]))
@@ -69,11 +80,12 @@ int __debug(const char *func, const int line,
const enum __debug_class cl,
const char *ch, const char *fmt, ...)
{
+ MutexAutolock m(mutex);
int ret = 0;
if(__debug_enabled(cl, ch)) {
if((unsigned)cl < NELEM(debug_class_str))
- ret += fprintf(logfp, "%s:%s:%s:%d ",
- debug_class_str[(unsigned)cl], ch, func, line);
+ ret += fprintf(logfp, "%u %s:%s:%s:%d ",
+ gettid(), debug_class_str[(unsigned)cl], ch, func, line);
if(fmt) {
va_list va;
va_start(va, fmt);
@@ -91,11 +103,12 @@ int __debug_va(const char *func, const int line,
const enum __debug_class cl,
const char *ch, const char *fmt, va_list va)
{
+ MutexAutolock m(mutex);
int ret = 0;
if(__debug_enabled(cl, ch)) {
if((unsigned)cl < NELEM(debug_class_str))
- ret += fprintf(logfp, "%s:%s:%s:%d ",
- debug_class_str[(unsigned)cl], ch, func, line);
+ ret += fprintf(logfp, "%u %s:%s:%s:%d ",
+ gettid(), debug_class_str[(unsigned)cl], ch, func, line);
if(fmt)
ret += vfprintf(logfp, fmt, va);
}
@@ -110,6 +123,8 @@ int __debug_va(const char *func, const int line,
int __log(const char *func, const int line, const enum __debug_class cl,
const char *ch, const char *fmt, ...)
{
+ MutexAutolock m(mutex);
+
std::string logmsg;
char str[8];
@@ -120,7 +135,8 @@ int __log(const char *func, const int line, const enum __debug_class cl,
if((unsigned)cl < NELEM(debug_class_str))
if((unsigned)cl < NELEM(debug_class_str))
#ifdef WITH_DEBUG
- ret = fprintf(logfp, "%s:%s:%s:%d ", debug_class_str[(unsigned)cl], ch, func, line);
+ ret = fprintf(logfp, "%u %s:%s:%s:%d ",
+ gettid(), debug_class_str[(unsigned)cl], ch, func, line);
#endif
sprintf(str, "%d", line);
logmsg = std::string(debug_class_str[(unsigned)cl]) + ":" + ch + ":" + func + ":" + str;
@@ -149,6 +165,8 @@ int __log(const char *func, const int line, const enum __debug_class cl,
int __log_va(const char *func, const int line, const enum __debug_class cl,
const char *ch, const char *fmt, va_list va)
{
+ MutexAutolock m(mutex);
+
std::string logmsg;
char str[8];
#ifdef WITH_DEBUG
@@ -157,7 +175,8 @@ int __log_va(const char *func, const int line, const enum __debug_class cl,
if(__debug_enabled(cl, ch)) {
if((unsigned)cl < NELEM(debug_class_str))
#ifdef WITH_DEBUG
- ret = fprintf(logfp, "%s:%s:%s:%d ", debug_class_str[(unsigned)cl], ch, func, line);
+ ret = fprintf(logfp, "%u %s:%s:%s:%d ",
+ gettid(), debug_class_str[(unsigned)cl], ch, func, line);
#endif
sprintf(str, "%d", line);
logmsg = std::string(debug_class_str[(unsigned)cl]) + ":" + ch + ":" + func + ":" + str;
@@ -181,9 +200,25 @@ int __log_va(const char *func, const int line, const enum __debug_class cl,
void debug_init(FILE *fp)
{
+ mutex.name = "debug";
+ MutexAutolock m(mutex);
logfp = fp;
}
+void debug_reinit(const char *logfile)
+{
+ MutexAutolock m(mutex);
+
+ if(logfp != stderr) {
+ fclose(logfp);
+ logfp = fopen(logfile, "a");
+ if(!logfp) {
+ fprintf(stderr, "Could not write to logfile: '%s'\n", logfile);
+ logfp = stderr;
+ }
+ }
+}
+
/*
* fmt := [set[,set]*]*
@@ -193,6 +228,7 @@ void debug_init(FILE *fp)
*/
void debug_parse(const char *fmt)
{
+ MutexAutolock m(mutex);
char *s;
char *next;
char *opt;
diff --git a/server/src/debug.h b/server/src/debug.h
index a5f199d..838d83f 100644
--- a/server/src/debug.h
+++ b/server/src/debug.h
@@ -53,6 +53,7 @@
#endif/*HAVE_CONFIG*/
void debug_init(FILE *fp);
+void debug_reinit(const char *file);
void debug_parse(const char *fmt);
enum __debug_class
diff --git a/server/src/httpd.cc b/server/src/httpd.cc
index 1c0575a..9349697 100644
--- a/server/src/httpd.cc
+++ b/server/src/httpd.cc
@@ -38,9 +38,15 @@
#include <string.h>
#include <microhttpd.h>
+#include <time.h>
#include "debug.h"
+// for inet_ntop
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
typedef struct {
void *ptr;
bool firstrun;
@@ -68,10 +74,22 @@ static int request_handler(void *cls,
unsigned int *data_size,
void **con_cls)
{
+ time_t now = time(NULL);
+ DEBUG(httpd, "Request time: %s", ctime(&now));
+
+ void *so;
+ so = MHD_get_connection_info(con, MHD_CONNECTION_INFO_CLIENT_ADDRESS)->client_addr;
+
+ char peeraddr[INET_ADDRSTRLEN];
+ inet_ntop(AF_INET, &((struct sockaddr_in*)so)->sin_addr, peeraddr, sizeof(peeraddr));
+ DEBUG(httpd, "peer: %s\n", peeraddr);
+
DEBUG(httpd, "request_handler: cls(%p) con(%p) url(%s) method(%s)"
" version(%s) *con_cls(%p)\n",
cls, con, url, method, version, *con_cls);
- DEBUG(httpd, "request_handler: *data_size(%u) data:[%s]\n", *data_size, data);
+ std::string datastr; datastr.append(data, *data_size);
+ DEBUG(httpd, "request_handler: *data_size(%u) data:[%s]\n",
+ *data_size, datastr.c_str());
int ret = MHD_YES;
diff --git a/server/src/journal.cc b/server/src/journal.cc
index fc4203c..04b1459 100644
--- a/server/src/journal.cc
+++ b/server/src/journal.cc
@@ -32,7 +32,8 @@
Journal::Journal() {}
void Journal::addEntry(Transaction &transaction, Commit &commit,
- std::string resume, Template *templ)
+ std::string resume, Template *templ,
+ LUAOnCommit *oncommit)
{
size_t index = 0;
std::vector< Macro >::iterator i = templ->macros.begin();
@@ -70,16 +71,17 @@ void Journal::addEntry(Transaction &transaction, Commit &commit,
}
#endif
- addEntry(resume, commit.macro, transaction.user, index);
+ addEntry(resume, commit.macro, transaction.user, index, oncommit);
}
void Journal::addEntry(std::string resume, std::string macro,
- std::string user, int index)
+ std::string user, int index, LUAOnCommit *oncommit)
{
DEBUG(journal, "Add: %p %s %s - %s\n", this, macro.c_str(),
user.c_str(), resume.c_str());
ResumeEntry re;
+ re.oncommit = oncommit;
re.resume = resume;
re.macro = macro;
re.user = user;
@@ -148,6 +150,22 @@ std::string Journal::patientID()
return _patientid;
}
+void Journal::runOnCommitScripts() throw(LUAScript::Exception)
+{
+ std::map< int, ResumeEntry >::iterator i = entrylist.begin();
+ while(i != entrylist.end()) {
+ if(i->second.oncommit != NULL) {
+ try {
+ i->second.oncommit->run();
+ } catch(LUAScript::Exception &e) {
+ throw e;
+ }
+ }
+ i++;
+ }
+}
+
+
#ifdef TEST_JOURNAL
//deps: debug.cc log.cc journal_uploadserver.cc journal_commit.cc
//cflags: -I..
diff --git a/server/src/journal.h b/server/src/journal.h
index 573f252..d098756 100644
--- a/server/src/journal.h
+++ b/server/src/journal.h
@@ -33,22 +33,31 @@
#include "transaction.h"
#include "template.h"
+#include "luaoncommit.h"
class SessionSerialiser;
class Journal {
friend class SessionSerialiser;
public:
+ class Exception {
+ public:
+ Exception(std::string m) : msg(m) {}
+ std::string msg;
+ };
+
Journal();
virtual ~Journal() {}
void addEntry(Transaction &transaction, Commit &commit,
- std::string resume, Template *templ);
+ std::string resume, Template *templ, LUAOnCommit *oncommit);
void addEntry(std::string resume, std::string macro,
- std::string user, int index);
+ std::string user, int index, LUAOnCommit *oncommit);
+
+ void runOnCommitScripts() throw(LUAScript::Exception);
- virtual void commit() = 0;
+ virtual void commit() throw(Exception) = 0;
std::string getEntry(std::string macro);
void removeEntry(std::string macro);
@@ -65,6 +74,7 @@ protected:
std::string resume;
std::string macro;
std::string user;
+ LUAOnCommit *oncommit;
bool dirty;
};
diff --git a/server/src/journal_commit.cc b/server/src/journal_commit.cc
index 0c1a93d..d765ebb 100644
--- a/server/src/journal_commit.cc
+++ b/server/src/journal_commit.cc
@@ -132,6 +132,7 @@ int journal_commit(const char *cpr, const char *user,
// send body
if(sock != -1 && write(sock, resume.c_str(), resume.size()) != (ssize_t)resume.size()) {
ERR_LOG(journal, "write did not write all the bytes in the buffer.\n");
+ return -1;
}
DEBUG(journal, "%s\n", buf);
diff --git a/server/src/journal_uploadserver.cc b/server/src/journal_uploadserver.cc
index a1299ec..eac6cd5 100644
--- a/server/src/journal_uploadserver.cc
+++ b/server/src/journal_uploadserver.cc
@@ -163,7 +163,10 @@ JournalUploadServer::JournalUploadServer(std::string host,
}
void JournalUploadServer::commit()
+ throw(Journal::Exception)
{
+ int ret = 0;
+
#ifdef USE_MULTIPLE_USERS
std::string resume;
std::string olduser;
@@ -177,9 +180,12 @@ void JournalUploadServer::commit()
}
if(i->second.user != olduser && olduser != "" && resume != "") {
- journal_commit(patientID().c_str(), olduser.c_str(),
- host.c_str(), port,
- resume.c_str(), resume.size());
+ ret = journal_commit(patientID().c_str(), olduser.c_str(),
+ host.c_str(), port,
+ resume.c_str(), resume.size());
+
+ if(ret == -1) throw Journal::Exception("Journal Commit error.");
+
// FIXME - UGLY HACK: Avoid upload server spooling in the wrong order.
usleep(200000);
resume = "";
@@ -195,9 +201,9 @@ void JournalUploadServer::commit()
if(resume == "") return;
- journal_commit(patientID().c_str(), olduser.c_str(),
- host.c_str(), port,
- resume.c_str(), resume.size());
+ ret = journal_commit(patientID().c_str(), olduser.c_str(),
+ host.c_str(), port,
+ resume.c_str(), resume.size());
#else
std::string resume;
std::string user;
@@ -222,10 +228,12 @@ void JournalUploadServer::commit()
if(resume == "") return;
// Connect to praxisuploadserver and commit all resumes in one bulk.
- journal_commit(patientID().c_str(), user.c_str(),
- host.c_str(), port,
- resume.c_str(), resume.size());
+ ret = journal_commit(patientID().c_str(), user.c_str(),
+ host.c_str(), port,
+ resume.c_str(), resume.size());
#endif/*USE_MULTIPLE_USERS*/
+
+ if(ret == -1) throw Journal::Exception("Journal Commit error.");
}
diff --git a/server/src/journal_uploadserver.h b/server/src/journal_uploadserver.h
index 2393709..3e2fab3 100644
--- a/server/src/journal_uploadserver.h
+++ b/server/src/journal_uploadserver.h
@@ -33,7 +33,7 @@
class JournalUploadServer : public Journal {
public:
JournalUploadServer(std::string host, unsigned short int port);
- void commit();
+ void commit() throw(Journal::Exception);
private:
std::string host;
diff --git a/server/src/luaoncommit.cc b/server/src/luaoncommit.cc
new file mode 100644
index 0000000..8e96066
--- /dev/null
+++ b/server/src/luaoncommit.cc
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * luaoncommit.cc
+ *
+ * Thu Jan 12 08:38:02 CET 2012
+ * Copyright 2012 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 "luaoncommit.h"
+
+#include <lua.hpp>
+#include <lauxlib.h>
+
+#include "luautil.h"
+#include "luapraxisd.h"
+
+#include "debug.h"
+
+#include <stdio.h>
+
+LUAOnCommit::LUAOnCommit(Transaction &t, Commit &c) : LUAScript()
+{
+ setEnv(LUAScript::ENV_PATIENTID, t.patientid);
+ setEnv(LUAScript::ENV_TEMPLATE, c.templ);
+ setEnv(LUAScript::ENV_MACRO, c.macro);
+ setEnv(LUAScript::ENV_USER, t.user);
+
+ std::map<std::string, std::string>::iterator i = c.fields.begin();
+ while(i != c.fields.end()) {
+ addValue(i->first, i->second);
+ i++;
+ }
+}
+
+#ifdef TEST_LUAONCOMMIT
+//Additional dependency files
+//deps:
+//Required cflags (autoconf vars may be used)
+//cflags:
+//Required link options (autoconf vars may be used)
+//libs:
+#include "test.h"
+
+TEST_BEGIN;
+
+// TODO: Put some testcode here (see test.h for usable macros).
+TEST_TRUE(false, "No tests yet!");
+
+TEST_END;
+
+#endif/*TEST_LUAONCOMMIT*/
diff --git a/server/src/resumeparser.h b/server/src/luaoncommit.h
index 381e7c6..8db75f8 100644
--- a/server/src/resumeparser.h
+++ b/server/src/luaoncommit.h
@@ -1,9 +1,10 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
/***************************************************************************
- * resumeparser.h
+ * luaoncommit.h
*
- * Mon Oct 1 11:17:35 CEST 2007
- * Copyright 2007 Bent Bisballe Nyeng
+ * Thu Jan 12 08:38:02 CET 2012
+ * Copyright 2012 Bent Bisballe Nyeng
* deva@aasimon.org
****************************************************************************/
@@ -24,13 +25,21 @@
* along with Pracro; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-#ifndef __PRACRO_RESUMEPARSER_H__
-#define __PRACRO_RESUMEPARSER_H__
+#ifndef __PRACRO_LUAONCOMMIT_H__
+#define __PRACRO_LUAONCOMMIT_H__
+
+#include "luascript.h"
-#include <string>
#include "transaction.h"
-#include "template.h"
+#include <string>
+
+class LUAOnCommit : public LUAScript {
+public:
+ LUAOnCommit() {}
+ LUAOnCommit(Transaction &transaction, Commit &commit);
+ virtual ~LUAOnCommit() {}
-std::string resume_parser(Macro &macro, Commit &commit);
+ const char *name() { return "lua on commit"; }
+};
-#endif/*__PRACRO_RESUMEPARSER_H__*/
+#endif/*__PRACRO_LUAONCOMMIT_H__*/
diff --git a/server/src/luapraxisd.cc b/server/src/luapraxisd.cc
index 04a83db..da34d32 100644
--- a/server/src/luapraxisd.cc
+++ b/server/src/luapraxisd.cc
@@ -37,11 +37,14 @@
#define luaL_checkbool(L, i) \
(lua_isboolean(L,i) ? lua_toboolean(L,i) : luaL_checkint(L,i))
+#define error(L, m) \
+ ERR(luapraxisd, "%s\n", m); lua_pushstring(L, m); lua_error(L);
+
typedef struct px_userdata {
Praxisd *px;
} px_userdata;
-static int px_addcave(lua_State *L)
+int px_addcave(lua_State *L)
{
px_userdata *pxu;
pxu = (px_userdata *)luaL_checkudata(L, 1, "Praxisd");
@@ -49,64 +52,377 @@ static int px_addcave(lua_State *L)
const char *cpr = luaL_checkstring(L, 2);
const char *cave = luaL_checkstring(L, 3);
+ const char *txt = luaL_checkstring(L, 4);
std::string sogeord;
std::string sogetxt;
- std::vector<Praxisd::cave_t> cavelist = pxu->px->diverse_get_cave("");
- std::vector<Praxisd::cave_t>::iterator i = cavelist.begin();
- while(i != cavelist.end()) {
- Praxisd::cave_t &c = *i;
- if(strcasecmp(cave, c.cave.c_str()) == 0) {
- pxu->px->add_sogeord(cpr, c.sogenr, "");
- return 0;
+ try {
+ std::vector<Praxisd::cave_t> cavelist = pxu->px->diverse_get_cave("");
+ std::vector<Praxisd::cave_t>::iterator i = cavelist.begin();
+ while(i != cavelist.end()) {
+ Praxisd::cave_t &c = *i;
+ if(strcasecmp(cave, c.cave.c_str()) == 0) {
+ pxu->px->add_sogeord(cpr, c.sogenr, txt);
+ return 0;
+ }
+ i++;
}
- i++;
+
+ std::string text = cave;
+ text += " ";
+ text += txt;
+ pxu->px->add_sogeord(cpr, "CA0003", text.c_str()); // CA0003 == 'ANDET'
+ } catch(const char *msg) {
+ error(L, msg);
}
- pxu->px->add_sogeord(cpr, "CA0003", cave); // CA0003 == 'ANDET'
+ return 0;
+}
+
+int px_addbehandling(lua_State *L)
+{
+ px_userdata *pxu;
+ pxu = (px_userdata *)luaL_checkudata(L, 1, "Praxisd");
+ luaL_argcheck(L, pxu, 1, "Praxisd expected");
+
+ const char *cpr = luaL_checkstring(L, 2);
+ const char *behandling = luaL_checkstring(L, 3);
+ const char *text = luaL_checkstring(L, 4);
+
+ std::string sogeord;
+ std::string sogetxt;
+
+ try {
+ std::vector<Praxisd::behandling_t> bhlst =
+ pxu->px->diverse_get_behandling("");
+ std::vector<Praxisd::behandling_t>::iterator i = bhlst.begin();
+ while(i != bhlst.end()) {
+ Praxisd::behandling_t &b = *i;
+ if(strcasecmp(behandling, b.kode.c_str()) == 0) {
+ pxu->px->add_sogeord(cpr, b.sogenr, text);
+ return 0;
+ }
+ i++;
+ }
+ } catch(const char *msg) {
+ error(L, msg);
+ }
return 0;
}
-static int px_getcave(lua_State *L)
+int px_adddiagnose(lua_State *L)
{
px_userdata *pxu;
pxu = (px_userdata *)luaL_checkudata(L, 1, "Praxisd");
luaL_argcheck(L, pxu, 1, "Praxisd expected");
const char *cpr = luaL_checkstring(L, 2);
+ const char *diagnose = luaL_checkstring(L, 3);
+ const char *text = luaL_checkstring(L, 4);
- std::vector<Praxisd::cave_t> cavelist;
+ std::string sogeord;
+ std::string sogetxt;
+
+ try {
+ std::vector<Praxisd::diagnose_t> dialst =
+ pxu->px->diverse_get_diagnose("");
+ std::vector<Praxisd::diagnose_t>::iterator i = dialst.begin();
+ while(i != dialst.end()) {
+ Praxisd::diagnose_t &d = *i;
+ if(strcasecmp(diagnose, d.kode.c_str()) == 0) {
+ pxu->px->add_sogeord(cpr, d.sogenr, text);
+ return 0;
+ }
+ i++;
+ }
+ } catch(const char *msg) {
+ error(L, msg);
+ }
+
+ return 0;
+}
+
+class cavedata_t : public Praxisd::cave_t {
+public:
+ std::string sogetxt;
+ std::string sogedato;
+};
+int px_getcave(lua_State *L)
+{
+ px_userdata *pxu;
+ pxu = (px_userdata *)luaL_checkudata(L, 1, "Praxisd");
+ luaL_argcheck(L, pxu, 1, "Praxisd expected");
+
+ const char *cpr = luaL_checkstring(L, 2);
+
+ std::vector<cavedata_t> cavelist;
+
+ try {
+ Praxisd::patient_t pat = pxu->px->patient_get_by_cpr(cpr);
+ std::vector<Praxisd::sogeord_t>::iterator i = pat.sogeord.begin();
+ while(i != pat.sogeord.end()) {
+ Praxisd::sogeord_t &s = *i;
+ if(s.sogenr[0] == 'C') {
+ std::string csogenr = s.sogenr.substr(1, s.sogenr.length() - 1);
+ std::vector<Praxisd::cave_t> cl = pxu->px->diverse_get_cave(csogenr);
+ if(cl.size() == 1) {
+ cavedata_t cdata;
+ cdata.cave = cl[0].cave;
+ cdata.bemaerkning1 = cl[0].bemaerkning1;
+ cdata.bemaerkning2 = cl[0].bemaerkning2;
+ cdata.bemaerkning3 = cl[0].bemaerkning3;
+ cdata.sogetxt = s.sogetxt;
+ cdata.sogedato = s.sogedato;
+ cavelist.push_back(cdata);
+ }
+ }
+
+ i++;
+ }
+ } catch(const char *msg) {
+ error(L, msg);
+ }
+
+ int num = cavelist.size();
+ int sz = 6; // 4 fields in cave_t + 1 sogetxt and 1 sogedato
+
+ lua_createtable(L, num, 0);
+ int toptop = lua_gettop(L);
+
+ for(int i = 1; i <= num; i++) {
+ lua_createtable(L, 0, sz);
+ int top = lua_gettop(L);
+
+ for(int j = 1; j <= sz; j++) {
+ if(j == 1) lua_pushstring(L, cavelist[i - 1].cave.c_str());
+ if(j == 2) lua_pushstring(L, cavelist[i - 1].bemaerkning1.c_str());
+ if(j == 3) lua_pushstring(L, cavelist[i - 1].bemaerkning2.c_str());
+ if(j == 4) lua_pushstring(L, cavelist[i - 1].bemaerkning3.c_str());
+ if(j == 5) lua_pushstring(L, cavelist[i - 1].sogetxt.c_str());
+ if(j == 6) lua_pushstring(L, cavelist[i - 1].sogedato.c_str());
+ lua_rawseti(L, top, j);
+ }
+
+ lua_rawseti(L, toptop, i);
+ }
+
+ return 1;
+}
+
+class behandlingdata_t : public Praxisd::behandling_t {
+public:
+ std::string sogetxt;
+ std::string sogedato;
+};
+int px_getbehandling(lua_State *L)
+{
+ px_userdata *pxu;
+ pxu = (px_userdata *)luaL_checkudata(L, 1, "Praxisd");
+ luaL_argcheck(L, pxu, 1, "Praxisd expected");
+
+ const char *cpr = luaL_checkstring(L, 2);
+
+ std::vector<behandlingdata_t> behandlinglist;
+
+ try {
+ Praxisd::patient_t pat = pxu->px->patient_get_by_cpr(cpr);
+ std::vector<Praxisd::sogeord_t>::iterator i = pat.sogeord.begin();
+ while(i != pat.sogeord.end()) {
+ Praxisd::sogeord_t &s = *i;
+ if(s.sogenr[0] == 'B') {
+ std::string csogenr = s.sogenr.substr(1, s.sogenr.length() - 1);
+ std::vector<Praxisd::behandling_t> cl = pxu->px->diverse_get_behandling(csogenr);
+ if(cl.size() == 1) {
+ behandlingdata_t cdata;
+ cdata.kode = cl[0].kode;
+ cdata.behandling = cl[0].behandling;
+ cdata.bemaerkning = cl[0].bemaerkning;
+ cdata.udregning = cl[0].udregning;
+ cdata.sogetxt = s.sogetxt;
+ cdata.sogedato = s.sogedato;
+ behandlinglist.push_back(cdata);
+ }
+ }
+
+ i++;
+ }
+ } catch(const char *msg) {
+ error(L, msg);
+ }
+
+ int num = behandlinglist.size();
+ int sz = 6; // 4 fields in behandling_t + 1 sogetxt and 1 sogedato
+
+ lua_createtable(L, num, 0);
+ int toptop = lua_gettop(L);
+
+ for(int i = 1; i <= num; i++) {
+ lua_createtable(L, 0, sz);
+ int top = lua_gettop(L);
+
+ for(int j = 1; j <= sz; j++) {
+ if(j == 1) lua_pushstring(L, behandlinglist[i - 1].kode.c_str());
+ if(j == 2) lua_pushstring(L, behandlinglist[i - 1].behandling.c_str());
+ if(j == 3) lua_pushstring(L, behandlinglist[i - 1].bemaerkning.c_str());
+ if(j == 4) lua_pushstring(L, behandlinglist[i - 1].udregning.c_str());
+ if(j == 5) lua_pushstring(L, behandlinglist[i - 1].sogetxt.c_str());
+ if(j == 6) lua_pushstring(L, behandlinglist[i - 1].sogedato.c_str());
+ lua_rawseti(L, top, j);
+ }
+
+ lua_rawseti(L, toptop, i);
+ }
+
+ return 1;
+}
+
+class diagnosedata_t : public Praxisd::diagnose_t {
+public:
+ std::string sogetxt;
+ std::string sogedato;
+};
+int px_getdiagnose(lua_State *L)
+{
+ px_userdata *pxu;
+ pxu = (px_userdata *)luaL_checkudata(L, 1, "Praxisd");
+ luaL_argcheck(L, pxu, 1, "Praxisd expected");
- Praxisd::patient_t pat = pxu->px->patient_get_by_cpr(cpr);
- std::vector<Praxisd::sogeord_t>::iterator i = pat.sogeord.begin();
- while(i != pat.sogeord.end()) {
- Praxisd::sogeord_t &s = *i;
- if(s.sogenr[0] == 'C') {
- std::string csogenr = s.sogenr.substr(1, s.sogenr.length() - 1);
- std::vector<Praxisd::cave_t> cl = pxu->px->diverse_get_cave(csogenr);
- if(cl.size() == 1) {
- if(cl[0].cave == "ANDET") cl[0].cave = s.sogetxt;
- cavelist.push_back(cl[0]);
+ const char *cpr = luaL_checkstring(L, 2);
+
+ std::vector<diagnosedata_t> diagnoselist;
+
+ try {
+ Praxisd::patient_t pat = pxu->px->patient_get_by_cpr(cpr);
+ std::vector<Praxisd::sogeord_t>::iterator i = pat.sogeord.begin();
+ while(i != pat.sogeord.end()) {
+ Praxisd::sogeord_t &s = *i;
+ if(s.sogenr[0] == 'D') {
+ std::string csogenr = s.sogenr.substr(1, s.sogenr.length() - 1);
+ std::vector<Praxisd::diagnose_t> cl = pxu->px->diverse_get_diagnose(csogenr);
+ if(cl.size() == 1) {
+ diagnosedata_t cdata;
+ cdata.kode = cl[0].kode;
+ cdata.diagnose = cl[0].diagnose;
+ cdata.bemaerkning = cl[0].bemaerkning;
+ cdata.sogetxt = s.sogetxt;
+ cdata.sogedato = s.sogedato;
+ diagnoselist.push_back(cdata);
+ }
}
+
+ i++;
+ }
+ } catch(const char *msg) {
+ error(L, msg);
+ }
+
+ int num = diagnoselist.size();
+ int sz = 5; // 3 fields in diagnose_t + 1 sogetxt and 1 sogedato
+
+ lua_createtable(L, num, 0);
+ int toptop = lua_gettop(L);
+
+ for(int i = 1; i <= num; i++) {
+ lua_createtable(L, 0, sz);
+ int top = lua_gettop(L);
+
+ for(int j = 1; j <= sz; j++) {
+ if(j == 1) lua_pushstring(L, diagnoselist[i - 1].kode.c_str());
+ if(j == 2) lua_pushstring(L, diagnoselist[i - 1].diagnose.c_str());
+ if(j == 3) lua_pushstring(L, diagnoselist[i - 1].bemaerkning.c_str());
+ if(j == 4) lua_pushstring(L, diagnoselist[i - 1].sogetxt.c_str());
+ if(j == 5) lua_pushstring(L, diagnoselist[i - 1].sogedato.c_str());
+ lua_rawseti(L, top, j);
+ }
+
+ lua_rawseti(L, toptop, i);
+ }
+
+ return 1;
+}
+
+int px_cavelist(lua_State *L)
+{
+ px_userdata *pxu;
+ pxu = (px_userdata *)luaL_checkudata(L, 1, "Praxisd");
+ luaL_argcheck(L, pxu, 1, "Praxisd expected");
+
+ const char *sogenr = luaL_checkstring(L, 2);
+
+ std::vector<Praxisd::cave_t> cavelist;
+ try {
+ cavelist = pxu->px->diverse_get_cave(sogenr);
+ } catch(const char *msg) {
+ error(L, msg);
+ }
+
+
+ int num = cavelist.size();
+ int sz = 4; // 4 fields in cave_t
+
+ lua_createtable(L, num, 0);
+ int toptop = lua_gettop(L);
+
+ for(int i = 1; i <= num; i++) {
+ lua_createtable(L, 0, sz);
+ int top = lua_gettop(L);
+
+ for(int j = 1; j <= sz; j++) {
+ if(j == 1) lua_pushstring(L, cavelist[i - 1].cave.c_str());
+ if(j == 2) lua_pushstring(L, cavelist[i - 1].bemaerkning1.c_str());
+ if(j == 3) lua_pushstring(L, cavelist[i - 1].bemaerkning2.c_str());
+ if(j == 4) lua_pushstring(L, cavelist[i - 1].bemaerkning3.c_str());
+ lua_rawseti(L, top, j);
}
- i++;
+ lua_rawseti(L, toptop, i);
+ }
+
+ return 1;
+}
+
+int px_behandlinglist(lua_State *L)
+{
+ px_userdata *pxu;
+ pxu = (px_userdata *)luaL_checkudata(L, 1, "Praxisd");
+ luaL_argcheck(L, pxu, 1, "Praxisd expected");
+
+ const char *sogenr = luaL_checkstring(L, 2);
+
+ std::vector<Praxisd::behandling_t> behandlinglist;
+ try {
+ behandlinglist = pxu->px->diverse_get_behandling(sogenr);
+ } catch(const char *msg) {
+ error(L, msg);
}
- lua_createtable(L, 0, cavelist.size());
- int top = lua_gettop(L);
+ int num = behandlinglist.size();
+ int sz = 4; // 4 fields in behandling_t
+
+ lua_createtable(L, num, 0);
+ int toptop = lua_gettop(L);
+
+ for(int i = 1; i <= num; i++) {
+ lua_createtable(L, 0, sz);
+ int top = lua_gettop(L);
+
+ for(int j = 1; j <= sz; j++) {
+ if(j == 1) lua_pushstring(L, behandlinglist[i - 1].kode.c_str());
+ if(j == 2) lua_pushstring(L, behandlinglist[i - 1].behandling.c_str());
+ if(j == 3) lua_pushstring(L, behandlinglist[i - 1].bemaerkning.c_str());
+ if(j == 4) lua_pushstring(L, behandlinglist[i - 1].udregning.c_str());
+ lua_rawseti(L, top, j);
+ }
- for(size_t i = 0; i < cavelist.size(); i++) {
- lua_pushstring(L, cavelist[i].cave.c_str());
- lua_rawseti(L, top, i);
+ lua_rawseti(L, toptop, i);
}
return 1;
}
-static int px_cavelist(lua_State *L)
+int px_diagnoselist(lua_State *L)
{
px_userdata *pxu;
pxu = (px_userdata *)luaL_checkudata(L, 1, "Praxisd");
@@ -114,20 +430,37 @@ static int px_cavelist(lua_State *L)
const char *sogenr = luaL_checkstring(L, 2);
- std::vector<Praxisd::cave_t> cavelist = pxu->px->diverse_get_cave(sogenr);
+ std::vector<Praxisd::diagnose_t> diagnoselist;
+ try {
+ diagnoselist = pxu->px->diverse_get_diagnose(sogenr);
+ } catch(const char *msg) {
+ error(L, msg);
+ }
- lua_createtable(L, 0, cavelist.size());
- int top = lua_gettop(L);
+ int num = diagnoselist.size();
+ int sz = 3; // 3 fields in diagnose_t
+
+ lua_createtable(L, num, 0);
+ int toptop = lua_gettop(L);
+
+ for(int i = 1; i <= num; i++) {
+ lua_createtable(L, 0, sz);
+ int top = lua_gettop(L);
+
+ for(int j = 1; j <= sz; j++) {
+ if(j == 1) lua_pushstring(L, diagnoselist[i - 1].kode.c_str());
+ if(j == 2) lua_pushstring(L, diagnoselist[i - 1].diagnose.c_str());
+ if(j == 3) lua_pushstring(L, diagnoselist[i - 1].bemaerkning.c_str());
+ lua_rawseti(L, top, j);
+ }
- for(size_t i = 0; i < cavelist.size(); i++) {
- lua_pushstring(L, cavelist[i].cave.c_str());
- lua_rawseti(L, top, i);
+ lua_rawseti(L, toptop, i);
}
return 1;
}
-static int px_new(lua_State *L)
+int px_new(lua_State *L)
{
const char *host = luaL_checkstring(L, 1);
int port = (int)luaL_checknumber(L, 2);
@@ -138,12 +471,16 @@ static int px_new(lua_State *L)
luaL_getmetatable(L, "Praxisd");
lua_setmetatable(L, -2);
- pxu->px = new Praxisd(host, port);
+ try {
+ pxu->px = new Praxisd(host, port);
+ } catch(const char *msg) {
+ error(L, msg);
+ }
return 1;
}
-static int px_gc(lua_State *L)
+int px_gc(lua_State *L)
{
px_userdata *pxu;
@@ -155,19 +492,6 @@ static int px_gc(lua_State *L)
return 0;
}
-static const struct luaL_Reg px_meths[] = {
- {"__gc" ,px_gc},
- {"cavelist", px_cavelist},
- {"getcave", px_getcave},
- {"addcave", px_addcave},
- {NULL, NULL}
-};
-
-static const struct luaL_reg px_funcs[] = {
- {"new", px_new},
- {NULL, NULL}
-};
-
void register_praxisd(lua_State *L)
{
luaL_newmetatable(L, "Praxisd");
@@ -179,7 +503,7 @@ void register_praxisd(lua_State *L)
}
#ifdef TEST_LUAPRAXISD
-//deps: praxisd.cc debug.cc saxparser.cc log.cc
+//deps: praxisd.cc debug.cc saxparser.cc log.cc mutex.cc
//cflags: -I.. $(LUA_CFLAGS) $(CURL_CFLAGS) $(EXPAT_CFLAGS)
//libs: $(LUA_LIBS) $(CURL_LIBS) $(EXPAT_LIBS)
#include "test.h"
@@ -198,29 +522,36 @@ register_praxisd(L);
/////
std::string program =
"px = Praxisd.new('localhost', 10000)\n"
- "cl = px:cavelist('')\n"
- "for i=1,#cl do\n"
- " print(cl[i])\n"
- "end\n"
+ "--cl = px:cavelist('')\n"
+ "--for i=1,#cl do\n"
+ "-- print(cl[i])\n"
+ "--end\n"
"\n"
- "--pcl = px:addcave('1505050505', 'LUMIGAN')\n"
+ "pcl = px:addcave('1505050505', 'AZOPT', 'test')\n"
"\n"
- "pcl = px:addcave('1505050505', os.date('%H%M%S'))\n"
+ "--pcl = px:addcave('1505050505', os.date('%H%M%S'))\n"
"\n"
- "pcl = px:getcave('1505050505')\n"
- "for i=1,#pcl do\n"
- " print('p: ' .. pcl[i])\n"
- "end\n"
+ "--pcl = px:getbehandling('1505050505')\n"
+ "--print('#pcl: ' .. #pcl)\n"
+ "--for i=1,#pcl do\n"
+ "-- pc = pcl[i]\n"
+ "-- print('#pc: ' .. #pc)\n"
+ "-- for j=1,#pc do\n"
+ "-- print(' pc: ' .. j .. ': ' .. pc[j])\n"
+ "-- end\n"
+ "--end\n"
;
//int top = lua_gettop(L);
if(luaL_loadbuffer(L, program.c_str(), program.size(), "luapraxisd test")) {
ERR(luaresume, "loadbufer: %s\n", lua_tostring(L, lua_gettop(L)));
+ printf("loadbuffer error: %s", lua_tostring(L, lua_gettop(L)));
}
if(lua_pcall(L, 0, LUA_MULTRET, 0)) {
ERR(luaresume, "pcall: %s\n" , lua_tostring(L, lua_gettop(L)));
+ printf("pcall error: %s", lua_tostring(L, lua_gettop(L)));
}
/*
if(top != lua_gettop(L) - 1) {
diff --git a/server/src/luapraxisd.h b/server/src/luapraxisd.h
index 2ab9ab5..82445e1 100644
--- a/server/src/luapraxisd.h
+++ b/server/src/luapraxisd.h
@@ -30,6 +30,221 @@
#include <lua.hpp>
+/***
+ * Praxisd Class
+ * @class Praxisd
+ * @serverside
+ * @clientside
+ * The praxisd class connects and handles communication with the praxisd
+ * daemon process.
+ */
+
+/***
+ * @method object Praxisd.new(string host, int port)
+ * Create a new Praxisd connection object.
+ * @param host The hostname to connect to.
+ * @param port The port number to connect to.
+ * @return The newly created communication object.
+ * @example Create a new praxisd object:
+ * px = Praxisd.new('localhost', 10000)
+ */
+int px_new(lua_State *L);
+
+/***
+ * @method stringlist-list praxisd:cavelist()
+ * Get server cave list.
+ * To retrieve cavelist for a patient see @see praxisd:getcave().
+ * @return The complete list of known (possible) cave from the server.
+ * The returned stringlist are indexed as follows: 1: cave - 2: bemaerkning1 -
+ * 3: bemaerkning2 - 4: bemaerkning3
+ * @example Create a new praxisd object, get and print cavelist:
+ * px = Praxisd.new('localhost', 10000)
+ * lst = px:cavelist()
+ * for i=0,#lst do
+ * print('cave: ' .. lst[i][1])
+ * print('bemaerkning1: ' .. lst[i][2])
+ * print('bemaerkning2: ' .. lst[i][3])
+ * print('bemaerkning3: ' .. lst[i][4])
+ * end
+ */
+int px_cavelist(lua_State *L);
+
+/***
+ * @method stringlist-list praxisd:behandlinglist()
+ * Get server behandling list.
+ * To retrieve behandlinglist for a patient see @see praxisd:getbehandling().
+ * @return The complete list of known (possible) behandling from the server.
+ * The returned stringlist are indexed as follows: 1: kode - 2: behandling -
+ * 3: bemaerkning - 4: udregning.
+ * @example Create a new praxisd object, get and print behandlinglist:
+ * px = Praxisd.new('localhost', 10000)
+ * lst = px:behandlinglist()
+ * for i=0,#lst do
+ * print('kode: ' .. lst[i][1])
+ * print('behandling: ' .. lst[i][2])
+ * print('bemaerkning: ' .. lst[i][3])
+ * print('udregning: ' .. lst[i][4])
+ * end
+ */
+int px_behandlinglist(lua_State *L);
+
+/***
+ * @method stringlist-list praxisd:diagnoselist()
+ * Get server diagnose list.
+ * To retrieve diagnoselist for a patient see @see praxisd:getdiagnose().
+ * @return The complete list of known (possible) diagnose from the server.
+ * The returned stringlist are indexed as follows: 1: kode - 2: diagnose -
+ * 3: bemaerkning.
+ * @example Create a new praxisd object, get and print diagnoselist:
+ * px = Praxisd.new('localhost', 10000)
+ * lst = px:diagnoselist()
+ * for i=0,#lst do
+ * print('kode: ' .. lst[i][1])
+ * print('diagnose: ' .. lst[i][2])
+ * print('bemaerkning: ' .. lst[i][3])
+ * end
+ */
+int px_diagnoselist(lua_State *L);
+
+/***
+ * @method stringlist-list praxisd:getcave(string patientid)
+ * Get cave list from a patient.
+ * To retrieve cavelist from the server see @see praxisd:cavelist(). To add cave
+ * to a patient see @see praxisd:addcave().
+ * @param patientid A string containing the patientid.
+ * @return The list cave registered with the patient.
+ * The returned stringlist are indexed as follows: 1: cave - 2: bemaerkning1 -
+ * 3: bemaerkning2 - 4: bemaerkning3 - 5: sogetxt - 6: sogedato.
+ * @example Create a new praxisd object, get and print cavelist:
+ * px = Praxisd.new('localhost', 10000)
+ * lst = px:getcave('1234567890')
+ * for i=0,#lst do
+ * print('cave: ' .. lst[i][1])
+ * print('bemaerkning1: ' .. lst[i][2])
+ * print('bemaerkning2: ' .. lst[i][3])
+ * print('bemaerkning3: ' .. lst[i][4])
+ * print('sogetxt: ' .. lst[i][5])
+ * print('sogedato: ' .. lst[i][6])
+ * end
+ */
+int px_getcave(lua_State *L);
+
+/***
+ * @method stringlist-list praxisd:getbehandling(string patientid)
+ * Get behandling list from a patient.
+ * To retrieve behandlinglist from the server see @see praxisd:behandlinglist(). To add behandling
+ * to a patient see @see praxisd:addbehandling().
+ * @param patientid A string containing the patientid.
+ * @return The list behandling registered with the patient.
+ * The returned stringlist are indexed as follows: 1: kode - 2: behandling -
+ * 3: bemaerkning - 4: udregning - 5: sogetxt - 6: sogedato.
+ * @example Create a new praxisd object, get and print behandlinglist:
+ * px = Praxisd.new('localhost', 10000)
+ * lst = px:getbehandling('1234567890')
+ * for i=0,#lst do
+ * print('kode: ' .. lst[i][1])
+ * print('behandling: ' .. lst[i][2])
+ * print('bemaerkning: ' .. lst[i][3])
+ * print('udregning: ' .. lst[i][4])
+ * print('sogetxt: ' .. lst[i][5])
+ * print('sogedato: ' .. lst[i][6])
+ * end
+ */
+int px_getbehandling(lua_State *L);
+
+/***
+ * @method stringlist-list praxisd:getdiagnose(string patientid)
+ * Get diagnose list from a patient.
+ * To retrieve diagnoselist from the server see @see praxisd:diagnoselist(). To add diagnose
+ * to a patient see @see praxisd:adddiagnose().
+ * @param patientid A string containing the patientid.
+ * @return The list diagnose registered with the patient.
+ * The returned stringlist are indexed as follows: 1: kode - 2: diagnose -
+ * 3: bemaerkning - 4: sogetxt - 5: sogedato.
+ * @example Create a new praxisd object, get and print diagnoselist:
+ * px = Praxisd.new('localhost', 10000)
+ * lst = px:getdiagnose('1234567890')
+ * for i=0,#lst do
+ * print('kode: ' .. lst[i][1])
+ * print('diagnose: ' .. lst[i][2])
+ * print('bemaerkning: ' .. lst[i][3])
+ * print('sogetxt: ' .. lst[i][4])
+ * print('sogedato: ' .. lst[i][5])
+ * end
+ */
+int px_getdiagnose(lua_State *L);
+
+/***
+ * @method nil praxisd:addcave(string patientid, string cave, string text)
+ * Add a cave entry to a patient. To retrieve list of cave from a patient
+ * see @see praxisd:getcave().
+ * NOTE: This function is only available on the server.
+ * @param patientid A string containing the patientid.
+ * @param diagnose The cave string.
+ * @param text A text to store with the cave entry. NOTE: This is not shown in
+ * PCPraxis! The string mat be up to 6 characters long. If longer it will be
+ * trunkated.
+ * @example Create a new praxisd object and add a cave entry:
+ * px = Praxisd.new('localhost', 10000)
+ * px:addcave('1234567890', 'AZOPT', '')
+ */
+int px_addcave(lua_State *L);
+
+/***
+ * @method nil praxisd:addbehandling(string patientid, string behandling, string text)
+ * Add a behandling to a patient. To retrieve list of behandling from a patient
+ * see @see praxisd:getbehandling().
+ * NOTE: This function is only available on the server.
+ * @param patientid A string containing the patientid.
+ * @param diagnose The behandling code.
+ * @param text A text to store with the behandling code. The string mat be up to 6
+ * characters long. If longer it will be trunkated.
+ * @example Create a new praxisd object and add a behandling:
+ * px = Praxisd.new('localhost', 10000)
+ * px:addbehandling('1234567890', 'B0001', 'o.sin')
+ */
+int px_addbehandling(lua_State *L);
+
+/***
+ * @method nil praxisd:adddiagnose(string patientid, string diagnose, string text)
+ * Add a diagnose to a patient. To retrieve list of diagnose from a patient
+ * see @see praxisd:getdiagnose().
+ * NOTE: This function is only available on the server.
+ * @param patientid A string containing the patientid.
+ * @param diagnose The diagnose code.
+ * @param text A text to store with the diagnose code. The string mat be up to 6
+ * characters long. If longer it will be trunkated.
+ * @example Create a new praxisd object and add a diagnose:
+ * px = Praxisd.new('localhost', 10000)
+ * px:adddiagnose('1234567890', 'C0001', 'o.dxt')
+ */
+int px_adddiagnose(lua_State *L);
+
+/***
+ * @method nil __gc()
+ * Garbage collector. Closes connection and frees all allocated memory.
+ */
+int px_gc(lua_State *L);
+
void register_praxisd(lua_State *L);
+const struct luaL_Reg px_meths[] = {
+ {"__gc", px_gc},
+ {"cavelist", px_cavelist},
+ {"behandliglist", px_behandlinglist},
+ {"diagnoselist", px_diagnoselist},
+ {"getcave", px_getcave},
+ {"getbehandling", px_getbehandling},
+ {"getdiagnose", px_getdiagnose},
+ {"addcave", px_addcave},
+ {"addbehandling", px_addbehandling},
+ {"adddiagnose", px_adddiagnose},
+ {NULL, NULL}
+};
+
+const struct luaL_reg px_funcs[] = {
+ {"new", px_new},
+ {NULL, NULL}
+};
+
#endif/*__PRACRO_LUAPRAXISD_H__*/
diff --git a/server/src/luaquerymapper.cc b/server/src/luaquerymapper.cc
index 27dc21f..56ea1e9 100644
--- a/server/src/luaquerymapper.cc
+++ b/server/src/luaquerymapper.cc
@@ -109,9 +109,53 @@ LUAQueryMapper::~LUAQueryMapper()
if(L) lua_close(L);
}
+static QueryResult splitgroups(QueryResult r)
+{
+ QueryResult result;
+
+ result.timestamp = r.timestamp;
+ result.source = r.source;
+
+ std::map< std::string, QueryResult >::iterator gi = r.groups.begin();
+ while(gi != r.groups.end()) {
+ QueryResult child = splitgroups(gi->second);
+ result.groups[gi->first] = child;
+ gi++;
+ }
+
+ std::map< std::string, std::string >::iterator vi = r.values.begin();
+ while(vi != r.values.end()) {
+ std::string name = vi->first;
+
+ // Also insert in table with name containing '.'.
+ if(name.find(".") != std::string::npos) result.values[name] = vi->second;
+
+ QueryResult *ncurrent = &result;
+ while(name.find(".") != std::string::npos) {
+ DEBUG(splitgroups, "value name: %s\n", name.c_str());
+ QueryResult grp;
+ grp.timestamp = ncurrent->timestamp;
+ grp.source = ncurrent->source;
+ std::string grpname = name.substr(0, name.find("."));
+ ncurrent->groups[grpname] = grp;
+ ncurrent = &(ncurrent->groups[grpname]);
+ name = name.substr(name.find(".") + 1);
+ }
+ ncurrent->values[name] = vi->second;
+
+ vi++;
+ }
+
+ return result;
+}
+
+
void LUAQueryMapper::addQueryResult(QueryResult &result) throw(Exception)
{
- loadResult(L, result);
+ // Check for '.' in names and further split up into groups.
+ QueryResult splitted = splitgroups(result);
+
+ loadResult(L, splitted);
clean_top = lua_gettop(L);
}
diff --git a/server/src/luaresume.cc b/server/src/luaresume.cc
index d3597ad..1db4fb3 100644
--- a/server/src/luaresume.cc
+++ b/server/src/luaresume.cc
@@ -26,122 +26,27 @@
*/
#include "luaresume.h"
+#include <lua.hpp>
+#include <lauxlib.h>
+
#include "luautil.h"
-#include "luapraxisd.h"
#include "debug.h"
#include <stdio.h>
-#define GLOBAL_POINTER "_pracroGlobalLUAObjectPointerThisShouldBeANameThatIsNotAccidentallyOverwritten"
-
-static int _value(lua_State *L)
-{
- Pracro::checkParameters(L,
- Pracro::T_STRING,
- Pracro::T_END);
-
- std::string name = lua_tostring(L, lua_gettop(L));
-
- lua_getglobal(L, GLOBAL_POINTER);
- LUAResume *lua = (LUAResume*)lua_touserdata(L, lua_gettop(L));
-
- if(!lua) {
- lua_pushstring(L, "No LUA pointer!");
- lua_error(L);
- return 1;
- }
-
- std::string value = lua->value(name);
- lua_pushstring(L, value.c_str());
-
- return 1;
-}
-
-LUAResume::LUAResume(Commit &c)
- : commit(c)
-{
- L = luaL_newstate();
- if(L == NULL) {
- ERR(luaresume, "Could not create LUA state.\n");
- return;
- }
-
- luaL_openlibs(L);
-
- lua_pushlightuserdata(L, this); // Push the pointer to 'this' instance
- lua_setglobal(L, GLOBAL_POINTER); // Assign it to a global lua var.
-
- lua_register(L, "value", _value);
-
- register_praxisd(L);
-}
-
-LUAResume::~LUAResume()
-{
- lua_close(L);
-}
-
-std::string LUAResume::value(std::string name)
+LUAResume::LUAResume(Transaction &t, Commit &c) : LUAScript()
{
- if(commit.fields.find(name) == commit.fields.end()) {
- ERR(luaresume, "LUAResume: No such field '%s'\n", name.c_str());
- return "";
+ setEnv(LUAScript::ENV_PATIENTID, t.patientid);
+ setEnv(LUAScript::ENV_TEMPLATE, c.templ);
+ setEnv(LUAScript::ENV_MACRO, c.macro);
+ setEnv(LUAScript::ENV_USER, t.user);
+
+ std::map<std::string, std::string>::iterator i = c.fields.begin();
+ while(i != c.fields.end()) {
+ addValue(i->first, i->second);
+ i++;
}
-
- return commit.fields[name];
-}
-
-std::string LUAResume::run(std::string program)
-{
- if(L == NULL) {
- ERR(luaresume, "LUA state not initialized!");
- return false;
- }
-
- DEBUG(luaresume, "Running %s\n", program.c_str());
-
- /*
- lua_pushstring(L, value.toStdString().c_str());
- lua_setglobal(L, "value");
-
- lua_pushstring(L, name.toStdString().c_str());
- lua_setglobal(L, "name");
- */
-
- int top = lua_gettop(L);
-
- if(luaL_loadbuffer(L, program.c_str(), program.size(),
- "lua resume generator")) {
- ERR(luaresume, "loadbufer: %s\n", lua_tostring(L, lua_gettop(L)));
- return false;
- }
-
- // Run the loaded code
- if(lua_pcall(L, 0, LUA_MULTRET, 0)) {
- ERR(luaresume, "pcall: %s\n" , lua_tostring(L, lua_gettop(L)));
- return false;
- }
-
- if(top != lua_gettop(L) - 1) {
- ERR(luaresume, "Program did not return a single value.\n");
- return false;
- }
-
- if(lua_isstring(L, lua_gettop(L)) == false) {
- ERR(luaresume, "Program did not return a string value.\n");
- return false;
- }
-
- std::string res = lua_tostring(L, lua_gettop(L));
- lua_pop(L, 1);
-
- return res;
-}
-
-void LUAResume::error(std::string message)
-{
- ERR(luaresume, "LUA ERROR: %s\n", message.c_str());
}
#ifdef TEST_LUARESUME
diff --git a/server/src/luaresume.h b/server/src/luaresume.h
index 1132f26..47a7652 100644
--- a/server/src/luaresume.h
+++ b/server/src/luaresume.h
@@ -27,26 +27,16 @@
#ifndef __PRACRO_LUARESUME_H__
#define __PRACRO_LUARESUME_H__
-#include <lua.hpp>
-#include <lauxlib.h>
+#include "luascript.h"
#include "transaction.h"
#include <string>
-class LUAResume {
+class LUAResume : public LUAScript {
public:
- LUAResume(Commit &commit);
- ~LUAResume();
-
- std::string run(std::string program);
+ LUAResume(Transaction &transaction, Commit &commit);
- std::string value(std::string name);
-
- void error(std::string message);
-
-private:
- lua_State *L;
- Commit &commit;
+ const char *name() { return "lua resume generator"; }
};
#endif/*__PRACRO_LUARESUME_H__*/
diff --git a/server/src/luascript.cc b/server/src/luascript.cc
new file mode 100644
index 0000000..6ba52a9
--- /dev/null
+++ b/server/src/luascript.cc
@@ -0,0 +1,317 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * luascript.cc
+ *
+ * Tue Jan 10 14:43:39 CET 2012
+ * Copyright 2012 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 "luascript.h"
+
+#include "configuration.h"
+#include "debug.h"
+
+#include "luautil.h"
+#include "luapraxisd.h"
+
+#define GLOBAL_POINTER "_pracroGlobalLUAObjectPointerThisShouldBeANameThatIsNotAccidentallyOverwritten"
+
+static int _debug(lua_State *L)
+{
+ Pracro::checkParameters(L,
+ Pracro::T_STRING,
+ Pracro::T_END);
+
+ std::string msg = lua_tostring(L, lua_gettop(L));
+
+ DEBUG(luascript, "%s\n", msg.c_str());
+
+ return 0;
+}
+
+static int _value(lua_State *L)
+{
+ Pracro::checkParameters(L,
+ Pracro::T_STRING,
+ Pracro::T_END);
+
+ std::string name = lua_tostring(L, lua_gettop(L));
+
+ lua_getglobal(L, GLOBAL_POINTER);
+ LUAScript *lua = (LUAScript*)lua_touserdata(L, lua_gettop(L));
+
+ if(!lua) {
+ lua_pushstring(L, "No LUA pointer!");
+ lua_error(L);
+ return 1;
+ }
+
+ if(lua->hasValue(name)) {
+ lua_pushstring(L, lua->value(name).c_str());
+ } else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+static int _patientid(lua_State *L)
+{
+ Pracro::checkParameters(L, Pracro::T_END);
+
+ lua_getglobal(L, GLOBAL_POINTER);
+ LUAScript *lua = (LUAScript*)lua_touserdata(L, lua_gettop(L));
+
+ if(!lua) {
+ lua_pushstring(L, "No LUA pointer!");
+ lua_error(L);
+ return 1;
+ }
+
+ lua_pushstring(L, lua->env(LUAScript::ENV_PATIENTID).c_str());
+
+ return 1;
+}
+
+static int _template(lua_State *L)
+{
+ Pracro::checkParameters(L, Pracro::T_END);
+
+ lua_getglobal(L, GLOBAL_POINTER);
+ LUAScript *lua = (LUAScript*)lua_touserdata(L, lua_gettop(L));
+
+ if(!lua) {
+ lua_pushstring(L, "No LUA pointer!");
+ lua_error(L);
+ return 1;
+ }
+
+ lua_pushstring(L, lua->env(LUAScript::ENV_TEMPLATE).c_str());
+
+ return 1;
+}
+
+static int _macro(lua_State *L)
+{
+ Pracro::checkParameters(L, Pracro::T_END);
+
+ lua_getglobal(L, GLOBAL_POINTER);
+ LUAScript *lua = (LUAScript*)lua_touserdata(L, lua_gettop(L));
+
+ if(!lua) {
+ lua_pushstring(L, "No LUA pointer!");
+ lua_error(L);
+ return 1;
+ }
+
+ lua_pushstring(L, lua->env(LUAScript::ENV_MACRO).c_str());
+
+ return 1;
+}
+
+static int _user(lua_State *L)
+{
+ Pracro::checkParameters(L, Pracro::T_END);
+
+ lua_getglobal(L, GLOBAL_POINTER);
+ LUAScript *lua = (LUAScript*)lua_touserdata(L, lua_gettop(L));
+
+ if(!lua) {
+ lua_pushstring(L, "No LUA pointer!");
+ lua_error(L);
+ return 1;
+ }
+
+ lua_pushstring(L, lua->env(LUAScript::ENV_USER).c_str());
+
+ return 1;
+}
+
+LUAScript::LUAScript()
+{
+ L = NULL;
+}
+
+void LUAScript::init()
+ throw(Exception)
+{
+ if(L) return;
+
+ L = luaL_newstate();
+ if(L == NULL) {
+ ERR(luascript, "Could not create LUA state.\n");
+ throw Exception("Could not create LUA state.");
+ }
+
+ luaL_openlibs(L);
+
+ lua_pushlightuserdata(L, this); // Push the pointer to 'this' instance
+ lua_setglobal(L, GLOBAL_POINTER); // Assign it to a global lua var.
+
+ lua_register(L, "value", _value);
+ lua_register(L, "patientid", _patientid);
+ lua_register(L, "template", _template);
+ lua_register(L, "macro", _macro);
+ lua_register(L, "user", _user);
+ lua_register(L, "debug", _debug);
+
+ register_praxisd(L);
+}
+
+void LUAScript::addFile(std::string src)
+{
+ std::string file =
+ Conf::xml_basedir + "/include/" + src;
+ FILE *fp = fopen(file.c_str(), "r");
+ if(fp) {
+ char buf[64];
+ size_t sz;
+ std::string inc;
+ while((sz = fread(buf, 1, sizeof(buf), fp)) != 0) {
+ inc.append(buf, sz);
+ }
+ fclose(fp);
+ addCode(inc, file);
+ }
+}
+
+void LUAScript::addCode(std::string c, std::string name)
+{
+ scripts.push_back(std::make_pair(c, name));
+}
+
+void LUAScript::addValue(std::string name, const std::string &value)
+{
+ values[name] = value;
+}
+
+void LUAScript::addScripts(std::vector< Script > &scripts)
+{
+ std::vector< Script >::iterator spi = scripts.begin();
+ while(spi != scripts.end()) {
+ if(spi->attributes.find("src") != spi->attributes.end()) {
+ std::string src = spi->attributes["src"];
+ addFile(src);
+ } else {
+ addCode(spi->code);
+ }
+ spi++;
+ }
+}
+
+void LUAScript::run()
+ throw(Exception)
+{
+ try {
+ init();
+ } catch(Exception &e) {
+ throw Exception(e.msg);
+ }
+
+ if(L == NULL) {
+ ERR(luascript, "LUA state not initialized!");
+ return;
+ }
+
+ top = lua_gettop(L);
+
+ std::vector<std::pair<std::string, std::string> >::iterator i =
+ scripts.begin();
+ while(i != scripts.end()) {
+ std::string program = i->first;
+ std::string codename = name();
+ if(i->second != "") codename += ": " + i->second;
+
+ DEBUG(luascript, "Running %s: %s\n", codename.c_str(), program.c_str());
+
+ if(luaL_loadbuffer(L, program.c_str(), program.size(), codename.c_str())) {
+ ERR(luascript, "loadbuffer: %s\n", lua_tostring(L, lua_gettop(L)));
+ throw Exception(lua_tostring(L, lua_gettop(L)));
+ }
+
+ // Run the loaded code
+ if(lua_pcall(L, 0, LUA_MULTRET, 0)) {
+ ERR(luascript, "pcall: %s\n" , lua_tostring(L, lua_gettop(L)));
+ throw Exception(lua_tostring(L, lua_gettop(L)));
+ }
+
+ i++;
+ }
+}
+
+std::string LUAScript::resultString() throw(Exception)
+{
+ if(top != lua_gettop(L) - 1) {
+ ERR(luascript, "Program did not return a single value.\n");
+ throw Exception("Program did not return a single value.");
+ }
+
+ if(lua_isstring(L, lua_gettop(L)) == false) {
+ ERR(luascript, "Program did not return a string value.\n");
+ throw Exception("Program did not return a string value.");
+ }
+
+ std::string res = lua_tostring(L, lua_gettop(L));
+ lua_pop(L, 1);
+
+ return res;
+}
+
+bool LUAScript::hasValue(std::string name)
+{
+ return values.find(name) != values.end();
+}
+
+std::string LUAScript::value(std::string name)
+{
+ if(values.find(name) != values.end()) return values[name];
+ return "";
+}
+
+std::string LUAScript::env(LUAScript::env_t id)
+{
+ if(_env.find(id) == _env.end()) return "";
+ return _env[id];
+}
+
+void LUAScript::setEnv(LUAScript::env_t id, std::string value)
+{
+ _env[id] = value;
+}
+
+#ifdef TEST_LUASCRIPT
+//Additional dependency files
+//deps:
+//Required cflags (autoconf vars may be used)
+//cflags:
+//Required link options (autoconf vars may be used)
+//libs:
+#include "test.h"
+
+TEST_BEGIN;
+
+// TODO: Put some testcode here (see test.h for usable macros).
+TEST_TRUE(false, "No tests yet!");
+
+TEST_END;
+
+#endif/*TEST_LUASCRIPT*/
diff --git a/server/src/luascript.h b/server/src/luascript.h
new file mode 100644
index 0000000..11fb77d
--- /dev/null
+++ b/server/src/luascript.h
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * luascript.h
+ *
+ * Tue Jan 10 14:43:39 CET 2012
+ * Copyright 2012 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_LUASCRIPT_H__
+#define __PRACRO_LUASCRIPT_H__
+
+#include <lua.hpp>
+#include <lauxlib.h>
+
+#include <string>
+#include <map>
+#include <vector>
+
+#include "template.h"
+
+class LUAScript {
+ friend class SessionSerialiser;
+ friend class SessionParser;
+public:
+ typedef enum {
+ ENV_PATIENTID,
+ ENV_TEMPLATE,
+ ENV_MACRO,
+ ENV_USER
+ } env_t;
+
+ class Exception {
+ public:
+ Exception(std::string m) : msg(m) {}
+ std::string msg;
+ };
+
+ LUAScript();
+ virtual ~LUAScript() {}
+
+ virtual const char *name() { return ""; }
+
+ void init() throw(Exception);
+
+ void addFile(std::string file);
+ void addCode(std::string code, std::string codename = "");
+ void addScripts(std::vector< Script > &scripts);
+
+ void addValue(std::string name, const std::string &value);
+
+ void run() throw(Exception);
+
+ bool hasValue(std::string name);
+ std::string value(std::string value);
+
+ std::string env(env_t id);
+ void setEnv(env_t id, std::string value);
+
+ std::string resultString() throw(Exception);
+
+protected:
+ lua_State *L;
+
+ std::map<env_t, std::string> _env;
+
+private:
+ std::vector<std::pair<std::string, std::string> > scripts;
+ std::map<std::string, std::string> values;
+
+ int top;
+};
+
+
+#endif/*__PRACRO_LUASCRIPT_H__*/
diff --git a/server/src/macroparser.cc b/server/src/macroparser.cc
index d1604b2..be781aa 100644
--- a/server/src/macroparser.cc
+++ b/server/src/macroparser.cc
@@ -114,7 +114,12 @@ void MacroParser::characterData(std::string &data)
if(state == SCRIPT) {
assert(current_script); // No script present!
- current_script->attributes["code"].append(data);
+ current_script->code.append(data);
+ }
+
+ if(state == COMMIT_SCRIPT) {
+ assert(current_commit_script); // No script present!
+ current_commit_script->code.append(data);
}
}
@@ -147,6 +152,18 @@ void MacroParser::startTag(std::string name, attributes_t &attr)
return;
}
+ // Enable oncommit parsing
+ if(name == "oncommit") {
+ if(state != MACRO) error("oncommit found outside macro.");
+ state = COMMIT_SCRIPTS;
+
+ m->resume.attributes = attr;
+
+ assert(m); // No macro is currently available, cannot create resume!
+
+ return;
+ }
+
// Enable Query parsing
if(name == "queries") {
if(state != MACRO) error("queries found outside macro.");
@@ -232,8 +249,18 @@ void MacroParser::startTag(std::string name, attributes_t &attr)
current_resume_script = &(m->resume_scripts.back());
}
break;
+ case COMMIT_SCRIPTS:
+ {
+ state = COMMIT_SCRIPT;
+
+ Script s;
+ s.attributes = attr;
+ m->commit_scripts.push_back(s);
+ current_commit_script = &(m->commit_scripts.back());
+ }
+ break;
default:
- error("<script> tag found outside <scripts> or <resume> tags.");
+ error("<script> tag found outside <scripts>, <commitscripts> or <resume> tags.");
break;
}
return;
@@ -290,6 +317,7 @@ void MacroParser::endTag(std::string name)
state = UNDEFINED;
}
if(name == "resume") state = MACRO;
+ if(name == "oncommit") state = MACRO;
if(name == "queries") state = MACRO;
if(name == "query") state = QUERIES;
if(name == "maps") state = MACRO;
@@ -310,6 +338,11 @@ void MacroParser::endTag(std::string name)
state = RESUME;
break;
+ case COMMIT_SCRIPT:
+ current_commit_script = NULL;
+ state = COMMIT_SCRIPTS;
+ break;
+
default:
// tag mismatch?
break;
diff --git a/server/src/macroparser.h b/server/src/macroparser.h
index 71ef911..ab6fda5 100644
--- a/server/src/macroparser.h
+++ b/server/src/macroparser.h
@@ -42,7 +42,9 @@ class MacroParser : public SAXParser {
MAP,
WIDGETS,
SCRIPTS,
- SCRIPT
+ SCRIPT,
+ COMMIT_SCRIPTS,
+ COMMIT_SCRIPT
} ParserState;
public:
@@ -76,6 +78,7 @@ private:
Map *current_map;
Script *current_script;
Script *current_resume_script;
+ Script *current_commit_script;
std::vector< Widget* > widgetstack;
// Error callback function.
diff --git a/server/src/mutex.cc b/server/src/mutex.cc
index ec0d0e8..9805591 100644
--- a/server/src/mutex.cc
+++ b/server/src/mutex.cc
@@ -27,6 +27,11 @@
*/
#include "mutex.h"
+#include "debug.h"
+
+#define MUTEX_DBG(x)
+//#define MUTEX_DBG(x) x
+
Mutex::Mutex()
{
pthread_mutex_init (&mutex, NULL);
@@ -39,16 +44,23 @@ Mutex::~Mutex()
bool Mutex::trylock()
{
- return pthread_mutex_trylock(&mutex) == 0;
+ bool ret = pthread_mutex_trylock(&mutex) == 0;
+
+ if(ret) MUTEX_DBG(printf("trylock succeeded on %s\n", name.c_str()));
+ else MUTEX_DBG(printf("trylock failed on %s\n", name.c_str()));
+
+ return ret;
}
void Mutex::lock()
{
pthread_mutex_lock(&mutex);
+ MUTEX_DBG(printf("lock on %s\n", name.c_str()));
}
void Mutex::unlock()
{
+ MUTEX_DBG(printf("unlock on %s\n", name.c_str()));
pthread_mutex_unlock(&mutex);
}
diff --git a/server/src/mutex.h b/server/src/mutex.h
index cf052ad..87f18e1 100644
--- a/server/src/mutex.h
+++ b/server/src/mutex.h
@@ -30,6 +30,8 @@
#include <pthread.h>
+#include <string>
+
class Mutex {
public:
Mutex();
@@ -39,6 +41,8 @@ public:
void lock();
void unlock();
+ std::string name;
+
private:
pthread_mutex_t mutex;
};
diff --git a/server/src/pracrod.cc b/server/src/pracrod.cc
index 81acfbc..b68cf07 100644
--- a/server/src/pracrod.cc
+++ b/server/src/pracrod.cc
@@ -69,7 +69,7 @@ static const char version_str[] =
;
static const char copyright_str[] =
-"Copyright (C) 2006-2009 Bent Bisballe Nyeng - Aasimon.org.\n"
+"Copyright (C) 2006-2012 Bent Bisballe Nyeng - Aasimon.org.\n"
"This is free software. You may redistribute copies of it under the terms of\n"
"the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.\n"
"There is NO WARRANTY, to the extent permitted by law.\n"
@@ -116,18 +116,12 @@ void childwait(int)
}
static FILE *logfp = stderr;
-static std::string logfile;
+std::string logfile;
+bool logfile_reload = false;
void reload(int)
{
- if(logfp != stderr) {
- fclose(logfp);
- logfp = fopen(logfile.c_str(), "a");
- if(!logfp) {
- fprintf(stderr, "Could not write to logfile: '%s'\n", optarg);
- logfp = stderr;
- }
- }
+ logfile_reload = true;
}
class PracroDaemon : public Daemon {
diff --git a/server/src/pracrodaopgsql.cc b/server/src/pracrodaopgsql.cc
index f9a773f..db0a9aa 100644
--- a/server/src/pracrodaopgsql.cc
+++ b/server/src/pracrodaopgsql.cc
@@ -228,6 +228,7 @@ void PracroDAOPgsql::commitTransaction(std::string sessionid,
}
+//#define NEW
Values PracroDAOPgsql::getLatestValues(std::string sessionid,
std::string patientid,
Macro *macro,
@@ -261,6 +262,70 @@ Values PracroDAOPgsql::getLatestValues(std::string sessionid,
}
pqxx::work W(*conn);
+
+#ifdef NEW
+
+ // Do not search for nothing...
+ if(fieldnames.size() == 0) return values;
+
+ std::string names;
+ std::vector< std::string >::iterator fni = fieldnames.begin();
+ while(fni != fieldnames.end()) {
+ if(names != "") names += " OR ";
+ names += "name='" + W.esc(*fni) + "'";
+ fni++;
+ }
+
+ std::string macros;
+ if(macro) {
+ macros += " AND macro='" + macro->name + "'";
+ if(macro->version != "")
+ macros += " AND t.version='" + macro->version + "'";
+ }
+
+ uncom = uncom;
+ query = "SELECT uid FROM commits WHERE patientid='"+patientid+"' AND"
+ " \"timestamp\">="+soldest.str()+" AND"
+ " (status='committed' OR uid="+sessionid+");";
+ DEBUG(sql, "Query: %s\n", query.c_str());
+ pqxx::result commits = W.exec(query);
+ pqxx::result::const_iterator ci = commits.begin();
+ while(ci != commits.end()) {
+ std::string cid = (*ci)[0].c_str();
+
+ query = "SELECT uid, \"timestamp\" FROM transactions WHERE cid="+cid+
+ macros+";";
+ DEBUG(sql, "Query: %s\n", query.c_str());
+ pqxx::result transactions = W.exec(query);
+ pqxx::result::const_iterator ti = transactions.begin();
+ while(ti != transactions.end()) {
+ std::string tid = (*ti)[0].c_str();
+ time_t timestamp = atol((*ti)[1].c_str());
+
+ query = "SELECT name, value FROM fields WHERE"
+ " transaction="+tid+" AND ("+ names +");";
+ DEBUG(sql, "Query: %s\n", query.c_str());
+ pqxx::result fields = W.exec(query);
+ DEBUG(sql, "Results: %lu\n", fields.size());
+ pqxx::result::const_iterator fi = fields.begin();
+ while(fi != fields.end()) {
+ std::string name = (*fi)[0].c_str();
+ if(values.find(name) == values.end() ||
+ values[name].timestamp <= timestamp) {
+ Value v;
+ v.value = (*fi)[1].c_str();
+ v.timestamp = timestamp;
+ values[name] = v;
+ }
+ fi++;
+ }
+
+ ti++;
+ }
+
+ ci++;
+ }
+#else/*NEW*/
std::string namecond;
if(fieldnames.size() > 0) {
@@ -318,6 +383,7 @@ Values PracroDAOPgsql::getLatestValues(std::string sessionid,
values[(*ri)[0].c_str()] = v;
ri++;
}
+#endif/*NEW*/
} catch (std::exception &e) {
ERR_LOG(db, "Query failed: %s: %s\n", e.what(), query.c_str());
}
diff --git a/server/src/praxisd.cc b/server/src/praxisd.cc
index 3ccdf0d..c198051 100644
--- a/server/src/praxisd.cc
+++ b/server/src/praxisd.cc
@@ -29,6 +29,13 @@
#include "saxparser.h"
+static const char* str2err(std::string msg)
+{
+ static char errbuf[1024];
+ sprintf(errbuf, "%s", msg.c_str());
+ return errbuf;
+}
+
static std::string strtime(bool with_sec = true)
{
std::string ret;
@@ -59,12 +66,13 @@ static size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp)
}
Praxisd::Praxisd(std::string h, int port)
+ throw(const char*)
{
ch = curl_easy_init();
host = h;
curl_easy_setopt(ch, CURLOPT_PORT, port);
- curl_easy_setopt(ch, CURLOPT_FAILONERROR, 1L);
+ curl_easy_setopt(ch, CURLOPT_FAILONERROR, 0L/*1L*/);
curl_easy_setopt(ch, CURLOPT_TIMEOUT, 150L);
curl_easy_setopt(ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_easy_setopt(ch, CURLOPT_CONNECTTIMEOUT, 15L);
@@ -82,6 +90,7 @@ Praxisd::~Praxisd()
// Get Journal By CPR
std::string Praxisd::journal_get_by_cpr(std::string cpr)
+ throw(const char*)
{
std::string journal;
@@ -93,16 +102,20 @@ std::string Praxisd::journal_get_by_cpr(std::string cpr)
CURLcode errornum = curl_easy_perform(ch);
if(errornum != CURLE_OK) {
- printf("Ouch %d\n", errornum);
+ throw curl_easy_strerror(errornum);
}
- time_t time;
- errornum = curl_easy_getinfo(ch, CURLINFO_FILETIME, &time);
+ long code = 0;
+ errornum = curl_easy_getinfo(ch, CURLINFO_RESPONSE_CODE, &code);
+ if(code != 200) {
+ throw str2err(journal);
+ }
return journal;
}
time_t Praxisd::journal_last_changed(std::string cpr)
+ throw(const char*)
{
std::string journal;
@@ -114,17 +127,27 @@ time_t Praxisd::journal_last_changed(std::string cpr)
CURLcode errornum = curl_easy_perform(ch);
if(errornum != CURLE_OK) {
- printf("Ouch %d\n", errornum);
+ throw curl_easy_strerror(errornum);
}
time_t time;
errornum = curl_easy_getinfo(ch, CURLINFO_FILETIME, &time);
+ if(errornum != CURLE_OK) {
+ throw curl_easy_strerror(errornum);
+ }
+
+ long code = 0;
+ errornum = curl_easy_getinfo(ch, CURLINFO_RESPONSE_CODE, &code);
+ if(code != 200) {
+ throw str2err(journal);
+ }
return time;
}
void Praxisd::journal_add(std::string cpr, std::string entry)
+ throw(const char*)
{
std::string xml;
xml += "<praxisd version=\"1.0\">\n";
@@ -150,12 +173,19 @@ void Praxisd::journal_add(std::string cpr, std::string entry)
CURLcode errornum = curl_easy_perform(ch);
if(errornum != CURLE_OK) {
- printf("Ouch: %d %s\n", errornum, reply.c_str());
+ throw curl_easy_strerror(errornum);
+ }
+
+ long code = 0;
+ errornum = curl_easy_getinfo(ch, CURLINFO_RESPONSE_CODE, &code);
+ if(code != 200) {
+ throw str2err(reply);
}
}
void Praxisd::add_sogeord(std::string cpr, std::string sogeord,
std::string sogetxt)
+ throw(const char*)
{
std::string datestr = strtime(false);
@@ -187,7 +217,13 @@ void Praxisd::add_sogeord(std::string cpr, std::string sogeord,
CURLcode errornum = curl_easy_perform(ch);
if(errornum != CURLE_OK) {
- printf("Ouch: %d %s\n", errornum, reply.c_str());
+ throw curl_easy_strerror(errornum);
+ }
+
+ long code = 0;
+ errornum = curl_easy_getinfo(ch, CURLINFO_RESPONSE_CODE, &code);
+ if(code != 200) {
+ throw str2err(reply);
}
}
@@ -259,6 +295,7 @@ private:
};
Praxisd::patient_t Praxisd::patient_get_by_cpr(std::string cpr)
+ throw(const char*)
{
patient_t p;
@@ -272,10 +309,14 @@ Praxisd::patient_t Praxisd::patient_get_by_cpr(std::string cpr)
CURLcode errornum = curl_easy_perform(ch);
if(errornum != CURLE_OK) {
- printf("Ouch %d\n", errornum);
+ throw curl_easy_strerror(errornum);
}
- // printf("Get Patient: %d %s\n", xml.length(), xml.c_str()); fflush(stdout);
+ long code = 0;
+ errornum = curl_easy_getinfo(ch, CURLINFO_RESPONSE_CODE, &code);
+ if(code != 200) {
+ throw str2err(xml);
+ }
PatientParser parser(p);
parser.parse(xml.data(), xml.length());
@@ -284,6 +325,7 @@ Praxisd::patient_t Praxisd::patient_get_by_cpr(std::string cpr)
}
std::string Praxisd::get_sogenr(std::string sogenr)
+ throw(const char*)
{
std::string xml;
@@ -296,7 +338,13 @@ std::string Praxisd::get_sogenr(std::string sogenr)
CURLcode errornum = curl_easy_perform(ch);
if(errornum != CURLE_OK) {
- printf("Ouch %d\n", errornum);
+ throw curl_easy_strerror(errornum);
+ }
+
+ long code = 0;
+ errornum = curl_easy_getinfo(ch, CURLINFO_RESPONSE_CODE, &code);
+ if(code != 200) {
+ throw str2err(xml);
}
return xml;
@@ -331,6 +379,7 @@ private:
};
std::vector<Praxisd::adresse_t> Praxisd::diverse_get_adresse(std::string sogenr)
+ throw(const char*)
{
std::vector<Praxisd::adresse_t> lst;
std::string xml = get_sogenr("A"+sogenr);
@@ -365,6 +414,7 @@ private:
std::vector<Praxisd::behandling_t>
Praxisd::diverse_get_behandling(std::string sogenr)
+ throw(const char*)
{
std::vector<Praxisd::behandling_t> lst;
std::string xml = get_sogenr("B"+sogenr);
@@ -398,6 +448,7 @@ private:
};
std::vector<Praxisd::cave_t> Praxisd::diverse_get_cave(std::string sogenr)
+ throw(const char*)
{
std::vector<Praxisd::cave_t> lst;
std::string xml = get_sogenr("C"+sogenr);
@@ -431,6 +482,7 @@ private:
std::vector<Praxisd::diagnose_t>
Praxisd::diverse_get_diagnose(std::string sogenr)
+ throw(const char*)
{
std::vector<Praxisd::diagnose_t> lst;
std::string xml = get_sogenr("D"+sogenr);
@@ -464,6 +516,7 @@ private:
};
std::vector<Praxisd::frase_t> Praxisd::diverse_get_frase(std::string sogenr)
+ throw(const char*)
{
std::vector<Praxisd::frase_t> lst;
std::string xml = get_sogenr("F"+sogenr);
@@ -495,6 +548,7 @@ private:
};
std::vector<Praxisd::grafik_t> Praxisd::diverse_get_grafik(std::string sogenr)
+ throw(const char*)
{
std::vector<Praxisd::grafik_t> lst;
std::string xml = get_sogenr("G"+sogenr);
@@ -530,6 +584,7 @@ private:
std::vector<Praxisd::indholdstof_t>
Praxisd::diverse_get_indholdstof(std::string sogenr)
+ throw(const char*)
{
std::vector<Praxisd::indholdstof_t> lst;
std::string xml = get_sogenr("I"+sogenr);
@@ -563,6 +618,7 @@ private:
std::vector<Praxisd::klage_t>
Praxisd::diverse_get_klage(std::string sogenr)
+ throw(const char*)
{
std::vector<Praxisd::klage_t> lst;
std::string xml = get_sogenr("K"+sogenr);
@@ -595,6 +651,7 @@ private:
std::vector<Praxisd::oversigt_t>
Praxisd::diverse_get_oversigt(std::string sogenr)
+ throw(const char*)
{
std::vector<Praxisd::oversigt_t> lst;
std::string xml = get_sogenr("O"+sogenr);
@@ -632,6 +689,7 @@ private:
std::vector<Praxisd::postnummer_t>
Praxisd::diverse_get_postnummer(std::string sogenr)
+ throw(const char*)
{
std::vector<Praxisd::postnummer_t> lst;
std::string xml = get_sogenr("P"+sogenr);
@@ -666,6 +724,7 @@ private:
std::vector<Praxisd::type_t>
Praxisd::diverse_get_type(std::string sogenr)
+ throw(const char*)
{
std::vector<Praxisd::type_t> lst;
std::string xml = get_sogenr("T"+sogenr);
@@ -699,6 +758,7 @@ private:
std::vector<Praxisd::undersoegelse_t>
Praxisd::diverse_get_undersoegelse(std::string sogenr)
+ throw(const char*)
{
std::vector<Praxisd::undersoegelse_t> lst;
std::string xml = get_sogenr("U"+sogenr);
@@ -736,6 +796,7 @@ private:
std::vector<Praxisd::ydelse_t>
Praxisd::diverse_get_ydelse(std::string sogenr)
+ throw(const char*)
{
std::vector<Praxisd::ydelse_t> lst;
std::string xml = get_sogenr("Y"+sogenr);
@@ -755,7 +816,7 @@ public:
if(name == "aftale") {
Praxisd::aftale_t a;
if(attr.find("date") != attr.end()) a.date = attr["date"];
- if(attr.find("calendar") != attr.end()) a.date = attr["calendar"];
+ if(attr.find("calendar") != attr.end()) a.calendar = attr["calendar"];
div.push_back(a);
}
DODIVTAG(cpr);
@@ -775,8 +836,9 @@ static std::string i2s(int i) {
return buf;
}
std::vector<Praxisd::aftale_t>
-Praxisd::aftale_get_all_by_date_and_calendar(int cal, int year, int month,
- int day)
+Praxisd::aftale_get_all_by_date_and_calendar(int cal,
+ int year, int month, int day)
+ throw(const char*)
{
std::vector<Praxisd::aftale_t> aft;
@@ -792,7 +854,13 @@ Praxisd::aftale_get_all_by_date_and_calendar(int cal, int year, int month,
CURLcode errornum = curl_easy_perform(ch);
if(errornum != CURLE_OK) {
- printf("Ouch %d\n", errornum);
+ throw curl_easy_strerror(errornum);
+ }
+
+ long code = 0;
+ errornum = curl_easy_getinfo(ch, CURLINFO_RESPONSE_CODE, &code);
+ if(code != 200) {
+ throw str2err(xml);
}
AftaleParser parser(aft);
@@ -802,6 +870,7 @@ Praxisd::aftale_get_all_by_date_and_calendar(int cal, int year, int month,
}
std::vector<Praxisd::aftale_t> Praxisd::aftale_get_all_by_cpr(std::string cpr)
+ throw(const char*)
{
std::vector<Praxisd::aftale_t> aft;
@@ -815,7 +884,13 @@ std::vector<Praxisd::aftale_t> Praxisd::aftale_get_all_by_cpr(std::string cpr)
CURLcode errornum = curl_easy_perform(ch);
if(errornum != CURLE_OK) {
- printf("Ouch %d\n", errornum);
+ throw curl_easy_strerror(errornum);
+ }
+
+ long code = 0;
+ errornum = curl_easy_getinfo(ch, CURLINFO_RESPONSE_CODE, &code);
+ if(code != 200) {
+ throw str2err(xml);
}
AftaleParser parser(aft);
@@ -825,6 +900,7 @@ std::vector<Praxisd::aftale_t> Praxisd::aftale_get_all_by_cpr(std::string cpr)
}
bool Praxisd::authenticate(std::string user, std::string pass)
+ throw(const char*)
{
std::string uri = host + "/praxisd/1.0/authenticate?user=" + user + "&pass=" +
pass;
@@ -835,11 +911,14 @@ bool Praxisd::authenticate(std::string user, std::string pass)
CURLcode errornum = curl_easy_perform(ch);
if(errornum != CURLE_OK) {
- return false;
+ throw curl_easy_strerror(errornum);
}
long code = 0;
errornum = curl_easy_getinfo(ch, CURLINFO_RESPONSE_CODE, &code);
+ if(errornum != CURLE_OK) {
+ throw curl_easy_strerror(errornum);
+ }
if(code == 401) return false;
if(code == 200) return true;
@@ -876,6 +955,7 @@ private:
};
std::vector<Praxisd::dokmenu_t> Praxisd::dokmenu_get_all_by_cpr(std::string cpr)
+ throw(const char*)
{
std::vector<Praxisd::dokmenu_t> dokmenu;
std::string xml;
@@ -888,7 +968,13 @@ std::vector<Praxisd::dokmenu_t> Praxisd::dokmenu_get_all_by_cpr(std::string cpr)
CURLcode errornum = curl_easy_perform(ch);
if(errornum != CURLE_OK) {
- printf("Ouch %d\n", errornum);
+ throw curl_easy_strerror(errornum);
+ }
+
+ long code = 0;
+ errornum = curl_easy_getinfo(ch, CURLINFO_RESPONSE_CODE, &code);
+ if(code != 200) {
+ throw str2err(xml);
}
DokMenuParser parser(dokmenu);
@@ -900,6 +986,7 @@ std::vector<Praxisd::dokmenu_t> Praxisd::dokmenu_get_all_by_cpr(std::string cpr)
// Get Dokmenu by Name and CPR
std::string Praxisd::dokmenu_get_by_cpr_and_name(std::string cpr,
std::string name)
+ throw(const char*)
{
std::string data;
@@ -912,7 +999,13 @@ std::string Praxisd::dokmenu_get_by_cpr_and_name(std::string cpr,
CURLcode errornum = curl_easy_perform(ch);
if(errornum != CURLE_OK) {
- printf("Ouch %d\n", errornum);
+ throw curl_easy_strerror(errornum);
+ }
+
+ long code = 0;
+ errornum = curl_easy_getinfo(ch, CURLINFO_RESPONSE_CODE, &code);
+ if(code != 200) {
+ throw str2err(data);
}
return data;
diff --git a/server/src/praxisd.h b/server/src/praxisd.h
index 84848b8..785cba1 100644
--- a/server/src/praxisd.h
+++ b/server/src/praxisd.h
@@ -37,13 +37,16 @@
class Praxisd {
public:
- Praxisd(std::string host, int port);
+ Praxisd(std::string host, int port)
+ throw(const char*);
~Praxisd();
- time_t journal_last_changed(std::string cpr);
+ time_t journal_last_changed(std::string cpr)
+ throw(const char*);
// Get Journal By CPR
- std::string journal_get_by_cpr(std::string cpr);
+ std::string journal_get_by_cpr(std::string cpr)
+ throw(const char*);
// Get Patient By CPR
typedef struct {
@@ -89,7 +92,8 @@ public:
std::string unknown251;
std::string jtime;
} patient_t;
- patient_t patient_get_by_cpr(std::string cpr);
+ patient_t patient_get_by_cpr(std::string cpr)
+ throw(const char*);
// Get Diverse From Sogenr
typedef struct {
@@ -102,7 +106,8 @@ public:
std::string tlf;
std::string fax;
} adresse_t;
- std::vector<adresse_t> diverse_get_adresse(std::string sogenr);
+ std::vector<adresse_t> diverse_get_adresse(std::string sogenr)
+ throw(const char*);
typedef struct {
std::string sogenr;
@@ -111,7 +116,8 @@ public:
std::string bemaerkning;
std::string udregning;
} behandling_t;
- std::vector<behandling_t> diverse_get_behandling(std::string sogenr);
+ std::vector<behandling_t> diverse_get_behandling(std::string sogenr)
+ throw(const char*);
typedef struct {
std::string sogenr;
@@ -120,7 +126,8 @@ public:
std::string bemaerkning2;
std::string bemaerkning3;
} cave_t;
- std::vector<cave_t> diverse_get_cave(std::string sogenr);
+ std::vector<cave_t> diverse_get_cave(std::string sogenr)
+ throw(const char*);
typedef struct {
std::string sogenr;
@@ -128,7 +135,8 @@ public:
std::string diagnose;
std::string bemaerkning;
} diagnose_t;
- std::vector<diagnose_t> diverse_get_diagnose(std::string sogenr);
+ std::vector<diagnose_t> diverse_get_diagnose(std::string sogenr)
+ throw(const char*);
typedef struct {
std::string sogenr;
@@ -137,14 +145,16 @@ public:
std::string frase3;
std::string frase4;
} frase_t;
- std::vector<frase_t> diverse_get_frase(std::string sogenr);
+ std::vector<frase_t> diverse_get_frase(std::string sogenr)
+ throw(const char*);
typedef struct {
std::string sogenr;
std::string navn;
std::string bemaerkning;
} grafik_t;
- std::vector<grafik_t> diverse_get_grafik(std::string sogenr);
+ std::vector<grafik_t> diverse_get_grafik(std::string sogenr)
+ throw(const char*);
typedef struct {
std::string sogenr;
@@ -154,7 +164,8 @@ public:
std::string form3;
std::string form4;
} indholdstof_t;
- std::vector<indholdstof_t> diverse_get_indholdstof(std::string sogenr);
+ std::vector<indholdstof_t> diverse_get_indholdstof(std::string sogenr)
+ throw(const char*);
typedef struct {
std::string sogenr;
@@ -162,14 +173,16 @@ public:
std::string klage;
std::string bemaerkning;
} klage_t;
- std::vector<klage_t> diverse_get_klage(std::string sogenr);
+ std::vector<klage_t> diverse_get_klage(std::string sogenr)
+ throw(const char*);
typedef struct {
std::string sogenr;
std::string navn;
std::string bemaerkning;
} oversigt_t;
- std::vector<oversigt_t> diverse_get_oversigt(std::string sogenr);
+ std::vector<oversigt_t> diverse_get_oversigt(std::string sogenr)
+ throw(const char*);
typedef struct {
std::string sogenr;
@@ -181,7 +194,8 @@ public:
std::string regionnavn;
std::string kommunenavn;
} postnummer_t;
- std::vector<postnummer_t> diverse_get_postnummer(std::string sogenr);
+ std::vector<postnummer_t> diverse_get_postnummer(std::string sogenr)
+ throw(const char*);
typedef struct {
std::string sogenr;
@@ -191,7 +205,8 @@ public:
std::string bemaerkning3;
std::string recept;
} type_t;
- std::vector<type_t> diverse_get_type(std::string sogenr);
+ std::vector<type_t> diverse_get_type(std::string sogenr)
+ throw(const char*);
typedef struct {
std::string sogenr;
@@ -200,7 +215,8 @@ public:
std::string bemaerkning;
std::string udregning;
} undersoegelse_t;
- std::vector<undersoegelse_t> diverse_get_undersoegelse(std::string sogenr);
+ std::vector<undersoegelse_t> diverse_get_undersoegelse(std::string sogenr)
+ throw(const char*);
typedef struct {
std::string sogenr;
@@ -213,7 +229,8 @@ public:
std::string journal2;
std::string moms;
} ydelse_t;
- std::vector<ydelse_t> diverse_get_ydelse(std::string sogenr);
+ std::vector<ydelse_t> diverse_get_ydelse(std::string sogenr)
+ throw(const char*);
// Get Aftale All by Date and Calendar
@@ -227,17 +244,21 @@ public:
std::string cres;
} aftale_t;
std::vector<aftale_t> aftale_get_all_by_date_and_calendar(int cal, int year,
- int month, int day);
+ int month, int day)
+ throw(const char*);
// Get Aftale All by CPR
- std::vector<aftale_t> aftale_get_all_by_cpr(std::string cpr);
+ std::vector<aftale_t> aftale_get_all_by_cpr(std::string cpr)
+ throw(const char*);
// Authenticate
- bool authenticate(std::string user, std::string pass);
+ bool authenticate(std::string user, std::string pass)
+ throw(const char*);
#if 0
// Get Name by UserID
- std::string user_get_name_by_id(std::string user);
+ std::string user_get_name_by_id(std::string user)
+ throw(const char*);
#endif
// Get All Dokmenu by CPR
@@ -248,19 +269,23 @@ public:
size_t filesize;
std::string date;
} dokmenu_t;
- std::vector<dokmenu_t> dokmenu_get_all_by_cpr(std::string cpr);
+ std::vector<dokmenu_t> dokmenu_get_all_by_cpr(std::string cpr)
+ throw(const char*);
// Get Dokmenu by Name and CPR
- std::string dokmenu_get_by_cpr_and_name(std::string cpr, std::string name);
+ std::string dokmenu_get_by_cpr_and_name(std::string cpr, std::string name)
+ throw(const char*);
// POST:
// Add To Journal
- void journal_add(std::string cpr, std::string entry);
+ void journal_add(std::string cpr, std::string entry)
+ throw(const char*);
// Update Patient
// Add Sogeord to Patient
- void add_sogeord(std::string cpr, std::string sogeord, std::string sogetxt);
+ void add_sogeord(std::string cpr, std::string sogeord, std::string sogetxt)
+ throw(const char*);
// Update Aftale
// Add Aftale
@@ -269,7 +294,8 @@ public:
// Delete File from Dokmenu
private:
- std::string get_sogenr(std::string sogenr);
+ std::string get_sogenr(std::string sogenr)
+ throw(const char*);
CURL *ch;
std::string host;
};
diff --git a/server/src/resumeparser.cc b/server/src/resumeparser.cc
deleted file mode 100644
index 1c5335a..0000000
--- a/server/src/resumeparser.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/***************************************************************************
- * resumeparser.cc
- *
- * Mon Oct 1 11:17:35 CEST 2007
- * Copyright 2007 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 "resumeparser.h"
-
-#include <string.h>
-
-#include "luaresume.h"
-#include "configuration.h"
-
-std::string resume_parser(Macro &macro, Commit &commit)
-{
- LUAResume luaresume(commit);
-
- std::string code;
-
- std::vector< Script >::iterator spi = macro.resume_scripts.begin();
- while(spi != macro.resume_scripts.end()) {
- if(spi->attributes.find("src") != spi->attributes.end()) {
- std::string src = spi->attributes["src"];
- std::string file =
- Conf::xml_basedir + "/include/" + src;
- FILE *fp = fopen(file.c_str(), "r");
- if(fp) {
- char buf[64];
- size_t sz;
- std::string inc;
- while((sz = fread(buf, 1, sizeof(buf), fp)) != 0) {
- inc.append(buf, sz);
- }
- fclose(fp);
- code += "\n-- BEGIN INCLUDE: '" + src + "'\n";
- code += inc;
- code += "\n-- END INCLUDE: '" + src + "'\n";
- }
- } else {
- code += spi->code;
- }
- spi++;
- }
-
- return luaresume.run(code);
-}
-
-#ifdef TEST_RESUMEPARSER
-//deps: luaresume.cc configuration.cc debug.cc log.cc luautil.cc
-//cflags: -I.. $(LUA_CFLAGS)
-//libs: $(LUA_LIBS)
-#include <test.h>
-
-TEST_BEGIN;
-
-// TODO: Put some testcode here (see test.h for usable macros).
-TEST_TRUE(false, "No tests yet!");
-
-TEST_END;
-
-#endif/*TEST_RESUMEPARSER*/
diff --git a/server/src/saxparser.cc b/server/src/saxparser.cc
index 95efffe..14f204c 100644
--- a/server/src/saxparser.cc
+++ b/server/src/saxparser.cc
@@ -130,6 +130,8 @@ bool SAXParser::parse(const char *data, size_t size)
xml.append(data, size);
DEBUG(sax, "parse %d bytes [%s]\n", size, xml.c_str());
+ if(data == NULL || size == 0) return done;
+
bufferbytes = size;
totalbytes += bufferbytes;
diff --git a/server/src/server.cc b/server/src/server.cc
index e4d6474..838da32 100644
--- a/server/src/server.cc
+++ b/server/src/server.cc
@@ -37,6 +37,9 @@
#include "client_connection.h"
#include "admin_connection.h"
+extern std::string logfile;
+extern volatile bool logfile_reload;
+
class PracroHttpd : public Httpd {
public:
PracroHttpd() {}
@@ -57,6 +60,12 @@ public:
headers_t &getargs,
headers_t &headers)
{
+ if(logfile_reload) {
+ DEBUG(pracrod, "Reopen log file %s\n", logfile.c_str());
+ debug_reinit(logfile.c_str());
+ logfile_reload = false;
+ }
+
Connection *connection = NULL;
if(headers.find("User-Agent") != headers.end() &&
@@ -73,7 +82,7 @@ public:
{
if(ptr) {
Connection *connection = (Connection *)ptr;
- connection->handle(data, data_size);
+ connection->data(data, data_size);
}
return true;
}
@@ -84,7 +93,7 @@ public:
Connection *connection = (Connection *)ptr;
// Flush and do commit/discards
- connection->handle(NULL, 0);
+ if(!connection->handle()) return false;
connection->getReply(reply);
}
diff --git a/server/src/session.cc b/server/src/session.cc
index fcd138a..ea4d11c 100644
--- a/server/src/session.cc
+++ b/server/src/session.cc
@@ -55,6 +55,8 @@ Session::Session(Environment *e,
patientid = pid;
templ = t;
+ mutex.name = "session-" + sid;
+
DEBUG(session, "[%p] new Session(sessionid: '%s', patientid: '%s',"
" template: '%s')\n", this, sid.c_str(), pid.c_str(), t.c_str());
@@ -82,10 +84,20 @@ std::string Session::id()
void Session::lock()
{
mutex.lock();
+ DEBUG(session, "lock() %p (%s)\n", this, sessionid.c_str());
+}
+
+bool Session::trylock()
+{
+ bool r = mutex.trylock();
+ DEBUG(session, "trylock() %p (%s) == %s\n",
+ this, sessionid.c_str(), r?"true":"false");
+ return r;
}
void Session::unlock()
{
+ DEBUG(session, "unlock() %p (%s)\n", this, sessionid.c_str());
mutex.unlock();
}
@@ -121,12 +133,21 @@ void Session::setIdle(bool idle)
}
}
-void Session::commit()
+void Session::commit() throw(LUAScript::Exception, Journal::Exception)
{
DEBUG(session, "[%p] commit(sessionid: '%s')\n", this, sessionid.c_str());
if(_journal != NULL) {
- _journal->commit();
+ try {
+ _journal->runOnCommitScripts();
+ } catch(LUAScript::Exception &e) {
+ throw e;
+ }
+ try {
+ _journal->commit();
+ } catch(Journal::Exception &e) {
+ throw e;
+ }
delete _journal;
_journal = NULL;
}
@@ -290,28 +311,76 @@ size_t Sessions::size()
void Sessions::store()
{
+ Session *session = NULL;
+ std::string sessionid;
+ do {
+ bool waitcont = false;
+ session = NULL;
+ {
+ MutexAutolock lock(mutex);
+ std::map<std::string, Session*>::iterator head = sessions.begin();
+ if(head != sessions.end()) {
+ session = head->second;
+ sessionid = head->first;
+ if(session->trylock()) {
+ sessions.erase(sessionid);
+ } else {
+ waitcont = true;
+ }
+ }
+ }
+
+ if(waitcont) {
+ usleep(200000); // sleep 200ms
+ continue;
+ }
+
+ if(session != NULL) {
+ SessionSerialiser ser(env, Conf::session_path);
+ ser.save(session);
+ delete session;
+ }
+ } while(session != NULL);
+
+ /*
MutexAutolock lock(mutex);
std::map<std::string, Session*>::iterator i = sessions.begin();
while(i != sessions.end()) {
SessionSerialiser ser(env, Conf::session_path);
- ser.save(i->second);
- delete i->second;
- sessions.erase(i);
+ Session *s = i->second;
+ s->lock();
+ ser.save(s);
+ delete s;
i++;
}
sessions.clear();
+ */
}
-std::vector<std::string> Sessions::activeSessions()
+std::vector<Sessions::SessionInfo> Sessions::activeSessions()
{
MutexAutolock lock(mutex);
- std::vector<std::string> act;
+ std::vector<SessionInfo> act;
std::map<std::string, Session*>::iterator i = sessions.begin();
while(i != sessions.end()) {
- act.push_back(i->first);
+ Session *s = i->second;
+ SessionInfo si;
+ si.id = i->first;
+ si.templ = "LOCKED";
+
+ if(s->trylock()) {
+ // si.user = "simpson";
+ // si.course = s->course;
+ si.patientid = s->patientid;
+ si.templ = s->templ;
+ si.idle = s->idle();
+ // si.ondisc = false;
+ s->unlock();
+ }
+ act.push_back(si);
i++;
}
@@ -326,6 +395,7 @@ SessionAutounlock::SessionAutounlock(Session **s)
SessionAutounlock::~SessionAutounlock()
{
+ DEBUG(session, "SessionAutounlock(%p)\n", *session);
if(*session) (*session)->unlock();
}
diff --git a/server/src/session.h b/server/src/session.h
index 4d1ed12..1cb3041 100644
--- a/server/src/session.h
+++ b/server/src/session.h
@@ -37,6 +37,9 @@
#include "transaction.h"
#include "template.h"
+#include "luascript.h"
+#include "journal.h"
+
class Environment;
class Journal;
@@ -50,9 +53,10 @@ public:
std::string id();
void lock();
+ bool trylock();
void unlock();
- void commit();
+ void commit() throw(LUAScript::Exception, Journal::Exception);
void nocommit();
void discard();
@@ -128,7 +132,17 @@ public:
//
// Admin methods
//
- std::vector<std::string> activeSessions();
+ class SessionInfo {
+ public:
+ std::string id;
+ std::string patientid;
+ std::string user;
+ std::string course;
+ std::string templ;
+ bool idle;
+ bool ondisc;
+ };
+ std::vector<SessionInfo> activeSessions();
private:
std::map<std::string, Session *> sessions;
diff --git a/server/src/sessionheaderparser.cc b/server/src/sessionheaderparser.cc
new file mode 100644
index 0000000..c9a8e67
--- /dev/null
+++ b/server/src/sessionheaderparser.cc
@@ -0,0 +1,182 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * sessionheaderparser.cc
+ *
+ * Thu Aug 9 09:06:32 CEST 2012
+ * Copyright 2012 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 "sessionheaderparser.h"
+
+/*
+<session timestamp="1234567890"
+ status="readonly""
+ id="12345"
+ template="amd_forunders"
+ patientid="0000000000">
+ ...
+</session>
+*/
+
+#include <stdio.h>
+
+// For assert
+#include <assert.h>
+
+// For open and friends
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+// For vprintf and friends
+#include <stdarg.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include "debug.h"
+#include "configuration.h"
+#include "exception.h"
+
+void SessionHeaderParser::error(const char* fmt, ...)
+{
+ ERR_LOG(session, "Error in SessionHeaderParser: ");
+
+ {
+ va_list argp;
+ va_start(argp, fmt);
+ ERR_LOG_VA(session, fmt, argp);
+ va_end(argp);
+
+ fprintf(stderr, "\n");
+ }
+
+ {
+ char *p;
+ va_list argp;
+ va_start(argp, fmt);
+ if(vasprintf(&p, fmt, argp) != -1) {
+ throw Exception("Error in SessionHeaderParser: " + std::string(p));
+ free(p);
+ }
+ va_end(argp);
+ }
+
+}
+
+SessionHeaderParser::SessionHeaderParser(std::string sessionfile)
+{
+ done = false;
+
+ file = sessionfile;
+
+ DEBUG(session, "Using session file: %s\n", sessionfile.c_str());
+
+ fd = open(sessionfile.c_str(), O_RDONLY);
+ if(fd == -1) error("Could not open file %s", sessionfile.c_str());
+}
+
+SessionHeaderParser::~SessionHeaderParser()
+{
+ if(fd != -1) close(fd);
+}
+
+void SessionHeaderParser::startTag(std::string name, attributes_t &attr)
+{
+ if(done) return;
+
+ if(name == "session") {
+ done = true;
+ if(attr.find("patientid") != attr.end()) {
+ header.patientid = attr["patientid"];
+ }
+
+ if(attr.find("template") != attr.end()) {
+ header.templ = attr["template"];
+ }
+
+ if(attr.find("id") != attr.end()) {
+ header.id = attr["id"];
+ }
+ } else {
+ throw Exception("Missing root tag 'session' - found '" + name + "'");
+ }
+}
+
+int SessionHeaderParser::readData(char *data, size_t size)
+{
+ if(done) return 0; // If done is true we already found what we were looking
+ // for and can dismiss the rest of the document.
+
+ if(fd == -1) {
+ ERR_LOG(session, "Invalid file descriptor.\n");
+ return 0;
+ }
+ ssize_t r = read(fd, data, size);
+ if(r == -1) {
+ ERR_LOG(session, "Could not read...%s\n", strerror(errno));
+ return 0;
+ }
+ return r;
+}
+
+void SessionHeaderParser::parseError(const char *buf, size_t len, std::string error, int lineno)
+{
+ if(done) return; // If done is true we already found what we were looking
+ // for and can dismiss the rest of the document.
+
+ ERR_LOG(session, "SessionHeaderParser[%s] error at line %d: %s\n",
+ file.c_str(), lineno, error.c_str());
+ ERR_LOG(session, "\tBuffer %u bytes: [", len);
+ if(fwrite(buf, len, 1, stderr) != len) {}
+ ERR_LOG(session, "]\n");
+
+ char *slineno;
+ if(asprintf(&slineno, " at line %d\n", lineno) != -1) {
+ throw Exception(error + slineno);
+ free(slineno);
+ }
+}
+
+SessionHeaderParser::Header SessionHeaderParser::getHeader()
+{
+ return header;
+}
+
+#ifdef TEST_SESSIONHEADERPARSER
+//Additional dependency files
+//deps:
+//Required cflags (autoconf vars may be used)
+//cflags:
+//Required link options (autoconf vars may be used)
+//libs:
+#include "test.h"
+
+TEST_BEGIN;
+
+// TODO: Put some testcode here (see test.h for usable macros).
+TEST_TRUE(false, "No tests yet!");
+
+TEST_END;
+
+#endif/*TEST_SESSIONHEADERPARSER*/
diff --git a/server/src/sessionheaderparser.h b/server/src/sessionheaderparser.h
new file mode 100644
index 0000000..5f2d3cf
--- /dev/null
+++ b/server/src/sessionheaderparser.h
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * sessionheaderparser.h
+ *
+ * Thu Aug 9 09:06:32 CEST 2012
+ * Copyright 2012 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_SESSIONHEADERPARSER_H__
+#define __PRACRO_SESSIONHEADERPARSER_H__
+
+#include "saxparser.h"
+
+/**
+ * Partial session parser.
+ * This class is used to parse only the first tag of a session xml file.
+ * The parser will run about 10 times faster than the one parsing the entire
+ * file (see the SessionParser class) and can be used to find a
+ * patientid/template match.
+ * This class inherits the SAXParser baseclass.
+ * Use the parse() method to run the parser, and collect the result via the
+ * getPatientID() and getTemplate() methods.
+ * If the file does not contain a session, or the file is not a valid xml file,
+ * an Exception is thrown.
+ */
+class SessionHeaderParser : public SAXParser {
+public:
+ class Header {
+ public:
+ std::string patientid;
+ std::string templ;
+ std::string id;
+ };
+
+ /**
+ * Constructor.
+ * @param sessionfile A std::string containing the name of the file to parse.
+ */
+ SessionHeaderParser(std::string sessionfile);
+
+ /**
+ * Destructor.
+ */
+ ~SessionHeaderParser();
+
+ /**
+ * Overloaded parser callback method.
+ */
+ void startTag(std::string name, attributes_t &attr);
+
+ /**
+ * Overloaded parser callback method.
+ */
+ void parseError(const char *buf, size_t len, std::string error, int lineno);
+
+ /**
+ * Get a pointer to the parsed macro.
+ * NOTE: The allocated memory for the macro is owned by the parser, and will be
+ * freed upon parser deletion.
+ * @return A pointer to the macro or NULL on error.
+ */
+ Header getHeader();
+
+protected:
+ /**
+ * Overloaded parser callback method.
+ */
+ int readData(char *data, size_t size);
+
+private:
+ int fd;
+
+ bool done;
+
+ Header header;
+
+ std::string file;
+ // Error callback function.
+ void error(const char* fmt, ...);
+};
+
+#endif/*__PRACRO_SESSIONHEADERPARSER_H__*/
diff --git a/server/src/sessionparser.cc b/server/src/sessionparser.cc
index 6b3653e..8913e3c 100644
--- a/server/src/sessionparser.cc
+++ b/server/src/sessionparser.cc
@@ -37,6 +37,9 @@ SessionParser::SessionParser()
totalbytes = 0;
inresume = false;
indatabase = false;
+ invalue = false;
+ inscript = false;
+ inenv = false;
}
SessionParser::~SessionParser()
@@ -49,6 +52,26 @@ void SessionParser::characterData(std::string &data)
entries[entries.size()-1].resume += data;
}
+ if(inscript) {
+ Entry &e = entries[entries.size() - 1];
+ LUAOnCommit *oncommit = e.oncommit;
+ std::pair<std::string, std::string> &val =
+ oncommit->scripts[oncommit->scripts.size() - 1];
+ val.first += data;
+ }
+
+ if(invalue) {
+ Entry &e = entries[entries.size() - 1];
+ LUAOnCommit *oncommit = e.oncommit;
+ oncommit->values[valuename] += data;
+ }
+
+ if(inenv) {
+ Entry &e = entries[entries.size() - 1];
+ LUAOnCommit *oncommit = e.oncommit;
+ oncommit->_env[envid] += data;
+ }
+
if(indatabase) {
database += data;
}
@@ -80,12 +103,51 @@ void SessionParser::startTag(std::string name, attributes_t &attr)
e.index = atoi(attr["index"].c_str());
e.macro = attr["macro"];
e.user = attr["user"];
+ e.oncommit = NULL;
entries.push_back(e);
}
if(name == "resume") {
inresume = true;
}
+
+ if(name == "oncommit") {
+ Entry &e = entries[entries.size() - 1];
+ if(e.oncommit != NULL) {
+ ERR(sessionparser, "Multiple oncommit tags in journal!\n");
+ return;
+ }
+ e.oncommit = new LUAOnCommit();
+ }
+ if(name == "envs") { }
+
+ if(name == "env") {
+ if(attr["id"] == "ENV_PATIENTID") envid = LUAScript::ENV_PATIENTID;
+ else if(attr["id"] == "ENV_TEMPLATE") envid = LUAScript::ENV_TEMPLATE;
+ else if(attr["id"] == "ENV_MACRO") envid = LUAScript::ENV_MACRO;
+ else if(attr["id"] == "ENV_USER") envid = LUAScript::ENV_USER;
+ else {
+ // Unknown env id
+ return;
+ }
+ inenv = true;
+ }
+
+ if(name == "values") { }
+
+ if(name == "value") {
+ valuename = attr["name"];
+ invalue = true;
+ }
+
+ if(name == "scripts") {}
+
+ if(name == "script") {
+ Entry &e = entries[entries.size() - 1];
+ LUAOnCommit *oncommit = e.oncommit;
+ oncommit->addCode("", attr["name"]);
+ inscript = true;
+ }
}
void SessionParser::endTag(std::string name)
@@ -96,6 +158,15 @@ void SessionParser::endTag(std::string name)
if(name == "database") {
indatabase = false;
}
+ if(name == "env") {
+ inenv = false;
+ }
+ if(name == "value") {
+ invalue = false;
+ }
+ if(name == "script") {
+ inscript = false;
+ }
}
void SessionParser::parseError(const char *buf, size_t len,
diff --git a/server/src/sessionparser.h b/server/src/sessionparser.h
index df32b06..8734fbd 100644
--- a/server/src/sessionparser.h
+++ b/server/src/sessionparser.h
@@ -30,6 +30,8 @@
#include "saxparser.h"
+#include "luaoncommit.h"
+
#include <string>
#include <vector>
@@ -50,10 +52,11 @@ public:
std::string userid;
std::string database;
std::string dbtype;
-
+
class Entry {
public:
int index;
+ LUAOnCommit *oncommit;
std::string macro;
std::string resume;
std::string user;
@@ -63,7 +66,12 @@ public:
private:
bool inresume;
+ bool inscript;
+ bool invalue;
+ bool inenv;
+ std::string valuename;
bool indatabase;
+ LUAScript::env_t envid;
};
#endif/*__PRACRO_SESSIONPARSER_H__*/
diff --git a/server/src/sessionserialiser.cc b/server/src/sessionserialiser.cc
index 36d0a0d..6288ddd 100644
--- a/server/src/sessionserialiser.cc
+++ b/server/src/sessionserialiser.cc
@@ -34,6 +34,7 @@
#include "journal.h"
#include "sessionparser.h"
+#include "sessionheaderparser.h"
#include "database.h"
#include "xml_encode_decode.h"
@@ -88,7 +89,8 @@ Session *SessionSerialiser::loadStr(const std::string &xml)
j->setPatientID(XDEC(parser.patientid));
std::vector<SessionParser::Entry>::iterator i = parser.entries.begin();
while(i != parser.entries.end()) {
- j->addEntry(XDEC(i->resume), XDEC(i->macro), XDEC(i->user), i->index);
+ j->addEntry(XDEC(i->resume), XDEC(i->macro), XDEC(i->user), i->index,
+ i->oncommit);
i++;
}
@@ -122,6 +124,50 @@ std::string SessionSerialiser::saveStr(Session *session)
" macro=\"" + XENC(i->second.macro) + "\""
" user=\"" + XENC(i->second.user) + "\">\n";
xml += " <resume>" + XENC(i->second.resume) + "</resume>\n";
+ LUAOnCommit *oncommit = i->second.oncommit;
+ if(oncommit != NULL) {
+ xml += " <oncommit>\n";
+
+ xml += " <envs>\n";
+ std::map<LUAScript::env_t, std::string>::iterator ei =
+ oncommit->_env.begin();
+ while(ei != oncommit->_env.end()) {
+ std::string id;
+ switch(ei->first) {
+ case LUAScript::ENV_PATIENTID: id = "ENV_PATIENTID"; break;
+ case LUAScript::ENV_TEMPLATE: id = "ENV_TEMPLATE"; break;
+ case LUAScript::ENV_MACRO: id = "ENV_MACRO"; break;
+ case LUAScript::ENV_USER: id = "ENV_USER"; break;
+ }
+
+ xml += " <env id=\"" + XENC(id) + "\">"+
+ XENC(ei->second) + "</env>\n";
+ ei++;
+ }
+ xml += " </envs>\n";
+
+ xml += " <values>\n";
+ std::map<std::string, std::string>::iterator vi =
+ oncommit->values.begin();
+ while(vi != oncommit->values.end()) {
+ xml += " <value name=\"" + XENC(vi->first) + "\">"+
+ XENC(vi->second) + "</value>\n";
+ vi++;
+ }
+ xml += " </values>\n";
+
+ xml += " <scripts>\n";
+ std::vector<std::pair<std::string, std::string> >::iterator si =
+ oncommit->scripts.begin();
+ while(si != oncommit->scripts.end()) {
+ xml += " <script name=\"" + XENC(si->second) + "\">"+
+ XENC(si->first) + "</script>\n";
+ si++;
+ }
+ xml += " </scripts>\n";
+
+ xml += " </oncommit>\n";
+ }
xml += " </entry>\n";
i++;
@@ -170,6 +216,11 @@ void SessionSerialiser::save(Session *session)
// write xml to file
FILE *fp = fopen(filename.c_str(), "w");
+ if(!fp) {
+ ERR(sessionserialiser, "Could not write session to file %s\n",
+ filename.c_str());
+ return;
+ }
fwrite(xml.data(), xml.size(), 1, fp);
fclose(fp);
}
@@ -210,25 +261,34 @@ Session *SessionSerialiser::findFromTupple(const std::string &patientid,
DEBUG(sessionserialiser, "Is xml file\n");
- // Load session file
- FILE *fp = fopen(filename.c_str(), "r");
- std::string xml;
- while(!feof(fp)) {
- char str[64];
- memset(str, 0, sizeof(str));
- fread(str, sizeof(str) - 1, 1, fp);
- xml += str;
+ SessionHeaderParser::Header header;
+
+ SessionHeaderParser p(filename);
+ try {
+ p.parse();
+ header = p.getHeader();
+ } catch( ... ) {
+ continue;
}
- fclose(fp);
- Session *session = loadStr(xml);
+ if(header.patientid == patientid && header.templ == templ) {
+ // Load session file
+ FILE *fp = fopen(filename.c_str(), "r");
+ std::string xml;
+ while(!feof(fp)) {
+ char str[64];
+ memset(str, 0, sizeof(str));
+ fread(str, sizeof(str) - 1, 1, fp);
+ xml += str;
+ }
+ fclose(fp);
+
+ Session *session = loadStr(xml);
- DEBUG(sessionserialiser, "PatientID %s - Template %s\n",
- session->patientid.c_str(),
- session->templ.c_str());
+ DEBUG(sessionserialiser, "PatientID %s - Template %s\n",
+ session->patientid.c_str(),
+ session->templ.c_str());
- if(session->patientid == patientid &&
- session->templ == templ) {
closedir(dir);
unlink(filename.c_str());
return session;
@@ -241,6 +301,46 @@ Session *SessionSerialiser::findFromTupple(const std::string &patientid,
return NULL;
}
+std::map<std::string, SessionHeaderParser::Header>
+SessionSerialiser::sessionFiles()
+{
+ std::map<std::string, SessionHeaderParser::Header> list;
+
+ DIR *dir = opendir(path.c_str());
+ if(!dir) {
+ ERR(sessionserialiser, "Could not open directory: %s - %s\n",
+ path.c_str(), strerror(errno));
+ return list;
+ }
+
+ struct dirent *dirent;
+ while( (dirent = readdir(dir)) != NULL ) {
+
+ std::string filename = path+"/"+dirent->d_name;
+
+ if(isxmlfile(filename)) {
+
+ SessionHeaderParser::Header header;
+
+ SessionHeaderParser p(filename);
+ try {
+ p.parse();
+ header = p.getHeader();
+ } catch( ... ) {
+ continue;
+ }
+
+ list[filename] = header;
+ }
+ }
+
+ closedir(dir);
+
+ return list;
+
+}
+
+
#ifdef TEST_SESSIONSERIALISER
//deps: session.cc journal.cc debug.cc configuration.cc mutex.cc journal_commit.cc sessionparser.cc saxparser.cc xml_encode_decode.cc database.cc pracrodaopgsql.cc pracrodaotest.cc pracrodao.cc journal_uploadserver.cc log.cc environment.cc semaphore.cc artefact.cc macrolist.cc templatelist.cc entitylist.cc inotify.cc versionstr.cc exception.cc macroheaderparser.cc templateheaderparser.cc
//cflags: -I.. $(PTHREAD_CFLAGS) $(EXPAT_CFLAGS) $(PQXX_CFLAGS) -DWITHOUT_ARTEFACT
diff --git a/server/src/sessionserialiser.h b/server/src/sessionserialiser.h
index a85fc63..2c4e7ea 100644
--- a/server/src/sessionserialiser.h
+++ b/server/src/sessionserialiser.h
@@ -29,6 +29,9 @@
#define __PRACRO_SESSIONSERIALISER_H__
#include <string>
+#include <map>
+
+#include "sessionheaderparser.h"
#include "session.h"
@@ -47,6 +50,8 @@ public:
Session *load(const std::string &sessionid);
void save(Session *session);
+ std::map<std::string, SessionHeaderParser::Header> sessionFiles();
+
private:
std::string path;
Environment *env;
diff --git a/server/src/template.h b/server/src/template.h
index a069cff..853db3d 100644
--- a/server/src/template.h
+++ b/server/src/template.h
@@ -67,6 +67,7 @@ public:
maps_t maps;
std::vector< Script > scripts;
std::vector< Script > resume_scripts;
+ std::vector< Script > commit_scripts;
Widget widgets;
Resume resume;
@@ -84,6 +85,8 @@ public:
class Template {
public:
+ std::vector< Script > scripts;
+
std::vector< Macro > macros;
std::string name;
diff --git a/server/src/templateparser.cc b/server/src/templateparser.cc
index b9c65f5..8fc3eff 100644
--- a/server/src/templateparser.cc
+++ b/server/src/templateparser.cc
@@ -81,6 +81,10 @@ TemplateParser::~TemplateParser()
void TemplateParser::characterData(std::string &data)
{
+ if(state == SCRIPT) {
+ assert(current_script); // No script present!
+ current_script->code.append(data);
+ }
}
void TemplateParser::startTag(std::string name, attributes_t &attr)
@@ -127,6 +131,39 @@ void TemplateParser::startTag(std::string name, attributes_t &attr)
return;
}
+ // Enable script parsing
+ if(name == "scripts") {
+ if(state != TEMPLATE) error("scripts found outside template.");
+ state = SCRIPTS;
+
+ assert(t); // No template is currently available, cannot create maps!
+
+ return;
+ }
+
+ // Create script
+ if(name == "script") {
+
+ assert(t); // No template is currently available, cannot create script!
+
+ switch(state) {
+ case SCRIPTS:
+ {
+ state = SCRIPT;
+
+ Script s;
+ s.attributes = attr;
+ t->scripts.push_back(s);
+ current_script = &(t->scripts.back());
+ }
+ break;
+ default:
+ error("<script> tag found outside <scripts> tag.");
+ break;
+ }
+ return;
+ }
+
error("Unknown/illegal tag: %s", name.c_str());
}
@@ -137,6 +174,18 @@ void TemplateParser::endTag(std::string name)
current_macro = NULL;
state = TEMPLATE;
}
+ if(name == "scripts") state = TEMPLATE;
+ if(name == "script") {
+ switch(state) {
+ case SCRIPT:
+ current_script = NULL;
+ state = SCRIPTS;
+ break;
+ default:
+ // tag mismatch?
+ break;
+ }
+ }
}
int TemplateParser::readData(char *data, size_t size)
diff --git a/server/src/templateparser.h b/server/src/templateparser.h
index 5b8302f..89f4917 100644
--- a/server/src/templateparser.h
+++ b/server/src/templateparser.h
@@ -34,6 +34,8 @@ typedef enum {
UNDEFINED,
TEMPLATE,
MACRO,
+ SCRIPTS,
+ SCRIPT
} ParserState;
class TemplateParser : public SAXParser {
@@ -60,6 +62,7 @@ private:
ParserState state;
Template *t;
Macro *current_macro;
+ Script *current_script;
std::vector< Widget* > widgetstack;
// Error callback function.
diff --git a/server/src/transactionhandler.cc b/server/src/transactionhandler.cc
index 5203ee2..6ab3d89 100644
--- a/server/src/transactionhandler.cc
+++ b/server/src/transactionhandler.cc
@@ -28,18 +28,27 @@
#include "transactionhandler.h"
#include "macroparser.h"
-#include "resumeparser.h"
#include "templateparser.h"
#include "templateheaderparser.h"
#include "courseparser.h"
#include "configuration.h"
#include "luaquerymapper.h"
+#include "luaresume.h"
+#include "luaoncommit.h"
#include "queryhandlerpentominos.h"
#include "queryhandlerpracro.h"
#include "xml_encode_decode.h"
#include "widgetgenerator.h"
#include "journal.h"
+#include "exception.h"
+
+class NotFoundException : public Exception {
+public:
+ NotFoundException(Request &r)
+ : Exception("Macro " + r.macro + " not found in template " + r.templ) {}
+};
+
static std::string error_box(std::string message)
{
std::string errorbox =
@@ -52,34 +61,45 @@ static std::string error_box(std::string message)
static std::string handleCommits(Transaction &transaction, Environment &env,
Session &session)
+ throw(LUAScript::Exception)
{
std::string answer;
- if(transaction.commits.size() > 0) {
-
- Commits::iterator i = transaction.commits.begin();
- while(i != transaction.commits.end()) {
- Commit &commit = *i;
-
- MacroParser mp(env.macrolist.getLatestVersion(commit.macro));
- mp.parse();
- Macro *macro = mp.getMacro();
-
- std::string resume = resume_parser(*macro, commit);
+ Commits::iterator i = transaction.commits.begin();
+ while(i != transaction.commits.end()) {
+ Commit &commit = *i;
+
+ MacroParser mp(env.macrolist.getLatestVersion(commit.macro));
+ mp.parse();
+ Macro *macro = mp.getMacro();
+
+ std::string resume;
+ try {
+ LUAResume luaresume(transaction, commit);
+ luaresume.addScripts(macro->resume_scripts);
+ luaresume.run();
+ resume = luaresume.resultString();
commit.fields["journal.resume"] = resume;
session.commitMacro(transaction, commit, *macro);
+ } catch(LUAScript::Exception &e) {
+ throw e;
+ }
- if(resume != "") {
-
- TemplateParser tp(env.templatelist.getLatestVersion(commit.templ));
- tp.parse();
- Template *templ = tp.getTemplate();
-
- session.journal()->addEntry(transaction, commit, resume, templ);
- }
+ LUAOnCommit *oncommit = NULL;
+ if(macro->commit_scripts.size() != 0) {
+ oncommit = new LUAOnCommit(transaction, commit);
+ oncommit->addScripts(macro->commit_scripts);
+ }
+
+ if(resume != "" || oncommit != NULL) {
+ TemplateParser tp(env.templatelist.getLatestVersion(commit.templ));
+ tp.parse();
+ Template *templ = tp.getTemplate();
- i++;
+ session.journal()->addEntry(transaction, commit, resume, templ, oncommit);
}
+
+ i++;
}
return answer;
@@ -87,6 +107,7 @@ static std::string handleCommits(Transaction &transaction, Environment &env,
static std::string handleRequest(Request &request, Environment &env,
Session &session)
+ throw(NotFoundException, Exception)
{
std::string answer;
@@ -244,7 +265,7 @@ static std::string handleRequest(Request &request, Environment &env,
answer +="\n-- END INCLUDE: '"+spi->attributes["src"]+"'\n";
}
} else {
- answer += xml_encode(spi->attributes["code"]);
+ answer += xml_encode(spi->code);
}
answer += "</script>\n";
spi++;
@@ -316,9 +337,9 @@ std::string handleTransaction(Request &request,
try {
answer += handleCommits(transaction, env, session);
- } catch( std::exception &e ) {
- ERR(server, "Commit error: %s\n", e.what());
- return error_box(xml_encode(e.what()));
+ } catch( LUAScript::Exception &e ) {
+ ERR(server, "Commit error: %s\n", e.msg.c_str());
+ return error_box(xml_encode(e.msg));
}
try {
diff --git a/server/src/transactionhandler.h b/server/src/transactionhandler.h
index 43ecf0b..914c9ad 100644
--- a/server/src/transactionhandler.h
+++ b/server/src/transactionhandler.h
@@ -28,18 +28,12 @@
#ifndef __PRACRO_TRANSACTIONHANDLER_H__
#define __PRACRO_TRANSACTIONHANDLER_H__
+#include <string>
+
#include "transaction.h"
#include "session.h"
#include "environment.h"
-#include "exception.h"
-
-class NotFoundException : public Exception {
-public:
- NotFoundException(Request &r)
- : Exception("Macro " + r.macro + " not found in template " + r.templ) {}
-};
-
std::string handleTransaction(Request &resuest,
Transaction &transaction,
Environment &env,