From 8f809c417ee15614307901a8040e41aeb72cf78c Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Mon, 20 Jul 2015 19:09:54 -0700 Subject: [PATCH] contact self-service pw changes, RT#37023 --- FS/FS/ClientAPI/MyAccount.pm | 53 +---------- FS/FS/ClientAPI/MyAccount/contact.pm | 132 +++++++++++++++++++++++++++ FS/FS/ClientAPI_XMLRPC.pm | 6 ++ FS/MANIFEST | 2 + bin/xmlrpc-contact_passwd | 29 ++++++ bin/xmlrpc-edit_contact | 29 ++++++ fs_selfservice/FS-SelfService/SelfService.pm | 100 +++++++++++++++++--- 7 files changed, 292 insertions(+), 59 deletions(-) create mode 100644 FS/FS/ClientAPI/MyAccount/contact.pm create mode 100755 bin/xmlrpc-contact_passwd create mode 100755 bin/xmlrpc-edit_contact diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm index 738f7e197..92c7c1cd8 100644 --- a/FS/FS/ClientAPI/MyAccount.pm +++ b/FS/FS/ClientAPI/MyAccount.pm @@ -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 index 000000000..a58603318 --- /dev/null +++ b/FS/FS/ClientAPI/MyAccount/contact.pm @@ -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; diff --git a/FS/FS/ClientAPI_XMLRPC.pm b/FS/FS/ClientAPI_XMLRPC.pm index 74d685479..219f7419a 100644 --- a/FS/FS/ClientAPI_XMLRPC.pm +++ b/FS/FS/ClientAPI_XMLRPC.pm @@ -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', diff --git a/FS/MANIFEST b/FS/MANIFEST index c828bd68b..5698bf4a2 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -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 index 000000000..1a89d4260 --- /dev/null +++ b/bin/xmlrpc-contact_passwd @@ -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 index 000000000..574284bbc --- /dev/null +++ b/bin/xmlrpc-edit_contact @@ -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; diff --git a/fs_selfservice/FS-SelfService/SelfService.pm b/fs_selfservice/FS-SelfService/SelfService.pm index 21bc9205a..96df7b310 100644 --- a/fs_selfservice/FS-SelfService/SelfService.pm +++ b/fs_selfservice/FS-SelfService/SelfService.pm @@ -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, 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, 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 -- 2.11.0