From 5f54469b5c4e53396ac35c2f4a7afbabe87becc8 Mon Sep 17 00:00:00 2001 From: Galen Charlton <gmc@equinoxinitiative.org> Date: Sun, 9 Jun 2019 18:54:04 -0400 Subject: [PATCH] LP#1832897: add tables, IDL, and seed data for carousels MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Carousels ^^^^^^^^^ This feature fully integrates the creation and management of book carousels into Evergreen, allowing for the display of book cover images on a libraryâs public catalog home page. Carousels may be animated or static. They can be manually maintained by staff or automatically maintained by Evergreen. Titles can appear in carousels based on newly cataloged items, recent returns, popularity, etc. Titles must have copies that are visible to the public catalog, be circulating, and holdable to appear in a carousel. Serial titles cannot be displayed in carousels. Administration ++++++++++++++ This feature introduces the concepts of Carousel Types, Carousels, and Carousel Library Mappings. The first can be administered in Server Administration while the latter two can be administerd in Local Administration. Carousel Types define the attributes of a carousel, such as whether it is automatically managed and how it is filtered. A carousel must be associated with a carousel type to function properly. There are five stock Carousel Types: * Newly Cataloged Items - titles appear automatically based on the active date of the titleâs copies * Recently Returned Items - titles appear automatically based on the mostly recently circulated copyâs check-in scan date and time * Top Circulated Titles - titles appear automatically based on the most circulated copies in the Item Libraries identified in the carousel definition; titles are chosen based on the number of action.circulation rows created during an interval specified in the carousel definition and includes both circulations and renewals * Newest Items by Shelving Location - titles appear automatically based on the active date and shelving location of the titleâs copies * Manual - titles are added and managed manually by library staff While additional Carousel Types can be added using the administration interface, new automatic types currently require additional Perl code to be recognized. Carousel definitions allow the operator to specify the type, owner, name and, for automatically-maintained types, the item libraries and shelving locations to look for titles to populate the carousels as well as how far back to look for titles. Carousel Library Mappings specify the libraries that the carousel should be displayed out. The visibility of a carousel at a given organizational unit is not automatically inherited by the descendants of that unit. The carouselâs owning organizational unit is automatically added to the list of display organizational units. A server-side job, refresh_carousels.srfsh, is available to periodically refresh the contents of automatic carousels. Staff Interface +++++++++++++++ Each carousel has a record bucket associated with it. Library staff can add titles to a carousel's bucket, and for the manual Carousel Type, that is the only way to populate the carousel. Records added to an automatic carousel's bucket will be removed whenever the carousel is next refreshed. Public Catalog ++++++++++++++ A new Template Toolkit macro called âcarouselsâ allows the Evergreen administrator to inject the contents of one or more carousels into any point in the OPAC. The macro will accept the following parameters: * carousel_id * dynamic (Boolean, default value false) * image_size (small, medium, or large) * width (number of titles to display on a âpaneâ of the carousel) * animated (Boolean to specify whether the carousel should automatically cycle through its panes) * animation_interval (the interval (in seconds) to wait before advancing to the next pane) If the carousel_id parameter is supplied, the carousel with that ID will be displayed. If carousel_id is not supplied, all carousels visible to the public catalogâs physical_loc organizational unit is displayed. Signed-off-by: Galen Charlton <gmc@equinoxinitiative.org> Signed-off-by: Bill Erickson <berickxx@gmail.com> Signed-off-by: Jane Sandberg <sandbej@linnbenton.edu> --- Open-ILS/examples/fm_IDL.xml | 88 ++++++++++++++++++++++ Open-ILS/src/sql/Pg/002.schema.config.sql | 21 ++++++ Open-ILS/src/sql/Pg/070.schema.container.sql | 25 ++++++ Open-ILS/src/sql/Pg/950.data.seed-values.sql | 9 ++- .../src/sql/Pg/upgrade/XXXX.schema.carousels.sql | 63 ++++++++++++++++ 5 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.schema.carousels.sql diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml index 544488e3f1..2fc7aa1b3a 100644 --- a/Open-ILS/examples/fm_IDL.xml +++ b/Open-ILS/examples/fm_IDL.xml @@ -12851,6 +12851,94 @@ SELECT usr, </permacrud> </class> + <class id="cct" + controller="open-ils.cstore open-ils.pcrud" + oils_obj:fieldmapper="config::carousel_type" + oils_persist:tablename="config.carousel_type" + reporter:label="Carousel Types"> + <fields oils_persist:primary="id" oils_persist:sequence="config.carousel_type_id_seq"> + <field reporter:label="Carousel Type ID" reporter:selector="name" name="id" reporter:datatype="id" /> + <field reporter:label="Name" name="name" reporter:datatype="text" oils_obj:required="true" oils_obj:i18n="true"/> + <field reporter:label="Automatically Managed?" name="automatic" reporter:datatype="bool"/> + <field reporter:label="Filter By Age?" name="filter_by_age" reporter:datatype="bool"/> + <field reporter:label="Filter By Item Owning Library?" name="filter_by_copy_owning_lib" reporter:datatype="bool"/> + <field reporter:label="Filter By Item Location?" name="filter_by_copy_location" reporter:datatype="bool"/> + </fields> + <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1"> + <actions> + <create permission="ADMIN_CAROUSEL_TYPE" global_required="true"/> + <retrieve/> + <update permission="ADMIN_CAROUSEL_TYPE" global_required="true"/> + <delete permission="ADMIN_CAROUSEL_TYPE" global_required="true"/> + </actions> + </permacrud> + </class> + + <class id="cc" + controller="open-ils.cstore open-ils.pcrud" + oils_obj:fieldmapper="container::carousel" + oils_persist:tablename="container.carousel" + reporter:label="Carousels"> + <fields oils_persist:primary="id" oils_persist:sequence="container.carousel_id_seq"> + <field reporter:label="Carousel ID" name="id" reporter:datatype="id" reporter:selector="name"/> + <field reporter:label="Carousel Type" name="type" reporter:datatype="link"/> + <field reporter:label="Owner" name="owner" reporter:datatype="link"/> + <field reporter:label="Name" name="name" reporter:datatype="text" oils_obj:required="true" oils_obj:i18n="true"/> + <field reporter:label="Bucket" name="bucket" reporter:datatype="link"/> + <field reporter:label="Creating User" name="creator" reporter:datatype="link"/> + <field reporter:label="Editing User" name="editor" reporter:datatype="link"/> + <field reporter:label="Create Time" name="create_time" reporter:datatype="timestamp"/> + <field reporter:label="Edit Time" name="edit_time" reporter:datatype="timestamp"/> + <field reporter:label="Age Limit" name="age_filter" reporter:datatype="interval"/> + <field reporter:label="Item Libraries" name="owning_lib_filter" reporter:datatype="text" /> <!-- Actually an int[], but this is the best we can do in fm_IDL.xml --> + <field reporter:label="Shelving Locations" name="copy_location_filter" reporter:datatype="text" /> <!-- ditto --> + <field reporter:label="Last Refresh Time" name="last_refresh_time" reporter:datatype="timestamp"/> + <field reporter:label="Is Active" name="active" reporter:datatype="bool"/> + <field reporter:label="Maximum Items" name="max_items" reporter:datatype="int"/> + </fields> + <links> + <link field="type" reltype="has_a" key="id" map="" class="cct"/> + <link field="owner" reltype="has_a" key="id" map="" class="aou"/> + <link field="bucket" reltype="has_a" key="id" map="" class="cbreb"/> + <link field="creator" reltype="has_a" key="id" map="" class="au"/> + <link field="editor" reltype="has_a" key="id" map="" class="au"/> + </links> + <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1"> + <actions> + <create permission="ADMIN_CAROUSEL" global_required="true"/> + <retrieve/> + <update permission="ADMIN_CAROUSEL" global_required="true"/> + <delete permission="ADMIN_CAROUSEL" global_required="true"/> + </actions> + </permacrud> + </class> + + <class id="ccou" + controller="open-ils.cstore open-ils.pcrud" + oils_obj:fieldmapper="container::carousel_org_unit" + oils_persist:tablename="container.carousel_org_unit" + reporter:label="Carousels Visible at Library"> + <fields oils_persist:primary="id" oils_persist:sequence="container.carousel_org_unit_id_seq"> + <field reporter:label="ID" name="id" reporter:datatype="id" /> + <field reporter:label="Carousel" name="carousel" reporter:datatype="link"/> + <field reporter:label="Override Name" name="override_name" reporter:datatype="text"/> + <field reporter:label="Library" name="org_unit" reporter:datatype="link"/> + <field reporter:label="Sequence Number" name="seq" reporter:datatype="int"/> + </fields> + <links> + <link field="carousel" reltype="has_a" key="id" map="" class="cc"/> + <link field="org_unit" reltype="has_a" key="id" map="" class="aou"/> + </links> + <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1"> + <actions> + <create permission="ADMIN_CAROUSEL" global_required="true"/> + <retrieve/> + <update permission="ADMIN_CAROUSEL" global_required="true"/> + <delete permission="ADMIN_CAROUSEL" global_required="true"/> + </actions> + </permacrud> + </class> + <!-- ********************************************************************************************************************* --> </IDL> diff --git a/Open-ILS/src/sql/Pg/002.schema.config.sql b/Open-ILS/src/sql/Pg/002.schema.config.sql index 5068463049..8afa76e79f 100644 --- a/Open-ILS/src/sql/Pg/002.schema.config.sql +++ b/Open-ILS/src/sql/Pg/002.schema.config.sql @@ -1349,4 +1349,25 @@ CREATE TABLE config.print_template ( CONSTRAINT label_once_per_lib UNIQUE (owner, label) ); +CREATE TABLE config.carousel_type ( + id SERIAL PRIMARY KEY, + name TEXT NOT NULL, + automatic BOOLEAN NOT NULL DEFAULT TRUE, + filter_by_age BOOLEAN NOT NULL DEFAULT FALSE, + filter_by_copy_owning_lib BOOLEAN NOT NULL DEFAULT FALSE, + filter_by_copy_location BOOLEAN NOT NULL DEFAULT FALSE +); + +INSERT INTO config.carousel_type + (id, name, automatic, filter_by_age, filter_by_copy_owning_lib, filter_by_copy_location) +VALUES + (1, 'Manual', FALSE, FALSE, FALSE, FALSE), + (2, 'Newly Catalogued Items', TRUE, TRUE, TRUE, TRUE), + (3, 'Recently Returned Items', TRUE, TRUE, TRUE, TRUE), + (4, 'Top Circulated Items', TRUE, TRUE, TRUE, FALSE), + (5, 'Newest Items By Shelving Location', TRUE, TRUE, TRUE, FALSE) +; + +SELECT SETVAL('config.carousel_type_id_seq'::TEXT, 100); + COMMIT; diff --git a/Open-ILS/src/sql/Pg/070.schema.container.sql b/Open-ILS/src/sql/Pg/070.schema.container.sql index 594dfafe58..8b1572f386 100644 --- a/Open-ILS/src/sql/Pg/070.schema.container.sql +++ b/Open-ILS/src/sql/Pg/070.schema.container.sql @@ -250,5 +250,30 @@ CREATE TABLE container.user_bucket_item_note ( note TEXT NOT NULL ); +CREATE TABLE container.carousel ( + id SERIAL PRIMARY KEY, + type INTEGER NOT NULL REFERENCES config.carousel_type (id), + owner INTEGER NOT NULL REFERENCES actor.org_unit (id), + name TEXT NOT NULL, + bucket INTEGER REFERENCES container.biblio_record_entry_bucket (id), + creator INTEGER NOT NULL REFERENCES actor.usr (id), + editor INTEGER NOT NULL REFERENCES actor.usr (id), + create_time TIMESTAMPTZ NOT NULL DEFAULT now(), + edit_time TIMESTAMPTZ NOT NULL DEFAULT now(), + age_filter INTERVAL, + owning_lib_filter INT[], + copy_location_filter INT[], + last_refresh_time TIMESTAMPTZ, + active BOOLEAN NOT NULL DEFAULT TRUE, + max_items INTEGER NOT NULL +); + +CREATE TABLE container.carousel_org_unit ( + id SERIAL PRIMARY KEY, + carousel INTEGER NOT NULL REFERENCES container.carousel (id) ON DELETE CASCADE, + override_name TEXT, + org_unit INTEGER NOT NULL REFERENCES actor.org_unit (id), + seq INTEGER NOT NULL +); COMMIT; diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql index 4d9d37615c..2627a08eb5 100644 --- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql +++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql @@ -1917,7 +1917,13 @@ INSERT INTO permission.perm_list ( id, code, description ) VALUES ( 610, 'CLEAR_PURCHASE_REQUEST', oils_i18n_gettext(610, 'Clear Completed User Purchase Requests', 'ppl', 'description')), ( 611, 'ADMIN_PRINT_TEMPLATE', oils_i18n_gettext(611, - 'Modify print templates', 'ppl', 'description')) + 'Modify print templates', 'ppl', 'description')), + ( 612, 'ADMIN_CAROUSEL_TYPE', oils_i18n_gettext(612, + 'Allow a user to manage carousel types', 'ppl', 'description')), + ( 613, 'ADMIN_CAROUSEL', oils_i18n_gettext(613, + 'Allow a user to manage carousels', 'ppl', 'description')), + ( 614, 'REFRESH_CAROUSEL', oils_i18n_gettext(614, + 'Allow a user to refresh carousels', 'ppl', 'description')) ; @@ -5652,6 +5658,7 @@ INSERT INTO container.biblio_record_entry_bucket_type (code,label) VALUES ('book INSERT INTO container.biblio_record_entry_bucket_type (code,label) VALUES ('reading_list', oils_i18n_gettext('reading_list', 'Reading List', 'cbrebt', 'label')); INSERT INTO container.biblio_record_entry_bucket_type (code,label) VALUES ('template_merge',oils_i18n_gettext('template_merge','Template Merge Container', 'cbrebt', 'label')); INSERT INTO container.biblio_record_entry_bucket_type (code,label) VALUES ('url_verify', oils_i18n_gettext('url_verify', 'URL Verification Queue', 'cbrebt', 'label')); +INSERT INTO container.biblio_record_entry_bucket_type (code,label) VALUES ('carousel', oils_i18n_gettext('url_verify', 'Carousel', 'cbrebt', 'label')); INSERT INTO container.user_bucket_type (code,label) VALUES ('misc', oils_i18n_gettext('misc', 'Miscellaneous', 'cubt', 'label')); INSERT INTO container.user_bucket_type (code,label) VALUES ('folks', oils_i18n_gettext('folks', 'Friends', 'cubt', 'label')); diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.carousels.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.carousels.sql new file mode 100644 index 0000000000..9dd366952e --- /dev/null +++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.carousels.sql @@ -0,0 +1,63 @@ +BEGIN; + +SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version); + +CREATE TABLE config.carousel_type ( + id SERIAL PRIMARY KEY, + name TEXT NOT NULL, + automatic BOOLEAN NOT NULL DEFAULT TRUE, + filter_by_age BOOLEAN NOT NULL DEFAULT FALSE, + filter_by_copy_owning_lib BOOLEAN NOT NULL DEFAULT FALSE, + filter_by_copy_location BOOLEAN NOT NULL DEFAULT FALSE +); + +INSERT INTO config.carousel_type + (id, name, automatic, filter_by_age, filter_by_copy_owning_lib, filter_by_copy_location) +VALUES + (1, 'Manual', FALSE, FALSE, FALSE, FALSE), + (2, 'Newly Catalogued Items', TRUE, TRUE, TRUE, TRUE), + (3, 'Recently Returned Items', TRUE, TRUE, TRUE, TRUE), + (4, 'Top Circulated Items', TRUE, TRUE, TRUE, FALSE), + (5, 'Newest Items By Shelving Location', TRUE, TRUE, TRUE, FALSE) +; + +SELECT SETVAL('config.carousel_type_id_seq'::TEXT, 100); + +CREATE TABLE container.carousel ( + id SERIAL PRIMARY KEY, + type INTEGER NOT NULL REFERENCES config.carousel_type (id), + owner INTEGER NOT NULL REFERENCES actor.org_unit (id), + name TEXT NOT NULL, + bucket INTEGER REFERENCES container.biblio_record_entry_bucket (id), + creator INTEGER NOT NULL REFERENCES actor.usr (id), + editor INTEGER NOT NULL REFERENCES actor.usr (id), + create_time TIMESTAMPTZ NOT NULL DEFAULT now(), + edit_time TIMESTAMPTZ NOT NULL DEFAULT now(), + age_filter INTERVAL, + owning_lib_filter INT[], + copy_location_filter INT[], + last_refresh_time TIMESTAMPTZ, + active BOOLEAN NOT NULL DEFAULT TRUE, + max_items INTEGER NOT NULL +); + +CREATE TABLE container.carousel_org_unit ( + id SERIAL PRIMARY KEY, + carousel INTEGER NOT NULL REFERENCES container.carousel (id) ON DELETE CASCADE, + override_name TEXT, + org_unit INTEGER NOT NULL REFERENCES actor.org_unit (id), + seq INTEGER NOT NULL +); + +INSERT INTO container.biblio_record_entry_bucket_type (code, label) VALUES ('carousel', 'Carousel'); + +INSERT INTO permission.perm_list ( id, code, description ) VALUES + ( 612, 'ADMIN_CAROUSEL_TYPE', oils_i18n_gettext(611, + 'Allow a user to manage carousel types', 'ppl', 'description')), + ( 613, 'ADMIN_CAROUSEL', oils_i18n_gettext(612, + 'Allow a user to manage carousels', 'ppl', 'description')), + ( 614, 'REFRESH_CAROUSEL', oils_i18n_gettext(613, + 'Allow a user to refresh carousels', 'ppl', 'description')) +; + +COMMIT; -- 2.11.0