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 {
";
$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?>