htdocs/support/see_request.bml
author fu
Fri Jan 27 13:51:52 2012 +0800
changeset 4239 555a213bdacc
parent 4053 4dc5918d25be
permissions -rw-r--r--
http://bugs.dwscoalition.org/show_bug.cgi?id=4230

Fix all the bad my $var = ... if ... constructions.

Patch by sophie.
     1 <?_c
     2 # This code was forked from the LiveJournal project owned and operated
     3 # by Live Journal, Inc. The code has been modified and expanded by
     4 # Dreamwidth Studios, LLC. These files were originally licensed under
     5 # the terms of the license supplied by Live Journal, Inc, which can
     6 # currently be found at:
     7 #
     8 # http://code.livejournal.org/trac/livejournal/browser/trunk/LICENSE-LiveJournal.txt
     9 #
    10 # In accordance with the original license, this code and all its
    11 # modifications are provided under the GNU General Public License.
    12 # A copy of that license can be found in the LICENSE file included as
    13 # part of this distribution.
    14 _c?>
    15 <?page
    16 title=><?_code return BML::ml('.title', { 'reqid' => $FORM{'id'}+0 }); _code?>
    17 head<=
    18 <?_code return LJ::robot_meta_tags(); _code?>
    19 <script language="JavaScript"><!--
    20     var tier_cell = document.getElementById('tier_cell');
    21     var approveans = document.getElementById('approveans');
    22 
    23     if (tier_cell && !approveans) {
    24         tier_cell.style.display = 'none';
    25     }
    26 
    27     function check_replytype (e) {
    28         if (! e) var e = window.event;
    29         if (! document.getElementById) return false;
    30 
    31         f = document.supportForm;
    32         if (! f) return false;
    33 
    34         var replytype = f.replytype;
    35         if (! replytype) return false;
    36 
    37         var bounce_email = document.getElementById('bounce_email');
    38         if (! bounce_email) return false;
    39 
    40         if (replytype.value == 'bounce')
    41             bounce_email.style.display = 'inline';
    42         else
    43             bounce_email.style.display = 'none';
    44 
    45         var tier_cell = document.getElementById('tier_cell');
    46         var approveans = document.getElementById('approveans');
    47 
    48         if (tier_cell && !approveans) {
    49             if (replytype.value == 'answer' || replytype.value == 'internal')
    50                 tier_cell.style.display = 'block';
    51             else
    52                 tier_cell.style.display = 'none';
    53         }
    54 
    55         if (e) {
    56             e.cancelBubble = true;
    57             if (e.stopPropagation) e.stopPropagation();
    58         }
    59 
    60         return false;
    61     }
    62 
    63     function updateFaqLink () {
    64         if (! document.getElementById) return false;
    65 
    66         f = document.supportForm;
    67         if (! f) return false;
    68 
    69         var faqDropdown = f.faqid;
    70         if (! faqDropdown) return false;
    71 
    72         var faqUrl = document.getElementById('faqlink');
    73         if (! faqUrl) return false;
    74 
    75         if (faqDropdown.value == 0)
    76             faqUrl.style.display = 'none';
    77         else
    78         {
    79             faqUrl.style.display = 'inline';
    80             faqUrl.href = 'faqbrowse?faqid=' + faqDropdown.value + '&view=full';
    81         }
    82         return false;
    83     }
    84 
    85     function doSummaryChanged () {
    86         if (! document.getElementById) return false;
    87 
    88         var summaryBox = document.getElementById('changesum');
    89         if (! summaryBox) return false;
    90 
    91         summaryBox.checked = true;
    92 
    93         return doSetReplyType('internal');
    94     }
    95 
    96     function doSetReplyType (replytype) {
    97         if (! document.getElementById) return false;
    98 
    99         var replytypeBox = document.getElementById('replytype');
   100         if (! replytypeBox) return false;
   101 
   102         replytypeBox.value = replytype;
   103         return false;
   104     }
   105 
   106     function doChangeCategory () {
   107         return doSetReplyType('internal');
   108     }
   109 
   110     function doChangeLanguage () {
   111         return doSetReplyType('internal');
   112     }
   113 
   114     function doDegreen () {
   115         return doSetReplyType('internal');
   116     }
   117 
   118     function doRegreen () {
   119         return doSetReplyType('internal');
   120     }
   121 
   122     function doApproveAnswer () {
   123         return doSetReplyType('internal');
   124     }
   125 
   126     function doSummaryClick () {
   127         if (! document.getElementById) return false;
   128 
   129         var summaryBox = document.getElementById('changesum');
   130         if (! summaryBox) return false;
   131 
   132         if (summaryBox.checked) {
   133             doSetReplyType('internal');
   134         }
   135 
   136         return false;
   137     }
   138 
   139     function doClearMessage () {
   140         if (! document.getElementById) return false;
   141 
   142         var bodyBox = document.getElementById('body');
   143         if (! bodyBox) return false;
   144 
   145         bodyBox.value = "";
   146 
   147         return false;
   148     }
   149 
   150     function doClearFocus () {
   151         if (! document.getElementById) return false;
   152 
   153         var submitBox = document.getElementById('submitpost');
   154         if (! submitBox) return false;
   155 
   156         submitBox.focus();
   157 
   158         return false;
   159     }
   160 
   161 // -->
   162 </script>
   163 <=head
   164 bodyopts=>onLoad="check_replytype();updateFaqLink();"
   165 body<=
   166 
   167 <?_code
   168 {
   169     use strict;
   170     use vars qw(%FORM);
   171         
   172     LJ::set_dynamic_crumb('Request #' . ($FORM{'id'}+0), 'supporthelp');
   173 
   174     my $spid = $FORM{'id'}+0;
   175     my $sp = LJ::Support::load_request($spid);
   176     my $props = LJ::Support::load_props($spid);
   177     my $cats = LJ::Support::load_cats();
   178     my $remote = LJ::get_remote();
   179     LJ::Support::init_remote($remote);
   180 
   181     if ($FORM{'find'}) {
   182         my $find = $FORM{'find'};
   183         my $op = '<';
   184         my $sort = 'DESC';
   185         if ($find eq 'next' || $find eq 'cnext' || $find eq 'first') {
   186             $op = '>';
   187             $sort = 'ASC';
   188         }
   189         my $spcatand = '';
   190         if ($sp && ($find eq 'cnext' || $find eq 'cprev')) {
   191             my $spcatid = $sp->{_cat}->{'spcatid'} + 0;
   192             $spcatand = "AND spcatid=$spcatid";
   193         } else {
   194             my @filter_cats = LJ::Support::filter_cats($remote, $cats);
   195             return "<?h1 $ML{'.error'} h1?><?p $ML{'.error.text1'} p?>"
   196                 unless @filter_cats;
   197             my $cats_in = join(",", map { $_->{'spcatid'} } @filter_cats);
   198             $spcatand = "AND spcatid IN ($cats_in)";
   199         }
   200         my $clause = "";
   201         $clause = "AND spid$op$spid" unless ($find eq 'first' || $find eq 'last');
   202         my $dbr = LJ::get_db_reader();
   203         my ($foundspid) = $dbr->selectrow_array("SELECT spid FROM support WHERE state='open' $spcatand $clause ".
   204                                                 "ORDER BY spid $sort LIMIT 1");
   205         if ($foundspid) {
   206             return BML::redirect("see_request?id=$foundspid");
   207         } else {
   208             my $goback = $sp ? BML::ml('.goback.text', {request_link=>"href='see_request?id=$spid'", spid=>$spid}) : undef;
   209             my $what = $find eq 'next' || $find eq 'cnext' ? $ML{'.next'} : $ML{'.previous'};
   210             my $cat = $find eq 'cnext' || $find eq 'cprev' ? $ML{'.incat'} : undef;
   211             return "<?h1 $ML{'.error'} h1?>".BML::ml('.error.text2', {what=>$what, cat=>$cat})." $goback";
   212         }
   213     }
   214 
   215     unless ($sp) { return "<?h1 $ML{'.error'} h1?><?p $ML{'.unknownumber'} p?>"; }
   216     my $sth;
   217     my $auth = $FORM{'auth'};
   218 
   219     my $email = $sp->{'reqemail'};
   220 
   221     my $user;
   222     my $user_url;
   223 
   224     # Get remote username and journal URL, or example user's username and journal URL
   225     if ( $remote ) {
   226         $user = $remote->user;
   227         $user_url = $remote->journal_base;
   228     } else {
   229         my $exampleu = LJ::load_user( $LJ::EXAMPLE_USER_ACCOUNT );
   230         $user = $exampleu
   231             ? $exampleu->user
   232             : "<b>[Unknown or undefined example username]</b>";
   233         $user_url = $exampleu
   234             ? $exampleu->journal_base
   235             : "<b>[Unknown or undefined example username]</b>";
   236     }
   237 
   238     my $u;
   239     my $clusterdown = 0;
   240     if ($sp->{'reqtype'} eq "user" && $sp->{'requserid'}) {
   241         $u = LJ::load_userid($sp->{'requserid'});
   242         unless ($u) {
   243             warn "Error: user '$sp->{requserid}' not found in request #$spid";
   244             return "<?h1 $ML{'.error'} h1?><?p Unknown user p?>";
   245         }
   246 
   247         # now do a check for a down cluster?
   248         my $dbr = LJ::get_cluster_reader($u);
   249         $clusterdown = 1 unless $dbr;
   250 
   251         $email = $u->email_raw if $u->email_raw;
   252         $u->preload_props( "stylesys", "s2_style", "browselang", "schemepref" )
   253             unless $clusterdown;
   254     }
   255 
   256     my $winner;  # who closed it?
   257     if ($sp->{'state'} eq "closed") {
   258         my $dbr = LJ::get_db_reader();
   259         $sth = $dbr->prepare("SELECT u.user, sp.points FROM useridmap u, supportpoints sp ".
   260                              "WHERE u.userid=sp.userid AND sp.spid=?");
   261         $sth->execute($spid);
   262         $winner = $sth->fetchrow_hashref;
   263     }
   264 
   265     # get all replies
   266     my @replies;
   267     my $dbr = LJ::get_db_reader();
   268     my $sql_extra = LJ::is_enabled("support_response_tier") ? ", tier" : "";
   269     $sth = $dbr->prepare("SELECT splid, timelogged, UNIX_TIMESTAMP()-timelogged AS 'age', type, faqid, userid, message$sql_extra " .
   270                          "FROM supportlog WHERE spid=? ORDER BY timelogged");
   271     $sth->execute($spid);
   272     while (my $le = $sth->fetchrow_hashref) {
   273         push @replies, $le;
   274     }
   275 
   276     # load category this request is in
   277     my $problemarea = $sp->{_cat}->{'catname'};
   278     my $catkey = $sp->{_cat}->{'catkey'};
   279 
   280     unless (LJ::Support::can_read($sp, $remote, $auth)) {
   281         return "<?h1 $ML{'.error'} h1?><?p $ML{'.nothaveprivilege'} p?>";
   282     }
   283 
   284     # helper variables for commonly called methods
   285     my $can_close = LJ::Support::can_close($sp, $remote, $auth) ? 1 : 0;
   286     my $can_reopen = LJ::Support::can_reopen($sp, $remote, $auth) ? 1 : 0;
   287     my $helper_mode = LJ::Support::can_help($sp, $remote) ? 1 : 0;
   288     my $stock_mode = LJ::Support::can_see_stocks($sp, $remote) ? 1 : 0;
   289     my $is_poster = LJ::Support::is_poster($sp, $remote, $auth) ? 1 : 0;
   290 
   291     # fix up the subject if needed
   292     eval {
   293         if ($sp->{'subject'} =~ /^=\?(utf-8)?/i) {
   294             my @subj_data;
   295             require MIME::Words;
   296             @subj_data = MIME::Words::decode_mimewords($sp->{'subject'});
   297             if (scalar(@subj_data)) {
   298                 if (!$1) {
   299                     $sp->{'subject'} = Unicode::MapUTF8::to_utf8({-string=>$subj_data[0][0], -charset=>$subj_data[0][1]});
   300                 } else {
   301                     $sp->{'subject'} = $subj_data[0][0];
   302                 }
   303             }
   304         }
   305     };
   306 
   307 
   308     ### request info table
   309 
   310     my $ret = "";
   311     $ret .= "<table summary='' class='support-requesttable'>\n";
   312     $ret .= "<tr><td valign='bottom' align='right'><b>$ML{'.from'}</b></td><td>";
   313     
   314     if ( $u->{'defaultpicid'} && !$u->is_suspended ) {
   315         my $userpic_obj = $u->userpic;
   316         $ret .= "<a href='" . $u->allpics_base . "'>";
   317         $ret .= $userpic_obj->imgtag;
   318         $ret .= "</a>";
   319     }
   320     
   321     # show requester name + email
   322     {
   323         my $visemail = $email;
   324         $visemail =~ s/^.+\@/********\@/;
   325 
   326         my $ename = $sp->{'reqtype'} eq 'user' ? LJ::ljuser($u) : LJ::ehtml($sp->{reqname});
   327 
   328         # we show links to the history page if the user is a helper since
   329         # helpers can always find this information anyway just by taking
   330         # more steps.  Show email history link if they have finduser and
   331         # thus once again could get this information anyway.
   332         my $has_sh = $remote && $remote->has_priv( 'supporthelp' );
   333         my $has_fu = $remote && $remote->has_priv( 'finduser' );
   334         my $has_vs = $remote && $remote->has_priv( 'supportviewscreened' );
   335 
   336         my %show_history = (
   337                             user  => $has_sh,
   338                             email => ($has_fu || ($has_sh && !$sp->{_cat}->{public_read})),
   339                             );
   340 
   341         if ($show_history{user} || $show_history{email}) {
   342             $ret .= $sp->{reqtype} eq 'user' && $show_history{user} ?
   343                     "$ename <a href=\"history?user=$u->{user}\">" . LJ::ehtml($u->{name}) . "</a>" :
   344                     "$ename";
   345 
   346             my $email_string = $has_vs || $has_sh ? " ($visemail)" : "";
   347             $email_string = " (<a href=\"history?email=" . LJ::eurl($email) . "\">$email</a>)" if $show_history{email};
   348             $ret .= $email_string;
   349         } else {
   350             # default view
   351             $ret .= $ename;
   352             $ret .= " ($visemail)" if $has_vs || $has_sh;
   353         }
   354     }
   355     $ret .= "</td></tr>\n";
   356 
   357     # uniq
   358     if ( $remote && ( $remote->has_priv( 'sysban', 'uniq' ) || $remote->has_priv( 'canview', 'userlog' ) ) ) {
   359         my $uniq = $props->{'uniq'} || "<i>$ML{'.none'}</i>";
   360         $ret .= "<tr><td valign='bottom' align='right'><b>$ML{'.uniq'}</b></td><td>$uniq</td></tr>\n";
   361     }
   362 
   363     # account type
   364     $ret .= "<tr><td align='right' valign='top'><b><span style='white-space: nowrap'>$ML{'.accounttype'}</span>:</b></td><td>";
   365     $ret .= LJ::Capabilities::name_caps( $u->{caps} ) || "<i>$ML{'.unknown'}</i>";
   366     $ret .= "</td></tr>\n";
   367 
   368     if ($u->{'userid'}) {
   369         $ret .= "<tr valign='top'><td align='right'><b>$LJ::SITENAMESHORT:</b></td><td>";
   370 
   371         if ($u->is_expunged) {
   372             $ret .= $ML{'.status.deleted.and.purged'} . "<br />";
   373         } elsif ($clusterdown) {
   374             $ret .= "<span style='color: red; font-weight: bold;'>" .
   375                $ML{'.unable.connect'} ."</span><br />";
   376         }
   377 
   378         if ($u->readonly) {
   379             $ret .= "<span style='color: red; font-weight: bold;'>" .
   380                $ML{'.userreadonly'} ."</span><br />";
   381         }
   382 
   383         $ret .= "$ML{'.username'}: <?ljuserf $u->{'user'} ljuserf?>";
   384         $ret .= "<br />$ML{'.style'}: ";
   385         if ($u->{'stylesys'} == 2) {
   386             $ret .= "(S2) ";
   387             if ($u->{'s2_style'}) {
   388                 my $s2style = LJ::S2::load_style($u->{'s2_style'});
   389                 my $pub = LJ::S2::get_public_layers(); # cached
   390                 foreach my $lay (sort { $a cmp $b } keys %{$s2style->{'layer'}}) {
   391                     my $lid = $s2style->{'layer'}->{$lay};
   392                     unless ($lid) {
   393                         $ret .= "$lay: none, ";
   394                         next;
   395                     }
   396                     $ret .= "$lay: <a href='$LJ::SITEROOT/customize/advanced/layerbrowse?id=$lid'>";
   397                     $ret .= (defined $pub->{$lid} ? 'public' : 'custom') . "</a>, ";
   398                 }
   399             } else {
   400                 $ret .= $ML{'.none'};
   401             }
   402         } else {
   403             $ret .= "(User on S1; why?) ";
   404         }
   405 
   406         LJ::Hooks::run_hooks("support_see_request_info_rows", {
   407             'u' => $u,
   408             'email' => $email,
   409             'sp' => $sp,
   410             'retref' => \$ret,
   411             'remote' => $remote,
   412         });
   413 
   414         # if the user has siteadmin:users or siteadmin:* show them link to resend validation email?
   415         my $extraval = sub {
   416             return '' unless $remote && $remote->has_priv( 'siteadmin', 'users' );
   417             return " (<a href='$LJ::SITEROOT/register?foruser=$u->{user}'>$ML{'.resend.validation.email'}</a>)";
   418         };
   419 
   420         $ret .= "<br />" . $ML{'.email.validated'} . " ";
   421         if ($u->{'status'} eq "A") { $ret .= "<b>$ML{'.yes'}</b>"; }
   422         if ($u->{'status'} eq "N") { $ret .= "<b>$ML{'.no'}</b>" . $extraval->(); }
   423         if ($u->{'status'} eq "T") { $ret .= $ML{'.transitioning'} . $extraval->(); }
   424         $ret .= "<br />";
   425         $ret .= "$ML{'.cluster'}: <b>" . LJ::DB::get_cluster_description( $u->{clusterid} ) . "</b>; "
   426             if $u->{clusterid};
   427         $ret .= "$ML{'.dataversion'}: <b>$u->{dversion}</b>";
   428         $ret .= "<br />$ML{'.scheme'}: <b>" . ($u->{schemepref} ? $u->{schemepref} : "default") . "</b>; ";
   429         $ret .= "$ML{'.language'}: <b>" . ($u->{browselang} ? $u->{browselang} : "default") . "</b>";
   430 
   431         my $view_history = $remote && $remote->has_priv( 'historyview' );
   432         my $view_userlog = $remote && $remote->has_priv( 'canview', 'userlog' );
   433 
   434         if ($view_history || $view_userlog) {
   435             $ret .= "<br />$ML{'.view'}: ";
   436             $ret .= "<a href='$LJ::SITEROOT/admin/statushistory?user=$u->{user}'>$ML{'.statushistory'}</a> "
   437                 if $view_history;
   438             $ret .= "<a href='$LJ::SITEROOT/admin/userlog?user=$u->{user}'>userlog</a> "
   439                 if $view_userlog;
   440         }
   441 
   442         if ( $u->in_class( LJ::BetaFeatures->cap_name )
   443             && LJ::Support::has_any_support_priv( $remote ) ) {
   444             $ret .= "<br />$ML{'.betatesting'}: ";
   445             $ret .= join ", ", $u->prop( LJ::BetaFeatures->prop_name );
   446         }
   447 
   448         $ret .= "</td></tr>\n";
   449     }
   450 
   451     $ret .= "<tr><td align='right' nowrap='nowrap'><b>$ML{'.supportcategory'}:</b></td><td>";
   452     if (LJ::Support::can_read_cat($sp->{_cat}, $remote)) {
   453         $ret .= "<a href='$LJ::SITEROOT/support/help?cat=$sp->{_cat}->{'catkey'}'>$problemarea</a>";
   454         $ret .= " [<a href='$LJ::SITEROOT/support/see_request?id=$sp->{'spid'}&amp;find=cprev'>$ML{'.previous'}</a>|";
   455         $ret .= "<a href='$LJ::SITEROOT/support/see_request?id=$sp->{'spid'}&amp;find=cnext'>$ML{'.next'}</a>]";
   456     } else {
   457         $ret .= $problemarea;
   458     }
   459     $ret .= "</td></tr>\n";
   460 
   461     # figure out the tier of the most recent answer
   462     my %tier_map = (
   463         0  => "0",
   464         10 => "1",
   465         20 => "2",
   466         30 => "3",
   467     );
   468     my $can_see_tier = $remote && ( $remote->has_priv( "supporthelp" ) || $remote->has_priv( "supportviewscreened" ) );
   469     if (LJ::is_enabled("support_response_tier") && $can_see_tier) {
   470         my $latest_timelogged = 0;
   471         my $latest_timelogged_tier = 0;
   472         foreach my $reply (@replies) {
   473             next unless $reply->{type} eq "answer" || $reply->{type} eq "internal";
   474 
   475             if ($reply->{tier} && $reply->{timelogged} && $reply->{timelogged} > $latest_timelogged) {
   476                 $latest_timelogged = $reply->{timelogged};
   477                 $latest_timelogged_tier = $reply->{tier};
   478             }
   479         }
   480         $ret .= "<tr><td align='right'><b>$ML{'.tier'}</b></td><td>$tier_map{$latest_timelogged_tier}</td></tr>\n";
   481     }
   482 
   483     my $timecreate = LJ::time_to_http( $sp->{timecreate} );
   484     my $age = LJ::diff_ago_text( $sp->{timecreate} );
   485     $ret .= "<tr><td align='right'><b>$ML{'.timeposted'}:</b></td><td>$timecreate ($age)</td></tr>\n";
   486     my $state = $sp->{'state'};
   487     if ($state eq "open") {
   488         # check if it's still open or needing help or what
   489         if ($sp->{'timelasthelp'} > ($sp->{'timetouched'}+5)) {
   490             # open, answered
   491             $state = $ML{'.answered'};
   492         } elsif ($sp->{'timelasthelp'} && $sp->{'timetouched'} > $sp->{'timelasthelp'}+5) {
   493             # open, still needs help
   494             $state = $ML{'.answered.need.help'};
   495         } else {
   496             # default
   497             $state = "<b><span style='color: #ff0000;'>$ML{'.open'}</span></b>";
   498         }
   499     }
   500     if ($state eq "closed" && $winner && LJ::Support::can_see_helper($sp, $remote)) {
   501         my $s = $winner->{'points'} > 1 ? "s" : "";
   502         my $wuser = $winner->{'user'};
   503         $state .= " (<b>$winner->{'points'}</b> point$s to ";
   504         $state .= LJ::ljuser($wuser, { 'full' => 1 }) . ")";
   505     }
   506     $ret .= "<tr><td align='right'><b>$ML{'.status'}:</b></td><td>$state";
   507     if ($can_close || $can_reopen) {
   508         if ($sp->{'state'} eq "open" && $can_close) {
   509             $ret .= ", <a href='act?close;$sp->{'spid'};$sp->{'authcode'}'><b>$ML{'.close.without.credit'}</b></a>";
   510         } elsif ($sp->{state} eq 'closed') {
   511             my $permastatus = LJ::Support::is_locked($sp);
   512             $ret .= $sp->{'state'} eq "closed" && !$permastatus ?
   513                     ", <a href='act?touch;$sp->{'spid'};$sp->{'authcode'}'><b>$ML{'.reopen.this.request'}</b></a>" : "";
   514             if (LJ::Support::can_lock($sp, $remote)) {
   515                 $ret .= $permastatus ?
   516                     ", <a href='act?unlock;$sp->{spid};$sp->{authcode}'><b>$ML{'.unlock.request'}</b></a>" :
   517                     ", <a href='act?lock;$sp->{spid};$sp->{authcode}'><b>$ML{'.lock.request'}</b></a>";
   518             }
   519         }
   520     }
   521     $ret .= "</td></tr>\n";
   522     $ret .= "<tr><td align='right'><b>$ML{'.summary'}:</b></td><td><span style='font-size: 1.1em'><b>" . LJ::ehtml($sp->{'subject'}) . "</b></span></td></tr>\n";
   523     $ret .= "</table>\n";
   524 
   525     ### end request info table
   526 
   527     LJ::Hooks::run_hooks("support_see_request_html", {
   528         'u' => $u,
   529         'email' => $email,
   530         'sp' => $sp,
   531         'retref' => \$ret,
   532         'remote' => $remote,
   533     });
   534 
   535     # put in a "this is private!" box if this is a private request and the user viewing
   536     # this page is the person who opened the request
   537     if (!$sp->{_cat}->{public_read} && $is_poster) {
   538         $ret .= "<div style='margin-top: 15px; margin-bottom: 15px; padding: 5px; " .
   539                 "text-align: center; background-color: #ffff00; border: solid 2px red;'>" .
   540                 $ML{'.private.request'}."</div>";
   541     }
   542 
   543     my @screened;
   544     my $most_recent_tier = 0;
   545     my $curlang = BML::get_language();
   546 
   547     ### reply loop
   548     foreach my $le (@replies)
   549     {
   550         if (LJ::is_enabled("support_response_tier") && $can_see_tier && ($le->{type} eq "answer" || $le->{type} eq "internal") && $le->{tier}) {
   551             $most_recent_tier = $le->{tier};
   552         }
   553 
   554         my $up = LJ::load_userid( $le->{userid} );
   555         my $remote_is_up = $remote && $remote->equals( $up );
   556 
   557         next if $le->{type} eq "internal" && ! ( LJ::Support::can_read_internal( $sp, $remote )
   558                                                  || $remote_is_up );
   559         next if $le->{type} eq "screened" && ! ( LJ::Support::can_read_screened( $sp, $remote )
   560                                                  || $remote_is_up );
   561         next if $le->{type} eq "screened" && $up && !$up->is_visible;
   562 
   563         push @screened, $le if $le->{type} eq "screened";
   564 
   565         my $message = $le->{message};
   566         my %url;
   567         my $urlN = 0;
   568 
   569         $message = LJ::ehtml($message);
   570         $message =~ s/^\s+//;
   571         $message =~ s/\s+$//;
   572         $message =~ s/\n( +)/"\n" . "&nbsp;&nbsp;"x length($1)/eg;
   573         $message =~ s/\n/<br \/>\n/g;
   574         $message = LJ::auto_linkify($message);
   575 
   576         # special case: original request
   577         if ($le->{'type'} eq "req") {
   578             # insert support diagnostics from props
   579             $message .= "<?hr?><strong>$ML{'.diagnostics'}:</strong> " . LJ::ehtml($props->{useragent}) if $props->{useragent};
   580 
   581             $ret .= "<div style='margin-top: 15px;'>\n";
   582             $ret .= "<b>$ML{'.original.request'}:</b><br />\n";
   583             $ret .= "<div class='requestdiv'>\n$message\n</div></div>";
   584             next;
   585         }
   586 
   587         # print anchor for links to jump here
   588         $ret .= "<a name='e$le->{splid}'></a>";
   589 
   590         # reply header
   591         my $header = "";
   592         if ($up && LJ::Support::can_see_helper($sp, $remote)) {
   593             my $picid = $up->get_picid_from_keyword( '_support' ) || $up->{defaultpicid};
   594             my $icon = $picid ? LJ::Userpic->new( $up, $picid ) : undef;
   595             $header = "<table summary='' style='margin-top: 15px;'><tr valign='bottom'>";
   596             if ( $icon && !$up->is_suspended ) {
   597                 my $alt = $up->display_name;
   598                 my $src = $icon->url;
   599                 my ( $width, $height ) = $icon->dimensions;
   600                 $header .= "<td><img src='$src' width='$width' height='$height' hspace='3' alt='$alt'/></td>";
   601             }
   602             $header .= "<td>" . LJ::ljuser( $up, { full => 1 } );
   603             $header .= " - " . $up->name_html unless $up->is_suspended;
   604             $header .= "</td></tr></table>\n"
   605         }
   606 
   607         my $what = $ML{'.answer'};
   608         if ($le->{'type'} eq "internal") { $what = $ML{'.internal.comment'}; }
   609         elsif ($le->{'type'} eq "comment") { $what = $ML{".comment"}; }
   610         elsif ($le->{'type'} eq "screened") { $what = $ML{'.screened.response'}; }
   611 
   612         my $link = "<a href='$LJ::SITEROOT/support/see_request?id=$spid#e$le->{splid}'>#$le->{splid}</a>";
   613         $header .= "<span style='font-size: 0.9em;'><b>$what</b> ($link)</span><br />";
   614         if (LJ::is_enabled("support_response_tier") && $can_see_tier && $le->{type} eq "answer") {
   615             # show the answer's tier level, or if there is no tier level, show the tier level at the time of posting
   616             my $display_tier = $le->{tier} ? $le->{tier} : $most_recent_tier;
   617             $header .= "<b>$ML{'.tier'}</b> $tier_map{$display_tier}<br />";
   618         }
   619         my $timehelped = LJ::time_to_http($le->{'timelogged'});
   620         my $age = LJ::ago_text($le->{'age'});
   621         $header .= "<b>$ML{'.posted'}:</b> $timehelped ($age)";
   622         if ($can_close && $sp->{'state'} eq "open" && $le->{'type'} eq "answer") {
   623             $header .= ", <a href='act?close;$sp->{'spid'};$sp->{'authcode'};$le->{'splid'}'><b>$ML{'.credit.fix'}</b></a>";
   624         }
   625 
   626         my $bordercolor = "default";
   627         if ($le->{'type'} eq "internal") { $bordercolor = "internal"; }
   628         if ($le->{'type'} eq "answer")   { $bordercolor = "answer"; }
   629         if ($le->{'type'} eq "screened") { $bordercolor = "screened"; }
   630 
   631         # reply
   632         $ret .= "$header<br />\n";
   633         $ret .= "<table summary='' class='support-requesttable-$bordercolor'>\n";
   634         $ret .= "<tr><td align='center'>\n";
   635         if ($le->{faqid}) {
   636             # faq question
   637             my $faq = LJ::Faq->load( $le->{faqid}, lang => $curlang );
   638             $faq->render_in_place;
   639             $ret .= "<div style='display: table; padding: 3px; margin-left: auto; margin-right: auto;'>\n";
   640             # whitespace between these two DIVs is necessary for proper
   641             # rendering in IE 5 for Mac OS < X
   642             $ret .= "<div class='highlight-box' style='text-align:center;'>";
   643             $ret .= "<b>$ML{'.faq.reference'}:</b><br /><a href='faqbrowse?faqid=$le->{faqid}&view=full'>" . $faq->question_html . "</a></div></div>\n";
   644         }
   645         $ret .= "<p align='left' style='margin-top: 0px; margin-bottom: 0px;'>$message</p>\n";
   646         $ret .= "</td></tr></table>\n";
   647     }
   648     ### end reply loop
   649 
   650     # return if support item is closed
   651     if ($sp->{'state'} eq "closed") {
   652         return $ret;
   653     }
   654 
   655     if ($is_poster) {
   656         $ret .= "<p style='margin-bottom: 0px;'><b>$ML{'.post.moreinformation'}:</b></p>\n";
   657     } elsif ($remote) {
   658         $ret .= "<p style='margin-bottom: 0px;'><b>$ML{'.post.comment'}:</b></p>\n";
   659     } else {
   660         $ret .= BML::ml('.mast.login', {loginlink=>"href='$LJ::SITEROOT/login?ret=1'"});
   661         $ret .= "\n";
   662         return $ret;
   663     }
   664 
   665     unless (LJ::Support::can_append($sp, $remote, $auth))
   666     {
   667         $ret .= "$ML{'.not.have.access'}\n";
   668         return $ret;
   669     }
   670 
   671     my @ans_type = LJ::Support::get_answer_types($sp, $remote, $auth);
   672     my %ans_type = @ans_type;
   673 
   674     if ($ans_type{'answer'} || $ans_type{'screened'})
   675     {
   676         $ret .= "<div class='highlight-box'>";
   677         $ret .= BML::ml('.important.notes.text2', {
   678                 sitenameshort=>$LJ::SITENAMESHORT,
   679                 supportlink=>"href='$LJ::SITEROOT/doc/guide/support'",
   680             });
   681         $ret .= "</div>\n";
   682     }
   683 
   684     # append_request form
   685 
   686     $ret .= "<br /><form method='post' action='append_request' name='supportForm'>\n";
   687 
   688     # hidden values
   689     $ret .= LJ::html_hidden('spid', $spid, 'auth', $auth) . "\n";
   690 
   691     # form
   692     $ret .= "<table summary='' class='support-requesttable'>\n";
   693     $ret .= "<tr valign='middle'><td align='right'>$ML{'.from'}</td><td>";
   694     
   695     if ($remote && $remote->{'userid'}) {
   696         $ret .= "<?ljuser $remote->{'user'} ljuser?>";
   697     } else {
   698         $ret .= "(not logged in)";
   699     }
   700     $ret .= "</td></tr>\n";
   701 
   702     if ($ans_type{'answer'} || $ans_type{'screened'})
   703     {
   704         my $dbr = LJ::get_db_reader();
   705         # FAQ reference
   706         $ret .= "<tr valign='middle'><td align='right'>$ML{'.reference'} <a href='faq'>$ML{'.faq'}</a>:</td><td colspan='2'>\n";
   707 
   708         my %faqcat;
   709         my %faqq;
   710         # FIXME: must refactor that somewhere
   711         my $deflang = BML::get_language_default();
   712         my $mll = LJ::Lang::get_lang( $curlang );
   713         my $mld = LJ::Lang::get_dom( "faq" );
   714         my $altlang = $deflang ne $curlang;
   715         $altlang = 0 unless $mld and $mll;
   716         if ( $altlang ) {
   717             my $sql = qq{SELECT fc.faqcat, t.text, fc.catorder
   718                          FROM faqcat fc, ml_text t, ml_latest l, ml_items i
   719                          WHERE t.dmid=$mld->{'dmid'} AND l.dmid=$mld->{'dmid'}
   720                              AND i.dmid=$mld->{'dmid'} AND l.lnid=$mll->{'lnid'}
   721                              AND l.itid=i.itid
   722                              AND i.itcode=CONCAT('cat.', fc.faqcat)
   723                              AND l.txtid=t.txtid AND fc.faqcat<>'int-abuse'};
   724             $sth = $dbr->prepare( $sql );
   725         } else {
   726             $sth = $dbr->prepare("SELECT faqcat, faqcatname, catorder FROM faqcat ".
   727                                  "WHERE faqcat<>'int-abuse'");
   728         }
   729         $sth->execute;
   730         while ($_ = $sth->fetchrow_hashref) {
   731             $faqcat{$_->{'faqcat'}} = $_;
   732         }
   733 
   734         foreach my $f ( LJ::Faq->load_all( lang => $curlang ) ) {
   735             $f->render_in_place( { user => $user, url => $user_url } );
   736             push @{ $faqq{$f->faqcat} ||= [] }, $f;
   737         }
   738 
   739         my @faqlist = ('0', "(don't reference FAQ)");
   740         foreach my $faqcat (sort { $faqcat{$a}->{'catorder'} <=> $faqcat{$b}->{'catorder'} } keys %faqcat)
   741         {
   742             push @faqlist, ('0', "[ $faqcat{$faqcat}->{'faqcatname'} ]");
   743             foreach my $faq ( sort { $a->sortorder <=> $b->sortorder }
   744                                    @{ $faqq{$faqcat} || [] } ) {
   745                 my $q = $faq->question_raw;
   746                 next unless $q;
   747                 $q = "... $q";
   748                 $q =~ s/^\s+//;
   749                 $q =~ s/\s+$//;
   750                 $q =~ s/\n/ /g;
   751                 $q = substr( $q, 0, 50 ) . "..." if length( $q ) > 50;
   752                 push @faqlist, ( $faq->faqid, $q );
   753             }
   754         }
   755         $ret .= LJ::html_select({ 'name' => 'faqid', 'onchange' => 'updateFaqLink()' }, @faqlist) . "\n";
   756         $ret .= qq(<script language="JavaScript"><!--
   757             if (document.getElementById)
   758                 document.write("<a href='faq' id='faqlink'>View FAQ</a>");
   759         //--></script>);
   760         $ret .= "</td></tr>\n";
   761     }
   762 
   763     # answer type
   764     {
   765         $ret .= "<tr><td align='right'>$ML{'.reply.type'}</td><td>";
   766 
   767         # if less than 2, remote is the person filing the request
   768         # so all they can do is add more info
   769         if (@ans_type > 2) {
   770             $ret .= LJ::html_select({ 'name' => 'replytype',
   771                                       'id' => 'replytype',
   772                                       'onchange' => "check_replytype()" },
   773                                     @ans_type) . "\n";
   774             $ret .= "<div id='bounce_email' style='display:none'>";
   775             $ret .= "&nbsp;$ML{'.email.user'} " . LJ::html_text({ 'name' => 'bounce_email', 'size' => '25' });
   776             $ret .= "</div>";
   777         } else {
   778             $ret .= LJ::html_hidden('replytype', $ans_type[0]) . "\n";
   779             $ret .= "<b>$ans_type[1]</b>";
   780         }
   781         $ret .= "</td></tr>\n";
   782     }
   783 
   784     # helpers can do actions:
   785     if (LJ::Support::can_perform_actions($sp, $remote) && ! $is_poster)
   786     {
   787         $ret .= "<tr><td align='right'></td><td>\n";
   788 
   789         $ret .= "<table summary='' cellpadding='5'>";
   790 
   791         $ret .= "<tr><td>$ML{'.change.cat'}:<br />";
   792         $ret .= LJ::html_select({ 'name' => 'changecat',
   793                                   'onchange' => 'doChangeCategory();' },
   794                                 ('', $sp->{'_cat'}->{'catname'}),
   795                                 map { $_->{'spcatid'}, "---> $_->{'catname'}" }
   796                                 LJ::Support::sorted_cats($cats));
   797         $ret .= "</td>";
   798 
   799         if (@screened && $helper_mode) {
   800             $ret .= "<td>$ML{'.approve.screened'}:<br />";
   801             $ret .= LJ::html_select({ 'name' => 'approveans',
   802                                       'id' => 'approveans',
   803                                       'onclick' => 'return doApproveAnswer();' },
   804                                     ('', ''),
   805                                     map { $_->{'splid'}, "\#$_->{'splid'} (" . LJ::get_username($_->{'userid'}) . ")" }
   806                                     @screened);
   807             $ret .= LJ::html_select({ 'name' => 'approveas' },
   808                                     ("answer" => "as answer", "comment" => "as comment",));
   809             $ret .= "</td>";
   810         }
   811         $ret .= "</tr></table>\n";
   812 
   813         $ret .= "</td></tr>\n";
   814     }
   815 
   816     my $lang_ret;
   817     my $tier_ret;
   818 
   819     if (LJ::is_enabled("support_request_language") && LJ::Support::can_read_internal($sp, $remote) && ! $is_poster) {
   820         # language
   821         my %langs;
   822         my @lang_codes;
   823         my $lang_list = LJ::Lang::get_lang_names();
   824         for (my $i = 0; $i < @$lang_list; $i = $i+2) {
   825             push @lang_codes, $lang_list->[$i];
   826             $langs{$lang_list->[$i]} = $lang_list->[$i+1];
   827         }
   828         @lang_codes = sort { $a cmp $b } @lang_codes;
   829 
   830         my $current_lang = $props->{language} ? "[$props->{language}] $langs{$props->{language}}" : $ML{'.change.language.nolang'};
   831 
   832         $lang_ret .= "<td>$ML{'.change.language'}<br />";
   833         $lang_ret .= LJ::html_select({ 'name' => 'changelanguage',
   834                                   'onchange' => 'doChangeLanguage();' },
   835                                 ('', $current_lang),
   836                                 map { $_, "---> [$_] $langs{$_}" }
   837                                 @lang_codes);
   838         $lang_ret .= "</td>";
   839     }
   840 
   841     if (LJ::is_enabled("support_response_tier") && LJ::Support::can_perform_actions($sp, $remote) && ! $is_poster && $helper_mode) {
   842         my @valid_tiers = (
   843             tier1 => $ML{'.tier.1'},
   844             tier2 => $ML{'.tier.2'},
   845             tier3 => $ML{'.tier.3'},
   846         );
   847 
   848         $tier_ret .= "<td id='tier_cell'>$ML{'.tier.set'}<br />";
   849         $tier_ret .= LJ::html_select({
   850                 name => 'settier',
   851             }, ('' => $ML{'.tier.selectone'}), @valid_tiers
   852         );
   853         $tier_ret .= "</td>";
   854     }
   855 
   856     if ($lang_ret || $tier_ret) {
   857         $ret .= "<tr><td align='right'></td><td>\n";
   858         $ret .= "<table summary='' cellpadding='5'><tr>";
   859         $ret .= "$lang_ret$tier_ret";
   860         $ret .= "</tr></table>";
   861         $ret .= "</td></tr>\n";
   862     }
   863 
   864     if (LJ::Support::can_perform_actions($sp, $remote) && ! $is_poster) {
   865         if ($sp->{'timelasthelp'} > ($sp->{'timetouched'}+5)) {
   866             $ret .= "<tr><td align='right'>$ML{'.put.in.queue'}:</td><td>";
   867             $ret .= LJ::html_check({ 'type' => 'checkbox', 'name' => 'touch',
   868                                      'onclick' => 'doRegreen();' });
   869             $ret .= "<?de $ML{'.use.this.to.re-open'} de?>\n";
   870             $ret .= "</td></tr>\n";
   871         } else {
   872             $ret .= "<tr><td align='right'>$ML{'.take.out.of.queue'}</td><td>";
   873             $ret .= LJ::html_check({ 'type' => 'checkbox', 'name' => 'untouch',
   874                                      'onclick' => 'doDegreen();' });
   875             $ret .= "<?de $ML{'.use.this.to.change.awaiting'} de?>\n";
   876             $ret .= "</td></tr>\n";
   877         }
   878         if (LJ::Support::can_change_summary($sp, $remote)) {
   879             $ret .= "<tr><td align='right'>$ML{'.change.summary'}:</td><td>";
   880             $ret .= LJ::html_check({ 'type' => 'checkbox', 'name' => 'changesum', id => 'changesum', 'onClick' => 'doSummaryClick();' });
   881             $ret .= LJ::html_text({ 'type' => 'text', 'name' => 'summary', 'size' => '50', 'maxlength' => '80', 'value' => $sp->{'subject'}, 'onChange' => 'doSummaryChanged();' });
   882             $ret .= "</td></tr>\n";
   883             $ret .= "<tr><td>&nbsp;</td><td>";
   884             $ret .= "<?de $ML{'.use.this.to.summary'} de?>\n";
   885             $ret .= "</td></tr>\n";
   886         }
   887     }
   888     # Prefill an e-mail validation nag, if needed.
   889     my $validationnag;
   890     if (!(LJ::isu($u) && ($u->{'status'} eq 'T')) &&
   891         ($u->{'status'} eq "N" || $u->{'status'} eq "T") &&
   892         ! $u->is_identity && ! $is_poster) {
   893         my $reminder = LJ::load_include('validationreminder');
   894         $validationnag .= "\n\n$reminder" if $reminder;
   895     }
   896 
   897     # add in canned answers if there are any for this category and the user can use them
   898     if ($stock_mode && ! $is_poster) {
   899         # if one category's stock answers exactly matches another's
   900         my $stock_spcatid = $LJ::SUPPORT_STOCKS_OVERRIDE{$sp->{_cat}->{catkey}} || $sp->{_cat}->{spcatid};
   901         my $rows = $dbr->selectall_arrayref('SELECT subject, body FROM support_answers WHERE spcatid = ? ORDER BY subject',
   902                                             undef, $stock_spcatid);
   903 
   904         if ($rows && @$rows) {
   905             $ret .= "<tr valign='top'><td align='right'><a href='$LJ::SITEROOT/support/stock_answers?spcatid=$stock_spcatid'>Stock answers</a>:</td><td colspan='2'>\n";
   906             $ret .= "<script type='text/javascript'>\n";
   907             $ret .= "var Iarr = new Array();\n";
   908             my $i = 0;
   909             foreach my $row (@$rows) {
   910                 $ret .= "Iarr[$i] = '" . LJ::ejs($row->[1]) . "';\n";
   911                 $i++;
   912             }
   913             $ret .= "function insertCanned(i) {\n";
   914             $ret .= "    var obj = document.getElementById('body');\n";
   915             $ret .= "    var canned = document.getElementById('canned');\n";
   916             $ret .= "    if (canned && canned.value > -1 && obj) {\n";
   917             $ret .= "        obj.value = obj.value + Iarr[canned.value];\n";
   918             $ret .= "    }\n";
   919             $ret .= "}\n";
   920             $ret .= "</script>\n";
   921             $ret .= "<select id='canned' onChange='insertCanned();'>\n";
   922             $ret .= "<option value='-1' selected>( $ML{'.select.canned.to.insert'} )</option>\n";
   923             $i = 0;
   924             foreach my $row (@$rows) {
   925                 $ret .= "<option value='$i'>" . LJ::ehtml($row->[0]) . "</option>\n";
   926                 $i++;
   927             }
   928             $ret .= "</input>\n";
   929             $ret .= "</td></tr>";
   930         }
   931     }
   932 
   933     # textarea for their message body
   934     $ret .= "<tr valign='top'><td align='right'>$ML{'.message'}:</td><td colspan='2'>";
   935     $ret .= LJ::html_textarea({ 'rows' => '12', 'cols' => '80', 'wrap' => 'virtual', 'id' => 'body', 'name' => 'body', 'value' => $validationnag }) . "<br />";
   936     $ret .= "<div style='float: right; font-size: smaller;'><a href='javascript://' onClick='doClearMessage();' onFocus='doClearFocus();'>$ML{'.clear'}</a></div>";
   937     $ret .= "<?de $ML{'.no.html.allowed'} de?><br />";
   938     if ($is_poster) {
   939         $ret .= LJ::html_submit('submitpost', $ML{'.postbuttoninfo'}, { id => 'submitpost' });
   940     } else {
   941         $ret .= LJ::html_submit('submitpost', $ML{'.postbutton'}, { id => 'submitpost' });
   942     }
   943     $ret .= "</td></tr></table>\n";
   944 
   945     $ret .= "</form>\n";
   946 
   947 
   948     return $ret;
   949 }
   950 _code?>
   951 <?hr?>
   952 <?_code
   953 {
   954     use strict;
   955     use vars qw(%FORM);
   956     return '' if $FORM{'find'};
   957     LJ::need_res( 'stc/support.css' );
   958 
   959     my $spid = $FORM{'id'}+0;
   960     my $ret;
   961     
   962     $ret .= BML::ml('.see.preview', {preview_link=>"href='$LJ::SITEROOT/support/see_request?id=$spid&amp;find=prev'"});
   963     $ret .= BML::ml('.see.next', {next_link=>"href='$LJ::SITEROOT/support/see_request?id=$spid&amp;find=next'"});
   964     
   965     return $ret; 
   966 }
   967 _code?>
   968 <br>
   969 <?_code
   970 {
   971     my $ret;
   972     $ret .= BML::ml('.help.link', {helplink=>'href="help"'});
   973     $ret .= BML::ml('.back.link', {backlink=>'href="./"'});
   974 
   975     return $ret;
   976 }
   977 _code?>
   978 
   979 <=body
   980 page?>