userid) : undef; return "" unless $u; my $max_accts = $u->count_max_xpost_accounts; my %errs; if (LJ::did_post()) { my $result; if ($POST{acctid}) { $result = edit_external_account($u, \%POST, \%errs); } else { $result = create_external_account($u, \%POST, \%errs); } if ($result) { return BML::redirect("$LJ::SITEROOT/manage/settings/?cat=othersites$result"); } } # this shows if we're creating a new account or editing an existing one. my $editpage = 0; my $editacct; my $acctid = $GET{acctid} ? $GET{acctid} : $POST{acctid}; if ($acctid) { $editacct = DW::External::Account->get_external_account($u, $acctid); # if the account doesn't exist, ignore it. if ($editacct) { $editpage = 1; } } $title = $editpage ? $ML{'.title.edit'} : $ML{'.title.new'}; my $body .= qq {
}; if ($editpage) { $body .= LJ::html_hidden('acctid', $editacct->acctid); } $body .= "
"; my %protocols = DW::External::XPostProtocol->get_all_protocols; $body .= ""; if ($editpage) { $body .= "\n"; $body .= "\n"; } else { my @sitevalues; my @sites = DW::External::Site->get_xpost_sites; # sort the sites for the site dropdown, but also add in the protocol # map for the options hide/show $body .= "\n"; # add the custom site option push @sitevalues, '-1'; push @sitevalues, $ML{'.setting.xpost.option.site.custom'}; # the values for the protocol selection dropdown for custom sites my %protocolselectmap; foreach my $protocol (keys %protocols) { $protocolselectmap{$protocol} = $protocol; } $body .= "\n"; # end } $body .= ""; if ($editpage) { $body .= "\n"; } else { $body .= "\n"; } $body .= ""; $body .= "\n"; $body .= ""; $body .= "\n"; $body .= ""; $body .= "\n"; $body .= ""; $body .= "\n"; # put in the protocol option section for each protocol foreach my $protocol_id ( keys %protocols ) { my $protocol = $protocols{$protocol_id}; my @protocol_options = $protocol->protocol_options( $editacct, LJ::did_post() ? \%POST : undef ); if ( @protocol_options ) { $body .= "\n"; $body .="\n"; } } } $body .= "\n"; } $body .= "\n"; $body .= "
" . $editacct->servername . "" . LJ::html_select({ name => "site", onchange => "updateSiteSelection()", selected => $POST{site} || '2' }, @sitevalues); my $servicetype_errdiv = errdiv( \%errs, "servicetype" ); $body .= "
$servicetype_errdiv\n" if $servicetype_errdiv; $body .= ""; $body .= ""; $body .= "\n"; # hide if we have javascript, and if we haven't already selected # a custom site. if ($POST{"site"} ne -1) { $body .= qq { }; } # servicename $body .= ""; $body .= "\n"; # serviceurl $body .= ""; $body .= "\n"; $body .= "
" . LJ::html_select({ name => "servicetype", id => "servicetype", onchange => "updateProtocolSelection()" }, %protocolselectmap); $body .= "
" . LJ::html_text({ name => "servicename", id => "servicename", value => $POST{servicename}, disabled => 0, size => 40, maxlength => 80, }); my $servicename_errdiv = errdiv(\%errs, "servicename"); $body .= "
$servicename_errdiv" if $servicename_errdiv; $body .= "
" . LJ::html_text({ name => "serviceurl", id => "serviceurl", value => $POST{serviceurl}, disabled => 0, size => 40, maxlength => 80, }); my $serviceurl_errdiv = errdiv(\%errs, "serviceurl"); $body .= "
$serviceurl_errdiv" if $serviceurl_errdiv; $body .= "
"; # end customsite table $body .= "
" . $editacct->username . "" . LJ::html_text({ name => "username", id => "username", value => $POST{username}, disabled => 0, size => 40, maxlength => 80, }); $body .= "
$ML{'.setting.xpost.option.username.info'}"; my $username_errdiv = errdiv(\%errs, "username"); $body .= "
$username_errdiv" if $username_errdiv; $body .= "
" . LJ::html_text({ name => "password", id => "password", value => $editpage ? "" : $POST{password}, disabled => 0, size => 40, maxlength => 80, type => 'password' }); $body .= "
$ML{'.setting.xpost.option.password.info'}"; my $password_errdiv = errdiv(\%errs, "password"); $body .= "
$password_errdiv" if $password_errdiv; my $accountinvalid_errdiv = errdiv(\%errs, "accountinvalid"); $body .= "
$accountinvalid_errdiv" if $accountinvalid_errdiv; $body .= "
" . LJ::html_check({ name => "xpostbydefault", value => 1, id => "xpostbydefault", selected => $editpage ? $editacct->xpostbydefault : $POST{xpostbydefault} }); my $xpostbydefault_errdiv = errdiv(\%errs, "xpostbydefault"); $body .= "
$xpostbydefault_errdiv" if $xpostbydefault_errdiv; $body .= "
" . LJ::html_check({ name => "recordlink", value => 1, id => "recordlink", selected => $editpage ? $editacct->recordlink : $POST{recordlink} }); my $recordlink_errdiv = errdiv(\%errs, "recordlink"); $body .= "
$recordlink_errdiv" if $recordlink_errdiv; $body .= "
" . LJ::html_check({ name => "savepassword", value => 1, id => "savepassword", selected => LJ::did_post() ? $POST{savepassword} : $editpage ? $editacct->password ne "" : 1, }); my $savepassword_errdiv = errdiv(\%errs, "savepassword"); $body .= "
$savepassword_errdiv" if $savepassword_errdiv; $body .= "
" . BML::ml( '.protocol.options', { protocol => $protocol->protocolid } ) . ""; foreach my $option ( @protocol_options ) { if ( $option->{type} eq 'select' ) { $body .= "" . LJ::html_select( $option->{opts}, @{$option->{options}} ) . "
"; $body .= "
"; $body .= LJ::html_submit(undef, $editpage ? $ML{'.btn.update'} : $ML{'.btn.create'}); $body .="
"; $body .= "
"; $body .= "
"; $body .= "
"; return $body; } sub errdiv { my ($errs, $key) = @_; return "" unless $errs; my $err = $errs->{$key} or return ""; # FIXME: red is temporary. move to css. return "
$err
"; } # form handler. does the actual new account creation. sub create_external_account { my ($u, $POST, $errs) = @_; # check to see if we're already at max. my $max_accts = $u->count_max_xpost_accounts; my @accounts = DW::External::Account->get_external_accounts($u); my $acct_count = scalar @accounts; if ($acct_count >= $max_accts) { my $errmsg = ( $max_accts == 1 ) ? '.error.maxacct.singular' : '.error.maxacct.plural'; $errs->{servicetype} = LJ::Lang::ml( $errmsg, { max_accts => $max_accts } ); return 0; } # create new account my %opts; my $ok = 1; # general properties, for all servers $opts{password} = $POST->{password}; $opts{username} = $POST->{username}; $opts{xpostbydefault} = $POST->{xpostbydefault}; $opts{recordlink} = $POST->{recordlink}; $opts{savepassword} = $POST->{savepassword}; # username is required if (! $opts{username}) { $errs->{username} = BML::ml('.settings.xpost.error.username.required'); $ok = 0; } my $extacct_info = +{ map { $_ => $POST{$_} } keys %POST }; # check if it's a default site or a custom site if ($POST->{"site"} ne -1) { # default site; just use the siteid $opts{siteid} = $POST->{"site"}; } else { # custom site $opts{servicename} = $POST->{servicename}; $opts{servicetype} = $POST->{servicetype}; $opts{serviceurl} = $POST->{serviceurl}; # all three fields are required for custom sites foreach my $reqfield( qw ( servicename servicetype serviceurl ) ) { if (! $opts{$reqfield}) { $errs->{$reqfield} = BML::ml(".settings.xpost.error.$reqfield.required"); $ok = 0; } } # validate the site. if ($ok) { my $protocol = DW::External::XPostProtocol->get_protocol($opts{servicetype}); if (! $protocol) { $errs->{servicetype} = BML::ml('.settings.xpost.error.servicetype', { servicetype => $opts{servicetype} }); $ok = 0; } else { my ( $valid, $serviceurl ) = $protocol->validate_server( $opts{serviceurl} ); if ( $valid ) { # update in case it's been canonicalized $extacct_info->{serviceurl} = $opts{serviceurl} = $serviceurl; } else { $errs->{serviceurl} = BML::ml('.settings.xpost.error.url', { url => $opts{serviceurl} }); $ok = 0; } } } } # verification of account info - only do this if $ok isn't already set to 0, so we have username/password and valid site info if ( $ok ) { my $account_valid = account_isvalid( $u, $extacct_info ); if ( $account_valid != 1 ) { $ok = 0; #create different error messages for different server errors. If we get some other error message, show the one we get from the server if ( $account_valid eq "Invalid username" ) { $errs->{username} = BML::ml('.settings.xpost.error.username.invalid'); } elsif ( $account_valid eq "Invalid password" ) { $errs->{password} = BML::ml('.settings.xpost.error.password.invalid'); } elsif ( $account_valid eq "Client error: Your IP address is temporarily banned for exceeding the login failure rate." ) { $errs->{accountinvalid} = BML::ml('.settings.xpost.error.ipban'); } else { $errs->{accountinvalid} = $account_valid; } } } if ( $ok ) { # check the options, if any. my $protocol; if ( $opts{siteid} ) { my $site = DW::External::Site->get_site_by_id( $opts{siteid} ); $protocol = DW::External::XPostProtocol->get_protocol( $site->servicetype ); } else { $protocol = DW::External::XPostProtocol->get_protocol( $opts{servicetype} ); } my $options = parse_options( $protocol, $extacct_info ); $opts{options} = $options; # if the user requested that we don't save their password, then # don't save their password. $opts{password} = "" unless $opts{savepassword}; my $new_acct = DW::External::Account->create($u, \%opts); # FIXME add error if create fails. if ($new_acct) { return "&create=". $new_acct->acctid; } else { return 0; } } return $ok; } #check whether an account actually exists on the other service and whether the password is correct by sending a 'login' request sub account_isvalid { my ( $u, $extacct ) = @_; my $protocol_id, my $proxyurl; # if the site was selected from the drop-down, we need to get the corresponding values. # if it's user-entered, we can construct the site from these values. # we only run this check if we have already validated the external site. if ( $extacct->{site} ne -1 ) { my $siteid = $extacct->{site}; my $externalsite = DW::External::Site->get_site_by_id( $siteid ); $proxyurl = "https://" . $externalsite->{domain} . "/interface/xmlrpc"; $protocol_id = $externalsite->servicetype; } else { $proxyurl = $extacct->{serviceurl}; $protocol_id = $extacct->{servicetype}; } #need to encrypt password to send it my $protocol = DW::External::XPostProtocol->get_protocol( $protocol_id ); my $encryptedpassword = $protocol->encrypt_password( $extacct->{password} ); $extacct->{encrypted_password} = $encryptedpassword; #check to see whether we can log in with this data my $authresp = DW::External::XPostProtocol::LJXMLRPC->call_xmlrpc( $proxyurl, 'login', {}, $extacct ); #if the validation was successful, return 1, if not return the error message if ( $authresp->{success} ) { return 1; } else { return $authresp->{error}; } } # form handler. edits the given account. sub edit_external_account { my ($u, $POST, $errs) = @_; my $acct = DW::External::Account->get_external_account($u, $POST{acctid}); return 0 unless $acct; my $newpw = $POST{password} || ""; if (! $POST{savepassword}) { # don't save the password. checkbox unchecked $acct->set_password(""); } elsif ( $POST{password} && $POST{password} ne "" ) { # we have a password $acct->set_password($POST{password}); } $acct->set_xpostbydefault($POST{xpostbydefault}); $acct->set_recordlink($POST{recordlink}); $acct->set_options( parse_options( $acct->protocol, $POST ) ); return "&update=" . $acct->acctid; } # returns the appropriate options from the post. sub parse_options { my ( $protocol, $POST ) = @_; my $options = {}; foreach my $option ( $protocol->protocol_options ) { my $option_name = $option->{opts}->{name}; my $value = $POST{$option_name}; if ( $value ) { $options->{$option_name} = $value; } } return $options; } _code?> <=body title=> windowtitle=> head<= <=head page?>