From 8c80c55011f034a0e9dc29a0142ee8ec5378c532 Mon Sep 17 00:00:00 2001 From: Milan Date: Mon, 20 Mar 2023 23:09:11 +0100 Subject: [PATCH] help-texts: add users with permission edit_help_texts are allowed to select edit help texts from menu and enter texts for all event fields. Other users will see help texts as tooltips. This allows to provide help to users depending on your workflow. help texts are saved by project and studio. --- install/create.sql | 13 +- install/migrate.sql | 12 + lib/calcms/help_texts.pm | 105 ++++++++ .../agenda/planung/css/edit-help-texts.css | 3 + website/agenda/planung/help-texts.cgi | 237 ++++++++++++++++++ website/agenda/planung/js/edit-event.js | 17 +- .../agenda/planung/pot/de/edit-help-texts.po | 0 website/agenda/planung/pot/de/help-texts.po | 12 + website/agenda/planung/pot/de/menu.po | 4 + website/agenda/planung/pot/de/roles.po | 3 + .../agenda/planung/pot/en/edit-help-texts.po | 0 website/agenda/planung/pot/en/help-texts.po | 12 + website/agenda/planung/pot/en/menu.po | 3 + website/agenda/planung/pot/en/roles.po | 3 + website/agenda/planung/templates/default.html | 4 + .../planung/templates/edit-help-texts.html | 21 ++ 16 files changed, 447 insertions(+), 2 deletions(-) create mode 100644 lib/calcms/help_texts.pm create mode 100644 website/agenda/planung/css/edit-help-texts.css create mode 100644 website/agenda/planung/help-texts.cgi create mode 100644 website/agenda/planung/pot/de/edit-help-texts.po create mode 100644 website/agenda/planung/pot/de/help-texts.po create mode 100644 website/agenda/planung/pot/en/edit-help-texts.po create mode 100644 website/agenda/planung/pot/en/help-texts.po create mode 100644 website/agenda/planung/templates/edit-help-texts.html diff --git a/install/create.sql b/install/create.sql index 801ceff..11bc7a5 100644 --- a/install/create.sql +++ b/install/create.sql @@ -620,6 +620,7 @@ CREATE TABLE `calcms_roles` ( `delete_audio_recordings` tinyint unsigned NOT NULL, `read_playout` tinyint unsigned NOT NULL, `create_download` tinyint unsigned NOT NULL, + `edit_help_texts` INT(1) UNSIGNED NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `role_2` (`role`), KEY `project_id` (`project_id`), @@ -1767,4 +1768,14 @@ UNLOCK TABLES; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2023-02-19 23:01:42 \ No newline at end of file +-- Dump completed on 2023-02-19 23:01:42 + +CREATE TABLE `coloradio`.`calcms_help_texts` ( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `project_id` INT UNSIGNED NOT NULL, + `studio_id` INT UNSIGNED NOT NULL, + `lang` VARCHAR(5) NOT NULL, + `table` VARCHAR(45) NOT NULL, + `column` VARCHAR(45) NOT NULL, + `text` TEXT(500) NOT NULL, + PRIMARY KEY (`id`)); diff --git a/install/migrate.sql b/install/migrate.sql index 9e2b52e..78b4a4d 100644 --- a/install/migrate.sql +++ b/install/migrate.sql @@ -289,3 +289,15 @@ DROP INDEX `category` ; ; ALTER TABLE calcms_user_series DROP COLUMN active; + +CREATE TABLE `coloradio`.`calcms_help_texts` ( + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, + `project_id` INT UNSIGNED NOT NULL, + `studio_id` INT UNSIGNED NOT NULL, + `lang` VARCHAR(5) NOT NULL, + `table` VARCHAR(45) NOT NULL, + `column` VARCHAR(45) NOT NULL, + `text` TEXT(500) NOT NULL, + PRIMARY KEY (`id`)); + +ALTER TABLE `calcms_roles` ADD COLUMN `edit_help_texts` INT(1) UNSIGNED NOT NULL; diff --git a/lib/calcms/help_texts.pm b/lib/calcms/help_texts.pm new file mode 100644 index 0000000..f9f037c --- /dev/null +++ b/lib/calcms/help_texts.pm @@ -0,0 +1,105 @@ +package help_texts; + +use strict; +use warnings; +no warnings 'redefine'; + +use Data::Dumper; + +# table: calcms_help_texts +# columns: id, studio_id, series_id, +# table, column, text + +#use base 'Exporter'; +our @EXPORT_OK = qw(get_columns get insert update delete); + +sub get_columns($) { + my ($config) = @_; + my $dbh = db::connect($config); + return db::get_columns_hash( $dbh, 'calcms_help_texts' ); +} + +#map schedule id to id +sub get($$) { + my ($config, $condition) = @_; + + my $dbh = db::connect($config); + + my @conditions = (); + my @bind_values = (); + for my $col ('project_id', 'studio_id', 'lang', 'table', 'column', 'text') { + if ( ( defined $condition->{$col} ) && ( $condition->{$col} ne '' ) ) { + push @conditions, "`calcms_help_texts`.`$col`=?"; + push @bind_values, $condition->{$col}; + } + } + my $conditions = ''; + $conditions = " where " . join( " and ", @conditions ) if ( @conditions > 0 ); + my $query = qq{ + select * + from calcms_help_texts + $conditions + }; + my $entries = db::get( $dbh, $query, \@bind_values ); + return $entries; +} + +sub insert ($$) { + my ($config, $entry) = @_; + + for my $col ('project_id', 'studio_id', 'lang', 'table', 'column', 'text') { + return undef unless defined $entry->{$col}; + } + my $dbh = db::connect($config); + + return db::insert( $dbh, 'calcms_help_texts', $entry ); +} + +sub update ($$) { + my ($config, $entry) = @_; + + for my $col ('project_id', 'studio_id', 'lang', 'table', 'column', 'text') { + return undef unless defined $entry->{$col}; + } + my $dbh = db::connect($config); + my @keys = sort keys %$entry; + my $values = join( ",", map { "`$_`" . '=?' } @keys); + my @bind_values = map { $entry->{$_} } @keys; + for my $col ('project_id', 'studio_id', 'lang', 'table', 'column') { + push @bind_values, $entry->{$col}; + } + my $query = qq{ + update calcms_help_texts + set $values + where + `calcms_help_texts`.`project_id`=? + and `calcms_help_texts`.`studio_id`=? + and `calcms_help_texts`.`lang`=? + and `calcms_help_texts`.`table`=? + and `calcms_help_texts`.`column`=? + }; + return db::put( $dbh, $query, \@bind_values ); + print "done\n"; +} + +sub delete($$) { + my ($config, $entry) = @_; + + for my $col ('project_id', 'studio_id', 'lang', 'table', 'column', 'text') { + return undef unless defined $entry->{$col}; + } + my $dbh = db::connect($config); + my $query = qq{ + delete + from calcms_help_texts + where project_id=? and studio_id=? and lang=? and `calcms_help_texts`.`table`=? and `calcms_help_texts`.`column`=? + }; + my $bind_values = []; + for my $col ('project_id', 'studio_id', 'lang', 'table', 'column') { + push @$bind_values, $entry->{$col}; + } + return db::put( $dbh, $query, $bind_values ); +} + +#do not delete last line! +1; diff --git a/website/agenda/planung/css/edit-help-texts.css b/website/agenda/planung/css/edit-help-texts.css new file mode 100644 index 0000000..579f1d2 --- /dev/null +++ b/website/agenda/planung/css/edit-help-texts.css @@ -0,0 +1,3 @@ +textarea{ + width:100px; +} \ No newline at end of file diff --git a/website/agenda/planung/help-texts.cgi b/website/agenda/planung/help-texts.cgi new file mode 100644 index 0000000..b1c19aa --- /dev/null +++ b/website/agenda/planung/help-texts.cgi @@ -0,0 +1,237 @@ +#!/usr/bin/perl + +use strict; +use warnings; +no warnings 'redefine'; + +use Data::Dumper; +use URI::Escape(); +use params(); +use config(); +use entry(); +use template(); +use auth(); +use uac(); +use help_texts(); +use localization(); +use JSON; +binmode STDOUT, ":utf8"; + +my $r = shift; +( my $cgi, my $params, my $error ) = params::get($r); + +my $config = config::get('../config/config.cgi'); +my ( $user, $expires ) = auth::get_user( $config, $params, $cgi ); +return if ( ( !defined $user ) || ( $user eq '' ) ); + +my $user_presets = uac::get_user_presets( + $config, + { + project_id => $params->{project_id}, + studio_id => $params->{studio_id}, + user => $user + } +); +$params->{default_studio_id} = $user_presets->{studio_id}; +$params = uac::setDefaultStudio( $params, $user_presets ); +$params = uac::setDefaultProject( $params, $user_presets ); + +my $request = { + url => $ENV{QUERY_STRING} || '', + params => { + original => $params, + checked => check_params( $config, $params ), + }, +}; +$request = uac::prepare_request( $request, $user_presets ); +$params = $request->{params}->{checked}; +return get_help( $config, $request ) if $params->{action} eq 'get'; + +#process header +my $headerParams = uac::set_template_permissions( $request->{permissions}, $params ); +$headerParams->{loc} = localization::get( $config, { user => $user, file => 'menu' } ); +template::process( $config, 'print', template::check( $config, 'default.html' ), $headerParams ); +return unless uac::check( $config, $params, $user_presets ) == 1; + +if ( defined $params->{action} ) { + save_help( $config, $request ) if $params->{action} eq 'save'; + delete_help( $config, $request ) if $params->{action} eq 'delete'; +} +edit_help( $config, $request ); + +$config->{access}->{write} = 0; + +return; + +sub save_help { + my ($config, $request) = @_; + + my $params = $request->{params}->{checked}; + my $permissions = $request->{permissions}; + unless ( $permissions->{edit_help_texts} == 1 ) { + uac::permissions_denied('edit_help_texts'); + return; + } + + for my $attr ( 'project_id', 'studio_id', 'table', 'column', 'text' ) { + unless ( defined $params->{$attr} ) { + uac::print_error( $attr . ' not given!' ); + return; + } + } + + my $entry = {}; + for my $attr ('project_id', 'studio_id', 'table', 'column', 'text') { + $entry->{$attr} = $params->{$attr} if defined $params->{$attr}; + } + my $user_settings = user_settings::get( $config, { user => $user } ); + $entry->{lang} = $user_settings->{language} || 'en', + my $results = help_texts::get($config, { + project_id => $entry->{project_id}, + studio_id => $entry->{studio_id}, + lang => $entry->{lang}, + table => $entry->{table}, + column => $entry->{column}, + }); + $config->{access}->{write} = 1; + if ( @$results ) { + help_texts::update( $config, $entry ); + uac::print_info("help text saved."); + } else { + my $schedule_id = help_texts::insert( $config, $entry ); + uac::print_info("help text added."); + } + $config->{access}->{write} = 0; +} + +sub delete_help { + my ($config, $request) = @_; + my $params = $request->{params}->{checked}; + my $permissions = $request->{permissions}; + unless ( $permissions->{edit_help_texts} == 1 ) { + uac::permissions_denied('edit_help_texts'); + return; + } + + for my $attr ( 'project_id', 'studio_id', 'table', 'column', 'text' ) { + unless ( defined $params->{$attr} ) { + uac::print_error( $attr . ' not given!' ); + return; + } + } + + my $entry = {}; + for my $attr ('project_id', 'studio_id', 'table', 'column') { + $entry->{$attr} = $params->{$attr} if defined $params->{$attr}; + } + my $user_settings = user_settings::get( $config, { user => $user } ); + $entry->{lang} = $user_settings->{language} || 'en', + + $config->{access}->{write} = 1; + help_texts::delete( $config, $entry ); + uac::print_info("help-text deleted"); +} + +sub edit_help { + my ($config, $request) = @_; + + $config->{access}->{write} = 0; + my $params = $request->{params}->{checked}; + my $permissions = $request->{permissions}; + unless ( $permissions->{edit_help_texts} == 1 ) { + uac::permissions_denied('edit_help_texts'); + return; + } + + for my $param ( 'project_id', 'studio_id' ) { + unless ( defined $params->{$param} ) { + uac::print_error("missing $param"); + return; + } + } + + my $table = "calcms_events"; + my $help_texts = help_texts::get( + $config, + { + project_id => $params->{project_id}, + studio_id => $params->{studio_id}, + table => $table + } + ); + my %texts_by_column = map { $_->{column} => $_->{text}} @$help_texts; + my $texts_by_column = \%texts_by_column; + + $params->{tables} = [{ + name => $table, + columns => [ + {table => $table, column => 'title', value => ($texts_by_column->{title} // '') }, + {table => $table, column => 'user_title', value => ($texts_by_column->{user_title} // '') }, + {table => $table, column => 'episode', value => ($texts_by_column->{episode} // '') }, + {table => $table, column => 'start_date', value => ($texts_by_column->{start_date} // '') }, + {table => $table, column => 'end_date', value => ($texts_by_column->{end_date} // '') }, + {table => $table, column => 'duration', value => ($texts_by_column->{duration} // '') }, + {table => $table, column => 'live', value => ($texts_by_column->{live} // '') }, + {table => $table, column => 'published', value => ($texts_by_column->{published} // '') }, + {table => $table, column => 'playout', value => ($texts_by_column->{playout} // '') }, + {table => $table, column => 'archive', value => ($texts_by_column->{archive} // '') }, + {table => $table, column => 'rerun', value => ($texts_by_column->{rerun} // '') }, + {table => $table, column => 'draw', value => ($texts_by_column->{draw} // '') }, + {table => $table, column => 'excerpt', value => ($texts_by_column->{excerpt} // '') }, + {table => $table, column => 'topic', value => ($texts_by_column->{topic} // '') }, + {table => $table, column => 'content', value => ($texts_by_column->{content} // '') }, + {table => $table, column => 'image', value => ($texts_by_column->{image} // '') }, + {table => $table, column => 'podcast_url', value => ($texts_by_column->{podcast_url} // '') }, + {table => $table, column => 'archive_url', value => ($texts_by_column->{archive_url} // '') }, + {table => $table, column => 'wiki_language', value => ($texts_by_column->{wiki_language} // '') }, + ] + }]; + + $params->{loc} = localization::get( $config, { user => $params->{presets}->{user}, file => 'edit-help-texts' } ); + template::process( $config, 'print', $params->{template}, $params ); +} + +sub get_help{ + my ($config, $request) = @_; + for my $param ( 'project_id', 'studio_id' ) { + unless ( defined $params->{$param} ) { + uac::print_error("missing $param"); + return; + } + } + + my $table = "calcms_events"; + my $help_texts = help_texts::get( + $config, + { + project_id => $params->{project_id}, + studio_id => $params->{studio_id}, + table => $table + } + ); + my %texts_by_column = map { $_->{column} => $_->{text}} @$help_texts; + my $texts_by_column = \%texts_by_column; + print "Content-type:application/json\n\n".JSON::encode_json($texts_by_column); +} + +sub check_params { + my ($config, $params) = @_; + + my $checked = {}; + + $checked->{action} = entry::element_of( $params->{action}, + ['get', 'edit', 'save', 'delete'] + ); + + entry::set_numbers( $checked, $params, ['project_id', 'studio_id']); + entry::set_strings( $checked, $params, ['table', 'column', 'text']); + + if ( defined $checked->{studio_id} ) { + $checked->{default_studio_id} = $checked->{studio_id}; + } else { + $checked->{studio_id} = -1; + } + + $checked->{template} = template::check( $config, $params->{template}, 'edit-help-texts' ); + return $checked; +} diff --git a/website/agenda/planung/js/edit-event.js b/website/agenda/planung/js/edit-event.js index 96390eb..d642195 100644 --- a/website/agenda/planung/js/edit-event.js +++ b/website/agenda/planung/js/edit-event.js @@ -333,7 +333,22 @@ $(document).ready( updateCheckBox("#edit_event input[name='published']", 0); } } - ) + ) + + jQuery.getJSON("help-texts.cgi?project_id="+getProjectId()+"&studio_id="+getStudioId()+"&action=get", + function(data){ + for (col in data){ + let value = data[col]; + console.log(col+" "+value) + $(`input[name="${col}"]`).hover(function() { + $(this).attr("title",value) + }); + $(`textarea[class="${col}"]`).hover(function() { + $(this).attr("title",value) + }); + } + }); + console.log("done") } ); diff --git a/website/agenda/planung/pot/de/edit-help-texts.po b/website/agenda/planung/pot/de/edit-help-texts.po new file mode 100644 index 0000000..e69de29 diff --git a/website/agenda/planung/pot/de/help-texts.po b/website/agenda/planung/pot/de/help-texts.po new file mode 100644 index 0000000..40ac1b3 --- /dev/null +++ b/website/agenda/planung/pot/de/help-texts.po @@ -0,0 +1,12 @@ +msgid "save_button" +msgstr "speichern" + +msgid "delete_button" +msgstr "löschen" + +msgid "table" +msgstr "Tabelle" + +msgid "column" +msgstr "spalte" + diff --git a/website/agenda/planung/pot/de/menu.po b/website/agenda/planung/pot/de/menu.po index 38c6dd5..6ab82df 100644 --- a/website/agenda/planung/pot/de/menu.po +++ b/website/agenda/planung/pot/de/menu.po @@ -64,3 +64,7 @@ msgstr "Nutzeraktivität" msgid "create-events" msgstr "Sendungen anlegen" +msgid "edit-help-texts" +msgstr "Hilfe bearbeiten" + + diff --git a/website/agenda/planung/pot/de/roles.po b/website/agenda/planung/pot/de/roles.po index ac53ee6..a909646 100644 --- a/website/agenda/planung/pot/de/roles.po +++ b/website/agenda/planung/pot/de/roles.po @@ -253,3 +253,6 @@ msgstr "Vorproduktion löschen" msgid "label_read_playout" msgstr "Playout anzeigen" +msgid "label_edit_help_texts" +msgstr "Hilfetexte bearbeiten" + diff --git a/website/agenda/planung/pot/en/edit-help-texts.po b/website/agenda/planung/pot/en/edit-help-texts.po new file mode 100644 index 0000000..e69de29 diff --git a/website/agenda/planung/pot/en/help-texts.po b/website/agenda/planung/pot/en/help-texts.po new file mode 100644 index 0000000..443b8b2 --- /dev/null +++ b/website/agenda/planung/pot/en/help-texts.po @@ -0,0 +1,12 @@ +msgid "save_button" +msgstr "save" + +msgid "delete_button" +msgstr "delete" + +msgid "table" +msgstr "Table" + +msgid "column" +msgstr "Column" + diff --git a/website/agenda/planung/pot/en/menu.po b/website/agenda/planung/pot/en/menu.po index b1543fd..b784fb9 100644 --- a/website/agenda/planung/pot/en/menu.po +++ b/website/agenda/planung/pot/en/menu.po @@ -64,3 +64,6 @@ msgstr "User Stats" msgid "create-events" msgstr "Create Events" +msgid "edit-help-texts" +msgstr "Edit Help" + diff --git a/website/agenda/planung/pot/en/roles.po b/website/agenda/planung/pot/en/roles.po index 8379cf5..2634c11 100644 --- a/website/agenda/planung/pot/en/roles.po +++ b/website/agenda/planung/pot/en/roles.po @@ -256,3 +256,6 @@ msgstr "delete audio recordings" msgid "label_read_playout" msgstr "show playout" +msgid "label_edit_help_texts" +msgstr "edit help texts" + diff --git a/website/agenda/planung/templates/default.html b/website/agenda/planung/templates/default.html index 6ef9eb5..2ea6113 100644 --- a/website/agenda/planung/templates/default.html +++ b/website/agenda/planung/templates/default.html @@ -57,6 +57,10 @@
 
+ +
 
+
+
 
 
diff --git a/website/agenda/planung/templates/edit-help-texts.html b/website/agenda/planung/templates/edit-help-texts.html new file mode 100644 index 0000000..ddee096 --- /dev/null +++ b/website/agenda/planung/templates/edit-help-texts.html @@ -0,0 +1,21 @@ + + + + +Table + + + + + + + + + + + + + + +
+
\ No newline at end of file