369 lines
12 KiB
Perl
369 lines
12 KiB
Perl
#!/usr/bin/perl
|
|
#
|
|
# DW::Controller::RPC::Misc
|
|
#
|
|
# The AJAX endpoint for general calls.
|
|
#
|
|
# Authors:
|
|
# Mark Smith <mark@dreamwidth.org>
|
|
#
|
|
# Copyright (c) 2009-2013 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::RPC::Misc;
|
|
|
|
use strict;
|
|
use LJ::JSON;
|
|
use DW::Routing;
|
|
use DW::Controller;
|
|
|
|
DW::Routing->register_rpc( "contentfilters", \&contentfilters_handler, format => 'json' );
|
|
DW::Routing->register_rpc( "extacct_auth", \&extacct_auth_handler, format => 'json' );
|
|
DW::Routing->register_rpc( "general", \&general_handler, format => 'json' );
|
|
DW::Routing->register_rpc(
|
|
"addcomment", \&addcomment_handler,
|
|
format => 'json',
|
|
methods => { POST => 1 }
|
|
);
|
|
|
|
sub contentfilters_handler {
|
|
my $r = DW::Request->get;
|
|
my $get = $r->get_args;
|
|
my $post = $r->post_args;
|
|
|
|
# make sure we have a user of some sort
|
|
my $remote = LJ::get_remote();
|
|
my $remote_user = $remote ? $remote->user : undef;
|
|
my $u = LJ::get_authas_user( $get->{user} || $remote_user );
|
|
return DW::RPC->alert('Unable to load user for call.') unless $u;
|
|
|
|
# in theory, they're passing a mode in the GET arguments
|
|
my $mode = $get->{mode}
|
|
or return DW::RPC->alert('No mode passed.');
|
|
|
|
my %ret;
|
|
|
|
# list_filters mode is very simple: it returns an array of the filters with the
|
|
# pertinent information about those filters
|
|
if ( $mode eq 'list_filters' ) {
|
|
$ret{filters} = {};
|
|
|
|
my @filters = $u->content_filters;
|
|
foreach my $filt (@filters) {
|
|
$ret{filters}->{ $filt->id } = {
|
|
id => $filt->id,
|
|
name => $filt->name,
|
|
sortorder => $filt->sortorder,
|
|
public => $filt->public,
|
|
};
|
|
}
|
|
|
|
# list the names of the people who are on a filter
|
|
}
|
|
elsif ( $mode eq 'list_members' ) {
|
|
$ret{members} = {};
|
|
|
|
my $filter = $u->content_filters( id => $get->{filterid} )
|
|
or return DW::RPC->alert('No such filter.');
|
|
|
|
my $data = $filter->data;
|
|
foreach my $uid ( keys %$data ) {
|
|
my $member = $data->{$uid};
|
|
|
|
# FIXME: use load_userids_multiple to get the user objects...
|
|
$ret{members}->{$uid} = {
|
|
user => LJ::load_userid($uid)->user,
|
|
adultcontent => $member->{adultcontent} || 'any',
|
|
postertype => $member->{postertype} || 'any',
|
|
tagmode => $member->{tagmode} || 'any_of',
|
|
tags => { map { $_ => 1 } @{ $member->{tags} || [] } },
|
|
};
|
|
}
|
|
|
|
# called to make a brand new filter
|
|
}
|
|
elsif ( $mode eq 'create_filter' ) {
|
|
return DW::RPC->alert('Can only create filters for people.')
|
|
unless $u->is_individual;
|
|
|
|
return DW::RPC->alert('No name provided.')
|
|
unless $get->{name} =~ /\S/;
|
|
|
|
my $fid = $u->create_content_filter( name => $get->{name} );
|
|
return DW::RPC->alert('Failed to create content filter.')
|
|
unless $fid;
|
|
|
|
my $cf = $u->content_filters( id => $fid );
|
|
return DW::RPC->alert('Failed to retrieve content filter.')
|
|
unless $cf;
|
|
|
|
%ret = (
|
|
id => $cf->id,
|
|
name => $cf->name,
|
|
public => $cf->public,
|
|
sortorder => $cf->sortorder,
|
|
);
|
|
|
|
# delete a content filter
|
|
}
|
|
elsif ( $mode eq 'delete_filter' ) {
|
|
return DW::RPC->alert('Can only create filters for people.')
|
|
unless $u->is_individual;
|
|
|
|
return DW::RPC->alert('No/invalid id provided.')
|
|
unless $get->{id} =~ /^\d+$/;
|
|
|
|
my $id = $u->delete_content_filter( id => $get->{id} );
|
|
return DW::RPC->alert('Failed to delete the content filter.')
|
|
unless $id == $get->{id};
|
|
|
|
$ret{ok} = 1;
|
|
|
|
# save incoming changes
|
|
}
|
|
elsif ( $mode eq 'save_filters' ) {
|
|
my $obj = from_json( $post->{json} );
|
|
|
|
foreach my $fid ( keys %$obj ) {
|
|
my $filt = $obj->{$fid};
|
|
|
|
# load this filter
|
|
my $cf = $u->content_filters( id => $fid );
|
|
return DW::RPC->alert("Filter id $fid does not exist.")
|
|
unless $cf;
|
|
|
|
# update the name if necessary, this has to be before the members check
|
|
# because they might not have loaded members (or it might have none)
|
|
$cf->name( $filt->{name} )
|
|
if $filt->{name} && $filt->{name} ne $cf->name;
|
|
|
|
# skip the filter if it hasn't actually been loaded
|
|
next unless defined $filt->{members};
|
|
|
|
# get data object for use later
|
|
my $data = $cf->data;
|
|
|
|
# fix up the member list
|
|
foreach my $uid ( keys %{ $filt->{members} } ) {
|
|
my $member = $filt->{members}->{$uid};
|
|
|
|
# don't need this, we can look it up
|
|
delete $member->{user};
|
|
|
|
# tags are given to us as a hashref, we need to flatten to an array
|
|
$member->{tags} = [ keys %{ $member->{tags} || {} } ];
|
|
|
|
# these may or may not be present, nuke them if they're default
|
|
delete $member->{postertype}
|
|
if $member->{postertype} && $member->{postertype} eq 'any';
|
|
delete $member->{adultcontent}
|
|
if $member->{adultcontent} && $member->{adultcontent} eq 'any';
|
|
delete $member->{tagmode}
|
|
if $member->{tagmode} && $member->{tagmode} eq 'any_of';
|
|
|
|
# now save this in the actual filter
|
|
$data->{$uid} = $member;
|
|
}
|
|
|
|
# see whether we deleted any members from the filter
|
|
foreach my $uid ( keys %{$data} ) {
|
|
|
|
# delete userid from $data if it is not also in $filt->{members}
|
|
delete $data->{$uid} unless exists $filt->{members}->{$uid};
|
|
}
|
|
|
|
# save public and sortorder preferences
|
|
$cf->_getset( 'sortorder', $filt->{sortorder} + 0 )
|
|
unless $filt->{sortorder} == $cf->{sortorder};
|
|
$cf->_getset( 'public', $filt->{public} ? 1 : 0 )
|
|
unless $filt->{public} == $cf->{public};
|
|
|
|
# save the filter, very important...
|
|
$cf->_save;
|
|
}
|
|
|
|
$ret{ok} = 1;
|
|
}
|
|
elsif ( $mode eq "view_filter" ) {
|
|
|
|
# called to get reading page url
|
|
return DW::RPC->alert('No name provided.')
|
|
unless $get->{name} =~ /\S/;
|
|
|
|
$ret{url} = $u->journal_base . "/read/" . $get->{name};
|
|
}
|
|
|
|
return DW::RPC->out(%ret);
|
|
}
|
|
|
|
sub extacct_auth_handler {
|
|
my $r = DW::Request->get;
|
|
my $get = $r->get_args;
|
|
|
|
my $u = LJ::get_remote();
|
|
return DW::RPC->err( LJ::Lang::ml('error.extacct_auth.nouser') )
|
|
unless $u;
|
|
|
|
# get the account
|
|
my $acctid = LJ::ehtml( $get->{acctid} );
|
|
my $account = DW::External::Account->get_external_account( $u, $acctid );
|
|
return DW::RPC->err(
|
|
LJ::Lang::ml(
|
|
'error.extacct_auth.nosuchaccount',
|
|
{
|
|
acctid => $acctid,
|
|
username => $u->username
|
|
}
|
|
)
|
|
) unless $account;
|
|
|
|
# make sure this account supports challenge/response authentication
|
|
return DW::RPC->err(
|
|
LJ::Lang::ml(
|
|
'error.extacct_auth.nochallenge',
|
|
{
|
|
account => LJ::ehtml( $account->displayname )
|
|
}
|
|
)
|
|
) unless $account->supports_challenge;
|
|
|
|
# get the auth challenge
|
|
my $challenge = $account->challenge;
|
|
return DW::RPC->err(
|
|
LJ::Lang::ml(
|
|
'error.extacct_auth.authfailed',
|
|
{
|
|
account => LJ::ehtml( $account->displayname )
|
|
}
|
|
)
|
|
) unless $challenge;
|
|
|
|
return DW::RPC->out( challenge => $challenge, success => 1 );
|
|
}
|
|
|
|
sub general_handler {
|
|
my $r = DW::Request->get;
|
|
my $args = $r->get_args;
|
|
|
|
# make sure we have a user of some sort
|
|
my $remote = LJ::get_remote();
|
|
my $u = LJ::load_user( $args->{user} ) || $remote
|
|
or return DW::RPC->alert('Unable to load user for call.');
|
|
|
|
# in theory, they're passing a mode in the args-> arguments
|
|
my $mode = $args->{mode}
|
|
or return DW::RPC->alert('No mode passed.');
|
|
|
|
my %ret;
|
|
|
|
# gets the list of people that this account subscribes to
|
|
if ( $mode eq 'list_subscriptions' ) {
|
|
$ret{subs} = $u->watch_list;
|
|
|
|
my $uobjs = LJ::load_userids( keys %{ $ret{subs} } );
|
|
foreach my $userid ( keys %$uobjs ) {
|
|
$ret{subs}->{$userid}->{username} = $uobjs->{$userid}->user;
|
|
$ret{subs}->{$userid}->{journaltype} = $uobjs->{$userid}->journaltype;
|
|
}
|
|
|
|
# get the list of someone's tags
|
|
}
|
|
elsif ( $mode eq 'list_tags' ) {
|
|
$ret{tags} = LJ::Tags::get_usertags( $u, { remote => $remote } );
|
|
foreach my $val ( values %{ $ret{tags} } ) {
|
|
delete $val->{security_level};
|
|
delete $val->{security};
|
|
delete $val->{display};
|
|
}
|
|
|
|
# get the list of members of an access filter
|
|
}
|
|
elsif ( $mode eq 'list_filter_members' ) {
|
|
my $filterid = $args->{filterid} + 0;
|
|
$ret{filter_members}->{filterusers} = $u->trust_group_members( id => $filterid );
|
|
$ret{filter_members}->{filtername} = $u->trust_groups( id => $filterid );
|
|
my $uobjs = LJ::load_userids( keys %{ $ret{filter_members}->{filterusers} } );
|
|
foreach my $userid ( keys %$uobjs ) {
|
|
next unless $uobjs->{$userid};
|
|
$ret{filter_members}->{filterusers}->{$userid}->{fancy_username} =
|
|
$uobjs->{$userid}->ljuser_display;
|
|
}
|
|
|
|
# problems
|
|
}
|
|
else {
|
|
return DW::RPC->alert('Unknown mode.');
|
|
|
|
}
|
|
|
|
return DW::RPC->out(%ret);
|
|
}
|
|
|
|
sub addcomment_handler {
|
|
my $remote = LJ::get_remote();
|
|
my $r = DW::Request->get;
|
|
my $post = $r->post_args;
|
|
|
|
return DW::RPC->err( LJ::Lang::ml('error.invalidform.quickerreply') )
|
|
if $r->did_post && !LJ::check_form_auth( $post->{lj_form_auth} );
|
|
|
|
# build the comment
|
|
my $req = {
|
|
ver => 1,
|
|
|
|
username => $remote->username,
|
|
journal => $post->{journal},
|
|
ditemid => $post->{itemid},
|
|
parent => $post->{parenttalkid},
|
|
|
|
body => $post->{body},
|
|
subject => $post->{subject},
|
|
prop_picture_keyword => $post->{prop_picture_keyword},
|
|
prop_editor => $post->{prop_editor},
|
|
|
|
useragent => "rpc-addcomment",
|
|
};
|
|
|
|
# post!
|
|
my $post_error;
|
|
my $result = LJ::Protocol::do_request( "addcomment", $req, \$post_error,
|
|
{ noauth => 1, nocheckcap => 1 } );
|
|
return DW::RPC->err( LJ::Protocol::error_message($post_error) ) if $post_error;
|
|
|
|
# figure out if they posted with a non-default editor
|
|
my $editor = DW::Formats::validate( $post->{prop_editor} );
|
|
my %format_opts = ();
|
|
if ( DW::Formats::is_active($editor) && $editor ne $remote->comment_editor ) {
|
|
%format_opts = (
|
|
extra => DW::Template->template_string(
|
|
'default_editor_form.tt',
|
|
{
|
|
type => 'comment',
|
|
format => $DW::Formats::formats{$editor},
|
|
exit_text => "Return to comment",
|
|
exit_url => $result->{commentlink},
|
|
}
|
|
)
|
|
);
|
|
}
|
|
|
|
# now get the comment count
|
|
my $entry;
|
|
my $uid = LJ::get_userid( $post->{journal} );
|
|
$entry = LJ::Entry->new( $uid, ditemid => $post->{itemid} ) if $uid;
|
|
$entry = undef unless $entry && $entry->valid;
|
|
|
|
my $count;
|
|
$count = $entry->reply_count( force_lookup => 1 ) if $entry;
|
|
|
|
return DW::RPC->out(
|
|
message => LJ::Lang::ml('comment.rpc.posted'),
|
|
count => $count,
|
|
%format_opts
|
|
);
|
|
}
|
|
|
|
1;
|