package LATMOS::Accounts::Bases::Sql::User; use 5.010000; use strict; use warnings; use LATMOS::Accounts::Utils; use LATMOS::Accounts::Log; use base qw(LATMOS::Accounts::Bases::Sql::objects); our $VERSION = (q$Rev$ =~ /^Rev: (\d+) /)[0]; =head1 NAME LATMOS::Ad - Perl extension for blah blah blah =head1 SYNOPSIS use LATMOS::Accounts::Bases; my $base = LATMOS::Accounts::Bases->new('sql'); ... =head1 DESCRIPTION Account base access over standard unix file format. =head1 FUNCTIONS =cut =head2 new(%options) Create a new LATMOS::Ad object for windows AD $domain. domain / server: either the Ad domain or directly the server ldap_args is an optionnal list of arguments to pass to L. =cut sub object_table { 'user' } sub key_field { 'name' } sub has_extended_attributes { 1 } sub _delayed_fields { my ($self)= @_; return qw(memberOf manager directReports); } sub _office_address_fields { qw(telephoneNumber physicalDeliveryOfficeName site) } sub _inline_fields { my ($class, $for, $base) = @_; return ( $class->SUPER::_inline_fields($for, $base), uidNumber => 'uidnumber', gidNumber => 'gidnumber', ); } sub _managed_fields { my ($self, $for, $base) = @_; return ( memberOf => 'memberOf', forward => 'forward', (map { $_ => $_ } $self->_address_fields), (map { $_ => $_ } $self->_office_address_fields), (($for !~ /w/) ? ( uid => 'name', cn => 'name', gecos => 'gecos', displayName => 'displayName', sAMAccountName => 'sAMAccountName', accountExpires => 'accountExpires', shadowExpire => 'shadowExpire', directReports => 'directReports', managedObjects => 'managedObjects', department => 'department', otheraddress => 'otheraddress', mainaddress => 'mainaddress', aliases => 'aliases', revaliases => 'revaliases', ) : ()), ) } sub get_field { my ($self, $field) = @_; if ($field eq 'gecos') { return to_ascii( join(' ', grep { $_ } ($self->_get_c_field('givenName'), ($self->_get_c_field('sn')))) ) || to_ascii($self->_get_c_field('description')); } elsif ($field eq 'displayName') { return join(' ', grep { $_ } ($self->_get_c_field('givenName'), ($self->_get_c_field('sn')))) || $self->id; } elsif ($field eq 'sAMAccountName') { return $self->id; } elsif ($field eq 'memberOf') { my $sth = $self->db->prepare_cached( q{ select name from "group" join group_attributes_users on group_attributes_users.okey = "group".ikey where value = ? and attr = ? } ); $sth->execute($self->id, 'memberUID'); my @res; while (my $res = $sth->fetchrow_hashref) { push(@res, $res->{name}); } return \@res; } elsif ($field eq 'directReports') { my $sth = $self->db->prepare_cached( q{ select name from "user" join user_attributes on user_attributes.okey = "user".ikey where value = ? and attr = ? } ); $sth->execute($self->id, 'manager'); my @res; while (my $res = $sth->fetchrow_hashref) { push(@res, $res->{name}); } return \@res; } elsif ($field eq 'department') { my $sth = $self->db->prepare_cached( q{ select name from "group" join group_attributes on "group".ikey = group_attributes.okey where okey in (select okey from group_attributes_users where value = ?) and attr = ? and value = ? } ); $sth->execute($self->id, 'sutype', 'dpmt'); my @res; while (my $res = $sth->fetchrow_hashref) { push(@res, $res->{name}); } return join(',', @res); } elsif ($field eq 'managedObjects') { my $sth = $self->db->prepare_cached( q{ select name from "group" join group_attributes on group_attributes.okey = "group".ikey where value = ? and attr = ? } ); $sth->execute($self->id, 'managedBy'); my @res; while (my $res = $sth->fetchrow_hashref) { push(@res, $res->{name}); } return \@res; } elsif ($field eq 'accountExpires') { my $sth = $self->db->prepare_cached( sprintf( q{select extract(epoch from expire) + 11644474161 as expire from %s where %s = ?}, $self->db->quote_identifier($self->object_table), $self->db->quote_identifier($self->key_field), ) ); $sth->execute($self->id); my $res = $sth->fetchrow_hashref; $sth->finish; return $res->{expire} ? sprintf("%.f", $res->{expire} * 1E7) : '9223372036854775807'; } elsif ($field eq 'shadowExpire') { my $sth = $self->db->prepare_cached( sprintf( q{select justify_hours(expire - '1/1/1970'::timestamp) as expire from %s where %s = ?}, $self->db->quote_identifier($self->object_table), $self->db->quote_identifier($self->key_field), ) ); $sth->execute($self->id); my $res = $sth->fetchrow_hashref; $sth->finish; return -1 unless($res->{expire}); $res->{expire} =~ /(\d+) days\s*(\w)?/; return $1 + ($2 ? 1 : 0); } elsif ($field eq 'otheraddress') { my $sth = $self->db->prepare_cached(q{ select name from address where "user" = ? }); $sth->execute($self->id); my @values; while (my $res = $sth->fetchrow_hashref) { push(@values, $res->{name}); } return \@values; } elsif ($field eq 'mainaddress') { my $sth = $self->db->prepare_cached(q{ select name from address join address_attributes on ikey = okey where "user" = ? and attr = 'isMainAddress' }); $sth->execute($self->id); my $res = $sth->fetchrow_hashref; $sth->finish; return $res->{name}; } elsif (grep { $field eq $_ } __PACKAGE__->_address_fields(), $self->_office_address_fields) { if (my $fmainaddress = $self->get_c_field('mainaddress')) { my $address = $self->base->get_object('address', $fmainaddress); if ($address) { return $address->get_c_field($field); } else { # can't happend return; } } else { return $self->SUPER::get_field($field); } } elsif ($field eq 'aliases') { my $sth = $self->db->prepare(q{ select name from aliases where forward = ? } . ($self->base->{wexported} ? '' : 'and exported = true')); $sth->execute($self->id); my @values; while (my $res = $sth->fetchrow_hashref) { push(@values, $res->{name}); } return \@values; } elsif ($field eq 'forward') { my $sth = $self->db->prepare(q{ select forward from aliases where name = ? } . ($self->base->{wexported} ? '' : ' and exported = true')); $sth->execute($self->id); my $res = $sth->fetchrow_hashref; $sth->finish; return $res->{forward} } elsif ($field eq 'revaliases') { my $sth = $self->db->prepare(q{ select "as" from revaliases where name = ? } . ($self->base->{wexported} ? '' : ' and exported = true')); $sth->execute($self->id); my $res = $sth->fetchrow_hashref; $sth->finish; return $res->{as} } else { return $self->SUPER::get_field($field); } } sub set_fields { my ($self, %data) = @_; my %fdata; my $res = 0; foreach my $attr (keys %data) { $attr =~ /^memberOf$/ and do { my %member; foreach (@{ $self->get_field('memberOf') }) { $member{$_}{c} = 1; } foreach (ref $data{$attr} ? @{ $data{$attr} || []} : $data{$attr}) { $member{$_}{n} = 1; } foreach (keys %member) { $member{$_}{c} && $member{$_}{n} and next; # no change ! my $group = $self->base->get_object('group', $_) or next; if ($member{$_}{n}) { my $sth = $self->db->prepare_cached( q{insert into group_attributes_users (value, attr, okey) values (?,?,?)} ); $sth->execute($self->id, 'memberUID', $group->_get_ikey); $res++; } elsif ($member{$_}{c}) { my $sth = $self->db->prepare_cached( q{delete from group_attributes_users where value = ? and attr = ? and okey = ?} ); $sth->execute($self->id, 'memberUID', $group->_get_ikey); $res++; } # else {} # can't happend } next; }; $attr =~ /^forward$/ and do { if ($data{$attr}) { if (my $f = $self->base->get_object('aliases', $self->id)) { $res += $f->set_c_fields(forward => $data{$attr}); } else { $self->base->create_c_object('aliases', $self->id, forward => $data{$attr}) and $res++; } } else { $self->base->delete_object('aliases', $self->id); $res++; } next; }; grep { $attr eq $_ } (__PACKAGE__->_office_address_fields, __PACKAGE__->_address_fields()) and do { my $fmainaddress = $self->_get_c_field('mainaddress'); if (!$fmainaddress) { $fmainaddress = $self->id . '-' . join('', map { ('a'..'z')[rand(26)] } (0..4)); $self->base->create_c_object( 'address', $fmainaddress, user => $self->id, isMainAddress => 1, ) or do { $self->base->log(LA_ERR, "Cannot create main address for user %s", $self->id); return; }; } if (my $address = $self->base->get_object('address', $fmainaddress)) { $res += $address->set_c_fields($attr => $data{$attr}); } next; }; $fdata{$attr} = $data{$attr} || undef; } if (keys %fdata) { return $self->SUPER::set_fields(%fdata) + $res; } else { return $res; } } 1; __END__ =head1 SEE ALSO =head1 AUTHOR Olivier Thauvin, Eolivier.thauvin@latmos.ipsl.frE =head1 COPYRIGHT AND LICENSE Copyright (C) 2008, 2009 CNRS SA/CETP/LATMOS This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.10.0 or, at your option, any later version of Perl 5 you may have available. =cut