[dw-free] shop points transfer page
[commit: http://hg.dwscoalition.org/dw-free/rev/7e8ff7c26de6]
http://bugs.dwscoalition.org/show_bug.cgi?id=2573
Implement /shop/transferpoints page. Allows transferring points to another
user.
Patch by
mark.
Files modified:
http://bugs.dwscoalition.org/show_bug.cgi?id=2573
Implement /shop/transferpoints page. Allows transferring points to another
user.
Patch by
Files modified:
- bin/upgrading/en.dat
- cgi-bin/DW/Controller/Shop.pm
- cgi-bin/DW/Logic/MenuNav.pm
- cgi-bin/DW/Template/Plugin.pm
- views/shop/transferpoints.tt
- views/shop/transferpoints.tt.text
--------------------------------------------------------------------------------
diff -r cf64a41b1154 -r 7e8ff7c26de6 bin/upgrading/en.dat
--- a/bin/upgrading/en.dat Fri Apr 30 06:36:45 2010 +0000
+++ b/bin/upgrading/en.dat Fri Apr 30 09:21:49 2010 +0000
@@ -1670,6 +1670,34 @@ esn.read_recent_entries=[[openlink]]Read
esn.read_recent_entries=[[openlink]]Read the recent entries in [[journal]][[closelink]]
esn.read_user_entries=[[openlink]]Read [[poster]]'s recent entries[[closelink]]
+
+esn.receivedpoints.anon.body<<
+Hi [[user]],
+
+You have been given [[points]] [[?points|point|points]] by an anonymous donor! Points can be used
+in the site store. You can visit the store with this link:
+
+ [[store]]
+
+
+Regards,
+ The [[sitename]] Team
+.
+
+esn.receivedpoints.subject=You have received [[sitename]] Points!
+
+esn.receivedpoints.user.body<<
+Hi [[user]],
+
+You have been given [[points]] [[?points|point|points]] by [[from]]! Points can be used
+in the site store. You can visit the store with this link:
+
+ [[store]]
+
+
+Regards,
+ The [[sitename]] Team
+.
esn.remove_trust=[[openlink]]Remove access from [[postername]][[closelink]]
@@ -1869,6 +1897,8 @@ event.poll_vote.id=Someone votes in poll
event.poll_vote.me=Someone votes in a poll I posted
+event.receivedpoints.me=Someone sends me [[sitename]] Points
+
event.removedfromcircle.me=Someone removes me from their circle
event.removedfromcircle.user=Someone removes [[user]] from their circle
@@ -2166,6 +2196,8 @@ menunav.shop.history=Payment History
menunav.shop.history=Payment History
menunav.shop.sponsor=Sponsor a User
+
+menunav.shop.transferpoints=Transfer Shop Points
notification_method.email.title=Email
diff -r cf64a41b1154 -r 7e8ff7c26de6 cgi-bin/DW/Controller/Shop.pm
--- a/cgi-bin/DW/Controller/Shop.pm Fri Apr 30 06:36:45 2010 +0000
+++ b/cgi-bin/DW/Controller/Shop.pm Fri Apr 30 09:21:49 2010 +0000
@@ -16,6 +16,8 @@
package DW::Controller::Shop;
+# FIXME: lots of english stripping needs to be done
+
use strict;
use warnings;
use DW::Controller;
@@ -27,6 +29,7 @@ use JSON;
# routing directions
DW::Routing->register_string( '/shop', \&shop_index_handler, app => 1 );
DW::Routing->register_string( '/shop/points', \&shop_points_handler, app => 1 );
+DW::Routing->register_string( '/shop/transferpoints', \&shop_transfer_points_handler, app => 1 );
# our basic shop controller, this does setup that is unique to all shop
# pages and everybody should call this first. returns the same tuple as
@@ -72,6 +75,92 @@ sub shop_index_handler {
return $rv unless $ok;
return DW::Template->render_template( 'shop/index.tt', $rv );
+}
+
+# if someone wants to transfer points...
+sub shop_transfer_points_handler {
+ my ( $ok, $rv ) = _shop_controller();
+ return $rv unless $ok;
+
+ my %errs;
+ $rv->{errs} = \%errs;
+ $rv->{has_points} = $rv->{remote}->shop_points;
+
+ my $r = DW::Request->get;
+ if ( LJ::did_post() ) {
+ my $args = $r->post_args;
+ die "invalid auth\n" unless LJ::check_form_auth( $args->{lj_form_auth} );
+
+ # error check the user
+ my $u = LJ::load_user( $args->{foruser} )
+ or $errs{foruser} = 'Invalid account.';
+ if ( $u ) {
+ if ( $u->is_visible && $u->is_person ) {
+ $rv->{foru} = $u;
+ } else {
+ $errs{foruser} = 'Account must be active and a personal account.';
+ }
+ }
+
+ # error check the points
+ my $points = $args->{points} + 0;
+ $errs{points} = 'Points must be in range 1 to 5,000.'
+ unless $points >= 1 && $points <= 5000;
+ $rv->{points} = $points;
+
+ # remove must have enough points
+ $errs{points} = 'You do not have enough points to do that.'
+ unless $rv->{remote}->shop_points >= $points;
+
+ # copy down anon value
+ $rv->{anon} = $args->{anon} ? 1 : 0;
+
+ # if this is a confirmation page, then confirm if there are no errors
+ if ( $args->{confirm} && ! scalar keys %errs ) {
+ # first add the points to the other person... wish we had transactions here!
+ $u->give_shop_points( amount => $points, reason => sprintf( 'transfer from %s(%d)', $rv->{remote}->user, $rv->{remote}->id ) );
+ $rv->{remote}->give_shop_points( amount => -$points, reason => sprintf( 'transfer to %s(%d)', $u->user, $u->id ) );
+
+ # send notification ...
+ my $e = $rv->{anon} ? 'anon' : 'user';
+ my $body = LJ::Lang::get_text( $u->prop( 'browselang' ), "esn.receivedpoints.$e.body", undef, {
+ user => $u->display_username,
+ points => $points,
+ from => $rv->{remote}->display_username,
+ sitename => $LJ::SITENAMESHORT,
+ store => "$LJ::SITEROOT/shop/",
+ } );
+
+ # FIXME: esnify the notification
+ LJ::send_mail( {
+ to => $u->email_raw,
+ from => $LJ::ACCOUNTS_EMAIL,
+ fromname => $LJ::SITENAME,
+ subject => LJ::Lang::get_text( $u->prop( 'browselang' ), 'esn.receivedpoints.subject', undef, { sitename => $LJ::SITENAMESHORT } ),
+ body => $body,
+ } );
+
+ # happy times ...
+ $rv->{transferred} = 1;
+
+ # else, if still no errors, send to the confirm pagea
+ } elsif ( ! scalar keys %errs ) {
+ $rv->{confirm} = 1;
+ }
+
+ } else {
+ if ( my $for = $r->get_args->{for} ) {
+ my $fu = LJ::load_user( $for );
+ $rv->{foru} = $fu if $fu;
+ }
+
+ if ( my $points = $r->get_args->{points} ) {
+ $rv->{points} = $points+0
+ if $points > 0 && $points <= 5000;
+ }
+ }
+
+ return DW::Template->render_template( 'shop/transferpoints.tt', $rv );
}
# handles the shop buy points page
diff -r cf64a41b1154 -r 7e8ff7c26de6 cgi-bin/DW/Logic/MenuNav.pm
--- a/cgi-bin/DW/Logic/MenuNav.pm Fri Apr 30 06:36:45 2010 +0000
+++ b/cgi-bin/DW/Logic/MenuNav.pm Fri Apr 30 09:21:49 2010 +0000
@@ -57,6 +57,7 @@ sub get_menu_navigation {
my $loggedin_hasnetwork = ( $loggedin && $u->can_use_network_page ) ? 1 : 0;
my $loggedin_ispaid = ( $loggedin && $u->is_paid ) ? 1 : 0;
my $loggedin_popsubscriptions = ( $loggedin && $u->can_use_popsubscriptions );
+ my $loggedin_person = ( $loggedin && $u->is_person ) ? 1 : 0;
my $loggedout = $loggedin ? 0 : 1;
my $always = 1;
my $never = 0;
@@ -241,12 +242,12 @@ sub get_menu_navigation {
text => "menunav.shop.paidtime",
display => LJ::is_enabled( 'payments' ) ? 1 : 0,
},
- {
+ {
url => "$LJ::SITEROOT/shop/history",
text => "menunav.shop.history",
display => LJ::is_enabled( 'payments' ) && $loggedin ? 1 : 0,
- },
- {
+ },
+ {
url => "$LJ::SITEROOT/shop/gifts",
text => "menunav.shop.gifts",
display => LJ::is_enabled( 'payments' ) && $loggedin ? 1 : 0,
@@ -255,6 +256,11 @@ sub get_menu_navigation {
url => "$LJ::SITEROOT/shop/randomgift",
text => "menunav.shop.sponsor",
display => LJ::is_enabled( 'payments' ) ? 1 : 0,
+ },
+ {
+ url => "$LJ::SITEROOT/shop/transferpoints",
+ text => "menunav.shop.transferpoints",
+ display => LJ::is_enabled( 'payments' ) && $loggedin_person ? 1 : 0,
},
],
},
diff -r cf64a41b1154 -r 7e8ff7c26de6 cgi-bin/DW/Template/Plugin.pm
--- a/cgi-bin/DW/Template/Plugin.pm Fri Apr 30 06:36:45 2010 +0000
+++ b/cgi-bin/DW/Template/Plugin.pm Fri Apr 30 09:21:49 2010 +0000
@@ -49,7 +49,7 @@ sub new {
Render a template to a string.
- [% dw.need_res( 'stc/some.css' ); %]
+ [% dw.need_res( 'stc/some.css' ) %]
=cut
@@ -63,7 +63,7 @@ Get or set the ML scope of the template
Get or set the ML scope of the template
# store the old value
- [% old_scope = dw.ml_scope( ) %]
+ [% old_scope = dw.ml_scope() %]
# CALL forces us to ignore the returned value, and not print it out
[% CALL dw.ml_scope( '/foo.tt' ) %]
@@ -76,11 +76,30 @@ sub ml_scope {
return $#_ == 1 ? $r->note( 'ml_scope', $_[1] ) : $r->note( 'ml_scope' );
}
+=head2 form_auth
+
+Return a HTML form element (input type=hidden) that contains the proper code for
+authenticating this form on POST. This is required to be on all forms to help
+prevent XSS and other exploits.
+
+ <form ...>
+ # within the form somewhere...
+ [% dw.form_auth() %]
+ </form>
+
+=cut
+
+sub form_auth {
+ return LJ::form_auth();
+}
+
=head1 AUTHOR
=over
=item Andrea Nall <anall@andreanall.com>
+
+=item Mark Smith <mark@dreamwidth.org>
=back
diff -r cf64a41b1154 -r 7e8ff7c26de6 views/shop/transferpoints.tt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/views/shop/transferpoints.tt Fri Apr 30 09:21:49 2010 +0000
@@ -0,0 +1,55 @@
+[%- sections.title = '.title' | ml(sitename = site.nameshort) -%]
+
+[% IF transferred %]
+
+ <p>[% '.transferred' | ml(points = points, user = foru.ljuser_display) %]
+ [% IF anon; '.transferred.anon' | ml; ELSE; '.transferred.notify' | ml; END %]</p>
+
+[% ELSIF confirm %]
+
+ <p>[% IF anon; '.confirm.anon' | ml(points = points, user = foru.ljuser_display);
+ ELSE; '.confirm' | ml(points = points, user = foru.ljuser_display); END %]</p>
+
+ <form method='post'>
+ [% dw.form_auth %]
+ <input type='hidden' name='foruser' value='[% foru.user %]' />
+ <input type='hidden' name='points' value='[% points %]' />
+ <input type='hidden' name='anon' value='[% anon %]' />
+ <input type='hidden' name='confirm' value='1' />
+ <input type='submit' value='[% '.btn.confirm' | ml %]' />
+ </form>
+
+[% ELSE %]
+
+ <p>[% '.about' | ml(sitename = site.nameshort) %]</p>
+
+ [% IF ! has_points %]
+ [% '.about.nopoints' | ml(sitename = site.nameshort, aopts = "href='$roots.site/shop/points'") %]
+ [% ELSE %]
+
+ <p>[% '.about.points' | ml(points = has_points) %]</p>
+
+ <form method='post'>
+ [% dw.form_auth %]
+ <table class='shop-table-gift'>
+ [% IF foru %]
+ <tr><td>[% '.buying.for' | ml %]</td><td>[% foru.ljuser_display %]
+ <input type='hidden' name='foruser' value='[% foru.user %]' />
+ </td></tr>
+ [% ELSE %]
+ <tr><td>[% '.buying.for' | ml %]</td><td><input type='text' name='foruser' maxlength='25' size='15' />
+ [% IF errs.foruser %]<br /><strong>[% errs.foruser %][% END %]
+ </td></tr>
+ [% END %]
+ <tr><td>[% '.buying.points' | ml %]</td><td><input type='text' name='points' id='points' maxlength='4' size='10' value='[% points %]' />
+ [% '.buying.points.range' | ml %]
+ [% IF errs.points %]<br /><strong>[% errs.points %][% END %]
+ </td></tr>
+ <tr><td></td><td><input type='checkbox' name='anon' id='anon'> <label for='anon'>[% '.anon' | ml %]</label></td></tr>
+ <tr><td></td><td><input type='submit' value='[% '.btn.transfer' | ml %]' /></td></tr>
+ </table>
+ </form>
+
+ [% END %]
+
+[% END %]
diff -r cf64a41b1154 -r 7e8ff7c26de6 views/shop/transferpoints.tt.text
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/views/shop/transferpoints.tt.text Fri Apr 30 09:21:49 2010 +0000
@@ -0,0 +1,29 @@
+.about=This page allows you to transfer [[sitename]] Points to another user.
+
+.about.nopoints=<strong>You have no points to transfer.</strong> You can buy some for yourself or someone else in the <a [[aopts]]>[[sitename]] Store</a>.
+
+.about.points=You have <strong>[[points]] [[?points|point|points]]</strong> on your account. You may transfer some or all of these points by filling out the form below. Once you are done, click the submit button and you will be taken to a confirmation page. After confirming, the points will be transferred.
+
+.anon=Transfer points anonymously
+
+.btn.confirm=Confirm Transfer Request
+
+.btn.transfer=Transfer Points
+
+.buying.for=Transfer To:
+
+.buying.points=Points to Transfer:
+
+.buying.points.range=(1 to 5,000 points)
+
+.confirm=You have requested to transfer [[points]] [[?points|point|points]] to [[user]]. If you are sure you wish to do this, please click the button below.
+
+.confirm.anon=You have requested to anonymously transfer [[points]] [[?points|point|points]] to [[user]]. They will not know the points came from you. If you are sure you wish to do this, please click the button below.
+
+.title=[[sitename]] Points Transfers
+
+.transferred=You have successfully transferred [[points]] [[?points|point|points]] to [[user]].
+
+.transferred.anon=An anonymous notification has been sent to advise of this transfer.
+
+.transferred.notify=A notification has been sent to advise of this transfer.
--------------------------------------------------------------------------------
