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

Last change on this file since 1551 was 1551, checked in by nanardon, 9 years ago

Various fixes after i18n changes

  • Property svn:keywords set to Id Rev
File size: 46.2 KB
RevLine 
[29]1package LATMOS::Accounts::Bases::Sql::User;
[19]2
3use 5.010000;
4use strict;
5use warnings;
[1329]6use overload '""' => 'stringify';
[19]7
[175]8use LATMOS::Accounts::Utils;
[390]9use LATMOS::Accounts::Log;
[1079]10use POSIX qw(strftime);
[1500]11use Date::Parse qw(str2time);
12use DateTime;
13use DateTime::TimeZone;
[29]14use base qw(LATMOS::Accounts::Bases::Sql::objects);
[1549]15use LATMOS::Accounts::I18N;
[19]16
17our $VERSION = (q$Rev$ =~ /^Rev: (\d+) /)[0];
18
19=head1 NAME
20
21LATMOS::Ad - Perl extension for blah blah blah
22
23=head1 DESCRIPTION
24
25Account base access over standard unix file format.
26
27=head1 FUNCTIONS
28
29=cut
30
[1071]31=head2 new(%config)
[19]32
33Create a new LATMOS::Ad object for windows AD $domain.
34
35domain / server: either the Ad domain or directly the server
36
37ldap_args is an optionnal list of arguments to pass to L<Net::LDAP>.
38
39=cut
40
[1014]41sub _object_table { 'user' }
[19]42
[1014]43sub _key_field { 'name' }
[29]44
[1014]45sub _has_extended_attributes { 1 }
[74]46
[1329]47sub stringify {
48    my ($self) = @_;
49
50    return join(' ', grep { $_ }
51        (
52            $self->get_field('givenName'),
53            $self->get_field('sn')
54        )
55    )
56    || $self->get_field('description')
57    || $self->id;
58}
59
[861]60sub _get_attr_schema {
61    my ($class, $base) = @_;
[92]62
[1315]63    my $subsetaddress = sub {
64        my ($self, $data) = @_;
65        my $fmainaddress = $self->object->_get_c_field('mainaddress');
66
67        # set address attribute => create address object on the fly
68        # except if attr is empty !
69        if (!$fmainaddress && $data) {
70            $fmainaddress = $self->object->id . '-' . join('', map { ('a'..'z')[rand(26)] }
71                (0..4));
72            $self->base->_create_c_object(
73                'address', $fmainaddress,
74                user => $self->object->id,
75                isMainAddress => 1, ) or do {
76                $self->base->log(LA_ERR,
77                    "Cannot create main address for user %s", $self->object->id);
78                return;
79            };
80        }
81        if ($fmainaddress && 
82            (my $address = $self->base->get_object('address', $fmainaddress))) {
83            if ($address->attribute($self->name) &&
84                !$address->attribute($self->name)->ro) {
85                return $address->set_c_fields($self->name => $data) ||0;
86            }
87        }
88    };
89
[1524]90    my $attrs = {
[1315]91            exported => {
92                post => sub {
93                    my ($self, $value) = @_;
94                    my $attr = $self->name;
95
96                    if (my $obj = $self->base->
97                            get_object('revaliases', $self->object->id)) {
98                        my $ares = $obj->set_c_fields(
99                            ($attr eq 'exported' ? 'exported' : 'unexported') => $value
100                        );
101                        if (!defined($ares)) {
102                            $self->base->log(LA_ERR,
103                                'Cannot set revaliases exported attribute for user %s',
104                                $self->object->id);
105                        }
106                    }
107                    my $must_expire = $self->name eq 'exported'
108                        ? ($value ? 0 : 1 )
109                        : ($value ? 1 : 0 );
110
[1500]111                    foreach my $al (grep { $_ } $self->object->get_attributes('aliases'), $self->object->id) {
[1315]112                        my $obj = $self->base->get_object('aliases', $al) or next;
113                        $obj->_set_c_fields(
[1470]114                            exported => $value,
[1315]115                        );
116                    }
[1498]117                    foreach my $al ($self->object->get_attributes('otheraddress')) {
118                        my $obj = $self->base->get_object('address', $al) or next;
119                        $obj->_set_c_fields(
120                            exported => $value,
121                        );
122                    }
[1315]123                },
124            },
[910]125            uidNumber => {
126                inline => 1,
127                iname => 'uidnumber',
128                uniq => 1,
129                mandatory => 1,
130                formopts => { length => 7 },
[1550]131                label => l('UID'),
[910]132            },
[1297]133            uidnumber => { inline => 1, hide => 1, monitored => 1 },
[1280]134            gidNumber => {
[861]135                inline => 1,
136                iname => 'gidnumber',
137                mandatory => 1,
138                can_values => sub {
[1347]139                    map { $_->id, $_->get_attributes('gidNumber') }
140                    map { $base->get_object('group', $_) }
141                    $base->list_objects('group')
142                },
143                can_values => sub {
[1315]144                    my $sth = $base->db->prepare_cached(
145                        q{
[1347]146                        select name, gidnumber from "group" where exported = true
[1315]147                        }
148                    );
149                    $sth->execute();
150                    my @res;
151                    while (my $res = $sth->fetchrow_hashref) {
[1347]152                        push(@res, $res->{name});
[1315]153                        push(@res, $res->{gidnumber});
154                    }
155                    return @res;
[861]156                },
157                display => sub {
158                    my ($self, $val) = @_;
159                    my ($gr) = $self->base->search_objects('group', "gidNumber=$val")
160                        or return;
161                    return $gr;
162                },
[1347]163                input => sub {
164                    my ($val) = @_;
165                    $val =~ /^\d+$/ and return $val;
166                    my ($gr) = $base->search_objects('group', "name=$val") or return;
167                    return $base->get_object('group', $gr)->get_attributes('gidNumber');
168                },
[861]169                reference => 'group',
[1550]170                label => l('GID'),
[861]171            },
[1550]172            loginShell => {
[1551]173                mandatory => 1,
[1550]174                label => l('Shell'),
175            },
[861]176            gidnumber => { inline => 1, hide => 1,
177                can_values => sub {
[1347]178                    map { $_->id, $_->get_attributes('gidNumber') }
[861]179                    map { $base->get_object('group', $_) }
180                    $base->list_objects('group')
181                },
[1347]182                display => sub {
183                    my ($self, $val) = @_;
184                    my ($gr) = $self->base->search_objects('group', "gidNumber=$val")
185                        or return;
186                    return $gr;
187                },
188                input => sub {
189                    my ($val) = @_;
190                    $val =~ /^\d+$/ and return $val;
191                    my ($gr) = $base->search_objects('group', "name=$val") or return;
192                    return $base->get_object('group', $gr)->get_attributes('gidNumber');
193                },
[861]194                mandatory => 1,
195                reference => 'group',
[1297]196                monitored => 1,
[861]197            },
198            locked    => {
199                formtype => 'CHECKBOX',
200                formopts => { rawvalue => 1, },
[1297]201                monitored => 1,
[1550]202                label => l('Locked'),
[861]203            },
[1506]204            expire        => {
205                inline => 1,
206                formtype => 'DATETIME',
207                monitored => 1,
[1550]208                label => l('Expire'),
[1506]209            },
210            endcircuit    => {
211                inline => 1,
212                formtype => 'DATE',
213                monitored => 1,
[1550]214                label => l('End of entrance'),
[1506]215            },
[1500]216            endEmployment => {
217                formtype => 'DATETIME',
218                managed => 1,
219                ro => 1,
220                get => sub {
221                    my ($attr) = @_;
222                    my $self = $attr->object;
[1526]223                    $self->_computeEndEmployment($self->base->config('employment_delay'));
[1500]224                },
[1550]225                label => l('End of employment'),
[1500]226            },
[1514]227            endStrictEmployment => {
228                formtype => 'DATETIME',
229                managed => 1,
230                ro => 1,
231                get => sub {
232                    my ($attr) = @_;
233                    my $self = $attr->object;
[1526]234                    $self->_computeEndEmployment();
[1522]235                },
236            },
237            endCurrentEmployment => {
238                formtype => 'DATETIME',
239                managed => 1,
240                ro => 1,
241                get => sub {
242                    my ($attr) = @_;
243                    my $self = $attr->object;
[1514]244
245                    my $list_empl = $self->base->db->prepare_cached(q{
246                        SELECT * FROM employment WHERE "user" = ? and
[1522]247                            firstday <= now() and
[1514]248                            (lastday is null or lastday >= now() - '1 days'::interval)
249                            order by firstday asc
250                    });
251                    $list_empl->execute($self->id);
252                    my $end;
253                    while (my $res = $list_empl->fetchrow_hashref) {
254                        if (!$res->{lastday}) {
255                            # Ultimate employment.
256                            $list_empl->finish;
257                            return undef;
[1522]258                        } else {
[1514]259                            $end = DateTime->from_epoch(epoch => str2time($res->{lastday}));
260                            $end->set_time_zone( DateTime::TimeZone->new( name => 'local' ) );
261                            $end->add(hours => 23, minutes => 59, seconds => 59);
262                        }
[1522]263                        last;
[1514]264                    }
[1522]265                    $list_empl->finish;
266
[1514]267                    return $end ? $end->iso8601 : undef
268                },
269            },
[1511]270            endLastEmployment => {
271                formtype => 'DATETIME',
272                managed => 1,
273                ro => 1,
274                get => sub {
275                    my ($attr) = @_;
276                    my $self = $attr->object;
277
278                    my $list_empl = $self->base->db->prepare_cached(q{
279                        SELECT * FROM employment WHERE "user" = ?
280                        order by lastday desc nulls first
281                    });
282                    $list_empl->execute($self->id);
283                    my $res = $list_empl->fetchrow_hashref;
284                    $list_empl->finish;
285                    my $end;
286                    if ($res && $res->{lastday}) {
287                        $end = DateTime->from_epoch(epoch => str2time($res->{lastday}));
288                        $end->set_time_zone( DateTime::TimeZone->new( name => 'local' ) );
289                        $end->add(hours => 23, minutes => 59, seconds => 59);
290                    }
291                    return $end ? $end->iso8601 : undef
292                },
[1550]293                label => l('End of any employment'),
[1511]294            },
[1117]295            cn        => {
296                inline => 1, ro => 1,
297                get => sub {
298                    my ($self) = @_;
299                    return join(' ', grep { $_ } 
300                        (
301                            $self->object->_get_c_field('givenName'),
302                            $self->object->_get_c_field('sn')
303                        )
304                    )
305                    || $self->object->_get_c_field('description')
306                    || $self->object->id;
307                },
308            },
[938]309            memberOf  => {
[1329]310                reference => 'group',
[938]311                multiple => 1, delayed => 1,
312                get => sub {
313                    my ($self) = @_;
314                    my $obj = $self->object;
315                    my $sth = $obj->db->prepare_cached(
316                        q{
317                        select name from "group" join
318                        group_attributes on group_attributes.okey = "group".ikey
319                        where value = ? and attr = ?
[1353]320                        } . ($self->base->{wexported} ? '' : ' and "group".exported = true')
[938]321                    );
322                    $sth->execute($obj->id, 'memberUID');
323                    my @res;
324                    while (my $res = $sth->fetchrow_hashref) {
325                        push(@res, $res->{name});
326                    }
327                    return \@res;
[1315]328                },
329                set => sub {
330                    my ($self, $values) = @_;
331                    my %old = map { $_ => 'o' } @{ $self->get };
332                    foreach my $group (grep { $_ } ref $values ? @{ $values } : $values) {
333                        if ($old{$group}) {
334                            $old{$group} = undef; # no change
335                        } else {
336                            $old{$group} = 'n';
337                        }
338                    }
339
340                    my $res = 0;
341                    foreach my $group (keys %old) {
342                        $old{$group} or next; # no change
343
344                        my $ogroup = $self->base->get_object('group', $group) or next;
345                        ($ogroup->_get_c_field('sutype') || '') =~ /^(jobtype|contrattype)$/ and next;
346
347                        if ($old{$group} eq 'n') {
348                            $res += $ogroup->_addAttributeValue('memberUID', $self->object->id);
349                        } else {
350                            if (($self->object->_get_c_field('department') || '') eq $ogroup->id) {
351                                $self->base->log(LA_WARN,
352                                    "Don't removing user %s from group %s: is its department",
353                                    $self->object->id, $ogroup->id);
354                                next;
355                            }
356                            $res += $ogroup->_delAttributeValue('memberUID', $self->object->id);
357                        }
358                    }
359                    return $res;
360                },
[1550]361                label => l('Member of'),
[938]362            },
[1315]363            forward => {
364                managed => 1,
365                get => sub {
366                    my ($self) = @_;
367                    my $sth = $self->base->db->prepare(q{
368                        select forward from aliases where name = ?
369                        } . ($self->base->{wexported} ? '' : ' and exported = true'));
370                    $sth->execute($self->object->id);
371                    my $res = $sth->fetchrow_hashref;
372                    $sth->finish;
373                    return $res->{forward}
374                },
375                set => sub {
376                    my ($self, $data) = @_;
377                    if ($data) {
378                        if (my $f = $self->base->get_object('aliases', $self->object->id)) {
379                            return $f->_set_c_fields(forward => $data);
380                        } else {
381                            if ($self->base->_create_c_object(
382                                    'aliases', $self->object->id,
383                                    forward => $data,
384                                    description => 'automatically created for ' . $self->object->id,
385                                )) {
386                                return 1;
387                            } else {
388                                $self->base->log(LA_ERR, "Cannot add forward for %s",
[1498]389                                    $self->object->id);
[1315]390                            }
391                        }
392                    } else {
[1372]393                        if (my $res = $self->base->_delete_object('aliases', $self->object->id)) {
[1315]394                            return $res;
395                        } else {
396                            $self->base->log(LA_ERR, "Cannot remove forward for %s",
[1395]397                                $self->object->id);
[1315]398                        }
399                    }
400                    return;
401                },
[1550]402                label => l('Forward'),
[1315]403            },
[861]404            aliases   => {
[1385]405                #reference => 'aliases',
[1418]406                delayed => 1,
[861]407                formtype => 'TEXT',
408                multiple => 1,
[1315]409                get => sub {
410                    my ($self) = @_;
411                    my $sth = $self->base->db->prepare(q{
[1460]412                        select name from aliases where lower($1) =
413                        lower(array_to_string("forward", ','))
[1315]414                        } . ($self->base->{wexported} ? '' : 'and exported = true'));
415                    $sth->execute($self->object->id);
416                    my @values;
417                    while (my $res = $sth->fetchrow_hashref) {
418                        push(@values, $res->{name});
419                    }
420                    return \@values;
421                },
422                set => sub {
423                    my ($self, $data) = @_;
[1418]424
[1315]425                    my $res = 0;
426                    my %aliases = map { $_ => 1 } grep { $_ } (ref $data ? @{$data} : $data);
427                    foreach ($self->object->_get_attributes('aliases')) {
428                        $aliases{$_} ||= 0;
429                        $aliases{$_} +=2;
430                    }
431                    foreach (keys %aliases) {
432                        if ($aliases{$_} == 2) {
433                            if ($self->base->_delete_object('aliases', $_)) {
434                                $res++
435                            } else {
436                                $self->base->log(LA_ERR,
437                                    "Cannot remove aliases %s from user %s", $_,
438                                    $self->object->id);
439                            }
440                        } elsif ($aliases{$_} == 1) {
441                            if ($self->base->_create_c_object(
442                                    'aliases', $_,
443                                    forward => [ $self->object->id ],
444                                    description => 'automatically created for ' . $self->object->id,
445                                )) {
446                                $res++
447                            } else {
448                                $self->base->log(LA_ERR, 'Cannot set forward %s to user %s',
449                                    $_, $self->object->id);
450                                return;
451                            }
452                        } # 3 no change
453                    }
454                    $res
455                },
[1550]456                label => l('Aliases'),
[861]457            },
458            revaliases => {
459                formtype => 'TEXT',
[1418]460                get => sub {
461                    my ($self) = @_;
462
463                    if (my $obj = $self->base->
464                        get_object('revaliases', $self->object->id)) {
465                        return $obj->get_attributes('as');
466                    } else {
467                        return;
468                    }
469                },
[1315]470                set => sub {
471                    my ($self, $data) = @_;
472               
473                    my $res = 0;
474                    if ($data) {
475                        if (my $obj = $self->base->
476                            get_object('revaliases', $self->object->id)) {
477                            my $ares = $obj->set_c_fields(
478                                'as' => $data,
[1404]479                                'exported' => ($self->object->get_attributes('exported') || 0),
[1315]480                            );
481                            if (defined($ares)) {
482                                $res+=$ares;
483                            } else {
484                                $self->base->log(LA_ERR, 'Cannot set revaliases for user %s',
485                                    $self->object->id);
486                            }
487                        } else {
488                            if ($self->base->_create_c_object(
489                                    'revaliases',
490                                    $self->object->id, as => $data,
[1392]491                                    'exported' => ($self->object->get_attributes('exported') || 0),
[1315]492                                    description => 'automatically created for ' . $self->object->id,
493                                )) {
494                                $res++;
495                            } else {
496                                $self->base->log(LA_ERR, 'Cannot set revaliases for user %s',
497                                    $self->object->id);
498                            }
499                        }
500                    } else {
501                        $self->base->_delete_object('revaliases', $self->object->id);
502                        $res++;
503                    }
504
505                    $res
506                },
[861]507            },
508            manager => {
[1365]509                reference => 'user',
510                ro => 1,
511                get => sub {
512                    my ($self) = @_;
513                    if (my $manager = $self->object->_get_c_field('managerContact')) {
514                        return $manager;
515                    } elsif (my $department = $self->object->_get_c_field('department')) {
516                        my $obj = $self->base->get_object('group', $department);
517                        return $obj->_get_c_field('managedBy');
518                    } else {
519                        return;
520                    }
[861]521                },
[1550]522                label => l('Responsible'),
[861]523            },
524            department => {
525                reference => 'group',
526                can_values => sub {
527                    $base->search_objects('group', 'sutype=dpmt')
[1280]528                },
[1297]529                monitored => 1,
[1550]530                label => l('Department'),
[861]531            },
532            contratType => {
533                reference => 'group',
534                can_values => sub {
535                    $base->search_objects('group', 'sutype=contrattype')
[1280]536                },
[1297]537                monitored => 1,
[1550]538                label => l('Type of contract'),
[861]539            },
540            site => {
541                reference => 'site',
542                can_values => sub {
543                    $base->search_objects('site')
[1315]544                },
545                get => sub {
546                    my ($self) = @_;
547                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
548                        $self->base->get_object('address', $fmainaddress)
549                            ->_get_c_field($self->name);
550                    } else {
551                        return;
552                    }
553                },
554                set => $subsetaddress,
[1550]555                label => l('Site'),
[861]556            },
[1315]557            co => {
558                get => sub {
559                    my ($self) = @_;
560                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
561                        $self->base->get_object('address', $fmainaddress)
562                            ->_get_c_field($self->name);
563                    } else {
564                        return;
565                    }
566                },
567                set => $subsetaddress,
568            },
569            l => {
570                get => sub {
571                    my ($self) = @_;
572                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
573                        $self->base->get_object('address', $fmainaddress)
574                            ->_get_c_field($self->name);
575                    } else {
576                        return;
577                    }
578                },
579                set => $subsetaddress,
[1550]580                label => l('City'),
[1315]581            },
582            postalCode => {
583                get => sub {
584                    my ($self) = @_;
585                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
586                        $self->base->get_object('address', $fmainaddress)
587                            ->_get_c_field($self->name);
588                    } else {
589                        return;
590                    }
591                },
592                set => $subsetaddress,
[1550]593                label => l('Postal code'),
[1315]594            },
595            streetAddress => {
596                formtype => 'TEXTAREA',
597                get => sub {
598                    my ($self) = @_;
599                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
600                        $self->base->get_object('address', $fmainaddress)
601                            ->_get_c_field($self->name);
602                    } else {
603                        return;
604                    }
605                },
606                set => $subsetaddress,
[1550]607                label => l('Street'),
[1315]608            },
609            postOfficeBox => {
610                get => sub {
611                    my ($self) = @_;
612                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
613                        $self->base->get_object('address', $fmainaddress)
614                            ->_get_c_field($self->name);
615                    } else {
616                        return;
617                    }
618                },
619                set => $subsetaddress,
[1550]620                label => l('Post office box'),
[1315]621            },
622            st => {
623                get => sub {
624                    my ($self) = @_;
625                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
626                        $self->base->get_object('address', $fmainaddress)
627                            ->_get_c_field($self->name);
628                    } else {
629                        return;
630                    }
631                },
632                set => $subsetaddress,
633            },
634            facsimileTelephoneNumber => {
635                get => sub {
636                    my ($self) = @_;
637                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
638                        $self->base->get_object('address', $fmainaddress)
639                            ->_get_c_field($self->name);
640                    } else {
641                        return;
642                    }
643                },
644                set => $subsetaddress,
[1550]645                label => l('Fax number'),
[1315]646            },
647            o => {
648                ro => 1,
649                iname => 'company',
[1550]650                label => l('Company'),
[1315]651            },
[1550]652            ou => {
653                iname => 'department',
654                ro => 1,
655                label => l('Department'),
656            },
[1315]657            telephoneNumber => {
658                get => sub {
659                    my ($self) = @_;
660                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
661                        $self->base->get_object('address', $fmainaddress)
662                            ->_get_c_field($self->name);
663                    } else {
664                        return;
665                    }
666                },
667                set => $subsetaddress,
[1550]668                label => l('Phone number'),
[1315]669            },
670            physicalDeliveryOfficeName => {
671                get => sub {
672                    my ($self) = @_;
673                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
674                        $self->base->get_object('address', $fmainaddress)
675                            ->_get_c_field($self->name);
676                    } else {
677                        return;
678                    }
679                },
680                set => $subsetaddress,
[1550]681                label => l('Office'),
[1315]682            },
[861]683            uid => { iname => 'name', ro => 1 },
684            cn =>  { iname => 'name', ro => 1 },
[938]685            gecos => {
686                ro => 1,
687                get => sub {
688                    my ($self) = @_;
689                    my $obj = $self->object;
690                    my $gecos = sprintf("%s,%s,%s,%s",
691                        join(' ', grep { $_ }
692                                ($obj->_get_c_field('givenName'),
693                                ($obj->_get_c_field('sn'))))
694                            || $obj->_get_c_field('description') || '',
695                        join(' - ', grep { $_ } (($obj->_get_c_field('site') ||
696                                    $obj->_get_c_field('l')),
697                            $obj->_get_c_field('physicalDeliveryOfficeName'))) || '',
698                        $obj->_get_c_field('telephoneNumber') || '',
699                        $obj->_get_c_field('expireText') || '',
700                    );
701                    $gecos =~ s/:/ /g;
702                    return to_ascii($gecos);
703                },
[1550]704                label => l('GECOS'),
[938]705            },
706            displayName  => {
707                ro => 1, managed => 1,
708                get => sub {
709                    my ($self) = @_;
710                    return join(' ', grep { $_ } 
711                        (
712                            $self->object->_get_c_field('givenName'),
713                            $self->object->_get_c_field('sn')
714                        )
715                    )
716                    || $self->object->_get_c_field('description')
[1075]717                    || $self->object->id;
[938]718                },
[1550]719                label => l('Name'),
[938]720            },
[1315]721            sAMAccountName  => {
722                ro => 1,
723                managed => 1,
724                iname => 'name',
725            },
[938]726            accountExpires => {
727                ro => 1,
728                managed => 1,
729                get => sub {
730                    my ($self) = @_;
731                    my $obj = $self->object;
732                    my $sth = $obj->db->prepare_cached(
733                        sprintf(
[1348]734                            q{select extract(epoch from COALESCE(endcircuit,  expire)) + 11644474161 as expire
[938]735                            from %s where %s = ?},
[1014]736                            $obj->db->quote_identifier($obj->_object_table),
737                            $obj->db->quote_identifier($obj->_key_field),
[938]738                        )
739                    );
740                    $sth->execute($obj->id);
741                    my $res = $sth->fetchrow_hashref;
742                    $sth->finish;
743                    return $res->{expire} ? sprintf("%.f", $res->{expire} * 1E7) : '9223372036854775807';
744                }
745            },
746            shadowExpire => {
747                ro => 1,
748                managed => 1,
749                get => sub {
750                    my ($self) = @_;
751                    my $obj = $self->object;
752                    my $sth = $obj->db->prepare_cached(
753                        sprintf(
[1348]754                            q{select justify_hours(COALESCE(endcircuit,  expire) - '1/1/1970'::timestamp) as expire
[938]755                            from %s where %s = ?},
[1014]756                            $obj->db->quote_identifier($obj->_object_table),
757                            $obj->db->quote_identifier($obj->_key_field),
[938]758                        )
759                    );
760                    $sth->execute($obj->id);
761                    my $res = $sth->fetchrow_hashref;
762                    $sth->finish;
763                    return -1 unless($res->{expire});
764                    $res->{expire} =~ /(\d+) days\s*(\w)?/;
765                    return $1 + ($2 ? 1 : 0);
766                }
767            },
[861]768            directReports => {
769                reference => 'user',
770                ro => 1,
771                delayed => 1,
[938]772                get => sub {
773                    my ($self) = @_;
774                    my $obj = $self->object;
775                    my $sth = $obj->db->prepare_cached(
776                        q{
[1365]777                        SELECT
778                        "user".name FROM
779                        public."user",
780                        public.user_attributes_groups,
781                        public.group_attributes_users,
782                        public.group_attributes_base gb,
783                        public."group"
784                        WHERE
785                        "user".ikey = user_attributes_groups.okey AND
786                        user_attributes_groups.value = "group".name AND
787                        group_attributes_users.okey = gb.okey AND
788                        "group".ikey = group_attributes_users.okey AND
789                        gb.attr = 'sutype' AND
790                        gb.value = 'dpmt' AND
791                        group_attributes_users.attr = 'managedBy' AND
792                        group_attributes_users.value = ?
793                        } . ($self->base->{wexported} ? '' : ' and "user".exported = true') . q{
794                            and "user".ikey not in
795                        (select okey from user_attributes_users
796                        where attr = 'manager' and value != ? )
797                        union
798                        select "user".name FROM public."user",
799                        user_attributes_users where
800                        user_attributes_users.attr = 'manager' and user_attributes_users.value = ?
801                            and "user".ikey = user_attributes_users.okey
802                        } . ($self->base->{wexported} ? '' : ' and "user".exported = true')
[938]803                    );
[1365]804                    $sth->execute($obj->id, $obj->id, $obj->id);
[938]805                    my @res;
806                    while (my $res = $sth->fetchrow_hashref) {
807                        push(@res, $res->{name});
808                    }
809                    return \@res;
810                },
[861]811            },
812            managedObjects => { ro => 1, reference => 'group', },
[1315]813            otheraddress => {
814                ro => 1,
815                reference => 'address',
816                get => sub {
817                    my ($self) = @_;
818                    my $sth = $self->base->db->prepare_cached(q{
819                        select name from address left join address_attributes
820                        on address.ikey = address_attributes.okey and
821                        address_attributes.attr = 'isMainAddress'
822                        where "user" = ?
823                        order by address_attributes.attr
824                        });
825                    $sth->execute($self->object->id);
826                    my @values;
827                    while (my $res = $sth->fetchrow_hashref) {
828                        push(@values, $res->{name});
829                    }
830                    return \@values;
831                },
832            },
833            mainaddress => {
834                ro => 1,
835                reference => 'address',
836                get => sub {
837                    my ($self) = @_;
838                    my $sth = $self->base->db->prepare_cached(q{
839                        select name from address join address_attributes on ikey = okey
840                        where "user" = ? and attr = 'isMainAddress'
841                        });
842                    $sth->execute($self->object->id);
843                    my $res = $sth->fetchrow_hashref;
844                    $sth->finish;
845                    return $res->{name};
846                },
847            },
848            postalAddress => {
849                ro => 1,
850                get => sub {
851                    my ($self) = @_;
852                    if (my $fmainaddress = $self->object->_get_c_field('mainaddress')) {
853                        $self->base->get_object('address', $fmainaddress)
854                            ->_get_c_field($self->name);
855                    } else {
856                        return;
857                    }
858                },
[1550]859                label => l('Postal Address'),
[1315]860            },
[1550]861            facsimileTelephoneNumber => {
862                ro => 1,
863                label => l('Fax number'),
864            },
[861]865            allsite   => {
866                ro => 1,
867                reference => 'site',
868            },
869            managerContact => {
[1365]870                delayed => 1,
871                can_values => sub {
872                    my %uniq = map { $_ => 1 } grep { $_ }
873                    ($_[1] ? $_[1]->get_attributes('managerContact') : ()),
874                    $base->search_objects('user', 'active=*');
875                    sort keys %uniq;
876                },
[861]877                reference => 'user',
[1365]878                monitored => 1,
879                iname => 'manager',
[1550]880                label => l('Manager'),
[861]881            },
[938]882            expireText => {
883                ro => 1,
884                get => sub {
885                    my ($self) = @_;
886                    my $obj = $self->object;
887                    my $sth = $obj->db->prepare_cached(
888                        sprintf(
[1348]889                            q{select to_char(COALESCE(endcircuit,  expire), 'YYYY/MM/DD') as expire
[938]890                            from %s where %s = ?},
[1014]891                            $obj->db->quote_identifier($obj->_object_table),
892                            $obj->db->quote_identifier($obj->_key_field),
[938]893                        )
894                    );
[1401]895                    $sth->execute($obj->id) or $obj->db->rollback;
[938]896                    my $res = $sth->fetchrow_hashref;
897                    $sth->finish;
898                    return $res->{expire}
899                },
900            },
[1315]901            krb5ValidEnd => {
902                ro => 1,
903                managed => 1,
904                get => sub {
905                    my ($self) = @_;
906                    my $sth = $self->object->db->prepare_cached(
907                        sprintf(
[1348]908                            q{select date_part('epoch', COALESCE(endcircuit,  expire))::int as expire
[1315]909                            from %s where %s = ?},
910                            $self->object->db->quote_identifier($self->object->_object_table),
911                            $self->object->db->quote_identifier($self->object->_key_field),
912                        )
913                    );
[1401]914                    $sth->execute($self->object->id) or $self->object->db->rollback;
[1315]915                    my $res = $sth->fetchrow_hashref;
916                    $sth->finish;
917                    return $res->{expire}
918                },
919            },
[861]920            cells  => {
921                ro => 1,
922                reference => 'group',
923            },
924            departments => {
925                reference => 'group',
926                delayed => 1,
927                ro => 1,
[1550]928                label => l('Departments'),
[861]929            },
930            arrivalDate => { },
[1550]931            expired => {
[1551]932                ro => 1,
[1550]933                label => l('Expired'),
934            },
935            active => {
[1551]936                ro => 1,
[1550]937                label => l('Active'),
938            },
[938]939            pwdAccountLockedTime => {
940                managed => 1,
941                ro => 1,
942                get => sub {
943                    my ($self) = @_;
944                    my $obj = $self->object;
945                    if ($obj->_get_c_field('locked')) {
946                        return '000001010000Z';
947                    } else {
948                        my $sth = $obj->db->prepare_cached(
949                            sprintf(
[1348]950                                q{select to_char(COALESCE(endcircuit,  expire) AT TIME ZONE 'Z', 'YYYYMMDDHH24MISSZ') as expire
[938]951                                from %s where %s = ? and expire < now()},
[1014]952                                $obj->db->quote_identifier($obj->_object_table),
953                                $obj->db->quote_identifier($obj->_key_field),
[938]954                            )
955                        );
956                        $sth->execute($obj->id);
957                        my $res = $sth->fetchrow_hashref;
958                        $sth->finish;
959                        return $res->{expire}
960                    }
961                },
962            },
[933]963            userPassword => { readable => 0, },
[1550]964            wWWHomePage => {
965                label => l('Web Page'),
966            },
[1315]967            title => { },
[1550]968            snNative => {
969                label => l('Native name'),
970            },
971            givenNameNative => {
972                label => l('Native first name'),
973            },
974            sn => {
975                label => l('Name'),
976            },
[1315]977            shadowWarning => { },
978            shadowMin => { },
979            shadowMax => { },
980            shadowLastChange => { },
981            shadowInactive => { },
982            shadowFlag => { },
983            otherTelephone => { },
984            nickname => { },
985            mobile => { },
[1550]986            mail => {
987                label => l('Email'),
988            },
[1315]989            labeledURI => { },
990            jobType => { },
991            ipPhone => { },
[1550]992            initials => {
993                label => l('Initials'),
994            },
[1315]995            homePhone => { },
[1550]996            homeDirectory => {
997                label => l('Home directory'),
998            },
[1315]999            halReference => { },
1000            grade => { },
[1550]1001            givenName => {
[1551]1002                label => l('First name'),
[1550]1003            },
[1315]1004            encryptedPassword => { },
[1550]1005            description => {
1006                label => l('Description'),
1007            },
1008            company => {
1009                label => l('Company'),
1010            },
1011            comment => {
1012                label => l('Comment'),
1013            },
[1315]1014            college => { },
[1366]1015            passwordLastSet => {
1016                ro => 1,
[1550]1017                label => l('Password set'),
[1366]1018            },
[1489]1019            currentEmployment => {
1020                managed => 1,
1021                ro => 1,
1022                reference => 'employment',
1023                get => sub {
1024                    my ($attr) = @_;
1025                    my $self = $attr->object;
1026
1027                    my $sth = $self->base->db->prepare_cached(
1028                        q{
1029                        select name from employment where firstday <= now() and
[1500]1030                        (lastday is null or lastday >= now() - '1 days'::interval) and "user" = ?
[1489]1031                        limit 1
1032                        }
1033                    );
1034                    $sth->execute($self->id);
[1498]1035                    my $res = $sth->fetchrow_hashref;
1036                    $sth->finish;
1037                    if ($res) {
[1489]1038                        return $res->{name}
1039                    } else {
1040                        return;
1041                    }
[1551]1042                },
[1489]1043            },
[1524]1044            nextEmployment => {
1045                managed => 1,
1046                ro => 1,
1047                reference => 'employment',
1048                get => sub {
1049                    my ($attr) = @_;
1050                    my $self = $attr->object;
1051
1052                    my $sth = $self->base->db->prepare_cached(
1053                        q{
1054                        select name from employment where firstday > now() and
1055                        (lastday is null or lastday >= now() - '1 days'::interval) and "user" = ?
1056                        limit 1
1057                        }
1058                    );
1059                    $sth->execute($self->id);
1060                    my $res = $sth->fetchrow_hashref;
1061                    $sth->finish;
1062                    if ($res) {
1063                        return $res->{name}
1064                    } else {
1065                        return;
1066                    }
1067                }
1068            },
[1500]1069            appliedEmployement => {
1070                hidden => 1,
1071                reference => 'employment',
1072            },
[1524]1073    };
1074
1075    foreach (qw(expire contratType managerContact company endcircuit department)) {
1076        $attrs->{$_}{ro} = sub {
1077
1078            my $setting = $base->config('employment_lock_user') || 'any';
1079
1080            for ($setting) {
1081                /^always$/ and return 1;
1082                /^never$/ and return 0;
1083
1084                !$_[0] and return 1;
1085
1086                /^any$/i and return $_[0]->listEmployment ? 1 : 0;
1087                /^active/i and do {
1088                    return $_[0]->_get_c_field('currentEmployment')
1089                        ? 1
1090                        : $_[0]->_get_c_field('nextEmployment') ? 1 : 0;
1091                };
1092                /(\S+)=(\S+)/ and do {
1093                    my $attr = $_[0]->_get_c_field($1);
1094                    if (defined($attr)) {
1095                        if ($2 eq '*') {
1096                            return 1;
1097                        } elsif($2 eq $attr) {
1098                            return 1;
1099                        } else {
1100                            return 0;
1101                        }
1102                    } else {
1103                        return 0;
1104                    }
1105                };
1106            }
1107            return $_[0]->listEmployment ? 1 : 0; # default is any!
1108        };
1109    }
1110
1111    $class->SUPER::_get_attr_schema($base, $attrs)
[95]1112}
1113
[861]1114sub _get_state {
1115    my ($self, $state) = @_;
1116    for ($state) {
1117        /^expired$/ and do {
1118            my $attribute = $self->attribute('expire');
1119            $attribute->check_acl('r') or return;
1120            my $sth = $self->db->prepare_cached(
1121                q{ select coalesce(expire < now(), false) as exp from "user"
1122                where "user".name = ?}
1123            );
1124            $sth->execute($self->id);
1125            my $res = $sth->fetchrow_hashref;
1126            $sth->finish;
1127            return $res->{exp} ? 1 : 0;
1128        };
1129    }
1130}
1131
[1498]1132=head2 listEmployment
1133
1134Return the ordered list of contract
1135
1136=cut
1137
1138sub listEmployment {
1139    my ($self) = @_;
1140
1141    my $sth = $self->base->db->prepare_cached(
1142        q{
1143        select name from employment where "user" = ?
1144        order by lastday desc NULLS first
1145        }
1146    );
1147    $sth->execute($self->id);
1148    my @list = ();
1149    while (my $res = $sth->fetchrow_hashref) {
1150        push(@list, $res->{name});
1151    }
1152
1153    @list
1154}
1155
[1522]1156
[1526]1157sub _computeEndEmployment {
[1522]1158    my ($self, $delay) = @_;
1159
1160    my $list_empl = $self->base->db->prepare_cached(q{
1161        SELECT *, firstday <= now() as "started" FROM employment WHERE "user" = ? and
1162        (lastday is null or lastday >= now() - '1 days'::interval)
1163        order by firstday asc
1164        });
1165    $list_empl->execute($self->id);
1166    my $end;
1167    while (my $res = $list_empl->fetchrow_hashref) {
1168        if (!$res->{lastday}) {
1169            # Ultimate employment.
1170            $list_empl->finish;
1171            return undef;
1172        }
1173        if ($end) {
1174            my $nextstart = DateTime->from_epoch(epoch => str2time($res->{firstday}));
1175            my $tend = $end->clone;
1176            if ($delay) {
1177                $tend->add(days => $delay);
1178            }
1179            if ($tend->ymd lt $nextstart->ymd) {
1180                last;
1181            }
1182        } else {
1183            if (!$res->{started}) {
1184                last;
1185            }
1186        }
1187        $end = DateTime->from_epoch(epoch => str2time($res->{lastday}));
1188        $end->set_time_zone( DateTime::TimeZone->new( name => 'local' ) );
1189        $end->add(hours => 23, minutes => 59, seconds => 59);
1190    }
1191    $list_empl->finish;
1192
1193    if (!$end) {
1194        my $listold = $self->base->db->prepare_cached(q{
1195            SELECT max(lastday) as lastday FROM employment WHERE "user" = ? and
1196            lastday IS NOT NULL and lastday <= now() - '1 days'::interval
1197            });
1198        $listold->execute($self->id);
1199        my $res = $listold->fetchrow_hashref;
1200        if ($res && $res->{lastday}) {
1201            $end = DateTime->from_epoch(epoch => str2time($res->{lastday}));
1202            $end->set_time_zone( DateTime::TimeZone->new( name => 'local' ) );
1203            $end->add(hours => 23, minutes => 59, seconds => 59);
1204        } else {
1205            if (my $default = $self->base->config('unemployed_expire')) {
1206                $end = DateTime->from_epoch(epoch => str2time($default));
1207            }
1208        }
1209        $listold->finish;
1210    }
1211    return $end ? $end->iso8601 : undef
1212}
1213
[19]12141;
1215
1216__END__
1217
1218=head1 SEE ALSO
1219
1220=head1 AUTHOR
1221
1222Olivier Thauvin, E<lt>olivier.thauvin@latmos.ipsl.frE<gt>
1223
1224=head1 COPYRIGHT AND LICENSE
1225
1226Copyright (C) 2008, 2009 CNRS SA/CETP/LATMOS
1227
1228This library is free software; you can redistribute it and/or modify
1229it under the same terms as Perl itself, either Perl version 5.10.0 or,
1230at your option, any later version of Perl 5 you may have available.
1231
1232=cut
Note: See TracBrowser for help on using the repository browser.