LibreCat/LibreCat

View on GitHub
lib/LibreCat/App/Catalogue/Controller/Permission.pm

Summary

Maintainability
Test Coverage
package LibreCat::App::Catalogue::Controller::Permission::Permissions;

use Catmandu::Sane;
use Catmandu;
use Catmandu::Util qw(:is);
use LibreCat qw(publication);
use LibreCat::App::Helper;
use LibreCat::Access;
use Carp;
use Dancer qw(:syntax);
use Exporter qw/import/;

use Moo;

sub cache {
    var("cache") or
    var cache => +{};
}

sub cache_get {

    my($self, $key) = @_;
    my $cache   = $self->cache();
    exists($cache->{$key}) ? $cache->{$key} : undef;

}

sub cache_set {

    my($self, $key, $val) = @_;
    my $cache = cache();
    $cache->{$key} = $val;

}

sub get_cached_publication {
    my($self, $id) = @_;

    my $pub = $self->cache_get( "PUBLICATION_${id}" );
    my $set_cache = !$pub;
    $pub //= h->publication->get($id);

    $self->cache_set( "PUBLICATION_${id}", $pub) if $set_cache;

    $pub;
}

sub get_cached_user {
    my($self, $user_id) = @_;

    my $user = $self->cache_get( "USER_${user_id}" );
    my $set_cache = !$user;
    $user //= h->get_person( $user_id );

    $self->cache_set("USER_${user_id}", $user) if $set_cache;

    $user;
}

sub _can_do_action {
    my ($self, $action, $id, $opts) = @_;

    unless (defined($action)) {
        h->log->fatal("whoops! an action role needs to be filled in");
        return 0;
    }

    is_string($id)     or return 0;
    is_hash_ref($opts) or return 0;

    h->log->debug("id: $id ; opts:" . to_dumper($opts));

    my $user_id = $opts->{user_id};
    my $role    = $opts->{role};

    return 0 unless defined($user_id) && defined($role);

    my $pub = $self->get_cached_publication($id);

    is_hash_ref($pub) or return 0;

    my $user  = $self->get_cached_user($user_id);

    # do not touch deleted records
    return 0 if $pub->{status} && $pub->{status} eq 'deleted';

    #no restrictions for super_admin
    return 1 if $role eq "super_admin";

    my $action_permissions = h->config->{permissions}->{access}->{$action};

    my $action_access = LibreCat::Access->new(
        allowed_user_id   => $action_permissions->{by_user_id}   ,
        allowed_user_role => $action_permissions->{by_user_role} ,
        publication_allow => $action_permissions->{publication_allow} ,
        publication_deny  => $action_permissions->{publication_deny} ,
    );

    if ($action_access->by_user_id($pub,$user)) {
        return 1;
    }
    elsif ($action_access->by_user_role($pub,$user,$role)) {
        return 1;
    }
    else {
        return 0;
    }
}

=head2 can_edit( $self, $id, $param)

=over 4

=item id

Publication identifier

=item opts

 * user_id
 * role

=back

=cut

sub can_edit {
    my ($self, $id, $param) = @_;
    return $self->_can_do_action('can_edit', $id, $param);
}

=head2 can_delete( $self, $id, $param )

=over 4

=item id

Publication identifier

=item opts

* user_id
* role

=back

=cut

sub can_delete {
    my ($self, $id, $param) = @_;
    return $self->_can_do_action('can_delete', $id, $param);
}

=head2 can_make_public( $self, $id, $param )

=over 4

=item id

Publication identifier

=item opts

* user_id
* role

=back

=cut

sub can_make_public {
    my ($self, $id, $param) = @_;
    return $self->_can_do_action('can_make_public', $id, $param);
}

=head2 can_return( $self, $id, $param )

=over 4

=item id

Publication identifier

=item opts

* user_id
* role

=back

=cut

sub can_return {
    my ($self, $id, $param) = @_;
    return $self->_can_do_action('can_return', $id, $param);
}

=head2 can_return( $self, $id, $param )

=over 4

=item id

Publication identifier

=item opts

* user_id
* role

=back

=cut

sub can_submit {
    my ($self, $id, $param) = @_;
    return $self->_can_do_action('can_submit', $id, $param);
}

=head2 can_download( $self, $id, $opts )

=over 4

=item id

Publication identifier

=item opts

Hash reference containing:

    * user_id (string)
    * role (string)
    * file_id (string)
    * ip (string)

=back

=cut

sub can_download {
    my ($self, $id, $opts) = @_;

    is_string($id)     or return (0, "");
    is_hash_ref($opts) or return (0, "");

    my $pub   = $self->get_cached_publication($id);

    is_hash_ref($pub) or return (0,"");

    my $file_id = $opts->{file_id};
    my $user_id = $opts->{user_id};
    my $role    = $opts->{role};
    my $ip      = $opts->{ip};

    my $ip_range = h->config->{ip_range};
    my $access;
    my $file_name;

    for (@{$pub->{file}}) {
        if ($_->{file_id} eq $file_id) {
            $access    = $_->{access_level};
            $file_name = $_->{file_name};
            last;
        }
    }

    return (0, '') unless defined $file_name;
    return (0, '') unless defined $access;

    if ($pub->{status} eq 'public' && $access eq 'open_access') {
        return (1, $file_name);
    }
    elsif ($pub->{status} eq 'public' && $access eq 'local' && h->within_ip_range($ip, $ip_range)) {
        return (1, $file_name);
    }
    else {
        # closed documents can be downloaded by user
        # if and only if the user can edit the record
        my $can_download
            = $self->_can_do_action('can_edit',$id, {user_id => $user_id, role => $role});
        return ($can_download ? 1 : 0, $file_name);
    }

    return (0, '');
}

=head2 all_author_types

Returns a listing of all the user_id fields for any of the edit,delete,..actions

=cut
sub all_author_types {
    my ($self) = @_;

    my $permissions = h->config->{permissions}->{access} // {};

    my $perm_by_user_identity = {};

    for my $action (keys %$permissions) {
        my $action_perm = $permissions->{$action}->{by_user_id} // [];
        for (@$action_perm) {
            $perm_by_user_identity->{$_} = 1;
        }
    }

    return [ keys %$perm_by_user_identity ];
}


=head2 all_author_roles

Returns a listing of all the user_role fields for any of the edit,delete,..actions

=cut
sub all_author_roles {
    my ($self) = @_;

    my $permissions = h->config->{permissions}->{access} // {};

    my $perm_by_user_role = {};

    for my $action (keys %$permissions) {
        my $action_perm = $permissions->{$action}->{by_user_role} // [];
        for (@$action_perm) {
            $perm_by_user_role->{$_} = 1;
        }
    }

    return [ keys %$perm_by_user_role ];
}

package LibreCat::App::Catalogue::Controller::Permission;

my $p = LibreCat::App::Catalogue::Controller::Permission::Permissions->new;

use Catmandu::Sane;
use Dancer qw(:syntax hook);
use Dancer::Plugin;

register p => sub {$p};

hook before_template => sub {

    $_[0]->{p} = $p;

};

register_plugin;

1;