contact self-service pw changes, RT#37023
authorIvan Kohler <ivan@freeside.biz>
Tue, 21 Jul 2015 02:09:54 +0000 (19:09 -0700)
committerIvan Kohler <ivan@freeside.biz>
Tue, 21 Jul 2015 02:09:54 +0000 (19:09 -0700)
FS/FS/ClientAPI/MyAccount.pm
FS/FS/ClientAPI/MyAccount/contact.pm [new file with mode: 0644]
FS/FS/ClientAPI_XMLRPC.pm
FS/MANIFEST
bin/xmlrpc-contact_passwd [new file with mode: 0755]
bin/xmlrpc-edit_contact [new file with mode: 0755]
fs_selfservice/FS-SelfService/SelfService.pm

index 738f7e1..92c7c1c 100644 (file)
@@ -48,7 +48,9 @@ use FS::msg_template;
 use FS::contact;
 use FS::cust_location;
 
-use FS::ClientAPI::MyAccount::quotation; # just for code organization
+# for code organization
+use FS::ClientAPI::MyAccount::contact;
+use FS::ClientAPI::MyAccount::quotation;
 
 $DEBUG = 0;
 $me = '[FS::ClientAPI::MyAccount]';
@@ -241,6 +243,8 @@ sub login {
     return { error => 'Incorrect contact password.' }
       unless $contact->authenticate_password($p->{'password'});
 
+    $session->{'contactnum'} = $contact->contactnum;
+
     $session->{'custnum'} = $contact->custnum;
 
   } else {
@@ -2962,53 +2966,6 @@ sub myaccount_passwd {
 
 }
 
-#  sub contact_passwd {
-#    my $p = shift;
-#    my($context, $session, $custnum) = _custoragent_session_custnum($p);
-#    return { 'error' => $session } if $context eq 'error';
-#  
-#    return { 'error' => 'Not logged in as a contact.' }
-#      unless $session->{'contactnum'};
-#  
-#    return { 'error' => "New passwords don't match." }
-#      if $p->{'new_password'} ne $p->{'new_password2'};
-#  
-#    return { 'error' => 'Enter new password' }
-#      unless length($p->{'new_password'});
-#  
-#    #my $search = { 'custnum' => $custnum };
-#    #$search->{'agentnum'} = $session->{'agentnum'} if $context eq 'agent';
-#    $custnum =~ /^(\d+)$/ or die "illegal custnum";
-#    my $search = " AND selfservice_access IS NOT NULL ".
-#                 " AND selfservice_access = 'Y' ".
-#                 " AND ( disabled IS NULL OR disabled = '' )".
-#                 " AND custnum IS NOT NULL AND custnum = $1";
-#    $search .= " AND agentnum = ". $session->{'agentnum'} if $context eq 'agent';
-#  
-#    my $contact = qsearchs( {
-#      'table'     => 'contact',
-#      'addl_from' => 'LEFT JOIN cust_main USING ( custnum ) ',
-#      'hashref'   => { 'contactnum' => $session->{'contactnum'}, },
-#      'extra_sql' => $search, #important
-#    } )
-#      or return { 'error' => "Email not found" }; #?  how did we get logged in?
-#                                                  # deleted since then?
-#  
-#    my $error = '';
-#  
-#    # use these svc_acct length restrictions??
-#    my $conf = new FS::Conf;
-#    $error = 'Password too short.'
-#      if length($p->{'new_password'}) < ($conf->config('passwordmin') || 6);
-#    $error = 'Password too long.'
-#      if length($p->{'new_password'}) > ($conf->config('passwordmax') || 8);
-#  
-#    $error ||= $contact->change_password($p->{'new_password'});
-#  
-#    return { 'error' => $error, };
-#  
-#  }
-
 sub reset_passwd {
   my $p = shift;
 
diff --git a/FS/FS/ClientAPI/MyAccount/contact.pm b/FS/FS/ClientAPI/MyAccount/contact.pm
new file mode 100644 (file)
index 0000000..a586033
--- /dev/null
@@ -0,0 +1,132 @@
+package FS::ClientAPI::MyAccount::contact;
+
+use strict;
+use FS::Record qw( qsearchs );
+use FS::cust_main;
+use FS::cust_contact;
+use FS::contact;
+
+sub _custoragent_session_custnum {
+  FS::ClientAPI::MyAccount::_custoragent_session_custnum(@_);
+}
+
+sub contact_passwd {
+  my $p = shift;
+  my($context, $session, $custnum) = _custoragent_session_custnum($p);
+  return { 'error' => $session } if $context eq 'error';
+
+  return { 'error' => 'Not logged in as a contact.' }
+    unless $session->{'contactnum'};
+
+  return { 'error' => 'Enter new password' }
+    unless length($p->{'new_password'});
+
+  my $contact = _contact( $session->{'contactnum'}, $custnum )
+    or return { 'error' => "Email not found" };
+
+  my $error = '';
+
+  # use these svc_acct length restrictions??
+  my $conf = new FS::Conf;
+  $error = 'Password too short.'
+    if length($p->{'new_password'}) < ($conf->config('passwordmin') || 6);
+  $error = 'Password too long.'
+    if length($p->{'new_password'}) > ($conf->config('passwordmax') || 8);
+
+  $error ||= $contact->change_password($p->{'new_password'});
+
+  return { 'error' => $error };
+
+}
+
+sub _contact {
+  my( $contactnum, $custnum ) = @_;
+
+  #my $search = { 'custnum' => $custnum };
+  #$search->{'agentnum'} = $session->{'agentnum'} if $context eq 'agent';
+  $custnum =~ /^(\d+)$/ or die "illegal custnum";
+  my $search = " AND contact.selfservice_access IS NOT NULL ".
+               " AND contact.selfservice_access = 'Y' ".
+               " AND ( disabled IS NULL OR disabled = '' )".
+               " AND custnum = $1";
+#  $search .= " AND agentnum = ". $session->{'agentnum'} if $context eq 'agent';
+
+  qsearchs( {
+    'table'     => 'contact',
+    'addl_from' => 'LEFT JOIN cust_main USING ( custnum ) ',
+    'hashref'   => { 'contactnum' => $contactnum, },
+    'extra_sql' => $search, #important
+  } );
+
+}
+
+sub list_contacts {
+  my $p = shift;
+
+  my($context, $session, $custnum) = _custoragent_session_custnum($p);
+  return { 'error' => $session } if $context eq 'error';
+
+  my $cust_main = qsearchs('cust_main', { custnum=>$custnum } );
+
+  my @contacts = ( map {
+    my $contact = $_->contact;
+    my @contact_email = $_->contact_email;
+    { 'contactnum'         => $_->contactnum,
+      'class'              => $_->contact_classname,
+      'first'              => $_->first,
+      'last'               => $_->get('last'),
+      'title'              => $_->title,
+      'emailaddress'       => join(',', map $_->emailaddress, @contact_email),
+      #TODO: contact phone numbers
+      'comment'            => $_->comment,
+      'selfservice_access' => $_->selfservice_access,
+      'disabled'           => $_->disabled,
+    };
+  } $cust_main->cust_contact );
+
+  return { 'error'    => '',
+           'contacts' => \@contacts,
+         };
+}
+
+sub edit_contact {
+  my $p = shift;
+
+  my($context, $session, $custnum) = _custoragent_session_custnum($p);
+  return { 'error' => $session } if $context eq 'error';
+
+  #shortcut: logged in as a contact?  that must be the one you want to edit
+  my $contactnum = $p->{contactnum} || $session->{'contactnum'};
+
+  my $contact = _contact( $contactnum, $custnum )
+    or return { 'error' => "Email not found" };
+
+  #TODO: change more fields besides just these
+
+  foreach (qw( first last title emailaddress )) {
+    $contact->$_( $p->{$_} ) if length( $p->{$_} );
+  }
+
+  my $error = $contact->replace;
+
+  return { 'error' => $error, };
+
+}
+
+sub delete_contact {
+  my $p = shift;
+
+  my($context, $session, $custnum) = _custoragent_session_custnum($p);
+  return { 'error' => $session } if $context eq 'error';
+
+  my $contact = qsearchs('contact', { contactnum =>$ p->{contactnum},
+                                      custnum    => $custnum,         } )
+    or return { 'error' => 'Unknown contactnum' };
+
+  my $error = $contact->delete;
+  return { 'error' => $error } if $error;
+
+  return { 'error' => '', };
+}
+
+1;
index 74d6854..219f741 100644 (file)
@@ -105,6 +105,12 @@ sub ss2clientapi {
   'switch_acct'               => 'MyAccount/switch_acct',
   'customer_info'             => 'MyAccount/customer_info',
   'customer_info_short'       => 'MyAccount/customer_info_short',
+
+  'contact_passwd'            => 'MyAccount/contact/contact_passwd',
+  'list_contacts'             => 'MyAccount/contact/list_contacts',
+  'edit_contact'              => 'MyAccount/contact/edit_contact',
+  'delete_contact'            => 'MyAccount/contact/delete_contact',
+
   'billing_history'           => 'MyAccount/billing_history',
   'edit_info'                 => 'MyAccount/edit_info',     #add to ss cgi!
   'invoice'                   => 'MyAccount/invoice',
index c828bd6..5698bf4 100644 (file)
@@ -36,6 +36,8 @@ FS/ClientAPI/passwd.pm
 FS/ClientAPI/Agent.pm
 FS/ClientAPI/MasonComponent.pm
 FS/ClientAPI/MyAccount.pm
+FS/ClientAPI/MyAccount/contact.pm
+FS/ClientAPI/MyAccount/quotation.pm
 FS/ClientAPI/PrepaidPhone.pm
 FS/ClientAPI/Signup.pm
 FS/Conf.pm
diff --git a/bin/xmlrpc-contact_passwd b/bin/xmlrpc-contact_passwd
new file mode 100755 (executable)
index 0000000..1a89d42
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/bin/perl
+
+use strict;
+use Frontier::Client;
+use Data::Dumper;
+
+my( $email, $current_pw, $new_pw ) = @ARGV;
+
+my $uri = new URI 'http://localhost:8080/';
+
+my $server = new Frontier::Client ( 'url' => $uri );
+
+my $login_result = $server->call(
+  'FS.ClientAPI_XMLRPC.login',
+    'email'    => $email,
+    'password' => $current_pw,
+);
+die $login_result->{'error'}."\n" if $login_result->{'error'};
+
+my $passwd_result = $server->call(
+  'FS.ClientAPI_XMLRPC.contact_passwd',
+    'session_id'   => $login_result->{'session_id'},
+    'new_password' => $new_pw,
+);
+die $passwd_result->{'error'}."\n" if $passwd_result->{'error'};
+
+warn "Password changed.\n";
+
+1;
diff --git a/bin/xmlrpc-edit_contact b/bin/xmlrpc-edit_contact
new file mode 100755 (executable)
index 0000000..574284b
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/bin/perl
+
+use strict;
+use Frontier::Client;
+use Data::Dumper;
+
+my( $email, $password, $new_email ) = @ARGV;
+
+my $uri = new URI 'http://localhost:8080/';
+
+my $server = new Frontier::Client ( 'url' => $uri );
+
+my $login_result = $server->call(
+  'FS.ClientAPI_XMLRPC.login',
+    'email'    => $email,
+    'password' => $password,
+);
+die $login_result->{'error'}."\n" if $login_result->{'error'};
+
+my $passwd_result = $server->call(
+  'FS.ClientAPI_XMLRPC.edit_contact',
+    'session_id'   => $login_result->{'session_id'},
+    'emailaddress' => $new_email,
+);
+die $passwd_result->{'error'}."\n" if $passwd_result->{'error'};
+
+warn "Email changed.\n";
+
+1;
index 21bc920..96df7b3 100644 (file)
@@ -32,6 +32,12 @@ $socket .= '.'.$tag if defined $tag && length($tag);
   'switch_acct'               => 'MyAccount/switch_acct',
   'customer_info'             => 'MyAccount/customer_info',
   'customer_info_short'       => 'MyAccount/customer_info_short',
+
+  'contact_passwd'            => 'MyAccount/contact/contact_passwd',
+  'list_contacts'             => 'MyAccount/contact/list_contacts',
+  'edit_contact'              => 'MyAccount/contact/edit_contact',
+  'delete_contact'            => 'MyAccount/contact/delete_contact',
+
   'billing_history'           => 'MyAccount/billing_history',
   'edit_info'                 => 'MyAccount/edit_info',     #add to ss cgi!
   'invoice'                   => 'MyAccount/invoice',
@@ -507,7 +513,7 @@ Invoice text
 
 =item list_invoices HASHREF
 
-Returns a list of all customer invoices.  Takes a hash references with a single
+Returns a list of all customer invoices.  Takes a hash reference with a single
 key, session_id.
 
 Returns a hash reference with the following keys:
@@ -1195,7 +1201,7 @@ error message on errors.
 
 Provisions an account (svc_acct).
 
-Takes a hash references as parameter with the following keys:
+Takes a hash reference as parameter with the following keys:
 
 =over 4
 
@@ -1223,7 +1229,7 @@ svcpart or service definition to provision
 
 Provisions a phone number (svc_phone).
 
-Takes a hash references as parameter with the following keys:
+Takes a hash reference as parameter with the following keys:
 
 =over 4
 
@@ -1265,7 +1271,7 @@ E911 Address (optional)
 
 Provisions a customer PBX (svc_pbx).
 
-Takes a hash references as parameter with the following keys:
+Takes a hash reference as parameter with the following keys:
 
 =over 4
 
@@ -1297,7 +1303,7 @@ svcpart or service definition to provision
 
 Provisions an external service (svc_external).
 
-Takes a hash references as parameter with the following keys:
+Takes a hash reference as parameter with the following keys:
 
 =over 4
 
@@ -1321,6 +1327,57 @@ svcpart or service definition to provision
 
 =back
 
+=head2 "MY ACCOUNT" CONTACT FUNCTIONS
+
+=over 4
+
+=item contact_passwd
+
+Changes the password for the currently-logged in contact.
+
+Takes a hash reference as parameter with the following keys:
+
+=over 4
+
+=item session_id
+
+=item new_password
+
+=back
+
+Returns a hash reference with a single parameter, B<error>, which contains an
+error message, or empty on success.
+
+=item list_contacts
+
+=item edit_contact
+
+Updates information for the currently-logged in contact, or (optionally) the
+specified contact
+
+Takes a hash reference as parameter with the following keys:
+
+=over 4
+
+=item session_id
+
+=item contactnum
+
+If already logged in as a contact, this is optional.
+
+=item first
+
+=item last
+
+=item emailaddress
+
+=back
+
+Returns a hash reference with a single parameter, B<error>, which contains an
+error message, or empty on success.
+
+=item delete_contact
+
 =head2 "MY ACCOUNT" QUOTATION FUNCTIONS
 
 All of these functions require the user to be logged in, and the 'session_id'
@@ -1333,12 +1390,33 @@ key to be included in the argument hashref.`
 Returns a hashref listing this customer's active self-service quotations.
 Contents are:
 
-- 'quotations', an arrayref containing an element for each quotation.
-  - quotationnum, the primary key
-  - _date, the date it was started
-  - num_pkgs, the number of packages
-  - total_setup, the sum of setup fees
-  - total_recur, the sum of recurring charges
+=over 4
+
+=item quotations
+
+an arrayref containing an element for each quotation.
+
+=item quotationnum
+
+the primary key
+
+=item _date
+
+the date it was started
+
+=item num_pkgs
+
+the number of packages
+
+=item total_setup
+
+the sum of setup fees
+
+=item total_recur
+
+the sum of recurring charges
+
+=back
 
 =item quotation_new HASHREF