source: trunk/LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Sql.pm @ 1928

Last change on this file since 1928 was 1928, checked in by nanardon, 8 years ago

Add RenameAlias? function

  • Property svn:keywords set to Id Rev
File size: 26.1 KB
Line 
1package LATMOS::Accounts::Bases::Sql;
2
3use 5.010000;
4use strict;
5use warnings;
6
7use base qw(LATMOS::Accounts::Bases);
8use LATMOS::Accounts::Log;
9use LATMOS::Accounts::Bases::Sql::DataRequest;
10use DBI;
11use Crypt::RSA;
12use Crypt::RSA::Key::Public::SSH;
13use Crypt::RSA::Key::Private::SSH;
14use Crypt::RSA::Key::Public;
15use Crypt::RSA::Key::Private;
16use MIME::Base64;
17
18our $VERSION = (q$Rev$ =~ /^Rev: (\d+) /)[0];
19
20sub SCHEMA_VERSION { 11 };
21
22=head1 NAME
23
24LATMOS::Ad - Perl extension for blah blah blah
25
26=head1 SYNOPSIS
27
28  use LATMOS::Accounts::Bases;
29  my $base = LATMOS::Accounts::Bases->new('unix');
30  ...
31
32=head1 DESCRIPTION
33
34Account base access over standard unix file format.
35
36=head1 FUNCTIONS
37
38=cut
39
40=head2 SCHEMA_VERSION
41
42Return the SQL schema version to use for this software version.
43
44=head2 new(%config)
45
46Create a new LATMOS::Ad object for windows AD $domain.
47
48domain / server: either the Ad domain or directly the server
49
50ldap_args is an optionnal list of arguments to pass to L<Net::LDAP>.
51
52=cut
53
54sub new {
55    my ($class, %config) = @_;
56   
57    my $base = {
58        db_conn => $config{db_conn},
59    };
60
61    bless($base, $class);
62}
63
64sub DESTROY {
65    my ($self) = @_;
66    $self->{_db} && $self->{_db}->rollback;
67}
68
69=head2 db
70
71Return a L<DBI> handle over database, load it if need.
72
73=cut
74
75sub db {
76    my ($self) = @_;
77
78    if ($self->{_db} && $self->{_db}->ping) {
79        return $self->{_db};
80    } else {
81        $self->{_db} = DBI->connect_cached(
82            'dbi:Pg:' . $self->{db_conn},
83            undef, undef,
84            {
85                RaiseError => 0,
86                AutoCommit => 0,
87                PrintWarn => 1,
88                PrintError => 1,
89                ($self->config('no_pg_utf8') ? (pg_enable_utf8 => 0) : ()),
90            }
91        ) or do {
92            $self->log(LA_ERR, "Cannot connect to database: %s", $DBI::errstr);   
93            return;
94        };
95        $self->{_db}->do(q(SET SESSION CHARACTERISTICS AS TRANSACTION
96                    ISOLATION LEVEL SERIALIZABLE));
97        $self->{_db}->do(q{set DATESTYLE to 'DMY'});
98        $self->log(LA_DEBUG, 'New connection to DB');
99
100
101        foreach my $otype ($self->list_supported_objects) {
102            my %attrlist = map { $_ => 1 } $self->list_registered_attributes($otype);
103            foreach my $attribute ($self->list_canonical_fields($otype, 'r')) {
104                my $attr = $self->attribute($otype, $attribute);
105                $attr->{inline} and next;
106                $attr->{managed} and next;
107
108                if ($attrlist{$attribute}) {
109                } else {
110                    if($self->register_attribute($otype, $attribute, $attr->{comment})) {
111                        $self->log(LA_NOTICE, "Attr. $attribute for object type $otype registred");
112                    } else {
113                        $self->log(LA_ERR, "Can't register attribute $attribute");
114                        $self->{_db}->rollback;
115                        return;
116                    }
117                }
118            }
119        }
120
121        $self->{_db}->commit;
122        return $self->{_db};
123    }
124}
125
126=head2 load
127
128Read file and load data into memory
129
130=cut
131
132sub load {
133    my ($self) = @_;
134    if (!$self->db) { return 0 };
135
136    my $sv = $self->get_global_value('schema_version') || 1;
137    if ($sv < SCHEMA_VERSION) {
138        $self->log(LA_CRIT,
139            "Schema version %d found, %d is need, please update db using " .
140            "`la-sql-upgrade' tool for `%s' base",
141            $sv,
142            SCHEMA_VERSION,
143            $self->label,
144        );
145        # return;
146    }
147
148    1;
149}
150
151=head2 ListInternalObjects($otype)
152
153List objects flags as internal for type C<$otype>
154
155=cut
156
157sub ListInternalObjects {
158    my ($self, $otype) = @_;
159
160    my $pclass = $self->_load_obj_class($otype) or return;
161
162    # Object Alias: checking if object is alias, then returning it:
163    my $sth = $self->db->prepare_cached(
164        sprintf(q{select %s as k from %s where and internobject = true},
165            $self->db->quote_identifier($pclass->_key_field),
166            $self->db->quote_identifier($pclass->_object_table),
167        ),
168    );
169    $sth->execute();
170    my @list;
171    while (my $res = $sth->fetchrow_hashref) {
172       push(@list, $_->{k});
173   }
174   return(@list);
175}
176
177=head2 GetRawObject($otype, $id)
178
179Return an object even it is internal, alias are not follow and even
180unexported object are returned
181
182This function must be used only for maintenance operation.
183
184=cut
185
186sub GetRawObject {
187    my ($self, $otype, $id) = @_;
188
189    my $pclass = $self->_load_obj_class($otype) or return;
190
191    return $self->SUPER::get_object($otype, $id);
192}
193
194sub _derefObject {
195    my ($self, $otype, $oalias) = @_;
196    $oalias or return;
197    if (my ($aliasotype, $aliasoname, $aliasattr) = $oalias =~ m/^([^\/]+)\.([^\.]+)\.(.*)$/) {
198        my $attribute = $self->attribute($aliasotype, $aliasattr) or do {
199            $self->log(LA_DEBUG, "Oalias %s (%s): can fetch attibute %s/%s",
200                $otype, $oalias, $aliasotype, $aliasattr);
201            return;
202        };
203        my $refotype = $attribute->reference or do {
204            $self->log(LA_DEBUG, "Oalias %s (%s): Attribute does not reference an object",
205                $otype, $oalias);
206            return;
207        };
208        $refotype eq $otype or do {
209            $self->log(LA_DEBUG, "Oalias %s (%s): Attribute does not reference same object type",
210                $otype, $oalias, $refotype);
211            return;
212        };
213        my $robj = $self->get_object($aliasotype, $aliasoname) or do {
214            $self->log(LA_DEBUG, "Oalias %s (%s): can fetch object %s/%s",
215                $otype, $oalias, $aliasotype, $aliasoname);
216            return;
217        };
218        my $rvalue = $robj->get_attributes($aliasattr) or do {
219            $self->log(LA_DEBUG, "Oalias %s (%s): attribute value is empty",
220                $otype, $oalias);
221            return;
222        };
223        return $self->get_object($refotype, $rvalue);
224    } else {
225        return $self->get_object($otype, $oalias);
226    }
227}
228
229sub get_object {
230    my ($self, $otype, $id) = @_;
231
232    my $pclass = $self->_load_obj_class($otype) or return;
233
234    # Object Alias: checking if object is alias, then returning it:
235    my $sth = $self->db->prepare_cached(
236        sprintf(q{select oalias from %s where %s = ? and internobject = false %s},
237            $self->db->quote_identifier($pclass->_object_table),
238            $self->db->quote_identifier($pclass->_key_field),
239            ($self->{wexported} ? '' : 'and exported = true'),
240        ),
241    );
242    $sth->execute($id);
243    my $res = $sth->fetchrow_hashref;
244    $sth->finish;
245    if (my $oalias = $res->{oalias}) {
246        # Cross reference over object/attribute
247        $self->_derefObject($otype, $oalias);
248    } else {
249        return $self->SUPER::get_object($otype, $id);
250    }
251}
252
253=head2 getObjectFromOKey ($okey)
254
255Return the object from the db internal key
256
257=cut
258
259sub getObjectFromOKey {
260    my ($self, $okey) = @_;
261
262    my $findobj = $self->{_db}->prepare_cached(q{
263        select * from objects_table where ikey = ?
264    });
265
266    $findobj->execute($okey);
267
268    my $res = $findobj->fetchrow_hashref;
269    $findobj->finish;
270
271    if ($res) {
272        return $self->get_object($res->{relname}, $res->{name});
273    } else {
274        return;
275    }
276}
277
278sub _sync_dyn_group {
279    my ($self) = @_;
280
281    my @groups = $self->search_objects('group', 'autoMemberFilter=*');
282
283    my $res = 0;
284    foreach (@groups) {
285        my $g = $self->get_object('group', $_) or next;
286        $res += $g->populate_dyn_group;
287    }
288
289    $self->log(LA_DEBUG, "Group Dyn res %d", $res);
290    $res
291}
292
293sub _sync_dyn_aliases {
294    my ($self) = @_;
295
296    my @groups = $self->search_objects('aliases', 'autoMemberFilter=*');
297
298    my $res = 0;
299    foreach (@groups) {
300        my $g = $self->get_object('aliases', $_) or next;
301        $res += $g->populate_dyn_aliases;
302    }
303
304    $self->log(LA_DEBUG, "Aliases Dyn res %d", $res);
305    $res
306}
307
308=head2 PopulateDynData
309
310Recomputate dynamics attributes (autoMembersFilters) if need
311
312=cut
313
314sub PopulateDynData {
315    my ($self) = @_;
316
317    foreach (1 .. 5) {
318        $self->log(LA_DEBUG, "%d loop for PopulateDynData", $_);
319        my $res = 0;
320        $res += $self->_sync_dyn_group   || 0;
321        $res += $self->_sync_dyn_aliases || 0;
322
323        if ($res == 0) {
324            last;
325        }
326    }
327
328    return 1;
329}
330
331sub _commit {
332    my ($self) = @_;
333
334    $self->PopulateDynData;
335
336    if ($ENV{LA_NO_COMMIT}) {
337        $self->log(LA_DEBUG, 'DB::COMMIT (ignore due to LA_NO_COMMIT)');
338        return 1;
339    } else {
340        $self->log(LA_DEBUG, 'DB::COMMIT');
341    }
342    $self->{__cache} = undef;
343    $self->db->commit;
344}
345
346sub _rollback {
347    my ($self) = @_;
348    if ($ENV{LA_NO_COMMIT}) {
349        $self->log(LA_DEBUG, 'DB::ROLLBACK (ignore due to LA_NO_COMMIT)');
350        return 1
351    } else {
352        $self->log(LA_DEBUG, 'DB::ROLLBACK');
353    }
354    $self->{__cache} = undef;
355    $self->db->rollback;
356}
357
358sub list_supported_objects {
359    my ($self, @otype) = @_;
360    $self->SUPER::list_supported_objects(qw(site), @otype);
361}
362
363# For SQL listRealObjects != list_objects
364sub listRealObjects {
365    my ($self, $otype) = @_;
366    my $pclass = $self->_load_obj_class($otype) or return;
367    $pclass->listReal($self);
368}
369
370sub current_rev {
371    my ($self) = @_;
372    my $sth = $self->db->prepare_cached(
373        q{select max(rev) from revisions}
374    );
375    $sth->execute;
376    my $res = $sth->fetchrow_hashref;
377    $sth->finish;
378    return ($res->{max});
379} 
380
381sub authenticate_user {
382    my ($self, $username, $passwd) = @_;
383    $username or return;
384    my $uobj = $self->get_object('user', $username) or do {
385        la_log(LA_ERR, "Cannot authenticate non existing user $username");
386        return;
387    };
388
389    if ($self->attribute('user', 'exported')) {
390        if (!$uobj->_get_c_field('exported')) {
391            la_log(LA_ERR, "User $username found but currently unexported");
392            return;
393        }
394    }
395
396    $self->SUPER::authenticate_user($username, $passwd);
397}
398
399=head1 SPECIFICS FUNCTIONS
400
401=head2 GetAlias($base, $id)
402
403Return object having id C<$id> only if it is an object alias
404
405=cut
406
407sub GetAlias {
408    my ($self, $otype, $id) = @_;
409
410    my $pclass = $self->_load_obj_class($otype) or return;
411
412    # Object Alias: checking if object is alias, then returning it:
413    my $sth = $self->db->prepare_cached(
414        sprintf(q{select oalias from %s where %s = ? and oalias IS NOT NULL and internobject = false %s},
415            $self->db->quote_identifier($pclass->_object_table),
416            $self->db->quote_identifier($pclass->_key_field),
417            ($self->{wexported} ? '' : 'and exported = true'),
418        ),
419    );
420    $sth->execute($id);
421    my $res = $sth->fetchrow_hashref;
422    $sth->finish;
423    if ($res) {
424        return $self->SUPER::get_object($otype, $id);
425    } else {
426        return;
427    }
428}
429
430=head2 CreateAlias($otype, $name, $for)
431
432Create an object alias named C<$name> for ovbject C<$for>
433
434=cut
435
436sub CreateAlias {
437    my ($self, $otype, $name, $for) = @_;
438
439    my $pclass = $self->_load_obj_class($otype) or return;
440
441    $for or die "Cannot create alias without giving object to point";
442
443    my $res = $pclass->CreateAlias($self, $name, $for);
444
445    if ($res) {
446        $self->ReportChange(
447            $otype,
448            $name,
449            $pclass->_get_ikey($self, $name),
450            'Create', "Alias %s %s => %s", $otype, $name, $for
451        );
452        $self->log(LA_DEBUG, "Alias $otype $name => $for created");
453        my $oalias = $self->GetAlias($otype, $name);
454        $oalias->_update_aliases_ptr();
455        return 1;
456    } else {
457        $self->log(LA_ERR, "Error when creating alias $otype $name");
458        return;
459    }
460}
461
462=head2 RenameAlias($otype, $name, $to)
463
464Rename an object alias
465
466=cut
467
468sub RenameAlias {
469    my ($self, $otype, $name, $to) = @_;
470
471    my $pclass = $self->_load_obj_class($otype) or return;
472
473    my $obj = $self->GetAlias($otype, $name) or do {
474        $self->log('Cannot get alias %s/%s for removal', $otype, $name);
475        return;
476    };
477
478    my $sth = $self->db->prepare_cached(sprintf(
479        'UPDATE %s SET %s = ? WHERE %s = ?',
480        $self->db->quote_identifier($pclass->_key_field),
481        $self->db->quote_identifier($pclass->_object_table),
482        $self->db->quote_identifier($pclass->_key_field),
483    ));
484
485    my $res = $sth->execute($to, $name);
486
487    return $res;
488}
489
490=head2 RemoveAlias($otype, $name, $for)
491
492Create an object alias named C<$name> for ovbject C<$for>
493
494=cut
495
496sub RemoveAlias {
497    my ($self, $otype, $name) = @_;
498
499    my $pclass = $self->_load_obj_class($otype) or return;
500
501    my $obj = $self->GetAlias($otype, $name) or do {
502        $self->log('Cannot get alias %s/%s for removal', $otype, $name);
503        return;
504    };
505
506    if ($obj->_get_attributes('internobject')) {
507        # Cannot happend: internal are not fetchable
508        $self->log(LA_ERR,'Cannot delete %s/%s: is an internal object', $pclass->type, $name);
509        return;
510    }
511    if ($obj->_get_attributes('nodelete')) {
512        $self->log(LA_ERR,'Cannot delete %s/%s: is write protected', $pclass->type, $name);
513        return;
514    }
515
516    my $id = $obj->Iid;
517
518    my $sth = $self->db->prepare_cached(sprintf(
519        'DELETE FROM %s WHERE %s = ?',
520        $self->db->quote_identifier($pclass->_object_table),
521        $self->db->quote_identifier($pclass->_key_field),
522    ));
523
524    $obj->_update_aliases_ptr;
525    my $res = $sth->execute($name);
526
527    if ($res) {
528        $self->ReportChange(
529            $otype,
530            $name,
531            $id,
532            'Delete', "Alias %s %s deleted", $otype, $name
533        );
534        $self->log(LA_DEBUG, "Alias $otype $name removed");
535        return 1;
536    } else {
537        $self->log(LA_ERR, "Error when removing alias $otype $name");
538        return;
539    }
540}
541
542=head2 get_global_value ($varname)
543
544Return global value set into base
545
546=cut
547
548sub get_global_value {
549    my ($self, $varname) = @_;
550
551    my $sth = $self->db->prepare_cached(q{
552        select val from settings where varname = ?
553        });
554    $sth->execute($varname);
555    my $res = $sth->fetchrow_hashref;
556    $sth->finish;
557    $res->{val}
558}
559
560=head2 set_global_value ($varname, $value)
561
562Set global value.
563
564=cut
565
566sub set_global_value {
567    my ($self, $varname, $value) = @_;
568    my $sth = $self->db->prepare(q{
569        update settings set val = ? where varname = ?
570        });
571    $sth->execute($value, $varname) == 0 and do {
572        my $sth2 = $self->db->prepare(q{
573            insert into settings (val, varname) values (?,?)
574            });
575        $sth2->execute($value, $varname);
576    };
577}
578
579=head2 del_global_value ($varname)
580
581Delete global value from base
582
583=cut
584
585sub del_global_value {
586    my ($self, $varname) = @_;
587
588    my $sth = $self->db->prepare_cached(q{
589        delete from settings where varname = ?
590        });
591    return $sth->execute($varname);
592}
593
594=head2 generate_rsa_key ($password)
595
596Return public and private peer rsa keys
597
598=cut
599
600sub generate_rsa_key {
601    my ($self, $password) = @_;
602
603    my $rsa = new Crypt::RSA ES => 'PKCS1v15';
604    my ($public, $private) = $rsa->keygen (
605        Identity  => 'LATMOS-Accounts',
606        Size      => 2048,
607        Password  => $password,
608        Verbosity => 0,
609    ) or die $rsa->errstr(); # TODO avoid die
610    return ($public, $private);
611}
612
613=head2 private_key ($password)
614
615Load and return private rsa key
616
617=cut
618
619sub private_key {
620    my ($self, $password) = @_;
621    my $base = $self;
622    my $serialize = $base->get_global_value('rsa_private_key') or return;
623    my $string = decode_base64($serialize);
624    my $privkey = $string =~ /^SSH PRIVATE KEY FILE/
625        ? Crypt::RSA::Key::Private::SSH->new
626        : Crypt::RSA::Key::Private->new;
627    $privkey = $privkey->deserialize(
628        String => [ $string ],
629        Password => $password
630    );
631    $privkey->reveal( Password => $password );
632    $privkey;
633}
634
635=head2 get_rsa_password
636
637Return hash with peer username => encryptedPassword
638
639=cut
640
641sub get_rsa_password {
642    my ($self) = @_;
643    my $base = $self;
644    my $sth = $base->db->prepare(q{
645        select "name", value from "user" join user_attributes_base
646        on "user".ikey = user_attributes_base.okey
647        where user_attributes_base.attr = 'encryptedPassword'
648    });
649    $sth->execute;
650    my %users;
651    while (my $res = $sth->fetchrow_hashref) {
652        $users{$res->{name}} = $res->{value};
653    }
654    %users
655}
656
657=head2 store_rsa_key ($public, $private)
658
659Store public and private RSA key info data base
660
661=cut
662
663sub store_rsa_key {
664    my ($self, $public, $private) = @_;
665    my $base = $self;
666    $private->hide;
667    $base->set_global_value('rsa_private_key',
668        encode_base64($private->serialize));
669    $base->set_global_value('rsa_public_key',
670        $public->serialize);
671    return;
672}
673
674=head2 find_next_expire_users ($expire)
675
676Search user expiring in C<$expire> delay
677
678=cut
679
680sub find_next_expire_users {
681    my ($self, $expire) = @_;
682
683    my $sth= $self->db->prepare(q{
684        select name from "user" where
685            expire < now() + ?::interval
686            and expire > now()
687            and expire is not null
688            and internobject = false
689            } . ($self->{wexported} ? '' : 'and exported = true') . q{
690            order by expire
691        }
692    );
693    $sth->execute($expire || '1 month');
694    my @users;
695    while (my $res = $sth->fetchrow_hashref) {
696        push(@users, $res->{name});
697    }
698    @users
699}
700
701=head2 find_expired_users ($expire)
702
703Return list of user going to expires in C<$expire> delay
704
705=cut
706
707sub find_expired_users {
708    my ($self, $expire) = @_;
709
710    my $sth= $self->db->prepare(q{
711        select name from "user" where
712            expire < now() - ?::interval
713            and expire is not null
714            and internobject = false
715        } . ($self->{wexported} ? '' : 'and exported = true') . q{
716            order by expire
717        }
718    );
719    $sth->execute($expire || '1 second');
720    my @users;
721    while (my $res = $sth->fetchrow_hashref) {
722        push(@users, $res->{name});
723    }
724    @users
725}
726
727=head2 rename_nethost ($nethostname, $to, %config)
728
729Facility function to rename computer to new name
730
731=cut
732
733sub rename_nethost {
734    my ($self, $nethostname, $to, %config) = @_;
735    {
736        my $obj = $self->get_object('nethost', $nethostname) or do {
737            $self->log(LA_ERR, 'Unable to rename non exisant host %s', $nethostname);
738            return;
739        };
740        $obj->_delAttributeValue(cname => $to);
741    }
742    $self->rename_object('nethost', $nethostname, $to) or return;
743    if ($config{'addcname'}) {
744        my $obj = $self->get_object('nethost', $to);
745        $obj->_addAttributeValue(cname => $nethostname);
746    }
747    return 1;
748}
749
750=head2 nethost_exchange_ip ($ip1, $ip2)
751
752Exchange ip1 with ip2 in base
753
754=cut
755
756sub nethost_exchange_ip {
757    my ($self, $ip1, $ip2) = @_;
758    my ($obj1, $obj2);
759    if (my ($host1) = $self->search_objects('nethost', "ip=$ip1")) {
760        $obj1 = $self->get_object('nethost', $host1);
761    } else {
762        $self->log(LA_ERR, "Cannot find host having $ip1");
763        return;
764    }
765    if (my ($host2) = $self->search_objects('nethost', "ip=$ip2")) {
766        $obj2 = $self->get_object('nethost', $host2);
767    } else {
768        $self->log(LA_ERR, "Cannot find host having $ip2");
769        return;
770    }
771    if ($obj1->id eq $obj2->id) {
772        $self->log(LA_ERR, "Both ip belong to same host (%s)", $obj1->id);
773        return;
774    }
775
776    $self->log(LA_NOTICE, "Exchanging IP between %s and %s", $obj1->id, $obj2->id);
777    $obj1->delAttributeValue('ip', $ip1) or return;
778    $obj2->delAttributeValue('ip', $ip2) or return;
779    $obj1->addAttributeValue('ip', $ip2) or return;
780    $obj2->addAttributeValue('ip', $ip1) or return;
781    return 1;
782}
783
784=head1 ATTRIBUTES FUNCTIONS
785
786=head2 register_attribute ($otype, $attribute, $comment)
787
788Register a new attribute in base
789
790=cut
791
792sub register_attribute {
793    my ($self, $otype, $attribute, $comment) = @_;
794    my $pclass = $self->_load_obj_class($otype) or return;
795    $pclass->register_attribute($self, $attribute, $comment);
796}
797
798=head2 is_registered_attribute ($otype, $attribute)
799
800Return true is attribute already exists
801
802=cut
803
804sub is_registered_attribute {
805    my ($self, $otype, $attribute) = @_;
806    my $pclass = $self->_load_obj_class($otype) or return;
807    $pclass->is_registered_attribute($self, $attribute);
808}
809
810=head2 list_registered_attributes ($otype)
811
812List all regiestered attribute
813
814=cut
815
816sub list_registered_attributes {
817    my ($self, $otype) = @_;
818    my $pclass = $self->_load_obj_class($otype) or return;
819    if ($pclass->_has_extended_attributes) {
820        return $pclass->list_registered_attributes($self);
821    } else {
822        return ();
823    }
824}
825
826=head2 get_attribute_comment ($otype, $attribute)
827
828Return the comment associated to attribute
829
830=cut
831
832sub get_attribute_comment {
833    my ($self, $otype, $attribute) = @_;
834    my $pclass = $self->_load_obj_class($otype) or return;
835    $pclass->get_attribute_comment($self, $attribute);
836}
837
838=head2 set_attribute_comment ($otype, $attribute, $comment)
839
840Set comment to attribute
841
842=cut
843
844sub set_attribute_comment {
845    my ($self, $otype, $attribute, $comment) = @_;
846    my $pclass = $self->_load_obj_class($otype) or return;
847    $pclass->set_attribute_comment($self, $attribute, $comment);
848}
849
850=head2 get_datarequest ($id)
851
852Return user request C<$id>
853
854=cut
855
856sub get_datarequest {
857    my ($self, $id) = @_;
858
859    my $sth = $self->db->prepare(q{
860        select name from request
861        where id = ?
862        });
863    $sth->execute($id);
864    if (my $res = $sth->fetchrow_hashref) {
865        my $accreq = $self->get_object('accreq', $res->{name});
866        return LATMOS::Accounts::Bases::Sql::DataRequest->new($accreq, $id);
867    } else {
868        return;
869    }
870}
871
872=head2 list_requests
873
874list user request currently waiting in base
875
876=cut
877
878sub list_requests {
879    my ($self, $due) = @_;
880
881    my $sth = $self->db->prepare(
882        sprintf(
883            q{
884            select id from request
885            where done is null
886            %s
887            order by apply
888            },
889            defined($due)
890                ? 'and apply ' . ($due ? '<' : '>=') . ' now()'
891                : ''
892        )
893    );
894    $sth->execute;
895    my @ids;
896    while (my $res = $sth->fetchrow_hashref) {
897        push(@ids, $res->{id});
898    }
899
900    @ids
901}
902
903=head2 list_requests_by_submitter ($id)
904
905list user request currently waiting in base ask by user C<$id>
906
907=cut
908
909sub list_requests_by_submitter {
910    my ($self, $id) = @_;
911
912    my $sth = $self->db->prepare(q{
913        select id from request
914        where done is null and "user" = ?
915        order by apply
916    });
917    $sth->execute($id);
918    my @ids;
919    while (my $res = $sth->fetchrow_hashref) {
920        push(@ids, $res->{id});
921    }
922
923    @ids
924}
925
926
927=head2 list_request_by_object ($otype, $id, $req)
928
929Return the list of pending request for a specific object
930
931C<$req> is an optional forms name to limit search
932
933=cut
934
935sub list_request_by_object {
936    my ($self, $otype, $id, $req) = @_;
937
938    my $sth = $self->db->prepare(q{
939        select * from request join
940        accreq on request.name = accreq.name
941        join accreq_attributes on accreq_attributes.okey = accreq.ikey
942        where
943        request.applied is NULL and
944        accreq_attributes.attr = 'oType' and
945        accreq_attributes.value = ?
946        and request.object = ?
947    } .
948    ($req ? ' and request.name = ? ' : '')
949    . q{
950        order by apply
951    });
952    $sth->execute($otype, $id, ($req ? ($req) : ()));
953    my @ids;
954    while (my $res = $sth->fetchrow_hashref) {
955        push(@ids, $res->{id});
956    }
957
958    @ids
959}
960
961=head2 list_pending_requests
962
963List user request to apply
964
965=cut
966
967sub list_pending_requests {
968    my ($self) = @_;
969
970    my $sth = $self->db->prepare(q{
971        select id from request
972        where done is null
973            and apply < now()
974        order by apply
975    });
976    $sth->execute;
977    my @ids;
978    while (my $res = $sth->fetchrow_hashref) {
979        push(@ids, $res->{id});
980    }
981
982    @ids
983}
984
985=head2 list_auto_pending_requests
986
987List automatic request
988
989=cut
990
991sub list_auto_pending_requests {
992    my ($self) = @_;
993
994    my $sth = $self->db->prepare(q{
995        select id from request
996        where done is null
997            and apply < now()
998            and automated = true
999        order by apply
1000    });
1001    $sth->execute;
1002    my @ids;
1003    while (my $res = $sth->fetchrow_hashref) {
1004        push(@ids, $res->{id});
1005    }
1006
1007    @ids
1008}
1009
1010sub ReportChange {
1011    my ($self, $otype, $name, $ref, $changetype, $message, @args) = @_;
1012
1013    my $sthmodifiedby = $self->db->prepare(q{
1014        UPDATE objects set modifiedby = ? where ikey = ?
1015    });
1016
1017    $sthmodifiedby->execute(
1018        $self->user || '@Console',
1019        $ref,
1020    );
1021
1022    my $sth = $self->db->prepare(q{
1023        INSERT into objectslogs (ikey, irev, otype, name, changetype, username, message)
1024        VALUES (?,?,?,?,?,?,?)
1025        });
1026
1027    $sth->execute(
1028        $ref,
1029        $self->current_rev,
1030        $otype,
1031        $name,
1032        $changetype,
1033        $self->user || '@Console',
1034        sprintf($message, @args),
1035    );
1036}
1037
1038=head2 getobjectlogs($otype, $name)
1039
1040Return logs for object type C<$otype> having C<$name>.
1041
1042=cut 
1043
1044sub getobjectlogs {
1045    my ($self, $otype, $name) = @_;
1046
1047    my $sth = $self->db->prepare(q{
1048        select ikey from objectslogs where
1049            otype = ? and
1050            name  = ?
1051        group by ikey
1052    });
1053    $sth->execute($otype, $name);
1054    my @ids;
1055    while (my $res = $sth->fetchrow_hashref) {
1056        push(@ids, $res->{ikey});
1057    }
1058    @ids or return;
1059
1060    my $sth2 = $self->db->prepare(sprintf(
1061        q{
1062            select * from objectslogs where ikey IN (%s)
1063            order by logdate asc
1064        },
1065        join(',', ('?') x scalar(@ids))
1066    ));
1067
1068    $sth2->execute(@ids);
1069    my @logs;
1070    while (my $res = $sth2->fetchrow_hashref) {
1071        push(@logs, $res);
1072    }
1073
1074    return @logs;
1075}
1076
1077=head2 getlogs
1078
1079Return logs for last year
1080
1081=cut
1082
1083sub getlogs {
1084    my ($self) = @_;
1085    my $sth2 = $self->db->prepare(
1086        q{
1087            select * from objectslogs
1088            where logdate > now() - '1 year'::interval
1089            order by logdate asc
1090        },
1091    );
1092
1093    $sth2->execute();
1094    my @logs;
1095    while (my $res = $sth2->fetchrow_hashref) {
1096        push(@logs, $res);
1097    }
1098
1099    return @logs;
1100}
1101
1102
11031;
1104
1105__END__
1106
1107=head1 SEE ALSO
1108
1109=head1 AUTHOR
1110
1111Olivier Thauvin, E<lt>olivier.thauvin@latmos.ipsl.frE<gt>
1112
1113=head1 COPYRIGHT AND LICENSE
1114
1115Copyright (C) 2008, 2009 CNRS SA/CETP/LATMOS
1116
1117This library is free software; you can redistribute it and/or modify
1118it under the same terms as Perl itself, either Perl version 5.10.0 or,
1119at your option, any later version of Perl 5 you may have available.
1120
1121
1122=cut
Note: See TracBrowser for help on using the repository browser.