288 lines
9.7 KiB
Perl
288 lines
9.7 KiB
Perl
|
|
#!/usr/bin/perl
|
||
|
|
#
|
||
|
|
# DW::Controller::Profile
|
||
|
|
#
|
||
|
|
# Displays information about an account in a viewer friendly manner.
|
||
|
|
#
|
||
|
|
# Authors:
|
||
|
|
# Mark Smith <mark@dreamwidth.org>
|
||
|
|
# Janine Smith <janine@netrophic.com>
|
||
|
|
# Jen Griffin <kareila@livejournal.com> -- TT conversion
|
||
|
|
#
|
||
|
|
# Copyright (c) 2009-2020 by Dreamwidth Studios, LLC.
|
||
|
|
#
|
||
|
|
# This program is free software; you may redistribute it and/or modify it under
|
||
|
|
# the same terms as Perl itself. For a copy of the license, please reference
|
||
|
|
# 'perldoc perlartistic' or 'perldoc perlgpl'.
|
||
|
|
#
|
||
|
|
|
||
|
|
package DW::Controller::Profile;
|
||
|
|
|
||
|
|
use strict;
|
||
|
|
|
||
|
|
use DW::Controller;
|
||
|
|
use DW::Routing;
|
||
|
|
|
||
|
|
DW::Routing->register_string( '/profile', \&profile_handler, app => 1 );
|
||
|
|
|
||
|
|
sub profile_handler {
|
||
|
|
my ( $ok, $rv ) = controller( anonymous => 1 );
|
||
|
|
return $rv unless $ok;
|
||
|
|
|
||
|
|
my $r = $rv->{r};
|
||
|
|
my $get = $r->get_args;
|
||
|
|
|
||
|
|
my $is_full = $get->{mode} && $get->{mode} eq 'full' ? 1 : 0;
|
||
|
|
|
||
|
|
my $scope = '/profile/main.tt';
|
||
|
|
|
||
|
|
my $remote = $rv->{remote};
|
||
|
|
my $u;
|
||
|
|
|
||
|
|
# figure out what $u should be
|
||
|
|
{
|
||
|
|
my $userarg = $get->{user};
|
||
|
|
|
||
|
|
# when using user domain URLs, get userarg from the request notes,
|
||
|
|
# which was set in LiveJournal.pm
|
||
|
|
$userarg ||= $r->note('_journal');
|
||
|
|
|
||
|
|
my $username = LJ::canonical_username($userarg);
|
||
|
|
|
||
|
|
# usually we're going off username, but under some circumstances
|
||
|
|
# we may be given a userid instead, so check for that first
|
||
|
|
|
||
|
|
if ( my $userid = ( $get->{userid} || 0 ) + 0 ) {
|
||
|
|
$u = LJ::load_userid($userid);
|
||
|
|
|
||
|
|
# only users with finduser can view profiles by userid, unless
|
||
|
|
# we are viewing the profile of an identity (OpenID) account
|
||
|
|
unless ( ( $remote && $remote->has_priv('finduser') )
|
||
|
|
|| ( $get->{t} && $get->{t} eq "I" && $u && $u->is_identity ) )
|
||
|
|
{
|
||
|
|
return error_ml("$scope.error.reqfinduser");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
elsif ($username) {
|
||
|
|
$u = LJ::load_user($username);
|
||
|
|
|
||
|
|
# redirect identity accounts to standard identity url
|
||
|
|
if ( $u && $u->is_identity ) {
|
||
|
|
return $r->redirect( $u->profile_url( full => $is_full ) );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
elsif ($remote) {
|
||
|
|
$u = $remote;
|
||
|
|
}
|
||
|
|
else { # visited $LJ::SITEROOT/profile with no userargs while logged out
|
||
|
|
return DW::Controller::needlogin();
|
||
|
|
}
|
||
|
|
|
||
|
|
# at this point, if we still don't have $u, give up
|
||
|
|
return error_ml( "$scope.error.nonexist", { user => $username } ) unless $u;
|
||
|
|
|
||
|
|
LJ::set_active_journal($u);
|
||
|
|
}
|
||
|
|
|
||
|
|
# error if account is purged
|
||
|
|
return DW::Template->render_template('error/purged.tt') if $u->is_expunged;
|
||
|
|
|
||
|
|
# redirect non-identity profiles to their subdomain urls
|
||
|
|
if ( !$u->is_identity ) {
|
||
|
|
my $url = $u->profile_url( full => $is_full );
|
||
|
|
|
||
|
|
# use regexps to extract the user domain from $url and compare to $r
|
||
|
|
my $good_domain = $url;
|
||
|
|
$good_domain =~ s!^https?://!!;
|
||
|
|
$good_domain =~ s!/.*!!;
|
||
|
|
if ( $r->header_in("Host") ne $good_domain ) {
|
||
|
|
return $r->redirect($url);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# rename redirect?
|
||
|
|
{
|
||
|
|
my $renamed_u = $u->get_renamed_user;
|
||
|
|
unless ( $u->equals($renamed_u) ) {
|
||
|
|
my $urlargs = { user => $renamed_u->user };
|
||
|
|
$urlargs->{mode} = 'full' if $is_full;
|
||
|
|
return $r->redirect( LJ::create_url( '/profile', args => $urlargs ) );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
# can't view suspended/deleted profiles unless you have viewall
|
||
|
|
my $viewall = 0;
|
||
|
|
($viewall) = $remote->view_priv_check( $u, $get->{viewall}, 'profile' ) if $remote;
|
||
|
|
|
||
|
|
unless ($viewall) {
|
||
|
|
return DW::Template->render_template( 'error/suspended.tt', { u => $u, remote => $remote } )
|
||
|
|
if $u->is_suspended;
|
||
|
|
|
||
|
|
return $u->display_journal_deleted($remote) if $u->is_deleted;
|
||
|
|
}
|
||
|
|
|
||
|
|
# DONE with error pages and redirects - begin building the page!
|
||
|
|
|
||
|
|
LJ::need_res("js/profile.js");
|
||
|
|
LJ::need_res( { priority => $LJ::OLD_RES_PRIORITY }, "stc/profile.css" );
|
||
|
|
|
||
|
|
my $vars = { u => $u, remote => $remote, is_full => $is_full };
|
||
|
|
|
||
|
|
$vars->{profile} = $u->profile_page( $remote, viewall => $viewall );
|
||
|
|
|
||
|
|
# block robots?
|
||
|
|
$vars->{robot_meta_tags} = LJ::robot_meta_tags()
|
||
|
|
if !$u->is_visible || $u->should_block_robots;
|
||
|
|
|
||
|
|
# TODO: stop profile choking on large numbers of subscribers or members
|
||
|
|
$vars->{force_empty} = exists $LJ::FORCE_EMPTY_SUBSCRIPTIONS{ $u->id } ? 1 : 0;
|
||
|
|
|
||
|
|
$vars->{load_userids} = sub { LJ::load_userids( @{ $_[0] } ) };
|
||
|
|
|
||
|
|
$vars->{sort_by_username} = sub {
|
||
|
|
my ( $list, $us ) = @_;
|
||
|
|
my $sort = sub { $a->display_name cmp $b->display_name };
|
||
|
|
$sort = sub { $us->{$a}->display_name cmp $us->{$b}->display_name }
|
||
|
|
if $us;
|
||
|
|
return [ sort $sort @$list ];
|
||
|
|
};
|
||
|
|
|
||
|
|
$vars->{createdate} = LJ::mysql_time( $u->timecreate );
|
||
|
|
$vars->{accttype} = DW::Pay::get_account_type_name($u);
|
||
|
|
$vars->{expiretime} = sub {
|
||
|
|
my $expiretime = DW::Pay::get_account_expiration_time($u);
|
||
|
|
return DateTime->from_epoch( epoch => $expiretime )->date
|
||
|
|
if $expiretime > 0;
|
||
|
|
};
|
||
|
|
|
||
|
|
# given a single item (scalar or hashref), linkify it and return string
|
||
|
|
$vars->{linkify} = sub {
|
||
|
|
my $l = $_[0];
|
||
|
|
return $l unless ref $l eq 'HASH';
|
||
|
|
|
||
|
|
if ( $l->{text} ) {
|
||
|
|
my $ret = "";
|
||
|
|
$ret .= $l->{secimg} if $l->{secimg};
|
||
|
|
$ret .= $l->{url} ? qq(<a href="$l->{url}" rel="nofollow">$l->{text}</a>) : $l->{text};
|
||
|
|
return $ret;
|
||
|
|
}
|
||
|
|
elsif ( $l->{email} ) {
|
||
|
|
|
||
|
|
# the ehtml call here shouldn't be necessary, but just in case
|
||
|
|
# they slip in an email that contains Bad Stuff, escape it
|
||
|
|
my $mangled_email = LJ::CleanHTML::mangle_email_address( LJ::ehtml( $l->{email} ) );
|
||
|
|
|
||
|
|
# return the mangled email with a privacy icon if there is one
|
||
|
|
$mangled_email = $l->{secimg} . $mangled_email if $l->{secimg};
|
||
|
|
return $mangled_email;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
return LJ::Lang::ml("$scope.error.linkify");
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
# given multiple items in an arrayref, linkify each one appropriately
|
||
|
|
# and return them as one string with the join_string separating each item
|
||
|
|
# (the join_string will be the first item in the arrayref)
|
||
|
|
$vars->{linkify_multiple} = sub {
|
||
|
|
my $r = $_[0];
|
||
|
|
return $r unless ref $r eq 'ARRAY';
|
||
|
|
|
||
|
|
return $vars->{linkify}->( $r->[0] ) unless @$r > 1;
|
||
|
|
|
||
|
|
my $join_string = shift @$r;
|
||
|
|
my @links;
|
||
|
|
foreach my $l (@$r) {
|
||
|
|
next unless $l;
|
||
|
|
push @links, $vars->{linkify}->($l);
|
||
|
|
}
|
||
|
|
|
||
|
|
return join( $join_string, @links );
|
||
|
|
};
|
||
|
|
|
||
|
|
# helper function for repetitive link array construction
|
||
|
|
$vars->{cb_links} = sub {
|
||
|
|
my $opts = $_[0];
|
||
|
|
my @ret;
|
||
|
|
push @ret, { url => $opts->{editurl}, text => LJ::Lang::ml("$scope.section.edit") }
|
||
|
|
if $remote && $remote->can_manage($u) && $opts->{editurl};
|
||
|
|
my $extra = $opts->{extra} // [];
|
||
|
|
push( @ret, $_ ) foreach @$extra;
|
||
|
|
return \@ret;
|
||
|
|
};
|
||
|
|
|
||
|
|
# code for separating OpenID users by site
|
||
|
|
$vars->{parse_openids} = sub {
|
||
|
|
my ($openids) = @_;
|
||
|
|
return unless $openids;
|
||
|
|
|
||
|
|
my %sites;
|
||
|
|
my %shortnames;
|
||
|
|
|
||
|
|
my $sitestore = sub {
|
||
|
|
my ( $site, $u, $name ) = @_;
|
||
|
|
$sites{$site} ||= [];
|
||
|
|
$shortnames{$site} ||= [];
|
||
|
|
|
||
|
|
push @{ $sites{$site} }, $u;
|
||
|
|
push @{ $shortnames{$site} }, $name;
|
||
|
|
};
|
||
|
|
|
||
|
|
# TODO: use DW::External methods here?
|
||
|
|
foreach my $u (@$openids) {
|
||
|
|
my $id = $u->display_name;
|
||
|
|
my @parts = split /\./, $id;
|
||
|
|
if ( @parts < 2 ) {
|
||
|
|
|
||
|
|
# we don't know how to parse this, so don't
|
||
|
|
$sitestore->( 'unknown', $u, $id );
|
||
|
|
next;
|
||
|
|
}
|
||
|
|
|
||
|
|
my ( $name, $site );
|
||
|
|
|
||
|
|
# if this looks like a URL, hope the username is at the end
|
||
|
|
if ( $parts[-1] =~ m=/([^/]+)/?$= ) {
|
||
|
|
$name = $1;
|
||
|
|
($site) = ( $id =~ m=([^/.]+\.[^/]+)= );
|
||
|
|
|
||
|
|
}
|
||
|
|
else { # assume the username is the hostname
|
||
|
|
my $host = shift @parts;
|
||
|
|
($name) = ( $host =~ m=([^/]+)$= );
|
||
|
|
$site = join '.', @parts;
|
||
|
|
}
|
||
|
|
|
||
|
|
$sitestore->( $site, $u, $name );
|
||
|
|
}
|
||
|
|
|
||
|
|
return { sites => \%sites, shortnames => \%shortnames };
|
||
|
|
};
|
||
|
|
|
||
|
|
# organize filtering subs for various watch/trust/etc. lists
|
||
|
|
$vars->{includeuser} = {
|
||
|
|
trusted => sub { 1 },
|
||
|
|
trusted_by => sub { $is_full || !$_[0]->is_inactive },
|
||
|
|
mutually_trusted => sub { $_[0]->is_individual },
|
||
|
|
not_mutually_trusted => sub { 1 },
|
||
|
|
not_mutually_trusted_by => sub { $is_full || !$_[0]->is_inactive },
|
||
|
|
watched => sub { # this one filters on journaltype
|
||
|
|
( $_[0]->journaltype =~ /^[\Q$_[1]\E]$/ ) # 'PI', 'C', 'Y'
|
||
|
|
&& ( $_[1] eq 'C' ? $is_full || !$_[0]->is_inactive : 1 );
|
||
|
|
},
|
||
|
|
watched_by => sub { $is_full || !$_[0]->is_inactive },
|
||
|
|
mutually_watched => sub { $_[0]->is_individual },
|
||
|
|
not_mutually_watched => sub { $_[0]->is_individual },
|
||
|
|
not_mutually_watched_by => sub { $is_full || !$_[0]->is_inactive },
|
||
|
|
members => sub { 1 },
|
||
|
|
member_of => sub { $is_full || !$_[0]->is_inactive },
|
||
|
|
admin_of => sub { $is_full || !$_[0]->is_inactive },
|
||
|
|
posting_access_to => sub { $is_full || !$_[0]->is_inactive },
|
||
|
|
posting_access_from => sub { 1 },
|
||
|
|
};
|
||
|
|
|
||
|
|
return DW::Template->render_template( 'profile/main.tt', $vars );
|
||
|
|
}
|
||
|
|
|
||
|
|
1;
|