]> mj.ucw.cz Git - pciids.git/blob - PciIds/DBQ.pm
Update to admin interface
[pciids.git] / PciIds / DBQ.pm
1 #       PciIds web database
2 #       Copyright (C) 2008 Michal Vaner (vorner@ucw.cz)
3 #
4 #       This program is free software; you can redistribute it and/or modify
5 #       it under the terms of the GNU General Public License as published by
6 #       he Free Software Foundation; either version 2 of the License, or
7 #       (at your option) any later version.
8 #
9 #       This program is distributed in the hope that it will be useful,
10 #       but WITHOUT ANY WARRANTY; without even the implied warranty of
11 #       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 #
13 #       GNU General Public License for more details.
14 #
15 #       You should have received a copy of the GNU General Public License
16 #       along with this program; if not, write to the Free Software
17 #       Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19 package PciIds::DBQ;
20 use strict;
21 use warnings;
22 use base 'PciIds::DBQAny';
23
24 my $adminDumpSql = 'SELECT DISTINCT
25                         locations.id, locations.name, locations.note, locations.mainhistory, musers.email, musers.login, main.discussion, main.time,
26                         history.id, history.discussion, history.nodename, history.nodenote, users.email, users.login, history.time, history.seen
27                 FROM
28                         locations INNER JOIN history ON history.location = locations.id
29                         LEFT OUTER JOIN users ON history.owner = users.id
30                         LEFT OUTER JOIN history AS main ON locations.mainhistory = main.id
31                         LEFT OUTER JOIN users AS musers ON main.owner = musers.id
32                         LEFT OUTER JOIN history AS test ON test.location = locations.id
33                 WHERE test.seen = "0" AND locations.id LIKE ?
34                 ORDER BY locations.id, history.id
35                 LIMIT ';
36
37 sub new( $ ) {
38         my( $dbh ) = @_;
39         my $node = 'SELECT id, name, note, mainhistory FROM locations WHERE parent = ? ORDER BY ';
40         my $noder = 'SELECT id, name, note, mainhistory FROM locations WHERE parent = ? AND id LIKE ? ORDER BY ';
41         return bless PciIds::DBQAny::new( $dbh, {
42                 'nodes-id' => $node.'id',
43                 'nodes-name' => $node.'name',
44                 'nodes-rid' => $node.'id DESC',
45                 'nodes-rname' => $node.'name DESC',
46                 'nodes-id-r' => $noder.'id',
47                 'nodes-name-r' => $noder.'name',
48                 'nodes-rid-r' => $noder.'id DESC',
49                 'nodes-rname-r' => $noder.'name DESC',
50                 'item' => 'SELECT parent, name, note, mainhistory FROM locations WHERE id = ?',
51                 'login' => 'SELECT id FROM users WHERE login = ?',
52                 'email' => 'SELECT id FROM users WHERE email = ?',
53                 'adduser' => 'INSERT INTO users (login, email, passwd) VALUES(?, ?, ?)',
54                 'adduser-null' => 'INSERT users (email, passwd) VALUES(?, ?)',
55                 'loginfomail' => 'SELECT id, passwd, logtime, lastlog FROM users WHERE email = ?',
56                 'loginfoname' => 'SELECT id, passwd, logtime, lastlog, email FROM users WHERE login = ?',
57                 'resetinfo' => 'SELECT id, login, passwd FROM users WHERE email = ?',
58                 'changepasswd' => 'UPDATE users SET passwd = ? WHERE id = ?',
59                 'setlastlog' => 'UPDATE users SET logtime = now(), lastlog = ? WHERE id = ?',
60                 'rights' => 'SELECT rightId FROM rights WHERE userId = ?',
61                 'newitem' => 'INSERT INTO locations (id, parent) VALUES(?, ?)',
62                 'newhistory' => 'INSERT INTO history (location, owner, discussion, nodename, nodenote) VALUES(?, ?, ?, ?, ?)',
63                 'history' => 'SELECT history.id, history.discussion, history.time, history.nodename, history.nodenote, history.seen, users.login, users.email FROM history LEFT OUTER JOIN users ON history.owner = users.id WHERE history.location = ? ORDER BY history.time',
64                 'admindump' => "$adminDumpSql 100",#Dumps new discussion submits with their senders and corresponding main history and names
65                 'delete-hist' => 'DELETE FROM history WHERE id = ?',
66                 'mark-checked' => 'UPDATE history SET seen = 1 WHERE id = ?',
67                 'delete-item' => 'DELETE FROM locations WHERE id = ?',
68                 'set-mainhist' => 'UPDATE locations SET
69                                 mainhistory = ?,
70                                 name = ( SELECT nodename FROM history WHERE id = ? ),
71                                 note = ( SELECT nodenote FROM history WHERE id = ? )
72                         WHERE
73                                 id = ?',
74                 'profiledata' => 'SELECT email, xmpp, login, mailgather, xmppgather FROM users WHERE id = ?',
75                 'pushprofile' => 'UPDATE users SET xmpp = ?, login = ?, mailgather = ?, xmppgather = ? WHERE id = ?',
76                 'setemail' => 'UPDATE users SET email = ?, passwd = ? WHERE id = ?',
77                 'notifuser' => 'SELECT location, recursive FROM notifications WHERE user = ? ORDER BY location',
78                 'notifdata' => 'SELECT recursive, type, notification FROM notifications WHERE user = ? AND location = ?',
79                 'drop-notif' => 'DELETE FROM notifications WHERE user = ? AND location = ?',
80                 'new-notif' => 'INSERT INTO notifications (user, location, recursive, type, notification) VALUES (?, ?, ?, ?, ?)',
81                 'notify' => 'INSERT INTO pending (user, history, notification, reason) SELECT DISTINCT user, ?, ?, ? FROM notifications WHERE ( notification = 2 OR notification = ? ) AND type <= ? AND ( location = ? OR ( recursive = 1 AND SUBSTR( ?, 1, LENGTH( location ) ) = location ) )',
82                 'newtime-mail' => 'UPDATE users SET nextmail = FROM_UNIXTIME( UNIX_TIMESTAMP( NOW() ) + 60 * mailgather ) WHERE nextmail < NOW() AND EXISTS ( SELECT 1 FROM notifications WHERE ( notification = 0 OR notification = 2 ) AND type <= ? AND ( location = ? OR ( recursive = 1 AND SUBSTR( ?, 1, LENGTH( location ) ) = location ) ) )',
83                 'newtime-xmpp' => 'UPDATE users SET nextxmpp = FROM_UNIXTIME( UNIX_TIMESTAMP( NOW() ) + 60 * xmppgather ) WHERE nextxmpp < NOW() AND EXISTS ( SELECT 1 FROM notifications WHERE ( notification = 1 OR notification = 2 ) AND type <= ? AND ( location = ? OR ( recursive = 1 AND SUBSTR( ?, 1, LENGTH( location ) ) = location ) ) )',
84                 'mailout' => 'SELECT
85                                 pending.user, users.email,
86                                 pending.reason, history.discussion, history.nodename, history.nodenote, history.time,
87                                 auth.login, history.location, locations.name, locations.note
88                         FROM
89                                 pending
90                                 INNER JOIN users ON users.id = pending.user
91                                 INNER JOIN history ON history.id = pending.history
92                                 INNER JOIN locations ON history.location = locations.id
93                                 INNER JOIN users AS auth ON auth.id = history.owner
94                         WHERE
95                                 pending.notification = 0
96                                 AND users.nextmail <= ?
97                         ORDER BY
98                                 pending.user, pending.reason, history.time, history.location',
99                 'xmppout' => 'SELECT
100                                 pending.user, users.xmpp,
101                                 pending.reason, history.discussion, history.nodename, history.nodenote, history.time,
102                                 auth.login, history.location, locations.name, locations.note
103                         FROM
104                                 pending
105                                 INNER JOIN users ON users.id = pending.user
106                                 INNER JOIN history ON history.id = pending.history
107                                 INNER JOIN locations ON history.location = locations.id
108                                 INNER JOIN users AS auth ON auth.id = history.owner
109                         WHERE
110                                 pending.notification = 1
111                                 AND users.nextxmpp <= ?
112                                 AND users.xmpp IS NOT NULL
113                         ORDER BY
114                                 pending.user, pending.reason, history.time, history.location',
115                 'dropnotifsxmpp' => 'DELETE FROM pending WHERE notification = 1 AND EXISTS ( SELECT 1 FROM users WHERE users.id = pending.user AND nextxmpp <= ? )',
116                 'dropnotifsmail' => 'DELETE FROM pending WHERE notification = 0 AND EXISTS ( SELECT 1 FROM users WHERE users.id = pending.user AND nextmail <= ? )',
117                 'time' => 'SELECT NOW()',
118                 'searchname' => 'SELECT l.id, l.name, p.name FROM locations AS l JOIN locations AS p ON l.parent = p.id WHERE l.name LIKE ? ORDER BY LENGTH(l.id), l.id',
119                 'searchlocalname' => 'SELECT l.id, l.name, p.name FROM locations AS l JOIN locations AS p ON l.parent = p.id WHERE l.name LIKE ? AND l.id LIKE ? ORDER BY LENGTH(l.id), l.id',
120                 'hasChildren' => 'SELECT DISTINCT 1 FROM locations WHERE parent = ?',
121                 'hasMain' => 'SELECT DISTINCT 1 FROM locations WHERE id = ? AND mainhistory IS NOT NULL',
122                 'notif-exists' => 'SELECT DISTINCT 1 FROM notifications WHERE user = ? AND ( location = ? OR ( recursive = 1 AND type <= 1 AND SUBSTR( ?, 1, LENGTH( location ) ) = location ) )',
123                 'itemname' => 'SELECT name FROM locations WHERE id = ?',
124                 'admincount' => 'SELECT COUNT( DISTINCT location ) FROM history WHERE seen = 0 AND location LIKE ?'
125         } );
126 }
127
128 sub hasChildren( $$ ) {
129         my( $self, $parent ) = @_;
130         return scalar @{$self->query( 'hasChildren', [ $parent ] )};
131 }
132
133 sub hasMain( $$ ) {
134         my( $self, $id ) = @_;
135         return scalar @{$self->query( 'hasMain', [ $id ] )};
136 }
137
138 my %sorts = ( 'id' => 1, 'rid' => 1, 'name' => 1, 'rname' => 1 );
139
140 sub nodes( $$$$ ) {
141         my( $self, $parent, $args, $restrict ) = @_;
142         my $q = 'id';
143         $q = $args->{'sort'} if( defined( $args->{'sort'} ) && defined( $sorts{$args->{'sort'}} ) );
144         if( defined( $restrict ) && ( $restrict ne "" ) ) {
145                 return $self->query( 'nodes-'.$q.'-r', [ $parent, $parent.'/'.$restrict.'%' ] );
146         } else {
147                 return $self->query( 'nodes-'.$q, [ $parent ] );
148         }
149 }
150
151 sub item( $$ ) {
152         my( $self, $id ) = @_;
153         my $result = $self->query( "item", [ $id ] );
154         if( scalar @{$result} ) {
155                 return $result->[ 0 ];
156         } else {
157                 return undef;
158         }
159 }
160
161 sub hasLogin( $$ ) {
162         my( $self, $login ) = @_;
163         my $result = $self->query( 'login', [ $login ] );
164         return scalar @{$result};
165 }
166
167 sub hasEmail( $$ ) {
168         my( $self, $email ) = @_;
169         my $result = $self->query( 'email', [ $email ] );
170         return scalar @{$result};
171 }
172
173 sub addUser( $$$$ ) {
174         my( $self, $login, $email, $passwd ) = @_;
175         eval {
176                 if( ( defined $login ) && ( $login ne '' ) ) {
177                         $self->command( 'adduser', [ $login, $email, $passwd ] );
178                 } else {
179                         $self->command( 'adduser-null', [ $email, $passwd ] );
180                 }
181         };
182         if( $@ ) {
183                 return 0;
184         } else {
185                 return $self->last();
186         }
187 }
188
189 sub getLogInfo( $$ ) {
190         my( $self, $info ) = @_;
191         my $data;
192         if( $info =~ /@/ ) {#An email address
193                 $data = $self->query( 'loginfomail', [ $info ] );
194         } else {
195                 $data = $self->query( 'loginfoname', [ $info ] );
196         }
197         if( scalar @{$data} ) {
198                 my( $id, $passwd, $logtime, $lastlog, $email ) = @{$data->[ 0 ]};
199                 my $logstring;
200                 $logstring = "Last logged from $lastlog at $logtime" if( defined $logtime && defined $lastlog );
201                 $email = $info if( $info =~ /@/ );
202                 return( $id, $passwd, $email, $logstring );
203         } else {
204                 return undef;
205         }
206 }
207
208 sub rights( $$ ) {
209         my( $self, $id ) = @_;
210         return $self->query( 'rights', [ $id ] );
211 }
212
213 sub setLastLog( $$$ ) {
214         my( $self, $id, $from ) = @_;
215         $self->command( 'setlastlog', [ $from, $id ] );
216 }
217
218 sub history( $$ ) {
219         my( $self, $addr ) = @_;
220         return $self->query( 'history', [ $addr ] );
221 }
222
223 sub spaceNorm( $ ) {
224         $_ = shift;
225         return undef unless defined $_;
226         s/[ \t]+/ /g;
227         s/^\s//;
228         s/\s$//;
229         s/\r//;
230         return $_;
231 }
232
233 sub submitItem( $$$ ) {
234         my( $self, $data, $auth ) = @_;
235         my( $addr ) = ( $data->{'address'} );
236         foreach( @{$addr->addressDeps()} ) {
237                 my( $dep, $error ) = @{$_};
238                 return ( $error, undef ) unless defined $self->item( $dep->get(), 0 );
239         }
240         return( 'exists', undef ) if( defined( $self->item( $addr->get(), 0 ) ) );
241         eval {
242                 $self->command( 'newitem', [ $addr->get(), $addr->parent()->get() ] );
243                 $self->command( 'newhistory', [ $addr->get(), $auth->{'authid'}, spaceNorm( $data->{'discussion'} ), spaceNorm( $data->{'name'} ), spaceNorm( $data->{'note'} ) ] );
244         };
245         if( $@ ) {
246                 $self->rollback();
247                 return( 'internal: '.$@, undef );
248         }
249         return( '', $self->last() );
250 }
251
252 sub submitHistory( $$$$ ) {
253         my( $self, $data, $auth, $address ) = @_;
254         if( $data->{'delete'} ) {
255                 $self->command( 'newhistory', [ $address->get(), $auth->{'authid'}, spaceNorm( $data->{'text'} ), '', '' ], 1 );
256         } else {
257                 $data->{'name'} = undef if defined $data->{'name'} && $data->{'name'} eq '';
258                 $self->command( 'newhistory', [ $address->get(), $auth->{'authid'}, spaceNorm( $data->{'text'} ), spaceNorm( $data->{'name'} ), spaceNorm( $data->{'note'} ) ], 1 );
259         }
260         return $self->last();
261 }
262
263 sub adminDump( $$$ ) {
264         my( $self, $prefix, $limit ) = @_;
265         if( $limit ) {
266                 $limit = int( $limit * 1.2 );
267                 my $q = $self->{'dbh'}->prepare( "$adminDumpSql $limit" );
268                 $q->execute( "$prefix%" );
269                 my @result = @{$q->fetchall_arrayref()};#Copy the array, finish() deletes the content
270                 $q->finish();
271                 return \@result;
272         } else {
273                 return $self->query( 'admindump', [ "$prefix%" ] );
274         }
275 }
276
277 sub deleteHistory( $$ ) {
278         my( $self, $id ) = @_;
279         $self->command( 'delete-hist', [ $id ] );
280 }
281
282 sub markChecked( $$ ) {
283         my( $self, $id ) = @_;
284         $self->command( 'mark-checked', [ $id ] );
285 }
286
287 sub deleteItem( $$ ) {
288         my( $self, $id ) = @_;
289         $self->command( 'delete-item', [ $id ] );
290 }
291
292 sub setMainHistory( $$$ ) {
293         my( $self, $location, $history ) = @_;
294         $self->command( 'set-mainhist', [ $history, $history, $history, $location ] );
295 }
296
297 sub resetInfo( $$ ) {
298         my( $self, $mail ) = @_;
299         my $result = $self->query( 'resetinfo', [ $mail ] );
300         if( scalar @{$result} ) {
301                 return ( @{$result->[0]} );
302         } else {
303                 return undef;
304         }
305 }
306
307 sub changePasswd( $$$ ) {
308         my( $self, $id, $passwd ) = @_;
309         $self->command( 'changepasswd', [ $passwd, $id ] );
310 }
311
312 sub profileData( $$ ) {
313         my( $self, $id ) = @_;
314         my %result;
315         ( $result{'email'}, $result{'xmpp'}, $result{'login'}, $result{'email_time'}, $result{'xmpp_time'} ) = @{$self->query( 'profiledata', [ $id ] )->[0]};
316         return \%result;
317 }
318
319 sub setEmail( $$$$ ) {
320         my( $self, $id, $email, $passwd ) = @_;
321         $self->command( 'setemail', [ $email, $passwd, $id ] );
322 }
323
324 sub pushProfile( $$$$$$ ) {
325         my( $self, $id, $login, $xmpp, $mailgather, $xmppgather ) = @_;
326         $self->command( 'pushprofile', [ $xmpp, $login, $mailgather, $xmppgather, $id ] );
327 }
328
329 sub notificationsUser( $$ ) {
330         my( $self, $uid ) = @_;
331         return $self->query( 'notifuser', [ $uid ] );
332 }
333
334 sub getNotifData( $$$ ) {
335         my( $self, $uid, $location ) = @_;
336         my $result = $self->query( 'notifdata', [ $uid, $location ] );
337         if( @{$result} ) {
338                 my( $recursive, $notification, $way ) = @{$result->[0]};
339                 return {
340                         'recursive' => $recursive,
341                         'notification' => $notification,
342                         'way' => $way };
343         } else {
344                 return { 'recursive' => 1 };
345         }
346 }
347
348 sub submitNotification( $$$$ ) {
349         my( $self, $uid, $location, $data ) = @_;
350         $self->command( 'drop-notif', [ $uid, $location ] );
351         $self->command( 'new-notif', [ $uid, $location, $data->{'recursive'}, $data->{'notification'}, $data->{'way'} ] ) unless( $data->{'notification'} == 3 );
352 }
353
354 sub pushNotifications( $$$$$ ) {
355         my( $self, $location, $history, $priority, $reason ) = @_;
356         $self->command( 'notify', [ $history, 0, $reason, 0, $priority, $location, $location ] );
357         $self->command( 'notify', [ $history, 1, $reason, 1, $priority, $location, $location ] );
358         $self->command( 'newtime-mail', [ $priority, $location, $location ] );
359         $self->command( 'newtime-xmpp', [ $priority, $location, $location ] );
360 }
361
362 sub notifExists( $$$ ) {
363         my( $self, $user, $location ) = @_;
364         return scalar @{$self->query( 'notif-exists', [ $user, $location, $location ] )};
365 }
366
367 sub mailNotifs( $$ ) {
368         my( $self, $time ) = @_;
369         return $self->query( 'mailout', [ $time ] );
370 }
371
372 sub xmppNotifs( $$ ) {
373         my( $self, $time ) = @_;
374         return $self->query( 'xmppout', [ $time ] );
375 }
376
377 sub time( $ ) {
378         my( $self ) = @_;
379         return $self->query( 'time', [] )->[0]->[0];
380 }
381
382 sub dropNotifs( $$ ) {
383         my( $self, $time ) = @_;
384         $self->command( 'dropnotifsmail', [ $time ] );
385         $self->command( 'dropnotifsxmpp', [ $time ] );
386 }
387
388 sub searchName( $$$ ) {
389         my( $self, $search, $prefix ) = @_;
390         return $self->query( 'searchlocalname', [ "%$search%", "$prefix/%" ] ) if defined $prefix;
391         return $self->query( 'searchname', [ "%$search%" ] );
392 }
393
394 sub itemName( $$ ) {
395         my( $self, $id ) = @_;
396         my $result = $self->query( 'itemname', [ $id ] )->[0]->[0];
397         return defined $result ? $result : '';
398 }
399
400 sub adminCount( $$ ) {
401         my( $tables, $prefix ) = @_;
402         return $tables->query( 'admincount', [ "$prefix%" ] )->[0]->[0];
403 }
404
405 1;