adding svc_mailinglist for communigate "groups" (mailing lists), RT#7514
authorivan <ivan>
Tue, 23 Mar 2010 03:48:31 +0000 (03:48 +0000)
committerivan <ivan>
Tue, 23 Mar 2010 03:48:31 +0000 (03:48 +0000)
16 files changed:
FS/FS/Schema.pm
FS/FS/mailinglist.pm [new file with mode: 0644]
FS/FS/mailinglistmember.pm [new file with mode: 0644]
FS/FS/svc_mailinglist.pm [new file with mode: 0644]
FS/MANIFEST
FS/t/mailinglist.t [new file with mode: 0644]
FS/t/mailinglistmember.t [new file with mode: 0644]
FS/t/svc_mailinglist.t [new file with mode: 0644]
httemplate/edit/mailinglistmember.html [new file with mode: 0644]
httemplate/edit/part_svc.cgi
httemplate/edit/process/mailinglistmember.html [new file with mode: 0644]
httemplate/edit/process/svc_mailinglist.html [new file with mode: 0644]
httemplate/edit/svc_mailinglist.cgi [new file with mode: 0644]
httemplate/misc/delete-mailinglistmember.html [new file with mode: 0644]
httemplate/search/mailinglistmember.html [new file with mode: 0644]
httemplate/view/svc_mailinglist.cgi [new file with mode: 0644]

index d0a61aa..b995d8e 100644 (file)
@@ -2711,6 +2711,45 @@ sub tables_hashref {
       'index'  => [ [ 'id' ] ],
     },
 
+    'svc_mailinglist' => { #svc_group?
+      'columns' => [
+        'svcnum',            'int',     '',            '', '', '', 
+        'username',      'varchar',     '', $username_len, '', '',
+        'domsvc',            'int',     '',            '', '', '', 
+        'listnum',           'int',     '',            '', '', '',
+        'reply_to',         'char', 'NULL',             1, '', '',#SetReplyTo
+        'remove_from',      'char', 'NULL',             1, '', '',#RemoveAuthor
+        'reject_auto',      'char', 'NULL',             1, '', '',#RejectAuto
+        'remove_to_and_cc', 'char', 'NULL',             1, '', '',#RemoveToAndCc
+      ],
+      'primary_key' => 'svcnum',
+      'unique' => [],
+      'index'  => [ ['username'], ['domsvc'], ['listnum'] ],
+    },
+
+    'mailinglist' => {
+      'columns' => [
+        'listnum',   'serial', '',      '', '', '',
+        'listname', 'varchar', '', $char_d, '', '',
+      ],
+      'primary_key' => 'listnum',
+      'unique' => [],
+      'index'  => [],
+    },
+
+    'mailinglistmember' => {
+      'columns' => [
+        'membernum',        'serial',     '',   '', '', '',
+        'listnum',             'int',     '',   '', '', '',
+        'svcnum',              'int', 'NULL',   '', '', '', 
+        'contactemailnum',     'int', 'NULL',   '', '', '', 
+        'email',           'varchar', 'NULL',  255, '', '', 
+      ],
+      'primary_key' => 'membernum',
+      'unique'      => [],
+      'index'       => [['listnum'],['svcnum'],['contactemailnum'],['email']],
+    },
+
 
     # name type nullability length default local
 
diff --git a/FS/FS/mailinglist.pm b/FS/FS/mailinglist.pm
new file mode 100644 (file)
index 0000000..db1502c
--- /dev/null
@@ -0,0 +1,163 @@
+package FS::mailinglist;
+
+use strict;
+use base qw( FS::Record );
+use FS::Record qw( qsearch dbh ); # qsearchs );
+use FS::mailinglistmember;
+
+=head1 NAME
+
+FS::mailinglist - Object methods for mailinglist records
+
+=head1 SYNOPSIS
+
+  use FS::mailinglist;
+
+  $record = new FS::mailinglist \%hash;
+  $record = new FS::mailinglist { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::mailinglist object represents a mailing list  FS::mailinglist inherits
+from FS::Record.  The following fields are currently supported:
+
+=over 4
+
+=item listnum
+
+primary key
+
+=item listname
+
+Mailing list name
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new mailing list.  To add the mailing list 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<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'mailinglist'; }
+
+=item insert
+
+Adds this record to the database.  If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+# the insert method can be inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+sub delete {
+  my $self = shift;
+
+  local $SIG{HUP} = 'IGNORE';
+  local $SIG{INT} = 'IGNORE';
+  local $SIG{QUIT} = 'IGNORE';
+  local $SIG{TERM} = 'IGNORE';
+  local $SIG{TSTP} = 'IGNORE';
+  local $SIG{PIPE} = 'IGNORE';
+
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
+
+  foreach my $member ( $self->mailinglistmember ) {
+    my $error = $member->delete;
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
+
+  my $error = $self->SUPER::delete;
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error;
+  }
+
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+  '';
+
+}
+
+=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.
+
+=cut
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid mailing list.  If there is
+an error, returns the error, otherwise returns false.  Called by the insert
+and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+  my $self = shift;
+
+  my $error = 
+    $self->ut_numbern('listnum')
+    || $self->ut_text('listname')
+  ;
+  return $error if $error;
+
+  $self->SUPER::check;
+}
+
+=item mailinglistmember
+
+=cut
+
+sub mailinglistmember {
+  my $self = shift;
+  qsearch('mailinglistmember', { 'listnum' => $self->listnum } );
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::mailinglistmember>, L<FS::svc_mailinglist>, L<FS::Record>, schema.html
+from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/mailinglistmember.pm b/FS/FS/mailinglistmember.pm
new file mode 100644 (file)
index 0000000..ca73b88
--- /dev/null
@@ -0,0 +1,150 @@
+package FS::mailinglistmember;
+
+use strict;
+use base qw( FS::Record );
+use FS::Record qw( qsearchs ); # qsearch );
+use FS::mailinglist;
+use FS::svc_acct;
+use FS::contact_email;
+
+=head1 NAME
+
+FS::mailinglistmember - Object methods for mailinglistmember records
+
+=head1 SYNOPSIS
+
+  use FS::mailinglistmember;
+
+  $record = new FS::mailinglistmember \%hash;
+  $record = new FS::mailinglistmember { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::mailinglistmember object represents a mailing list member.
+FS::mailinglistmember inherits from FS::Record.  The following fields are
+currently supported:
+
+=over 4
+
+=item membernum
+
+primary key
+
+=item listnum
+
+listnum
+
+=item svcnum
+
+svcnum
+
+=item contactemailnum
+
+contactemailnum
+
+=item email
+
+email
+
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new mailing list member.  To add the member 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<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'mailinglistmember'; }
+
+=item insert
+
+Adds this record to the database.  If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+# the insert method can be inherited from FS::Record
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=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.
+
+=cut
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid member.  If there is
+an error, returns the error, otherwise returns false.  Called by the insert
+and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+  my $self = shift;
+
+  my $error = 
+    $self->ut_numbern('membernum')
+    || $self->ut_foreign_key('listnum', 'mailinglist', 'listnum')
+    || $self->ut_foreign_keyn('svcnum', 'svc_acct', 'svcnum')
+    || $self->ut_foreign_keyn('contactemailnum', 'contact_email', 'contactemailnum')
+    || $self->ut_textn('email') #XXX ut_email! from svc_forward, cust_main_invoice
+  ;
+  return $error if $error;
+
+  $self->SUPER::check;
+}
+
+=item mailinglist
+
+=cut
+
+sub mailinglist {
+  my $self = shift;
+  qsearchs('mailinglist', { 'listnum' => $self->listnum } );
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
diff --git a/FS/FS/svc_mailinglist.pm b/FS/FS/svc_mailinglist.pm
new file mode 100644 (file)
index 0000000..9c1a09d
--- /dev/null
@@ -0,0 +1,330 @@
+package FS::svc_mailinglist;
+
+use strict;
+use base qw( FS::svc_Domain_Mixin FS::svc_Common );
+use FS::Record qw( qsearchs dbh ); # qsearch );
+use FS::svc_domain;
+use FS::mailinglist;
+
+=head1 NAME
+
+FS::svc_mailinglist - Object methods for svc_mailinglist records
+
+=head1 SYNOPSIS
+
+  use FS::svc_mailinglist;
+
+  $record = new FS::svc_mailinglist \%hash;
+  $record = new FS::svc_mailinglist { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::svc_mailinglist object represents a mailing list customer service.
+FS::svc_mailinglist inherits from FS::Record.  The following fields are
+currently supported:
+
+=over 4
+
+=item svcnum
+
+primary key
+
+=item username
+
+username
+
+=item domsvc
+
+domsvc
+
+=item listnum
+
+listnum
+
+=item reply_to_group
+
+reply_to_group
+
+=item remove_author
+
+remove_author
+
+=item reject_auto
+
+reject_auto
+
+=item remove_to_and_cc
+
+remove_to_and_cc
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new record.  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<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'svc_mailinglist'; }
+
+sub table_info {
+  {
+    'name' => 'Mailing list',
+    'display_weight' => 80,
+    'cancel_weight'  => 55,
+    'fields' => {
+      'username' => { 'label' => 'List address',
+                      'disable_default'   => 1,
+                      'disable_fixed'     => 1,
+                      'disable_inventory' => 1,
+                    },
+      'domsvc' => { 'label' => 'List address domain',
+                    'disable_inventory' => 1,
+                    },
+      'domain' => 'List address domain',
+      'listnum' => { 'label' => 'List name',
+                     'disable_inventory' => 1,
+                   },
+      'listname' => 'List name', #actually mailinglist.listname
+      'reply_to' => { 'label' => 'Reply-To list',
+                      'type'  => 'checkbox',
+                      'disable_inventory' => 1,
+                      'disable_select'    => 1,
+                    },
+      'remove_from' => { 'label' => 'Remove From: from messages',
+                          'type'  => 'checkbox',
+                          'disable_inventory' => 1,
+                          'disable_select'    => 1,
+                        },
+      'reject_auto' => { 'label' => 'Reject automatic messages',
+                         'type'  => 'checkbox',
+                         'disable_inventory' => 1,
+                         'disable_select'    => 1,
+                       },
+      'remove_to_and_cc' => { 'label' => 'Remove To: and Cc: from messages',
+                              'type'  => 'checkbox',
+                              'disable_inventory' => 1,
+                              'disable_select'    => 1,
+                            },
+    },
+  };
+}
+
+=item insert
+
+Adds this record to the database.  If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+sub insert {
+  my $self = shift;
+
+  local $SIG{HUP} = 'IGNORE';
+  local $SIG{INT} = 'IGNORE';
+  local $SIG{QUIT} = 'IGNORE';
+  local $SIG{TERM} = 'IGNORE';
+  local $SIG{TSTP} = 'IGNORE';
+  local $SIG{PIPE} = 'IGNORE';
+
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
+
+  my $error;
+
+  #attach to existing lists?  sound scary 
+  #unless ( $self->listnum ) {
+    my $mailinglist = new FS::mailinglist {
+      'listname' => $self->get('listname'),
+    };
+    $error = $mailinglist->insert;
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+    warn $mailinglist->listnum;
+    $self->listnum($mailinglist->listnum);
+  #}
+
+  $error = $self->SUPER::insert(@_);
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error;
+  }
+
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+  '';
+}
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+sub delete {
+  my $self = shift;
+
+  local $SIG{HUP} = 'IGNORE';
+  local $SIG{INT} = 'IGNORE';
+  local $SIG{QUIT} = 'IGNORE';
+  local $SIG{TERM} = 'IGNORE';
+  local $SIG{TSTP} = 'IGNORE';
+  local $SIG{PIPE} = 'IGNORE';
+
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
+
+  my $error = $self->mailinglist->delete || $self->SUPER::delete;
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error;
+  }
+
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+  '';
+
+}
+
+=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.
+
+=cut
+
+sub replace {
+  my $new = shift;
+
+  my $old = ( blessed($_[0]) && $_[0]->isa('FS::Record') )
+              ? shift
+              : $new->replace_old;
+
+  return "can't change listnum" if $old->listnum != $new->listnum; #?
+
+  my %options = @_;
+
+  local $SIG{HUP} = 'IGNORE';
+  local $SIG{INT} = 'IGNORE';
+  local $SIG{QUIT} = 'IGNORE';
+  local $SIG{TERM} = 'IGNORE';
+  local $SIG{TSTP} = 'IGNORE';
+  local $SIG{PIPE} = 'IGNORE';
+
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
+
+  if ( $new->get('listname') && $new->get('listname') ne $old->listname ) {
+    my $mailinglist = $old->mailinglist;
+    $mailinglist->listname($new->get('listname'));
+    my $error = $mailinglist->replace;
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error if $error;
+    }
+  }
+
+  my $error = $new->SUPER::replace($old, %options);
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error if $error;
+  }
+
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
+  ''; #no error
+  
+
+}
+
+=item check
+
+Checks all fields to make sure this is a valid record.  If there is
+an error, returns the error, otherwise returns false.  Called by the insert
+and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+  my $self = shift;
+
+  my $error = 
+    $self->ut_numbern('svcnum')
+    || $self->ut_text('username')
+    || $self->ut_foreign_key('domsvc', 'svc_domain', 'svcnum')
+    #|| $self->ut_foreign_key('listnum', 'mailinglist', 'listnum')
+    || $self->ut_foreign_keyn('listnum', 'mailinglist', 'listnum')
+    || $self->ut_enum('reply_to_group', [ '', 'Y' ] )
+    || $self->ut_enum('remove_author', [ '', 'Y' ] )
+    || $self->ut_enum('reject_auto', [ '', 'Y' ] )
+    || $self->ut_enum('remove_to_and_cc', [ '', 'Y' ] )
+  ;
+  return $error if $error;
+
+  return "Can't remove listnum" if $self->svcnum && ! $self->listnum;
+
+  $self->SUPER::check;
+}
+
+=item mailinglist
+
+=cut
+
+sub mailinglist {
+  my $self = shift;
+  qsearchs('mailinglist', { 'listnum' => $self->listnum } );
+}
+
+=item listname
+
+=cut
+
+sub listname {
+  my $self = shift;
+  my $mailinglist = $self->mailinglist;
+  $mailinglist ? $mailinglist->listname : '';
+}
+
+=item label
+
+=cut
+
+sub label {
+  my $self = shift;
+  $self->listname. ' <'. $self->username. '@'. $self->domain. '>';
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::Record>, schema.html from the base documentation.
+
+=cut
+
+1;
+
index b58ab22..f7bfe80 100644 (file)
@@ -490,3 +490,9 @@ FS/cust_bill_pkg_discount.pm
 t/cust_bill_pkg_discount.t
 FS/location_Mixin.pm
 t/location_Mixin.t
+FS/svc_mailinglist.pm
+t/svc_mailinglist.t
+FS/mailinglist.pm
+t/mailinglist.t
+FS/mailinglistmember.pm
+t/mailinglistmember.t
diff --git a/FS/t/mailinglist.t b/FS/t/mailinglist.t
new file mode 100644 (file)
index 0000000..45b7dd5
--- /dev/null
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::mailinglist;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/mailinglistmember.t b/FS/t/mailinglistmember.t
new file mode 100644 (file)
index 0000000..1ceb2f5
--- /dev/null
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::mailinglistmember;
+$loaded=1;
+print "ok 1\n";
diff --git a/FS/t/svc_mailinglist.t b/FS/t/svc_mailinglist.t
new file mode 100644 (file)
index 0000000..73896da
--- /dev/null
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::svc_mailinglist;
+$loaded=1;
+print "ok 1\n";
diff --git a/httemplate/edit/mailinglistmember.html b/httemplate/edit/mailinglistmember.html
new file mode 100644 (file)
index 0000000..2391cb6
--- /dev/null
@@ -0,0 +1,25 @@
+<% include( 'elements/edit.html',
+              'name_singular' => 'member',
+              'table'         => 'mailinglistmember',
+              'popup'         => 1,
+              'fields'        => [
+                { field=>'listnum', type=>'hidden', },
+                { field=>'svcnum', type=>'hidden', }, #not yet
+                { field=>'contactemailnum', type=>'hidden', }, #not yet
+                { field=>'email', type=>'text', },
+              ],
+              'labels' => { 'membernum' => 'Member',
+                            'email'     => 'Email address',
+                          },
+              'new_callback' => $new_callback,
+          )
+%>
+<%init>
+
+my $new_callback = sub {
+  #my( $cgi, $object, $fields_listref, $opt_hashref ) = @_;
+  my( $cgi, $object ) = @_;
+  $object->listnum( $cgi->param('listnum') );
+};
+
+</%init>
index 51925c0..98ed9fe 100755 (executable)
@@ -15,7 +15,8 @@ Disable new orders <INPUT TYPE="checkbox" NAME="disabled" VALUE="Y"<% $hashref->
 Service definitions are the templates for items you offer to your customers.
 <UL><LI>svc_acct - Accounts - anything with a username (Mailboxes, PPP accounts, shell accounts, RADIUS entries for broadband, etc.)
     <LI>svc_domain - Domains
-    <LI>svc_forward - mail forwarding
+    <LI>svc_forward - Mail forwarding
+    <LI>svc_mailinglist - Mailing list
     <LI>svc_www - Virtual domain website
     <LI>svc_broadband - Broadband/High-speed Internet service (always-on)
     <LI>svc_phone - Customer phone numbers
diff --git a/httemplate/edit/process/mailinglistmember.html b/httemplate/edit/process/mailinglistmember.html
new file mode 100644 (file)
index 0000000..f1842b8
--- /dev/null
@@ -0,0 +1,6 @@
+<% include( 'elements/process.html',
+              'table'        => 'mailinglistmember',
+              'popup_reload' => 'Member added',
+          )
+%>
+%#XXX ACL
diff --git a/httemplate/edit/process/svc_mailinglist.html b/httemplate/edit/process/svc_mailinglist.html
new file mode 100644 (file)
index 0000000..580f6cc
--- /dev/null
@@ -0,0 +1,11 @@
+<% include( 'elements/svc_Common.html',
+               'table'  => 'svc_mailinglist',
+               'fields' => [ fields('svc_mailinglist'), 'listname' ],
+           )
+%>
+<%init>
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Provision customer service'); #something else more specific?
+
+</%init>
diff --git a/httemplate/edit/svc_mailinglist.cgi b/httemplate/edit/svc_mailinglist.cgi
new file mode 100644 (file)
index 0000000..c7c739d
--- /dev/null
@@ -0,0 +1,25 @@
+<% include( 'elements/svc_Common.html',
+              'table'  => 'svc_mailinglist',
+              'fields' => \@fields,
+          )
+%>
+<%init>
+
+die "access denied"
+  unless $FS::CurrentUser::CurrentUser->access_right('Provision customer service'); #something else more specific?
+
+my @fields = (
+  'username',
+  { field=>'domsvc',           type=>'select-svc-domain',
+    #label => 'List address domain',
+  },
+  { field=>'listnum',          type=>'hidden', },
+  { field=>'listname',         type=>'text', },
+  { field=>'reply_to',         type=>'checkbox', value=>'Y' },
+  { field=>'remove_from',      type=>'checkbox', value=>'Y' },
+  { field=>'reject_auto',      type=>'checkbox', value=>'Y' },
+  { field=>'remove_to_and_cc', type=>'checkbox', value=>'Y' },
+
+);
+
+</%init>
diff --git a/httemplate/misc/delete-mailinglistmember.html b/httemplate/misc/delete-mailinglistmember.html
new file mode 100644 (file)
index 0000000..6b91de8
--- /dev/null
@@ -0,0 +1,20 @@
+% if ( $error ) {
+%   errorpage($error);
+% } else {
+<% $cgi->redirect($p."search/mailinglistmember.html?listnum=$listnum") %>
+% }
+<%init>
+
+my($query) = $cgi->keywords;
+$query =~ /^(\d+)$/ || die "Illegal devicenum";
+my $membernum = $1;
+
+my $mailinglistmember =
+  qsearchs('mailinglistmember', { 'membernum' => $membernum } )
+    or die "unknown membernum $membernum";
+
+my $listnum = $mailinglistmember->listnum;
+
+my $error = $mailinglistmember->delete;
+
+</%init>
diff --git a/httemplate/search/mailinglistmember.html b/httemplate/search/mailinglistmember.html
new file mode 100644 (file)
index 0000000..c748c3a
--- /dev/null
@@ -0,0 +1,48 @@
+<% include('elements/search.html',
+             'title'         => $title,
+             'name_singular' => 'member',
+             'query'         => $query,
+             'count_query'   => $count_query,
+             'header'        => [ 'Email address' ],
+             'fields'        => [ $email_sub, ], #just this one for now
+             'html_init'     => $html_init,
+          )
+%>
+<%init>
+
+#XXX ACL:
+#make sure the mailing list is attached to a customer service i can see/view
+
+$cgi->param('listnum') =~ /^(\d+)$/ or die 'illegal listnum';
+my $listnum = $1;
+
+my $mailinglist = qsearchs('mailinglist', { 'listnum' => $listnum })
+  or die "unknown listnum $listnum";
+my $title = $mailinglist->listname. ' mailing list';
+
+my $query = {
+  'table' => 'mailinglistmember',
+  'hashref' => { 'listnum' => $listnum },
+};
+
+my $count_query = "SELECT COUNT(*) FROM mailinglistmember WHERE listnum = $listnum";
+
+my $email_sub = sub {
+  my $member = shift;
+  my $r = $member->email; #just this one for now
+  my $a = qq[<A HREF="javascript:areyousure('$r', ]. $member->membernum. ')">';
+  $r .= " (${a}remove</A>)";
+  $r;
+};
+
+my $html_init = <<"END";
+<SCRIPT TYPE="text/javascript">
+  function areyousure(email,membernum) {
+    if ( confirm('Are you sure you want to remove ' + email + ' from this mailing list?') )
+      window.location.href="${p}misc/delete-mailinglistmember.html?" + membernum;
+    
+  }
+</SCRIPT>
+END
+
+</%init>
diff --git a/httemplate/view/svc_mailinglist.cgi b/httemplate/view/svc_mailinglist.cgi
new file mode 100644 (file)
index 0000000..f646a41
--- /dev/null
@@ -0,0 +1,71 @@
+<% include('elements/svc_Common.html',
+             'table' => 'svc_mailinglist',
+             %opt,
+          )
+%>
+<%init>
+
+my %opt = ();
+
+my $info = FS::svc_mailinglist->table_info;
+
+$opt{'name'} = $info->{'name'};
+
+my $fields = $info->{'fields'};
+my %labels = map { $_ =>  ( ref($fields->{$_})
+                             ? $fields->{$_}{'label'}
+                             : $fields->{$_}
+                         );
+                 }
+             keys %$fields;
+
+#$opt{'fields'} = [ keys %$fields ];
+$opt{'fields'} = [
+  'username',
+  'domain',
+  'listname',
+  'reply_to',
+  'remove_from',
+  'reject_auto',
+  'remove_to_and_cc',
+];
+
+$opt{'labels'} = \%labels;
+
+$opt{'html_foot'} = sub {
+  my $svc_mailinglist = shift;
+  my $listnum = $svc_mailinglist->listnum;
+
+  my $sql = 'SELECT COUNT(*) FROM mailinglistmember WHERE listnum = ?';
+  my $sth = dbh->prepare($sql) or die dbh->errstr;
+  $sth->execute($listnum) or die $sth->errstr;
+  my $num = $sth->fetchrow_arrayref->[0];
+
+  my $add_url = $p."edit/mailinglistmember.html?listnum=$listnum";
+
+  my $add_link = include('/elements/init_overlib.html').
+                 include('/elements/popup_link.html',
+                           'action' => $add_url,
+                           'label'  => 'add',
+                           'actionlabel' => 'Add list member',
+                           'width'  => 392,
+                           'height' => 192,
+                        );
+
+  ntable('#cccccc').'<TR><TD>'.ntable('#cccccc',2). qq[
+    <TR>
+      <TD>List members</TD>
+      <TD BGCOLOR="#ffffff">
+        $num members
+        ( <A HREF="${p}search/mailinglistmember.html?listnum=$listnum">view</A>
+        | $add_link )
+      </TD>
+    </TR>
+    </TABLE></TD></TR></TABLE>
+
+    <BR><BR>
+  ]. include('svc_export_settings.html', $svc_mailinglist);
+
+};
+
+</%init>