190 lines
6.1 KiB
Perl
190 lines
6.1 KiB
Perl
# This code was forked from the LiveJournal project owned and operated
|
|
# by Live Journal, Inc. The code has been modified and expanded by
|
|
# Dreamwidth Studios, LLC. These files were originally licensed under
|
|
# the terms of the license supplied by Live Journal, Inc, which can
|
|
# currently be found at:
|
|
#
|
|
# http://code.livejournal.org/trac/livejournal/browser/trunk/LICENSE-LiveJournal.txt
|
|
#
|
|
# In accordance with the original license, this code and all its
|
|
# modifications are provided under the GNU General Public License.
|
|
# A copy of that license can be found in the LICENSE file included as
|
|
# part of this distribution.
|
|
|
|
package LJ::Console::Command::Finduser;
|
|
|
|
use strict;
|
|
use base qw(LJ::Console::Command);
|
|
use Carp qw(croak);
|
|
|
|
sub cmd { "finduser" }
|
|
|
|
sub desc { "Finds all accounts matching a certain criterion. Requires priv: finduser." }
|
|
|
|
sub args_desc {
|
|
[
|
|
'criteria' => "One of: 'user', 'userid', 'email', 'openid', 'delve', or 'timeupdate'.",
|
|
'data' => "Either a username or email address, or a userid when using 'userid',"
|
|
. " or a URL when using 'openid'.",
|
|
]
|
|
}
|
|
|
|
sub usage { '<criteria> <data>' }
|
|
|
|
sub can_execute {
|
|
my $remote = LJ::get_remote();
|
|
return $remote && $remote->has_priv("finduser");
|
|
}
|
|
|
|
sub execute {
|
|
my ( $self, @args ) = @_;
|
|
|
|
return $self->error("No arguments given") unless @args;
|
|
|
|
my ( $crit, $data );
|
|
my $use_timeupdate = 0;
|
|
my $do_delve = 0;
|
|
|
|
if ( scalar(@args) == 1 ) {
|
|
|
|
# we can auto-detect emails easy enough
|
|
$data = $args[0];
|
|
$crit = ( $data =~ /@/ ) ? 'email' : 'user';
|
|
}
|
|
else {
|
|
# old format...but new variations
|
|
$crit = $args[0];
|
|
$data = $args[1];
|
|
|
|
# if they gave us the timeupdate flag as the criterion,
|
|
# rewrite as a regular finduser, but display last update time, too
|
|
if ( $crit eq 'timeupdate' ) {
|
|
$use_timeupdate = 1;
|
|
$crit = ( $data =~ /@/ ) ? 'email' : 'user';
|
|
}
|
|
|
|
# if they gave us the delve subcommand, do search by email
|
|
# but only do the delve if they also have the infohistory priv
|
|
if ( $crit eq 'delve' ) {
|
|
my $remote = LJ::get_remote();
|
|
$do_delve = 1 if $remote && $remote->has_priv( "finduser", "infohistory" );
|
|
$crit = 'email';
|
|
}
|
|
|
|
# if they gave us a username and want to search by email, instead find
|
|
# all users with that email address
|
|
if ( $crit eq 'email' && $data !~ /@/ ) {
|
|
my $u = LJ::load_user($data)
|
|
or return $self->error("User $data doesn't exist.");
|
|
$data = $u->email_raw
|
|
or return $self->error( $u->user . " does not have an email address." );
|
|
}
|
|
|
|
if ( $crit eq 'openid' ) {
|
|
if ( $data =~ m!^[^/]+$! ) {
|
|
|
|
# (a) given host.domain (no slashes)
|
|
$data = "//$data/"; # add slashes to indicate start and end
|
|
}
|
|
elsif ( $data =~ s/^https?:// || $data =~ m!^//! ) {
|
|
|
|
# (b) convert HTTP(S) link to protocol-neutral URL;
|
|
# add trailing slash if we aren't using a host/page URL
|
|
$data .= '/' if $data =~ m!^//[^/]+$!;
|
|
}
|
|
else {
|
|
return $self->error("Doesn't look like a valid web URL: $data");
|
|
}
|
|
|
|
# URL should now be of the form //host.domain/ or //host.domain/page
|
|
}
|
|
}
|
|
|
|
my $dbh = LJ::get_db_reader();
|
|
my $userlist;
|
|
my %idmap; # for identity accounts
|
|
|
|
if ( $crit eq 'email' ) {
|
|
$userlist =
|
|
$dbh->selectcol_arrayref( "SELECT userid FROM email WHERE email = ?", undef, $data );
|
|
}
|
|
elsif ( $crit eq 'userid' ) {
|
|
$userlist =
|
|
$dbh->selectcol_arrayref( "SELECT userid FROM user WHERE userid = ?", undef, $data );
|
|
}
|
|
elsif ( $crit eq 'user' ) {
|
|
$data = LJ::canonical_username($data);
|
|
$userlist =
|
|
$dbh->selectcol_arrayref( "SELECT userid FROM user WHERE user = ?", undef, $data );
|
|
}
|
|
elsif ( $crit eq 'openid' ) {
|
|
|
|
# Use wildcard search to match either HTTP or HTTPS entries.
|
|
my $rows = $dbh->selectcol_arrayref(
|
|
"SELECT userid, identity FROM identitymap WHERE idtype='O' AND identity LIKE ?",
|
|
{ Columns => [ 1, 2 ] }, "%$data" );
|
|
%idmap = @$rows;
|
|
$userlist = [ keys %idmap ];
|
|
}
|
|
else {
|
|
return $self->error("Unknown criterion. Consult the reference.");
|
|
}
|
|
|
|
return $self->error("Error in database query.")
|
|
if $dbh->err;
|
|
|
|
my $userids = [];
|
|
push @$userids, @{ $userlist || [] };
|
|
|
|
return $self->error("No matches")
|
|
unless @$userids;
|
|
|
|
my $us = LJ::load_userids(@$userids);
|
|
|
|
if ($do_delve) {
|
|
$self->info( sprintf( "%d accounts found for email %s", scalar @$userids, $data ) );
|
|
foreach ( LJ::Hooks::run_hooks( "finduser_delve", $us ) ) {
|
|
next unless $_->[0];
|
|
$self->info($_) foreach ( split( /\n/, $_->[0] ) );
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
my $timeupdate;
|
|
$timeupdate = LJ::get_timeupdate_multi( {}, @$userids )
|
|
if $use_timeupdate;
|
|
|
|
foreach my $u ( sort { $a->id <=> $b->id } values %$us ) {
|
|
next unless $u;
|
|
my $userid = $u->id;
|
|
|
|
$self->info( "User: "
|
|
. $u->user . " ("
|
|
. $u->id
|
|
. "), journaltype: "
|
|
. $u->journaltype
|
|
. ", statusvis: "
|
|
. $u->statusvis
|
|
. ", email: ("
|
|
. $u->email_status . ") "
|
|
. $u->email_raw );
|
|
|
|
$self->info(" URL: $idmap{$userid}") if $crit eq 'openid';
|
|
|
|
$self->info(" User is currently in read-only mode.")
|
|
if $u->readonly;
|
|
|
|
$self->info( " Last updated: "
|
|
. ( $timeupdate->{$userid} ? LJ::time_to_http( $timeupdate->{$userid} ) : "Never" )
|
|
) if $use_timeupdate;
|
|
|
|
foreach ( LJ::Hooks::run_hooks( "finduser_extrainfo", $u ) ) {
|
|
next unless $_->[0];
|
|
$self->info($_) foreach ( split( /\n/, $_->[0] ) );
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
1;
|