View | Details | Raw Unified | Return to bug 13799
Collapse All | Expand All

(-)a/Koha/ApiKey.pm (+46 lines)
Line 0 Link Here
1
package Koha::ApiKey;
2
3
# Copyright BibLibre 2015
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
22
use Carp;
23
24
use Koha::Database;
25
26
use base qw(Koha::Object);
27
28
=head1 NAME
29
30
Koha::ApiKey - Koha API Key Object class
31
32
=head1 API
33
34
=head2 Class Methods
35
36
=cut
37
38
=head3 type
39
40
=cut
41
42
sub type {
43
    return 'ApiKey';
44
}
45
46
1;
(-)a/Koha/ApiKeys.pm (+121 lines)
Line 0 Link Here
1
package Koha::ApiKeys;
2
3
# Copyright BibLibre 2015
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
use Scalar::Util qw(blessed);
22
23
use Koha::Borrowers;
24
use Koha::ApiKey;
25
26
use base qw(Koha::Objects);
27
28
use Koha::Exception::BadParameter;
29
use Koha::Exception::UnknownObject;
30
31
=head1 NAME
32
33
Koha::ApiKeys - Koha API Keys Object class
34
35
=head1 API
36
37
=head2 Class Methods
38
39
=cut
40
41
=head3 type
42
43
=cut
44
45
sub type {
46
    return 'ApiKey';
47
}
48
49
sub object_class {
50
    return 'Koha::ApiKey';
51
}
52
53
sub _get_castable_unique_columns {
54
    return ['api_key_id', 'api_key'];
55
}
56
57
=head grant
58
59
    my $apiKey = Koha::ApiKey->grant({borrower => $borrower,
60
                                    apiKey => $apiKey
61
                                });
62
63
Granting an ApiKey should be easy. This creates a new ApiKey for the given Borrower,
64
or sets the owner of an existing key.
65
$PARAM1 HASHRef of params, {
66
            borrower => MANDATORY, a Koha::Borrower or something castable to one.
67
            apiKey   => OPTIONAL, an existing Koha::ApiKEy to give to somebody else.
68
                                not sure why anybody would want to do that, but
69
                                provided as a convenience for testing.
70
}
71
@THROWS Koha::Exception::BadParameter
72
=cut
73
74
sub grant {
75
    my ($self, $borrower, $apiKey) = @_;
76
    $borrower = Koha::Borrowers->cast($borrower);
77
    if ($apiKey) {
78
        $apiKey = Koha::ApiKeys->cast($apiKey);
79
        $apiKey->borrowernumber($borrower->borrowernumber);
80
    }
81
    else {
82
        $apiKey = new Koha::ApiKey;
83
        $apiKey->borrowernumber($borrower->borrowernumber);
84
        $apiKey->api_key(String::Random->new->randregex('[a-zA-Z0-9]{32}'));
85
    }
86
    $apiKey->store;
87
    return $apiKey;
88
}
89
90
sub delete {
91
    my ($self, $apiKey) = @_;
92
    $apiKey = Koha::ApiKeys->cast($apiKey);
93
94
    if ($apiKey) {
95
        $apiKey->delete;
96
    }
97
}
98
99
sub revoke {
100
    my ($self, $apiKey) = @_;
101
    $apiKey = Koha::ApiKeys->cast($apiKey);
102
103
    if ($apiKey) {
104
        $apiKey->active(0);
105
        $apiKey->store;
106
    }
107
    return $apiKey;
108
}
109
110
sub activate {
111
    my ($self, $apiKey) = @_;
112
    $apiKey = Koha::ApiKeys->cast($apiKey);
113
114
    if ($apiKey) {
115
        $apiKey->active(1);
116
        $apiKey->store;
117
    }
118
    return $apiKey;
119
}
120
121
1;
(-)a/Koha/Borrower.pm (+32 lines)
Lines 69-74 sub isSuperuser { Link Here
69
    return (exists($self->{superuser}) && $self->{superuser}) ? 1 : undef;
69
    return (exists($self->{superuser}) && $self->{superuser}) ? 1 : undef;
70
}
70
}
71
71
72
=head getApiKeys
73
74
    my @apiKeys = $borrower->getApiKeys( $activeOnly );
75
76
=cut
77
78
sub getApiKeys {
79
    my ($self, $activeOnly) = @_;
80
81
    my @dbix_objects = $self->_result()->api_keys({active => 1});
82
    for (my $i=0 ; $i<scalar(@dbix_objects) ; $i++) {
83
        $dbix_objects[$i] = Koha::ApiKey->_new_from_dbic($dbix_objects[$i]);
84
    }
85
86
    return \@dbix_objects;
87
}
88
89
=head getApiKey
90
91
    my $apiKey = $borrower->getApiKeys( $activeOnly );
92
93
=cut
94
95
sub getApiKey {
96
    my ($self, $activeOnly) = @_;
97
98
    my $dbix_object = $self->_result()->api_keys({active => 1})->next();
99
    my $object = Koha::ApiKey->_new_from_dbic($dbix_object);
100
101
    return $object;
102
}
103
72
=head1 AUTHOR
104
=head1 AUTHOR
73
105
74
Kyle M Hall <kyle@bywatersolutions.com>
106
Kyle M Hall <kyle@bywatersolutions.com>
(-)a/Koha/Schema/Result/ApiKey.pm (+122 lines)
Line 0 Link Here
1
use utf8;
2
package Koha::Schema::Result::ApiKey;
3
4
# Created by DBIx::Class::Schema::Loader
5
# DO NOT MODIFY THE FIRST PART OF THIS FILE
6
7
=head1 NAME
8
9
Koha::Schema::Result::ApiKey
10
11
=cut
12
13
use strict;
14
use warnings;
15
16
use base 'DBIx::Class::Core';
17
18
=head1 TABLE: C<api_keys>
19
20
=cut
21
22
__PACKAGE__->table("api_keys");
23
24
=head1 ACCESSORS
25
26
=head2 api_key_id
27
28
  data_type: 'integer'
29
  is_auto_increment: 1
30
  is_nullable: 0
31
32
=head2 borrowernumber
33
34
  data_type: 'integer'
35
  is_foreign_key: 1
36
  is_nullable: 0
37
38
=head2 api_key
39
40
  data_type: 'varchar'
41
  is_nullable: 0
42
  size: 255
43
44
=head2 last_request_time
45
46
  data_type: 'integer'
47
  default_value: 0
48
  is_nullable: 1
49
50
=head2 active
51
52
  data_type: 'integer'
53
  default_value: 1
54
  is_nullable: 1
55
56
=cut
57
58
__PACKAGE__->add_columns(
59
  "api_key_id",
60
  { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
61
  "borrowernumber",
62
  { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
63
  "api_key",
64
  { data_type => "varchar", is_nullable => 0, size => 255 },
65
  "last_request_time",
66
  { data_type => "integer", default_value => 0, is_nullable => 1 },
67
  "active",
68
  { data_type => "integer", default_value => 1, is_nullable => 1 },
69
);
70
71
=head1 PRIMARY KEY
72
73
=over 4
74
75
=item * L</api_key_id>
76
77
=back
78
79
=cut
80
81
__PACKAGE__->set_primary_key("api_key_id");
82
83
=head1 UNIQUE CONSTRAINTS
84
85
=head2 C<apk_bornumkey_idx>
86
87
=over 4
88
89
=item * L</borrowernumber>
90
91
=item * L</api_key>
92
93
=back
94
95
=cut
96
97
__PACKAGE__->add_unique_constraint("apk_bornumkey_idx", ["borrowernumber", "api_key"]);
98
99
=head1 RELATIONS
100
101
=head2 borrowernumber
102
103
Type: belongs_to
104
105
Related object: L<Koha::Schema::Result::Borrower>
106
107
=cut
108
109
__PACKAGE__->belongs_to(
110
  "borrowernumber",
111
  "Koha::Schema::Result::Borrower",
112
  { borrowernumber => "borrowernumber" },
113
  { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
114
);
115
116
117
# Created by DBIx::Class::Schema::Loader v0.07039 @ 2015-07-31 11:03:00
118
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:8nljlCCakQs1X0kTmW7PYw
119
120
121
# You can replace this text with custom code or comments, and it will be preserved on regeneration
122
1;
(-)a/Koha/Schema/Result/Borrower.pm (-15 lines)
Lines 656-676 __PACKAGE__->has_many( Link Here
656
  { cascade_copy => 0, cascade_delete => 0 },
656
  { cascade_copy => 0, cascade_delete => 0 },
657
);
657
);
658
658
659
=head2 api_timestamp
660
661
Type: might_have
662
663
Related object: L<Koha::Schema::Result::ApiTimestamp>
664
665
=cut
666
667
__PACKAGE__->might_have(
668
  "api_timestamp",
669
  "Koha::Schema::Result::ApiTimestamp",
670
  { "foreign.borrowernumber" => "self.borrowernumber" },
671
  { cascade_copy => 0, cascade_delete => 0 },
672
);
673
674
=head2 aqbasketusers
659
=head2 aqbasketusers
675
660
676
Type: has_many
661
Type: has_many
(-)a/installer/data/mysql/kohastructure.sql (+19 lines)
Lines 16-21 Link Here
16
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
16
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
17
17
18
--
18
--
19
-- Table structure for table api_keys
20
--
21
22
DROP TABLE IF EXISTS api_keys;
23
CREATE TABLE api_keys (
24
    api_key_id INT(11) NOT NULL auto_increment,
25
    borrowernumber INT(11) NOT NULL, -- foreign key to the borrowers table
26
    api_key VARCHAR(255) NOT NULL, -- API key used for API authentication
27
    last_request_time INT(11) default 0, -- UNIX timestamp of when was the last transaction for this API-key? Used for request replay control.
28
    active INT(1) DEFAULT 1, -- 0 means this API key is revoked
29
    PRIMARY KEY (api_key_id),
30
    UNIQUE KEY apk_bornumkey_idx (borrowernumber, api_key),
31
    CONSTRAINT api_keys_fk_borrowernumber
32
      FOREIGN KEY (borrowernumber)
33
      REFERENCES borrowers (borrowernumber)
34
      ON DELETE CASCADE ON UPDATE CASCADE
35
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
36
37
--
19
-- Table structure for table `auth_header`
38
-- Table structure for table `auth_header`
20
--
39
--
21
40
(-)a/installer/data/mysql/updatedatabase.pl (+30 lines)
Lines 10730-10735 if ( CheckVersion($DBversion) ) { Link Here
10730
    SetVersion ($DBversion);
10730
    SetVersion ($DBversion);
10731
}
10731
}
10732
10732
10733
$DBversion = "XXX";
10734
if(CheckVersion($DBversion)) {
10735
    $dbh->do(q{
10736
        DROP TABLE IF EXISTS api_keys;
10737
    });
10738
    $dbh->do(q{
10739
        CREATE TABLE api_keys (
10740
            api_key_id INT(11) NOT NULL auto_increment,
10741
            borrowernumber INT(11) NOT NULL, -- foreign key to the borrowers table
10742
            api_key VARCHAR(255) NOT NULL, -- API key used for API authentication
10743
            last_request_time INT(11) default 0, -- UNIX timestamp of when was the last transaction for this API-key? Used for request replay control.
10744
            active INT(1) DEFAULT 1, -- 0 means this API key is revoked
10745
            PRIMARY KEY (api_key_id),
10746
            UNIQUE KEY apk_bornumkey_idx (borrowernumber, api_key),
10747
            CONSTRAINT api_keys_fk_borrowernumber
10748
              FOREIGN KEY (borrowernumber)
10749
              REFERENCES borrowers (borrowernumber)
10750
              ON DELETE CASCADE ON UPDATE CASCADE
10751
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
10752
    });
10753
10754
    use Koha::Auth::PermissionManager;
10755
    my $pm = Koha::Auth::PermissionManager->new();
10756
    $pm->addPermission({code => 'manage_api_keys', description => "Manage Borrowers' REST API keys"});
10757
10758
    print "Upgrade to $DBversion done (Bug 13920: Add API keys table)\n";
10759
    SetVersion($DBversion);
10760
}
10761
10762
10733
# DEVELOPER PROCESS, search for anything to execute in the db_update directory
10763
# DEVELOPER PROCESS, search for anything to execute in the db_update directory
10734
# SEE bug 13068
10764
# SEE bug 13068
10735
# if there is anything in the atomicupdate, read and execute it.
10765
# if there is anything in the atomicupdate, read and execute it.
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/members-toolbar.inc (+5 lines)
Lines 170-175 function searchToHold(){ Link Here
170
                [% ELSE %]
170
                [% ELSE %]
171
                    <li class="disabled"><a data-toggle="tooltip" data-placement="left" title="You are not authorized to set permissions" id="patronflags" href="#">Set permissions</a></li>
171
                    <li class="disabled"><a data-toggle="tooltip" data-placement="left" title="You are not authorized to set permissions" id="patronflags" href="#">Set permissions</a></li>
172
                [% END %]
172
                [% END %]
173
                [% IF ( CAN_user_borrowers_manage_api_keys ) %]
174
                    <li><a id="apikeys" href="/cgi-bin/koha/members/apikeys.pl?borrowernumber=[% borrowernumber %]">Manage API keys</a></li>
175
                [% ELSE %]
176
                    <li class="disabled"><a data-toggle="tooltip" data-placement="left" title="You are not authorized to manage API keys" id="apikeys" href="#">Manage API keys</a></li>
177
                [% END %]
173
                [% IF ( CAN_user_borrowers ) %]
178
                [% IF ( CAN_user_borrowers ) %]
174
                    [% IF ( NorwegianPatronDBEnable == 1 ) %]
179
                    [% IF ( NorwegianPatronDBEnable == 1 ) %]
175
                        <li><a id="deletepatronlocal" href="#">Delete local</a></li>
180
                        <li><a id="deletepatronlocal" href="#">Delete local</a></li>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/members/apikeys.tt (+78 lines)
Line 0 Link Here
1
[% USE Koha %]
2
[% INCLUDE 'doc-head-open.inc' %]
3
<title>Koha &rsaquo; Patrons &rsaquo; API Keys</title>
4
[% INCLUDE 'doc-head-close.inc' %]
5
</head>
6
<body id="pat_apikeys" class="pat">
7
[% INCLUDE 'header.inc' %]
8
[% INCLUDE 'patron-search.inc' %]
9
10
<div id="breadcrumbs">
11
  <a href="/cgi-bin/koha/mainpage.pl">Home</a>
12
  &rsaquo;
13
  <a href="/cgi-bin/koha/members/members-home.pl">Patrons</a>
14
  &rsaquo;
15
  API Keys for [% INCLUDE 'patron-title.inc' %]
16
</div>
17
18
<div id="doc3" class="yui-t2">
19
  <div id="bd">
20
    <div id="yui-main">
21
      <div class="yui-b">
22
        [% INCLUDE 'members-toolbar.inc' %]
23
24
        <h1>API keys for [% INCLUDE 'patron-title.inc' %]</h1>
25
        <div>
26
          <form action="/cgi-bin/koha/members/apikeys.pl" method="post">
27
            <input type="hidden" name="borrowernumber" value="[% borrowernumber %]">
28
            <input type="hidden" name="op" value="generate">
29
            <input id="generatenewkey" type="submit" value="Generate new key">
30
          </form>
31
        </div>
32
        [% IF api_keys.size > 0 %]
33
          <table id="apikeystable">
34
            <thead>
35
              <tr>
36
                <th>Key</th>
37
                <th>Active</th>
38
                <th>Last transaction</th>
39
                <th>Actions</th>
40
              </tr>
41
            </thead>
42
            <tbody>
43
              [% FOREACH key IN api_keys %]
44
                <tr>
45
                  <td class="apikeykey">[% key.api_key %]</td>
46
                  <td class="apikeyactive">[% IF key.active %]Yes[% ELSE %]No[% END %]</td>
47
                  <td class="apikeylastransaction">[% key.last_request_time || '' %]</td>
48
                  <td>
49
                    <form action="/cgi-bin/koha/members/apikeys.pl" method="post">
50
                      <input type="hidden" name="borrowernumber" value="[% borrowernumber %]">
51
                      <input type="hidden" name="key" value="[% key.api_key %]">
52
                      <input type="hidden" name="op" value="delete">
53
                      <input class="apikeydelete" type="submit" value="Delete">
54
                    </form>
55
                    <form action="/cgi-bin/koha/members/apikeys.pl" method="post">
56
                      <input type="hidden" name="borrowernumber" value="[% borrowernumber %]">
57
                      <input type="hidden" name="key" value="[% key.api_key %]">
58
                      [% IF key.active %]
59
                        <input type="hidden" name="op" value="revoke">
60
                        <input class="apikeyrevoke" type="submit" value="Revoke">
61
                      [% ELSE %]
62
                        <input type="hidden" name="op" value="activate">
63
                        <input class="apikeyactivate" type="submit" value="Activate">
64
                      [% END %]
65
                    </form>
66
                  </td>
67
                </tr>
68
              [% END %]
69
            </tbody>
70
          </table>
71
        [% END %]
72
      </div>
73
    </div>
74
    <div class="yui-b">
75
      [% INCLUDE 'circ-menu.inc' %]
76
    </div>
77
  </div>
78
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/includes/usermenu.inc (+8 lines)
Lines 1-3 Link Here
1
[% USE Koha %]
1
[% IF ( ( Koha.Preference( 'opacuserlogin' ) == 1 ) && loggedinusername ) %]
2
[% IF ( ( Koha.Preference( 'opacuserlogin' ) == 1 ) && loggedinusername ) %]
2
    <div id="menu">
3
    <div id="menu">
3
        <h4><a href="#" class="menu-collapse-toggle">Your account menu</a></h4>
4
        <h4><a href="#" class="menu-collapse-toggle">Your account menu</a></h4>
Lines 102-107 Link Here
102
                [% END %]
103
                [% END %]
103
                <a href="/cgi-bin/koha/opac-discharge.pl">ask for a discharge</a></li>
104
                <a href="/cgi-bin/koha/opac-discharge.pl">ask for a discharge</a></li>
104
            [% END %]
105
            [% END %]
106
107
            [% IF apikeysview %]
108
              <li class="active">
109
            [% ELSE %]
110
              <li>
111
            [% END %]
112
              <a href="/cgi-bin/koha/opac-apikeys.pl">your API keys</a></li>
105
        </ul>
113
        </ul>
106
    </div>
114
    </div>
107
[% END %]
115
[% END %]
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-apikeys.tt (+82 lines)
Line 0 Link Here
1
[% INCLUDE 'doc-head-open.inc' %]
2
<title>[% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha online[% END %] catalog &rsaquo; Your library home &rsaquo; Your API keys</title>
3
[% INCLUDE 'doc-head-close.inc' %]
4
[% BLOCK cssinclude %][% END %]
5
</head>
6
[% INCLUDE 'bodytag.inc' bodyid='opac-user' bodyclass='scrollto' %]
7
[% INCLUDE 'masthead.inc' %]
8
9
<div class="main">
10
    <ul class="breadcrumb">
11
        <li><a href="/cgi-bin/koha/opac-main.pl">Home</a> <span class="divider">&rsaquo;</span></li>
12
        <li>
13
          <a href="/cgi-bin/koha/opac-user.pl">
14
            [% INCLUDE 'patron-title.inc' category_type = borrower.category_type firstname = borrower.firstname surname = borrower.surname othernames = borrower.othernames %]
15
          </a>
16
          <span class="divider">&rsaquo;</span>
17
        </li>
18
        <li><a href="/cgi-bin/koha/opac-apikeys.pl">Your API keys</a></li>
19
    </ul>
20
21
    <div class="container-fluid">
22
        <div class="row-fluid">
23
            <div class="span2">
24
                <div id="navigation">
25
                    [% INCLUDE 'navigation.inc' IsPatronPage = 1 %]
26
                </div>
27
            </div>
28
            <div class="span10">
29
                <div id="apikeys" class="maincontent">
30
                  <h1>Your API keys</h1>
31
                  <div>
32
                    <form action="/cgi-bin/koha/opac-apikeys.pl" method="post">
33
                      <input type="hidden" name="op" value="generate">
34
                      <input id="generatenewkey" type="submit" value="Generate new key">
35
                    </form>
36
                  </div>
37
                  [% IF api_keys.size > 0 %]
38
                    <table id="apikeystable" class="table table-bordered table-striped">
39
                      <thead>
40
                        <tr>
41
                          <th>Key</th>
42
                          <th>Active</th>
43
                          <th>Last transaction</th>
44
                          <th>Actions</th>
45
                        </tr>
46
                      </thead>
47
                      <tbody>
48
                        [% FOREACH key IN api_keys %]
49
                          <tr>
50
                            <td class="apikeykey">[% key.api_key %]</td>
51
                            <td class="apikeyactive">[% IF key.active %]Yes[% ELSE %]No[% END %]</td>
52
                            <td class="apikeylastransaction">[% key.last_request_time || '' %]</td>
53
                            <td>
54
                              <form action="/cgi-bin/koha/opac-apikeys.pl" method="post" class="form-inline">
55
                                <input type="hidden" name="key" value="[% key.api_key %]">
56
                                <input type="hidden" name="op" value="delete">
57
                                <input class="apikeydelete" type="submit" value="Delete">
58
                              </form>
59
                              <form action="/cgi-bin/koha/opac-apikeys.pl" method="post" class="form-inline">
60
                                <input type="hidden" name="key" value="[% key.api_key %]">
61
                                [% IF key.active %]
62
                                  <input type="hidden" name="op" value="revoke">
63
                                  <input class="apikeyrevoke" type="submit" value="Revoke">
64
                                [% ELSE %]
65
                                  <input type="hidden" name="op" value="activate">
66
                                  <input class="apikeyactivate" type="submit" value="Activate">
67
                                [% END %]
68
                              </form>
69
                            </td>
70
                          </tr>
71
                        [% END %]
72
                      </tbody>
73
                    </table>
74
                  [% END %]
75
                </div> <!-- /#apikeys -->
76
            </div> <!-- /.span10 -->
77
        </div> <!-- /.row-fluid -->
78
    </div> <!-- /.container-fluid -->
79
</div> <!-- /#main -->
80
81
[% BLOCK jsinclude %][% END %]
82
[% INCLUDE 'opac-bottom.inc' %]
(-)a/members/apikeys.pl (+82 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2015 BibLibre
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
22
use CGI;
23
use String::Random;
24
25
use C4::Auth;
26
use C4::Members;
27
use C4::Output;
28
use Koha::ApiKeys;
29
use Koha::ApiKey;
30
31
my $cgi = new CGI;
32
33
my ($template, $loggedinuser, $cookie) = get_template_and_user({
34
    template_name => 'members/apikeys.tt',
35
    query => $cgi,
36
    type => 'intranet',
37
    authnotrequired => 0,
38
    flagsrequired => {borrowers => 'manage_api_keys'},
39
});
40
41
my $borrowernumber = $cgi->param('borrowernumber');
42
my $borrower = C4::Members::GetMember(borrowernumber => $borrowernumber);
43
my $op = $cgi->param('op');
44
45
if ($op) {
46
    if ($op eq 'generate') {
47
        Koha::ApiKeys->grant($borrower);
48
        print $cgi->redirect('/cgi-bin/koha/members/apikeys.pl?borrowernumber=' . $borrowernumber);
49
        exit;
50
    }
51
52
    if ($op eq 'delete') {
53
        my $key = $cgi->param('key');
54
        Koha::ApiKeys->delete($key);
55
        print $cgi->redirect('/cgi-bin/koha/members/apikeys.pl?borrowernumber=' . $borrowernumber);
56
        exit;
57
    }
58
59
    if ($op eq 'revoke') {
60
        my $key = $cgi->param('key');
61
        Koha::ApiKeys->revoke($key);
62
        print $cgi->redirect('/cgi-bin/koha/members/apikeys.pl?borrowernumber=' . $borrowernumber);
63
        exit;
64
    }
65
66
    if ($op eq 'activate') {
67
        my $key = $cgi->param('key');
68
        Koha::ApiKeys->activate($key);
69
        print $cgi->redirect('/cgi-bin/koha/members/apikeys.pl?borrowernumber=' . $borrowernumber);
70
        exit;
71
    }
72
}
73
74
my @api_keys = Koha::ApiKeys->search({borrowernumber => $borrowernumber});
75
76
$template->param(
77
    api_keys => \@api_keys,
78
    borrower => $borrower,
79
    borrowernumber => $borrowernumber,
80
);
81
82
output_html_with_http_headers $cgi, $cookie, $template->output;
(-)a/opac/opac-apikeys.pl (+81 lines)
Line 0 Link Here
1
#!/usr/bin/env perl
2
3
# Copyright 2015 BibLibre
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
22
use CGI;
23
use String::Random;
24
25
use C4::Auth;
26
use C4::Members;
27
use C4::Output;
28
use Koha::ApiKeys;
29
30
my $cgi = new CGI;
31
32
my ($template, $loggedinuser, $cookie) = get_template_and_user({
33
    template_name => 'opac-apikeys.tt',
34
    query => $cgi,
35
    type => 'opac',
36
    authnotrequired => 0,
37
});
38
39
my $borrowernumber = $loggedinuser;
40
my $borrower = C4::Members::GetMember(borrowernumber => $borrowernumber);
41
my $op = $cgi->param('op');
42
43
if ($op) {
44
    if ($op eq 'generate') {
45
        Koha::ApiKeys->grant($borrower);
46
        print $cgi->redirect('/cgi-bin/koha/opac-apikeys.pl');
47
        exit;
48
    }
49
50
    if ($op eq 'delete') {
51
        my $key = $cgi->param('key');
52
        Koha::ApiKeys->delete($key);
53
        print $cgi->redirect('/cgi-bin/koha/opac-apikeys.pl');
54
        exit;
55
    }
56
57
    if ($op eq 'revoke') {
58
        my $key = $cgi->param('key');
59
        Koha::ApiKeys->revoke($key);
60
        print $cgi->redirect('/cgi-bin/koha/opac-apikeys.pl');
61
        exit;
62
    }
63
64
    if ($op eq 'activate') {
65
        my $key = $cgi->param('key');
66
        Koha::ApiKeys->activate($key);
67
        print $cgi->redirect('/cgi-bin/koha/opac-apikeys.pl');
68
        exit;
69
    }
70
}
71
72
my @api_keys = Koha::ApiKeys->search({borrowernumber => $borrowernumber});
73
74
$template->param(
75
    apikeysview => 1,
76
    api_keys => \@api_keys,
77
    borrower => $borrower,
78
    borrowernumber => $borrowernumber,
79
);
80
81
output_html_with_http_headers $cgi, $cookie, $template->output;
(-)a/t/db_dependent/Koha/ApiKeys.t (+124 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2015 Vaara-kirjastot
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
use Test::More;
22
use Try::Tiny;
23
use Scalar::Util qw(blessed);
24
25
use Koha::Auth::PermissionManager;
26
use Koha::ApiKeys;
27
28
use t::lib::TestObjects::ObjectFactory;
29
use t::lib::TestObjects::BorrowerFactory;
30
use t::lib::Page::Members::Moremember;
31
use t::lib::Page::Opac::OpacMain;
32
33
##Setting up the test context
34
my $testContext = {};
35
36
my $password = '1234';
37
my $borrowerFactory = t::lib::TestObjects::BorrowerFactory->new();
38
my $borrowers = $borrowerFactory->createTestGroup([
39
            {firstname  => 'Olli-Antti',
40
             surname    => 'Kivi',
41
             cardnumber => '1A01',
42
             branchcode => 'CPL',
43
             password   => $password,
44
            },
45
            {firstname  => 'Alli-Ontti',
46
             surname    => 'Ivik',
47
             cardnumber => '1A02',
48
             branchcode => 'CPL',
49
             password   => $password,
50
            },
51
        ], undef, $testContext);
52
my $borrowerKivi = $borrowers->{'1A01'};
53
my $borrowerIvik = $borrowers->{'1A02'};
54
my $permissionManager = Koha::Auth::PermissionManager->new();
55
$permissionManager->grantPermission($borrowerKivi, 'borrowers', 'manage_api_keys');
56
57
58
##Test context set, starting testing:
59
eval { #run in a eval-block so we don't die without tearing down the test context
60
subtest "ApiKeys API Unit tests" => sub {
61
    my $borrowerKivi = $borrowers->{'1A01'};
62
    my $borrowerIvik = $borrowers->{'1A02'};
63
64
65
    my $apiKey = Koha::ApiKeys->grant($borrowerKivi);
66
    is($apiKey->borrowernumber, $borrowerKivi->borrowernumber, "ApiKey granted");
67
68
    Koha::ApiKeys->revoke($apiKey);
69
    is($apiKey->active, 0, "ApiKey revoked");
70
71
    Koha::ApiKeys->activate($apiKey);
72
    is($apiKey->active, 1, "ApiKey activated");
73
74
    Koha::ApiKeys->grant($borrowerIvik, $apiKey);
75
    is($apiKey->borrowernumber, $borrowerIvik->borrowernumber, "ApiKey granted to another Borrower");
76
77
    Koha::ApiKeys->delete($apiKey);
78
    $apiKey = Koha::ApiKeys->find({api_key_id => $apiKey->api_key_id});
79
    ok(not($apiKey), "ApiKey deleted");
80
}
81
};
82
if ($@) { #Catch all leaking errors and gracefully terminate.
83
    warn $@;
84
    tearDown();
85
    exit 1;
86
}
87
88
eval {
89
subtest "ApiKeys Intra Integration tests" => sub {
90
    my $agent = t::lib::Page::Members::Moremember->new({borrowernumber => $borrowerKivi->borrowernumber});
91
    $agent->doPasswordLogin($borrowerKivi->userid, $password)->navigateManageApiKeys()->generateNewApiKey();
92
    my @apiKeys = Koha::ApiKeys->search({borrowernumber => $borrowerKivi->borrowernumber});
93
    $agent->revokeApiKey($apiKeys[0]->api_key)->deleteApiKey($apiKeys[0]->api_key)
94
               ->quit();
95
}
96
};
97
if ($@) { #Catch all leaking errors and gracefully terminate.
98
    warn $@;
99
    tearDown();
100
    exit 1;
101
}
102
103
eval {
104
subtest "ApiKeys OPAC Integration tests" => sub {
105
    my $agent = t::lib::Page::Opac::OpacMain->new();
106
    $agent->doPasswordLogin($borrowerKivi->userid, $password)->navigateYourAPIKeys()->generateNewApiKey();
107
    my @apiKeys = Koha::ApiKeys->search({borrowernumber => $borrowerKivi->borrowernumber});
108
    $agent->revokeApiKey($apiKeys[0]->api_key)->deleteApiKey($apiKeys[0]->api_key)
109
               ->quit();
110
}
111
};
112
if ($@) { #Catch all leaking errors and gracefully terminate.
113
    warn $@;
114
    tearDown();
115
    exit 1;
116
}
117
118
##All tests done, tear down test context
119
tearDown();
120
done_testing;
121
122
sub tearDown {
123
    t::lib::TestObjects::ObjectFactory->tearDownTestContext($testContext);
124
}
(-)a/t/lib/Page/Members/ApiKeys.pm (+200 lines)
Line 0 Link Here
1
package t::lib::Page::Members::ApiKeys;
2
3
# Copyright 2015 KohaSuomi!
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
use Scalar::Util qw(blessed);
22
use Test::More;
23
24
use base qw(t::lib::Page::Intra t::lib::Page::Members::Toolbar);
25
26
use Koha::Exception::BadParameter;
27
use Koha::Exception::UnknownObject;
28
29
=head NAME t::lib::Page::Members::ApiKeys
30
31
=head SYNOPSIS
32
33
apikeys.pl PageObject providing page functionality as a service!
34
35
=cut
36
37
=head new
38
39
    my $apikeys = t::lib::Page::Members::ApiKeys->new({borrowernumber => "1"});
40
41
Instantiates a WebDriver and loads the members/apikeys.pl.
42
@PARAM1 HASHRef of optional and MANDATORY parameters
43
MANDATORY extra parameters:
44
    borrowernumber => loads the page to display Borrower matching the given borrowernumber
45
46
@RETURNS t::lib::Page::Members::ApiKeys, ready for user actions!
47
=cut
48
49
sub new {
50
    my ($class, $params) = @_;
51
    unless (ref($params) eq 'HASH' || (blessed($params) && $params->isa('t::lib::Page') )) {
52
        $params = {};
53
    }
54
    $params->{resource} = '/cgi-bin/koha/members/apikeys.pl';
55
    $params->{type}     = 'staff';
56
57
    $params->{getParams} = [];
58
    #Handle MANDATORY parameters
59
    if ($params->{borrowernumber}) {
60
        push @{$params->{getParams}}, "borrowernumber=".$params->{borrowernumber};
61
    }
62
    else {
63
        Koha::Exception::BadParameter->throw(error => __PACKAGE__."->new():> Parameter 'borrowernumber' is missing.");
64
    }
65
66
    my $self = $class->SUPER::new($params);
67
68
    return $self;
69
}
70
71
################################################################################
72
=head UI Mapping helper subroutines
73
See. Selenium documentation best practices for UI element mapping to common language descriptions.
74
=cut
75
################################################################################
76
77
=head _getActionsAndTableElements
78
@RETURNS List of
79
         HASHRef of Selenium::Driver::Webelement-objects matching the generic
80
                 actions on this page, eg. 'generateNewKey'.
81
         HASHRef of Selenium::Driver::Webelement-objects keyed with the apiKey hash/text.
82
                 These are all the apiKey table rows present, and have the
83
                 elements prefetched for easy access.
84
                 
85
=cut
86
87
sub _getActionsAndTableElements {
88
    my ($self) = @_;
89
    my $d = $self->getDriver();
90
91
    my $generateNewKeySubmit = $d->find_element("#generatenewkey", 'css');
92
93
    my $a = {}; #Collect action elements here
94
    $a->{generateNewKey} = $generateNewKeySubmit; #Bind the global action here for easy reference.
95
96
    my $apiKeyRows;
97
    eval { #We might not have ApiKeys yet.
98
        $apiKeyRows = $d->find_elements("#apikeystable tr", 'css');
99
        shift @$apiKeyRows; #Remove the table header row
100
    };
101
    my %apiKeys;
102
    for(my $i=0 ; $i<scalar(@$apiKeyRows) ; $i++) {
103
        #Iterate every apiKey in the apiKeys table and prefetch the interesting data as text and available action elements.
104
        my $row = $apiKeyRows->[$i];
105
        $row->{'nth-of-type'} = $i+1; #starts from 1
106
        $row->{key} = $d->find_child_element($row, "td.apikeykey", 'css')->get_text();
107
        $row->{active} = $d->find_child_element($row, "td.apikeyactive", 'css')->get_text();
108
        $row->{lastTransaction} = $d->find_child_element($row, "td.apikeylastransaction", 'css')->get_text();
109
        $row->{delete} = $d->find_child_element($row, "input.apikeydelete", 'css');
110
        eval {
111
            $row->{revoke} = $d->find_child_element($row, "input.apikeyrevoke", 'css');
112
        };
113
        eval {
114
            $row->{activate} = $d->find_child_element($row, "input.apikeyactivate", 'css');
115
        };
116
        $apiKeys{$row->{key}} = $row;
117
    }
118
119
    return ($a, \%apiKeys);
120
}
121
122
123
124
################################################################################
125
=head PageObject Services
126
127
=cut
128
################################################################################
129
130
sub generateNewApiKey {
131
    my ($self) = @_;
132
    my $d = $self->getDriver();
133
    $self->debugTakeSessionSnapshot();
134
135
    my ($actionElements, $apiKeyRows) = $self->_getActionsAndTableElements();
136
    my $apiKeyRowsCountPre = (ref $apiKeyRows eq 'HASH') ? scalar(keys(%$apiKeyRows)) : 0;
137
    $actionElements->{generateNewKey}->click();
138
    $self->debugTakeSessionSnapshot();
139
140
    ($actionElements, $apiKeyRows) = $self->_getActionsAndTableElements();
141
    my $apiKeyRowsCountPost = (ref $apiKeyRows eq 'HASH') ? scalar(keys(%$apiKeyRows)) : 0;
142
    is($apiKeyRowsCountPre+1, $apiKeyRowsCountPost, "ApiKey generated");
143
    return $self;
144
}
145
146
sub revokeApiKey {
147
    my ($self, $apiKey) = @_;
148
    my $d = $self->getDriver();
149
    $self->debugTakeSessionSnapshot();
150
151
    my ($actionElements, $apiKeyRows) = $self->_getActionsAndTableElements();
152
    my $apiKeyRow = $apiKeyRows->{$apiKey};
153
    Koha::Exception::UnknownObject->throw(error => __PACKAGE__."revokeApiKey():> No matching apiKey '$apiKey' found.") unless $apiKeyRow;
154
    $apiKeyRow->{revoke}->click();
155
    $self->debugTakeSessionSnapshot();
156
157
    ($actionElements, $apiKeyRows) = $self->_getActionsAndTableElements();
158
    $apiKeyRow = $apiKeyRows->{$apiKey};
159
    Koha::Exception::UnknownObject->throw(error => __PACKAGE__."revokeApiKey():> No matching apiKey '$apiKey' found after revoking it.") unless $apiKeyRow;
160
    is($apiKeyRow->{active}, 'No', "ApiKey revoked");
161
    return $self;
162
}
163
164
sub activateApiKey {
165
    my ($self, $apiKey) = @_;
166
    my $d = $self->getDriver();
167
    $self->debugTakeSessionSnapshot();
168
169
    my ($actionElements, $apiKeyRows) = $self->_getActionsAndTableElements();
170
    my $apiKeyRow = $apiKeyRows->{$apiKey};
171
    Koha::Exception::UnknownObject->throw(error => __PACKAGE__."revokeApiKey():> No matching apiKey '$apiKey' found.") unless $apiKeyRow;
172
    $apiKeyRow->{activate}->click();
173
    $self->debugTakeSessionSnapshot();
174
175
    ($actionElements, $apiKeyRows) = $self->_getActionsAndTableElements();
176
    $apiKeyRow = $apiKeyRows->{$apiKey};
177
    Koha::Exception::UnknownObject->throw(error => __PACKAGE__."revokeApiKey():> No matching apiKey '$apiKey' found after activating it.") unless $apiKeyRow;
178
    is($apiKeyRow->{active}, 'Yes', "ApiKey activated");
179
    return $self;
180
}
181
182
sub deleteApiKey {
183
    my ($self, $apiKey) = @_;
184
    my $d = $self->getDriver();
185
    $self->debugTakeSessionSnapshot();
186
187
    my ($actionElements, $apiKeyRows) = $self->_getActionsAndTableElements();
188
    my $apiKeyRowsCountPre = (ref $apiKeyRows eq 'HASH') ? scalar(keys(%$apiKeyRows)) : 0;
189
    my $apiKeyRow = $apiKeyRows->{$apiKey};
190
    Koha::Exception::UnknownObject->throw(error => __PACKAGE__."revokeApiKey():> No matching apiKey '$apiKey' found.") unless $apiKeyRow;
191
    $apiKeyRow->{delete}->click();
192
    $self->debugTakeSessionSnapshot();
193
194
    ($actionElements, $apiKeyRows) = $self->_getActionsAndTableElements();
195
    my $apiKeyRowsCountPost = (ref $apiKeyRows eq 'HASH') ? scalar(keys(%$apiKeyRows)) : 0;
196
    is($apiKeyRowsCountPre-1, $apiKeyRowsCountPost, "ApiKey deleted");
197
    return $self;
198
}
199
200
1; #Make the compiler happy!
(-)a/t/lib/Page/Members/MemberFlags.pm (-1 / +1 lines)
Lines 22-28 use Test::More; Link Here
22
22
23
use t::lib::Page::Members::Moremember;
23
use t::lib::Page::Members::Moremember;
24
24
25
use base qw(t::lib::Page::Intra);
25
use base qw(t::lib::Page::Intra t::lib::Page::Members::Toolbar);
26
26
27
=head NAME t::lib::Page::Members::MemberFlags
27
=head NAME t::lib::Page::Members::MemberFlags
28
28
(-)a/t/lib/Page/Members/Moremember.pm (-2 / +4 lines)
Lines 20-26 package t::lib::Page::Members::Moremember; Link Here
20
use Modern::Perl;
20
use Modern::Perl;
21
use Scalar::Util qw(blessed);
21
use Scalar::Util qw(blessed);
22
22
23
use base qw(t::lib::Page::Intra);
23
use base qw(t::lib::Page::Intra t::lib::Page::Members::Toolbar);
24
25
use t::lib::Page::Members::ApiKeys;
24
26
25
use Koha::Exception::BadParameter;
27
use Koha::Exception::BadParameter;
26
28
Lines 86-89 See. Selenium documentation best practices for UI element mapping to common lang Link Here
86
88
87
89
88
90
89
1; #Make the compiler happy!
91
1; #Make the compiler happy!
(-)a/t/lib/Page/Members/Toolbar.pm (+135 lines)
Line 0 Link Here
1
package t::lib::Page::Members::Toolbar;
2
3
# Copyright 2015 KohaSuomi!
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
use Test::More;
22
23
use Koha::Exception::BadParameter;
24
25
=head NAME t::lib::Page::Members::Toolbar
26
27
=head SYNOPSIS
28
29
PageObject Accessory encapsulating specific page-related functionality.
30
Is a static class and should not be attached to the instantiated PageObject.
31
this way we preserve the interoperability of the UserAgent when it moves from page
32
to page.
33
34
In this case this encapsulates the members-module toolbar's services and provides
35
a reusable class from all member-module PageObjects.
36
37
=cut
38
39
################################################################################
40
=head UI Mapping helper subroutines
41
See. Selenium documentation best practices for UI element mapping to common language descriptions.
42
=cut
43
################################################################################
44
45
=head _getToolbarActionElements
46
Shares the same toolbar with moremember.pl
47
@RETURNS HASHRef of Selenium::Driver::Webelements matching all the clickable elements
48
                 in the actions toolbar over the Borrower information.
49
=cut
50
51
sub _getToolbarActionElements {
52
    my ($self) = @_;
53
    my $d = $self->getDriver();
54
55
    my $editA = $d->find_element("#editpatron", 'css');
56
    my $changePasswordA = $d->find_element("#changepassword", 'css');
57
    my $duplicateA = $d->find_element("#duplicate", 'css');
58
    my $printButton = $d->find_element("#duplicate + div > button", 'css');
59
    my $searchToHoldA = $d->find_element("#searchtohold", 'css');
60
    my $moreButton = $d->find_element("#searchtohold + div > button", 'css');
61
62
    my $e = {};
63
    $e->{edit} = $editA if $editA;
64
    $e->{changePassword} = $changePasswordA if $changePasswordA;
65
    $e->{duplicate} = $duplicateA if $duplicateA;
66
    $e->{print} = $printButton if $printButton;
67
    $e->{searchToHold} = $searchToHoldA if $searchToHoldA;
68
    $e->{more} = $moreButton if $moreButton;
69
    return $e;
70
}
71
72
=head _getMoreDropdownElements
73
Clicks the dropdown open if it isnt yet.
74
@RETURNS HASHRef of all the dropdown elements under the More button in the toolbar
75
                 over Borrower information.
76
=cut
77
78
sub _getMoreDropdownElements {
79
    my ($self) = @_;
80
    my $d = $self->getDriver();
81
82
    my $toolbarElements = $self->_getToolbarActionElements();
83
    my $moreButton = $toolbarElements->{more};
84
    my $deleteA;
85
    eval {
86
        $deleteA = $d->find_child_element($moreButton, "#deletepatron", 'css');
87
    };
88
    unless ($deleteA && $deleteA->is_visible()) {
89
        $moreButton->click();
90
        $self->debugTakeSessionSnapshot();
91
    }
92
93
    my $renewPatronA      = $d->find_element("#renewpatron", 'css');
94
    my $setPermissionsA   = $d->find_element("#patronflags", 'css');
95
    my $manageApiKeysA    = $d->find_element("#apikeys", 'css');
96
       $deleteA           = $d->find_element("#deletepatron", 'css');
97
    $self->debugTakeSessionSnapshot();
98
    my $updateChildToAdultPatronA = $d->find_element("#updatechild", 'css');
99
    my $exportCheckinBarcodesA = $d->find_element("#exportcheckins", 'css');
100
101
    my $e = {};
102
    $e->{renewPatron}     = $renewPatronA if $renewPatronA;
103
    $e->{setPermissions}  = $setPermissionsA if $setPermissionsA;
104
    $e->{manageApiKeys}   = $manageApiKeysA if $manageApiKeysA;
105
    $e->{delete}          = $deleteA if $deleteA;
106
    $e->{updateChildToAdultPatron} = $updateChildToAdultPatronA if $updateChildToAdultPatronA;
107
    $e->{exportCheckinBarcodes} = $exportCheckinBarcodesA if $exportCheckinBarcodesA;
108
    return $e;
109
}
110
111
112
################################################################################
113
=head PageObject Services
114
115
=cut
116
################################################################################
117
118
sub navigateManageApiKeys {
119
    my ($self) = @_;
120
    my $d = $self->getDriver();
121
    $self->debugTakeSessionSnapshot();
122
123
    my $elements = $self->_getMoreDropdownElements();
124
    $elements->{manageApiKeys}->click();
125
    ok($d->get_title() =~ m/API Keys/, "Intra Navigate to Manage API Keys");
126
127
    $self->debugTakeSessionSnapshot();
128
129
    return t::lib::Page::Members::ApiKeys->rebrandFromPageObject($self);
130
}
131
132
133
134
135
1; #Make the compiler happy!
(-)a/t/lib/Page/Opac/LeftNavigation.pm (+109 lines)
Line 0 Link Here
1
package t::lib::Page::Opac::LeftNavigation;
2
3
# Copyright 2015 Open Source Freedom Fighters
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
use Scalar::Util qw(blessed);
22
use Test::More;
23
24
use t::lib::Page::Opac::OpacApiKeys;
25
26
=head NAME t::lib::Page::Opac::LeftNavigation
27
28
=head SYNOPSIS
29
30
Provides the services of the Opac left navigation column/frame for the implementing PageObject
31
32
=cut
33
34
################################################################################
35
=head UI Mapping helper subroutines
36
See. Selenium documentation best practices for UI element mapping to common language descriptions.
37
=cut
38
################################################################################
39
40
=head _getLeftNavigationActionElements
41
@RETURNS HASHRef of Selenium::Driver::Webelements matching all the clickable elements
42
                 in the left navigation frame/column at all Opac pages requiring login.
43
=cut
44
45
sub _getLeftNavigationActionElements {
46
    my ($self) = @_;
47
    my $d = $self->getDriver();
48
49
    my $e = {};
50
    eval {
51
        $e->{yourSummary} = $d->find_element("a[href*='opac-user.pl']", 'css');
52
    };
53
    eval {
54
        $e->{yourFines}   = $d->find_element("a[href*='opac-account.pl']", 'css');
55
    };
56
    eval {
57
        $e->{yourPersonalDetails} = $d->find_element("a[href*='opac-memberentry.pl']", 'css');
58
    };
59
    eval {
60
        $e->{yourTags}    = $d->find_element("a[href*='opac-tags.pl']", 'css');
61
    };
62
    eval {
63
        $e->{changeYourPassword} = $d->find_element("a[href*='opac-passwd.pl']", 'css');
64
    };
65
    eval {
66
        $e->{yourSearchHistory} = $d->find_element("a[href*='opac-search-history.pl']", 'css');
67
    };
68
    eval {
69
        $e->{yourReadingHistory} = $d->find_element("a[href*='opac-readingrecord.pl']", 'css');
70
    };
71
    eval {
72
        $e->{yourPurchaseSuggestions} = $d->find_element("a[href*='opac-suggestions.pl']", 'css');
73
    };
74
    eval {
75
        $e->{yourLists} = $d->find_element("a[href*='opac-shelves.pl']", 'css');
76
    };
77
    eval {
78
        $e->{yourAPIKeys} = $d->find_element("a[href*='opac-apikeys.pl']", 'css');
79
    };
80
    return $e;
81
}
82
83
84
85
################################################################################
86
=head PageObject Services
87
88
=cut
89
################################################################################
90
91
sub navigateYourAPIKeys {
92
    my ($self) = @_;
93
    my $d = $self->getDriver();
94
    $self->debugTakeSessionSnapshot();
95
96
    my $elements = $self->_getLeftNavigationActionElements();
97
    $elements->{yourAPIKeys}->click();
98
    $self->debugTakeSessionSnapshot();
99
100
    my $breadcrumbs = $self->_getBreadcrumbLinks();
101
102
    ok(ref($breadcrumbs) eq 'ARRAY' &&
103
       $breadcrumbs->[scalar(@$breadcrumbs)-1]->get_text() =~ m/API keys/i,
104
       "Opac Navigate to Your API Keys");
105
106
    return t::lib::Page::Opac::OpacApiKeys->rebrandFromPageObject($self);
107
}
108
109
1; #Make the compiler happy!
(-)a/t/lib/Page/Opac/OpacApiKeys.pm (+170 lines)
Line 0 Link Here
1
package t::lib::Page::Opac::OpacApiKeys;
2
3
# Copyright 2015 KohaSuomi!
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
use Scalar::Util qw(blessed);
22
use Test::More;
23
24
use base qw(t::lib::Page::Opac t::lib::Page::Opac::LeftNavigation);
25
26
use Koha::Exception::BadParameter;
27
use Koha::Exception::UnknownObject;
28
29
=head NAME t::lib::Page::Members::ApiKeys
30
31
=head SYNOPSIS
32
33
apikeys.pl PageObject providing page functionality as a service!
34
35
=cut
36
37
sub new {
38
    Koha::Exception::FeatureUnavailable->throw(error => __PACKAGE__."->new():> You must login first to navigate to this page!");
39
}
40
41
################################################################################
42
=head UI Mapping helper subroutines
43
See. Selenium documentation best practices for UI element mapping to common language descriptions.
44
=cut
45
################################################################################
46
47
=head _getActionsAndTableElements
48
@RETURNS List of
49
         HASHRef of Selenium::Driver::Webelement-objects matching the generic
50
                 actions on this page, eg. 'generateNewKey'.
51
         HASHRef of Selenium::Driver::Webelement-objects keyed with the apiKey hash/text.
52
                 These are all the apiKey table rows present, and have the
53
                 elements prefetched for easy access.
54
                 
55
=cut
56
57
sub _getActionsAndTableElements {
58
    my ($self) = @_;
59
    my $d = $self->getDriver();
60
61
    my $generateNewKeySubmit = $d->find_element("#generatenewkey", 'css');
62
63
    my $a = {}; #Collect action elements here
64
    $a->{generateNewKey} = $generateNewKeySubmit; #Bind the global action here for easy reference.
65
66
    my $apiKeyRows;
67
    eval { #We might not have ApiKeys yet.
68
        $apiKeyRows = $d->find_elements("#apikeystable tr", 'css');
69
        shift @$apiKeyRows; #Remove the table header row
70
    };
71
    my %apiKeys;
72
    for(my $i=0 ; $i<scalar(@$apiKeyRows) ; $i++) {
73
        #Iterate every apiKey in the apiKeys table and prefetch the interesting data as text and available action elements.
74
        my $row = $apiKeyRows->[$i];
75
        $row->{'nth-of-type'} = $i+1; #starts from 1
76
        $row->{key} = $d->find_child_element($row, "td.apikeykey", 'css')->get_text();
77
        $row->{active} = $d->find_child_element($row, "td.apikeyactive", 'css')->get_text();
78
        $row->{lastTransaction} = $d->find_child_element($row, "td.apikeylastransaction", 'css')->get_text();
79
        $row->{delete} = $d->find_child_element($row, "input.apikeydelete", 'css');
80
        eval {
81
            $row->{revoke} = $d->find_child_element($row, "input.apikeyrevoke", 'css');
82
        };
83
        eval {
84
            $row->{activate} = $d->find_child_element($row, "input.apikeyactivate", 'css');
85
        };
86
        $apiKeys{$row->{key}} = $row;
87
    }
88
89
    return ($a, \%apiKeys);
90
}
91
92
93
94
################################################################################
95
=head PageObject Services
96
97
=cut
98
################################################################################
99
100
sub generateNewApiKey {
101
    my ($self) = @_;
102
    my $d = $self->getDriver();
103
    $self->debugTakeSessionSnapshot();
104
105
    my ($actionElements, $apiKeyRows) = $self->_getActionsAndTableElements();
106
    my $apiKeyRowsCountPre = (ref $apiKeyRows eq 'HASH') ? scalar(keys(%$apiKeyRows)) : 0;
107
    $actionElements->{generateNewKey}->click();
108
    $self->debugTakeSessionSnapshot();
109
110
    ($actionElements, $apiKeyRows) = $self->_getActionsAndTableElements();
111
    my $apiKeyRowsCountPost = (ref $apiKeyRows eq 'HASH') ? scalar(keys(%$apiKeyRows)) : 0;
112
    is($apiKeyRowsCountPre+1, $apiKeyRowsCountPost, "ApiKey generated");
113
    return $self;
114
}
115
116
sub revokeApiKey {
117
    my ($self, $apiKey) = @_;
118
    my $d = $self->getDriver();
119
    $self->debugTakeSessionSnapshot();
120
121
    my ($actionElements, $apiKeyRows) = $self->_getActionsAndTableElements();
122
    my $apiKeyRow = $apiKeyRows->{$apiKey};
123
    Koha::Exception::UnknownObject->throw(error => __PACKAGE__."revokeApiKey():> No matching apiKey '$apiKey' found.") unless $apiKeyRow;
124
    $apiKeyRow->{revoke}->click();
125
    $self->debugTakeSessionSnapshot();
126
127
    ($actionElements, $apiKeyRows) = $self->_getActionsAndTableElements();
128
    $apiKeyRow = $apiKeyRows->{$apiKey};
129
    Koha::Exception::UnknownObject->throw(error => __PACKAGE__."revokeApiKey():> No matching apiKey '$apiKey' found after revoking it.") unless $apiKeyRow;
130
    is($apiKeyRow->{active}, 'No', "ApiKey revoked");
131
    return $self;
132
}
133
134
sub activateApiKey {
135
    my ($self, $apiKey) = @_;
136
    my $d = $self->getDriver();
137
    $self->debugTakeSessionSnapshot();
138
139
    my ($actionElements, $apiKeyRows) = $self->_getActionsAndTableElements();
140
    my $apiKeyRow = $apiKeyRows->{$apiKey};
141
    Koha::Exception::UnknownObject->throw(error => __PACKAGE__."revokeApiKey():> No matching apiKey '$apiKey' found.") unless $apiKeyRow;
142
    $apiKeyRow->{activate}->click();
143
    $self->debugTakeSessionSnapshot();
144
145
    ($actionElements, $apiKeyRows) = $self->_getActionsAndTableElements();
146
    $apiKeyRow = $apiKeyRows->{$apiKey};
147
    Koha::Exception::UnknownObject->throw(error => __PACKAGE__."revokeApiKey():> No matching apiKey '$apiKey' found after activating it.") unless $apiKeyRow;
148
    is($apiKeyRow->{active}, 'Yes', "ApiKey activated");
149
    return $self;
150
}
151
152
sub deleteApiKey {
153
    my ($self, $apiKey) = @_;
154
    my $d = $self->getDriver();
155
    $self->debugTakeSessionSnapshot();
156
157
    my ($actionElements, $apiKeyRows) = $self->_getActionsAndTableElements();
158
    my $apiKeyRowsCountPre = (ref $apiKeyRows eq 'HASH') ? scalar(keys(%$apiKeyRows)) : 0;
159
    my $apiKeyRow = $apiKeyRows->{$apiKey};
160
    Koha::Exception::UnknownObject->throw(error => __PACKAGE__."revokeApiKey():> No matching apiKey '$apiKey' found.") unless $apiKeyRow;
161
    $apiKeyRow->{delete}->click();
162
    $self->debugTakeSessionSnapshot();
163
164
    ($actionElements, $apiKeyRows) = $self->_getActionsAndTableElements();
165
    my $apiKeyRowsCountPost = (ref $apiKeyRows eq 'HASH') ? scalar(keys(%$apiKeyRows)) : 0;
166
    is($apiKeyRowsCountPre-1, $apiKeyRowsCountPost, "ApiKey deleted");
167
    return $self;
168
}
169
170
1; #Make the compiler happy!
(-)a/t/lib/Page/Opac/OpacSearchHistory.pm (-1 / +1 lines)
Lines 20-26 package t::lib::Page::Opac::OpacSearchHistory; Link Here
20
use Modern::Perl;
20
use Modern::Perl;
21
use Test::More;
21
use Test::More;
22
22
23
use base qw(t::lib::Page::Opac);
23
use base qw(t::lib::Page::Opac t::lib::Page::Opac::LeftNavigation);
24
24
25
use Koha::Exception::FeatureUnavailable;
25
use Koha::Exception::FeatureUnavailable;
26
26
(-)a/t/lib/Page/Opac/OpacUser.pm (-3 / +2 lines)
Lines 19-25 package t::lib::Page::Opac::OpacUser; Link Here
19
19
20
use Modern::Perl;
20
use Modern::Perl;
21
21
22
use base qw(t::lib::Page::Opac);
22
use base qw(t::lib::Page::Opac t::lib::Page::Opac::LeftNavigation);
23
23
24
use Koha::Exception::FeatureUnavailable;
24
use Koha::Exception::FeatureUnavailable;
25
25
Lines 61-64 See. Selenium documentation best practices for UI element mapping to common lang Link Here
61
61
62
62
63
63
64
1; #Make the compiler happy!
64
1; #Make the compiler happy!
65
- 

Return to bug 13799