fu: Close-up of Fu, bringing a scoop of water to her mouth (Default)
fu ([personal profile] fu) wrote in [site community profile] changelog2011-10-28 11:25 am

[dw-free] self-expiring promo codes

[commit: http://hg.dwscoalition.org/dw-free/rev/1364c50df8e7]

http://bugs.dwscoalition.org/show_bug.cgi?id=3386

Allow to auto-expire promo codes.

Patch by [personal profile] rb.

Files modified:
  • bin/upgrading/update-db-general.pl
  • cgi-bin/DW/InviteCodes.pm
  • cgi-bin/DW/InviteCodes/Promo.pm
  • htdocs/admin/invites/promo.bml
  • htdocs/admin/invites/promo.bml.text
--------------------------------------------------------------------------------
diff -r ce0787149088 -r 1364c50df8e7 bin/upgrading/update-db-general.pl
--- a/bin/upgrading/update-db-general.pl	Fri Oct 28 19:14:26 2011 +0800
+++ b/bin/upgrading/update-db-general.pl	Fri Oct 28 19:26:06 2011 +0800
@@ -2972,6 +2972,7 @@
     suggest_journalid int unsigned,
     paid_class varchar(100),
     paid_months tinyint unsigned,
+    expiry_date int(10) unsigned not null default 0,
 
     PRIMARY KEY ( code )
 )
@@ -3949,6 +3950,10 @@
         do_alter( 'acctcode_promo', "ALTER TABLE acctcode_promo ADD COLUMN paid_months tinyint unsigned" );
     }
 
+    unless ( column_type( 'acctcode_promo', 'expiry_date' ) ) {
+        do_alter( 'acctcode_promo', "ALTER TABLE acctcode_promo ADD COLUMN expiry_date int(10) unsigned NOT NULL default '0'" );
+    }
+
     if ( $LJ::IS_DEV_SERVER ) {
         # strip constant definitions from user layers
         if ( table_relevant( "s2compiled2" ) && ! check_dbnote( "no_layer_constants" ) ) {
diff -r ce0787149088 -r 1364c50df8e7 cgi-bin/DW/InviteCodes.pm
--- a/cgi-bin/DW/InviteCodes.pm	Fri Oct 28 19:14:26 2011 +0800
+++ b/cgi-bin/DW/InviteCodes.pm	Fri Oct 28 19:26:06 2011 +0800
@@ -148,8 +148,7 @@
     # if it is, make sure it's active and we're not over the creation limit for the code
     my $promo_code_info = DW::InviteCodes::Promo->load( code => $code );
     if ( ref $promo_code_info ) {
-        return 0 unless $promo_code_info->{active} && ( $promo_code_info->{current_count} < $promo_code_info->{max_count} );
-        return 1;
+        return $promo_code_info->usable;
     }
 
     return 0 unless $class->could_be_code( string => $code );
diff -r ce0787149088 -r 1364c50df8e7 cgi-bin/DW/InviteCodes/Promo.pm
--- a/cgi-bin/DW/InviteCodes/Promo.pm	Fri Oct 28 19:14:26 2011 +0800
+++ b/cgi-bin/DW/InviteCodes/Promo.pm	Fri Oct 28 19:26:06 2011 +0800
@@ -100,6 +100,23 @@
 
 =head1 INSTANCE METHODS
 
+=head2 C<< $self->usable >>
+
+Checks code is available, not already used up, and not expired.
+
+=cut
+
+sub usable {
+    my ( $self ) = @_;
+        
+    return 0 unless $self->{active};
+    return 0 unless $self->{current_count} < $self->{max_count}; 
+
+    # 0 for expiry_date means never expire;
+    return 0 unless $self->{expiry_date} && time() < $self->{expiry_date};
+    return 1;
+}
+
 =head2 C<< $self->apply_for_user( $u ) >>
 
 Handle any post-create operations for this user.
@@ -151,7 +168,7 @@
     return $_[0]->{paid_class} ? $_[0]->{paid_months} : 0;
 }
 
-=head2 C<< $self->paid_type >>
+=head2 C<< $self->paid_class >>
 
 =cut
 sub paid_class {
diff -r ce0787149088 -r 1364c50df8e7 htdocs/admin/invites/promo.bml
--- a/htdocs/admin/invites/promo.bml	Fri Oct 28 19:14:26 2011 +0800
+++ b/htdocs/admin/invites/promo.bml	Fri Oct 28 19:26:06 2011 +0800
@@ -35,6 +35,7 @@
         my $errors = $_[1] || {};
         my $suggest_u = ( $data && $data->{suggest_journalid} ) ? LJ::load_userid($data->{suggest_journalid}) : undef;
         my $active = ( defined $data->{active} ) ? $data->{active} : 1;
+        my $expiry_date = $data->{expiry_date} ? LJ::mysql_date( $data->{expiry_date} ) : "";
 
         if ( $state eq 'create' ) {
             $title = $ML{'.title.create'};
@@ -69,7 +70,7 @@
         $ret .= LJ::html_text( { id => 'suggest_journal', name => 'suggest_journal', value => ( $suggest_u ? $suggest_u->username : ( $data->{suggest_journal} || "" ) ), size => 28, maxlength => 25  } );
         $ret .= "  <strong>[$ML{'.error.label'} " . join(', ', @{$errors->{suggest_journal}}) . "]</strong>" if $errors->{suggest_journal};
         $ret .= '<br />';
-        
+
         $ret .= LJ::labelfy( 'paid_class', "$ML{'.field.paid_class.label'} "  );
         $ret .= LJ::html_select( {
                 id => 'paid_class',
@@ -81,16 +82,27 @@
             { value => 'premium', text => $ML{'.field.paid_class.premium'} },
         );
         $ret .= '<br />';
-        
+
         $ret .= LJ::labelfy( 'paid_months', "$ML{'.field.paid_months.label'} "  );
         $ret .= LJ::html_text( { id => 'paid_months', name => 'paid_months', value => ( $data->{paid_months} || "" ), size => 10, maxlength => 2 } );
         $ret .= '<br />';
 
-        
+        $ret .= LJ::html_hidden( { name => 'expiry_date_unedited', value => $expiry_date } );
+
+        $ret .= LJ::labelfy( 'expiry_date', "$ML{'.field.expiry_date.label'} " );
+        $ret .= LJ::html_text( { id => 'expiry_date', name => 'expiry_date', value => $expiry_date, size => 12, maxlength => 12  } );
+        $ret .= $ML{'.field.expiry_date.format'} . ", " . $ML{'.field.expiry_date.label_extra'} . " ";
+        $ret .= LJ::html_text( { id => 'expiry_months', name => 'expiry_months', value => ( $data->{expiry_months} || "" ), size => 5, maxlength => 2 } );
+        $ret .= LJ::labelfy( 'expiry_months', "$ML{'.field.expiry_date.months'} " );
+        $ret .= LJ::html_text( { id => 'expiry_days', name => 'expiry_days', value => ( $data->{expiry_days} || "" ), size => 5, maxlength => 2 } );
+        $ret .= LJ::labelfy( 'expiry_days', "$ML{'.field.expiry_date.days'} " );
+        $ret .= "  <strong>[$ML{'.error.label'} " . join(', ', @{$errors->{expiry_date}}) . "]</strong>" if $errors->{expiry_date};
+        $ret .= "</br>";
+
         $ret .= LJ::html_submit( value => $ML{ ( $data ? '.btn.save' : '.btn.create' ) } );
         $ret .= "</form>";
     };
-    
+
     if ( LJ::did_post ) {
         return LJ::error_list( $ML{'error.invalidform'} )
             unless LJ::check_form_auth();
@@ -105,6 +117,10 @@
                 suggest_journal => $POST{suggest_journal},
                 paid_class => $POST{paid_class} || '',
                 paid_months => $POST{paid_months} || undef,
+                expiry_date_unedited => $POST{expiry_date_unedited} || 0,
+                expiry_date => $POST{expiry_date} || 0,
+                expiry_months => $POST{expiry_months} || 0,
+                expiry_days => $POST{expiry_days} || 0,
             };
             my $valid = 1;
             my $errors = {};
@@ -136,10 +152,35 @@
                 $data->{paid_class} = undef;
                 $data->{paid_months} = undef;
             }
+            
+            if ( $data->{expiry_date} ne $data->{expiry_date_unedited} ) {
+                if ( $data->{expiry_days} || $data->{expiry_months} ) {
+                    push @{$errors->{expiry_date}}, $ML{'.error.date.double_specified'};
+                    $valid = 0;
+                }
+                $data->{expiry_db} = LJ::mysqldate_to_time( $data->{expiry_date} );
+            } else {
+                if ( $data->{expiry_days} < 0 ) {
+                    push @{$errors->{expiry_date}}, $ML{'.error.days.negative'};
+                    $valid = 0;
+                }
+                if ($data->{expiry_months} < 0) {
+                    push @{$errors->{expiry_date}}, $ML{'.error.months.negative'};
+                    $valid = 0;
+                }
+                $data->{expiry_months} = 0 unless $data->{expiry_months};
+                $data->{expiry_days} = 0 unless $data->{expiry_days};
+                my $length = $data->{expiry_months} * 30 + $data->{expiry_days};
+                if ( $length ) {
+                    $data->{expiry_db} = time() + ( $length * 86400 );
+                } else {
+                    $data->{expiry_db} = 0;
+                }
+            }
             if ( $valid ) {
                 my $dbh = LJ::get_db_writer();
-                $dbh->do( "INSERT INTO acctcode_promo (code, max_count, active, suggest_journalid, paid_class, paid_months) VALUES (?, ?, ?, ?, ?, ?)", undef,
-                            $data->{code}, $data->{max_count}, $data->{active}, $data->{suggest_journalid}, $data->{paid_class}, $data->{paid_months} ) or die $dbh->errstr;
+                $dbh->do( "INSERT INTO acctcode_promo (code, max_count, active, suggest_journalid, paid_class, paid_months, expiry_date) VALUES (?, ?, ?, ?, ?, ?, ?)", undef,
+                        $data->{code}, $data->{max_count}, $data->{active}, $data->{suggest_journalid}, $data->{paid_class}, $data->{paid_months}, $data->{expiry_db} ) or die $dbh->errstr;
             } else {
                 $create_form->( $data, $errors );
                 return $ret;
@@ -155,6 +196,10 @@
                 suggest_journal => $POST{suggest_journal},
                 paid_class => $POST{paid_class} || '',
                 paid_months => $POST{paid_months} || undef,
+                expiry_date_unedited => $POST{expiry_date_unedited} || 0,
+                expiry_date => $POST{expiry_date} || 0,
+                expiry_days => $POST{expiry_days} || 0,
+                expiry_months => $POST{expiry_months} || 0,
             };
             my $valid = 1;
             my $errors = {};
@@ -186,10 +231,36 @@
                 $data->{paid_class} = undef;
                 $data->{paid_months} = undef;
             }
+           
+            if ( $data->{expiry_date} ne $data->{expiry_date_unedited} ) {
+                if ( $data->{expiry_days} || $data->{expiry_months} ) {
+                    push @{$errors->{expiry_date}}, $ML{'.error.date.double_specified'};
+                    $valid = 0;
+                }
+                $data->{expiry_db} = LJ::mysqldate_to_time( $data->{expiry_date} );
+            } else {
+                if ( $data->{expiry_days} < 0 ) {
+                    push @{$errors->{expiry_date}}, $ML{'.error.days.negative'};
+                    $valid = 0;
+                }
+                if ($data->{expiry_months} < 0) {
+                    push @{$errors->{expiry_date}}, $ML{'.error.months.negative'};
+                    $valid = 0;
+                }
+                $data->{expiry_months} = 0 unless $data->{expiry_months};
+                $data->{expiry_days} = 0 unless $data->{expiry_days};
+                my $length = $data->{expiry_months} * 30 + $data->{expiry_days};
+                if ( $length ) {
+                    $data->{expiry_db} = time() + ( $length * 86400 );
+                } else {
+                    $data->{expiry_db} = 0;
+                }
+            }
+
             if ( $valid ) {
                 my $dbh = LJ::get_db_writer();
-                $dbh->do( "UPDATE acctcode_promo SET max_count = ?, active = ?, suggest_journalid = ?, paid_class = ?, paid_months = ? WHERE code = ?", undef,
-                            $data->{max_count}, $data->{active}, $data->{suggest_journalid}, $data->{paid_class}, $data->{paid_months}, $data->{code} ) or die $dbh->errstr;
+                $dbh->do( "UPDATE acctcode_promo SET max_count = ?, active = ?, suggest_journalid = ?, paid_class = ?, paid_months = ?, expiry_date =? WHERE code = ?", undef,
+                        $data->{max_count}, $data->{active}, $data->{suggest_journalid}, $data->{paid_class}, $data->{paid_months}, $data->{expiry_db}, $data->{code} ) or die $dbh->errstr;
             } else {
                 $create_form->( $data, $errors );
                 return $ret;
@@ -214,7 +285,7 @@
         $ret .= '<a href="/admin/invites/promo?state=noneleft">' . $ML{'.state.noneleft'} . '</a>';
 
         $ret .= "<table>";
-        $ret .= "<thead><tr><th>$ML{'.heading.code'}</th><th>$ML{'.heading.active'}</th><th>$ML{'.heading.count'}</th><th>$ML{'.heading.suggest'}</th><th>$ML{'.heading.paid'}</tr></thead>";
+        $ret .= "<thead><tr><th>$ML{'.heading.code'}</th><th>$ML{'.heading.active'}</th><th>$ML{'.heading.count'}</th><th>$ML{'.heading.suggest'}</th><th>$ML{'.heading.paid'}</th><th>$ML{'.heading.expiry'}</th></tr></thead>";
         
         if ( scalar( @$codes ) ) {
             foreach my $code (@$codes) {
@@ -233,10 +304,11 @@
                 } else {
                     $ret .= "<td>$ML{'.paid.no'}</td>";
                 }
+                $ret .= "<td>" . ( $code->{expiry_date} ? LJ::mysql_date( $code->{expiry_date} ) : $ML{'.expiry.none'} ) . "</td>";
                 $ret .= "</tr>";
             }
         } else {
-            $ret .= '<tr><th colspan="4">' . $ML{'.nomatch'} . '</th></tr>';
+            $ret .= '<tr><th colspan="5">' . $ML{'.nomatch'} . '</th></tr>';
         }
         $ret .= "</table>";
     }
@@ -252,3 +324,4 @@
 </style>
 <=head
 page?>
+
diff -r ce0787149088 -r 1364c50df8e7 htdocs/admin/invites/promo.bml.text
--- a/htdocs/admin/invites/promo.bml.text	Fri Oct 28 19:14:26 2011 +0800
+++ b/htdocs/admin/invites/promo.bml.text	Fri Oct 28 19:26:06 2011 +0800
@@ -23,6 +23,14 @@
 
 .error.suggest_journal.invalid=Cannot find that user
 
+.error.months.negative=Months until expiry must be positive or zero
+
+.error.days.negative=Days until expiry must be positive or zero
+
+.error.date.double_specified=You can't specify both an expiry date and months/days to add.
+
+.expiry.none=(none)
+
 .field.active.label=Active
 
 .field.code.label=Code:
@@ -41,6 +49,16 @@
 
 .field.suggest_journal.label=Suggest Journal:
 
+.field.expiry_date.label=Expiry Date:
+
+.field.expiry_date.format=(YYYY-MM-DD)
+
+.field.expiry_date.label_extra=or add time
+
+.field.expiry_date.months=months
+
+.field.expiry_date.days=days
+
 .heading.active=Active
 
 .heading.code=Code
@@ -51,6 +69,8 @@
 
 .heading.suggest=Suggest Journal
 
+.heading.expiry=Expiry Date
+
 .nomatch=No promo codes match your criteria
 
 .paid=[[type]] for [[months]] [[?months|month|months]]
--------------------------------------------------------------------------------
pne: A picture of a plush toy, halfway between a duck and a platypus, with a green body and a yellow bill and feet. (Default)

[personal profile] pne 2011-10-28 03:40 pm (UTC)(link)
do_alter( 'acctcode_promo', "ALTER TABLE acctcode_promo ADD COLUMN expiry_date int(10) unsigned NOT NULL default '0'" );

Why the quotes around the '0'?

They don't match the "create table" statement, and they don't make a lot of sense to me for an int column.
mark: A photo of Mark kneeling on top of the Taal Volcano in the Philippines. It was a long hike. (Default)

[staff profile] mark 2011-10-28 07:57 pm (UTC)(link)
It's probably a copy-paste, I've certainly used the quotes when defining defaults for a numeric column in the past. It doesn't hurt it any. It's totally not necessary, either -- the default for a NOT NULL column is whatever that column's zero value is -- 0 for numeric columns.