*auditing (used to log money transfers)
authorkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Tue, 18 Aug 2009 17:02:23 +0000 (17:02 +0000)
committerkonrad <konrad@6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33>
Tue, 18 Aug 2009 17:02:23 +0000 (17:02 +0000)
*brought woc table generation up to snuff
*allow calls in mappings

git-svn-id: https://silmor.de/svn/softmagic/smoke/trunk@335 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33

15 files changed:
wob/audit.wolf
wob/event.wolf
wob/magicsmoke.wolf
wob/order.wolf
woc/phpout.cpp
woc/phpout.h
woc/processor.cpp
woc/processor.h
www/inc/db/autoload.php
www/inc/db/barcodetable.php [new file with mode: 0644]
www/inc/db/db.php
www/inc/machine/session.php
www/inc/wbase/table.php
www/inc/wbase/transaction.php
www/index.php

index af255b3..1a8443e 100644 (file)
@@ -7,20 +7,6 @@
   - see COPYING.AGPL for details
   -->
 <Wolf>
-
-       <Table name="moneylog" backup="yes">
-               <Column name="logid" type="seq64" primarykey="yes"/>
-               <Column name="logtime" type="int64" notnull="yes"/>
-               <Column name="uname" type="string:64" foreignkey="user:uname" null="yes"/>
-               <Column name="orderid" type="int32" foreignkey="order:orderid" null="yes"/>
-               <Column name="voucherid" type="string:32" foreignkey="voucher:voucherid" null="yes"/>
-               <Column name="moved" type="int32" notnull='yes'/>
-               <Column name="orderpaid" type="int32" null="yes"/>
-               <Column name="orderdue" type="int32" null="yes"/>
-               <Column name="vouchervalue" type="int32" null="yes"/>
-               <Column name="log" type="string" notnull='yes'/>
-       </Table>
-       
        <Table name="documentlog" backup="yes">
                <Column name="docid" type="seq64" primarykey="yes"/>
                <Column name="logtime" type="int64" notnull="yes"/>
index dd11253..777b778 100644 (file)
                <Property name="name" type="string"/>
                <Property name="description" type="string"/>
                <Property name="comment" type="string"/>
+               
+               <Mapping table="artist">
+                       <Map column="artistid" property="id"/>
+                       <Map column="artistname" property="name"/>
+                       <Map column="description"/>
+                       <Map column="comment"/>
+               </Mapping>
        </Class>
        
        <Class name="Price">
                <Mapping table="event">
                        <Map column="eventid" property="id"/>
                        <Map column="title"/>
-                       <Map column="artist"/>
+                       <Map property="artist">
+                               <Call lang="php" method="WOArtist::fromTableartist($table->getObjectForartistid())"/>
+                       </Map>
                        <Map column="description"/>
                        <Map column="comment"/>
                        <!--timing and location-->
index f6ac072..e898b9b 100644 (file)
        <!-- generic settings -->
        <Project baseDir=".." wobDir="wob" name="MagicSmoke"/>
        <Version comm="0100" needcomm="0100" humanReadable="1.91 alpha" svnTarget="."/>
-       <DataBase instance="db" schema="dbScheme" version="01.04"/>
+       <DataBase instance="db" schema="dbScheme" version="01.04">
+               <AuditTables>
+                       <Column name="audittime" type="int64">
+                               <Call lang="php" method="time()"/>
+                       </Column>
+                       <Column name="audituname" type="string:64">
+                               <Call lang="php" method="Session::currentUserName()"/>
+                       </Column>
+                       <Column name="audittransaction" type="string:64">
+                               <Call lang="php" method="WobTransactionBase::getExecutingName()"/>
+                       </Column>
+               </AuditTables>
+       </DataBase>
        
        <!-- configure output -->
        <QtClientOutput sourceDir="src" subDir="wob" priInclude="wob.pri" classPrefix="M" clean="yes"/>
@@ -18,7 +30,7 @@
                <Authenticator 
                        isAuthenticated="Session::instance()->isAuthenticated()"
                        hasRole="Session::instance()->canExecute(%)"
-                       userName="Session::instance()->getUser()"
+                       userName="Session::currentUserName()"
                        init="new Session($this)"/>
        </PHPServerOutput>
        <!-- HtmlOutput sourceDir="doc" subDir="wob"/ -->
index 6921415..6507c4a 100644 (file)
               <Column name="flags" type="string"/>
               <Column name="description" type="string"/> <!--description for the shipping type-->
        </Table>
-       <Table name="order" backup="yes">
+       <Table name="paymenttype" backup="yes">
+               <Column name="paytype" type="string:64" primarykey="yes"/>
+               <Column name="description" type="string"/>
+               <Column name="dataname" type="string:64"/>
+       </Table>
+       <Table name="order" backup="yes" audit="yes">
                <Column name="orderid" type="seq32" primarykey="yes"/>
                <!--customer-->
                <Column name="customerid" type="int32" foreignkey="customer:customerid"/>
                <!--pointer to shipping type (none per default, programmatic default is in config)-->
                <Column name="shippingtype" type="int32" null="yes" foreignkey="shipping:shipid"/>
                
+               <!-- in audit: monitor the type of payment -->
+               <AuditColumn name="paytype" type="string:64" foreignkey="paymenttype:paytype"/>
+               <AuditColumn name="paydata" type="string"/>
+               
                <Foreign method="getTickets" via="ticket:orderid=orderid"/>
                <Foreign method="getVouchers" via="voucher:orderid=orderid"/>
+               <Foreign method="getItems" via="item:orderid=orderid"/>
        </Table>
-       <Table name="ticket" backup="yes" base="BarcodeTable">
+       <Table name="ticket" backup="yes" base="BarcodeTable" audit="yes">
                <!--a 8-32 char code (code39: case-insensitive letters+digits) for the ticket-->
-               <Column name="ticketid" type="string:32" primarykey="yes"/>
+               <Column name="ticketid" type="string:32" primarykey="yes">
+                       <Call lang="php" method="BarcodeTable::getNewTicketId()"/>
+               </Column>
                <Column name="eventid" type="int32" foreignkey="event:eventid"/>
                <!--initially a copy from event, can be adjusted by seller-->
                <Column name="price" type="int32" notnull="yes"/>
                
                <!-- TODO: add check constraint that eventid,pricecategoryid exist in eventprice-->
        </Table>
-       <Table name="voucher" backup="yes" base="BarcodeTable">
+       <Table name="voucher" backup="yes" base="BarcodeTable" audit="yes">
                <!--a 8-32 char code (code39: case-insensitive letters+digits) for the voucher-->
-               <Column name="voucherid" type="string:32" primarykey="yes"/>
+               <Column name="voucherid" type="string:32" primarykey="yes">
+                       <Call lang="php" method="BarcodeTable::getNewVoucherId()"/>
+               </Column>
                <!--price of the voucher (0 if cancelled)-->
                <Column name="price" type="int32" notnull="yes"/>
                <!--order this voucher belongs to-->
                <Column name="flags" type="string"/>
                <Column name="tax" type="int32"/>
        </Table>
-       <Table name="item" backup="yes">
+       <Table name="item" backup="yes" audit="yes">
                <Column name="itemid" type="seq64" primarykey="yes"/>
                <Column name="productid" type="int32" foreignkey="product:productid" notnull="yes"/>
                <Column name="orderid" type="int32" foreignkey="order:orderid" notnull="yes"/>
index 8f256fb..676bb26 100644 (file)
@@ -169,7 +169,7 @@ void WocPHPServerOut::newTable(const WocTable&tbl)
        for(int i=0;i<cols.size();i++){
                //automatic resolution of internal foreign keys
                if(tbl.columnIsForeign(cols[i])){
-                       code+="public function get"+cols[i]+"(){\n\tglobal "+dbi+";\n\treturn WT";
+                       code+="public function getObjectFor"+cols[i]+"(){\n\tglobal "+dbi+";\n\treturn WT";
                        QStringList foreign=tbl.columnForeign(cols[i]).split(":");
                        code+=foreign[0]+"::selectFromDB(\""+foreign[1]+"=\"."+dbi+"->escapeColumn(\""+foreign[0]+"\",\""+foreign[1]+"\",$this->"+cols[i]+"));\n}\n\n";
                }
@@ -214,6 +214,31 @@ void WocPHPServerOut::newTable(const WocTable&tbl)
                code+="const "+ens[i].first+"="+QString::number(ens[i].second)+";\n";
        }
        
+       //hasproperty function
+       code+="public function hasProperty($p){switch($p){\n";
+       for(int i=0;i<cols.size();i++)
+               code+="\tcase \""+cols[i]+"\":\n";
+       QStringList aps=tbl.auditColumns();
+       for(int i=0;i<aps.size();i++)
+               code+="\tcase \""+aps[i]+"\":\n";
+       code+="\t\treturn true;\n\tdefault:return false;}}\n";
+       
+       //create audit stuff
+       if(tbl.isAuditable()){
+               code+="public function isAuditable(){return true;}\n";
+               code+="protected function createAudit(){$ad=new WT"+tbl.name()+"_audit($this->data,false,\""+tbl.name()+"_audit\");\n";
+               code+="\treturn $ad->insert();\n}\n";
+       }
+       
+       //create newKey function
+       code+="public function newKey(){\n\tparent::newKey();\n";
+       for(int i=0;i<cols.size();i++){
+               QString c=tbl.columnCall(cols[i],"php");
+               if(c=="")continue;
+               code+="\t$this->cdata[\""+cols[i]+"\"]="+c+";\n";
+       }
+       code+="}\n";
+       
        //write table class
        code+="};\n";
        tf.write(code.toAscii());
@@ -677,9 +702,12 @@ QString WocPHPServerOut::classMappings(const WocClass&cls)
        for(int i=0;i<k.size();i++){
                code+="\nstatic public function fromTable"+k[i]+"($table){\n";
                code+="\t$data=new WO"+cls.name()+"();\n";
-               QList<QPair<QString,QString> >map=cls.mapping(k[i]);
-               for(int j=0;j<map.size();j++){
-                       code+="\t$data->prop_"+map[j].second+"=$table->"+map[j].first+";\n";
+               QMap<QString,QString>map=cls.mapping(k[i]);
+               QStringList mapk=map.keys();
+               for(int j=0;j<mapk.size();j++){
+                       QString meth=cls.mapMethod(k[i],mapk[j],"php");
+                       if(meth!="")code+="\t$data->prop_"+mapk[j]+"="+meth+";\n";
+                       else code+="\t$data->prop_"+mapk[j]+"=$table->"+map[mapk[j]]+";\n";
                }
                code+="\treturn $data;\n}\n";
                code+="static public function fromTableArray"+k[i]+"(array $table){\n\t$ret=array();\n";
@@ -792,6 +820,8 @@ void WocPHPServerOut::newTransaction(const WocTransaction&trn)
        //getters/setters
        tf.write(trnGetSet(trn).toAscii());
        
+       //direct execution
+       tf.write(trnExecute(trn).toAscii());
        
        //end
        code="\n//end of class\n}\n";
@@ -991,3 +1021,22 @@ QString WocPHPServerOut::trnGetSet(const WocTransaction&trn)
        
        return code;
 }
+
+QString WocPHPServerOut::trnExecute(const WocTransaction&trn)
+{
+       QStringList in=trn.inputNames();
+       QString code="static public function execute(";
+       for(int i=0;i<in.size();i++){
+               if(i)code+=",";
+               code+="$"+in[i];
+       }
+       code+=")\n{\n\t$inst=new "+trnClassName(trn)+";\n";
+       for(int i=0;i<in.size();i++)
+               code+="\t$this->ainput[\""+in[i]+"\"]=$"+in[i]+";\n";
+       code+="\tself::$running=\""+trn.name()+"\";\n";
+       code+="\t$inst->do_execute();\n";
+       code+="\tself::$running=\"\";\n";
+       code+="\treturn $inst;\n}\n";
+       code+="private function do_execute(){"+trn.callFunction("php")+"}\n";
+       return code;
+}
index d74c7ad..c5e986f 100644 (file)
 
 class QDomElement;
 
+/**generates output for a PHP server side*/
 class WocPHPServerOut:public WocOutput
 {
        public:
+               /**initializes the output object*/
                WocPHPServerOut(const QDomElement&);
        protected:
+               /**writes any last words after parsing finished*/
                virtual void finalize();
+               /**creates a class*/
                virtual void newClass(const WocClass&);
+               /**creates a table*/
                virtual void newTable(const WocTable&);
+               /**creates a transaction*/
                virtual void newTransaction(const WocTransaction&);
        private:
                QString m_basedir,m_subdir,m_fileext;
@@ -74,6 +80,8 @@ class WocPHPServerOut:public WocOutput
                QString trnOutput(const WocTransaction&);
                /**helper: create getters and setters*/
                QString trnGetSet(const WocTransaction&);
+               /**helper: create direct execution code for web interface*/
+               QString trnExecute(const WocTransaction&);
                
                /**helper: return the PHP-class-name of a WocClass*/
                QString className(const WocClass&c){return "WO"+c.name();}
index 877d8c5..0e3b88d 100644 (file)
@@ -89,6 +89,12 @@ bool WocProcessor::processFile(QString fn)
                                m_tables.append(tbl);
                                emit newTable(tbl);
                                if(m_error)return false;
+                               if(tbl.isAuditable()){
+                                       WocTable atbl=tbl.auditTable();
+                                       m_tables.append(atbl);
+                                       emit newTable(atbl);
+                                       if(m_error)return false;
+                               }
                        }else
                                return false;
                }else
@@ -120,6 +126,9 @@ bool WocProcessor::processFile(QString fn)
                                m_dbSchema=el.attribute("schema","dbSchema");
                        if(el.hasAttribute("version"))
                                m_dbVer=el.attribute("version");
+                       QDomNodeList nl=el.elementsByTagName("AuditTables");
+                       for(int i=0;i<nl.size();i++)
+                               WocTable::parseAuditStatic(nl.at(i).toElement());
                }else
                if(tn=="QtClientOutput"){
                        new WocQtClientOut(el);
@@ -407,20 +416,29 @@ WocClass::WocClass(const QDomElement&cls)
                        m_valid=false;
                        return;
                }
-               QList<QPair<QString,QString> >map;
+               QList<s_map>map;
                QDomNodeList nl2=el.elementsByTagName("Map");
                for(int j=0;j<nl2.size();j++){
                        QDomElement el2=nl2.at(j).toElement();
                        if(el2.isNull())continue;
-                       QString col=el2.attribute("column");
-                       QString prp=el2.attribute("property");
-                       if(prp=="")prp=col;
-                       if(col=="")col=prp;
-                       if(col==""){
+                       s_map sm;
+                       sm.column=el2.attribute("column");
+                       sm.property=el2.attribute("property");
+                       if(sm.property=="")sm.property=sm.column;
+                       if(sm.column=="")sm.column=sm.property;
+                       if(sm.column==""){
                                qDebug("Warning: empty mapping in class %s mapping %s. Ignoring it.",m_name.toAscii().data(),name.toAscii().data());
                                continue;
                        }
-                       map.append(QPair<QString,QString>(col,prp));
+                       QDomNodeList nl3=el2.elementsByTagName("Call");
+                       for(int k=0;k<nl3.size();k++){
+                               QDomElement el3=nl3.at(k).toElement();
+                               if(el3.isNull())continue;
+                               QString lang=el3.attribute("lang");
+                               QString meth=el3.attribute("method","false");
+                               sm.method.insert(lang,meth);
+                       }
+                       map.append(sm);
                }
                m_maps.insert(name,map);
        }
@@ -526,6 +544,28 @@ bool WocClass::propertyIsList(QString p)const
        else return false;
 }
 
+QMap<QString,QString> WocClass::mapping(QString m)const
+{
+       if(!m_maps.contains(m))return QMap<QString,QString>();
+       QList<s_map> sml=m_maps[m];
+       QMap<QString,QString>ret;
+       for(int i=0;i<sml.size();i++)
+               ret.insert(sml[i].property,sml[i].column);
+       return ret;
+}
+
+QString WocClass::mapMethod(QString table,QString property,QString lang)const
+{
+       if(!m_maps.contains(table))return "";
+       QList<s_map> sml=m_maps[table];
+       for(int i=0;i<sml.size();i++)
+               if(sml[i].property==property){
+                       if(sml[i].method.contains(lang))return sml[i].method[lang];
+                       else return "";
+               }
+       return "";
+}
+
 
 /******************************************************************************
  * WocTable
@@ -533,7 +573,7 @@ bool WocClass::propertyIsList(QString p)const
 
 WocTable::WocTable()
 {
-       m_backup=m_valid=false;
+       m_backup=m_valid=m_audit=false;
 }
 
 WocTable::WocTable(const QDomElement&tbl)
@@ -556,72 +596,30 @@ WocTable::WocTable(const QDomElement&tbl)
        }
        m_backup=str2bool(tbl.attribute("backup","0"));
        m_base=tbl.attribute("base","WobTable");
+       m_audit=str2bool(tbl.attribute("audit","0"));
        qDebug("Info: parsing table %s",m_name.toAscii().data());
-       QDomNodeList nl=tbl.elementsByTagName("Column");
        //Columns
+       QDomNodeList nl=tbl.elementsByTagName("Column");
        for(int i=0;i<nl.size();i++){
                QDomElement el=nl.at(i).toElement();
                if(el.isNull())continue;
-               s_col cl;
-               cl.name=el.attribute("name");
-               //check name syntax, check it is not doubled
-               if(!good.exactMatch(cl.name)){
-                       qDebug("Error: table %s column %s does not have a regular name.",m_name.toAscii().data(),cl.name.toAscii().data());
+               QPair<bool,s_col> cl=parseColumn(el,m_name);
+               if(!cl.first)return;
+               if(hasColumn(cl.second.name)){
+                       qDebug("Error: double definition of column %s in table %s.",cl.second.name.toAscii().data(),m_name.toAscii().data());
                        m_valid=false;
                        return;
                }
-               if(hasColumn(cl.name)){
-                       qDebug("Error: double definition of column %s in table %s.",cl.name.toAscii().data(),m_name.toAscii().data());
-                       m_valid=false;
-                       return;
-               }
-               cl.isprime=str2bool(el.attribute("primarykey","0"));
-               cl.isunique=str2bool(el.attribute("unique","0"));
-               cl.isindex=str2bool(el.attribute("index","0"));
-               if(el.hasAttribute("null"))
-                       cl.isnull=str2bool(el.attribute("null"));
-               else
-                       cl.isnull=!str2bool(el.attribute("notnull","0"));
-               cl.type=el.attribute("type");
-               //TODO: validate type
-               cl.foreign=el.attribute("foreignkey");
-               //check foreign key exists
-               if(cl.foreign!=""){
-                       QStringList fgn=cl.foreign.split(":");
-                       if(fgn.size()!=2){
-                               qDebug("Error: table %s column %s: foreign key definition must use syntax 'table:column'",m_name.toAscii().data(),cl.name.toAscii().data());
-                               m_valid=false;
-                               return;
-                       }
-                       if(!woc->hasTable(fgn[0])){
-                               qDebug("Error: table %s column %s: foreign key target table %s does not exist",m_name.toAscii().data(),cl.name.toAscii().data(),fgn[0].toAscii().data());
-                               m_valid=false;
-                               return;
-                       }
-                       if(!woc->table(fgn[0]).hasColumn(fgn[1])){
-                               qDebug("Error: table %s column %s: foreign key target table/column %s does not exist",m_name.toAscii().data(),cl.name.toAscii().data(),cl.foreign.toAscii().data());
-                               m_valid=false;
-                               return;
-                       }
-               }
-               cl.defaultval=el.attribute("default");
-               //TODO: validate default against type
-               QDomNodeList nl2=el.elementsByTagName("Value");
-               int nxval=0;
-               //enum values
-               for(int j=0;j<nl2.size();j++){
-                       QDomElement el2=nl2.at(j).toElement();
-                       if(el2.isNull())continue;
-                       QString n=el2.attribute("name");
-                       if(n==""){
-                               qDebug("Warning: anonymous enum value in table %s column %s. Ignoring it.",m_name.toAscii().data(),cl.name.toAscii().data());
-                               continue;
-                       }
-                       nxval=el2.attribute("value",QString::number(nxval)).toInt(0,0);
-                       cl.enumvals.append(QPair<QString,int>(n,nxval));
-                       nxval++;
-               }
-               m_columns.append(cl);
+               m_columns.append(cl.second);
+       }
+       //Audit Columns
+       nl=tbl.elementsByTagName("AuditColumn");
+       for(int i=0;i<nl.size();i++){
+               QDomElement el=nl.at(i).toElement();
+               if(el.isNull())continue;
+               QPair<bool,s_col> cl=parseColumn(el,m_name);
+               if(!cl.first)return;
+               m_auditcolumns.append(cl.second);
        }
        
        //Foreign getter methods
@@ -675,6 +673,74 @@ WocTable::WocTable(const QDomElement&tbl)
        }
 }
 
+
+QPair<bool,WocTable::s_col> WocTable::parseColumn(const QDomElement&el,QString m_name)
+{
+       s_col cl;
+       QRegExp good("[a-z][a-z0-9_]*",Qt::CaseInsensitive);
+       cl.name=el.attribute("name");
+       //check name syntax, check it is not doubled
+       if(!good.exactMatch(cl.name)){
+               qDebug("Error: table %s column %s does not have a regular name.",m_name.toAscii().data(),cl.name.toAscii().data());
+               return QPair<bool,s_col>(false,s_col());
+       }
+       cl.isprime=str2bool(el.attribute("primarykey","0"));
+       cl.isunique=str2bool(el.attribute("unique","0"));
+       cl.isindex=str2bool(el.attribute("index","0"));
+       if(el.hasAttribute("null"))
+               cl.isnull=str2bool(el.attribute("null"));
+       else
+               cl.isnull=!str2bool(el.attribute("notnull","0"));
+       cl.type=el.attribute("type");
+       //TODO: validate type
+       cl.foreign=el.attribute("foreignkey");
+       WocProcessor*woc=WocProcessor::instance();
+       //check foreign key exists
+       if(cl.foreign!=""){
+               QStringList fgn=cl.foreign.split(":");
+               if(fgn.size()!=2){
+                       qDebug("Error: table %s column %s: foreign key definition must use syntax 'table:column'",m_name.toAscii().data(),cl.name.toAscii().data());
+                       return QPair<bool,s_col>(false,s_col());
+               }
+               if(!woc->hasTable(fgn[0])){
+                       qDebug("Error: table %s column %s: foreign key target table %s does not exist",m_name.toAscii().data(),cl.name.toAscii().data(),fgn[0].toAscii().data());
+                       return QPair<bool,s_col>(false,s_col());
+               }
+               if(!woc->table(fgn[0]).hasColumn(fgn[1])){
+                       qDebug("Error: table %s column %s: foreign key target table/column %s does not exist",m_name.toAscii().data(),cl.name.toAscii().data(),cl.foreign.toAscii().data());
+                       return QPair<bool,s_col>(false,s_col());
+               }
+       }
+       cl.defaultval=el.attribute("default");
+       //TODO: validate default against type
+       QDomNodeList nl2=el.elementsByTagName("Value");
+       int nxval=0;
+       //enum values
+       for(int j=0;j<nl2.size();j++){
+               QDomElement el2=nl2.at(j).toElement();
+               if(el2.isNull())continue;
+               QString n=el2.attribute("name");
+               if(n==""){
+                       qDebug("Warning: anonymous enum value in table %s column %s. Ignoring it.",m_name.toAscii().data(),cl.name.toAscii().data());
+                       continue;
+               }
+               nxval=el2.attribute("value",QString::number(nxval)).toInt(0,0);
+               cl.enumvals.append(QPair<QString,int>(n,nxval));
+               nxval++;
+       }
+       //default calls
+       nl2=el.elementsByTagName("Call");
+       for(int j=0;j<nl2.size();j++){
+               QDomElement el2=nl2.at(j).toElement();
+               if(el2.isNull())continue;
+               QString lang=el2.attribute("lang");
+               QString meth=el2.attribute("method","false");
+               cl.methodcalls.insert(lang,meth);
+       }
+       
+       return QPair<bool,s_col>(true,cl);
+}
+
 QStringList WocTable::columns()const
 {
        QStringList r;
@@ -683,6 +749,16 @@ QStringList WocTable::columns()const
        return r;
 }
 
+QStringList WocTable::auditColumns()const
+{
+       QStringList r;
+       for(int i=0;i<m_staticauditcolumns.size();i++)
+               r<<m_staticauditcolumns[i].name;
+       for(int i=0;i<m_auditcolumns.size();i++)
+               r<<m_auditcolumns[i].name;
+       return r;
+}
+
 QStringList WocTable::primaryColumns()const
 {
        QStringList r;
@@ -812,6 +888,70 @@ bool WocTable::haveForeign(QString f)const
        return false;
 }
 
+QString WocTable::columnCall(QString col,QString lang)const
+{
+       for(int i=0;i<m_columns.size();i++){
+               s_col cl=m_columns[i];
+               if(cl.name==col){
+                       if(!cl.methodcalls.contains(lang))return "";
+                       else return cl.methodcalls[lang];
+               }
+       }
+       return "";
+}
+
+QList<WocTable::s_col>WocTable::m_staticauditcolumns;
+void WocTable::parseAuditStatic(const QDomElement&el)
+{
+       QDomNodeList nl=el.elementsByTagName("Column");
+       for(int i=0;i<nl.size();i++){
+               QDomElement el2=nl.at(i).toElement();
+               if(el2.isNull())continue;
+               QPair<bool,s_col>cl=parseColumn(el2,"(global audit settings)");
+               if(!cl.first){
+                       WocProcessor::instance()->errorFound();
+                       return;
+               }
+               m_staticauditcolumns.append(cl.second);
+       }
+}
+
+WocTable WocTable::auditTable()const
+{
+       WocTable adt;
+       adt.m_valid=m_valid;
+       adt.m_backup=m_backup;
+       adt.m_audit=false;
+       adt.m_name=m_name+"_audit";//enhance the name
+       adt.m_base="WobTable";//revert to default
+       adt.m_foreign=m_foreign;
+       //these stay empty: m_presets, m_auditcolumns
+       
+       //now for the complicated stuff
+       //create primary key
+       s_col cl;
+       cl.name="auditid";cl.type="seq64";
+       cl.isindex=cl.isunique=cl.isnull=false;cl.isprime=true;
+       adt.m_columns.append(cl);
+       //copy common columns
+       adt.m_columns.append(m_staticauditcolumns);
+       //copy normal columns
+       for(int i=0;i<m_columns.size();i++){
+               //get and reset
+               cl=m_columns[i];
+               cl.isprime=cl.isunique=false;
+               cl.methodcalls.clear();
+               if(cl.type.left(3)=="seq")cl.type="int"+cl.type.mid(3);
+               //add
+               adt.m_columns.append(cl);
+       }
+       //copy local audit columns
+       adt.m_columns.append(m_auditcolumns);
+       
+       //return result
+       return adt;
+}
+
 
 /******************************************************************************
  * WocTransaction
index 48369f7..da26967 100644 (file)
@@ -94,8 +94,10 @@ class WocClass
                bool hasMapping(QString m)const{return m_maps.contains(m);}
                /**returns the names of all tables for which a mapping exists*/
                QStringList mappingTables()const{return m_maps.keys();}
-               /**returns the specific mapping*/
-               QList<QPair<QString,QString> >mapping(QString m)const{return m_maps[m];}
+               /**returns the specific mapping; map key=property, map value=column*/
+               QMap<QString,QString> mapping(QString m)const;
+               /**returns the method for a specific mapping or an empty string if it does not exist in the specified language*/
+               QString mapMethod(QString table,QString property,QString lang)const;
                
        private:
                //valid: parsing the WOLF succeeded
@@ -111,7 +113,11 @@ class WocClass
                };
                QList<s_prop> m_props;
                //mappings: "table-name" => List of ("column-name","property-name")
-               QMap<QString,QList<QPair<QString,QString> > >m_maps;
+               struct s_map{
+                       QString column,property;
+                       QMap<QString,QString>method;//lang->method
+               };
+               QMap<QString,QList<s_map> >m_maps;
                //enum types: "type-name" => List of ("constant-name",int-constant-value)
                QMap<QString,QList<QPair<QString,int> > >m_enumvals;
                //serializers: "name" => List of properties (syntax Objects: "propertyname/Serializer"
@@ -166,6 +172,8 @@ class WocTable
                bool columnIsUnique(QString)const;
                /**returns enum definitions of the column - each pair contains the symbolic name in first and the assigned integer value in second*/
                QList<QPair<QString,int> > columnEnums(QString)const;
+               /**returns the insert call of a column for a specific language; empty string if there is none*/
+               QString columnCall(QString col,QString lang)const;
                
                /**returns all enum definitions of the table; see also columnEnums */
                QList<QPair<QString,int> > getEnums()const;
@@ -180,17 +188,31 @@ class WocTable
                /**returns a list of all preset values (to be generated when the DB is created);
                each entry in the list is a dictionary with the column name as key and the intended preset value as value - each entry of the list is one DB row, each key-value-pair in the map is one preset value in that row*/
                QList<QMap<QString,QString> > presets()const{return m_presets;}
+               
+               /**parses the static part of auditing*/
+               static void parseAuditStatic(const QDomElement&);
+               /**returns whether the table is auditable*/
+               bool isAuditable()const{return m_audit;}
+               /**creates and returns the table instance that represents the audit table*/
+               WocTable auditTable()const;
+               /**returns the names of audit columns (except auditid)*/
+               QStringList auditColumns()const;
        private:
-               bool m_valid,m_backup;
+               bool m_valid,m_backup,m_audit;
                QString m_name,m_base;
                struct s_col {
                        QString name,type,foreign,defaultval;
                        bool isnull,isprime,isindex,isunique;
                        QList<QPair<QString,int> >enumvals;
+                       QMap<QString,QString>methodcalls;
                };
-               QList<s_col>m_columns;
+               QList<s_col>m_columns,m_auditcolumns;
+               static QList<s_col>m_staticauditcolumns;
                QList<QPair<QString,QString> >m_foreign;
                QList<QMap<QString,QString> >m_presets;
+               
+               //helper method: parses a single column element
+               static QPair<bool,s_col> parseColumn(const QDomElement&,QString);
 };
 
 /**internal representation of a transaction*/
@@ -349,7 +371,7 @@ class WocProcessor:public QObject
                void newClass(const WocClass&);
                void newTable(const WocTable&);
                void newTransaction(const WocTransaction&);
-       private slots:
+       public slots:
                void errorFound();
        private:
                QString m_baseDir,m_wobDir,m_verComm,m_verNeedComm,m_verHR,m_projname;
index 741b725..f33f429 100644 (file)
@@ -12,6 +12,7 @@
 //
 $AUTOCLASS["DbEngine"]='./inc/db/db.php';
 $AUTOCLASS["MysqlEngine"]='./inc/db/db_mysql.php';
+$AUTOCLASS["BarcodeTable"]='./inc/db/barcodetable.php';
 
 include('./inc/db/db_scheme.php');
 ?>
\ No newline at end of file
diff --git a/www/inc/db/barcodetable.php b/www/inc/db/barcodetable.php
new file mode 100644 (file)
index 0000000..57527be
--- /dev/null
@@ -0,0 +1,44 @@
+<?
+//
+// PHP Implementation: barcodetable
+//
+// Description: 
+//
+//
+// Author: Konrad Rosenbaum <konrad@silmor.de>, (C) 2009
+//
+// Copyright: See README/COPYING files that come with this distribution
+//
+//
+
+class BarcodeTable extends WobTable
+{
+       private static $NumTicketChars=false;
+       private static function init()
+       {
+               if(self::$NumTicketChars===false){
+                       self::$NumTicketChars=$db->getConfig("TicketIDChars")+0;
+                       if(self::$NumTicketChars<=5)self::$NumTicketChars=10;
+               }
+       }
+       public static function getNewTicketId()
+       {
+               self::init();
+               do{
+                       $tid=getCode39ID(self::$NumTicketChars,RND_TICKET);
+                       $res=$db->select("ticket","ticketid","ticketid=".$db->escapeString($tid));
+                       if(count($res)==0)return $tid;
+               }while(true);
+       }
+       public static function getNewVoucherId()
+       {
+               self::init();
+               do{
+                       $tid=getCode39ID(self::$NumTicketChars,RND_VOUCHER);
+                       $res=$db->select("voucher","voucherid","voucherid=".$db->escapeString($tid));
+                       if(count($res)==0)return $tid;
+               }while(true);
+       }
+};
+
+?>
\ No newline at end of file
index 00a7656..555b3f5 100644 (file)
@@ -195,6 +195,8 @@ abstract class DbEngine
                $cm="";
                $val=") VALUES (";
                while(list($k,$v)=each($values)){
+                       //make sure the column exists, ignore the riff-raff
+                       if(!$dbScheme->tableHasColumn($table,$k))continue;
                        $ret.=$cm;$val.=$cm;$cm=",";
                        //append column name
                        $ret.=$k;
@@ -230,6 +232,8 @@ abstract class DbEngine
                reset($values);
                $cm="";
                while(list($k,$v)=each($values)){
+                       //make sure the column exists, ignore the riff-raff
+                       if(!$dbScheme->tableHasColumn($table,$k))continue;
                        $ret.=$cm;$cm=",";
                        //append column name
                        $ret.=$k."=";
index 218cae2..9e89db6 100644 (file)
@@ -19,10 +19,10 @@ $db->deleteRows("session","timeout<=".time());
 /**The session class*/
 class Session
 {
-       private $sessid="";
-       private $user="";
-       private $roles;
-       private $rights;
+       protected $sessid="";
+       protected $user="";
+       protected $roles;
+       protected $rights;
        
        /**construct the session object, check validity*/
        public function __construct($trans)
@@ -48,6 +48,21 @@ class Session
                return $session;
        }
        
+       /**return the name of the currently logged in user*/
+       public static function currentUserName()
+       {
+               global $session;
+               if(isset($session))return $session->getUser();
+               else return "(unknown)";
+       }
+       
+       /**initialize system in web session mode (ie. some user called the web page in a browser)*/
+       public static function setWebSession()
+       {
+               global $session;
+               $session=new DummyWebSession;
+       }
+       
        /**internal: retrieve and remember the rights of this user*/
        protected function initRights()
        {
@@ -67,7 +82,7 @@ class Session
        /**returns all roles of this user*/
        public function getRoles(){return $this->roles;}
        
-       /**creates a new session*/
+       /**creates a new session, called from the Login transaction*/
        static public function login($trans)
        {
                global $db,$ClientSessionTimeout;
@@ -79,39 +94,39 @@ class Session
                        $hosts[]=$hst["host"];
                //logic check 1: abort if host is unknown
                if(count($hres)==0){
-                       $trans->abortWithError(translate("php::","Unknown Host"),"auth");
+                       $trans->abortWithError(translate("Session","Unknown Host"),"auth");
                }
                //logic check: login is allowed if
                // a) $hosts contains _any and the host is known, or
                // b) $hosts contains the transmitted host name
                $hostname=$trans->gethostname();
                if( !in_array($hostname,$hosts) && !in_array("_any",$hosts)){
-                       $trans->abortWithError(translate("php::","Host/User combination not allowed"),"auth");
+                       $trans->abortWithError(translate("Session","Host/User combination not allowed"),"auth");
                }
                
                //validate host
                $splt=explode(" ",$hres[0]["hostkey"]);
                if(count($splt)!=2){
-                       $trans->abortWithError(translate("php::","Host authentication failed"),"auth");
+                       $trans->abortWithError(translate("Session","Host authentication failed"),"auth");
                }
                $cmp=strtolower(sha1($splt[0].$trans->gethostkey()));
                if($cmp != strtolower($splt[1])){
-                       $trans->abortWithError(translate("php::","Host authentication failed"),"auth");
+                       $trans->abortWithError(translate("Session","Host authentication failed"),"auth");
                }
                
                //get user data
                $ures=$db->select("user","*","uname=".$db->escapeString($trans->getusername()));
                if(count($ures)<1){
-                       $trans->abortWithError(translate("php::","User Authentication failed"),"auth");
+                       $trans->abortWithError(translate("Session","User Authentication failed"),"auth");
                }
                //validate user
                $splt=explode(" ",$ures[0]["passwd"]);
                if(count($splt)!=2){
-                       $trans->abortWithError(translate("php::","User Authentication failed"),"auth");
+                       $trans->abortWithError(translate("Session","User Authentication failed"),"auth");
                }
                $cmp=strtolower(sha1($splt[0].$trans->getpassword()));
                if($cmp!=strtolower($splt[1])){
-                       $trans->abortWithError(translate("php::","User Authentication failed"),"auth");
+                       $trans->abortWithError(translate("Session","User Authentication failed"),"auth");
                }
                
                //create session and return
@@ -161,16 +176,7 @@ class Session
                return $this->user!="";
        }
        
-       /**helper function for authenticate*/
-       protected function xdie($str)
-       {
-               //debug version:
-//             print($str);
-               //all versions
-               exit();
-       }
-       
-       /**set my own password*/
+       /**set my own password; called from SetMyPasswd transaction*/
        public function setMyPasswd($trans)
        {
                $old=$trans->getoldpassword();
@@ -214,333 +220,17 @@ class Session
        }
 };
 
-//return all users to client
-function getAllUsersXml()
-{
-       global $db;
-       header("X-MagicSmoke-Status: Ok");
-       $res=$db->select("users","uname,description","");
-       $dom=new DomDocument;
-       $root=$dom->createElement("Users");
-       for($i=0;$i<count($res);$i++){
-               $usr=$dom->createElement("User",xq($res[$i]["description"]));
-               $usr->setAttributeNode(new DOMAttr("name",$res[$i]["uname"]));
-               $root->appendChild($usr);
-       }
-       $dom->appendChild($root);
-       print($dom->saveXML());
-}
-
-//return the roles of a specific user
-function getUserAclXml($user)
+/**dummy class used by browsed pages to represent the virtual web user*/
+class DummyWebSession extends Session
 {
-       //sanity check
-       $user=trim($user);
-       if(ereg("^[A-Za-z0-9_\\.,:-]+$",$user)===false){
-               header("X-MagicSmoke-Status: SyntaxError");
-               die(tr("invalid user name"));
-       }
-       //go on...
-       global $db,$ALLOWEDREQUESTS,$SPECIALROLES;
-       header("X-MagicSmoke-Status: Ok");
-       //create list of roles
-       $roles=$ALLOWEDREQUESTS;
-       foreach($SPECIALROLES as $rl)
-               $roles[]=$rl;
-       //get roles from DB
-       $res=$db->select("userrole","role","uname=".$db->escapeString($user));
-       $acl=array();
-       foreach($res as $rl)$acl[]=$rl["role"];
-       $dom=new DOMDocument;
-       $root=$dom->createElement("ACL");
-       $root->setAttributeNode(new DOMAttr("user",$user));
-       foreach($roles as $rl){
-               $re=$dom->createElement("Role");
-               $re->setAttributeNode(new DOMAttr("name",$rl));
-               if(array_search($rl,$acl)===false)$re->setAttributeNode(new DOMAttr("set","0"));
-               else $re->setAttributeNode(new DOMAttr("set","1"));
-               $root->appendChild($re);
-       }
-       $dom->appendChild($root);
-       print($dom->saveXML());
-}
-
-//set the ACL of a user
-function setUserAclXml($txt)
-{
-       //DOM
-       $xml=new DOMDocument;
-       if(!$xml->loadXML($txt)){
-               header("X-MagicSmoke-Status: SyntaxError");
-               die(tr("unable to parse XML data"));
-       }
-       //get user name
-       $acl=$xml->getElementsByTagName("ACL");
-       if($acl->length != 1){
-               header("X-MagicSmoke-Status: SyntaxError");
-               die(tr("expected exactly 1 ACL element"));
-       }
-       global $db,$ALLOWEDREQUESTS,$SPECIALROLES;
-       $roles=$ALLOWEDREQUESTS;
-       foreach($SPECIALROLES as $rl)
-               $roles[]=$rl;
-       $usr=$acl->item(0)->getAttribute("user");
-       //check user name
-       $db->beginTransaction();
-       $res=$db->select("users","count(uname)","uname=".$db->escapeString($usr));
-       if($res[0][0]!=1){
-               header("X-MagicSmoke-Status: SyntaxError");
-               $db->rollbackTransaction();
-               die(tr("unknown user name"));
-       }
-       //update roles
-       $acl=$xml->getElementsByTagName("Role");
-       for($i=0;$i<$acl->length;$i++){
-               //does role exist?
-               $name=$acl->item($i)->getAttribute("name");
-               if(array_search($name,$roles)===false)continue;
-               $isset=$acl->item($i)->getAttribute("set")+0;
-               if($isset){
-                       $res=$db->select("userrole","count(role)","uname=".$db->escapeString($usr)." AND role=".$db->escapeString($name));
-                       if($res[0][0]!=0)continue;
-                       $db->insert("userrole",array("uname"=>$usr,"role"=>$name));
-               }else{
-                       $db->deleteRows("userrole","uname=".$db->escapeString($usr)." AND role=".$db->escapeString($name));
-               }
-       }
-       $db->commitTransaction();
-       header("X-MagicSmoke-Status: Ok");
-}
-
-//return the hosts of a specific user
-function getUserHostsXml($user)
-{
-       //sanity check
-       $user=trim($user);
-       if(ereg("^[A-Za-z0-9_\\.,:-]+$",$user)===false){
-               header("X-MagicSmoke-Status: SyntaxError");
-               die(tr("invalid user name"));
-       }
-       //go on...
-       global $db;
-       header("X-MagicSmoke-Status: Ok");
-       //create list of hosts
-       $hosts=array();
-       $res=$db->select("host","hostname","");
-       for($i=0;$i<count($res);$i++){
-               $hosts[]=$res[$i]["hostname"];
-       }
-       //get roles from DB
-       $res=$db->select("userhosts","host","uname=".$db->escapeString($user));
-       $acl=array();
-       foreach($res as $rl)$acl[]=$rl["host"];
-       $dom=new DOMDocument;
-       $root=$dom->createElement("Hosts");
-       $root->setAttributeNode(new DOMAttr("user",$user));
-       foreach($hosts as $hs){
-               $re=$dom->createElement("Host");
-               $re->setAttributeNode(new DOMAttr("name",$hs));
-               if(array_search($hs,$acl)===false)$re->setAttributeNode(new DOMAttr("set","0"));
-               else $re->setAttributeNode(new DOMAttr("set","1"));
-               $root->appendChild($re);
-       }
-       $dom->appendChild($root);
-       print($dom->saveXML());
-}
-
-//set the Hosts of a user
-function setUserHostsXml($txt)
-{
-       //DOM
-       $xml=new DOMDocument;
-       if(!$xml->loadXML($txt)){
-               header("X-MagicSmoke-Status: SyntaxError");
-               die(tr("unable to parse XML data"));
-       }
-       //get user name
-       $acl=$xml->getElementsByTagName("Hosts");
-       if($acl->length != 1){
-               header("X-MagicSmoke-Status: SyntaxError");
-               die(tr("expected exactly 1 Hosts element"));
-       }
-       global $db;
-       //create list of hosts
-       $hosts=array();
-       $res=$db->select("host","hostname","");
-       for($i=0;$i<count($res);$i++){
-               $hosts[]=$res[$i]["hostname"];
-       }
-       $usr=$acl->item(0)->getAttribute("user");
-       //check user name
-       $db->beginTransaction();
-       $res=$db->select("users","count(uname)","uname=".$db->escapeString($usr));
-       if($res[0][0]!=1){
-               header("X-MagicSmoke-Status: SyntaxError");
-               $db->rollbackTransaction();
-               die(tr("unknown user name"));
-       }
-       //update roles
-       $acl=$xml->getElementsByTagName("Host");
-       for($i=0;$i<$acl->length;$i++){
-               //does role exist?
-               $name=$acl->item($i)->getAttribute("name");
-               if(array_search($name,$hosts)===false)continue;
-               $isset=$acl->item($i)->getAttribute("set")+0;
-               if($isset){
-                       $res=$db->select("userhosts","count(host)","uname=".$db->escapeString($usr)." AND host=".$db->escapeString($name));
-                       if($res[0][0]!=0)continue;
-                       $db->insert("userhosts",array("uname"=>$usr,"host"=>$name));
-               }else{
-                       $db->deleteRows("userhosts","uname=".$db->escapeString($usr)." AND host=".$db->escapeString($name));
-               }
-       }
-       $db->commitTransaction();
-       header("X-MagicSmoke-Status: Ok");
-}
-
-//helper function: parse User-XML-structure
-function parseUserXml($txt)
-{
-       $xml=new DOMDocument;
-       if(!$xml->loadXML($txt)){
-               header("X-MagicSmoke-Status: SyntaxError");
-               die(tr("unable to parse XML data"));
-       }
-       $ret=array();
-       foreach($xml->getElementsByTagName("User") as $el){
-               $usr["name"]=$el->getAttribute("name");
-               $usr["descr"]="";
-               $usr["passwd"]=$el->getAttribute("passwd");
-               foreach($el->childNodes as $cn)
-                       if($cn->nodeType==XML_TEXT_NODE)
-                               $usr["descr"]=$cn->wholeText;
-               $ret[]=$usr;
-       }
-       return $ret;
-}
-
-//set new description for user
-function setUserDescrXml($txt)
-{
-       global $db;
-       $usr=parseUserXml($txt);
-       for($i=0;$i<count($usr);$i++){
-               $db->update("users",array("description"=>$usr[$i]["descr"]),"uname=".$db->escapeString($usr[$i]["name"]));
-       }
-       header("X-MagicSmoke-Status: Ok");
-}
-
-//add a new user
-function addUserXml($txt)
-{
-       global $db;
-       $usr=parseUserXml($txt);
-       $dom=new DOMDocument;
-       $root=$dom->createElement("Users");
-       for($i=0;$i<count($usr);$i++){
-               //syntax check
-               if(ereg("^[A-Za-z0-9_\\.,:-]+$",$usr[$i]["name"])===false)continue;
-               //existance check
-               $db->beginTransaction();
-               $res=$db->select("users","uname","uname='".$usr[$i]["name"]."'");
-               if(count($res)==0){
-                       //create new
-                       $db->insert("users",array("uname"=>$usr[$i]["name"],"description"=>$usr[$i]["descr"],"passwd"=>$usr[$i]["passwd"]));
-                       //print data
-                       $udm=$dom->createElement("User",xq($usr[$i]["descr"]));
-                       $udm->setAttributeNode(new DOMAttr("name",$usr[$i]["name"]));
-                       $root->appendChild($udm);
-               }
-               $db->commitTransaction();
-       }
-       $dom->appendChild($root);
-       print($dom->saveXML());
-       header("X-MagicSmoke-Status: Ok");
-}
-
-//delete a user
-function deleteUserXml($txt)
-{
-       global $db;
-       $lst=explode("\n",trim($txt));
-       if($lst===false || count($lst)<1){
-               header("X-MagicSmoke-Status: SyntaxError");
-               echo tr("Syntax Error");
-               return;
-       }
-       $usr=trim($lst[0]);
-       if(count($lst)>1)$nusr=trim($lst[1]);
-       else $nusr=false;
-       //start transaction
-       $db->beginTransaction();
-       $b=true;
-       //delete ACL
-       $b &= $db->deleteRows("userrole","uname=".$db->escapeString($usr)) !== false;
-       //delete Hosts
-       $b &= $db->deleteRows("userhosts","uname=".$db->escapeString($usr)) !== false;
-       //delete open sessions
-       $b &= $db->deleteRows("session","user=".$db->escapeString($usr)) !== false;
-       //check for success so far
-       if(!$b){
-               $db->rollbackTransaction();
-               echo tr("Cannot remove user: DB error while deleting ACL.");
-               return;
-       }
-       //re-assign DB objects
-       $b &= $db->update("order",array("soldby"=>$nusr),"soldby=".$db->escapeString($usr)) !== false;
-       $b &= $db->update("order",array("depositat"=>$nusr),"depositat=".$db->escapeString($usr)) !== false;
-       $b &= $db->update("ticket",array("reservedby"=>$nusr),"reservedby=".$db->escapeString($usr)) !== false;
-       if(!$b){
-               header("X-MagicSmoke-Status: Error");
-               echo tr("Cannot remove user: unable to replace user.");
-               //end transaction
-               $db->rollbackTransaction();
-               return;
-       }
-       //attempt to delete User itself
-       $b=$db->deleteRows("users","uname=".$db->escapeString($usr)) !== false;
-       //say OK or not OK now
-       if($b){
-               header("X-MagicSmoke-Status: Ok");
-               //end transaction
-               $db->commitTransaction();
-       }else{
-               header("X-MagicSmoke-Status: Error");
-               echo tr("Cannot remove user: DB error while deleting user.");
-               //end transaction
-               $db->rollbackTransaction();
-       }
-}
-
-//set another users passwd
-function setPasswdXml($txt)
-{
-       global $db;
-       //parse XML
-       $dom=new DOMDocument;
-       if(!$dom->loadXML($txt)){
-               header("X-MagicSmoke-Status: SyntaxError");
-               die(tr("unable to parse XML data"));
-       }
-       $nl=$dom->getElementsByTagName("SetPasswd");
-       if($nl->length!=1){
-               header("X-MagicSmoke-Status: SyntaxError");
-               die(tr("expected exactly one passwd element"));
-       }
-       $spw=$nl->item(0);
-       $usr=$spw->getAttribute("user");
-       $nwp=$spw->getAttribute("newpwd");
-       //sanity check
-       if($nwp==""){
-               header("X-MagicSmoke-Status: SyntaxError");
-               die(tr("cannot set an empty password"));
+       public function __construct()
+       {
+               $this->user="(web)";
+               //fake admin, because web pages do their own checks
+               //TODO: do something more sensible (eg. _web role)
+               $this->roles=array("_admin");
+               $this->rights=array();
        }
-       //set new password
-       if($db->update("users",array("passwd"=>$nwp),"uname=".$db->escapeString($usr))===false){
-               header("X-MagicSmoke-Status: Error");
-               die(tr("Unable to change this password."));
-       }else
-               header("X-MagicSmoke-Status: Ok");
 }
 
 ?>
\ No newline at end of file
index 79070d2..7d103f2 100644 (file)
@@ -11,6 +11,7 @@
 //
 //
 
+/**thrown by WobTable if a property change is out of range*/
 class ValueOutOfRange extends Exception
 {
        public function __construct($tab,$col,$val)
@@ -19,38 +20,76 @@ class ValueOutOfRange extends Exception
        }
 };
 
-class WobTable
+/**parent class of all tables*/
+abstract class WobTable
 {
        private $data;
+       private $cdata;
        private $isfromdb;
        private $table;
        
+       /**constructs a basic table*/
        protected function __construct(array $data,$isfromdb,$table)
        {
                $this->data=$data;
                $this->isfromdb=$isfromdb;
                $this->table=$table;
+               $this->cdata=array();
        }
        
+       /**set properties*/
        public function __set($name,$value)
        {
-               global $db,$dbScheme;
-               //verify name against scheme
-               if(!$dbScheme->tableHasColumn($this->table,$name))return;
-               //verify enum vals
+               //check for property
+               if(!$this->hasProperty($name)){
+                       $trace=debug_backtrace();
+                       trigger_error("Trying to set undefined property ".$name." in ".$trace[0]['file']." on line ".$trace[0]['line'],E_USER_NOTICE);
+               }
+               //verify value (TODO: what about NULL?)
                $vm="verifyValue".$name;
                if(method_exists($this,$vm))
-                       if(!$t->$vm($value))
+                       if(!$this->$vm($value))
                                throw ValueOutOfRange($this->table,$name,$value);
-               //DB update (if from DB)
-               $succ=true;
-               if($this->isfromdb){
-                       $succ=$db->update($this->table,array($name => $value),$this->where());
+               //set
+               $this->cdata[$name]=$value;
+       }
+       
+       /**reverts changes to the property*/
+       public function revert($name)
+       {
+               if(!$this->hasProperty($name)){
+                       $trace=debug_backtrace();
+                       trigger_error("Trying to revert undefined property ".$name." in ".$trace[0]['file']." on line ".$trace[0]['line'],E_USER_NOTICE);
                }
-               //if successful: store
-               if($succ)$this->data[$name]=$value;
+               if(array_key_exists($name,$this->cdata))unset($this->cdata[$name]);
        }
        
+       /**reverts all changes to properties*/
+       public function revertAll()
+       {
+               $this->cdata=array();
+       }
+       
+       /**returns the name of the table*/
+       public function tableName(){return $this->table;}
+       
+       /**returns whether the table contains a specific column*/
+       public function hasColumn($c)
+       {
+               global $dbScheme;
+               return $dbScheme->tableHasColumn($this->table,$name);
+       }
+       
+       /**overridden by woc, returns true if the property exists*/
+       abstract public function hasProperty($c);
+       
+       /**returns whether this is an auditable table*/
+       public function isAuditable(){return false;}
+       
+       /**overridden by woc, if this an auditable table; used in insert and update*/
+       protected function createAudit(){}
+       
+       /**returns the where clause to find this instance (via primary key columns)*/
        public function where()
        {
                global $dbScheme,$db;
@@ -63,11 +102,17 @@ class WobTable
                return $r;
        }
        
+       /**returns the property*/
        public function __get($name)
        {
                //verify name
+               if(!$this->hasProperty($name)){
+                       $trace=debug_backtrace();
+                       trigger_error("Accessing undefined property ".$name." in ".$trace[0]['file']." on line ".$trace[0]['line'],E_USER_NOTICE);
+               }
                //return value or null
-               if(isset($this->data[$name]))return $this->data[$name];
+               if(array_key_exists($name,$this->cdata))return $this->cdata[$name];
+               if(array_key_exists($name,$this->data))return $this->data[$name];
                else return null;
        }
        
@@ -75,7 +120,8 @@ class WobTable
        {
                global $db;
                //verify name and return true on existence AND notnull
-               if(isset($this->data[$name]))return !$db->isNull($this->data[$name]);
+               if(array_key_exists($name,$this->cdata))return isset($this->cdata[$name]);
+               if(array_key_exists($name,$this->data))return isset($this->data[$name]);
                else return false;
        }
        
@@ -83,30 +129,80 @@ class WobTable
        {
                global $dbScheme;
                //reset to null
-               if($dbScheme->tableHasColumn($name))$this->data[$name]=null;
+               if($this->hasProperty($name))$this->cdata[$name]=null;
        }
        
        /**insert the object under a new primary key value into the DB (implicitly calls newKey); returns true on success*/
        public function insert()
        {
-               //remove PK from object (so it is set to default)
                global $dbScheme;
                $this->isfromdb=false;
-               $pk=$dbScheme->primaryKeyColumns($this->table);
-               foreach($pk as $c)unset($this->data[$c]);
-               //optionally create new key
+               //create new key
                $this->newKey();
                //now insert
-               $r=$db->insert($this->table,$this->data);
+               $data=array();
+               foreach($this->data as $k=>$d)$data[$k]=$d;
+               foreach($this->cdata as $k=>$d)$data[$k]=$d;
+               $r=$db->insert($this->table,$data);
                if($r===false)return false;
-               //TODO: make this a bit more safe:
-               if($r!==true)$this->data[$pk[0]]=$r;
+               $this->isfromdb=true;
+               $this->data=$data;
+               $this->cdata=array();
+               createAudit();
+               //assign primary key if sequence (otherwise newKey has done it)
+               $seq=$dbScheme->hasSequence($this->table);
+               if($seq!==false)
+                       $this->data[$seq]=$r;
+               //return success
                return true;
        }
        
-       /**generate a new primary key value for insert and marks the object as not yet in the DB; the default sets the primary key to NULL; call the original first if you overwrite it*/
+       /**generate a new primary key value for insert and marks the object as not yet in the DB; the default sets the primary key to NULL if it is a sequence; call the original first if you overwrite it*/
        public function newKey()
        {
+               $this->isfromdb=false;
+               $pk=$dbScheme->hasSequence($this->table);
+               if($pk!==false){
+                       if(array_key_exists($pk,$this->data))unset($this->data[$pk]);
+                       if(array_key_exists($pk,$this->cdata))unset($this->cdata[$pk]);
+               }
+       }
+       
+       /**updates the object in the database; returns true on success; fails if it did not come from the DB - use insertOrUpdate in this case; succeeds without asking the database if nothing has changed*/
+       public function update()
+       {
+               if(!$this->isfromdb)return false;
+               if(count($this->cdata)==0)return true;
+               global $db;
+               $succ=$db->update($this->table,$this->cdata,$this->where())!==false;
+               if($succ){
+                       foreach($this->cdata as $k=>$d)$this->data[$k]=$d;
+                       $this->cdata=array();
+                       createAudit();
+               }
+               return $succ;
+       }
+       
+       /**updates existing object in the database or inserts it if it does not exist in the DB yet*/
+       public function insertOrUpdate()
+       {
+               if($this->isfromdb)return $this->update();
+               else return $this->insert();
+       }
+       
+       /**deletes this instance from the database; returns true if it actually executed*/
+       public function deleteFromDb()
+       {
+               if(!$this->isfromdb)return false;
+               global $db;
+               //obliterate audit data
+               if($this->isAuditable())
+                       $db->deleteRows($this->table."_audit",$this->where());
+               //delete data
+               $db->deleteRows($this->table,$this->where());
+               //mark as outsider
+               $this->isfromdb=false;
+               return true;
        }
 };
 
index 8c34a1f..7d3de02 100644 (file)
@@ -18,6 +18,10 @@ class WobTransactionBase {
        protected $aoutput;
        protected $toutput;
        
+       protected static $running="";
+       
+       static public function getExecutingName(){return self::$running;}
+       
        /**called to determine the correct transaction, aborts the script if there is none.*/
        static public function getTransactionName(){
                global $_SERVER;
@@ -31,7 +35,8 @@ class WobTransactionBase {
                        print("<WobResponse status=\"error\"><Error type=\"non-wob\">Request is not a Wob Request, Aborting.</Error></WobResponse>\n");
                        exit();
                }
-               return $_SERVER["HTTP_X_WOBREQUEST"];
+               self::$running=$_SERVER["HTTP_X_WOBREQUEST"];
+               return self::$running;
        }
        /**called to determine the session id*/
        static public function getHeader($hd)
index d8ffbe5..3dfaff2 100644 (file)
@@ -21,6 +21,8 @@ if(isset($_GET["mode"])){
 
 $lang->setLanguage("de");
 
+Session::setWebSession();
+
 //get page template and process it
 switch($mode){
        case "eventDetails":