--- lib/A3C/LDAP.pm 2008/03/30 00:02:18 36 +++ lib/A3C/LDAP.pm 2008/05/01 14:52:48 104 @@ -5,24 +5,201 @@ use Net::LDAP; use Data::Dump qw/dump/; -use base 'Jifty::Object'; +use base qw(Jifty::Object Class::Accessor::Fast); +our @config_fields = qw( server dn password base ); +Jifty->log->debug("using fields from configuration: ",dump( @config_fields )); +__PACKAGE__->mk_accessors( qw(ldap current_search), @config_fields ); -my $ldap_config = Jifty->config->app('LDAP'); -Jifty->log->debug( "config->app(LDAP) = ",dump( $ldap_config ) ); +=head1 NAME -my $ldap = Net::LDAP->new( $ldap_config->{Server} ) or die "$@"; +A3C::LDAP -# an anonymous bind -#my $mesg = $ldap->bind; -my $mesg = $ldap->bind( $ldap_config->{DN}, password => $ldap_config->{Password} ); +=head1 DESCRIPTION -Jifty->log->info("Connected to ", $ldap_config->{Server}, " with DN ", $ldap_config->{DN}); +This object turn L into something with looks like +L + +=head1 METHODS + +=head2 new + + my $ldap = A3C::LDAP->new; + +=cut + +sub new { + my $class = shift; + + my $args = { @_ }; + + my $ldap_config = Jifty->config->app('LDAP'); + Jifty->log->debug( "config->app(LDAP) = ",dump( $ldap_config ) ); + + foreach my $f ( @config_fields ) { + if ( my $v = $ldap_config->{$f} ) { + $args->{$f} = $v; + } + } + + my $ldap = Net::LDAP->new( $args->{server} ) or die "$@"; + + # an anonymous bind + #$ldap->bind; + $ldap->bind( $args->{dn}, password => $args->{password} ); + + Jifty->log->info("Connected to ", $args->{server}, " with DN ", $args->{dn}); + + $args->{ldap} = $ldap; + + $class->SUPER::new( $args ); +} + +=head2 search + + my $msg = A3C::LDAP->search( + base => 'dc=skole,dc=hr', + filter => '(objectClass=hrEduOrg)', + sizelimit => 10, + ); + +=cut sub search { my $self = shift; - return $ldap->search( @_ ); + my $search = $self->ldap->search( @_ ); + if ( $search->code != 0 ) { + Jifty->log->error( $search->error, ' for ', dump( @_ ) ); + } + return $self->current_search( $search ); +} + +=head2 next + +Syntaxtic shugar to look more like L + + my $entry = ldap->next; + +=cut + +sub next { + my $self = shift; + + die "no current LDAP search" unless $self->current_search; + + return $self->current_search->shift_entry; +} + +=head2 count + + my $search_results = $ldap->count; + +=cut + +sub count { + my $self = shift; + $self->current_search->count; +} + +=head2 as_collection_of + + my $connection = $ldap->collection( + # name of model to use + 'Organization', + # optional params + limit => $limit, + filter => '(uid=foobar)', + ); + +=cut + +my $collection2filter = { + 'Person' => '(objectClass=hrEduPerson)', + 'Organization' => '(objectClass=hrEduOrg)', +}; + +sub collection { + my $self = shift; + my $model = shift or die "no model?"; + my $args = {@_}; + + $args->{limit} ||= 0; # unlimited by default + + my $filter = $collection2filter->{$model}; +# die "unknown model $model" unless $filter; + # fallback to model named as objectClass + $filter ||= "(objectClass=$model)"; + + # add user filter + $filter = '(&' . $filter . $args->{filter} . ')' if $args->{filter}; + + $self->search( + base => $self->base, + filter => $filter, + sizelimit => $args->{limit}, + ); + + Jifty->log->info( + "Searching LDAP for $model with $filter ", + $args->{limit} ? 'limit ' . $args->{limit} . ' ' : '', + 'returned ', $self->count, ' results' + ); + + my $class = Jifty->app_class('Model', $model . 'Collection' ) or die "can't create ${model}Collection"; + my $collection = $class->new() or die "can't $class->new"; + + while ( my $entry = $self->next ) { + my $model_obj = Jifty->app_class('Model',$model)->new; + #warn dump( $model_obj ); + my $additional; + $self->model_from_entry( $model_obj, $entry, %$additional ); + $collection->add_record( $model_obj ); + } + + return $collection; +} + +=head1 INTERNAL METHODS + +Following methods map directly into L + +=head2 current_search + +Result of last C<< $ldap->search >> request + +=head2 model_from_entry + + $ldap->model_from_entry( $model, $entry, $additional ); + +=cut + +sub model_from_entry { + my ( $self, $model, $entry, $additional ) = @_; + my $data; + + my @columns = map { $_->name } $model->columns; + #warn "# columns = ",dump( @columns ); + + foreach my $attr ( $entry->attributes ) { + if ( grep(/^\Q$attr\E$/, @columns ) ) { + $data->{$attr} = $entry->get_value( $attr ); +# } elsif ( $attr !~ m/^(objectClass)$/i ) { +# Jifty->log->warn(ref($model)," doesn't have $attr"); + } + } + + Jifty->log->debug( ref($model), ' = ', dump( $data ) ); + + my ( $id, $message ) = $model->load_or_create( %$data, %$additional ); + + if ( $id ) { + Jifty->log->info( $message || 'Added', ' ', ref($model), ' ', $model->id, ' ', $model->name ); + } else { + Jifty->log->error( ref($model), " ", $message ); + } } + + 1;