From cc40b7d77271966a6922317774f63f8fa86d0871 Mon Sep 17 00:00:00 2001 From: Mark Wells Date: Tue, 5 Apr 2016 12:51:49 -0700 Subject: [PATCH] persistent user prefs for UI pages, #41397 --- FS/FS/Mason.pm | 4 +- FS/FS/Schema.pm | 20 +++++ FS/FS/UI/Web.pm | 72 +++++++++++++++- FS/FS/access_user.pm | 72 ++++++++++++++++ FS/FS/access_user_page_pref.pm | 128 +++++++++++++++++++++++++++++ FS/MANIFEST | 2 + FS/t/access_user_page_pref.t | 5 ++ httemplate/elements/header.html | 8 ++ httemplate/elements/page_pref.js | 10 +++ httemplate/misc/process/set_page_pref.html | 12 +++ 10 files changed, 331 insertions(+), 2 deletions(-) create mode 100644 FS/FS/access_user_page_pref.pm create mode 100644 FS/t/access_user_page_pref.t create mode 100644 httemplate/elements/page_pref.js create mode 100644 httemplate/misc/process/set_page_pref.html diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm index 3a00f427c..aa9d3bebf 100644 --- a/FS/FS/Mason.pm +++ b/FS/FS/Mason.pm @@ -131,7 +131,8 @@ if ( -e $addl_handler_use_file ) { use FS::Conf; use FS::CGI qw(header menubar table itable ntable idiot eidiot myexit http_header); - use FS::UI::Web qw(svc_url random_id); + use FS::UI::Web qw(svc_url random_id + get_page_pref set_page_pref); use FS::UI::Web::small_custview qw(small_custview); use FS::UI::bytecount; use FS::UI::REST qw( rest_auth rest_uri_remain encode_rest ); @@ -409,6 +410,7 @@ if ( -e $addl_handler_use_file ) { use FS::svc_fiber; use FS::fiber_olt; use FS::olt_site; + use FS::access_user_page_pref; # Sammath Naur if ( $FS::Mason::addl_handler_use ) { diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index c27b727b8..2cb942524 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -5812,6 +5812,26 @@ sub tables_hashref { 'index' => [ ['usernum'], ['path'], ['_date'] ], }, + 'access_user_page_pref' => { + 'columns' => [ + 'prefnum' => 'serial', '', '', '', '', + 'usernum' => 'int', '', '', '', '', + 'path' => 'text', '', '', '', '', + 'tablenum' => 'int', 'NULL', '', '', '', + '_date' => @date_type, '', '', + 'prefname' => 'varchar', '', $char_d, '', '', + 'prefvalue' => 'text', '', '', '', '', + ], + 'primary_key' => 'prefnum', + 'unique' => [ [ 'usernum', 'path', 'tablenum', 'prefname' ] ], + 'index' => [], + 'foreign_keys' => [ + { columns => [ 'usernum' ], + table => 'access_user' + }, + ], + }, + 'sched_item' => { 'columns' => [ 'itemnum', 'serial', '', '', '', '', diff --git a/FS/FS/UI/Web.pm b/FS/FS/UI/Web.pm index 136c8e6af..8f10011e5 100644 --- a/FS/FS/UI/Web.pm +++ b/FS/FS/UI/Web.pm @@ -15,7 +15,7 @@ use FS::cust_main; # are sql_balance and sql_date_balance in the right module? #@ISA = qw( FS::UI ); @ISA = qw( Exporter ); -@EXPORT_OK = qw( svc_url random_id ); +@EXPORT_OK = qw( get_page_pref set_page_pref svc_url random_id ); $DEBUG = 0; $me = '[FS::UID::Web]'; @@ -23,9 +23,79 @@ $me = '[FS::UID::Web]'; our $NO_RANDOM_IDS; ### +# user prefs +### + +=item get_page_pref NAME, TABLENUM + +Returns the user's page preference named NAME for the current page. If the +page is a view or edit page or otherwise shows a single record at a time, +it should use TABLENUM to link the preference to that record. + +=cut + +sub get_page_pref { + my ($prefname, $tablenum) = @_; + + my $m = $HTML::Mason::Commands::m + or die "can't get page pref when running outside the UI"; + # what's more useful: to tie prefs to the base_comp (usually where + # code is executing right now), or to the request_comp (approximately the + # one in the URL)? not sure. + $FS::CurrentUser::CurrentUser->get_page_pref( $m->request_comp->path, + $prefname, + $tablenum + ); +} + +=item set_page_pref NAME, TABLENUM, VALUE + +Sets the user's page preference named NAME for the current page. Use TABLENUM +as for get_page_pref. + +If VALUE is an empty string, the preference will be deleted (and +C will return an empty string). + + my $mypref = set_page_pref('mypref', '', 100); + +=cut + +sub set_page_pref { + my ($prefname, $tablenum, $prefvalue) = @_; + + my $m = $HTML::Mason::Commands::m + or die "can't set page pref when running outside the UI"; + $FS::CurrentUser::CurrentUser->set_page_pref( $m->request_comp->path, + $prefname, + $tablenum, + $prefvalue ); +} + +### # date parsing ### +=item parse_beginning_ending CGI [, PREFIX ] + +Parses a beginning/ending date range, as used on many reports. This function +recognizes two sets of CGI params: "begin" and "end", the integer timestamp +values, and "beginning" and "ending", the user-readable date fields. + +If "begin" contains an integer, that's passed through as the beginning date. +Otherwise, "beginning" is passed to L and turned +into an integer. If this fails or it doesn't have a value, zero is used as the +beginning date. + +The same happens for "end" and "ending", except that if "ending" contains a +date without a time, it gets moved to the end of that day, and if there's no +value, the value returned is the highest unsigned 32-bit time value (some time +in 2037). + +PREFIX is optionally a string to prepend (with '_' as a delimiter) to the form +field names. + +=cut + use Date::Parse; sub parse_beginning_ending { my($cgi, $prefix) = @_; diff --git a/FS/FS/access_user.pm b/FS/FS/access_user.pm index 3b36e46f0..a9fdf5b1e 100644 --- a/FS/FS/access_user.pm +++ b/FS/FS/access_user.pm @@ -742,6 +742,78 @@ sub locale { $self->{_locale} = $self->option('locale'); } +=item get_page_pref PATH, NAME, TABLENUM + +Returns the user's page preference named NAME for the page at PATH. If the +page is a view or edit page or otherwise shows a single record at a time, +it should use TABLENUM to tell which record the preference is for. + +=cut + +sub get_page_pref { + my $self = shift; + my ($path, $prefname, $tablenum) = @_; + $tablenum ||= ''; + + my $access_user_page_pref = qsearchs('access_user_page_pref', { + path => $path, + usernum => $self->usernum, + tablenum => $tablenum, + prefname => $prefname, + }); + $access_user_page_pref ? $access_user_page_pref->prefvalue : ''; +} + +=item set_page_pref PATH, NAME, TABLENUM, VALUE + +Sets the user's page preference named NAME for the page at PATH. Use TABLENUM +as for get_page_pref. + +=cut + +sub set_page_pref { + my $self = shift; + my ($path, $prefname, $tablenum, $prefvalue) = @_; + $tablenum ||= ''; + + my $error; + my $access_user_page_pref = qsearchs('access_user_page_pref', { + path => $path, + usernum => $self->usernum, + tablenum => $tablenum, + prefname => $prefname, + }); + if ( $access_user_page_pref ) { + if ( $prefvalue eq $access_user_page_pref->get('prefvalue') ) { + return ''; + } + if ( length($prefvalue) > 0 ) { + $access_user_page_pref->set('prefvalue', $prefvalue); + $error = $access_user_page_pref->replace; + $error .= " (updating $prefname)" if $error; + } else { + $error = $access_user_page_pref->delete; + $error .= " (removing $prefname)" if $error; + } + } else { + if ( length($prefvalue) > 0 ) { + $access_user_page_pref = FS::access_user_page_pref->new({ + path => $path, + usernum => $self->usernum, + tablenum => $tablenum, + prefname => $prefname, + prefvalue => $prefvalue, + }); + $error = $access_user_page_pref->insert; + $error .= " (creating $prefname)" if $error; + } else { + return ''; + } + } + + return $error; +} + =back =head1 BUGS diff --git a/FS/FS/access_user_page_pref.pm b/FS/FS/access_user_page_pref.pm new file mode 100644 index 000000000..890d29f17 --- /dev/null +++ b/FS/FS/access_user_page_pref.pm @@ -0,0 +1,128 @@ +package FS::access_user_page_pref; +use base qw( FS::Record ); + +use strict; +use FS::Record qw( qsearch qsearchs ); + +sub table { 'access_user_page_pref'; } + +=head1 NAME + +FS::access_user_page_pref - Object methods for access_user_page_pref records + +=head1 SYNOPSIS + + use FS::access_user_page_pref; + + $record = new FS::access_user_page_pref \%hash; + $record = new FS::access_user_page_pref { 'column' => 'value' }; + + $error = $record->insert; + + $error = $new_record->replace($old_record); + + $error = $record->delete; + + $error = $record->check; + +=head1 DESCRIPTION + +An FS::access_user_page_pref object represents a per-page user interface +preference. FS::access_user_page_pref inherits from FS::Record. The +following fields are currently supported: + +=over 4 + +=item prefnum + +primary key + +=item usernum + +The user who has this preference, a L foreign key. + +=item path + +The path of the page where the preference is set, relative to the Mason +document root. + +=item tablenum + +For view and edit pages (which show one record at a time), the record primary +key that the preference applies to. + +=item _date + +The date the preference was created. + +=item prefname + +The name of the preference, as defined by the page. + +=item prefvalue + +The value (a free-text field). + +=back + +=head1 METHODS + +=over 4 + +=item new HASHREF + +Creates a new preference. To add the preference to the database, see +L<"insert">. + +=item insert + +Adds this record to the database. If there is an error, returns the error, +otherwise returns false. + +=item delete + +Delete this record from the database. + +=item replace OLD_RECORD + +Replaces the OLD_RECORD with this one in the database. If there is an error, +returns the error, otherwise returns false. + +=item check + +Checks all fields to make sure this is a valid preference. If there is +an error, returns the error, otherwise returns false. Called by the insert +and replace methods. + +=cut + +sub check { + my $self = shift; + + $self->set('_date', time) unless $self->get('_date'); + + my $error = + $self->ut_numbern('prefnum') + || $self->ut_number('usernum') + || $self->ut_foreign_key('usernum', 'access_user', 'usernum') + || $self->ut_text('path') + || $self->ut_numbern('tablenum') + || $self->ut_numbern('_date') + || $self->ut_text('prefname') + || $self->ut_text('prefvalue') + ; + return $error if $error; + + $self->SUPER::check; +} + +=back + +=head1 SEE ALSO + +L + +=cut + +1; + diff --git a/FS/MANIFEST b/FS/MANIFEST index 80ff917f0..d0bf99b85 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -866,3 +866,5 @@ FS/olt_site.pm t/olt_site.t FS/webservice_log.pm t/webservice_log.t +FS/access_user_page_pref.pm +t/access_user_page_pref.t diff --git a/FS/t/access_user_page_pref.t b/FS/t/access_user_page_pref.t new file mode 100644 index 000000000..4a45b4d39 --- /dev/null +++ b/FS/t/access_user_page_pref.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n" } +END {print "not ok 1\n" unless $loaded;} +use FS::access_user_page_pref; +$loaded=1; +print "ok 1\n"; diff --git a/httemplate/elements/header.html b/httemplate/elements/header.html index c8a83ca7e..699f82c53 100644 --- a/httemplate/elements/header.html +++ b/httemplate/elements/header.html @@ -53,6 +53,12 @@ Example: <% $head |n %> +%# announce our base path, and the Mason comp path of this page + + STYLE="margin-top:0; margin-bottom:0; margin-left:0px; margin-right:0px"> @@ -178,6 +184,7 @@ Example: % } <% $menubar !~ /^\s*$/ ? "$menubar

" : '' %> + <%init> my( $title, $title_noescape, $menubar, $etc, $head ) = ( '', '', '', '', '' ); @@ -225,4 +232,5 @@ if ( scalar(@agentnums) == 1 ) { $company_name = $conf->config('company_name'); $company_url = $conf->config('company_url'); } + diff --git a/httemplate/elements/page_pref.js b/httemplate/elements/page_pref.js new file mode 100644 index 000000000..253c6da86 --- /dev/null +++ b/httemplate/elements/page_pref.js @@ -0,0 +1,10 @@ +function set_page_pref(prefname, tablenum, prefvalue, success) { + jQuery.post( window.fsurl + 'misc/process/set_page_pref.html', + { path: window.request_comp_path, + name: prefname, + num: tablenum, + value: prefvalue + }, + success + ); +} diff --git a/httemplate/misc/process/set_page_pref.html b/httemplate/misc/process/set_page_pref.html new file mode 100644 index 000000000..a7f123116 --- /dev/null +++ b/httemplate/misc/process/set_page_pref.html @@ -0,0 +1,12 @@ +<%init> +my $path = $cgi->param('path'); +my $name = $cgi->param('name'); +my $tablenum = $cgi->param('num') || ''; +my $value = $cgi->param('value'); + +my $error = $FS::CurrentUser::CurrentUser->set_page_pref($path, $name, $tablenum, $value); +my $result = { 'error' => $error }; # in case someone cares + +http_header('Content-Type', 'application/json'); + +<% encode_json($result) %> -- 2.11.0