From 2d1f4bcbb9cb9ce75609e860c2db635566d0086f Mon Sep 17 00:00:00 2001 From: Aleisha Amohia Date: Mon, 12 Dec 2016 02:41:59 +0000 Subject: [PATCH] Bug 15326: [FOLLOW-UP] Add CMS feature This patch builds on Martin Persson's patch. I made a few changes that improve the patch and make this feature functional. The only thing I am not completely satisfied with (and doesn't reliably work) is the navigation for the CMS pages on both the staff side and the OPAC side. This needs work. Otherwise the CMS feature works. - Make sure you update database after applying patch - After adding a few pages, confirm that filtering results works (play with different combinations of display location, library and language) - Confirm that pages with specific locations ONLY show up in those locations, i.e. OPAC pages can only be accessed in OPAC and staff interface pages can only be accessed on staff client - Confirm that table is showing correct data, particularly language, location and library - Confirm that if page has not been published and user does not have permission to edit pages, page content will not display on OPAC side. On staff side, a message will show saying that page has not been published - Confirm pagination for table shows and works - Confirm deleting pages works as expected (confirm message before delete) - Confirm link title must be unique when adding new pages - Confirm that editing the details of an existing page works - Confirm that adding a child page will only work if the location of child page matches location of parent page, i.e., if parent page is an OPAC page then child page must also be OPAC page. if parent page is in all locations then child page can be in all or either interface(s) - Confirm Select All/Clear All toggle works - Confirm viewing of CMS pages in OPAC and in staff client works and looks nice Sponsored-by: Region Halland --- Koha/CmsPage.pm | 2 +- Koha/CmsPages.pm | 78 ++++--- Koha/Schema/Result/Branch.pm | 16 +- Koha/Schema/Result/CmsPage.pm | 150 ++++++++++++ .../bug15326-add_cms_pages_permission.sql | 1 + .../intranet-tmpl/prog/en/includes/tools-menu.inc | 71 ++++-- .../prog/en/modules/tools/cmspages.tt | 259 +++++++++++++-------- .../opac-tmpl/bootstrap/en/includes/masthead.inc | 14 -- .../opac-tmpl/bootstrap/en/includes/navigation.inc | 27 ++- .../bootstrap/en/modules/opac-cmspages.tt | 56 ++--- koha-tmpl/opac-tmpl/bootstrap/less/opac.less | 40 +--- opac/opac-cmspages.pl | 14 +- opac/opac-main.pl | 14 +- tools/cmspages.pl | 41 ++-- 14 files changed, 521 insertions(+), 262 deletions(-) create mode 100644 Koha/Schema/Result/CmsPage.pm create mode 100644 installer/data/mysql/atomicupdate/bug15326-add_cms_pages_permission.sql diff --git a/Koha/CmsPage.pm b/Koha/CmsPage.pm index fd5b52a..cb333d0 100644 --- a/Koha/CmsPage.pm +++ b/Koha/CmsPage.pm @@ -39,7 +39,7 @@ Koha::CmsPage - Koha Page Object class =cut -sub type { +sub _type { return 'CmsPage'; } diff --git a/Koha/CmsPages.pm b/Koha/CmsPages.pm index b49881e..85a612f 100644 --- a/Koha/CmsPages.pm +++ b/Koha/CmsPages.pm @@ -40,7 +40,7 @@ Koha::CmsPage - Koha CMS Page Object Class =cut -sub type { +sub _type { return 'CmsPage'; } @@ -54,14 +54,13 @@ Adds a new page to the CMS database based on the input data. sub add { my ( $self, $input ) = @_; -warn "input: ", scalar $input->param('location'); carp( 'Koha::CmsPages::add() undefined parameter: input' ) unless defined $input; my $data = { - parent => scalar $input->param( 'parent' ) eq '' ? undef : scalar $input->param( 'parent' ), - location => scalar $input->param( 'location' ) eq '' ? undef : scalar $input->param( 'location'), - branchcode => scalar $input->param( 'branchcode' ) eq '' ? undef : scalar $input->param( 'branchcode' ), + parent => scalar $input->param( 'parent' ) eq '' ? undef : scalar $input->param( 'parent' ), + location => scalar $input->param( 'disp' ) eq '' ? undef : scalar $input->param( 'disp'), + branchcode => scalar $input->param( 'branch' ) eq '' ? undef : scalar $input->param( 'branch' ), lang => scalar $input->param( 'lang' ), - sortorder => scalar $input->param( 'sortorder' ), + sortorder => scalar $input->param( 'number' ), title => scalar $input->param( 'title' ), title_link => scalar $input->param( 'title_link' ), publish => defined (scalar $input->param( 'publish' )), @@ -72,6 +71,30 @@ warn "input: ", scalar $input->param('location'); $data->{'id'} = scalar $input->param( 'id' ); } + # Ensuring link titles are unique + my $title_link = $input->param('title_link'); + if ( Koha::CmsPages->find({ title_link => $title_link }) ) { + my $existing_link = Koha::CmsPages->find({ title_link => $title_link }); + my $link = $existing_link->unblessed; + unless ( $link->{'id'} eq $input->param('id') ) { + return undef; + } + } + + # Ensuring that, if page has parent, provided location suits parent location + my $parent = $input->param('parent'); + my $parent_obj = Koha::CmsPages->find($parent); + if ( $parent_obj ) { + my $parent_unblessed = $parent_obj->unblessed; + if ( $parent_unblessed->{'location'} ne "" ) { + # if parent location is not all interfaces + if ( $parent_unblessed->{'location'} != $input->param('disp') ) { + # if parent location is not the same as provided location + return undef; + } + } + } + my $new_page = $self->_resultset()->update_or_create( $data, { key => 'primary' }); return $new_page; @@ -86,15 +109,24 @@ Lists pages based input filtering paramters for location, branch and language. sub list { my ( $self, $id, $disp, $branch, $lang ) = @_; - my $filter = { }; - $filter->{'location'} = $disp unless not defined $disp; - $filter->{'branch'} = $branch unless not defined $branch; - $filter->{'lang'} = $lang unless not defined $lang; + my %filter; + if ($branch) { + my $branch_push = [ $branch, undef ]; + push @{$filter{'branchcode'}}, $branch_push; + } + if ($lang) { + my $lang_push = [ $lang, undef ]; + push @{$filter{'lang'}}, $lang_push; + } + if ($disp) { + my $disp_push = [ $disp, undef ]; + push @{$filter{'location'}}, $disp_push; + } - my $pages = $self->_resultset()->search( undef, { + my $pages = $self->_resultset()->search( {}, { order_by => { - -asc => [qw/parent location branchcode lang sortorder/] - }, where => $filter + -asc => [qw/parent location branchcode lang sortorder/] + }, where => { %filter } } ); my $page_list = []; @@ -143,20 +175,13 @@ Retrieves all data to show a single CMS page. =cut sub page { - my ( $self, $id ) = @_; - - carp( 'Missing CMS page id parameter in Koha::Pages::page' ) unless defined $id; - - # Probably want to merge these to a single query: - my $top_links = $self->_resultset()->search( - { parent => undef }, { qw/id title_link/ }); + my ( $self, $id ) = @_; - my $page_links = $self->_resultset()->search( - { parent => $id }, { qw/id title_link/ }); + carp( 'Missing CMS page id parameter in Koha::Pages::page' ) unless defined $id; - my $page_data = $self->_resultset()->find( $id ); + my $page_data = $self->_resultset()->find( $id ); - return ( $top_links, $page_links, $page_data ); + return $page_data; } =head3 child_links @@ -168,9 +193,8 @@ Lists pages which are children of a specific id (or undef for root). sub child_links { my ( $self, $id ) = @_; - # 'id' can be undefined if listing top-level links. - my $rs = $self->_resultset()->search({ parent => $id }, - { columns => [qw/id title_link/] } ); + # 'id' can be undefined if listing top-level links. + my $rs = $self->_resultset()->search({ parent => $id }, { qw/id title_link/ }); return $rs; } diff --git a/Koha/Schema/Result/Branch.pm b/Koha/Schema/Result/Branch.pm index aea24e7..6136e70 100644 --- a/Koha/Schema/Result/Branch.pm +++ b/Koha/Schema/Result/Branch.pm @@ -413,6 +413,21 @@ __PACKAGE__->has_many( { cascade_copy => 0, cascade_delete => 0 }, ); +=head2 cms_pages + +Type: has_many + +Related object: L + +=cut + +__PACKAGE__->has_many( + "cms_pages", + "Koha::Schema::Result::CmsPage", + { "foreign.branchcode" => "self.branchcode" }, + { cascade_copy => 0, cascade_delete => 0 }, +); + =head2 collections Type: has_many @@ -622,7 +637,6 @@ __PACKAGE__->many_to_many("categorycodes", "branchrelations", "categorycode"); # Created by DBIx::Class::Schema::Loader v0.07042 @ 2017-11-09 11:42:45 # DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:LmN2FlbKiZTRX+egCHuDjQ - # You can replace this text with custom code or comments, and it will be preserved on regeneration sub koha_objects_class { diff --git a/Koha/Schema/Result/CmsPage.pm b/Koha/Schema/Result/CmsPage.pm new file mode 100644 index 0000000..1136c1d --- /dev/null +++ b/Koha/Schema/Result/CmsPage.pm @@ -0,0 +1,150 @@ +use utf8; +package Koha::Schema::Result::CmsPage; + +# Created by DBIx::Class::Schema::Loader +# DO NOT MODIFY THE FIRST PART OF THIS FILE + +=head1 NAME + +Koha::Schema::Result::CmsPage + +=cut + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; + +=head1 TABLE: C + +=cut + +__PACKAGE__->table("cms_pages"); + +=head1 ACCESSORS + +=head2 id + + data_type: 'integer' + is_auto_increment: 1 + is_nullable: 0 + +=head2 parent + + data_type: 'integer' + is_nullable: 1 + +=head2 branchcode + + data_type: 'varchar' + is_foreign_key: 1 + is_nullable: 1 + size: 10 + +=head2 lang + + data_type: 'varchar' + default_value: (empty string) + is_nullable: 0 + size: 25 + +=head2 title + + data_type: 'varchar' + is_nullable: 1 + size: 255 + +=head2 title_link + + data_type: 'varchar' + is_nullable: 1 + size: 64 + +=head2 sortorder + + data_type: 'integer' + default_value: 0 + is_nullable: 0 + +=head2 location + + data_type: 'tinyint' + is_nullable: 1 + +=head2 publish + + data_type: 'tinyint' + default_value: 0 + is_nullable: 0 + +=head2 content + + data_type: 'text' + is_nullable: 1 + +=cut + +__PACKAGE__->add_columns( + "id", + { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, + "parent", + { data_type => "integer", is_nullable => 1 }, + "branchcode", + { data_type => "varchar", is_foreign_key => 1, is_nullable => 1, size => 10 }, + "lang", + { data_type => "varchar", default_value => "", is_nullable => 0, size => 25 }, + "title", + { data_type => "varchar", is_nullable => 1, size => 255 }, + "title_link", + { data_type => "varchar", is_nullable => 1, size => 64 }, + "sortorder", + { data_type => "integer", default_value => 0, is_nullable => 0 }, + "location", + { data_type => "tinyint", is_nullable => 1 }, + "publish", + { data_type => "tinyint", default_value => 0, is_nullable => 0 }, + "content", + { data_type => "text", is_nullable => 1 }, +); + +=head1 PRIMARY KEY + +=over 4 + +=item * L + +=back + +=cut + +__PACKAGE__->set_primary_key("id"); + +=head1 RELATIONS + +=head2 branchcode + +Type: belongs_to + +Related object: L + +=cut + +__PACKAGE__->belongs_to( + "branchcode", + "Koha::Schema::Result::Branch", + { branchcode => "branchcode" }, + { + is_deferrable => 1, + join_type => "LEFT", + on_delete => "CASCADE", + on_update => "CASCADE", + }, +); + + +# Created by DBIx::Class::Schema::Loader v0.07042 @ 2016-12-12 02:41:09 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:9044j1OZyypCpGV71FgvYg + + +# You can replace this text with custom code or comments, and it will be preserved on regeneration +1; diff --git a/installer/data/mysql/atomicupdate/bug15326-add_cms_pages_permission.sql b/installer/data/mysql/atomicupdate/bug15326-add_cms_pages_permission.sql new file mode 100644 index 0000000..72ce00f --- /dev/null +++ b/installer/data/mysql/atomicupdate/bug15326-add_cms_pages_permission.sql @@ -0,0 +1 @@ +INSERT IGNORE INTO permissions (`module_bit`, `code`, `description`) VALUES ('13', 'edit_pages', 'Create, edit and delete CMS pages for OPAC and staff interfaces'); diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/tools-menu.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/tools-menu.inc index 50e52f7..be90f2e 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/tools-menu.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/tools-menu.inc @@ -1,3 +1,23 @@ + + [% END # / OpacPublic %] diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/includes/navigation.inc b/koha-tmpl/opac-tmpl/bootstrap/en/includes/navigation.inc index 89921a0..c0e2d6f 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/includes/navigation.inc +++ b/koha-tmpl/opac-tmpl/bootstrap/en/includes/navigation.inc @@ -1,12 +1,23 @@
-[% IF ( cms_nav_left ) %] - -[% END %] -[% OpacNav %]
+ [% IF ( links ) %] +

Pages

+
    + [% FOREACH link IN links %] + [% IF ( link.publish == '1' || link.publish == '0' && CAN_user_tools_edit_pages ) %] + [% IF ( link.location == '' || link.location == '2' ) %] + [% IF ( link.parent != '' ) %] + [% FOREACH parent IN parent_list %] + [% IF ( parent.id == link.parent ) %]
  • [% parent.title_link %][% link.title_link %]
  • [% END %] + [% END %] + [% ELSE %] +
  • [% link.title_link %]
  • + [% END %] + [% END %][% END %] + [% END %] +
+ [% END %] + [% OpacNav %] + [% IF IsPatronPage %]
[% INCLUDE usermenu.inc %]
[% END %] diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-cmspages.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-cmspages.tt index 9bc3e35..88811ef 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-cmspages.tt +++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-cmspages.tt @@ -1,7 +1,7 @@ [% USE Koha %] [% USE Branches %] [% INCLUDE 'doc-head-open.inc' %] -[% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha online[% END %][% IF (cms_page.title) %] - [% cms_page.title %][% ELSE %] catalog[% END%] +[% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha online catalog[% END %][% IF (cms_page.title) %] › [% cms_page.title %][% END%] [% INCLUDE 'doc-head-close.inc' %] [% BLOCK cssinclude %][% END %] @@ -10,8 +10,12 @@
@@ -39,48 +43,16 @@ [% ELSE %]
[% END %] - [% cms_page.content %] + + [% IF ( cms_page.publish == 1 ) || ( cms_page.publish == 0 && CAN_user_tools_edit_pages ) %] + [% cms_page.content %] + [% ELSE %] + This page has not been published. + [% END %] + [% IF ( OpacMainUserBlock ) %]
[% OpacMainUserBlock %]
[% END %]
- [% IF ( ( Koha.Preference( 'opacuserlogin' ) == 1 ) || OpacNavRight ) %] -
- [% IF Koha.Preference( 'opacuserlogin' ) == 1 %] - [% UNLESS ( loggedinusername ) %] - [% UNLESS ( casAuthentication || shibbolethAuthentication ) %] -
-
- -
- Log in to your account: - - -
- -
- [% IF PatronSelfRegistration && PatronSelfRegistrationDefaultCategory %]

Don't have an account? Register here.

[% END %] -
- [% IF Koha.Preference( 'NoLoginInstructions' ) %] -
- [% Koha.Preference( 'NoLoginInstructions' ) %] -
- [% END %] -
-
- [% END # /casAuthentication %] - [% IF persona %] - Sign in with your email - [% END # /persona %] - [% END # / loggedinusername %] - [% END # /opacuserlogin %] - [% IF ( OpacNavRight ) %] -
- [% OpacNavRight %] -
- [% END # /OpacNavRight %] -
- [% END # /opacuserlogin || OpacNavRight %] -
diff --git a/koha-tmpl/opac-tmpl/bootstrap/less/opac.less b/koha-tmpl/opac-tmpl/bootstrap/less/opac.less index ace3dbc..ef10e69 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/less/opac.less +++ b/koha-tmpl/opac-tmpl/bootstrap/less/opac.less @@ -221,37 +221,15 @@ td { } #cms_nav_top { - li { - margin-bottom: -1em; - display: inline; - white-space: nowrap; - border-top-left-radius: 5px; - border-top-right-radius: 5px; - background-color: #eee; - border: 1px solid #D2D2CF; - border-bottom: none; - padding: 0.1em 0.8em 0em 0.8em; - font-weight: bold; - font-size: 1.2em; - border-bottom: 1px solid #D2D2CF; - a { - text-decoration: none; - } - &.cms_nav_top_active { - background-color: #fff; - border-bottom: 1px solid #FFF; - } - } - ul { - margin: 0; - display: inline; - } - display: inline; -} - -ul#cms_nav_left { - list-style-type: none; - padding: 0; + list-style-type: circle; + padding: 0; + margin: 0; + a { + text-decoration: none; + } + a:hover { + text-decoration: underline; + } } #news { diff --git a/opac/opac-cmspages.pl b/opac/opac-cmspages.pl index eaace18..f93f2b8 100755 --- a/opac/opac-cmspages.pl +++ b/opac/opac-cmspages.pl @@ -23,6 +23,7 @@ use C4::Auth; use C4::Output; use C4::Languages qw( getTranslatedLanguages accept_language ); use Koha::CmsPages; +use Data::Dumper; my $input = new CGI; my $id = scalar $input->param( 'id' ) // ''; @@ -42,11 +43,14 @@ my ( $template, $borrowernumber, $cookie ) = get_template_and_user( my ( $theme, $news_lang, $availablethemes ) = C4::Templates::themelanguage( C4::Context->config( 'opachtdocs'), 'opac-cmspages.tt', 'opac', $input ); -my ($cms_nav_top, $cms_nav_left, $cms_data) = Koha::CmsPages->page( $id ); +# List all pages, if id is set generate parent page list and data. +my ( $page_list, $parent_list, $page_data ) = Koha::CmsPages->list( $id ); + +my $links = Koha::CmsPages->search( {}, { order_by => 'sortorder' } ); +my $cms_data = Koha::CmsPages->page( $id ); $template->param( - cms_page => $cms_data, - cms_nav_top => $cms_nav_top, - cms_nav_left => $cms_nav_left, + links => $links, + cms_page => $cms_data, + parent_list => $parent_list, ); - output_html_with_http_headers $input, $cookie, $template->output; diff --git a/opac/opac-main.pl b/opac/opac-main.pl index 07253e0..b473988 100755 --- a/opac/opac-main.pl +++ b/opac/opac-main.pl @@ -29,7 +29,7 @@ use C4::Members; use C4::Overdues; use Koha::Checkouts; use Koha::Holds; -use Koha::CmsPages qw( list ); +use Koha::CmsPages; my $input = new CGI; my $dbh = C4::Context->dbh; @@ -96,9 +96,17 @@ $template->param( daily_quote => $quote, ); +my $id = scalar $input->param( 'id' ) // ''; +my ( $page_list, $parent_list, $page_data ) = Koha::CmsPages->list( $id ); +my $links = Koha::CmsPages->search( {}, { order_by => 'parent' } ); +my $cms_data = Koha::CmsPages->page( $id ); $template->param( - cms_nav_top => Koha::CmsPages->child_links( undef ), -); + links => $links, + cms_page => $cms_data, + parent_list => $parent_list, + ); + + if (C4::Context->preference('GoogleIndicTransliteration')) { $template->param('GoogleIndicTransliteration' => 1); diff --git a/tools/cmspages.pl b/tools/cmspages.pl index 314724a..846f5e1 100755 --- a/tools/cmspages.pl +++ b/tools/cmspages.pl @@ -23,8 +23,8 @@ use CGI qw( -utf8 ); use C4::Auth; use C4::Output; use C4::Languages qw( getTranslatedLanguages ); -use Koha::Database; use Koha::CmsPages; +use Koha::Libraries; my $link_self = '/cgi-bin/koha/tools/cmspages.pl'; @@ -50,17 +50,14 @@ $template->param( disp => $disp ); -my $schema = Koha::Database->new->schema; -my @branches = $schema->resultset( 'Branch' )->all; -$template->param( branch_list => @branches ); - my $lang_list = getTranslatedLanguages; +my $branches = Koha::Libraries->search( {}, { order_by => ['branchcode'] }, ); # List all pages, if id is set generate parent page list and data. my ( $page_list, $parent_list, $page_data ) = Koha::CmsPages->list( $id ); $template->param( - page_list_count => scalar $page_list, + branch_list => $branches, page_list => $page_list, parent_list => $parent_list, data => $page_data, @@ -74,17 +71,35 @@ if ( $op eq 'form' ) { id => $id, op => 'add' ); -} - -if ( $op eq 'add' ) { - Koha::CmsPages->add( $cgi ); - print $cgi->redirect( $link_self ); - +} elsif ( $op eq 'add' ) { + my $success = Koha::CmsPages->add( $cgi ); + unless ($success) { + $template->param( failed_add => 1 ); + } + if ($success) { + print $cgi->redirect( $link_self ); + } } elsif ( $op eq 'del' ) { # param => multi_param; no list-ctx warnings Koha::CmsPages->remove( $cgi->multi_param( 'ids' ) ); print $cgi->redirect( $link_self ); +} elsif ( $op eq 'view' ) { + my $cms_data = Koha::CmsPages->page( $id ); + my $links = Koha::CmsPages->search( {}, { order_by => 'sortorder' } ); + $template->param( + links => $links, + cms_page => $cms_data, + view => 1, + id => $id, + op => 'view', + ); +} elsif ( $op eq 'filter' ) { + my ( $page_list, $parent_list, $page_data ) = Koha::CmsPages->list( $id, $disp, $branch, $lang ); + $template->param( + page_list => $page_list, + parent_list => $parent_list, + data => $page_data, + ); } - $template->param( link_self => $link_self ); output_html_with_http_headers $cgi, $cookie, $template->output; -- 2.1.4