From: konrad Date: Mon, 17 Nov 2008 16:57:52 +0000 (+0000) Subject: *restructured DB driver a bit X-Git-Url: http://git.silmor.de/gitweb/?a=commitdiff_plain;h=e83fdcc62c20ca9ae5f8cc099ea864ebd7caf1e4;p=konrad%2Fsmoke.git *restructured DB driver a bit *added shipping to DB *added shipping to docu (not implemented yet) git-svn-id: https://silmor.de/svn/softmagic/smoke/trunk@188 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33 --- diff --git a/doc/prog_protocol.html b/doc/prog_protocol.html index e6c8803..3af00be 100644 --- a/doc/prog_protocol.html +++ b/doc/prog_protocol.html @@ -456,6 +456,7 @@ The order XML representation looks as follows: totalprice="amountInCent" paid="amountInCent" status="orderstate"> <Ticket event="eventid" id="ticketid" price="priceInCent" status="ticketstate" /> <Voucher id="voucherid" price="priceInCent" value="remainingValueInCent" /> + <Shipping price="priceInCent" type="shippingtypeID">Shipping Comment</Shipping> <DeliveryAddress>deliver address</DeliveryAddress> <Comment>comment...</Comment> </Order> @@ -463,7 +464,6 @@ The order XML representation looks as follows: - @@ -474,9 +474,25 @@ The order XML representation looks as follows: - + + + + + + + + + + + + + + + + +
ItemDescriptionOccurrence
OrderContainer for one single order or sale1
  idID of the order, if already known.0-1
  totalpriceTotal accumulated price of the order. Automatically filled in.0-1
  paidAmount that has already been paid. Automatically filled in.0-1
  statusCurrent status of the order. Automatically filled in. See table below.0-1
Ticket(*)data about a single ticket bought in this order0-unlimited
  idID of the ticket1
  eventID of the event this ticket refers to.1
  pricePrice of the ticket1
  statusStatus of the ticket (see below)1
Voucher(*)data about a single voucher bought in this order, vouchers that are used to pay for an order are not stored0-unlimited
  idID of the voucher1
  pricePrice of the voucher (adds to price of the order)1
  valueValue (in cent) of the voucher (does not add to the order, but refers to how much the voucher is worth)1
Shippinginformation about the kind of shipping used and how much it costs; if text is used it is a copy of the text from the shipping table information - it cannot be changed here0-1
  pricePrice of the shipping option1
  typeshipping type ID1
DeliveryAddressthe address to send the stuff to, if not present or empty the address of the customer is used0-1
Commentcomment entered into the order by customer or seller0-1
(*)At least one of Ticket or Voucher must be used.

@@ -517,8 +533,9 @@ The request is an order object without most fields filled in, the response is a Ordercustomerid(1), customer, seller(3), ordertime(1,4), totalprice(5), paid(1), status(6), senttime(2,4) Ticketevent, price(7)event, id(1), price, status(6) Vouchervalue, price(7)value, price, id(1) -DeliveryAddress-- -Comment-- +Shippingtype(8), price(9)type(10), price, [text](10) +DeliveryAddress[text][text] +Comment[text][text] (1)field is optional for checks and has no meaning there, it is recommended the server returns a dummy ID for checks
(2)the field only exists for sales
@@ -526,7 +543,10 @@ The request is an order object without most fields filled in, the response is a (4)time stamps are automatically filled in with the current server time
(5)the total price is the accumulated price of all tickets and vouchers in the order
(6)the status fields have special meanings for checks, see below
-(7)the price field will only be honoured in the request, if the user also has the privilege to use the changeticketprice transaction

+(7)the price field will only be honoured in the request, if the user also has the privilege to use the changeticketprice transaction
+(8)the shipping types that are allowed depend on whether the user has the _anyshipping privilege
+(9)price is optional, if set it is ignored if the user does not have the _repriceshipping privilege
+(10)the type in the response may be -1 if an error occurred in this case the text contains the error message, otherwise it contains a copy of the shipping option text

Order status for checks: @@ -594,6 +614,51 @@ The setordercomment transaction is used to change the orders comment. T The response body is empty or optionally contains an error message. +

Changing the shipping option on an order

+ +The orderchangeshipping transaction can be used to change the shipping information on an order. The request looks like: + +
+<OrderChangeShipping orderid="orderId" type="newShippingType" price="newPriceInCent"/>
+
+ +If type is not present, the price is taken from the new shipping type. If type is not present, it is not changed. If type is empty it is reset to none (NULL) in the Database. If a price other than 0 is used, the type in the database must be present (!= NULL).

+ +The response contains the updated order object or just an error message. + +

Creating/Changing Shipping Options

+ +The setshipping creates or changes a shipping option. The request looks like: + +
+<ShippingOption id="shippingOptionID" price="priceInCent" web="0|1" anyUser="0|1">
+  Text that describes the option
+</ShippingOption>
+
+ +If the id attribute is missing the server creates a new option. Otherwise it changes an existing one. The web attribute tells whether the option is available to customers using the web interface. The anyUser attribute tells whether the option can be used by anyone who can create an order/sale (=1) or only by users with the "_anyshipping" privilege (=0).

+ +The response is empty or contains an error message. + +

Listing Shipping Options

+ +The getshipping transaction can be used to return all shipping options. If the user has the "setshipping" or "_anyshipping" privilege the list will also contain privileged options. The request is empty. The response looks like: + +
+<ShippingList>
+  <ShippingOption id="shippingOptionID" price="priceInCent" web="0|1" anyUser="0|1">
+    Text that describes the option
+  </ShippingOption>
+  ...
+  ...
+</ShippingList>
+
+ +

Adding Tickets or Vouchers to an Order

+ +tbd. + + diff --git a/www/admin.php b/www/admin.php index b7b9dac..b4f2422 100644 --- a/www/admin.php +++ b/www/admin.php @@ -25,21 +25,37 @@ if(isset($_GET["CreateDB"])){ ?> canUseDb()){ +$canUseDb=$db->canUseDb(); +if($canUseDb){ ?> -Database exists and is usable. +Database exists and is usable.

+ +
+ + + Database is not usable. Create?
+ +"); + $db->showCreateDb(); +} + +//the stuff below does not work if DB unusable +if(!$canUseDb) + exit(); +?>

Checking for Admin Users

diff --git a/www/inc/db/db.php b/www/inc/db/db.php index 2b3edd5..8e7cfc4 100644 --- a/www/inc/db/db.php +++ b/www/inc/db/db.php @@ -36,30 +36,34 @@ abstract class DbEngine } /**returns the version of the DB layout that is required by this version of Magic Smoke*/ - public function needVersion(){return "00.01";} + public function needVersion() + { + global $dbScheme; + return $dbScheme->version(); + } /**returns whether the table exists; must be implemented by driver*/ public abstract function haveTable($tablename); - /**begins a transaction; must be implemented by driver*/ + /**begins a transaction; must be implemented by driver; use sqlBeginTransaction to create the SQL statement!*/ public abstract function beginTransaction(); - /**ends a transaction successfully; must be implemented by driver; returns true on success*/ + /**ends a transaction successfully; must be implemented by driver; returns true on success; use sqlCommitTransaction to create the SQL statement!*/ public abstract function commitTransaction(); - /**ends a transaction with a rollback; must be implemented by driver; returns true on success*/ + /**ends a transaction with a rollback; must be implemented by driver; returns true on success; use sqlRollbackTransaction to create the SQL statement!*/ public abstract function rollbackTransaction(); - /**gets some data from the database; $table is the name of the table, $cols is the list of columns to return or "*" for all, $where is the where clause of the SQL-statement, $orderby may contain additional ORDER BY or GROUP BY clauses; returns array of rows, which are in *_fetch_array format; returns false on error*/ + /**gets some data from the database; $table is the name of the table, $cols is the list of columns to return or "*" for all, $where is the where clause of the SQL-statement, $orderby may contain additional ORDER BY or GROUP BY clauses; returns array of rows, which are in *_fetch_array format; returns false on error; use sqlSelect to create the SQL statement!*/ public abstract function select($table,$cols,$where,$orderby=""); - /**insert values into a table; returns false on failure, the new primary key if a sequence was set, true otherwise*/ + /**insert values into a table; returns false on failure, the new primary key if a sequence was set, true otherwise; use sqlInsert to create the SQL statement!*/ public abstract function insert($table,array $values); - /**update database values; returns how many rows have been changed or false for failure*/ + /**update database values; returns how many rows have been changed or false for failure; use sqlUpdate to create the SQL statement!*/ public abstract function update($table,array $values,$where); - /**delete database values; returns the amount of rows deleted or false if an error occurred*/ + /**delete database values; returns the amount of rows deleted or false if an error occurred; use sqlDelete to create the SQL statement!*/ public abstract function deleteRows($table,$where); /**creates a table; the argument is an array of the form "col-name" => array("col-type", "flags"...); use sqlCreateTable() etc. to create the actual statement*/ @@ -69,11 +73,12 @@ abstract class DbEngine protected function tableName($tname){return $tname;} /**returns the correct type name for the required abstract data type; - types that must be understood are: int32 (INTEGER), int64 (LONG INTEGER), seq32 (auto-incrementing int), seq64, string:$length (text up to 255 chars, length is optional, default is 255; VARCHAR($length)), text (unlimited text)*/ + types that must be understood are: int32 (INTEGER), int64 (LONG INTEGER), seq32 (auto-incrementing int), seq64, bool (boolean), string:$length (text up to 255 chars, length is optional, default is 255; VARCHAR($length)), text (unlimited text)*/ protected function dataType($type) { if($type=="int32")return "INTEGER"; if($type=="int64")return "LONG INTEGER"; + if($type=="bool")return "BOOLEAN"; $tpa=explode(":",$type); if($tpa[0]=="string"){ if(isset($tpa[1])) @@ -89,6 +94,7 @@ abstract class DbEngine protected function columnFlag($flag,$col) { if($flag=="primarykey")return "PRIMARY KEY"; + if($flag=="null")return "NULL"; if($flag=="notnull")return "NOT NULL"; if($flag=="unique")return "NOT NULL UNIQUE"; if($flag=="index")return "INDEX"; @@ -108,9 +114,14 @@ abstract class DbEngine return "DEFAULT NULL"; return "DEFAULT ".$this->escapeString($tpa[1]); } + if($tpa[0]=="defaultbool"){ + if(count($tpa)<2) + return "DEFAULT NULL"; + return "DEFAULT ".$this->escapeBool($tpa[1]); + } } - /**creates a SQL92 statement for creating a table*/ + /**creates a SQL92 statement for creating a table; overwrite this to implement DB specific syntax*/ protected function sqlCreateTable($tablename,$table) { $ret="CREATE TABLE ".$this->tableName($tablename)." ("; @@ -137,13 +148,13 @@ abstract class DbEngine return $ret; } - /**This function can be used to amend the column definitions of a table; if overwritten it must return a string*/ + /**This function can be used to amend the column definitions of a table; if overwritten it must return a string; overwrite this to implement DB specific syntax*/ protected function createTableExtras($tablename,$table) { return ""; } - /**creates primary key statement for sqlCreateTable*/ + /**creates primary key statement for sqlCreateTable; overwrite this to implement DB specific syntax*/ protected function sqlCreateTablePrimaryKey(array $cols) { $ret="PRIMARY KEY("; @@ -155,7 +166,16 @@ abstract class DbEngine return $ret; } - /**creates a SQL92 statement for inserts*/ + /**creates a SQL92 statement for selects; overwrite this to implement DB specific syntax*/ + public function sqlSelect($table,$cols,$where,$orderby) + { + $query="SELECT $cols FROM ".$this->tableName($table); + if($where!="")$query.=" WHERE ".$where; + if($orderby!="")$query.=" ".$orderby; + return $query; + } + + /**creates a SQL92 statement for inserts; overwrite this to implement DB specific syntax*/ protected function sqlInsert($table,array $values) { global $dbScheme; @@ -185,13 +205,13 @@ abstract class DbEngine return $ret; } - /**creates a SQL92 statement for deletes*/ + /**creates a SQL92 statement for deletes; overwrite this to implement DB specific syntax*/ protected function sqlDelete($table,$where) { return "DELETE FROM ".$this->tableName($table)." WHERE ".$where; } - /**creates a SQL92 statement for updates*/ + /**creates a SQL92 statement for updates; overwrite this to implement DB specific syntax*/ protected function sqlUpdate($table,array $values,$where) { global $dbScheme; @@ -220,6 +240,24 @@ abstract class DbEngine return $ret; } + /**returns the SQL92 statement for beginning a transaction; overwrite this to implement DB specific syntax*/ + public function sqlBeginTransaction() + { + return "BEGIN TRANSACTION"; + } + + /**returns the SQL92 statement for committing a transaction; overwrite this to implement DB specific syntax*/ + public function sqlCommitTransaction() + { + return "COMMIT TRANSACTION"; + } + + /**returns the SQL92 statement for rolling a transaction back; overwrite this to implement DB specific syntax*/ + public function sqlRollbackTransaction() + { + return "ROLLBACK TRANSACTION"; + } + /**escapes integers; the default implementation just makes sure it is an int*/ public function escapeInt($i) { @@ -227,19 +265,38 @@ abstract class DbEngine return round($i + 0); } - /**escapes strings; the default uses addslashes and encloses the value in ''*/ + /**escapes strings; the default uses addslashes and encloses the value in ''; it is recommended to overwrite this with the proper escaping procedure for the target DB*/ public function escapeString($s) { if($s === false) return "NULL"; return "'".addslashes($s)."'"; } - /**escapes blobs; the default uses addslashes and encloses the value in ''*/ + /**escapes blobs; the default uses addslashes and encloses the value in ''; it is recommended to overwrite this with the proper escaping procedure for the target DB*/ public function escapeBlob($s) { if($s === false) return "NULL"; return "'".addslashes($s)."'"; } + + /**escapes a boolean value; the default translates 0, '0', 'f', 'false', 'no' to FALSE and numerics !=0, 't', 'true', 'yes' to TRUE; any other value (incl. the PHP constant false) is translated to NULL (exception: the constant true is treated as 'true')*/ + public function escapeBool($s) + { + if(is_numeric($s)){ + if(($s+0)!=0)return "TRUE"; + else return "FALSE"; + } + if($s===false)return "NULL"; + if($s===true)return "TRUE"; + switch(strtolower($s)){ + case "t":case "true":case "yes":case "y": + return "TRUE"; + case "f":case "false":case "n":case "no": + return "FALSE"; + default: + return "NULL"; + } + } /**returns a configuration setting*/ public function getConfig($key) @@ -275,27 +332,42 @@ abstract class DbEngine //iterate DB schema and create tables $tabs=$dbScheme->tableNames(); for($i=0;$icreateTable($tabs[$i],$dbScheme->tableDefinition($tabs[$i]))){ print("DB Error while creating ".$tabs[$i].": ".$this->lastError()."

\n"); print("Last statement was: ".$this->sqlCreateTable($tabs[$i],$dbScheme->tableDefinition($tabs[$i]))."

\n"); $this->rollbackTransaction(); die("Unable to create database."); } + //insert defaults + foreach($dbScheme->tableDefaults($tabs[$i]) as $def){ + $this->insert($tabs[$i],$def); + } } - //insert some defaults - $this->insert("config",array("ckey"=>"MagicSmokeVersion","cval"=>$this->needVersion())); - $this->insert("config",array("ckey"=>"ValidVouchers","cval"=>"10 20 25 50")); - $this->insert("config",array("ckey"=>"OrderStop","cval"=>"24")); - $this->insert("config",array("ckey"=>"SaleStop","cval"=>"0")); - $this->insert("config",array("ckey"=>"TicketIDChars","cval"=>"10")); - $this->insert("config",array("ckey"=>"VoucherIDChars","cval"=>"10")); - $this->insert("host",array("hostname"=>"_any")); - $this->insert("host",array("hostname"=>"_anon")); - $this->insert("host",array("hostname"=>"_online")); //close transaction $this->commitTransaction(); } + /**shows how the database would be created, used by admin.php only!!*/ + public function showCreateDb() + { + global $dbScheme; + print("

Database Creation SQL Script

\n
\n");
+		print(htmlentities($this->sqlBeginTransaction()).";\n");
+		//iterate DB schema and create tables
+		$tabs=$dbScheme->tableNames();
+		for($i=0;$isqlCreateTable($tabs[$i],$dbScheme->tableDefinition($tabs[$i]))).";\n");
+			//insert defaults
+			foreach($dbScheme->tableDefaults($tabs[$i]) as $def){
+				print(htmlentities($this->sqlInsert($tabs[$i],$def)).";\n");
+			}
+		}
+		//close transaction
+		print(htmlentities($this->sqlCommitTransaction()).";\n
\n");
+	}
+	
 	/**returns the error string of the last operation*/
 	public abstract function lastError();
 };
diff --git a/www/inc/db/db_mysql.php b/www/inc/db/db_mysql.php
index b4644ac..2539f83 100644
--- a/www/inc/db/db_mysql.php
+++ b/www/inc/db/db_mysql.php
@@ -70,24 +70,29 @@ class MysqlEngine extends DbEngine
 	}
 	public function beginTransaction()
 	{
-		return mysqli_query($this->dbhdl,"BEGIN");
+		return mysqli_query($this->dbhdl,$this->sqlBeginTransaction());
 	}
 	
 	public function commitTransaction()
 	{
-		return mysqli_query($this->dbhdl,"COMMIT");
+		return mysqli_query($this->dbhdl,$this->sqlCommitTransaction());
 	}
 	
 	public function rollbackTransaction()
 	{
-		return mysqli_query($this->dbhdl,"ROLLBACK");
+		return mysqli_query($this->dbhdl,$this->sqlRollbackTransaction());
 	}
 	
+	public function sqlBeginTransaction(){return "BEGIN";}
+	
+	public function sqlCommitTransaction(){return "COMMIT";}
+	
+	public function sqlRollbackTransaction(){return "ROLLBACK";}
+
+	
 	public function select($table,$cols,$where,$orderby="")
 	{
-		$query="SELECT $cols FROM ".$this->tableName($table);
-		if($where!="")$query.=" WHERE ".$where;
-		if($orderby!="")$query.=" ".$orderby;
+		$query=$this->sqlSelect($table,$cols,$where,$orderby);
 		$res=mysqli_query($this->dbhdl,$query);
 		if($res===false)return false;
 		$nr=mysqli_num_rows($res);
@@ -101,14 +106,22 @@ class MysqlEngine extends DbEngine
 	
 	protected function createTable($tn,$t)
 	{
+		$sql=$this->sqlCreateTable($tn,$t);
+		return mysqli_query($this->dbhdl,$sql);
+	}
+	
+	protected function sqlCreateTable($tn,$t)
+	{
 		$this->tableappend="";
-		$sql=$this->sqlCreateTable($tn,$t)." engine=".$this->engine." default charset=".$this->charset;
+		$sql=parent::sqlCreateTable($tn,$t)." engine=".$this->engine." default charset=".$this->charset;
 // 		print("
\n$sql\n
\n"); - return mysqli_query($this->dbhdl,$sql); + return $sql; } protected function createTableExtras($tablename,$table) { + //warning: this is rather dangerous, but safe at the moment since there is only + // one user of this function return $this->tableappend; } diff --git a/www/inc/db/db_scheme.php b/www/inc/db/db_scheme.php index 69443da..0f26e56 100644 --- a/www/inc/db/db_scheme.php +++ b/www/inc/db/db_scheme.php @@ -2,13 +2,29 @@ /**This class contains a high-level description of the database structure*/ class DbScheme { private static $scheme; + private static $preset; + private static $sversion; + function __construct() { + // //////////////////// + // version of this scheme + $this->sversion="00.02"; + + // //////////////////// //configuration $this->scheme["config"]=array( "ckey"=>array("string:32","primarykey"), "cval"=>array("string") ); + $this->preset["config"]=array( + array("ckey"=>"MagicSmokeVersion","cval"=>$this->sversion), + array("ckey"=>"ValidVouchers","cval"=>"10 20 25 50"), + array("ckey"=>"OrderStop","cval"=>"24"), + array("ckey"=>"SaleStop","cval"=>"0"), + array("ckey"=>"TicketIDChars","cval"=>"10"), + array("ckey"=>"VoucherIDChars","cval"=>"10") + ); // //////////////////// // Machine Interface Stuff @@ -19,6 +35,12 @@ class DbScheme { //if hostkey is NULL it is a special host (_any, _anon, _online) "hostkey"=>array("string") ); + $this->preset["host"]=array( + array("hostname"=>"_any"), + array("hostname"=>"_anon"), + array("hostname"=>"_online") + ); + //client users (ticket sellers, admins, etc.; for customers and web logins see below) $this->scheme["users"]=array( "uname" => array("string:64","primarykey"), @@ -55,7 +77,7 @@ class DbScheme { // ////////////////////// - // Shared Stuff + // Shared Stuff (web & GUI-client) //rooms $this->scheme["room"]=array( @@ -96,6 +118,15 @@ class DbScheme { "customerid" => array("int32","unique","foreignkey:customer:customerid"), "passwd" => array("string:64"),//salted SHA-1 hash of passwd ); + + //kinds of shipping that are available (templates) + $this->scheme["shipping"]=array( + "shipid" => array("seq32","primarykey"), + "cost" => array("int32","notnull"), //default cost of this shipping type + "canuseweb" => array("bool","default:false"), //is offered on web interface + "canallusers" => array("bool","default:true") //all GUI users may select it + ); + //orders by customers $this->scheme["order"]=array( "orderid" => array("seq32","primarykey"), @@ -115,7 +146,11 @@ class DbScheme { "comments" => array("text"), //how much has been paid already (including used vouchers) //this is for comparison with the price fields in ticket and voucher tables - "amountpaid" => array("int32") + "amountpaid" => array("int32"), + //shipping price + "shippingcosts" => array("int32","default:0"), + //pointer to shipping type (none per default, programmatic default is in config) + "shippingtype" => array("int32","null","foreignkey:shipping:shipid") ); //tickets $this->scheme["ticket"]=array( @@ -187,6 +222,9 @@ class DbScheme { ); } + /**return the version of this scheme*/ + public function version(){return $this->sversion;} + /**return the tables to be created in order*/ public function tableNames() { @@ -209,6 +247,13 @@ class DbScheme { return array_keys($this->scheme[$tab]); } + /**return default lines of the table for the initialization; returns empty array if there are none*/ + public function tableDefaults($tab) + { + if(isset($this->preset[$tab]))return $this->preset[$tab]; + else return array(); + } + /**return the type of a column, or false if it does not exist*/ public function columnType($tab,$col) {