File Coverage: lib/Yukki/Model/User.pm

# File Coverage

File: | lib/Yukki/Model/User.pm
Coverage: | 57.3%

line | stmt | bran | cond | sub | pod | time | code
--- | --- | --- | --- | --- | --- | --- | ---
1 |  |  |  |  |  |  | package Yukki::Model::User;
2 |
3 | 2 2 |  |  | 2 |  | 971 7 | use v5.24;
4 | 2 2 2 |  |  | 2 |  | 5 3 10 | use utf8;
5 | 2 2 2 |  |  | 2 |  | 23 4 7 | use Moo;
6 |
7 |  |  |  |  |  |  | extends 'Yukki::Model';
8 |
9 | 2 2 2 |  |  | 2 |  | 455 2 15 | use Yukki::Types qw( LoginName );
10 | 2 2 2 |  |  | 2 |  | 773 2 11 | use Yukki::TextUtil qw( load_file );
11 |
12 | 2 2 2 |  |  | 2 |  | 470 3 10 | use Type::Params qw( validate );
13 | 2 2 2 |  |  | 2 |  | 316 3 9 | use Type::Utils;
14 | 2 2 2 |  |  | 2 |  | 1955 4 14 | use Types::Path::Tiny;
15 | 2 2 2 |  |  | 2 |  | 384 3 12 | use Types::Standard qw( slurpy Dict );
16 |
17 | 2 2 2 |  |  | 2 |  | 1234 4 24 | use Yukki::User;
18 |
19 | 2 2 2 |  |  | 2 |  | 15 3 13 | use namespace::clean;
20 |
21 |  |  |  |  |  |  | # ABSTRACT: lookup users
22 |
23 - 46 |  |
    =head1 SYNOPSIS

      my $users = $app->model('User');
      my $user  = $users->find('bob');

      my $login_name = $user->login_name;
      my $password   = $user->password;
      my $name       = $user->name;
      my $email      = $user->email;
      my @groups     = $user->groups->@*;

    =head1 DESCRIPTION

    Read access to the current list of authorized users.

    =head1 METHODS

    =head2 set_password

        $users->set_password($user, $cleartext);

    Given a password in cleartext, this will hash the password using the application's hasher. The second argument containing the cleartext password is optional. When omitted, the value returned by the C<password> accessor of the C<$user> object will be used instead.

    =cut
47 |
48 |  |  |  |  |  |  | sub set_password {
49 | 0 |  |  | 0 | 1 | 0 | my ($self, $user, $clear_password) = @_;
50 | 0 |  | 0 |  |  | 0 | $clear_password //= $user->password;
51 |
52 | 0 |  |  |  |  | 0 | my $digest = $self->app->hasher;
53 | 0 |  |  |  |  | 0 | $digest->add($clear_password);
54 | 0 |  |  |  |  | 0 | $user->password($digest->generate);
55 |
56 | 0 |  |  |  |  | 0 | return;
57 |  |  |  |  |  |  | }
58 |
59 - 65 |  |
    =head2 save

        $users->save($user, create_only => 1);

    Writes a L<Yukki::User> object to the users database. If the C<create_only> flag is set, the method will fail with an exception when the user already exists.

    =cut
66 |
67 |  |  |  |  |  |  | sub save {
68 | 0 |  |  | 0 | 1 | 0 | my ($self, $user, %opt) = @_;
69 |
70 | 0 |  |  |  |  | 0 | my $user_file = $self->locate('user_path', $user->login_name);
71 |
72 | 0 | 0 | 0 |  |  | 0 | if ($opt{create_only} && $user_file->exists) {
73 | 0 |  |  |  |  | 0 | die "User ", $user->login_name, " already exists.";
74 |  |  |  |  |  |  | }
75 |
76 | 0 |  |  |  |  | 0 | $user_file->parent->mkpath;
77 | 0 | 0 |  |  |  | 0 | $user_file->chmod(0600) if $user_file->exists;
78 | 0 |  |  |  |  | 0 | $user_file->spew_utf8($user->dump_yaml);
79 | 0 |  |  |  |  | 0 | $user_file->chmod(0400);
80 |
81 | 0 |  |  |  |  | 0 | return;
82 |  |  |  |  |  |  | }
83 |
84 - 90 |  |
    =head2 delete

        $users->delete($user);

    Given a L<Yukki::User>, this method deletes the user file for that object.

    =cut
91 |
92 |  |  |  |  |  |  | sub delete {
93 | 0 |  |  | 0 | 1 | 0 | my ($self, $user) = @_;
94 |
95 | 0 |  |  |  |  | 0 | my $user_file = $self->locate('user_path', $user->login_name);
96 | 0 | 0 |  |  |  | 0 | $user_file->remove if $user_file->is_file;
97 |
98 | 0 |  |  |  |  | 0 | return;
99 |  |  |  |  |  |  | }
100 |
101 - 107 |  |
    =head2 find

      my $user = $users->find(login_name => $login_name);

    Returns a hash containing the information related to a specific user named by login name.

    =cut
108 |
109 |  |  |  |  |  |  | sub find {
110 | 1 |  |  | 1 | 1 | 2219 | my ($self, $opt)
111 |  |  |  |  |  |  | = validate(\@_, class_type(__PACKAGE__),
112 |  |  |  |  |  |  | slurpy Dict[
113 |  |  |  |  |  |  | login_name => LoginName
114 |  |  |  |  |  |  | ],
115 |  |  |  |  |  |  | );
116 | 1 |  |  |  |  | 13 | my $login_name = $opt->{login_name};
117 |
118 | 1 |  |  |  |  | 68 | my $user_file = $self->locate('user_path', $login_name);
119 | 1 | 50 |  |  |  | 4 | if ($user_file->exists) {
120 | 1 |  |  |  |  | 28 | return Yukki::User->load_yaml($user_file->slurp_utf8);
121 |  |  |  |  |  |  | }
122 |
123 | 0 |  |  |  |  |  | return;
124 |  |  |  |  |  |  | }
125 |
126 - 132 |  |
    =head2 list

        my @names = $users->list;

    Returns a list of login names for all users configured.

    =cut
133 |
134 |  |  |  |  |  |  | sub list {
135 | 0 |  |  | 0 | 1 |  | my $self = shift;
136 |
137 | 0 |  |  |  |  |  | my $user_dir = $self->locate('user_path');
138 | 0 0 |  |  |  |  |  | return map { $_->basename } $user_dir->children;
139 |  |  |  |  |  |  | }
140 |
141 |  |  |  |  |  |  | 1;