manage refuse answer to licence manager
[brisk.git] / web / Obj / dbase_pgsql.phh
1 <?php
2   /*
3    *  brisk - dbase_pgsql.phh
4    *
5    *  Copyright (C) 2006-2012 Matteo Nastasi
6    *                          mailto: nastasi@alternativeoutput.it
7    *                                  matteo.nastasi@milug.org
8    *                          web: http://www.alternativeoutput.it
9    *
10    * This program is free software; you can redistribute it and/or modify
11    * it under the terms of the GNU General Public License as published by
12    * the Free Software Foundation; either version 2 of the License, or
13    * (at your option) any later version.
14    *
15    * This program is distributed in the hope that it will be useful, but
16    * WITHOUT ANY WARRANTY; without even the implied warranty of
17    * MERCHANTABLILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18    * General Public License for more details. You should have received a
19    * copy of the GNU General Public License along with this program; if
20    * not, write to the Free Software Foundation, Inc, 59 Temple Place -
21    * Suite 330, Boston, MA 02111-1307, USA.
22    *
23    */
24
25 require_once("${G_base}Obj/dbase_base.phh");
26
27 $escsql_from = array( "\\",   "'"   );
28 $escsql_to   = array( "\\\\", "\\'" );
29
30 function escsql($s)
31 {
32     GLOBAL $escsql_from, $escsql_to;
33
34     return str_replace($escsql_from, $escsql_to, $s);
35 }
36
37 class DBConn
38 {
39     static $dbcnnx = FALSE;
40     var $db = FALSE;
41
42     function DBConn()
43     {
44         $this->db = DBConn::$dbcnnx;
45     }
46
47     static function create()
48     {
49         GLOBAL $G_dbauth;
50
51         if (DBConn::$dbcnnx == FALSE) {
52             if (!(DBConn::$dbcnnx = @pg_connect ($G_dbauth, PGSQL_CONNECT_FORCE_NEW))) {
53                 return (FALSE);
54             }
55         }
56
57         $out = new DBConn();
58
59         return $out;
60     }
61
62     static function destroy()
63     {
64         if (DBConn::$dbcnnx != FALSE) {
65             DBConn::$dbcnnx = FALSE;
66             return (pg_close(DBConn::$dbcnnx));
67         }
68         return TRUE;
69     }
70
71     static function recover()
72     {
73         self::destroy();
74         return (self::create());
75     }
76
77     function db()
78     {
79         return ($this->db);
80     }
81 }
82
83 class BriskDB
84 {
85     var $dbconn;
86     var $item;
87     var $item_n;
88
89     function BriskDB($dbconn)
90     {
91         $this->dbconn = $dbconn;
92     }
93
94     static function create()
95     {
96         GLOBAL $DOCUMENT_ROOT, $G_dbpfx;
97
98         $ret = FALSE;
99
100         log_main("BriskDB create:start");
101
102         do {
103             if (($dbconn = DBConn::create()) == FALSE) {
104                 break;
105             }
106
107             $ret = new BriskDB($dbconn);
108         } while (0);
109
110         return ($ret);
111     }
112
113     function query($sql)
114     {
115         if (($res = pg_query($this->dbconn->db(), $sql)) == FALSE) {
116             // try to recover the connection
117             if (($this->dbconn = DBConn::recover()) == FALSE)
118                 return FALSE;
119             return (pg_query($this->dbconn->db(), $sql));
120         }
121
122         return ($res);
123     }
124
125     function users_load()
126     {
127     }
128
129     function login_exists($login)
130     {
131         GLOBAL $G_dbpfx;
132
133         /* check the existence of the nick in the BriskDB */
134         log_main("login_exists: ".$login);
135
136         $user_sql = sprintf("SELECT * FROM %susers WHERE login = lower('%s') AND (type & CAST (X'%08x' as integer)) = 0;",
137                             $G_dbpfx, escsql($login), USER_FLAG_TY_DISABLE);
138         if (($user_pg = $this->query($user_sql)) != FALSE)
139             if (pg_numrows($user_pg) == 1)
140                 return TRUE;
141
142         return FALSE;
143     }
144
145     function getrecord_bylogin($login) {
146         GLOBAL $G_dbpfx;
147
148         $user_sql = sprintf("SELECT * FROM %susers WHERE login = lower('%s') AND (type & CAST (X'%08x' as integer)) = 0;",  $G_dbpfx, escsql($login), USER_FLAG_TY_DISABLE);
149         if (($user_pg  = $this->query($user_sql)) == FALSE) {
150             return FALSE;
151         }
152         if (pg_numrows($user_pg) != 1)
153             return FALSE;
154
155         $user_obj = pg_fetch_object($user_pg, 0);
156
157         return ($user_obj);
158     }
159
160     function user_update_login_time($code, $lintm)
161     {
162         GLOBAL $G_dbpfx;
163
164         $user_sql = sprintf("UPDATE %susers SET (lintm) = (date 'epoch' + %d * INTERVAL '1 second') WHERE code = %d;", $G_dbpfx, $lintm, $code);
165
166         if ( ! (($user_pg  = $this->query($user_sql)) != FALSE && pg_affected_rows($user_pg) == 1) ) {
167              return FALSE;
168         }
169
170         return TRUE;
171     }
172
173     function user_prefs_update($code, $flags, $supp_comp)
174     {
175         GLOBAL $G_dbpfx;
176
177         $user_sql = sprintf("UPDATE %susers SET (type, supp_comp) = (%d, '%s') WHERE code = %d;",
178                             $G_dbpfx, $flags, escsql($supp_comp), $code);
179         fprintf(STDERR, "REQUEST [%s]\n", $user_sql);
180         if ( ! (($user_pg  = $this->query($user_sql)) != FALSE && pg_affected_rows($user_pg) == 1) ) {
181              return FALSE;
182         }
183         fprintf(STDERR, "REQUEST GOOD [%s]\n", $user_sql);
184
185         return TRUE;
186     }
187
188     function user_state_update($code, $flags, $disa_reas)
189     {
190         GLOBAL $G_dbpfx;
191
192         $user_sql = sprintf("UPDATE %susers SET (type, disa_reas) = (%d, %d) WHERE code = %d;",
193                             $G_dbpfx, $flags, $disa_reas, $code);
194         fprintf(STDERR, "REQUEST [%s]\n", $user_sql);
195         if ( ! (($user_pg  = $this->query($user_sql)) != FALSE && pg_affected_rows($user_pg) == 1) ) {
196              return FALSE;
197         }
198         fprintf(STDERR, "REQUEST GOOD [%s]\n", $user_sql);
199
200         return TRUE;
201     }
202
203     function user_licence_update($code, $lice_vers)
204     {
205         GLOBAL $G_dbpfx;
206
207         $user_sql = sprintf("UPDATE %susers SET (lice_vers) = ('%s') WHERE code = %d;",
208                             $G_dbpfx, escsql($lice_vers), $code);
209         fprintf(STDERR, "REQUEST [%s]\n", $user_sql);
210         if ( ! (($user_pg  = $this->query($user_sql)) != FALSE && pg_affected_rows($user_pg) == 1) ) {
211              return FALSE;
212         }
213         fprintf(STDERR, "REQUEST GOOD [%s]\n", $user_sql);
214
215         return TRUE;
216     }
217
218     /*
219       if success return a LoginDBItem object
220      */
221     function login_verify($login, $pass)
222     {
223         GLOBAL $G_dbpfx;
224
225         $ret = FALSE;
226
227         log_main("login_verify: ".$login);
228
229         //O /* check the existence of the nick in the BriskDB */
230         //O for ($i = 0 ; $i < $this->item_n ; $i++) {
231         //O log_main("login_verify: BEGIN");
232
233         if (($user_obj = $this->getrecord_bylogin($login)) == FALSE) {
234             return FALSE;
235         }
236
237         log_main("login[".$user_obj->code."]: ".$user_obj->login);
238
239         /* if it exists check for a valid challenge */
240         if (($a_sem = Challenges::lock_data(TRUE)) != FALSE) {
241             if (($chals = &Challenges::load_data()) != FALSE) {
242                 for ($e = 0 ; $e < $chals->item_n ; $e++) {
243                     log_main("challenge[".$e."]: ".$chals->item[$e]->login);
244                     if (strcmp($login, $chals->item[$e]->login) == 0) {
245                         log_main("login_verify [".$pass."] with [".md5($chals->item[$e]->token.$user_obj->pass)."]");
246
247                         if (strcmp($pass, md5($chals->item[$e]->token.$user_obj->pass)) == 0) {
248                             log_main("login_verify SUCCESS for ".$login);
249
250                             $chals->rem($login);
251                             $this->user_update_login_time($user_obj->code, time());
252                             $ret = LoginDBItem::LoginDBItemFromRecord($user_obj);
253                             break;
254                         }
255                     }
256                 } // end for ($e = 0 ...
257             }
258
259             if ($chals->ismod()) {
260                 Challenges::save_data(&$chals);
261             }
262
263             Challenges::unlock_data($a_sem);
264         }
265         //O break;
266         // O } //  if (strcasecmp($this->item[$i]->login, ...
267         //O }
268
269         return ($ret);
270     }
271
272     function getitem_bylogin($login, &$id) {
273         $ret = FALSE;
274         $id = -1;
275
276         log_main("getitem_bylogin: ".$login);
277
278         if (($user_obj = $this->getrecord_bylogin($login)) == FALSE)
279             return $ret;
280
281         $id = $user_obj->code;
282         return (LoginDBItem::LoginDBItemFromRecord($user_obj));
283     }
284
285     // TODO FOR DB
286     function getmail($login)
287     {
288         log_main("getmail");
289
290         if (($ret = $this->getrecord_bylogin($login)) == FALSE)
291             return FALSE;
292
293         return ($ret->email);
294     }
295
296     function addusers_from_olddb($olddb, &$cont)
297     {
298         GLOBAL $G_dbpfx;
299
300         for ($i = 0 ; $i < $olddb->count() ; $i++) {
301             $user_sql = sprintf("INSERT INTO %susers ( login, pass, email, type) VALUES ('%s', '%s', '%s', %d);",
302                                 $G_dbpfx, escsql(strtolower($olddb->item[$i]->login)), escsql($olddb->item[$i]->pass),
303                                 escsql($olddb->item[$i]->email), $olddb->item[$i]->type & USER_FLAG_TY_ALL);
304
305             if ( ! (($user_pg  = $this->query($user_sql)) != FALSE && pg_affected_rows($user_pg) == 1) ) {
306                 $cont .= sprintf("ERROR IN LINE: %s\n", eschtml($user_sql));
307
308                 return FALSE;
309             }
310         }
311         return TRUE;
312     }
313
314     function getdbconn()
315     {
316         return ($this->dbconn);
317     }
318
319     // return array of array('code', 'login' [, 'first', 'last', 'tidx']) ordered by table position
320     function users_get($match_code, $with_minmaxtidx, $is_newmatch)
321     {
322         GLOBAL $G_dbpfx;
323
324         if ($is_newmatch) { // is new
325             $usr_sql = sprintf("SELECT u.code AS code, u.login AS login%s
326                                   FROM %sbin5_matches AS m, %sbin5_games AS g, %sbin5_points AS p,
327                                        %susers AS u, %sbin5_table_orders AS o
328                                   WHERE m.code = g.mcode AND g.code = p.gcode AND u.code = p.ucode
329                                        AND m.code = o.mcode AND u.code = o.ucode AND m.code = %d
330                                   GROUP BY u.code, u.login%s, o.pos
331                                   ORDER BY o.pos;",
332                                ($with_minmaxtidx ? ", min(g.tstamp) AS first, max(g.tstamp) AS last, m.tidx AS tidx" : ""),
333                                $G_dbpfx, $G_dbpfx, $G_dbpfx, $G_dbpfx, $G_dbpfx, $match_code,
334                                ($with_minmaxtidx ? ", m.tidx" : ""));
335         }
336         else { // is old
337             $usr_sql = sprintf("SELECT u.code AS code, u.login AS login%s
338                                   FROM %sbin5_matches AS m, %sbin5_games AS g, %sbin5_points AS p, %susers AS u
339                                   WHERE m.code = g.mcode AND g.code = p.gcode AND u.code = p.ucode AND m.code = %d
340                                   GROUP BY u.code, u.login%s;",
341                                ($with_minmaxtidx ? ", min(g.tstamp) AS first, max(g.tstamp) AS last, m.tidx AS tidx" : ""),
342                                $G_dbpfx, $G_dbpfx, $G_dbpfx, $G_dbpfx, $match_code,
343                                ($with_minmaxtidx ? ", m.tidx" : ""));
344         }
345
346         if (($usr_pg  = pg_query($this->dbconn->db(), $usr_sql)) == FALSE ) {
347             log_crit(sprintf("%s::%s: pg_query usr_sql failed [%s]", __CLASS__, __FUNCTION__, $usr_sql));
348             return (FALSE);
349         }
350         $usr_n = pg_numrows($usr_pg);
351         if ($usr_n != BIN5_PLAYERS_N) {
352             log_crit(sprintf("%s::%s: wrong number of players [%s] %d", __CLASS__, __FUNCTION__, $usr_sql, $usr_n));
353             return (FALSE);
354         }
355         $users = array();
356
357         if ($with_minmaxtidx)
358             $fields = array('code', 'login', 'first', 'last', 'tidx');
359         else
360             $fields = array('code', 'login');
361
362         for ($u = 0 ; $u < $usr_n ; $u++) {
363             $usr_obj = pg_fetch_object($usr_pg, $u);
364             $users[$u] = array();
365             foreach($fields as $field) {
366                 $users[$u][$field] = $usr_obj->$field;
367             }
368         }
369         return ($users);
370     }
371
372     // out: tab->{points,points_n,old_reason}, in: tab->ttok
373     function match_continue($match_code, $table, $tidx)
374     {
375         GLOBAL $G_dbpfx;
376
377         if (($users = $this->users_get($match_code, FALSE /*without minmaxidx*/, TRUE /*new game*/)) == FALSE) {
378             log_crit(sprintf("%s::%s: retrieve users fails", __CLASS__, __FUNCTION__));
379             return (FALSE);
380         }
381
382         $num_sql = sprintf("SELECT count(*) AS points_n FROM %sbin5_games WHERE mcode = %d;", $G_dbpfx, $match_code);
383         if (($num_pg  = $this->query($num_sql)) == FALSE || pg_numrows($num_pg) != 1) {
384             log_crit(sprintf("%s::%s: get games number fails", __CLASS__, __FUNCTION__));
385             return (FALSE);
386         }
387         $num_obj = pg_fetch_object($num_pg, 0);
388         $table->points_n = $num_obj->points_n;
389
390         $tot_sql = sprintf("SELECT sum(p.pts) AS pts
391                             FROM %sbin5_games AS g, %sbin5_points AS p, %susers AS u,
392                                  %sbin5_table_orders AS o
393                             WHERE g.mcode = %d AND g.code = p.gcode AND p.ucode = u.code
394                                   AND p.ucode = o.ucode AND g.mcode = o.mcode
395                             GROUP BY p.ucode, o.pos
396                             ORDER BY o.pos;",
397                            $G_dbpfx, $G_dbpfx, $G_dbpfx, $G_dbpfx, $match_code);
398         if (($tot_pg  = pg_query($this->dbconn->db(), $tot_sql)) == FALSE
399             || pg_numrows($tot_pg) != BIN5_PLAYERS_N) {
400             log_crit(sprintf("%s::%s: get games totals fails", __CLASS__, __FUNCTION__));
401             return(FALSE);
402         }
403
404         $u = 0;
405         foreach ($users as $user) {
406             $pts_sql = sprintf("SELECT p.pts AS pts
407                                     FROM %sbin5_points as p, %sbin5_games as g
408                                     WHERE p.gcode = g.code AND g.mcode = %d AND p.ucode = %d
409                                     ORDER BY g.code ASC
410                                     LIMIT %d OFFSET %d;",
411                                $G_dbpfx, $G_dbpfx, $match_code, $user['code'],
412                                MAX_POINTS,
413                                ($num_obj->points_n < MAX_POINTS ? 0 : $num_obj->points_n - MAX_POINTS));
414
415             // points of the match for each user
416             if (($pts_pg  = $this->query($pts_sql)) == FALSE) {
417                 log_crit(sprintf("%s::%s: get points fails", __CLASS__, __FUNCTION__));
418                 return (FALSE);
419             }
420             $pts_n = pg_numrows($pts_pg);
421             if ($pts_n > $table->points_n) {
422                 // inconsistent scenario number of points great than number of games
423                 log_crit(sprintf("%s::%s: number of points great than number of games", __CLASS__, __FUNCTION__));
424                 return (FALSE);
425             }
426             for ($i = 0 , $ct = $table->points_n - $pts_n; $ct < $table->points_n ; $ct++, $i++) {
427                 $pts_obj = pg_fetch_object($pts_pg, $i);
428                 $table->points[$ct % MAX_POINTS][$u] = $pts_obj->pts;
429             }
430             $tot_obj = pg_fetch_object($tot_pg, $u);
431             $table->total[$u] = $tot_obj->pts;
432
433             $u++;
434         }
435
436         $gam_sql = sprintf("SELECT * FROM %sbin5_games WHERE mcode = %d ORDER BY code DESC LIMIT 1;", $G_dbpfx, $match_code);
437         if (($gam_pg  = $this->query($gam_sql)) == FALSE || pg_numrows($gam_pg) != 1) {
438             log_crit(sprintf("%s::%s: get last game fails", __CLASS__, __FUNCTION__));
439             return (FALSE);
440         }
441         $gam_obj = pg_fetch_object($gam_pg, 0);
442
443         $table->old_reason = game_description($gam_obj->act, 'html', $gam_obj->mult,
444                                               $gam_obj->asta_win, ($gam_obj->asta_win != -1 ?
445                                                                    $users[$gam_obj->asta_win]['login'] : ""),
446                                               $gam_obj->friend, ($gam_obj->friend != -1 ?
447                                                                  $users[$gam_obj->friend]['login'] : ""),
448                                               $gam_obj->pnt, $gam_obj->asta_pnt);
449
450         return (TRUE);
451     }
452
453     function match_order_get(&$match_data, $match_code, $exp_num)
454     {
455         GLOBAL $G_dbpfx;
456
457         $ord_sql = sprintf("SELECT ucode FROM %sbin5_table_orders WHERE mcode = %d ORDER BY pos ASC;",
458                            $G_dbpfx, $match_code);
459
460         if (($ord_pg  = $this->query($ord_sql)) == FALSE || pg_numrows($ord_pg) != $exp_num) {
461             log_crit(sprintf("%s: fails for id or users number", __FUNCTION__));
462             return (FALSE);
463         }
464
465         $ucodes = array();
466         for ($i = 0 ; $i < $exp_num ; $i++) {
467             $ord_obj = pg_fetch_object($ord_pg, $i);
468             $ucodes[$i] = $ord_obj->ucode;
469         }
470
471         if ($match_data !== NULL) {
472             $mtdt_sql = sprintf("SELECT * FROM %sbin5_matches WHERE code = %d;",
473                                 $G_dbpfx, $match_code);
474
475             if (($mtdt_pg  = $this->query($mtdt_sql)) == FALSE || pg_numrows($mtdt_pg) != 1) {
476                 log_crit(sprintf("%s: fails retrieve match_data values [%d]", __FUNCTION__, $match_code));
477                 return (FALSE);
478             }
479
480             $mtdt_obj = pg_fetch_object($mtdt_pg, 0);
481
482             foreach (array('ttok', 'tidx', 'mult_next', 'mazzo_next', 'tcode') as $match_name) {
483                 $match_data[$match_name] = $mtdt_obj->$match_name;
484             }
485         }
486
487         return ($ucodes);
488     }
489
490     //   ttok   text UNIQUE,
491     //   tidx
492     function bin5_points_save($date, $table, $tidx, $action, $ucodes, $pts)
493     {
494         GLOBAL $G_dbpfx;
495         $sql_ttok = escsql($table->table_token);
496
497         $is_trans = FALSE;
498         $ret = FALSE;
499
500         $n = count($ucodes);
501         /* check the existence of the nick in the BriskDB */
502         log_main("bin5_points_save: ");
503
504         do {
505             if ($this->query("BEGIN") == FALSE) {
506                 break;
507             }
508             $is_trans = TRUE;
509
510             /*
511              * matches management
512              */
513             $mtc_sql = sprintf("UPDATE %sbin5_matches SET (mazzo_next, mult_next) = (%d, %d) WHERE ttok = '%s' RETURNING *;",
514                                $G_dbpfx, $table->mazzo, $table->mult, $sql_ttok);
515             if (($mtc_pg  = $this->query($mtc_sql)) == FALSE || pg_numrows($mtc_pg) != 1) {
516
517                 // match not exists, insert it
518                 $mtc_sql = sprintf("INSERT INTO %sbin5_matches (ttok, tidx, mazzo_next, mult_next) VALUES ('%s', %d, %d, %d) RETURNING *;",
519                                    $G_dbpfx, $sql_ttok, $tidx, $table->mazzo, $table->mult);
520                 if (($mtc_pg  = $this->query($mtc_sql)) == FALSE || pg_affected_rows($mtc_pg) != 1) {
521                     log_crit(sprintf("bin5_points_save: failed at insert match [%s]", $mtc_sql));
522                     break;
523                 }
524                 $mtc_obj = pg_fetch_object($mtc_pg, 0);
525
526                 for ($i = 0 ; $i < $n ; $i++) {
527                     $ord_sql = sprintf("INSERT INTO %sbin5_table_orders (mcode, ucode, pos) VALUES (%d, %d, %d);",
528                                        $G_dbpfx, $mtc_obj->code, $ucodes[$i], $i);
529                     if (($ord_pg = $this->query($ord_sql)) == FALSE || pg_affected_rows($ord_pg) != 1 ) {
530                         log_crit(sprintf("bin5_points_save: failed at insert table order [%s]", $ord_sql));
531                         break;
532                     }
533                 }
534                 if ($i < $n)
535                     break;
536             }
537             else {
538                 $mtc_obj = pg_fetch_object($mtc_pg,0);
539             }
540
541             /*
542              * games management
543              */
544             $gam_sql = sprintf("INSERT INTO %sbin5_games (mcode, tstamp, act, asta_pnt, pnt, asta_win, friend, mazzo, mult)
545                                                VALUES (%d, to_timestamp(%d), %d, %d, %d, %d, %d, %d, %d) RETURNING *;",
546                                $G_dbpfx, $mtc_obj->code, $date, $action,
547                                $table->old_asta_pnt, $table->old_pnt,
548                                $table->old_asta_win,
549                                $table->old_friend,
550                                $table->old_mazzo, $table->old_mult);
551             if (($gam_pg  = $this->query($gam_sql)) == FALSE || pg_affected_rows($gam_pg) != 1) {
552                 log_crit(sprintf("bin5_points_save: failed at insert game [%s]", $gam_sql));
553                 break;
554             }
555
556             $gam_obj = pg_fetch_object($gam_pg,0);
557
558             /*
559              * points management
560              */
561             for ($i = 0 ; $i < $n ; $i++) {
562                 /* put points */
563                 $pts_sql = sprintf("INSERT INTO %sbin5_points (gcode, ucode, pts)
564                                                VALUES (%d, %d, %d);",
565                                    $G_dbpfx, $gam_obj->code, $ucodes[$i], $pts[$i]);
566                 if (($pts_pg  = $this->query($pts_sql)) == FALSE || pg_affected_rows($pts_pg) != 1) {
567                     log_crit(sprintf("bin5_points_save: failed at insert point [%s]", $pts_sql));
568                     break;
569                 }
570             }
571             if ($i < $n)
572                 break;
573
574             if ($this->query("COMMIT") == FALSE) {
575                 break;
576             }
577
578             $is_trans = FALSE;
579
580             $table->match_id = $mtc_obj->code;
581             $ret = TRUE;
582         } while (0);
583
584         if ($is_trans)
585             $this->query("ROLLBACK");
586
587         return $ret;
588     }
589
590 } // End class BriskDB
591
592 class LoginDBOld
593 {
594     var $item;
595     var $item_n;
596
597     function LoginDBOld($filename)
598     {
599         GLOBAL $DOCUMENT_ROOT;
600         log_main("LoginDBOld create:start");
601
602         if (file_exists("$DOCUMENT_ROOT/Etc/".$filename)) {
603             require("$DOCUMENT_ROOT/Etc/".$filename);
604         }
605         else {
606             return (FALSE);
607         }
608         $this->item_n = count($this->item);
609         log_main("LoginDBOld create:end");
610     }
611
612     function count()
613     {
614         return ($this->item_n);
615     }
616
617 } // End class LoginDBOld
618
619 ?>