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

(-)a/admin/domain_limits.pl (+35 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2023 Rijksmuseum, Koha development team
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 CGI qw ( -utf8 );
22
23
use C4::Auth qw( get_template_and_user );
24
use C4::Output qw( output_html_with_http_headers );
25
26
my $input = CGI->new;
27
my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
28
    {
29
        template_name => "admin/domain_limits.tt",
30
        query         => $input,
31
        type          => "intranet",
32
        flagsrequired => { parameters => 'manage_smtp_servers' },
33
    }
34
);
35
output_html_with_http_headers $input, $cookie, $template->output;
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/domain_limits.tt (+111 lines)
Line 0 Link Here
1
[% USE raw %]
2
[% USE Asset %]
3
[% SET footerjs = 1 %]
4
5
[% INCLUDE 'doc-head-open.inc' %]
6
<title>Domain limits &rsaquo; Administration &rsaquo; Koha</title>
7
[% INCLUDE 'doc-head-close.inc' %]
8
</head>
9
10
<body id="admin_domain_limits" class="admin">
11
[% INCLUDE 'header.inc' %]
12
[% INCLUDE 'prefs-admin-search.inc' %]
13
14
[% BLOCK modal_form %]
15
<div id="domain_limits_modal" class="modal" role="dialog" aria-hidden="true">
16
<div class="modal-dialog">
17
<div class="modal-content">
18
<form class="modal-form">
19
    <div class="modal-header">
20
        <h3 class="modal-title add">Add domain limit</h4>
21
        <h3 class="modal-title add_member">Add member</h4>
22
        <h3 class="modal-title edit edit_member">Edit domain limit</h4>
23
    </div>
24
    <div class="modal-body"><fieldset class="rows"><ul>
25
        <li class="add edit add_member edit_member"><label for="domain_name" class="">Domain name</label>
26
        <input type="text" name="domain_name" class="" required/></li>
27
28
        <li class="add edit"><label for="domain_limit">Message limit</label>
29
        <input type="text" name="domain_limit" class="toggle_validation" required inputmode="numeric" pattern="[0-9]*"/></li>
30
31
        <li class="add edit"><label for="units">Units</label></td>
32
        <input type="text" name="units" class="toggle_validation" required inputmode="numeric" pattern="[0-9]*"/></li>
33
34
        <li class="add edit"><label for="unit_type">Unit type</label>
35
        <select name="unit_type" class="toggle_validation" required>
36
            <option value="days"   >days   </option>
37
            <option value="hours"  >hours  </option>
38
            <option value="minutes">minutes</option>
39
        </select></li>
40
41
        <li class="add_member edit_member"><label for="group_domain">Group domain</label>
42
        <input type="text" name="group_domain" class="" disabled/></li>
43
    </ul></fieldset></div>
44
    <div class="modal-footer">
45
        <button class="btn btn-default save" data-dismiss="modal" role="button">Save</button>
46
        <button class="btn btn-default cancel" data-dismiss="modal" role="button">Cancel</button>
47
    </div>
48
</form>
49
</div>
50
</div>
51
</div>
52
[% END %]
53
54
[% WRAPPER 'sub-header.inc' %]
55
    [% WRAPPER breadcrumbs %]
56
        [% WRAPPER breadcrumb_item %]
57
            <a href="/cgi-bin/koha/admin/admin-home.pl">Administration</a>
58
        [% END %]
59
        [% WRAPPER breadcrumb_item bc_active= 1 %]
60
            <span>Domain limits</span>
61
        [% END %]
62
    [% END #/ WRAPPER breadcrumbs %]
63
[% END #/ WRAPPER sub-header.inc %]
64
65
<div class="main container-fluid">
66
    <div class="row">
67
    <div class="col-sm-10 col-sm-push-2">
68
    <main>
69
70
    <div class="dialog message" id="domain_limit_message" style="display:none;"></div>
71
    <div class="dialog alert"   id="domain_limit_alert"   style="display:none;"></div>
72
73
    <div id="toolbar" class="btn-toolbar">
74
        <a class="btn btn-default add" href="#"><i class="fa fa-plus"></i> New limit</a>
75
    </div>
76
77
    <h1>Domain limits</h1>
78
    <div class="page-section">
79
        <table id="domain_limits">
80
            <thead>
81
                <tr>
82
                    <th>Domain</th>
83
                    <th>Message limit</th>
84
                    <th>Units</th>
85
                    <th>Unit type</th>
86
                    <th>Belongs to</th>
87
                    <th data-class-name="actions noExport">Actions</th>
88
                </tr>
89
            </thead>
90
        </table>
91
        [% INCLUDE modal_form %]
92
    </div>
93
94
    </main>
95
    </div> <!-- /.col-sm-10.col-sm-push-2 -->
96
97
    <div class="col-sm-2 col-sm-pull-10">
98
        <aside>
99
            [% INCLUDE 'admin-menu.inc' %]
100
        </aside>
101
    </div>
102
    </div> <!-- /.row -->
103
<!-- /div in bottom include -->
104
105
[% MACRO jsinclude BLOCK %]
106
    [% Asset.js("js/admin-menu.js") | $raw %]
107
    [% INCLUDE 'datatables.inc' %]
108
    [% Asset.js("js/domain_limits.js") | $raw %]
109
[% END %]
110
111
[% INCLUDE 'intranet-bottom.inc' %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smtp_servers.tt (+1 lines)
Lines 244-249 Link Here
244
244
245
    <div id="toolbar" class="btn-toolbar">
245
    <div id="toolbar" class="btn-toolbar">
246
        <a class="btn btn-default" id="new_smtp_server" href="/cgi-bin/koha/admin/smtp_servers.pl?op=add_form"><i class="fa fa-plus"></i> New SMTP server</a>
246
        <a class="btn btn-default" id="new_smtp_server" href="/cgi-bin/koha/admin/smtp_servers.pl?op=add_form"><i class="fa fa-plus"></i> New SMTP server</a>
247
        <a class="btn btn-default" id="mail_domain_limits" href="/cgi-bin/koha/admin/domain_limits.pl">Domain limits</a>
247
    </div>
248
    </div>
248
249
249
    <h1>SMTP servers</h1>
250
    <h1>SMTP servers</h1>
(-)a/koha-tmpl/intranet-tmpl/prog/js/domain_limits.js (-1 / +246 lines)
Line 0 Link Here
0
- 
1
// domain_limits.js: Code for the corresponding admin form
2
3
var domain_limits_table;
4
$(document).ready(function() {
5
    domain_limits_table = init_table();
6
    $('#toolbar').on( "click", 'a.add', function (ev) {
7
        ev.preventDefault();
8
        start_modal( 'add' );
9
    });
10
    $('#domain_limits').on( "click", 'a.add_member', function (ev) {
11
        ev.preventDefault();
12
        start_modal( 'add_member', { belongs_to: $(this).parents('tr').attr('id') } );
13
    });
14
    $('#domain_limits').on( "click", 'a.edit, a.edit_member', function (ev) {
15
        ev.preventDefault();
16
        hide_dialogs();
17
        var limit_id = $(this).parents('tr').attr('id');
18
        api_get(limit_id);
19
    });
20
    $('#domain_limits').on( "click", 'a.delete', function (ev) {
21
        ev.preventDefault();
22
        hide_dialogs();
23
        if ( window.confirm( _("Delete this limit?") ) ) {
24
            var limit_id = $(this).parents('tr').attr('id');
25
            api_delete( limit_id );
26
        }
27
    });
28
    $('#domain_limits_modal').on( 'keydown', function(ev) {
29
        if ( ev.which == 27 ) { // respond to escape key
30
          $('#domain_limits_modal').hide();
31
          return false;
32
        }
33
    });
34
    $('#domain_limits_modal button.save').on( 'click', function() {
35
        if ( !$('#domain_limits_modal form').get(0).checkValidity() ) return; // Do not return false here to allow validation.
36
        var limit_id = $('#domain_limits_modal .modal-form').data('id');
37
        var row = get_modal_inputs();
38
        if ( limit_id ) api_put(limit_id, row); else api_post(row);
39
        return false;
40
    });
41
    $('#domain_limits_modal button.cancel').on( 'click', function() {
42
        $('#domain_limits_modal').hide();
43
        return false;
44
    });
45
});
46
47
function api_get (limit_id) {
48
    var row = domain_limits_table.DataTable().row('#'+limit_id).data();
49
    $.ajax({
50
        method: "GET",
51
        url: '/api/v1/smtp/domain_limits/' + limit_id,
52
    }).done(function (data) {
53
        start_modal( row.belongs_to ? 'edit_member' : 'edit', data );
54
    }).fail(function (xhr) {
55
        status_message( 'get', xhr.status, row );
56
    });
57
}
58
59
function api_delete (limit_id) {
60
    var limit_name = domain_limits_table.DataTable().row('#'+limit_id).data().domain_name;
61
    $.ajax({
62
        method: "DELETE",
63
        url: '/api/v1/smtp/domain_limits/' + limit_id,
64
    }).done(function () {
65
        domain_limits_table.api().ajax.reload();
66
        $('#domain_limit_message').html( _("Limit for '%s' deleted.").format(limit_name) ).show();
67
    }).fail(function (xhr) {
68
        status_message( 'delete', xhr.status, { domain_name: limit_name } );
69
    });
70
}
71
72
function api_post (row) {
73
    $.ajax({
74
        method: "POST",
75
        url: '/api/v1/smtp/domain_limits',
76
        data: JSON.stringify(row),
77
        contentType: 'application/json',
78
    }).done(function () {
79
        domain_limits_table.api().ajax.reload();
80
        $('#domain_limit_message').html( _("Limit for '%s' added.").format(row['domain_name']) ).show();
81
    }).fail(function (xhr, status, error) {
82
        status_message( 'post', xhr.status, row );
83
    }).always(function () {
84
        $('#domain_limits_modal').hide();
85
    });;
86
}
87
88
function api_put (limit_id, row) {
89
    $.ajax({
90
        method: "PUT",
91
        url: '/api/v1/smtp/domain_limits/' + limit_id,
92
        data: JSON.stringify(row),
93
        contentType: 'application/json',
94
    }).done(function () {
95
        domain_limits_table.api().ajax.reload();
96
        $('#domain_limit_message').html( _("Limit for '%s' modified.").format(row.domain_name) ).show();
97
    }).fail(function (xhr, status, error) {
98
        status_message( 'put', xhr.status, row );
99
    }).always(function () {
100
        $('#domain_limits_modal').hide();
101
    });
102
}
103
104
function status_message (method, status, row) { // only used in ajax.fail
105
    // Extending with parsing xhr.responseText seems not needed here (now).
106
    // POST and PUT may trigger similar exceptions, GET and DELETE are trivial.
107
    var messages = {
108
        delete          : _( "Deleting limit for '%s' failed." ),
109
        get             : _( "Retrieving limit for '%s' failed." ),
110
        put             : _( "Modifying limit for '%s' failed." ),
111
        post            : _( "Adding limit for '%s' failed." ),
112
        status_400      : _( " (Status 400 - Bad request: expected columns were empty.)" ),
113
        status_401      : _( " (Status 401 - Unauthorized: session may have expired.)" ),
114
        status_403      : _( " (Status 403 - Forbidden: check permissions.)" ),
115
        status_404      : _( " (Status 404 - Not found)" ),
116
        status_404_put  : _( " (Status 404 - Not found: group domain does not exist)" ),
117
        status_404_post : _( " (Status 404 - Not found: group domain does not exist)" ),
118
        status_409      : _( " (Status 409 - Conflict: duplicate domain name.)" ),
119
    };
120
    var str = messages['status_'+status+'_'+method] || messages['status_'+status] || '';
121
    $( '#domain_limit_alert' ).html( messages[method].format(row.domain_name) + str ).show();
122
}
123
124
function hide_dialogs () {
125
    $('div.dialog').html('').hide();
126
}
127
128
function get_actions_html (row) {
129
    var result = '';
130
    if ( row.belongs_to == undefined ) {
131
        result += '<a class="btn btn-default btn-xs edit" href="#"><i class="fa fa-pencil-alt"></i> '+_("Edit")+'</a>'+"\n";
132
        result += '<a class="btn btn-default btn-xs delete" href="#"><i class="fa fa-trash-can"></i> '+_("Delete")+'</a>'+"\n";
133
        result += '<a class="btn btn-default btn-xs add_member" href="#"><i class="fa fa-plus"></i> '+_("New member")+'</a>'+"\n";
134
    } else {
135
        result += '<a class="btn btn-default btn-xs edit_member" href="#"><i class="fa fa-pencil-alt"></i> '+_("Edit")+'</a>'+"\n";
136
        result += '<a class="btn btn-default btn-xs delete" href="#"><i class="fa fa-trash-can"></i> '+_("Delete")+'</a>'+"\n";
137
    }
138
    return result;
139
}
140
141
function get_modal_inputs () {
142
    var row = {};
143
    row.domain_name = $('input[name="domain_name"]').val();
144
    if( $('input[name="group_domain"]:visible').length ) {
145
        row.belongs_to = $('#domain_limits_modal .modal-form').data('belongs_to');
146
    } else {
147
        row.domain_limit = $('input[name="domain_limit"]').val();
148
        row.units = $('input[name="units"]').val();
149
        row.unit_type = $('select[name="unit_type"]').val();
150
    }
151
    return row;
152
}
153
154
function toggle_modal_inputs (action) {
155
    hide_dialogs();
156
    // Show one title
157
    $('h3.modal-title').hide().filter('.'+action).show()
158
    // Hide and disable some inputs (disable needed to skip validation)
159
    $('.modal-body li').hide().filter('.'+action).show();
160
    $('.modal-body .toggle_validation').prop('disabled', true);
161
    $('.modal-body li.'+action+' .toggle_validation').prop('disabled', false);
162
}
163
164
function fill_modal_inputs (action, row) {
165
    // Start by clearing
166
    $('#domain_limits_modal input').val('');
167
    $('#domain_limits_modal select').val('');
168
169
    if ( action=='edit' ) {
170
        for ( const field_name of [ 'domain_name', 'domain_limit', 'units' ] ) {
171
            $('#domain_limits_modal input[name="'+field_name+'"]').val(row[field_name]);
172
        }
173
        $('#domain_limits_modal select').val(row['unit_type']);
174
    } else if ( action=='edit_member' ) {
175
        $('#domain_limits_modal input[name="domain_name"]').val(row.domain_name);
176
        $('#domain_limits_modal input[name="group_domain"]').val(row.group_domain);
177
    } else if( action=='add_member' ) {
178
        $('#domain_limits_modal input[name="group_domain"]').val(row.group_domain);
179
    }
180
}
181
182
function start_modal (action, row) {
183
    toggle_modal_inputs(action);
184
    $('#domain_limits_modal .modal-form').data('id', row ? row.domain_limit_id : null).data('belongs_to', row ? row.belongs_to : null);
185
    if( action=='add_member' ) {
186
        // fetch group domain name from corresponding row
187
        var group_domain = domain_limits_table.DataTable().row('#' + row.belongs_to).data().domain_name;
188
        fill_modal_inputs( action, { group_domain: group_domain } );
189
    } else {
190
        fill_modal_inputs(action, row);
191
    }
192
    $('#domain_limits_modal').show().find('input')[0].focus();
193
}
194
195
function init_table () {
196
    return $("#domain_limits").kohaTable({
197
        "ajax": {
198
            "url": '/api/v1/smtp/domain_limits',
199
        },
200
        'language': {
201
            'emptyTable': '<div>'+_("There are no domain limits defined.")+'</div>'
202
        },
203
        "columnDefs": [ {
204
            "targets": [0,1,2,3,4],
205
            "render": function (data, type, row, meta) {
206
                if ( type == 'display' && data != null ) {
207
                    return data.escapeHtml();
208
                }
209
                return data;
210
            }
211
        } ],
212
        "columns": [
213
            {
214
                "data": "domain_name",
215
                "searchable": true,
216
                "orderable": true,
217
            },
218
            {
219
                "data": "domain_limit",
220
                "searchable": true,
221
                "orderable": true,
222
            },
223
            {
224
                "data": "units",
225
                "searchable": true,
226
                "orderable": true,
227
            },
228
            {
229
                "data": "unit_type",
230
                "searchable": true,
231
                "orderable": true,
232
            },
233
            {
234
                "data": "group_domain",
235
                "searchable": false,
236
                "orderable": false,
237
            },
238
            {
239
                "data": function( row, type, val, meta ) { return get_actions_html(row) },
240
                "searchable": false,
241
                "orderable": false
242
            }
243
        ],
244
        rowId: 'domain_limit_id',
245
    });
246
}

Return to bug 33537