password policy enforcement for contacts, #32456
[freeside.git] / FS / FS / ClientAPI / MyAccount / contact.pm
1 package FS::ClientAPI::MyAccount::contact;
2
3 use strict;
4 use FS::Record qw( qsearchs );
5 use FS::cust_main;
6 use FS::contact;
7
8 sub _custoragent_session_custnum {
9   FS::ClientAPI::MyAccount::_custoragent_session_custnum(@_);
10 }
11
12 sub contact_passwd {
13   my $p = shift;
14   my($context, $session, $custnum) = _custoragent_session_custnum($p);
15   return { 'error' => $session } if $context eq 'error';
16
17   return { 'error' => 'Not logged in as a contact.' }
18     unless $session->{'contactnum'};
19
20   return { 'error' => 'Enter new password' }
21     unless length($p->{'new_password'});
22
23   my $contact = _contact( $session->{'contactnum'}, $custnum )
24     or return { 'error' => "Email not found" };
25
26   my $error = '';
27
28   # use these svc_acct length restrictions??
29   my $conf = new FS::Conf;
30   $error = 'Password too short.'
31     if length($p->{'new_password'}) < ($conf->config('passwordmin') || 6);
32   $error = 'Password too long.'
33     if length($p->{'new_password'}) > ($conf->config('passwordmax') || 8);
34
35   $error ||= $contact->is_password_allowed($p->{'new_password'});
36
37   $error ||= $contact->change_password($p->{'new_password'});
38
39   return { 'error' => $error };
40
41 }
42
43 sub _contact {
44   my( $contactnum, $custnum ) = @_;
45
46   #my $search = { 'custnum' => $custnum };
47   #$search->{'agentnum'} = $session->{'agentnum'} if $context eq 'agent';
48   $custnum =~ /^(\d+)$/ or die "illegal custnum";
49   my $search = " AND contact.selfservice_access IS NOT NULL ".
50                " AND contact.selfservice_access = 'Y' ".
51                " AND ( disabled IS NULL OR disabled = '' )".
52                " AND custnum = $1";
53 #  $search .= " AND agentnum = ". $session->{'agentnum'} if $context eq 'agent';
54
55   qsearchs( {
56     'table'     => 'contact',
57     'addl_from' => 'LEFT JOIN cust_main USING ( custnum ) ',
58     'hashref'   => { 'contactnum' => $contactnum, },
59     'extra_sql' => $search, #important
60   } );
61
62 }
63
64 sub list_contacts {
65   my $p = shift;
66
67   my($context, $session, $custnum) = _custoragent_session_custnum($p);
68   return { 'error' => $session } if $context eq 'error';
69
70   my $cust_main = qsearchs('cust_main', { custnum=>$custnum } );
71
72   my @contacts = ( map {
73     my $contact = $_->contact;
74     my @contact_email = $_->contact_email;
75     { 'contactnum'         => $_->contactnum,
76       'class'              => $_->contact_classname,
77       'first'              => $_->first,
78       'last'               => $_->get('last'),
79       'title'              => $_->title,
80       'emailaddress'       => join(',', map $_->emailaddress, @contact_email),
81       #TODO: contact phone numbers
82       'comment'            => $_->comment,
83       'selfservice_access' => $_->selfservice_access,
84       #'disabled'           => $_->disabled,
85     };
86   } $cust_main->cust_contact );
87
88   return { 'error'    => '',
89            'contacts' => \@contacts,
90          };
91 }
92
93 sub edit_contact {
94   my $p = shift;
95
96   my($context, $session, $custnum) = _custoragent_session_custnum($p);
97   return { 'error' => $session } if $context eq 'error';
98
99   #shortcut: logged in as a contact?  that must be the one you want to edit
100   my $contactnum = $p->{contactnum} || $session->{'contactnum'};
101
102   my $contact = _contact( $contactnum, $custnum )
103     or return { 'error' => "Email not found" };
104
105   #TODO: change more fields besides just these
106
107   foreach (qw( first last title emailaddress )) {
108     $contact->$_( $p->{$_} ) if length( $p->{$_} );
109   }
110
111   my $error = $contact->replace;
112
113   return { 'error' => $error, };
114
115 }
116
117 sub delete_contact {
118   my $p = shift;
119
120   my($context, $session, $custnum) = _custoragent_session_custnum($p);
121   return { 'error' => $session } if $context eq 'error';
122
123   return { 'error' => 'Cannot delete the currently-logged in contact.' }
124     if $p->{contactnum} == $session->{contactnum};
125
126   my $contact = qsearchs('contact', { contactnum =>$ p->{contactnum},
127                                       custnum    => $custnum,         } )
128     or return { 'error' => 'Unknown contactnum' };
129
130   my $error = $contact->delete;
131   return { 'error' => $error } if $error;
132
133   return { 'error' => '', };
134 }
135
136 sub new_contact {
137   my $p = shift;
138
139   my($context, $session, $custnum) = _custoragent_session_custnum($p);
140   return { 'error' => $session } if $context eq 'error';
141
142   #TODO: add phone numbers too
143   #TODO: specify a classnum by name and/or list_contact_classes method
144
145   my $contact = new FS::contact {
146     'custnum' => $custnum,
147     map { $_ => $p->{$_} }
148       qw( first last emailaddress classnum comment selfservice_access )
149   };
150
151   $contact->change_password_fields($p->{_password}) if length($p->{_password});
152
153   my $error = $contact->insert;
154   return { 'error' => $error, };
155 }
156
157 1;