reworked template subsystem
authorkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sat, 22 Nov 2008 15:50:28 +0000 (15:50 +0000)
committerkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Sat, 22 Nov 2008 15:50:28 +0000 (15:50 +0000)
git-svn-id: https://silmor.de/svn/softmagic/smoke/trunk@198 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33

19 files changed:
doc/prog_protocol.html
src/eventsummary.cpp
src/odtrender.cpp
src/odtrender.h
src/orderwin.cpp
src/overview.cpp
src/overview.h
src/smoke.pro
src/templatedlg.cpp [new file with mode: 0644]
src/templatedlg.h [new file with mode: 0644]
src/templates.cpp
src/templates.h
src/ticketrender.cpp
src/ticketrender.h
src/webrequest.cpp
src/webrequest.h
www/inc/machine/template.php
www/inc/machine/version.inc
www/machine.php

index f0cfe90..7299d2b 100644 (file)
@@ -758,7 +758,10 @@ Templates are used for printouts and documents. There are several types of templ
 <li><a href="prog_tickettemplate.html">XML Ticket printer template</a></li>
 </ul><p>
 
-Filenames of templates are restricted to the regular expression <tt>^[a-z0-9_.]+$</tt> and are case-insensitive.
+Base names of templates are restricted to the regular expression <tt>^[a-z0-9_]+$</tt> and are case-insensitive. They may have an extension (legal values: "od[ts]t", "xtt") and a variant ID (at the moment numeric, but may match "^[a-z0-9_]+$").<p>
+
+Below "file name" refers to the complete concatenation of base name, extension, and variant:
+<i>basename</i><b>.</b><i>extension</i>[<b>,</b><i>variant</i>]
 
 <h3>List of Templates</h3>
 
@@ -766,7 +769,7 @@ The <tt>gettemplatelist</tt> transaction returns an informational list of templa
 
 <pre>
 &lt;TList>
-  &lt;Template name="filename" hash="md5-hash"/>
+  &lt;Template name="filename" hash="md5-hash">Description text&lt;/Template>
   ...
 &lt;/TList>
 </pre>
@@ -779,4 +782,10 @@ The <tt>gettemplate</tt> transaction returns a specific template. The request co
 
 <h3>Setting a Template</h3>
 
-The <tt>settemplate</tt> transaction creates a new template file. The request contains the file name terminated with a newline ("\n") and then the binary content of the template - it is important that there are no additional characters between the newline and the template content. The response contains the new hash of the template or error details.
\ No newline at end of file
+The <tt>settemplate</tt> transaction creates a new template file. The request contains the file name terminated with a newline ("\n") and then the binary content of the template - it is important that there are no additional characters between the newline and the template content. The response contains the new hash of the template or error details. The description is initially set to NULL and can be changed later with <tt>settemplatedescription</tt>.<p>
+
+The <tt>settemplatedescription</tt> transaction sets a new description for a template. The first line of the request contains the filename, the remainder the description.
+
+<h3>Deleting a Template</h3>
+
+The <tt>deletetemplate</tt> transaction deletes a template from the database. The request contains the file name (full name). The response is empty. The transaction does not return any errors.
index f9bd8b6..bcc0086 100644 (file)
@@ -171,9 +171,9 @@ void MEventSummary::getSummaryData()
 
 void MEventSummary::print()
 {
-       QString tf=req->getTemplate("eventsummary.odtt");
-       if(tf==""){
-               QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (eventsummary.odtt). Giving up."));
+       MTemplate tf=req->getTemplate("eventsummary");
+       if(!tf.isValid()){
+               QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (eventsummary). Giving up."));
                return;
        }
        MOdtSignalRenderer rend(tf);
@@ -185,17 +185,17 @@ void MEventSummary::print()
 
 void MEventSummary::saveas()
 {
-       QString tf=req->getTemplate("eventsummary.odtt");
-       if(tf==""){
-               QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (eventsummary.odtt). Giving up."));
+       MTemplate tf=req->getTemplate("eventsummary");
+       if(!tf.isValid()){
+               QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (eventsummary). Giving up."));
                return;
        }
        QFileDialog fd(this);
        fd.setAcceptMode(QFileDialog::AcceptSave);
        fd.setFileMode(QFileDialog::AnyFile);
        fd.setConfirmOverwrite(true);
-       fd.setFilter("Open Document Text (*.odt)");
-       fd.setDefaultSuffix("odt");
+       fd.setFilter(tr("Open Document File (*.%1)").arg(tf.targetExtension()));
+       fd.setDefaultSuffix(tf.targetExtension());
        QString fname;
        if(fd.exec()){
                QStringList fn=fd.selectedFiles();
index 40e4fa5..85972ba 100644 (file)
@@ -48,9 +48,9 @@ class MOdtRendererPrivate
                QFile tfile;
 };
 
-MOdtRenderer::MOdtRenderer(QString file)
+MOdtRenderer::MOdtRenderer(MTemplate file)
 {
-       d=new MOdtRendererPrivate(file,this);
+       d=new MOdtRendererPrivate(file.cacheFileName(),this);
 }
 
 MOdtRendererPrivate::MOdtRendererPrivate(QString file,MOdtRenderer*p)
@@ -293,7 +293,7 @@ QString MOdtRendererPrivate::getLoopVariable(QString loopname,int iteration,QStr
 
 /********************************************************************/
 
-MOdtSignalRenderer::MOdtSignalRenderer(QString file)
+MOdtSignalRenderer::MOdtSignalRenderer(MTemplate file)
        :MOdtRenderer(file)
 {
 }
index b707c32..7dc7c62 100644 (file)
@@ -16,6 +16,8 @@
 #include <QObject>
 #include <QString>
 
+#include "templates.h"
+
 class MOdtRendererPrivate;
 class QFile;
 
@@ -24,7 +26,7 @@ class MOdtRenderer
 {
        public:
                /**instantiates a renderer loaded from template file*/
-               MOdtRenderer(QString file);
+               MOdtRenderer(MTemplate file);
                /**deletes the renderer*/
                virtual ~MOdtRenderer();
                
@@ -64,7 +66,7 @@ class MOdtSignalRenderer:public QObject,public MOdtRenderer
        Q_OBJECT
        public:
                /**instantiates a renderer loaded from template file*/
-               MOdtSignalRenderer(QString file);
+               MOdtSignalRenderer(MTemplate file);
                /**deletes the renderer*/
                ~MOdtSignalRenderer();
        
index 89d185e..d8fa0bb 100644 (file)
@@ -252,8 +252,8 @@ void MOrderWindow::printTickets(QList<MTicket> ticketsin)
                return;
        }
        //get template
-       QString tf=req->getTemplate("ticket.xtt");
-       if(tf==""){
+       MTemplate tf=req->getTemplate("ticket");
+       if(!tf.isValid()){
                QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (ticket.xtt). Giving up."));
                return;
        }
@@ -291,8 +291,8 @@ void MOrderWindow::printVouchers(QList<MVoucher> vouchersin)
                return;
        }
        //get template
-       QString tf=req->getTemplate("voucher.xtt");
-       if(tf==""){
+       MTemplate tf=req->getTemplate("voucher");
+       if(!tf.isValid()){
                QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (voucher.xtt). Giving up."));
                return;
        }
@@ -319,9 +319,9 @@ void MOrderWindow::printVouchers(QList<MVoucher> vouchersin)
 void MOrderWindow::printBill()
 {
        //get template
-       QString tf=req->getTemplate("bill.odtt");
-       if(tf==""){
-               QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (bill.odtt). Giving up."));
+       MTemplate tf=req->getTemplate("bill");
+       if(!tf.isValid()){
+               QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (bill). Giving up."));
                return;
        }
        //mark order as shipped?
@@ -342,9 +342,9 @@ void MOrderWindow::printBill()
 void MOrderWindow::saveBill()
 {
        //get template
-       QString tf=req->getTemplate("bill.odtt");
-       if(tf==""){
-               QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (eventsummary.odtt). Giving up."));
+       MTemplate tf=req->getTemplate("bill");
+       if(!tf.isValid()){
+               QMessageBox::warning(this,tr("Warning"),tr("Unable to get template file (eventsummary). Giving up."));
                return;
        }
        //get target file name
@@ -352,8 +352,8 @@ void MOrderWindow::saveBill()
        fd.setAcceptMode(QFileDialog::AcceptSave);
        fd.setFileMode(QFileDialog::AnyFile);
        fd.setConfirmOverwrite(true);
-       fd.setFilter("Open Document Text (*.odt)");
-       fd.setDefaultSuffix("odt");
+       fd.setFilter(tr("Open Document File (*.%1)").arg(tf.targetExtension()));
+       fd.setDefaultSuffix(tf.targetExtension());
        QString fname;
        if(fd.exec()){
                QStringList fn=fd.selectedFiles();
@@ -676,8 +676,8 @@ MOrderItemView::MOrderItemView(QWidget*w,MWebRequest*r,QList<MTicket>t,QList<MVo
                cb->addItem(tr("Voucher: ")+vouchers[i].voucherID());
        vl->addWidget(disp=new QLabel,10);
        //get the templates
-       trender=new MTicketRenderer(req->getTemplate("ticket.xtt"));
-       vrender=new MVoucherRenderer(req->getTemplate("voucher.xtt"));
+       trender=new MTicketRenderer(req->getTemplate("ticket"));
+       vrender=new MVoucherRenderer(req->getTemplate("voucher"));
        changeItem(0);
        connect(cb,SIGNAL(currentIndexChanged(int)),this,SLOT(changeItem(int)));
 }
index 219e63f..4fafd46 100644 (file)
@@ -66,7 +66,8 @@ MOverview::MOverview(MWebRequest*mw,QString pk)
        m->addAction(tr("&Offline mode"))->setEnabled(false);
        m->addAction(tr("Change my &Password"),this,SLOT(setMyPassword())) ->setEnabled(req->hasRole("setmypasswd"));
        m->addSeparator();
-       m->addAction(tr("&Upload Template..."),this,SLOT(uploadTemplate()));
+       m->addAction(tr("&Edit Templates..."),req,SLOT(editTemplates()));
+       m->addAction(tr("&Update Templates Now"),req,SLOT(updateTemplates()));
        m->addSeparator();
        m->addAction(tr("&Close Session"),this,SLOT(close()));
        
@@ -1237,28 +1238,6 @@ void MOverview::orderByCustomer()
        ordermode->setCurrentIndex(ordermode->count()-1);
 }
 
-void MOverview::uploadTemplate()
-{
-       //get file
-       QString fn=QFileDialog::getOpenFileName(this,tr("Please select a template file."));
-       if(fn=="")return;
-       //get template name
-       QString tn=QFileInfo(fn).fileName();
-       QRegExp fr("[a-z0-9_\\.]+");
-       do{
-               bool ok;
-               tn=QInputDialog::getText(this,tr("Enter Template Name"),tr("Please enter a name for the template file, it should contain only letters, digits, underscores and dots:"),QLineEdit::Normal,tn,&ok).toLower();
-               if(!ok)return;
-               if(fr.exactMatch(tn))break;
-               QMessageBox::warning(this,tr("Warning"),tr("The template name must only contain letters, digits, underscores and dots."));
-       }while(true);
-       //send it
-       if(req->setTemplate(tn,fn))
-               QMessageBox::information(this,tr("Success"),tr("Successfully uploaded the template."));
-       else
-               QMessageBox::warning(this,tr("Warning"),tr("Unable to upload the template."));
-}
-
 void MOverview::ticketReturn()
 {
        //get ticket
index 97aa944..1475caa 100644 (file)
@@ -125,9 +125,6 @@ class MOverview:public QMainWindow
                /**react on entry in Entrance tab*/
                void entranceValidate();
                
-               /**upload Templates*/
-               void uploadTemplate();
-               
                /**return a ticket*/
                void ticketReturn();
                /**return a voucher*/
index 35e7e21..4786b53 100644 (file)
@@ -45,7 +45,8 @@ SOURCES = \
        orderwin.cpp \
        labeldlg.cpp \
        version.cpp \
-       templates.cpp
+       templates.cpp \
+       templatedlg.cpp
 
 HEADERS = \
        keygen.h \
@@ -69,7 +70,8 @@ HEADERS = \
        orderwin.h \
        labeldlg.h \
        misc.h \
-       templates.h
+       templates.h \
+       templatedlg.h
        
 #some PHP files are listed in this file to scan them for translatable items
 #use genphpscan.sh to regenerate it.
diff --git a/src/templatedlg.cpp b/src/templatedlg.cpp
new file mode 100644 (file)
index 0000000..a384e36
--- /dev/null
@@ -0,0 +1,228 @@
+//
+// C++ Implementation: templatedlg
+//
+// Description: 
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2008
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#include "templatedlg.h"
+
+#include <QComboBox>
+#include <QBoxLayout>
+#include <QFileDialog>
+#include <QFileInfo>
+#include <QMessageBox>
+#include <QPushButton>
+#include <QSettings>
+#include <QLabel>
+#include <QStandardItemModel>
+#include <QTreeView>
+
+MTemplateChoice::MTemplateChoice(const QString&cd,const QString&tname,const QStringList&choices,const QString&sg)
+       :sgroup(sg),cachedir(cd)
+{
+       setWindowTitle(tr("Chose Template"));
+       QVBoxLayout *vl;
+       setLayout(vl=new QVBoxLayout);
+       vl->addWidget(new QLabel(tr("Please chose a variant of template %s:").arg(tname)));
+       vl->addWidget(box=new QComboBox);
+       box->setEditable(false);
+       QSettings set;
+       set.beginGroup(sg);
+       for(int i=0;i<choices.size();i++){
+               QStringList vs=choices[i].split(",");
+               QString v,d;
+               if(vs.size()>1)v=vs[1];
+               else v=tr("(default)","default template pseudo-variant");
+               d=set.value(choices[i]+"/description").toString();
+               box->addItem(v+": "+d,choices[i]);
+       }
+       vl->addStretch(1);
+       QHBoxLayout *hl;
+       vl->addLayout(hl=new QHBoxLayout);
+       hl->addStretch(1);
+       QPushButton*p;
+       hl->addWidget(p=new QPushButton(tr("Ok")));
+       p->setDefault(true);
+       connect(p,SIGNAL(clicked()),this,SLOT(accept()));
+}
+
+MTemplate MTemplateChoice::choice()const
+{
+       QString fn=box->itemData(box->currentIndex()).toString();
+       QSettings set;
+       set.beginGroup(sgroup+"/"+fn);
+       return MTemplate(cachedir+"/"+fn, set.value("checksum").toString(), set.value("description").toString());
+}
+
+
+
+/**************************************************************/
+
+MTemplateEditor::MTemplateEditor(MTemplateStore*s)
+{
+       store=s;
+       nochange=false;
+       
+       setWindowTitle(tr("Edit Template Directory"));
+       
+       QHBoxLayout*hl;
+       QVBoxLayout*vl,*vl2;
+       
+       setLayout(vl=new QVBoxLayout);
+       vl->addLayout(hl=new QHBoxLayout,1);
+       hl->addWidget(tree=new QTreeView,1);
+       tree->setModel(model=new QStandardItemModel(this));
+       connect(model,SIGNAL(itemChanged(QStandardItem*)),this,SLOT(changeDescr(QStandardItem*)));
+       QPushButton*p;
+       hl->addLayout(vl2=new QVBoxLayout);
+       vl2->addWidget(p=new QPushButton(tr("Update Now")));
+       connect(p,SIGNAL(clicked()),this,SLOT(forceUpdate()));
+       vl2->addWidget(p=new QPushButton(tr("Add Variant")));
+       connect(p,SIGNAL(clicked()),this,SLOT(addItem()));
+       vl2->addWidget(p=new QPushButton(tr("Delete Variant")));
+       connect(p,SIGNAL(clicked()),this,SLOT(deleteItem()));
+       vl2->addStretch(1);
+       
+       vl->addSpacing(15);
+       vl->addLayout(hl=new QHBoxLayout);
+       hl->addStretch(1);
+       hl->addWidget(p=new QPushButton(tr("Close")));
+       connect(p,SIGNAL(clicked()),this,SLOT(accept()));
+       
+       updateView();
+}
+
+static const int BASEROLE=Qt::UserRole;
+static const int NAMEROLE=Qt::UserRole+1;
+
+void MTemplateEditor::updateView()
+{
+       //basic cleanup
+       nochange=true;
+       model->clear();
+       model->insertColumns(0,3);
+       model->setHorizontalHeaderLabels(QStringList()<<tr("Template/Variant")<<tr("Description")<<tr("Checksum"));
+       //get base names
+       QStringList base=MTemplate::legalBaseNames();
+       //get all templates, sort them into buckets
+       QList<MTemplate>all=store->allTemplates();
+       QMap<QString,QList<MTemplate> >hier;
+       for(int i=0;i<all.size();i++){
+               QString b=all[i].baseName();
+               if(!base.contains(b))base.append(b);
+               if(!hier.contains(b))hier.insert(b,QList<MTemplate>());
+               hier[b].append(all[i]);
+       }
+       //create hierarchy
+       qSort(base);
+       model->insertRows(0,base.size());
+       for(int i=0;i<base.size();i++){
+               QModelIndex idx=model->index(i,0);
+               model->setData(idx,base[i]);
+               model->setData(idx,base[i],BASEROLE);
+               model->setData(idx,"",NAMEROLE);
+               model->itemFromIndex(idx)->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
+               model->setData(model->index(i,1),"");
+               model->itemFromIndex(model->index(i,1))->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
+               model->setData(model->index(i,2),"");
+               model->itemFromIndex(model->index(i,1))->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
+               if(!hier.contains(base[i]))continue;
+               if(hier[base[i]].size()<1)continue;
+               QList<MTemplate>sub=hier[base[i]];
+               model->insertRows(0,sub.size(),idx);
+               model->insertColumns(0,3,idx);
+               for(int j=0;j<sub.size();j++){
+                       QModelIndex idx2=model->index(j,0,idx);
+                       model->setData(idx2,sub[j].fileName()+" ("+sub[j].variantID()+")");
+                       model->setData(idx2,base[i],BASEROLE);
+                       model->setData(idx2,sub[j].completeFileName(),NAMEROLE);
+                       model->itemFromIndex(idx2)->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
+                       model->setData(model->index(j,1,idx),sub[j].description());
+                       model->setData(model->index(j,2,idx),sub[j].checksum());
+                       model->itemFromIndex(model->index(j,2,idx))->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled);
+               }
+       }
+       //expand all
+       tree->expandAll();
+       nochange=false;
+}
+void MTemplateEditor::deleteItem()
+{
+       //get selection
+       QModelIndex idx=tree->currentIndex();
+       if(!idx.isValid())return;
+       QModelIndex bidx=model->index(idx.row(),0,idx.parent());
+       QString fn=model->data(bidx,NAMEROLE).toString();
+       if(fn=="")return;
+       //delete
+       if(store->deleteTemplate(fn))
+               model->removeRow(idx.row(),idx.parent());
+       else
+               QMessageBox::warning(this,tr("Warning"),tr("Unable to delete this template."));
+}
+
+void MTemplateEditor::addItem()
+{
+       //get selection
+       QModelIndex idx=tree->currentIndex();
+       if(!idx.isValid())return;
+       QModelIndex pidx=idx.parent();
+       QModelIndex bidx=model->index(idx.row(),0,pidx);
+       QString base=model->data(bidx,BASEROLE).toString();
+       if(base=="")return;
+       //query file name
+       QString fn=QFileDialog::getOpenFileName(this,tr("Select Template File"));
+       if(fn=="")return;
+       //check extension
+       QString ext=QFileInfo(fn).completeSuffix();
+       if(!MTemplate::legalSuffixes(base).contains(ext)){
+               QMessageBox::warning(this,tr("Warning"),tr("Files with this extension (%1) are not legal for this template.").arg(ext));
+               return;
+       }
+       //get new variant name
+       QStringList lst;
+       for(int i=0;i<model->rowCount(pidx);i++){
+               QStringList f=model->data(model->index(i,0,pidx),NAMEROLE).toString().split(",");
+               if(f.size()>1)
+                       lst<<f[1];
+       }
+       QString nvar;
+       for(int i=0;i<1000000000;i++){
+               nvar=QString::number(i,16).toLower();
+               if(!lst.contains(nvar))break;
+       }
+       //send up
+       if(store->setTemplate(base+"."+ext+","+nvar,fn))
+               forceUpdate();
+       else
+               QMessageBox::warning(this,tr("Warning"),tr("Unable to upload file."));
+}
+
+void MTemplateEditor::changeDescr(QStandardItem*item)
+{
+       if(nochange)return;
+       if(!item)return;
+       //sanity check
+       if(item->column()!=1)return;
+       //get full name & data
+       QModelIndex idx=item->index();
+       QString dsc=model->data(idx).toString();
+       QModelIndex bidx=model->index(item->row(),0,idx.parent());
+       QString fn=model->data(bidx,NAMEROLE).toString();
+       if(fn=="")return;
+       //send to server
+       if(!store->setTemplateDescription(fn,dsc))
+               QMessageBox::warning(this,tr("Warning"),tr("Unable to send new description to server."));
+}
+
+void MTemplateEditor::forceUpdate()
+{
+       store->updateTemplates(true);
+       updateView();
+}
diff --git a/src/templatedlg.h b/src/templatedlg.h
new file mode 100644 (file)
index 0000000..b4e7fcb
--- /dev/null
@@ -0,0 +1,64 @@
+//
+// C++ Interface: templatedlg
+//
+// Description: 
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2008
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+#ifndef MAGICSMOKE_TEMPLATEDLG_H
+#define MAGICSMOKE_TEMPLATEDLG_H
+
+#include <QDialog>
+#include <QString>
+
+#include "templates.h"
+
+class QComboBox;
+class QStandardItem;
+class QStandardItemModel;
+class QStringList;
+class QTreeView;
+
+/**gives the user a choice of template variants; used by MTemplateStore only!*/
+class MTemplateChoice:public QDialog
+{
+       Q_OBJECT
+       public:
+               MTemplateChoice(const QString&,const QString&,const QStringList&,const QString&);
+               
+               MTemplate choice()const;
+       private:
+               //selection box
+               QComboBox*box;
+               //settings group where to find data
+               QString sgroup,cachedir;
+};
+
+/**lets the user add and remove templates and variants to/from the database; used by MWebRequest!*/
+class MTemplateEditor:public QDialog
+{
+       Q_OBJECT
+       public:
+               MTemplateEditor(MTemplateStore*);
+               
+       private slots:
+               void updateView();
+               void deleteItem();
+               void addItem();
+               void changeDescr(QStandardItem*);
+               void forceUpdate();
+       private:
+               MTemplateStore*store;
+               QTreeView*tree;
+               QStandardItemModel*model;
+               bool nochange;
+};
+
+
+
+#endif
index c53ba42..6da43bd 100644 (file)
 //
 //
 
+/*****************************
+ * Settings hierarchy for templates:
+ *
+ * /templates/$PROFILEID -> template settings for this profile
+ *  .../$TEMPLATENAME -> the settings for a template, uses the complete name (eg. bill.odtt,2)
+ *  ....../checksum -> key that stores the checksum (calculated by server!!)
+ *  ....../description -> key that stores the description (as received from server)
+ *
+ *
+ * Template buffer on disk:
+ *
+ * req->dataDir()/templates -> directory for template files;
+ *   each file is stored with complete name, no meta-info
+ ***************************/
+
+#include "main.h"
+#include "templatedlg.h"
 #include "templates.h"
 #include "webrequest.h"
-#include "main.h"
 
-#include <QStringList>
-#include <QSettings>
-#include <QRegExp>
+#include <QCoreApplication>
 #include <QDateTime>
-#include <QFile>
 #include <QDir>
 #include <QDomDocument>
 #include <QDomElement>
+#include <QFile>
+#include <QProgressDialog>
+#include <QRegExp>
+#include <QSettings>
+#include <QStringList>
 
 
-MTemplates::MTemplates(MWebRequest*r,QString p)
+MTemplateStore::MTemplateStore(MWebRequest*r,QString p)
 {
        req=r;
        profileid=p;
 }
 
-QString MTemplates::getTemplate(QString f)
+MTemplate MTemplateStore::getTemplate(QString f)
 {
        //syntax check
        f=f.toLower();
-       QRegExp fregexp("[a-z0-9_\\.]+");
-       if(!fregexp.exactMatch(f))return "";
+       QRegExp fregexp("[a-z0-9_]+");
+       if(!fregexp.exactMatch(f))return MTemplate();
+       //update directory (no force)
+       updateTemplates(false);
+       //find files matching the pattern
+       //basics
+       QString dname=req->dataDir()+"/templates/";
+       QSettings set;
+       set.beginGroup("templates/"+profileid);
+       //get directory
+       QStringList dir=set.childGroups();
+       QStringList tdir;
+       for(int i=0;i<dir.size();i++){
+               if(dir[i].split(".")[0].startsWith(f,Qt::CaseInsensitive))
+                       tdir<<dir[i];
+       }
+       //check dir size
+       if(tdir.size()==0)return MTemplate();
+       if(tdir.size()==1)return MTemplate(dname+"/"+tdir[0], set.value(tdir[0]+"/checksum").toString(), set.value(tdir[0]+"/description").toString());
+       //hmm, more than one choice
+       MTemplateChoice c(dname,f,tdir,"templates/"+profileid);
+       if(c.exec()==QDialog::Accepted)return c.choice();
+       else return MTemplate();
+}
+
+struct STemp{
+       STemp(QString f,QString c,QString d){fname=f;checksum=c;descr=d;}
+       STemp(){}
+       QString fname,checksum,descr;
+};
+
+void MTemplateStore::updateTemplates(bool force)
+{
        //basics
        QString dname=req->dataDir()+"/templates/";
        QSettings set;
        set.beginGroup("templates/"+profileid);
-       //do we need an update?
+       //do we need an update yet?
        QDateTime last=QDateTime::fromTime_t(set.value("lastupdate",0).toInt()+300);
-       if(last<QDateTime::currentDateTime()){do{//pseudo-loop, so we can use break instead of goto
-               //get local info
-               set.beginGroup("checksum");
-               QStringList files=set.childKeys();
-               QMap<QString,QString> fmap;
-               for(int i=0;i<files.size();i++)
-                       fmap.insert(files[i],set.value(files[i]).toString());
-               set.endGroup();
-               //get remote info, assume it is still valid if unable to retrieve it
-               if(!req->request("gettemplatelist",""))break;
-               if(req->responseStatus()!=MWebRequest::Ok)break;
-               //remember update time
-               set.setValue("lastupdate",QDateTime::currentDateTime().toTime_t());
-               //parse info
-               QDomDocument doc;
-               if(!doc.setContent(req->responseBody()))break;
-               //prune old stuff
-               set.remove("checksum");
-               //scan and create new list
-               QDomNodeList nl=doc.elementsByTagName("Template");
-               QMap<QString,QString>nfmap;
-               for(int i=0;i<nl.size();i++){
-                       QDomElement el=nl.at(i).toElement();
-                       if(el.isNull())continue;
-                       QString f=el.attribute("name","");
-                       QString h=el.attribute("hash","");
-                       if(f=="" || !fregexp.exactMatch(f))continue;
-                       nfmap.insert(f,h);
-                       set.setValue("checksum/"+f,h);
-               }
-               //compare old with new list, delete changed files
-               for(int i=0;i<files.size();i++){
-                       if(!nfmap.contains(files[i]))
-                               QFile(dname+"/"+f).remove();
-                       else
-                       if(nfmap[files[i]]!=fmap[files[i]])
-                               QFile(dname+"/"+f).remove();
+       if(last>=QDateTime::currentDateTime() && !force)return;
+       
+       //get local info
+       QStringList files=set.childGroups();
+       QMap<QString,STemp> fmap;
+       for(int i=0;i<files.size();i++){
+               STemp t(files[i],set.value(files[i]+"/checksum").toString(), set.value(files[i]+"/description").toString());
+               fmap.insert(files[i],t);
+       }
+       
+       //display progress dialog
+       QProgressDialog progress(QCoreApplication::translate("MTemplateStore","Retrieving templates from server."),"",0,1);
+       progress.setCancelButton(0);
+       progress.setMinimumDuration(0);
+       progress.setValue(0);
+       
+       //get remote info, assume it is still valid if unable to retrieve it
+       if(!req->request("gettemplatelist",""))return;
+       if(req->responseStatus()!=MWebRequest::Ok)return;
+       //remember update time
+       set.setValue("lastupdate",QDateTime::currentDateTime().toTime_t());
+       //parse info
+       QDomDocument doc;
+       if(!doc.setContent(req->responseBody()))return;
+       //scan and create new list
+       QDomNodeList nl=doc.elementsByTagName("Template");
+       QMap<QString,STemp>nfmap;
+       for(int i=0;i<nl.size();i++){
+               QDomElement el=nl.at(i).toElement();
+               if(el.isNull())continue;
+               QString f=el.attribute("name","");
+               QString h=el.attribute("hash","");
+               QString d=el.text();
+               if(f=="")continue;
+               nfmap.insert(f,STemp(f,h,d));
+       }
+       
+       //check old list for removed or changed entries; remove them
+       for(int i=0;i<files.size();i++){
+               if(!nfmap.contains(files[i]))
+                       fmap.remove(files[i]);
+               else
+               if(nfmap[files[i]].checksum != fmap[files[i]].checksum)
+                       fmap.remove(files[i]);
+       }
+       files=fmap.keys();
+       
+       //retrieve new files from server
+       QStringList nfiles=nfmap.keys();
+       progress.setRange(0,nfiles.size());
+       for(int i=0;i<nfiles.size();i++){
+               progress.setValue(i);
+               if(!files.contains(nfiles[i])){
+                       //file is not in current cache (or was outdated)
+                       if(retrieveFile(dname,nfiles[i]))
+                               fmap.insert(nfiles[i],nfmap[nfiles[i]]);
+               }else{
+                       //file is already up to date, still copy the current description
+                       fmap[nfiles[i]].descr=nfmap[nfiles[i]].descr;
                }
-       }while(false);}
-       //check that it is a valid template file
-       if(!set.contains("checksum/"+f))return "";
-       //get the file if it does not exist
-       if(!QFile(dname+"/"+f).exists()){
-               //make sure directory exists
-               QDir(req->dataDir()).mkpath("templates");
-               //retrieve template file
-               if(!req->request("gettemplate",f.toAscii()))
-                       return "";
-               if(req->responseStatus()!=MWebRequest::Ok)
-                       return "";
-               QFile fl(dname+"/"+f);
-               if(!fl.open(QIODevice::WriteOnly))
-                       return "";
-               fl.write(req->responseBody());
-               fl.close();
        }
-       //return file name
-       return dname+"/"+f;
+       files=fmap.keys();
+       
+       //clean up directory
+       QDir dir(dname);
+       QStringList dfiles=dir.entryList(QDir::Files);
+       for(int i=0;i<dfiles.size();i++)
+               if(!files.contains(dfiles[i]))
+                       dir.remove(dfiles[i]);
+       
+       //settings: prune old stuff
+       set.remove("");
+       //settings: create new entries
+       for(int i=0;i<files.size();i++){
+               STemp s=fmap[files[i]];
+               set.setValue(s.fname+"/checksum",s.checksum);
+               set.setValue(s.fname+"/description",s.descr);
+       }
+}
+
+bool MTemplateStore::retrieveFile(QString dname,QString fn)
+{
+       //request
+       if(!req->request("gettemplate",fn.toUtf8()))return false;
+       if(req->responseStatus()!=MWebRequest::Ok)return false;
+       //store
+       QFile f(dname+"/"+fn);
+       if(!f.open(QIODevice::WriteOnly|QIODevice::Truncate))return false;
+       f.write(req->responseBody());
+       return true;
 }
 
-bool MTemplates::setTemplate(QString n,QString f)
+bool MTemplateStore::setTemplate(QString n,QString f)
 {
-       //sanity check
-       QRegExp fregexp("[a-z0-9_\\.]+");
+       //very rough sanity check
+       QRegExp fregexp("[a-z0-9_\\.,]+");
        if(!fregexp.exactMatch(n))return false;
        //get content
        QFile fl(f);
@@ -114,13 +195,165 @@ bool MTemplates::setTemplate(QString n,QString f)
        QByteArray ba=fl.readAll();
        fl.close();
        //send to server
-       if(!req->request("settemplate",n.toAscii()+"\n"+ba))
+       if(!req->request("settemplate",n.toUtf8()+"\n"+ba))
+               return false;
+       if(req->responseStatus()!=MWebRequest::Ok)
+               return false;
+       //delete it from cache, so it is retrieved again; force retrieval
+       //TODO: the server returns the hash (since dec08), use it and update the cache without retrieval
+       QSettings set;
+       set.remove("templates/"+profileid+"/"+n);
+       set.setValue("templates/"+profileid+"/lastupdate",0);
+       QFile(req->dataDir()+"/templates/"+n).remove();
+       //return success
+       return true;
+}
+
+bool MTemplateStore::deleteTemplate(QString n)
+{
+       //very rough sanity check
+       QRegExp fregexp("[a-z0-9_\\.,]+");
+       if(!fregexp.exactMatch(n))return false;
+       //send to server
+       if(!req->request("deletetemplate",n.toUtf8()))
                return false;
        if(req->responseStatus()!=MWebRequest::Ok)
                return false;
-       //delete it from cache, so it is retrieved again
-       QSettings().remove("templates/"+profileid+"/checksum/"+n);
+       //delete it from cache
+       QSettings set;
+       set.remove("templates/"+profileid+"/"+n);
        QFile(req->dataDir()+"/templates/"+n).remove();
+       return true;
+}
+
+bool MTemplateStore::setTemplateDescription(QString n,QString d)
+{
+       //very rough sanity check
+       QRegExp fregexp("[a-z0-9_\\.,]+");
+       if(!fregexp.exactMatch(n))return false;
+       //check that we have a real change
+       QSettings set;
+       set.beginGroup("templates/"+profileid+"/"+n);
+       QString o=set.value("description").toString();
+       qDebug("setting %s '%s' -> '%s'",n.toAscii().data(),o.toAscii().data(),d.toAscii().data());
+       if(o==d)return true;
+       //send to server
+       if(!req->request("settemplatedescription",n.toUtf8()+"\n"+d.toUtf8()))
+               return false;
+       if(req->responseStatus()!=MWebRequest::Ok)
+               return false;
+       //update internal description
+       set.setValue("description",d);
        //return success
        return true;
 }
+
+QList<MTemplate> MTemplateStore::allTemplates()
+{
+       updateTemplates(false);
+       QString dname=req->dataDir()+"/templates/";
+       QSettings set;
+       set.beginGroup("templates/"+profileid);
+       QStringList names=set.childGroups();
+       QList<MTemplate> ret;
+       for(int i=0;i<names.size();i++)
+               ret.append(MTemplate(dname+"/"+names[i],set.value(names[i]+"/checksum").toString(),set.value(names[i]+"/description").toString()));
+       return ret;
+}
+
+/****************************************************************************/
+
+MTemplate::MTemplate(){}
+MTemplate::MTemplate(QString fn,QString chk,QString dsc){m_fname=fn;m_checksum=chk;m_descr=dsc;}
+QString MTemplate::cacheFileName()const{return m_fname;}
+
+QString MTemplate::fileName()const
+{
+       return QFileInfo(m_fname).fileName().split(",")[0];
+}
+
+QString MTemplate::completeFileName()const
+{
+       return QFileInfo(m_fname).fileName();
+}
+
+QString MTemplate::baseName()const
+{
+       return QFileInfo(m_fname).baseName();
+}
+
+QString MTemplate::extension()const
+{
+       return QFileInfo(m_fname).completeSuffix().split(",")[0];
+}
+
+QString MTemplate::variantID()const
+{
+       QStringList lst=QFileInfo(m_fname).fileName().split(",");
+       if(lst.size()>1)return lst[1];
+       return "";
+}
+
+QString MTemplate::checksum()const{return m_checksum;}
+
+bool MTemplate::isValid()const{return m_fname!="";}
+
+QString MTemplate::targetExtension()const
+{
+       QString x=extension();
+       //ODF file?
+       if(QRegExp("od.t").exactMatch(x))return x.left(3);
+       //all else: not storable
+       return "";
+}
+
+bool MTemplate::isOdf()const{return (type()&OdfTemplate)!=0;}
+
+bool MTemplate::isLabel()const{return type()==LabelTemplate;}
+MTemplate::Type MTemplate::type()const
+{
+       QString x=extension();
+       //ODF file?
+       if(x=="odtt")return OdtTemplate;
+       if(x=="odst")return OdsTemplate;
+       if(x=="odpt")return OdpTemplate;
+       if(x=="odgt")return OdgTemplate;
+       if(x=="odbt")return OdbTemplate;
+       //label?
+       if(x=="xtt")return LabelTemplate;
+       //hmm, unknown one
+       return UnknownTemplate;
+}
+
+QString MTemplate::description()const{return m_descr;}
+
+
+static QStringList tempBaseNames;
+//static 
+QStringList MTemplate::legalBaseNames()
+{
+       if(tempBaseNames.size()==0){
+               tempBaseNames<<"ticket"<<"voucher"<<"bill"<<"eventsummary";
+       }
+       return tempBaseNames;
+}
+
+//static 
+MTemplate::Types MTemplate::legalTypes(QString bn)
+{
+       if(bn=="ticket" || bn=="voucher")
+               return LabelTemplate;
+       if(bn=="bill" || bn=="eventsummary")
+               return OdfTemplate;
+       return UnknownTemplate;
+}
+
+//static
+QStringList MTemplate::legalSuffixes(QString bn)
+{
+       if(bn=="ticket" || bn=="voucher")
+               return QStringList()<<"xtt";
+       if(bn=="bill" || bn=="eventsummary")
+               return QStringList()<<"odtt"<<"odst"<<"odpt"<<"odgt"<<"odbt";
+       return QStringList();
+}
index 3ef3c1a..b4a2d29 100644 (file)
 
 class MWebRequest;
 
-class MTemplates
+/**this class wraps a single template*/
+class MTemplate
 {
        public:
-               MTemplates(MWebRequest*,QString);
+               /**creates an invalid template*/
+               MTemplate();
                
-               QString getTemplate(QString);
+               /**returns the name/path of the cache file, if it exists*/
+               QString cacheFileName()const;
                
-               bool setTemplate(QString,QString);
+               /**returns the file name of the template (eg. mytemplate.odtt)*/
+               QString fileName()const;
+               
+               /**returns the complete encoded name of the template (eg. mytemplate.odtt,v1)*/
+               QString completeFileName()const;
+               
+               /**returns the base name of the template (eg. mytemplate for mytemplate.odtt)*/
+               QString baseName()const;
+               
+               /**returns the extension of the template (eg. odtt for mytemplate.odtt)*/
+               QString extension()const;
+               
+               /**returns the variant ID of the template (warning: it has no meaning outside the template storage system*/
+               QString variantID()const;
+               
+               /**returns the checksum (calculated by the server)*/
+               QString checksum()const;
+               
+               /**returns the description*/
+               QString description()const;
+               
+               /**returns whether this is a valid template*/
+               bool isValid()const;
+               
+               /**returns the extension of the target document if it is saved (empty if the template cannot be saved)*/
+               QString targetExtension()const;
+               
+               /**returns whether this is an ODF template*/
+               bool isOdf()const;
+               
+               /**returns whether this is a label template*/
+               bool isLabel()const;
+               
+               /**template type; currently only ODF and Labels are known*/
+               enum Type{
+                       /**uninitialized or unknown label type*/
+                       UnknownTemplate=0,
+                       /**ODF Text template*/
+                       OdtTemplate=1,
+                       /**ODF SpreadSheet template*/
+                       OdsTemplate=2,
+                       /**ODF Presentation*/
+                       OdpTemplate=4,
+                       /**ODF Drawing*/
+                       OdgTemplate=8,
+                       /**ODF DataBase*/
+                       OdbTemplate=0x10,
+                       /**ODF template*/
+                       OdfTemplate=0xff,
+                       /**Label template*/
+                       LabelTemplate=0x100
+               };
+               Q_DECLARE_FLAGS(Types,Type)
+               
+               /**returns the template type*/
+               Type type()const;
+               
+               /**returns the currently known (by the client) template base names*/
+               static QStringList legalBaseNames();
+               
+               /**returns the legal file types (as understood by the client) for a template base name; returns UnknownTemplate if none is legal*/
+               static Types legalTypes(QString);
+               
+               /**returns the legal template file suffixes (as understood by the client) for a template base name; returns empty if none is legal*/
+               static QStringList legalSuffixes(QString);
+
+       protected:
+               friend class MTemplateStore;
+               friend class MTemplateChoice;
+               /**creates a template wrapper from a cache file name; this constructor is used internally in the storage system*/
+               MTemplate(QString fn,QString chk,QString dsc);
+       private:
+               QString m_fname,m_checksum,m_descr;
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(MTemplate::Types)
+
+/**this class implements the storage end of the template subsystem, its only instance exists in the webrequest*/
+class MTemplateStore
+{
+       protected:
+               friend class MWebRequest;
+               friend class MTemplateEditor;
+               /**instantiates the template subsystem*/
+               MTemplateStore(MWebRequest*,QString);
+               
+               /**stores a specific template*/
+               bool setTemplate(QString templatename,QString localfile);
+               
+               /**stores a new description for a template*/
+               bool setTemplateDescription(QString templatename,QString description);
+               
+               /**deletes a template (requires full name), used by MTemplateEditor*/
+               bool deleteTemplate(QString);
+               
+               /**updates the template directory, does not do anything if force==false and the last update was less than 5min ago*/
+               void updateTemplates(bool force);
+               
+               /**returns all templates (for MTemplateEditor)*/
+               QList<MTemplate> allTemplates();
+               
+       private:
+               /**unused, just here to remove it from accessability*/
+               MTemplateStore(){}
+               
+               /**helper for updateTemplates: retrieves a single file from the server*/
+               bool retrieveFile(QString,QString);
+               
+       public:
+               /**returns a specific template, opens a template choice dialog if necessary*/
+               MTemplate getTemplate(QString);
                
        private:
                MWebRequest*req;
                QString profileid;
-
 };
 
 #endif
index 9ed75de..aef8094 100644 (file)
@@ -81,9 +81,9 @@ class MLabelRendererPrivate
                QSizeF tonatural(const QPaintDevice&,QSizeF);
 };
 
-MLabelRenderer::MLabelRenderer(QString file)
+MLabelRenderer::MLabelRenderer(MTemplate file)
 {
-       d=new MLabelRendererPrivate(file,this);
+       d=new MLabelRendererPrivate(file.cacheFileName(),this);
 }
 
 MLabelRendererPrivate::MLabelRendererPrivate(QString file,MLabelRenderer*p)
@@ -477,7 +477,7 @@ QString MTicketLabel::getVariable(QString var)const
        return "";
 }
 
-MTicketRenderer::MTicketRenderer(QString f):MLabelRenderer(f){}
+MTicketRenderer::MTicketRenderer(MTemplate f):MLabelRenderer(f){}
 bool MTicketRenderer::render(const MTicket&label,QPaintDevice&pdev,QPainter*painter,QPointF offset)
 {
        return MLabelRenderer::render(MTicketLabel(label),pdev,painter,offset);
@@ -500,7 +500,7 @@ QString MVoucherLabel::getVariable(QString var)const
        return "";
 }
 
-MVoucherRenderer::MVoucherRenderer(QString f):MLabelRenderer(f){}
+MVoucherRenderer::MVoucherRenderer(MTemplate f):MLabelRenderer(f){}
 bool MVoucherRenderer::render(const MVoucher&label,QPaintDevice&pdev,QPainter*painter,QPointF offset)
 {
        return MLabelRenderer::render(MVoucherLabel(label),pdev,painter,offset);
index ce424c4..46cb400 100644 (file)
@@ -17,6 +17,8 @@
 #include <QPointF>
 #include <QSizeF>
 
+#include "templates.h"
+
 class MLabelRendererPrivate;
 class MTicket;
 class MVoucher;
@@ -41,7 +43,7 @@ class MLabelRenderer
 {
        public:
                /**instantiates a renderer loaded from template file*/
-               MLabelRenderer(QString file);
+               MLabelRenderer(MTemplate file);
                /**deletes the renderer*/
                virtual ~MLabelRenderer();
                
@@ -62,7 +64,7 @@ class MLabelRenderer
 class MVoucherRenderer:public MLabelRenderer
 {
        public:
-               MVoucherRenderer(QString f);
+               MVoucherRenderer(MTemplate f);
                bool render(const MVoucher&label,QPaintDevice&pdev,QPainter*painter=0,QPointF offset=QPointF());
 };
 
@@ -70,7 +72,7 @@ class MVoucherRenderer:public MLabelRenderer
 class MTicketRenderer:public MLabelRenderer
 {
        public:
-               MTicketRenderer(QString f);
+               MTicketRenderer(MTemplate f);
                bool render(const MTicket&label,QPaintDevice&pdev,QPainter*painter=0,QPointF offset=QPointF());
 };
 
index 67342a1..5046f16 100644 (file)
@@ -13,6 +13,7 @@
 #include "hmac.h"
 #include "keygen.h"
 #include "main.h"
+#include "templatedlg.h"
 #include "version.h"
 #include "webrequest.h"
 
@@ -585,12 +586,18 @@ QString MWebRequest::hostName()
        return hostname;
 }
 
-QString MWebRequest::getTemplate(QString f)
+MTemplate MWebRequest::getTemplate(QString f)
 {
        return temp.getTemplate(f);
 }
 
-bool MWebRequest::setTemplate(QString n,QString f)
+void MWebRequest::editTemplates()
 {
-       return temp.setTemplate(n,f);
+       MTemplateEditor ed(&temp);
+       ed.exec();
+}
+
+void MWebRequest::updateTemplates()
+{
+       temp.updateTemplates(true);
 }
index d9dc944..df75eb3 100644 (file)
@@ -108,11 +108,8 @@ class MWebRequest:public QObject
                /**return current host name of this session*/
                QString hostName();
                
-               /**return the (local) file name of a template, queries the DB if necessary - cache timeout is 5 minutes; returns an empty string if the template does not exist*/
-               QString getTemplate(QString);
-               
-               /**sends the template file to the server, returns whether it was successful*/
-               bool setTemplate(QString templatename,QString localfilename);
+               /**returns the requested template as cached locally (see MTemplateStore for details)*/
+               MTemplate getTemplate(QString);
                
        public slots:
                /**set how long to wait for a web request*/
@@ -131,6 +128,12 @@ class MWebRequest:public QObject
                /**change password; returns error string if it fails, empty if it succeeds*/
                QString changeMyPassword(QString oldpwd,QString newpwd);
                
+               /**force an update of templates*/
+               void updateTemplates();
+               
+               /**opens the template editor*/
+               void editTemplates();
+               
        private slots:
                /**internal: used by wait loop for web requests*/
                void httpFin(int,bool);
@@ -163,7 +166,7 @@ class MWebRequest:public QObject
                //profile name for lookups
                QString profileid;
                //template subsystem
-               MTemplates temp;
+               MTemplateStore temp;
                
                /**used by login and relogin to do the actual work*/
                bool doLogin();
index c870588..fed15ec 100644 (file)
@@ -18,13 +18,19 @@ function getTemplateList()
 {
        global $db;
        header("X-MagicSmoke-Status: Ok");
-       print("<TList>\n");
-       $res=$db->select("template","filename,hash","");
+       $xml=new DomDocument;
+       $root=$xml->createElement("TList");
+       $res=$db->select("template","filename,hash,description","");
        for($i=0;$i<count($res);$i++){
-               //it is safe to do this since setTemplate checks syntax:
-               print("<Template name=\"".$res[$i]["filename"]."\" hash=\"".$res[$i]["hash"]."\"/>\n");
+               $el=$xml->createElement("Template");
+               $el->setAttribute("name",$res[$i]["filename"]);
+               $el->setAttribute("hash",$res[$i]["hash"]);
+               if(!$db->isNull($res[$i]["description"]))
+                       $el->appendChild($xml->createTextNode($res[$i]["description"]));
+               $root->appendChild($el);
        }
-       print("</TList>\n");
+       $xml->appendChild($root);
+       print($xml->saveXml());
 }
 
 function getTemplate($fname)
@@ -50,7 +56,7 @@ function setTemplate($data)
        $fname=strtolower(trim(substr($data,0,$pos)));
        $data=substr($data,$pos+1);
        //syntax check
-       if(ereg("^[a-z0-9_\\.]+$",$fname)===false){
+       if(ereg("^[a-z0-9_]+\\.[a-z0-9_]+(,[a-z0-9_]+)?$",$fname)===false){
                header("X-MagicSmoke-Status: Error");
                die(tr("Illegal File Name"));
        }
@@ -66,6 +72,40 @@ function setTemplate($data)
        }
        $db->commitTransaction();
        header("X-MagicSmoke-Status: Ok");
+       echo $hash;
+}
+
+function setTemplateDescription($data)
+{
+       $pos=strpos($data,"\n");
+       if($pos===false){
+               header("X-MagicSmoke-Status: Error");
+               die(tr("Unable to find file name"));
+       }
+       //split
+       $fname=strtolower(trim(substr($data,0,$pos)));
+       $data=substr($data,$pos+1);
+       //syntax check
+       if(ereg("^[a-z0-9_]+\\.[a-z0-9_]+(,[a-z0-9_]+)?$",$fname)===false){
+               header("X-MagicSmoke-Status: Error");
+               die(tr("Illegal File Name"));
+       }
+       //store
+       global $db;
+       $r=$db->update("template",array("description"=>$data),"filename=".$db->escapeString($fname));
+       if($r===false || $r<1){
+               header("X-MagicSmoke-Status: Error");
+               die(tr("Template file does not exist"));
+       }
+       header("X-MagicSmoke-Status: Ok");
+}
+
+function deleteTemplate($fname)
+{
+       global $db;
+       $db->deleteRows("template","filename=".$db->escapeString($fname));
+       header("X-MagicSmoke-Status: Ok");
+       echo $hash;
 }
 
 ?>
\ No newline at end of file
index b95ff13..25dd38f 100644 (file)
@@ -13,7 +13,7 @@
 //minimum version that the server understands (4 hex digits)
 defversion(MINSERVER,0000)
 //current version of the server
-defversion(CURSERVER,0002)
+defversion(CURSERVER,0003)
 
 //current human readable version of the server
 defversion(HRSERVER,0.2 beta)
@@ -21,7 +21,7 @@ defversion(HRSERVER,0.2 beta)
 //minimum version that the client requires
 defversion(MINCLIENT,0000)
 //current version of the client
-defversion(CURCLIENT,0002)
+defversion(CURCLIENT,0003)
 
 //current human readable version of the client
 defversion(HRCLIENT,0.2 beta)
index af4f794..3da9275 100644 (file)
@@ -29,7 +29,7 @@ $ALLOWEDREQUESTS=array(
        tr("getshipping"),tr("setshipping"),tr("deleteshipping"), //shipping info
        tr("getticket"),tr("useticket"),tr("changeticketprice"),tr("ticketreturn"),//ticket management
        tr("getvoucherprices"),tr("cancelvoucher"),tr("emptyvoucher"),tr("usevoucher"),tr("getvoucher"), //voucher management
-       tr("gettemplatelist"),tr("gettemplate"),tr("settemplate") //templates
+       tr("gettemplatelist"),tr("gettemplate"),tr("settemplate"),tr("settemplatedescription"),tr("deletetemplate") //templates
 );
 /**special roles begin with _ and are listed here (in lower case and wrapped in tr())*/
 $SPECIALROLES=array(
@@ -264,6 +264,16 @@ if($SMOKEREQUEST=="settemplate"){
        setTemplate($REQUESTDATA);
        exit();
 }
+//set a specific template description
+if($SMOKEREQUEST=="settemplatedescription"){
+       setTemplateDescription($REQUESTDATA);
+       exit();
+}
+//delete a template
+if($SMOKEREQUEST=="deletetemplate"){
+       deleteTemplate(trim($REQUESTDATA));
+       exit();
+}
 
 
 //get the list of customers