RT# 75817 - fixed contact password page to be more consistant with svc password page...
authorChristopher Burger <burgerc@freeside.biz>
Thu, 6 Jul 2017 15:52:22 +0000 (11:52 -0400)
committerChristopher Burger <burgerc@freeside.biz>
Fri, 18 Aug 2017 17:08:45 +0000 (13:08 -0400)
Conflicts:
FS/FS/contact.pm
FS/FS/cust_contact.pm
httemplate/elements/contact.html

FS/FS/contact.pm
FS/FS/cust_contact.pm [new file with mode: 0644]
httemplate/elements/change_password.html
httemplate/elements/contact.html
httemplate/elements/random_pass.html
httemplate/elements/validate_password.html

index ad0de6e..76ebe98 100644 (file)
@@ -370,6 +370,15 @@ sub replace {
     }
   }
 
+  if ( $self->get('password') ) {
+    my $error = $self->is_password_allowed($self->get('password'))
+          ||  $self->change_password($self->get('password'));
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
+
   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
 
   '';
@@ -456,7 +465,7 @@ and replace methods.
 sub check {
   my $self = shift;
 
-  if ( $self->selfservice_access eq 'R' ) {
+  if ( $self->selfservice_access eq 'R' || $self->selfservice_access eq 'P' ) {
     $self->selfservice_access('Y');
     $self->_resend('Y');
   }
@@ -742,6 +751,7 @@ sub cgi_contact_fields {
 
   my @contact_fields = qw(
     classnum first last title comment emailaddress selfservice_access
+    invoice_dest password
   );
 
   push @contact_fields, 'phonetypenum'. $_->phonetypenum
diff --git a/FS/FS/cust_contact.pm b/FS/FS/cust_contact.pm
new file mode 100644 (file)
index 0000000..6820ac4
--- /dev/null
@@ -0,0 +1,151 @@
+package FS::cust_contact;
+use base qw( FS::Record );
+
+use strict;
+use FS::Record qw( qsearch qsearchs );
+
+=head1 NAME
+
+FS::cust_contact - Object methods for cust_contact records
+
+=head1 SYNOPSIS
+
+  use FS::cust_contact;
+
+  $record = new FS::cust_contact \%hash;
+  $record = new FS::cust_contact { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::cust_contact object represents a contact's attachment to a specific
+customer.  FS::cust_contact inherits from FS::Record.  The following fields are
+currently supported:
+
+=over 4
+
+=item custcontactnum
+
+primary key
+
+=item custnum
+
+custnum
+
+=item contactnum
+
+contactnum
+
+=item classnum
+
+classnum
+
+=item comment
+
+comment
+
+=item selfservice_access
+
+empty or Y
+
+=item invoice_dest
+
+'Y' if the customer should get invoices sent to this address, null if not
+
+=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 { 'cust_contact'; }
+
+=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 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;
+
+  if ( $self->selfservice_access eq 'R' || $self->selfservice_access eq 'P') {
+    $self->selfservice_access('Y');
+    $self->_resend('Y');
+  }
+
+  my $error = 
+    $self->ut_numbern('custcontactnum')
+    || $self->ut_number('custnum')
+    || $self->ut_number('contactnum')
+    || $self->ut_numbern('classnum')
+    || $self->ut_textn('comment')
+    || $self->ut_enum('selfservice_access', [ '', 'Y' ])
+    || $self->ut_flag('invoice_dest')
+  ;
+  return $error if $error;
+
+  $self->SUPER::check;
+}
+
+=item contact_classname
+
+Returns the name of this contact's class (see L<FS::contact_class>).
+
+=cut
+
+sub contact_classname {
+  my $self = shift;
+  my $contact_class = $self->contact_class or return '';
+  $contact_class->classname;
+}
+
+=back
+
+=head1 BUGS
+
+=head1 SEE ALSO
+
+L<FS::contact>, L<FS::cust_main>, L<FS::Record>
+
+=cut
+
+1;
+
index a8cc883..463384f 100644 (file)
@@ -8,69 +8,81 @@
   display: none;
 }
 </STYLE>
+% if (!$opt{'no_label_display'}) {
 <A ID="<%$pre%>link" HREF="javascript:void(0)" onclick="<%$pre%>toggle(true)">(<% emt( $change_title ) %>)</A>
+% }
 <DIV ID="<%$pre%>form" CLASS="passwordbox">
+% if (!$opt{'noformtag'}) {
   <FORM METHOD="POST" ACTION="<%$fsurl%>misc/process/change-password.html">
-    <% $change_id_input %>
-    <INPUT TYPE="text" ID="<%$pre%>password" NAME="password" VALUE="<% $curr_value |h%>">
-    <& /elements/random_pass.html, $pre.'password', 'randomize' &>
-    <INPUT TYPE="submit" VALUE="change">
-% if ($opt{'popup'}) {
-    <INPUT TYPE="button" VALUE="cancel" onclick="parent.cClick();">
 % }
-% else {
-    <INPUT TYPE="button" VALUE="cancel" onclick="<%$pre%>toggle(false)">  
+
+    <% $change_id_input %>
+    <INPUT TYPE="text" ID="<%$pre%>password" NAME="<% $opt{'pre_pwd_field_label'} %>password" VALUE="<% $curr_value |h%>">
+    <& /elements/random_pass.html, $pre.'password', 'randomize', $change_button_id &>
+% if (!$opt{'noformtag'}) {
+    <INPUT TYPE="submit" ID="<%$change_button_id%>" VALUE="change" disabled="disabled">
+% } else {
+    <INPUT TYPE="button" ID="<%$change_button_id%>" VALUE="change" onclick="<%$pre%>toggle(false)" disabled="disabled">
 %}
+    <INPUT TYPE="button" ID="<%$pre%>cancel_button" VALUE="cancel" onclick="<%$pre%>toggle(false, true)">
+
     <DIV ID="<%$pre%>password_result" STYLE="font-size: smaller"></DIV>
     <& '/elements/validate_password.html', 
          'fieldid'    => $pre.'password',
          'svcnum'     => $svcnum,
-         'contactnum' => $contactnum,
+         'contactnum' => $opt{'contact_num'},
+         'submitid'   => $change_button_id,
     &>
 % if ( $error ) {
     <BR><SPAN STYLE="color: #ff0000"><% $error |h %></SPAN>
 % }
+
+% if (!$opt{'noformtag'}) {
   </FORM>
+% }
+
 </DIV>
 <SCRIPT TYPE="text/javascript">
-function <%$pre%>toggle(val) {
+function <%$pre%>toggle(toggle, clear) {
+  if (clear) {
+    document.getElementById('<%$pre%>password').value = '';
+    document.getElementById('<%$pre%>password_result').innerHTML = '';
+% if ($opt{'contact_num'}) {
+    document.getElementById('<% $opt{'pre_pwd_field_label'} %>selfservice_access').value = 'Y';
+% }
+}
   document.getElementById('<%$pre%>form').style.display =
-    val ? 'inline-block' : 'none';
+    toggle ? 'inline-block' : 'none';
+% if (!$opt{'no_label_display'}) {
   document.getElementById('<%$pre%>link').style.display =
-    val ? 'none' : 'inline';
-}
-% if ( $error || $opt{'popup'} ) {
-<%$pre%>toggle(true);
+    toggle ? 'none' : 'inline';
 % }
+}
 </SCRIPT>
 <%init>
 my %opt = @_;
 
-my $contactnum = $opt{'contact_num'};
 my $curr_value = $opt{'curr_value'} || '';
 my $change_title = $opt{'label'} || 'change';
-
 my $svcnum;
 my $change_id_input = '';
 my $pre = 'changepw';
 
 if ($opt{'svc_acct'}) {
   my $svc_acct = $opt{'svc_acct'};
-  $change_id_input = '<INPUT TYPE="hidden" NAME="svcnum" VALUE="' . $svc_acct->svcnum . '">';
+  $change_id_input = '<INPUT TYPE="hidden" NAME="'.$opt{'pre_pwd_field_label'}.'svcnum" VALUE="' . $svc_acct->svcnum . '">';
   $pre .= $svc_acct->svcnum . '_';
   $svcnum = $svc_acct->svcnum;
 }
 elsif ($opt{'contact_num'}) {
   $change_id_input = '
-    <INPUT TYPE="hidden" NAME="contactnum" VALUE="' . $opt{'contact_num'} . '">
-    <INPUT TYPE="hidden" NAME="custnum" VALUE="' . $opt{'custnum'} . '">
+    <INPUT TYPE="hidden" NAME="'.$opt{'pre_pwd_field_label'}.'contactnum" VALUE="' . $opt{'contact_num'} . '">
+    <INPUT TYPE="hidden" NAME="'.$opt{'pre_pwd_field_label'}.'custnum" VALUE="' . $opt{'custnum'} . '">
   ';
-  $pre .= $opt{'contact_num'} . '_';
+  $pre .= $opt{'pre_pwd_field_label'};
 }
 
-if ($opt{'popup'}) {
-  $change_id_input .= '<INPUT TYPE="hidden" NAME="popup" VALUE="' . $opt{'popup'} . '">';
-}
+my $change_button_id = $pre.'change_button';
 
  my $error = $cgi->param($pre.'error');
 </%init>
index 755daed..df2107a 100644 (file)
 
         <TD>
 %         if ( $field eq 'selfservice_access' ) {
+
             <SELECT NAME = "<%$name%>_<%$field%>"
                     ID   = "<%$id%>_<%$field%>"
+                    STYLE = "width: 140px"
             >
               <OPTION VALUE="">Disabled
 %             if ( $value || $self_base_url ) {
                 <OPTION VALUE="Y" <% $value eq 'Y' ? 'SELECTED' : '' %>>Enabled
 %               if ( $value eq 'Y' && $self_base_url ) {
                   <OPTION VALUE="R">Re-email
+                  <OPTION VALUE="P"><% $pwd_change_label %>
 %               }
 %             }
             </SELECT>
-
+                  <& /elements/change_password.html,
+                   'contact_num'         => $curr_value,
+                   'custnum'             => $opt{'custnum'},
+                   'curr_value'          => '',
+                   'no_label_display'    => '1',
+                   'noformtag'           => '1',
+                   'pre_pwd_field_label' => $id.'_',
+                  &>
+            <SCRIPT TYPE="text/javascript">
+                    document.getElementById("<%$id%>_<%$field%>").onchange = function() {
+                      if (this.value == "P") { changepw<%$id%>_toggle(true); }
+                      return false
+                    }
+            </SCRIPT>
+%         } elsif ( $field eq 'invoice_dest' ) {
+%           my $curr_value = $cgi->param($name . '_' . $field);
+%           $curr_value = $value if !defined($curr_value);
+            <& select.html,
+                field         => $name . '_' . $field,
+                curr_value    => $curr_value,
+                options       => [ '', 'Y' ],
+                option_labels => { '' => 'no', 'Y' => 'yes' },
+                style         => 'width: 100%',
+            &>
 %         } else {
             <INPUT TYPE  = "text"
                    NAME  = "<%$name%>_<%$field%>"
           <FONT SIZE="-1"><% $label{$field} %></FONT>
         </TD>
 %     }
-%     my $pwd_change_label = 'change';
-%     $pwd_change_label = 'setup' unless $contact->_password;
-%     my $action = $fsurl . "edit/cust_main-contacts-password.html?custnum=" . $opt{'custnum'} . "&contactnum=" . $curr_value . "&label=" . $pwd_change_label . "&popup=1";
-%     if ($curr_value) {
-        <TD>
-          <% include('/elements/popup_link.html',
-                         'action'      => $action,
-                         'width'       => '763',
-                         'height'      => '408',
-                         'actionlabel' => "$pwd_change_label password",
-                         'html_label'  => "$pwd_change_label password",
-
-                    )
-          %>
-          <br>
-          <FONT SIZE="-1">Password</FONT>
-        </TD>
-%     }
     </TR>
   </TABLE>
 
@@ -100,9 +108,6 @@ my( %opt ) = @_;
 
 my $conf = new FS::Conf;
 
-use Data::Dumper;
-print Dumper($conf->config);
-
 my $self_base_url = $conf->config('selfservice_server-base_url');
 
 my $name = $opt{'element_name'} || $opt{'field'} || 'contactnum';
@@ -150,4 +155,7 @@ $label{'comment'} = 'Comment';
 
 my @fields = $opt{'name_only'} ? qw( first last ) : keys %label;
 
+my $pwd_change_label = 'Change Password';
+$pwd_change_label = 'Setup Password' unless $contact->_password;
+
 </%init>
index 1517a55..778aa20 100644 (file)
@@ -1,6 +1,6 @@
-<INPUT TYPE="button" VALUE="<% emt($label) %>" onclick="randomPass()">
+<INPUT TYPE="button" VALUE="<% emt($label) %>" onclick="<% $id %>randomPass()">
 <SCRIPT TYPE="text/javascript">
-function randomPass() {
+function <% $id %>randomPass() {
   var pw_set = <% $pw_set |js_string %>;
   var lower = <% $lower |js_string %>;
   var upper = <% $upper |js_string %>;
@@ -19,11 +19,15 @@ function randomPass() {
   for(var j, x, i = pass.length; i; j = Math.floor(Math.random() * i), x = pass[--i], pass[i] = pass[j], pass[j] = x);
   pass = pass.join('');
   document.getElementById('<% $id %>').value = pass;
+% if ($submitid) {
+    document.getElementById('<% $submitid %>').disabled = false;
+% }
 }
 </SCRIPT>
 <%init>
 my $id = shift;
 my $label = shift || 'Generate';
+my $submitid = shift;
 my $pw_set = join('', FS::Password_Mixin->pw_set);
 my $lower = join('', $pw_set =~ /[[:lower:]]/g);
 my $upper = join('', $pw_set =~ /[[:upper:]]/g);
index cb15029..3ca311d 100644 (file)
@@ -21,9 +21,9 @@ should be the input id plus '_result'.
     'method' => 'POST', # important not to put passwords in url
 &>
 <SCRIPT>
-function add_password_validation (fieldid) {
+function add_password_validation (fieldid, submitid) {
   var inputfield = document.getElementById(fieldid);
-  inputfield.onchange = function () {
+  inputfield.onkeyup = function () {
     var fieldid = this.id+'_result';
     var resultfield = document.getElementById(fieldid);
     if (this.value) {
@@ -37,11 +37,14 @@ function add_password_validation (fieldid) {
             var validimg = '<IMG SRC="<% $p %>images/tick.png" style="width: 1em; display: inline-block; padding-right: .5em">';
             if (result.valid) {
               resultfield.innerHTML = validimg+'<SPAN STYLE="color: green;">Password valid!</SPAN>';
+              if (submitid){ document.getElementById(submitid).disabled = false; }
             } else if (result.error) {
               resultfield.innerHTML = errorimg+'<SPAN STYLE="color: red;">'+result.error+'</SPAN>';
+              if (submitid){ document.getElementById(submitid).disabled = true; }
             } else {
               result.syserror = result.syserror || 'Server error';
               resultfield.innerHTML = errorimg+'<SPAN STYLE="color: red;">'+result.syserror+'</SPAN>';
+              if (submitid){ document.getElementById(submitid).disabled = true; }
             }
           }
         }
@@ -51,7 +54,8 @@ function add_password_validation (fieldid) {
     }
   };
 }
-add_password_validation('<% $opt{'fieldid'} %>');
+
+add_password_validation('<% $opt{'fieldid'} %>', '<% $opt{'submitid'} %>');
 </SCRIPT>
 
 <%init>