]> git.imager.perl.org - bse.git/blobdiff - site/cgi-bin/modules/SiteUser.pm
0.14_03 commit
[bse.git] / site / cgi-bin / modules / SiteUser.pm
index af304a2e42b29b6dc6661616fd2ca708df32492b..22d2c8bf29a561a7c3ff1ff33beb4f62f1f3f59f 100644 (file)
@@ -4,13 +4,21 @@ use strict;
 use Squirrel::Row;
 use vars qw/@ISA/;
 @ISA = qw/Squirrel::Row/;
+use Constants qw($SHOP_FROM);
+use BSE::Util::SQL qw/now_datetime/;
+
+use constant MAX_UNACKED_CONF_MSGS => 3;
+use constant MIN_UNACKED_CONF_GAP => 2 * 24 * 60 * 60;
 
 sub columns {
   return qw/id userId password email keepAddress whenRegistered lastLogon
             name1 name2 address city state postcode telephone facsimile 
             country wantLetter confirmed confirmSecret waitingForConfirmation
             textOnlyMail title organization referral otherReferral
-            prompt otherPrompt profession otherProfession previousLogon/;
+            prompt otherPrompt profession otherProfession previousLogon
+            billFirstName billLastName billStreet billSuburb billState 
+            billPostCode billCountry instructions billTelephone billFacsimile 
+            billEmail adminNotes disabled/;
 }
 
 sub removeSubscriptions {
@@ -25,4 +33,121 @@ sub removeSubscription {
   SiteUsers->doSpecial('removeSub', $self->{id}, $subid);
 }
 
+sub generic_email {
+  my ($class, $checkemail) = @_;
+
+  # Build a generic form for the email - since an attacker could
+  # include comments or extra spaces or a bunch of other stuff.
+  # this isn't strictly correct, but it's good enough
+  1 while $checkemail =~ s/\([^)]\)//g;
+  if ($checkemail =~ /<([^>]+)>/) {
+    $checkemail = $1;
+  }
+  $checkemail = lc $checkemail;
+  $checkemail =~ s/\s+//g;
+
+  $checkemail;
+}
+
+sub subscriptions {
+  my ($self) = @_;
+
+  require BSE::SubscriptionTypes;
+  return BSE::SubscriptionTypes->getSpecial(userSubscribedTo => $self->{id});
+}
+
+sub send_conf_request {
+  my ($user, $cgi, $cfg, $rcode, $rmsg) = @_;
+      
+  my $nopassword = $cfg->entryBool('site users', 'nopassword', 0);
+  
+  # check for existing in-progress confirmations
+  my $checkemail = $user->generic_email($user->{email});
+  
+  # check the blacklist
+  require BSE::EmailBlacklist;
+
+  # check that the from address has been configured
+  my $from = $cfg->entry('confirmations', 'from') || 
+    $cfg->entry('basic', 'emailfrom')|| $SHOP_FROM;
+  unless ($from) {
+    $$rcode = 'config';
+    $$rmsg = "Configuration Error: The confirmations from address has not been configured";
+    return;
+  }
+
+  my $blackentry = BSE::EmailBlacklist->getEntry($checkemail);
+
+  if ($blackentry) {
+    $$rcode = "blacklist";
+    $$rmsg = $blackentry->{why};
+    return;
+  }
+  
+  unless ($user->{confirmSecret}) {
+    use BSE::Util::Secure qw/make_secret/;
+    # print STDERR "Generating secret\n";
+    $user->{confirmSecret} = make_secret($cfg);
+    $user->save;
+  }
+
+  # check for existing confirmations
+  my $confirm = BSE::EmailRequests->getBy(genEmail=>$checkemail);
+  if ($confirm) {
+    if ($confirm->{unackedConfMsgs} >= MAX_UNACKED_CONF_MSGS) {
+      $$rcode = 'toomany';
+      $$rmsg = "Too many confirmations have been sent to this email address";
+      return;
+    }
+    use BSE::Util::SQL qw/sql_datetime_to_epoch/;
+    my $lastSentEpoch = sql_datetime_to_epoch($confirm->{lastConfSent});
+    if ($lastSentEpoch + MIN_UNACKED_CONF_GAP > time) {
+      $$rcode = 'toosoon';
+      $$rmsg = "The last confirmation was sent too recently, please wait before trying again";
+      return;
+    }
+  }
+  else {
+    my %confirm;
+    my @cols = BSE::EmailRequest->columns;
+    shift @cols;
+    $confirm{email} = $user->{email};
+    $confirm{genEmail} = $checkemail;
+    # prevents silliness on error
+    use BSE::Util::SQL qw(sql_datetime);
+    $confirm{lastConfSent} = sql_datetime(time - MIN_UNACKED_CONF_GAP);
+    $confirm{unackedConfMsgs} = 0;
+    $confirm = BSE::EmailRequests->add(@confirm{@cols});
+  }
+
+  # ok, now we can send the confirmation request
+  my %confacts;
+  %confacts =
+    (
+     BSE::Util::Tags->basic(\%confacts, $cgi, $cfg),
+     user => sub { $user->{$_[0]} },
+     confirm => sub { $confirm->{$_[0]} },
+     remote_addr => sub { $ENV{REMOTE_ADDR} },
+    );
+  my $email_template = 
+    $nopassword ? 'user/email_confirm_nop' : 'user/email_confirm';
+  my $body = BSE::Template->get_page($email_template, $cfg, \%confacts);
+  
+  my $mail = BSE::Mail->new(cfg=>$cfg);
+  my $subject = $cfg->entry('confirmations', 'subject') 
+    || 'Subscription Confirmation';
+  unless ($mail->send(from=>$from, to=>$user->{email}, subject=>$subject,
+                     body=>$body)) {
+    # a problem sending the mail
+    $$rcode = "mail";
+    $$rmsg = $mail->errstr;
+    return;
+  }
+  ++$confirm->{unackedConfMsgs};
+  $confirm->{lastConfSent} = now_datetime;
+  $confirm->save;
+
+  return 1;
+}
+
 1;