body<= '/community/manage.bml', 'text' => $ML{'.manage2'}, }); # get remote my $remote = LJ::get_remote(); unless ($remote) { $ret .= ""; return $ret; } my $cname = $GET{'comm'}; return BML::redirect("$LJ::SITEROOT/community/manage.bml") unless $cname; # get $c object my $c = LJ::load_user($cname); unless ($c) { $ret .= ""; return $ret; } my $cid = $c->{'userid'}; # is $remote an admin? unless (LJ::can_manage_other($remote, $c)) { $ret .= " LJ::ljuser($cname, { 'type' => 'C' }) }); $ret .= " p?>"; return $ret; } my @allattribs = ('member', 'post', 'preapprove', 'moderate', 'admin'); my %attrshort = ( X => 'member', P => 'post', N => 'preapprove', M => 'moderate', A => 'admin'); my %attrshort_r = ( map { $attrshort{$_} => $_ } keys %attrshort ); # reversed # saving a form submission if ($POST{'action:update'}) { # validate form auth return "" unless LJ::check_form_auth(); my @userids = split(',', $POST{'ids'}); my @saveattribs = split(',', $POST{'attribs'}); # now we need to create our 'was' list my %was; # ( userid => { attrib => 1; } ) my %users; # ( userid => username ) foreach my $row (split ';', $POST{was}) { # UID:UNAME:MNPX;UID:UNAME:MX;UID:UNAME:AM # if this row matches... if ($row =~ /^(\d+):(\w+):(\w+)$/) { my ($uid, $name, $attrs) = ($1, $2, $3); $uid += 0; next unless $uid && $name && $attrs; # split attrs and setup $was{$uid}->{$attrshort{$_}} = 1 foreach split '', $attrs; $users{$uid} = $name; } } # invite new users my @to_add; my @add_errors; foreach my $num (1..5) { $POST{"add_$num"} = LJ::trim($POST{"add_$num"}); next unless $POST{"add_$num"} =~ /^\w+$/; my $target = LJ::load_user($POST{"add_$num"}); unless ($target) { push @add_errors, BML::ml('.error.nouser', { 'user' => $POST{"add_$num"} }); next; } unless ($target->{statusvis} eq 'V') { push @add_errors, BML::ml('.error.notactive', { 'user' => LJ::ljuser($POST{"add_$num"}) }); next; } my @attr = grep { defined $POST{"add_${num}_$_"} } @saveattribs; unless (@attr) { push @add_errors, BML::ml('.error.noattr', { 'user' => LJ::ljuser($POST{"add_$num"}, { 'type' => $target->{'journaltype'} }) }); next; } unless ($target->{'journaltype'} eq 'P') { push @add_errors, BML::ml('.error.invaliduser', { 'user' => LJ::ljuser($POST{"add_$num"}, { 'type' => $target->{'journaltype'} }) }); next; } if (grep { $target->{'userid'} == $_ } @userids) { push @add_errors, BML::ml('.error.alreadyadded', { 'user' => LJ::ljuser($POST{"add_$num"}, { 'type' => $target->{'journaltype'} }) }); next; } # insert authactions row push @to_add, [ $target, \@attr ]; } return LJ::bad_input(@add_errors) if @add_errors; # now do the additions if any were needed my @fail; my @invited; if (@to_add) { foreach my $row (@to_add) { # good, let's extend an invite to this person my ($target, $attrs) = @$row; if (LJ::send_comm_invite($target, $c, $remote, $attrs)) { push @invited, $row; } else { push @fail, [ $target, LJ::last_error_code() ]; } } } if (@fail) { my @bad; foreach (@fail) { if ($_->[1] eq 'comm_user_has_banned') { push @bad, BML::ml('.error.adding', { user => LJ::ljuser($_->[0], { type => 'P' }) }); } elsif ($_->[1] eq 'comm_invite_limit') { push @bad, BML::ml('.error.limit', { user => LJ::ljuser($_->[0], { type => 'P' }) }); } else { push @bad, BML::ml('.error.unknown', { user => LJ::ljuser($_->[0], { type => 'P' }) }); } } return LJ::bad_input(@bad); } # initialize lists of users to update and delete # keyed on attribute type my %add = (); my %delete = (); foreach (@allattribs) { $add{$_} = {}; $delete{$_} = {}; } # need a db handle now my $dbh = LJ::get_db_writer(); # if we have $other_maints, then there are maintainers not in our # current view, so they will not be modified, so the user can delete # all maintainers from the current view my $in = join(',', map { $dbh->quote($_) } @userids); my $other_maints = $dbh->selectrow_array("SELECT COUNT(*) FROM reluser " . "WHERE userid=? AND type='A' " . "AND targetid NOT IN ($in)", undef, $cid); # users already in community my $maints = 0; my (%addr, %delr); # store additions and removals sorted by userid foreach my $id (@userids) { $id = $id + 0; my $str; foreach (@allattribs) { if ($POST{"edit_${id}_$_"}) { unless ($was{$id}->{$_}) { $add{$_}->{$id} = 1; $addr{$id}->{$_} = 1; } } else { if ($was{$id}->{$_}) { $delete{$_}->{$id} = 1; $delr{$id}->{$_} = 1; } } } $maints++ if $POST{"edit_${id}_admin"}; } # can't remove ALL maintainers, give them an error so they can # go back and decide who to keep if (! $other_maints && $maints < 1) { $ret .= " 'C' }) . ", must have at least one maintainer. " . "Please " . "go back and add a maintainer. p?>"; return $ret; } # delete members if (%{$delete{'member'}}) { # TAG:FR:bml_comm_members:del_members LJ::remove_friend($cid, [ keys %{$delete{'member'}} ]); } # log maintainer deletions foreach my $uid (keys %{$delete{admin} || {}}) { $c->log_event('maintainer_remove', { actiontarget => $uid, remote => $remote }); } # delete other rel edges LJ::clear_rel_multi( (map { [$cid, $_, 'A'] } keys %{$delete{admin} || {}}), (map { [$cid, $_, 'P'] } keys %{$delete{post} || {}}), (map { [$cid, $_, 'M'] } keys %{$delete{moderate} || {}}), (map { [$cid, $_, 'N'] } keys %{$delete{preapprove} || {}}), ); # perform additions my @msgs; if (%{$add{'member'}}) { foreach my $id (keys %{$add{'member'}}) { next if $was{$id}->{'member'}; my $u = LJ::load_userid($id); if (LJ::u_equals($u, $remote)) { # you're allowed to add yourself as member LJ::join_community($remote, $c); } else { if (LJ::send_comm_invite($u, $c, $remote, [ 'member' ])) { # if it succeeded, push the reinvited information push @msgs, BML::ml('.reinvited2', { user => LJ::ljuser($u, { type => 'P' }), aopts => "href='$LJ::SITEROOT/manage/invites.bml'" }); } } } } # log maintainer additions foreach my $uid (keys %{$add{admin} || {}}) { $c->log_event('maintainer_add', { actiontarget => $uid, remote => $remote }); } # set rels in db/memcache LJ::set_rel_multi( (map { [$cid, $_, 'A'] } keys %{$add{admin} || {}}), (map { [$cid, $_, 'P'] } keys %{$add{post} || {}}), (map { [$cid, $_, 'M'] } keys %{$add{moderate} || {}}), (map { [$cid, $_, 'N'] } keys %{$add{preapprove} || {}}), ); # create some other messages my %done; # keep track of who we've done foreach my $id (keys %addr, keys %delr) { next if $done{$id}++; my ($str, @astr, @dstr); push @astr, $ML{"/manage/invites.bml.label.$_"} foreach keys %{$addr{$id} || {}}; push @dstr, $ML{"/manage/invites.bml.label.$_"} foreach keys %{$delr{$id} || {}}; $str .= "
  • " . BML::ml('.success.added', { list => join(', ', @astr) }) . "
  • \n" if @astr; $str .= "
  • " . BML::ml('.success.deleted', { list => join(', ', @dstr) }) . "
  • \n" if @dstr; push @msgs, LJ::ljuser($users{$id}, { type => 'P' }) . ":" if $str; } $ret .= ""; if (@msgs) { $ret .= "\n"; } if (@invited) { $ret .= " "href='$LJ::SITEROOT/manage/invites.bml'" }); $ret .= " p?>"; } $ret .= "" unless @msgs || @invited; $ret .= " BML::get_uri() . "?comm=$cname" }) . " p?>"; return $ret; } # browsing mode # now get lists of: members, admins, able to post, moderators my %users = (); # need a dbr now my $dbr = LJ::get_db_reader(); # get community members # TAG:FR:bml_comm_members:get_members my $sth = $dbr->prepare("SELECT u.userid, u.user FROM useridmap u, friends f " . "WHERE u.userid=f.friendid AND f.userid=?"); $sth->execute($cid); while (my ($id, $user) = $sth->fetchrow_array) { $users{$id}->{'userid'} = $id; $users{$id}->{'name'} = $user; $users{$id}->{'member'} = 1; } my $sth = $dbr->prepare("SELECT r.targetid, r.type, u.user FROM reluser r, useridmap u " . "WHERE r.targetid = u.userid AND r.userid=? AND r.type IN ('A','P','M','N')"); $sth->execute($cid); my %count; while (my ($id, $type, $user) = $sth->fetchrow_array) { $users{$id}->{'userid'} = $id; $users{$id}->{'name'} = $user; my $key = {'A'=>'admin','P'=>'post','M'=>'moderate','N'=>'preapprove'}->{$type}; $users{$id}->{$key} = 1; $count{$type}++; } # columns of our table, excluding username my @attribs = ('member', 'post'); LJ::load_user_props($c, 'moderated'); push @attribs, ('preapprove') if $c->{'moderated'} || $count{'N'}; push @attribs, ('moderate') if $c->{'moderated'} || $count{'M'}; push @attribs, 'admin'; # sorting method; my $method = $GET{'sort'}; my $cmp = sub {$a->{'name'} cmp $b->{'name'}}; $cmp = sub {$b->{'member'} <=> $a->{'member'}} if $method eq 'member'; $cmp = sub {$b->{'admin'} <=> $a->{'admin'}} if $method eq 'admin'; $cmp = sub {$b->{'post'} <=> $a->{'post'}} if $method eq 'post'; $cmp = sub {$b->{'moderate'} <=> $a->{'moderate'}} if $method eq 'moderate'; $cmp = sub {$b->{'preapprove'} <=> $a->{'preapprove'}} if $method eq 'preapprove'; my @users = sort $cmp values %users; my $page_size = 100; # change to adjust page size # are we going to jump to a specific user ? my $jumppage; my $jumpuser; if (@users > $page_size && $POST{'jumpto'} =~ /^\w+$/) { my $ct; foreach (@users) { $jumppage++ if $ct % $page_size == 0; if ($POST{'jumpto'} eq $_->{'name'}) { $jumpuser = $_->{'name'}; last; } $ct++; } undef $jumppage unless $jumpuser; } # how to make links back to this page my $self_link = sub { my $sort = "&sort=$GET{'sort'}" if $GET{'sort'}; return "members.bml?comm=$cname&page=$_[0]$sort"; }; my %items = BML::paging(\@users, $jumppage || $GET{'page'}, $page_size); my $navbar = LJ::paging_bar($items{'page'}, $items{'pages'}, { 'self_link' => $self_link }); @users = @{$items{'items'}}; # output starts here $ret .= " LJ::ljuser($cname, { 'type' => 'C' }) }); $ret .= " " . BML::ml('.settings', { 'link' => "settings.bml?comm=$cname"}) . " p?>"; $ret .= "
    "; $ret .= LJ::form_auth(); # jump to user if ($items{'pages'} > 1) { $ret .= "
    Jump to user: "; $ret .= LJ::html_text({ 'name' => 'jumpto', 'value' => $POST{'jumpto'}, 'size' => '10', 'maxlength' => '15' }) . " "; $ret .= LJ::html_submit(undef, 'Go') . "
    "; $ret .= $navbar; } my $sortlink = BML::get_uri() . "?comm=$cname&sort="; $ret .= "
    \n" . ""; $ret .= "" for (@attribs); $ret .= "\n"; # rows for existing users my $rc = 0; my @wstrs; foreach(@users) { my $rstyle = ($rc++ & 1) ? "" : ""; $ret .= ""; my $wstr; foreach my $key (@attribs) { $ret .= ""; } push @wstrs, "$_->{userid}:$_->{name}:$wstr" if $wstr; $ret .= "\n"; } # if on the last page, let users add to the list if ($items{'page'} == $items{'pages'}) { foreach(1..5) { my $rstyle = ($rc++ & 1) ? "" : ""; $ret .= ""; foreach my $key (@attribs) { $ret .= ""; } $ret .= "\n"; } } # some hidden values $ret .= "
    $ML{'.key.user'}".$ML{".key.$_"}."
    " . LJ::ljuser($_->{'name'}) . ""; $ret .= LJ::html_check({ 'name' => "edit_$_->{'userid'}_$key", 'selected' => $_->{$key} }); $wstr .= $attrshort_r{$key} if $_->{$key}; $ret .= "
    "; $ret .= LJ::html_text({ 'name' => "add_$_", 'size' => '10', 'maxlength' => '15' }) . ""; if ($key eq 'member' || $key eq 'post') { $ret .= LJ::html_check({ name => "add_${_}_$key", selected => 1, }); } else { $ret .= LJ::html_check({ name => "add_${_}_$key" }); } $ret .= "
    "; $ret .= LJ::html_hidden('ids', join(',', map { $_->{'userid'}} @users), 'attribs', join(',', @attribs), 'was', join(';', @wstrs)) . "\n"; $ret .= "

    " . LJ::html_submit('action:update', $ML{'.update'}) . "

    \n"; $ret .= "
    \n\n"; $ret .= $navbar; return $ret; } _code?> <=body page?>