afuna: Cat under a blanket. Text: "Cats are just little people with Fur and Fangs" (Default)
afuna ([personal profile] afuna) wrote in [site community profile] changelog2009-08-08 12:28 pm

[dw-free] Random Account Sponsorship/Paid Account Fairy

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

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

Add links to /shop so you can sponsor random free accounts. Users can opt-
out under the Privacy tab.

Patch by [personal profile] janinedog.

Files modified:
  • bin/upgrading/en.dat
  • bin/upgrading/proplists.dat
  • bin/upgrading/update-db-general.pl
  • cgi-bin/DW/Pay.pm
  • cgi-bin/DW/Shop/Item/Account.pm
  • cgi-bin/DW/Widget/ShopItemGroupDisplay.pm
  • cgi-bin/LJ/User.pm
  • cgi-bin/LJ/Widget/ShopCart.pm
  • cgi-bin/LJ/Widget/ShopItemOptions.pm
  • htdocs/manage/settings/index.bml
  • htdocs/shop/account.bml
  • htdocs/shop/account.bml.text
--------------------------------------------------------------------------------
diff -r 255031e8e79e -r d23c0007a311 bin/upgrading/en.dat
--- a/bin/upgrading/en.dat	Fri Aug 07 15:42:52 2009 +0000
+++ b/bin/upgrading/en.dat	Sat Aug 08 12:18:52 2009 +0000
@@ -2727,6 +2727,14 @@ setting.prod.display.title=New Setting!
 
 setting.profileemail.label=Email to display on your profile
 
+setting.randompaidgifts.label=Random Paid Gifts
+
+setting.randompaidgifts.option=Include yourself in the pool of free users who can be randomly selected by our sponsor-a-free-user program.
+
+setting.randompaidgifts.option.paid=If your paid account expires, include yourself in the pool of free users who can be randomly selected by our sponsor-a-free-user program.
+
+setting.randompaidgifts.option.note=You may receive a paid account from someone you do not know.
+
 setting.safesearch.error.invalid=Invalid safe search setting.
 
 setting.safesearch.label=Safe Search Filter
@@ -3126,6 +3134,40 @@ The [[sitename]] Team
 
 shop.email.user.other.subject=[[sitename]] Account Purchase
 
+shop.email.user.random.body<<
+Dear [[touser]],
+
+Your account has been randomly selected to receive [[fromuser]]'s payment
+through our sponsor-a-free-user program.  The account that was purchased is:
+
+    [[accounttype]]
+
+Congratulations on your paid time!
+
+
+Regards,
+The [[sitename]] Team
+.
+
+shop.email.user.random.subject=[[sitename]] Account Purchase
+
+shop.email.user.random_anon.body<<
+Dear [[touser]],
+
+Your account has been randomly selected to receive someone's payment through our
+sponsor-a-free-user program.  The account that was purchased is:
+
+    [[accounttype]]
+
+Congratulations on your paid time!
+
+
+Regards,
+The [[sitename]] Team
+.
+
+shop.email.user.random_anon.subject=[[sitename]] Account Purchase
+
 shop.email.user.self.body<<
 Dear [[touser]],
 
@@ -3263,6 +3305,8 @@ shop.item.account.conflicts.multipleperm
 
 shop.item.account.name=[[name]] ([[num]] [[?num|month|months]])
 
+shop.item.account.randomuser=Random active free user
+
 sitescheme.accountlinks.account=Account
 
 sitescheme.accountlinks.btn.login=Log in
@@ -4526,6 +4570,8 @@ widget.shopcart.header.item=Item
 
 widget.shopcart.header.price=Price
 
+widget.shopcart.header.random=Random?
+
 widget.shopcart.header.remove=Remove?
 
 widget.shopcart.header.to=To
@@ -4556,6 +4602,10 @@ widget.shopitemgroupdisplay.paidaccounts
 
 widget.shopitemgroupdisplay.paidaccounts.item.newaccount=<a [[aopts]]>For a new account</a>
 
+widget.shopitemgroupdisplay.paidaccounts.item.randomaccount.noshow=<a [[aopts]]>For an anonymous random active free account</a>
+
+widget.shopitemgroupdisplay.paidaccounts.item.randomaccount.show=<a [[aopts]]>For an identified random active free account</a>
+
 widget.shopitemgroupdisplay.paidaccounts.item.self=<a [[aopts]]>For yourself</a> ([[user]])
 
 widget.shopitemoptions.error.banned=You are restricted from making purchases for this journal.
@@ -4565,6 +4615,8 @@ widget.shopitemoptions.error.nocart=Unab
 widget.shopitemoptions.error.nocart=Unable to get a shopping cart for you.  Please try again later.
 
 widget.shopitemoptions.error.notloggedin=You must be logged in as a personal account in order to purchase paid time for yourself.
+
+widget.shopitemoptions.error.nousers=There are currently no active free users.
 
 widget.shopitemoptions.header.paid=Paid Account
 
diff -r 255031e8e79e -r d23c0007a311 bin/upgrading/proplists.dat
--- a/bin/upgrading/proplists.dat	Fri Aug 07 15:42:52 2009 +0000
+++ b/bin/upgrading/proplists.dat	Sat Aug 08 12:18:52 2009 +0000
@@ -1203,6 +1203,14 @@ logproplist.opt_preformatted:
   sortorder: 20
   ownership: user
 
+userproplist.opt_randompaidgifts:
+  cldversion: 4
+  datatype: char
+  des: N = don't allow this user to receive random paid gifts, otherwise allow it
+  indexed: 1
+  multihomed: 0
+  prettyname: Random Paid Gifts
+
 logproplist.opt_screening:
   datatype: char
   des: Like opt_whoscreened: A = All, R = Remote needed (anonymous only), F = non-Friends, N = None, else use userprop.
diff -r 255031e8e79e -r d23c0007a311 bin/upgrading/update-db-general.pl
--- a/bin/upgrading/update-db-general.pl	Fri Aug 07 15:42:52 2009 +0000
+++ b/bin/upgrading/update-db-general.pl	Sat Aug 08 12:18:52 2009 +0000
@@ -3282,6 +3282,17 @@ CREATE TABLE acctcode_promo (
 )
 EOC
 
+register_tablecreate('users_for_paid_accounts', <<'EOC');
+CREATE TABLE users_for_paid_accounts (
+    userid int unsigned not null,
+    time_inserted int unsigned not null default 0,
+    points int(5) unsigned not null default 0,
+
+    PRIMARY KEY ( userid, time_inserted ),
+    INDEX ( time_inserted )
+)
+EOC
+
 
 # NOTE: new table declarations go ABOVE here ;)
 
diff -r 255031e8e79e -r d23c0007a311 cgi-bin/DW/Pay.pm
--- a/cgi-bin/DW/Pay.pm	Fri Aug 07 15:42:52 2009 +0000
+++ b/cgi-bin/DW/Pay.pm	Sat Aug 08 12:18:52 2009 +0000
@@ -560,6 +560,53 @@ sub num_permanent_accounts_available_est
 }
 
 ################################################################################
+# DW::Pay::get_random_active_free_user
+#
+# ARGUMENTS: for_u = user that is requesting the random free user (remote if
+#            no user is given)
+#
+# RETURN: a random active free user that for_u can purchase a paid account for,
+#         or undef if there aren't any valid results
+#
+sub get_random_active_free_user {
+    my $for_u = shift || LJ::get_remote();
+
+    my $dbr = LJ::get_db_reader();
+    my $rows = $dbr->selectall_arrayref( "SELECT userid, points FROM users_for_paid_accounts", { Slice => {} } );
+
+    my @active_us;
+    my $us = LJ::load_userids( map { $_->{userid} } @$rows );
+    foreach my $row ( @$rows ) {
+        my $userid = $row->{userid};
+        my $points = $row->{points};
+        my $u = $us->{$userid};
+
+        next unless $u;
+        next unless $u->is_visible;
+        next unless $u->is_personal;
+        next if $u->is_paid;
+        next unless $u->opt_randompaidgifts;
+        next if LJ::sysban_check( 'pay_user', $u->user );
+        next if $for_u && $u->equals( $for_u );
+        next if $for_u && $u->has_banned( $for_u );
+
+        # each point that a user has gives them an extra chance of being chosen out of the array
+        push @active_us, $u;
+        if ( $points ) {
+            foreach my $point ( 1..$points ) {
+                push @active_us, $u;
+            }
+        }
+    }
+
+    return undef unless scalar @active_us;
+
+    my @shuffled_us = List::Util::shuffle( @active_us );
+
+    return $shuffled_us[0];
+}
+
+################################################################################
 ################################################################################
 ################################################################################
 
diff -r 255031e8e79e -r d23c0007a311 cgi-bin/DW/Shop/Item/Account.pm
--- a/cgi-bin/DW/Shop/Item/Account.pm	Fri Aug 07 15:42:52 2009 +0000
+++ b/cgi-bin/DW/Shop/Item/Account.pm	Sat Aug 08 12:18:52 2009 +0000
@@ -53,6 +53,14 @@ sub new {
 
     if ( $args{anonymous} ) {
         return undef unless $args{anonymous} == 1;
+    }
+
+    if ( $args{random} ) {
+        return undef unless $args{random} == 1;
+    }
+
+    if ( $args{anonymous_target} ) {
+        return undef unless $args{anonymous_target} == 1;
     }
 
     # looks good
@@ -152,8 +160,13 @@ sub _apply_userid {
             } );
         }
     } else {
-        my $emailtype = $fu && $u->equals( $fu ) ? 'self' : 'other';
-        $emailtype = 'anon' if $self->anonymous;
+        my $emailtype;
+        if ( $self->random ) {
+            $emailtype = $self->anonymous ? 'random_anon' : 'random';
+        } else {
+            $emailtype = $fu && $u->equals( $fu ) ? 'self' : 'other';
+            $emailtype = 'anon' if $self->anonymous;
+        }
 
         $subj = LJ::Lang::ml( "shop.email.user.$emailtype.subject", { sitename => $LJ::SITENAME } );
         $body = LJ::Lang::ml( "shop.email.user.$emailtype.body",
@@ -325,9 +338,19 @@ sub conflicts {
 
 # render our target as a string
 sub t_html {
-    my $self = $_[0];
+    my ( $self, %opts ) = @_;
 
-    if ( my $uid = $self->t_userid ) {
+    if ( $self->anonymous_target ) {
+        my $random_user_string = LJ::Lang::ml( 'shop.item.account.randomuser' );
+        if ( $opts{admin} ) {
+            my $u = LJ::load_userid( $self->t_userid );
+            return "<strong>invalid userid " . $self->t_userid . "</strong>"
+                unless $u;
+            return "$random_user_string (" . $u->ljuser_display . ")";
+        } else {
+            return "<strong>$random_user_string</strong>";
+        }
+    } elsif ( my $uid = $self->t_userid ) {
         my $u = LJ::load_userid( $uid );
         return $u->ljuser_display
             if $u;
@@ -414,6 +437,8 @@ sub from_userid  { return $_[0]->{from_u
 sub from_userid  { return $_[0]->{from_userid};     }
 sub deliverydate { return $_[0]->{deliverydate};    }
 sub anonymous    { return $_[0]->{anonymous};       }
+sub random       { return $_[0]->{random};          }
+sub anonymous_target { return $_[0]->{anonymous_target}; }
 
 
 1;
diff -r 255031e8e79e -r d23c0007a311 cgi-bin/DW/Widget/ShopItemGroupDisplay.pm
--- a/cgi-bin/DW/Widget/ShopItemGroupDisplay.pm	Fri Aug 07 15:42:52 2009 +0000
+++ b/cgi-bin/DW/Widget/ShopItemGroupDisplay.pm	Sat Aug 08 12:18:52 2009 +0000
@@ -38,6 +38,8 @@ sub render_body {
             $ret .= "<li>" . $class->ml( 'widget.shopitemgroupdisplay.paidaccounts.item.exisitingaccount', { aopts => "href='$LJ::SITEROOT/shop/account?for=gift'" } ) . "</li>";
         }
         $ret .= "<li>" . $class->ml( 'widget.shopitemgroupdisplay.paidaccounts.item.newaccount', { aopts => "href='$LJ::SITEROOT/shop/account?for=new'" } ) . "</li>";
+        $ret .= "<li>" . $class->ml( 'widget.shopitemgroupdisplay.paidaccounts.item.randomaccount.show', { aopts => "href='$LJ::SITEROOT/shop/randomgift'" } ) . "</li>";
+        $ret .= "<li>" . $class->ml( 'widget.shopitemgroupdisplay.paidaccounts.item.randomaccount.noshow', { aopts => "href='$LJ::SITEROOT/shop/account?for=random'" } ) . "</li>";
         $ret .= "</ul>";
     }
 
diff -r 255031e8e79e -r d23c0007a311 cgi-bin/LJ/User.pm
--- a/cgi-bin/LJ/User.pm	Fri Aug 07 15:42:52 2009 +0000
+++ b/cgi-bin/LJ/User.pm	Sat Aug 08 12:18:52 2009 +0000
@@ -658,6 +658,13 @@ sub is_paid {
 }
 
 
+sub is_perm {
+    my $u = shift;
+    return 0 if $u->is_identity || $u->is_syndicated;
+    return DW::Pay::get_account_type( $u ) eq 'seed' ? 1 : 0;
+}
+
+
 sub is_person {
     my $u = shift;
     return $u->{journaltype} eq "P";
@@ -1987,6 +1994,12 @@ sub opt_nctalklinks {
     }
 
     return $u->prop( 'opt_nctalklinks' ) eq "1" ? 1 : 0;
+}
+
+sub opt_randompaidgifts {
+    my $u = shift;
+
+    return $u->prop( 'opt_randompaidgifts' ) eq 'N' ? 0 : 1;
 }
 
 sub opt_showcontact {
diff -r 255031e8e79e -r d23c0007a311 cgi-bin/LJ/Widget/ShopCart.pm
--- a/cgi-bin/LJ/Widget/ShopCart.pm	Fri Aug 07 15:42:52 2009 +0000
+++ b/cgi-bin/LJ/Widget/ShopCart.pm	Sat Aug 08 12:18:52 2009 +0000
@@ -52,6 +52,7 @@ sub render_body {
     $ret .= "<th>" . $class->ml( 'widget.shopcart.header.deliverydate' ) . "</th>";
     $ret .= "<th>" . $class->ml( 'widget.shopcart.header.to' ) . "</th>";
     $ret .= "<th>" . $class->ml( 'widget.shopcart.header.from' ) . "</th>";
+    $ret .= "<th>" . $class->ml( 'widget.shopcart.header.random' ) . "</th>" if $opts{admin};
     $ret .= "<th>" . $class->ml( 'widget.shopcart.header.price' ) . "</th>";
     $ret .= "<th>ADMIN</th>" if $opts{admin};
     $ret .= "</tr>";
@@ -63,8 +64,9 @@ sub render_body {
             unless $opts{receipt};
         $ret .= "<td>" . $item->name_html . "</td>";
         $ret .= "<td>" . ( $item->deliverydate ? $item->deliverydate : $class->ml( 'widget.shopcart.deliverydate.today' ) ) . "</td>";
-        $ret .= "<td>" . $item->t_html . "</td>";
+        $ret .= "<td>" . $item->t_html( admin => $opts{admin} ) . "</td>";
         $ret .= "<td>" . ( $item->anonymous || !LJ::isu( $from_u ) ? $class->ml( 'widget.shopcart.anonymous' ) : $from_u->ljuser_display ) . "</td>";
+        $ret .= "<td>" . ( $item->random ? 'Y' : 'N' ) . "</td>" if $opts{admin};
         $ret .= "<td>\$" . $item->cost . " USD</td>";
         if ( $opts{admin} ) {
             $ret .= "<td>";
diff -r 255031e8e79e -r d23c0007a311 cgi-bin/LJ/Widget/ShopItemOptions.pm
--- a/cgi-bin/LJ/Widget/ShopItemOptions.pm	Fri Aug 07 15:42:52 2009 +0000
+++ b/cgi-bin/LJ/Widget/ShopItemOptions.pm	Sat Aug 08 12:18:52 2009 +0000
@@ -104,6 +104,25 @@ sub handle_post {
 
         $item_data{target_userid} = $target_u->id;
 
+    } elsif ( $post->{for} eq 'random' ) {
+        my $target_u;
+        if ( $post->{username} eq '(random)' ) {
+            $target_u = DW::Pay::get_random_active_free_user();
+            return ( error => $class->ml( 'widget.shopitemoptions.error.nousers' ) )
+                unless LJ::isu( $target_u );
+            $item_data{anonymous_target} = 1;
+        } else {
+            $target_u = LJ::load_user( $post->{username} );
+            return ( error => $class->ml( 'widget.shopitemoptions.error.invalidusername' ) )
+                unless LJ::isu( $target_u );
+        }
+
+        return ( error => $class->ml( 'widget.shopitemoptions.error.banned' ) )
+            if $remote && $target_u->has_banned( $remote );
+
+        $item_data{target_userid} = $target_u->id;
+        $item_data{random} = 1;
+
     } elsif ( $post->{for} eq 'new' ) {
         my @email_errors;
         LJ::check_email( $post->{email}, \@email_errors );
diff -r 255031e8e79e -r d23c0007a311 htdocs/manage/settings/index.bml
--- a/htdocs/manage/settings/index.bml	Fri Aug 07 15:42:52 2009 +0000
+++ b/htdocs/manage/settings/index.bml	Sat Aug 08 12:18:52 2009 +0000
@@ -113,6 +113,7 @@ body<=
                 LJ::Setting::CommentIP
                 LJ::Setting::Display::BanUsers
                 DW::Setting::ProfileEmail
+                DW::Setting::RandomPaidGifts
             )],
         },
         history => {
diff -r 255031e8e79e -r d23c0007a311 htdocs/shop/account.bml
--- a/htdocs/shop/account.bml	Fri Aug 07 15:42:52 2009 +0000
+++ b/htdocs/shop/account.bml	Sat Aug 08 12:18:52 2009 +0000
@@ -1,9 +1,9 @@
 <?_c
 #
-# shop.bml
+# /shop/account.bml
 #
-# This is the main storefront for the shop.  Gives people a page they can browse
-# around looking for something interesting to buy.
+# This is the page where a person can choose to buy a paid account for
+# themself, another user, or a new user.
 #
 # Authors:
 #      Mark Smith <mark@dreamwidth.org>
@@ -32,7 +32,7 @@ body<=
     # let's see what they're trying to do
     my $for = $GET{for};
     return BML::redirect( "$LJ::SITEROOT/shop" )
-        unless $for && $for =~ /^(?:self|gift|new)$/;
+        unless $for && $for =~ /^(?:self|gift|new|random)$/;
 
     $title = $ML{'.title'};
 
@@ -57,6 +57,8 @@ body<=
         $ret .= DW::Widget::PaidAccountStatus->render;
     } elsif ( $for eq 'gift' ) {
         $ret .= "<p>" . BML::ml( '.intro.gift', { aopts => "href='$LJ::HELPURL{paidaccountinfo}'" } ) . "</p>";
+    } elsif ( $for eq 'random' ) {
+        $ret .= "<p>" . BML::ml( '.intro.random', { aopts => "href='$LJ::HELPURL{paidaccountinfo}'" } ) . "</p>";
     } else { # $for eq 'new'
         $ret .= "<p>" . BML::ml( '.intro.new', { aopts => "href='$LJ::HELPURL{paidaccountinfo}'" } ) . "</p>";
     }
@@ -100,11 +102,24 @@ body<=
 
     $ret .= "</table>";
 
-    if ( $for =~ /^(?:gift|new)$/ ) {
+    if ( $for =~ /^(?:gift|new|random)$/ ) {
         $ret .= "<table class='shop-table-gift'>";
 
         if ( $for eq 'gift' ) {
             $ret .= "<tr><td>$ML{'.giftfor.username'}</td><td>" . LJ::html_text( { name => 'username', value => LJ::ehtml( $GET{user} ) } ) . "</td></tr>";
+        } elsif ( $for eq 'random' ) {
+            if ( my $username = LJ::ehtml( $GET{user} ) ) {
+                my $randomu = LJ::load_user( $username );
+                if ( LJ::isu( $randomu ) ) {
+                    $ret .= "<tr><td>$ML{'.giftfor.username'}</td><td><strong>" . $randomu->ljuser_display . "</strong></td></tr>";
+                    $ret .= LJ::html_hidden( username => $randomu->user );
+                } else {
+                    return BML::redirect( "$LJ::SITEROOT/shop" );
+                }
+            } else {
+                $ret .= "<tr><td>$ML{'.giftfor.username'}</td><td><strong>$ML{'.giftfor.username.random'}</strong></td></tr>";
+                $ret .= LJ::html_hidden( username => '(random)' );
+            }
         } else { # $for eq 'new'
             $ret .= "<tr><td>$ML{'.giftfor.email'}</td><td>" . LJ::html_text( { name => 'email' } ) . "</td></tr>";
         }
diff -r 255031e8e79e -r d23c0007a311 htdocs/shop/account.bml.text
--- a/htdocs/shop/account.bml.text	Fri Aug 07 15:42:52 2009 +0000
+++ b/htdocs/shop/account.bml.text	Sat Aug 08 12:18:52 2009 +0000
@@ -20,10 +20,14 @@
 
 .giftfor.username=Username to receive this account:
 
+.giftfor.username.random=Random active free user
+
 .intro.gift=Please choose the type of paid account that you'd like to purchase for an existing account.
 
 .intro.new=Please choose the type of paid account that you'd like to purchase for a new account.
 
+.intro.random=Please choose the type of paid account that you'd like to purchase for a random active free account.
+
 .intro.self=Please choose the type of paid account that you'd like to purchase for your account [[user]].
 
 .title=Buy a Paid Account
--------------------------------------------------------------------------------
cesy: "Cesy" - An old-fashioned quill and ink (Default)

[personal profile] cesy 2009-08-08 05:52 pm (UTC)(link)
Yay!
yvi: Kaylee half-smiling, looking very pretty (Default)

[personal profile] yvi 2009-08-08 11:28 pm (UTC)(link)
\o/