From c738a3c4923774b64960aa87fa58bd0751487edb Mon Sep 17 00:00:00 2001 From: ivan Date: Sun, 18 Jun 2006 12:54:49 +0000 Subject: [PATCH] ACLs: finish group edit (agents + rights) & browse --- FS/FS/AccessRight.pm | 139 ++++++++++++++++--------- FS/FS/access_group.pm | 57 ++++++++-- FS/FS/access_groupagent.pm | 24 +++-- FS/FS/m2name_Common.pm | 95 +++++++++++++++++ FS/FS/part_pkg.pm | 53 ++++++---- FS/MANIFEST | 3 + htetc/handler.pl | 4 + httemplate/browse/access_group.html | 45 ++++++++ httemplate/browse/access_user.html | 2 +- httemplate/edit/access_group.html | 36 +++++++ httemplate/edit/elements/edit.html | 21 ++++ httemplate/edit/part_pkg.cgi | 2 +- httemplate/edit/process/access_group.html | 10 ++ httemplate/edit/process/elements/process.html | 15 ++- httemplate/elements/checkboxes-table-name.html | 85 +++++++++++++++ httemplate/elements/checkboxes-table.html | 28 +++-- 16 files changed, 520 insertions(+), 99 deletions(-) create mode 100644 FS/FS/m2name_Common.pm create mode 100644 httemplate/elements/checkboxes-table-name.html diff --git a/FS/FS/AccessRight.pm b/FS/FS/AccessRight.pm index 01d63e35d..5229e1e65 100644 --- a/FS/FS/AccessRight.pm +++ b/FS/FS/AccessRight.pm @@ -1,7 +1,7 @@ package FS::AccessRight; use strict; -user vars qw(@rights %rights); +use vars qw(@rights); # %rights); use Tie::IxHash; =head1 NAME @@ -19,59 +19,94 @@ assigned to users and/or groups. =cut +#@rights = ( +# 'Reports' => [ +# '_desc' => 'Access to high-level reporting', +# ], +# 'Configuration' => [ +# '_desc' => 'Access to configuration', +# +# 'Settings' => {}, +# +# 'agent' => [ +# '_desc' => 'Master access to reseller configuration', +# 'agent_type' => {}, +# 'agent' => {}, +# ], +# +# 'export_svc_pkg' => [ +# '_desc' => 'Access to export, service and package configuration', +# 'part_export' => {}, +# 'part_svc' => {}, +# 'part_pkg' => {}, +# 'pkg_class' => {}, +# ], +# +# 'billing' => [ +# '_desc' => 'Access to billing configuration', +# 'payment_gateway' => {}, +# 'part_bill_event' => {}, +# 'prepay_credit' => {}, +# 'rate' => {}, +# 'cust_main_county' => {}, +# ], +# +# 'dialup' => [ +# '_desc' => 'Access to dialup configuraiton', +# 'svc_acct_pop' => {}, +# ], +# +# 'broadband' => [ +# '_desc' => 'Access to broadband configuration', +# 'router' => {}, +# 'addr_block' => {}, +# ], +# +# 'misc' => [ +# 'part_referral' => {}, +# 'part_virtual_field' => {}, +# 'msgcat' => {}, +# 'inventory_class' => {}, +# ], +# +# }, +# +#); +# +##turn it into a more hash-like structure, but ordered via IxHash + +#well, this is what we have for now. could be ordered better, could be lots of +# things better, but this ACL system does 99% of what folks need and the UI +# isn't *that* bad @rights = ( - 'Reports' => [ - '_desc' => 'Access to high-level reporting', - ], - 'Configuration' => [ - '_desc' => 'Access to configuration', - - 'Settings' => {}, - - 'agent' => [ - '_desc' => 'Master access to reseller configuration', - 'agent_type' => {}, - 'agent' => {}, - ], - - 'export_svc_pkg' => [ - '_desc' => 'Access to export, service and package configuration', - 'part_export' => {}, - 'part_svc' => {}, - 'part_pkg' => {}, - 'pkg_class' => {}, - ], - - 'billing' => [ - '_desc' => 'Access to billing configuration', - 'payment_gateway' => {}, - 'part_bill_event' => {}, - 'prepay_credit' => {}, - 'rate' => {}, - 'cust_main_county' => {}, - ], - - 'dialup' => [ - '_desc' => 'Access to dialup configuraiton', - 'svc_acct_pop' => {}, - ], - - 'broadband' => [ - '_desc' => 'Access to broadband configuration', - 'router' => {}, - 'addr_block' => {}, - ], - - 'misc' => [ - 'part_referral' => {}, - 'part_virtual_field' => {}, - 'msgcat' => {}, - 'inventory_class' => {}, - ], - - }, + 'New customer', + 'View customer', + #'View Customer | View tickets', + 'Edit customer', + 'Cancel customer', + 'Delete customer', + + 'Order customer package', + 'Change customer package', + 'Edit customer package dates', + 'Customize customer package', + 'Suspend customer package', + 'Unsuspend customer package', + 'Cancel customer package immediately', + 'Cancel customer package later', + + 'Provision service', + 'Unprovision service', + #legacy link stuff + + 'Post payment', + 'Process payment', + 'Post credit', + #more financial stuff ); -#turn it into a more hash-like structure, but ordered via IxHash +sub rights { + @rights; +} diff --git a/FS/FS/access_group.pm b/FS/FS/access_group.pm index 9d870e57f..25190406f 100644 --- a/FS/FS/access_group.pm +++ b/FS/FS/access_group.pm @@ -3,8 +3,11 @@ package FS::access_group; use strict; use vars qw( @ISA ); use FS::Record qw( qsearch qsearchs ); +use FS::m2name_Common; +use FS::access_groupagent; +use FS::access_right; -@ISA = qw(FS::Record); +@ISA = qw(FS::m2m_Common FS::m2name_Common FS::Record); =head1 NAME @@ -27,15 +30,14 @@ FS::access_group - Object methods for access_group records =head1 DESCRIPTION -An FS::access_group object represents an example. FS::access_group inherits from +An FS::access_group object represents an access group. FS::access_group inherits from FS::Record. The following fields are currently supported: =over 4 =item groupnum - primary key -=item groupname - - +=item groupname - Access group name =back @@ -45,7 +47,7 @@ FS::Record. The following fields are currently supported: =item new HASHREF -Creates a new example. To add the example to the database, see L<"insert">. +Creates a new access group. To add the access group to the database, see L<"insert">. Note that this stores the hash reference, not a distinct copy of the hash it points to. You can ask the object for a copy with the I method. @@ -84,7 +86,7 @@ returns the error, otherwise returns false. =item check -Checks all fields to make sure this is a valid example. If there is +Checks all fields to make sure this is a valid access group. If there is an error, returns the error, otherwise returns false. Called by the insert and replace methods. @@ -105,12 +107,51 @@ sub check { $self->SUPER::check; } +=item access_groupagent + +Returns all associated FS::access_groupagent records. + +=cut + +sub access_groupagent { + my $self = shift; + qsearch('access_groupagent', { 'groupnum' => $self->groupnum } ); +} + +=item access_rights + +Returns all associated FS::access_right records. + +=cut + +sub access_rights { + my $self = shift; + qsearch('access_right', { 'righttype' => 'FS::access_group', + 'rightobjnum' => $self->groupnum + } + ); +} + +=item access_right RIGHTNAME + +Returns the specified FS::access_right record. Can be used as a boolean, to +test if this group has the given RIGHTNAME. + +=cut + +sub access_right { + my( $self, $name ) = shift; + qsearchs('access_right', { 'righttype' => 'FS::access_group', + 'rightobjnum' => $self->groupnum, + 'rightname' => $name, + } + ); +} + =back =head1 BUGS -The author forgot to customize this manpage. - =head1 SEE ALSO L, schema.html from the base documentation. diff --git a/FS/FS/access_groupagent.pm b/FS/FS/access_groupagent.pm index 6b5def1a3..3de8feeed 100644 --- a/FS/FS/access_groupagent.pm +++ b/FS/FS/access_groupagent.pm @@ -3,6 +3,7 @@ package FS::access_groupagent; use strict; use vars qw( @ISA ); use FS::Record qw( qsearch qsearchs ); +use FS::agent; @ISA = qw(FS::Record); @@ -27,7 +28,7 @@ FS::access_groupagent - Object methods for access_groupagent records =head1 DESCRIPTION -An FS::access_groupagent object represents an example. FS::access_groupagent inherits from +An FS::access_groupagent object represents an group reseller virtualization. FS::access_groupagent inherits from FS::Record. The following fields are currently supported: =over 4 @@ -47,7 +48,7 @@ FS::Record. The following fields are currently supported: =item new HASHREF -Creates a new example. To add the example to the database, see L<"insert">. +Creates a new group reseller virtualization. To add the record to the database, see L<"insert">. Note that this stores the hash reference, not a distinct copy of the hash it points to. You can ask the object for a copy with the I method. @@ -86,7 +87,7 @@ returns the error, otherwise returns false. =item check -Checks all fields to make sure this is a valid example. If there is +Checks all fields to make sure this is a valid group reseller virtualization. If there is an error, returns the error, otherwise returns false. Called by the insert and replace methods. @@ -100,20 +101,29 @@ sub check { my $error = $self->ut_numbern('groupagentnum') - || $self->ut_number('groupnum') - || $self->ut_number('agentnum') + || $self->ut_foreign_key('groupnum', 'access_group', 'groupnum') + || $self->ut_foreign_key('agentnum', 'agent', 'agentnum') ; return $error if $error; $self->SUPER::check; } +=item agent + +Returns the associated FS::agent object. + +=cut + +sub agent { + my $self = shift; + qsearchs('agent', { 'agentnum' => $self->agentnum } ); +} + =back =head1 BUGS -The author forgot to customize this manpage. - =head1 SEE ALSO L, schema.html from the base documentation. diff --git a/FS/FS/m2name_Common.pm b/FS/FS/m2name_Common.pm new file mode 100644 index 000000000..7c9637e27 --- /dev/null +++ b/FS/FS/m2name_Common.pm @@ -0,0 +1,95 @@ +package FS::m2name_Common; + +use strict; +use vars qw( @ISA $DEBUG ); +use FS::Schema qw( dbdef ); +use FS::Record qw( qsearch qsearchs ); #dbh ); + +@ISA = qw( FS::Record ); + +$DEBUG = 0; + +=head1 NAME + +FS::m2name_Common - Base class for tables with a related table listing names + +=head1 SYNOPSIS + +use FS::m2name_Common; + +@ISA = qw( FS::m2name_Common ); + +=head1 DESCRIPTION + +FS::m2name_Common is intended as a base class for classes which have a +related table that lists names. + +=head1 METHODS + +=over 4 + +=item process_m2name + +=cut + +sub process_m2name { + my( $self, %opt ) = @_; + + my $self_pkey = $self->dbdef_table->primary_key; + my $link_sourcekey = $opt{'num_col'} || $self_pkey; + + my $link_table = $self->_load_table($opt{'link_table'}); + + my $link_static = $opt{'link_static'} || {}; + + foreach my $name ( @{ $opt{'names_list'} } ) { + + my $obj = qsearchs( $link_table, { + $link_sourcekey => $self->$self_pkey(), + $opt{'name_col'} => $name, + %$link_static, + }); + + if ( $obj && ! $opt{'params'}->{"$link_table.$name"} ) { + + my $d_obj = $obj; #need to save $obj for below. + my $error = $d_obj->delete; + die "error deleting $d_obj for $link_table.$name: $error" if $error; + + } elsif ( $opt{'params'}->{"$link_table.$name"} && ! $obj ) { + + #ok to clobber it now (but bad form nonetheless?) + #$obj = new "FS::$link_table" ( { + $obj = "FS::$link_table"->new( { + $link_sourcekey => $self->$self_pkey(), + $opt{'name_col'} => $name, + %$link_static, + }); + my $error = $obj->insert; + die "error inserting $obj for $link_table.$name: $error" if $error; + } + + } + + ''; +} + +sub _load_table { + my( $self, $table ) = @_; + eval "use FS::$table"; + die $@ if $@; + $table; +} + +=back + +=head1 BUGS + +=head1 SEE ALSO + +L + +=cut + +1; + diff --git a/FS/FS/part_pkg.pm b/FS/FS/part_pkg.pm index 05dc59913..de4d047de 100644 --- a/FS/FS/part_pkg.pm +++ b/FS/FS/part_pkg.pm @@ -1,7 +1,7 @@ package FS::part_pkg; use strict; -use vars qw( @ISA %freq %plans $DEBUG ); +use vars qw( @ISA %plans $DEBUG ); use Carp qw(carp cluck confess); use Tie::IxHash; use FS::Conf; @@ -571,6 +571,32 @@ sub is_free { } } + +sub freqs_href { + #method, class method or sub? #my $self = shift; + + tie my %freq, 'Tie::IxHash', + '0' => '(no recurring fee)', + '1h' => 'hourly', + '1d' => 'daily', + '1w' => 'weekly', + '2w' => 'biweekly (every 2 weeks)', + '1' => 'monthly', + '2' => 'bimonthly (every 2 months)', + '3' => 'quarterly (every 3 months)', + '6' => 'semiannually (every 6 months)', + '12' => 'annually', + '24' => 'biannually (every 2 years)', + '36' => 'triannually (every 3 years)', + '48' => '(every 4 years)', + '60' => '(every 5 years)', + '120' => '(every 10 years)', + ; + + \%freq; + +} + =item freq_pretty Returns an english representation of the I field, such as "monthly", @@ -578,29 +604,14 @@ Returns an english representation of the I field, such as "monthly", =cut -tie %freq, 'Tie::IxHash', - '0' => '(no recurring fee)', - '1h' => 'hourly', - '1d' => 'daily', - '1w' => 'weekly', - '2w' => 'biweekly (every 2 weeks)', - '1' => 'monthly', - '2' => 'bimonthly (every 2 months)', - '3' => 'quarterly (every 3 months)', - '6' => 'semiannually (every 6 months)', - '12' => 'annually', - '24' => 'biannually (every 2 years)', - '36' => 'triannually (every 3 years)', - '48' => '(every 4 years)', - '60' => '(every 5 years)', - '120' => '(every 10 years)', -; - sub freq_pretty { my $self = shift; my $freq = $self->freq; - if ( exists($freq{$freq}) ) { - $freq{$freq}; + + my $freqs_href = $self->freqs_href; + + if ( exists($freqs_href->{$freq}) ) { + $freqs_href->{$freq}; } else { my $interval = 'month'; if ( $freq =~ /^(\d+)([hdw])$/ ) { diff --git a/FS/MANIFEST b/FS/MANIFEST index 9e3285dbb..098fe4a64 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -342,3 +342,6 @@ t/access_right.t FS/m2m_Common.pm FS/pay_batch.pm t/pay_batch.t +FS/ConfDefaults.pm +t/ConfDefaults.t +FS/m2name_Common.pm diff --git a/htetc/handler.pl b/htetc/handler.pl index d400a55ea..1dfa1376e 100644 --- a/htetc/handler.pl +++ b/htetc/handler.pl @@ -182,6 +182,10 @@ sub handler use FS::pkg_class; use FS::access_user; use FS::access_group; + use FS::access_usergroup; + use FS::access_groupagent; + use FS::access_right; + use FS::AccessRight; if ( %%%RT_ENABLED%%% ) { eval ' diff --git a/httemplate/browse/access_group.html b/httemplate/browse/access_group.html index 6ba89ea81..9ebb2b882 100644 --- a/httemplate/browse/access_group.html +++ b/httemplate/browse/access_group.html @@ -4,6 +4,45 @@ my $html_init = "Internal access groups control access to the back-office interface.

". qq!Add an internal access group

!; +#false laziness w/access_user.html & agent_type.cgi +my $agents_sub = sub { + my $access_group = shift; + + [ map { + my $access_groupagent = $_; + my $agent = $access_groupagent->agent; + [ + { + 'data' => $agent->agent, + 'align' => 'left', + 'link' => $p. 'edit/agent.cgi?'. $agent->agentnum, + }, + ]; + } + grep { $_->agent } #? + $access_group->access_groupagent, + + ]; + +}; + +my $rights_sub = sub { + my $access_group = shift; + + [ map { my $access_right = $_; + [ + { + 'data' => $access_right->rightname, + 'align' => 'left', + }, + ]; + } + $access_group->access_rights, + + ]; + +}; + my $count_query = 'SELECT COUNT(*) FROM access_group'; my $link = [ $p.'edit/access_group.html?', 'groupnum' ]; @@ -22,12 +61,18 @@ my $link = [ $p.'edit/access_group.html?', 'groupnum' ]; 'count_query' => $count_query, 'header' => [ '#', 'Group name', + 'Agents', + 'Rights', ], 'fields' => [ 'groupnum', 'groupname', + $agents_sub, + $rights_sub, ], 'links' => [ $link, $link, + '', + '', ], ) %> diff --git a/httemplate/browse/access_user.html b/httemplate/browse/access_user.html index 38d5430b1..be11bf82a 100644 --- a/httemplate/browse/access_user.html +++ b/httemplate/browse/access_user.html @@ -4,7 +4,7 @@ my $html_init = "Internal users have access to the back-office interface. Typically, this is your employees and contractors, but in a VISP setup, you can also add accounts for your reseller's employees. It is highly recommended to add a separate account for each person rather than using role accounts.

". qq!Add an internal user

!; -#false laziness w/agent_type.cgi +#false laziness w/access_group.html & agent_type.cgi my $groups_sub = sub { my $access_user = shift; diff --git a/httemplate/edit/access_group.html b/httemplate/edit/access_group.html index 11b8df7bc..d7f7667f4 100644 --- a/httemplate/edit/access_group.html +++ b/httemplate/edit/access_group.html @@ -5,6 +5,42 @@ 'groupnum' => 'Group number', 'groupname' => 'Group name', }, + 'viewall_dir' => 'browse', + + 'html_bottom' => + sub { + my $access_group = shift; + + "
Group virtualized to customers of agents:
". + ntable("#cccccc",2). + ''. + include( '/elements/checkboxes-table.html', + 'source_obj' => $access_group, + 'link_table' => 'access_groupagent', + 'target_table' => 'agent', + 'name_col' => 'agent', + 'target_link' => $p.'edit/agent.cgi?', + 'disable-able' => 1, + ). + ''. + + "
Group rights:
". + ntable("#cccccc",2). + ''. + include( '/elements/checkboxes-table-name.html', + 'source_obj' => $access_group, + 'link_table' => 'access_right', + 'link_static' => { 'righttype' => + 'FS::access_group', + }, + 'num_col' => 'rightobjnum', + 'name_col' => 'rightname', + 'names_list' => [ FS::AccessRight->rights() ], + ). + '' + + ; + }, ) %> diff --git a/httemplate/edit/elements/edit.html b/httemplate/edit/elements/edit.html index 120c03a3c..94bf6eecd 100644 --- a/httemplate/edit/elements/edit.html +++ b/httemplate/edit/elements/edit.html @@ -16,6 +16,18 @@ # # 'menubar' => '', #menubar arrayref # + # #run when re-displaying with an error + # 'error_callback' => sub { my $cgi, $object = @_; }, + # + # #run when editing + # 'edit_callback' => sub { my $cgi, $object = @_; }, + # + # #run when adding + # 'new_callback' => sub { my $cgi, $object = @_; }, + # + # #broken'html_table_bottom' => '', #string or listref of additinal HTML to + # #add before + # # 'viewall_dir' => '', #'search' or 'browse', defaults to 'search' # # 'html_bottom' => '', #string @@ -43,16 +55,25 @@ map { $_ => scalar($cgi->param($_)) } fields($table) }); + &{$opt{'error_callback'}}($cgi, $object) + if $opt{'error_callback'}; + } elsif ( $cgi->keywords ) { #editing my( $query ) = $cgi->keywords; $query =~ /^(\d+)$/; $object = qsearchs( $table, { $pkey => $1 } ); + &{$opt{'edit_callback'}}($cgi, $object) + if $opt{'edit_callback'}; + } else { #adding $object = $class->new( {} ); + &{$opt{'new_callback'}}($cgi, $object) + if $opt{'new_callback'}; + } my $action = $object->$pkey() ? 'Edit' : 'Add'; diff --git a/httemplate/edit/part_pkg.cgi b/httemplate/edit/part_pkg.cgi index 462d5161f..b085d2260 100755 --- a/httemplate/edit/part_pkg.cgi +++ b/httemplate/edit/part_pkg.cgi @@ -237,7 +237,7 @@ if ( dbdef->table('pkg_svc')->column('primary_svc') ) { push @form_radio, 'pkg_svc_primary'; } -tie my %freq, 'Tie::IxHash', %FS::part_pkg::freq; +tie my %freq, 'Tie::IxHash', %{FS::part_pkg->freqs_href()}; if ( $part_pkg->dbdef_table->column('freq')->type =~ /(int)/i ) { delete $freq{$_} foreach grep { ! /^\d+$/ } keys %freq; } diff --git a/httemplate/edit/process/access_group.html b/httemplate/edit/process/access_group.html index e8c6d07b1..9bb9d1dda 100644 --- a/httemplate/edit/process/access_group.html +++ b/httemplate/edit/process/access_group.html @@ -1,5 +1,15 @@ <%= include( 'elements/process.html', 'table' => 'access_group', 'viewall_dir' => 'browse', + 'process_m2m' => { 'link_table' => 'access_groupagent', + 'target_table' => 'agent', + }, + 'process_m2name' => { + 'link_table' => 'access_right', + 'link_static' => { 'righttype' => 'FS::access_group', }, + 'num_col' => 'rightobjnum', + 'name_col' => 'rightname', + 'names_list' => [ FS::AccessRight->rights() ], + }, ) %> diff --git a/httemplate/edit/process/elements/process.html b/httemplate/edit/process/elements/process.html index 59ad35ee4..a6e3b50e3 100644 --- a/httemplate/edit/process/elements/process.html +++ b/httemplate/edit/process/elements/process.html @@ -16,7 +16,14 @@ # 'viewall_dir' => '', #'search' or 'browse', defaults to 'search' # 'process_m2m' => { 'link_table' => 'link_table_name', # 'target_table' => 'target_table_name', - # }. + # }, + # 'process_m2name' => { 'link_table' => 'link_table_name', + # 'link_static' => { 'column' => 'value' }, + # 'num_col' => 'column', #if column name is different in + # #link_table than source_table + # 'name_col' => 'name_column', + # 'names_list' => [ 'list', 'names' ], + # }, my(%opt) = @_; @@ -52,6 +59,12 @@ ); } + if ( !$error && $opt{'process_m2name'} ) { + $error = $new->process_m2name( %{ $opt{'process_m2name'} }, + 'params' => scalar($cgi->Vars), + ); + } + if ( $error ) { $cgi->param('error', $error); print $cgi->redirect(popurl(2). "$table.html?". $cgi->query_string ); diff --git a/httemplate/elements/checkboxes-table-name.html b/httemplate/elements/checkboxes-table-name.html new file mode 100644 index 000000000..8e9dd29d2 --- /dev/null +++ b/httemplate/elements/checkboxes-table-name.html @@ -0,0 +1,85 @@ +<% + + ## + # required + ## + # 'link_table' => 'table_name', + # + # 'name_col' => 'name_column', + # #or + # 'name_callback' => sub { }, + # + # 'names_list' => [ 'value', 'other value' ], + # + ## + # recommended (required?) + ## + # 'source_obj' => $obj, + # #or? + # #'source_table' => 'table_name', + # #'sourcenum' => '4', #current value of primary key in source_table + # # # (none is okay, just pass it if you have it) + ## + # optional + ## + # 'num_col' => 'col_name' #if column name is different in link_table than + # #source_table + # 'link_static' => { 'column' => 'value' }, + + my( %opt ) = @_; + + my( $source_pkey, $sourcenum, $source_obj ); + if ( $opt{'source_obj'} ) { + + $source_obj = $opt{'source_obj'}; + #$source_table = $source_obj->dbdef_table->table; + $source_pkey = $source_obj->dbdef_table->primary_key; + $sourcenum = $source_obj->$source_pkey(); + + } else { + + #$source_obj? + $source_pkey = $opt{'source_table'} + ? dbdef->table($opt{'source_table'})->primary_key + : ''; + $sourcenum = $opt{'sourcenum'}; + } + + $source_pkey = $opt{'num_col'} || $source_pkey; + + my $link_static = $opt{'link_static'} || {}; + +%> + +<% foreach my $name ( @{ $opt{'names_list'} } ) { + + my $checked; + if ( $cgi->param('error') ) { + + $checked = $cgi->param($opt{'link_table'}. ".$name" ) + ? 'CHECKED' + : ''; + + } else { + + $checked = + qsearchs( $opt{'link_table'}, { + $source_pkey => $sourcenum, + $opt{'name_col'} => $name, + %$link_static, + } ) + ? 'CHECKED' + : '' + + } + +%> + + " <%= $checked %> VALUE="ON"> + + <%= $name %> + +
+ +<% } %> + diff --git a/httemplate/elements/checkboxes-table.html b/httemplate/elements/checkboxes-table.html index d26ebef35..16376fa3d 100644 --- a/httemplate/elements/checkboxes-table.html +++ b/httemplate/elements/checkboxes-table.html @@ -68,16 +68,28 @@ ) { my $targetnum = $target_obj->$target_pkey(); + + my $checked; + if ( $cgi->param('error') ) { + + $checked = $cgi->param($target_pkey.$targetnum) + ? 'CHECKED' + : ''; + + } else { + + $checked = qsearchs( $opt{'link_table'}, { + $source_pkey => $sourcenum, + $target_pkey => $targetnum, + } ) + ? 'CHECKED' + : '' + + } + %> - $sourcenum, - $target_pkey => $targetnum, - }) - ? 'CHECKED ' - : '' - %> VALUE="ON"> + VALUE="ON"> <% if ( $opt{'target_link'} ) { %> -- 2.11.0