Committer: ailyin
LJSUP-12382 (Add to shop/history pagination on every 50 positions)U trunk/bin/upgrading/en_LJ.dat U trunk/cgi-bin/LJ/Pay/Payment.pm U trunk/cgi-bin/LJ/Pay/Wallet/Log.pm U trunk/cgi-bin/LJ/Widget/Shop/History.pm U trunk/templates/Shop/History.tmpl
Modified: trunk/bin/upgrading/en_LJ.dat =================================================================== --- trunk/bin/upgrading/en_LJ.dat 2012-05-30 15:28:36 UTC (rev 12035) +++ trunk/bin/upgrading/en_LJ.dat 2012-05-30 16:45:36 UTC (rev 12036) @@ -8205,6 +8205,12 @@ shop.history.orders.header.status|staleness=1 shop.history.orders.header.status=Status +shop.history.paging.title=Pages: + +shop.history.paging.previous=previous + +shop.history.paging.next=next + shop.history.status.locked=Unpaid shop.history.status.open|staleness=1 Modified: trunk/cgi-bin/LJ/Pay/Payment.pm =================================================================== --- trunk/cgi-bin/LJ/Pay/Payment.pm 2012-05-30 15:28:36 UTC (rev 12035) +++ trunk/cgi-bin/LJ/Pay/Payment.pm 2012-05-30 16:45:36 UTC (rev 12036) @@ -2051,38 +2051,56 @@ return $valid; } +# supported opts (all mandatory): +# * u +# * pagenum +# * pagesize +# returns: { 'carts' => [ ... ], 'pagecount' => 3 } sub get_user_history { - my ($class, $userid) = @_; + my ( $class, %opts ) = @_; - $userid = LJ::want_userid($userid); + my $u = $opts{'u'}; + my $pagenum = $opts{'pagenum'}; + my $pagesize = $opts{'pagesize'}; + my $userid = $u->userid; + + my $conditions = "userid=$userid AND " . + "forwhat IN ('cart', 'recbill', 'appbill')"; + my $dbh = LJ::get_db_writer(); - my $res = $dbh->selectall_arrayref(qq{ - SELECT * FROM payments - WHERE userid=? AND (forwhat="cart" OR forwhat="recbill" OR forwhat="appbill") - ORDER BY payid DESC - }, { 'Slice' => {} }, $userid); + my ($cartcount) = $dbh->selectrow_array( + "SELECT COUNT(*) FROM payments WHERE $conditions" ); - my @ret; - if (@$res > 50) { - # less resource-consuming way: show all carts - foreach my $row (@$res) { - push @ret, $class->new_memonly(%$row); - } - } else { - # we can go ahead and load items, so that we can hide - # empty carts, nifty! - foreach my $row (@$res) { - my $cart = eval { $class->load('payid' => $row->{'payid'}) }; + my $pagecount = int( ( $cartcount + $pagesize - 1 ) / $pagesize ); - next unless $cart; - next unless $cart->get_items; + if ( $pagenum > $pagecount ) { + return { 'carts' => [], 'pagecount' => $pagecount }; + } - push @ret, $cart; + my $sql_offset = ($pagenum - 1) * $pagesize; + + my $rows = $dbh->selectall_arrayref( + "SELECT * FROM payments WHERE $conditions ORDER BY payid DESC " . + "LIMIT $pagesize OFFSET $sql_offset", + { 'Slice' => {} }, + ); + + my @carts; + + foreach my $row (@$rows) { + if ( $pagecount > 1 ) { + # fast way: put all carts there + push @carts, $class->new_memonly(%$row); + } else { + # slow way: put only carts that actually contain items there + my $cart = eval { $class->load( 'payid' => $row->{'payid'} ) }; + next unless $cart && $cart->get_items; + push @carts, $cart; } } - return \@ret; + return { 'carts' => \@carts, 'pagecount' => $pagecount }; } sub allow_repeat { Modified: trunk/cgi-bin/LJ/Pay/Wallet/Log.pm =================================================================== --- trunk/cgi-bin/LJ/Pay/Wallet/Log.pm 2012-05-30 15:28:36 UTC (rev 12035) +++ trunk/cgi-bin/LJ/Pay/Wallet/Log.pm 2012-05-30 16:45:36 UTC (rev 12036) @@ -176,14 +176,14 @@ SET $parts }, undef, @binds); - return bless({ 'logid' => $dbh->{'mysql_insertid'} }); + return bless( { 'logid' => $dbh->{'mysql_insertid'} } , $class ); } sub new_from_row { my ($class, $row) = @_; $row->{'_props_loaded'} = 1; - return bless($row); + return bless( $row, $class ); } sub update { @@ -357,39 +357,77 @@ return (\@parts, \@binds); } +# TODO: this function doesn't do what it usually does when 'use_paging' +# is passed to it; either rename the function or refactor some parts +# out sub query_handler { my ($class, %params) = @_; my ($parts, $binds) = $class->parse_common_params(\%params); my @parts = @$parts; my @binds = @$binds; + my ( $use_paging, $pagenum, $pagesize ); + if ( $use_paging = delete $params{'use_paging'} ) { + $pagenum = delete $params{'pagenum'}; + $pagesize = delete $params{'pagesize'}; + } + Carp::cluck "unknown parameters: " . join(', ', keys %params) if %params; $parts = join(' AND ', @parts); my $dbh = LJ::get_db_writer(); + + my $pagecount; + if ($use_paging) { + my ($entrycount) = $dbh->selectrow_array( + "SELECT COUNT(*) FROM user_wallet_history WHERE $parts", + undef, @binds ); + $pagecount = int( ( $entrycount + $pagesize - 1 ) / $pagesize ); + + if ( $pagenum > $pagecount ) { + return { 'items' => [], 'pagecount' => $pagecount }; + } + } + + my $sql_limit_cond = ''; + if ($use_paging) { + my $offset = ( $pagenum - 1 ) * $pagesize; + $sql_limit_cond = "LIMIT $pagesize OFFSET $offset"; + } + my $sth = $dbh->prepare(qq{ SELECT * FROM user_wallet_history WHERE $parts ORDER BY time_end DESC + $sql_limit_cond }, { 'mysql_use_result' => 1 }); $sth->execute(@binds); - return $sth; + return $sth unless $use_paging; + + my $rows = $sth->fetchall_arrayref( {} ); + my @items = map { $class->new_from_row($_) } @$rows; + + return { 'items' => \@items, 'pagecount' => $pagecount }; } sub query { my ($class, %params) = @_; + if ( $params{'use_paging'} ) { + return $class->query_handler(%params); + } + my $sth = $class->query_handler(%params); my @ret; while (my $row = $sth->fetchrow_hashref) { - push @ret, bless($row); + push @ret, $class->new_from_row($row); } return \@ret; Modified: trunk/cgi-bin/LJ/Widget/Shop/History.pm =================================================================== --- trunk/cgi-bin/LJ/Widget/Shop/History.pm 2012-05-30 15:28:36 UTC (rev 12035) +++ trunk/cgi-bin/LJ/Widget/Shop/History.pm 2012-05-30 16:45:36 UTC (rev 12036) @@ -3,6 +3,8 @@ use base 'LJ::Widget::Shop'; +use constant PAGE_SIZE => 50; + use LJ::TimeUtil; use LJ::Pay::Payment; use LJ::Pay::Wallet; @@ -14,12 +16,81 @@ sub get_template_file { 'History' } sub show_right_sidebar { 0 } +# TODO: refactor this chunk of code somewhere else? ratings +# also use this type of pagination, so it may be pretty useful +sub paging_params { + my ( $self, %args ) = @_; + + my $prefix = $args{'param_prefix'}; + my $pagenum = $args{'pagenum'}; + my $pagecount = $args{'pagecount'}; + my $cb_page_link = $args{'cb_page_link'}; + + return () unless $pagecount > 1; + + my %ret = ( "${prefix}show_paging" => 1 ); + + if ( $pagenum > 1 ) { + $ret{"${prefix}previous_page"} = $cb_page_link->( $pagenum - 1 ); + } + + if ( $pagenum < $pagecount ) { + $ret{"${prefix}next_page"} = $cb_page_link->( $pagenum + 1 ); + } + + my $start_page = $pagenum - 1; + if ( $start_page <= 2 ) { + $start_page = 1; + } else { + $ret{"${prefix}first_page"} = $cb_page_link->(1); + } + + my $end_page = $pagenum + 1; + if ( $end_page >= $pagecount - 1 ) { + $end_page = $pagecount; + } else { + $ret{"${prefix}last_page"} = $cb_page_link->($pagecount); + $ret{"${prefix}last_page_num"} = $pagecount; + } + + if ( $end_page - $start_page <= 1 ) { + if ( $start_page > 1 ) { + $start_page--; + } + + if ( $end_page < $pagecount ) { + $end_page++; + } + } + + my @pages_display; + foreach my $page ( $start_page .. $end_page ) { + push @pages_display, { + 'page_num' => $page, + 'page_link' => $cb_page_link->($page), + 'page_current' => ( $page == $pagenum ), + }; + } + $ret{"${prefix}pages"} = \@pages_display; + + return %ret; +} + sub get_orders_history { my ($self) = @_; my $remote = LJ::get_remote(); - my $carts = LJ::Pay::Payment->get_user_history($remote); + my $pagenum = int( LJ::Request->get_param('page') || 1 ); + my $carts_data = LJ::Pay::Payment->get_user_history( + 'u' => $remote, + 'pagenum' => $pagenum, + 'pagesize' => PAGE_SIZE, + ); + + my $pagecount = $carts_data->{'pagecount'}; + my $carts = $carts_data->{'carts'}; + my @ret; foreach my $cart (@$carts) { my $datesent = $cart->get_datesent; @@ -80,7 +151,20 @@ }; } - return \@ret; + my %paging_params = $self->paging_params( + 'param_prefix' => 'orders_', + 'pagenum' => $pagenum, + 'pagecount' => $pagecount, + 'cb_page_link' => sub { + my ($page) = @_; + return "$LJ::SITEROOT/shop/history.bml?tab=orders&page=$page"; + }, + ); + + return { + 'orders' => \@ret, + %paging_params, + }; } sub get_wallet_history { @@ -88,10 +172,17 @@ my $remote = LJ::get_remote(); - my $log = LJ::Pay::Wallet::Log->query( - 'userid' => $remote->id, + my $pagenum = int( LJ::Request->get_param('page') || 1 ); + my $log_data = LJ::Pay::Wallet::Log->query( + 'userid' => $remote->id, + 'use_paging' => 1, + 'pagenum' => $pagenum, + 'pagesize' => PAGE_SIZE, ); + my $items = $log_data->{'items'}; + my $pagecount = $log_data->{'pagecount'}; + my %result_map = ( STATUS_STARTED() => LJ::Lang::ml('wallet.widget.history.status.in_progress'), @@ -227,7 +318,7 @@ }; - foreach my $logitem (@$log) { + foreach my $logitem (@$items) { my $time = $logitem->time_end; my $des = $describe_logitem->($logitem); @@ -258,7 +349,20 @@ }; } - return \@ret; + my %paging_params = $self->paging_params( + 'param_prefix' => 'wallet_', + 'pagenum' => $pagenum, + 'pagecount' => $pagecount, + 'cb_page_link' => sub { + my ($page) = @_; + return "$LJ::SITEROOT/shop/history.bml?tab=wallet&page=$page"; + }, + ); + + return { + 'wallet' => \@ret, + %paging_params, + }; } sub get_loyalty_userpics_history { @@ -274,7 +378,7 @@ $row->{'num_pics'} = int $row->{'num_pics'}; } - return $rows; + return { 'loyalty' => $rows }; } sub get_page_params { @@ -291,19 +395,26 @@ $current_tab = 'wallet' if $current_tab eq 'tokens'; } - my %tabs; + my %page_params = ( + 'self_url' => "$LJ::SITEROOT/shop/history.bml", + ); foreach my $tab (qw(orders wallet loyalty)) { - $tabs{"tab_${tab}_active"} = ($current_tab eq $tab); + $page_params{"tab_${tab}_active"} = ($current_tab eq $tab); } - return { - 'orders' => $self->get_orders_history, - 'wallet' => $self->get_wallet_history, - 'loyalty' => $self->get_loyalty_userpics_history, - %tabs, - 'self_url' => "$LJ::SITEROOT/shop/history.bml", - }; + if ( $current_tab eq 'orders' ) { + %page_params = ( %page_params, %{ $self->get_orders_history } ); + } elsif ( $current_tab eq 'wallet' ) { + %page_params = ( %page_params, %{ $self->get_wallet_history } ); + } elsif ( $current_tab eq 'loyalty' ) { + %page_params = ( + %page_params, + %{ $self->get_loyalty_userpics_history }, + ); + } + + return \%page_params; } 1; Modified: trunk/templates/Shop/History.tmpl =================================================================== --- trunk/templates/Shop/History.tmpl 2012-05-30 15:28:36 UTC (rev 12035) +++ trunk/templates/Shop/History.tmpl 2012-05-30 16:45:36 UTC (rev 12036) @@ -40,6 +40,38 @@ </tr> </TMPL_LOOP> </table> + + <TMPL_IF orders_show_paging> + <p class="history-paging"> + <strong><TMPL_VAR expr="ml('shop.history.paging.title')"></strong> + + <TMPL_IF orders_previous_page> + <a href="<TMPL_VAR orders_previous_page ESCAPE=HTML>"><TMPL_VAR expr="ml('shop.history.paging.previous')"></a> + </TMPL_IF> + + <TMPL_IF orders_first_page> + <a href="<TMPL_VAR orders_first_page ESCAPE=HTML>">1</a> + … + </TMPL_IF> + + <TMPL_LOOP orders_pages> + <TMPL_IF page_current> + <strong><TMPL_VAR page_num></strong> + <TMPL_ELSE> + <a href="<TMPL_VAR page_link ESCAPE=HTML>"><TMPL_VAR page_num></a> + </TMPL_IF> + </TMPL_LOOP> + + <TMPL_IF orders_last_page> + … + <a href="<TMPL_VAR orders_last_page ESCAPE=HTML>"><TMPL_VAR orders_last_page_num></a> + </TMPL_IF> + + <TMPL_IF orders_next_page> + <a href="<TMPL_VAR orders_next_page ESCAPE=HTML>"><TMPL_VAR expr="ml('shop.history.paging.next')"></a> + </TMPL_IF> + </p> + </TMPL_IF> </div> <TMPL_IF name="tab_wallet_active"> <div id="tab_wallet" class="b-payment-history-wallet"> @@ -64,6 +96,37 @@ </tr> </TMPL_LOOP> </table> + <TMPL_IF wallet_show_paging> + <p class="history-paging"> + <strong><TMPL_VAR expr="ml('shop.history.paging.title')"></strong> + + <TMPL_IF wallet_previous_page> + <a href="<TMPL_VAR wallet_previous_page ESCAPE=HTML>"><TMPL_VAR expr="ml('shop.history.paging.previous')"></a> + </TMPL_IF> + + <TMPL_IF wallet_first_page> + <a href="<TMPL_VAR wallet_first_page ESCAPE=HTML>">1</a> + … + </TMPL_IF> + + <TMPL_LOOP wallet_pages> + <TMPL_IF page_current> + <strong><TMPL_VAR page_num></strong> + <TMPL_ELSE> + <a href="<TMPL_VAR page_link ESCAPE=HTML>"><TMPL_VAR page_num></a> + </TMPL_IF> + </TMPL_LOOP> + + <TMPL_IF wallet_last_page> + … + <a href="<TMPL_VAR wallet_last_page ESCAPE=HTML>"><TMPL_VAR wallet_last_page_num></a> + </TMPL_IF> + + <TMPL_IF wallet_next_page> + <a href="<TMPL_VAR wallet_next_page ESCAPE=HTML>"><TMPL_VAR expr="ml('shop.history.paging.next')"></a> + </TMPL_IF> + </p> + </TMPL_IF> </div> <TMPL_IF name="tab_loyalty_active"> <div id="tab_loyalty" class="b-payment-history-loyalty">