ljr/local/htdocs/modify.bml

494 lines
20 KiB
Plaintext
Executable File

<?page
title=><?_ml .title _ml?>
head<=
<?_code return $LJ::COMMON_CODE{'autoradio_check'}; _code?>
<style>
option.disabled { color: GrayText; }
</style>
<=head
body<=
<?_code
{
# this file used to be modify_do.bml, but modify.bml died, so we moved this
# functionality to modify.bml, but we don't want the translators to have to
# retranslate all of the phrases, so we're still using /modify_do.bml scope
BML::set_language_scope("/modify_do.bml");
use strict;
use vars qw(%GET %POST);
return LJ::server_down_html() if $LJ::SERVER_DOWN;
LJ::set_active_crumb('modify');
my $remote = LJ::get_remote();
return LJ::bad_input("You must be logged in to modify your journal")
unless $remote;
my $authas = $GET{'authas'} || $remote->{'user'};
my $u = LJ::get_authas_user($authas);
return LJ::bad_input("You could not be authenticated as the specified user.")
unless $u;
return $LJ::MSG_READONLY_USER if LJ::get_cap($remote, "readonly");
### user is now authenticated ###
my $dbr = LJ::get_db_reader();
my $sth;
my $capstyles = LJ::get_cap($u, "styles");
LJ::load_user_props($u, "opt_usesharedpic",
"s1_lastn_style", "s1_calendar_style",
"s1_day_style", "s1_friends_style",
"stylesys", "journaldomain");
# if a POST, update their info
if (LJ::did_post()) {
return "<?badinput?>" unless LJ::text_in(\%POST);
# database error reporting
my $dberr = sub {
return "<?h1 $ML{'Error'} h1?><?p $ML{'error.dberror'} <b>@_[0]</b> p?>";
};
my $dbh = LJ::get_db_writer();
# setup what we're gonna update in the user table:
my %update = ();
# what userprops we'll be setting.
my %uprop;
# journal domains
my $dom_cap = LJ::get_cap($u, 'userdomain');
if ((exists $POST{'journaldomain'} && $u->{'journaldomain'} ne $POST{'journaldomain'}) ||
(! $dom_cap && $POST{'journaldomain_del'}))
{
$POST{'journaldomain'} =~ s!^(http://)?(www\.)?!!;
my $dom = lc($POST{'journaldomain'});
if (($dom_cap && ! $dom) || (! $dom_cap && $POST{'journaldomain_del'})) {
$dbh->do("DELETE FROM domains WHERE userid=?", undef, $u->{'userid'});
} else {
$dbh->do("INSERT INTO domains VALUES (?, ?)", undef, $dom, $u->{'userid'});
if ($dbh->err) {
my $otherid = $dbh->selectrow_array("SELECT userid FROM domains WHERE domain=?",
undef, $dom);
return LJ::bad_input($ML{'.error.dupdomainalias'}) if $otherid != $u->{'userid'};
}
if ($u->{'journaldomain'}) {
$dbh->do("DELETE FROM domains WHERE userid=? AND domain <> ?",
undef, $u->{'userid'}, $dom);
}
}
# set journaldomain prop if it's been changed
$uprop{'journaldomain'} = $dom
unless $POST{'journaldomain'} eq $u->{'journaldomain'};
}
# validate moodthemeid
# mood theme, make sure they're allowed to use it
my $moodthemeid = $POST{'moodthemeid'}+0;
if ($moodthemeid) {
my ($mownerid, $mpublic) = $dbr->selectrow_array("SELECT ownerid, is_public FROM moodthemes ".
"WHERE moodthemeid=?", undef, $moodthemeid);
$moodthemeid = 0 unless $mpublic eq 'Y' || $mownerid == $u->{'userid'};
}
$update{'moodthemeid'} = $moodthemeid;
$update{'opt_forcemoodtheme'} = $POST{'opt_forcemoodtheme'} ? "Y" : "N";
# all of these options should only be processed for S1 users
if ($u->{'stylesys'} != 2) {
# color themes
$update{'themeid'} = $POST{'themetype'} eq "custom" ? 0 : $POST{'themeid'};
if ($POST{'themetype'} eq "custom") {
my $dig = Digest::MD5::md5_hex(join(",", map { $POST{"theme_cust:$_"} }
map { $_->[0] } @LJ::S1::themecoltypes));
if ($dig ne $POST{'themecolors_dig'}) {
my %cols;
foreach my $col (@LJ::S1::themecoltypes) {
my $val = $POST{"theme_cust:$col->[0]"};
next if length($val) > 20;
next unless ($val =~ /^\#[a-f0-9]{6,6}$/i ||
$val !~ /[^\s\w]/);
$cols{$col->[0]} = $val;
}
return $ML{"error.nodb"} unless $u->writer;
$u->do("INSERT IGNORE INTO s1usercache (userid) VALUES (?)", undef, $u->{'userid'});
$u->do("UPDATE s1usercache SET color_stor=? WHERE userid=?", undef,
Storable::nfreeze(\%cols), $u->{'userid'});
LJ::MemCache::delete([$u->{'userid'}, "s1uc:$u->{'userid'}"]);
$dbh->do("DELETE FROM themecustom WHERE user=?", undef, $u->{'user'})
if $dbh->selectrow_array("SELECT user FROM themecustom ".
"WHERE user=? LIMIT 1", undef, $u->{'user'});
}
}
# update 'overrides' table
if ($POST{'overrides'} !~ /\S/) {
LJ::S1::clear_overrides($u);
$update{'useoverrides'} = "N";
} else {
my $oldoverrides = "";
if ($u->{'useoverrides'} eq "Y") {
$oldoverrides = LJ::S1::get_overrides($u);
}
# This allows users to keep their current illegal overrides,
# but they may not create new ones nor edit the ones they already have.
# They may only delete or keep illegal overrides.
my %overrides = ();
my %newoverrides = ();
LJ::parse_vars(\$oldoverrides,\%overrides);
LJ::parse_vars(\$POST{'overrides'},\%newoverrides);
# head overrides should only have valid head elements in them
foreach my $a (qw(GLOBAL LASTN FRIENDS CALENDAR DAY)) {
my $sec = "${a}_HEAD";
next unless $newoverrides{$sec} ne $overrides{$sec};
my $testtag = sub {
my $tag = lc(shift);
return "<$tag" if ($tag eq "title" || $tag eq "base" ||
$tag eq "style" || $tag eq "link" ||
$tag eq "meta" || $tag eq "xx");
return "<xx-$tag";
};
$newoverrides{$sec} =~ s/\<(\w+)/$testtag->($1)/eig;
$newoverrides{$sec} =~ s/\<\/head/\<\/xx-head/ig;
}
# load all the properties to see which ones are overridable
my @vars;
LJ::load_objects_from_file("vars.dat", \@vars);
foreach my $v (@vars) {
my $ov = $v->{'props'}->{'override'};
if ($ov eq "yes" || $ov eq "only" || $capstyles) {
my $name = $v->{'name'};
if (defined $newoverrides{$name}) {
$overrides{$name} = $newoverrides{$name};
}
}
}
# make the new override code we'll put in the database
my $overr='';
foreach (keys %overrides) {
if ($newoverrides{$_}) {
if ($overrides{$_} =~ /\n/) {
$overr .= "$_<=\n".$overrides{$_}."\n<=$_\n\n";
} else {
$overr .= "$_=>".$overrides{$_}."\n\n";
}
}
}
# no value, delete overrides
if ($overr !~ /\S/) {
LJ::S1::clear_overrides($u);
$update{'useoverrides'} = "N";
# have a value, update overrides
} else {
LJ::S1::save_overrides($u, $overr);
$update{'useoverrides'} = "Y";
}
}
# friends view shared pic option for s1
$uprop{'opt_usesharedpic'} = $POST{'opt_usesharedpic'} ? "1" : "0";
# set all the styles
{
my @picked = ();
foreach my $view (@LJ::views) {
my $sid = $POST{"s1_${view}_style"}+0;
if ($sid) {
$uprop{"s1_${view}_style"} = $sid;
push @picked, $sid;
}
}
# verify they haven't forged the style numbers
unless ($capstyles) {
# just load whole structure since it should be cached
my $pubstyles = LJ::S1::get_public_styles();
my $userstyles = LJ::S1::get_user_styles($u);
foreach (@picked) {
my $type = $userstyles->{$_}->{'type'};
return LJ::bad_input($ML{'.error.stylenotavailable'})
unless exists $pubstyles->{$_} ||
exists $userstyles->{$_} &&
($capstyles || $_ == $u->{"s1_${type}_style"});
}
}
}
}
# update 'user' table
foreach (keys %update) {
delete $update{$_} if $u->{$_} eq $update{$_};
}
LJ::update_user($u, \%update) if %update;
# change any of the userprops ?
foreach my $uprop (keys %uprop) {
next if $POST{$uprop} eq $u->{$uprop};
LJ::set_userprop($u, $uprop, $uprop{$uprop});
}
# tell the user all is well
return "<?h1 $ML{'.success.head'} h1?><?p ".BML::ml(".success.text", {'url' => LJ::journal_base($u) . "/" })." p?>";
}
# not submitting a post, show edit form
my $ret;
# user switcher
$ret .= "<form action='modify.bml' method='get'>\n";
$ret .= LJ::make_authas_select($remote, { 'authas' => $GET{'authas'} });
$ret .= "</form>\n\n";
### journal style
$ret .= "<?h1 $ML{'.journaloptions.head'} h1?>\n<?p $ML{'.journaloptions.about'} p?>\n\n";
###
### LAYOUT OPTIONS
###
$ret .= "<form method='post' action='modify.bml?authas=$authas'>\n";
# using S1, need to take style input
if ($u->{'stylesys'} != 2)
{
my $and = $capstyles ? "" : $ML{'.pagelayoutstyle.warning'};
$ret .= "<?h2 $ML{'.pagelayoutstyle.head'} h2?><?p $ML{'.pagelayoutstyle.about'} $and p?>\n";
$ret .= "<table style='margin-left: 30px; margin-bottom: 20px;'>\n";
$ret .= "<tr bgcolor='#d0d0d0'><td></td><td>$ML{'.availablestyles.head'}</td></tr>\n";
my $pubstyles = LJ::S1::get_public_styles();
my %pubstyles = ();
foreach (sort { $a->{'styledes'} cmp $b->{'styledes'} } values %$pubstyles) {
push @{$pubstyles{$_->{'type'}}}, $_;
}
my $userstyles = LJ::S1::get_user_styles($u);
my %userstyles = ();
foreach (sort { $a->{'styledes'} cmp $b->{'styledes'} } values %$userstyles) {
push @{$userstyles{$_->{'type'}}}, $_;
}
foreach my $view (@LJ::views) {
$ret .= "<tr><td bgcolor='#d0d0d0'>$LJ::viewinfo{$view}->{'des'}</td><td>";
my @list = map { $_->{'styleid'}, $_->{'styledes'} }
@{$pubstyles{$view} || []};
if (@{$userstyles{$view} || []}) {
my @user_list = map { $_->{'styleid'}, $_->{'styledes'} }
grep { $capstyles || $u->{"s1_${view}_style"} == $_->{'styleid'} }
@{$userstyles{$view} || []};
push @list, { value => "",
text => "--- $ML{'.availablestyles.userstyles'} ---",
disabled => 1 }, @user_list
if @user_list;
my @disabled_list =
map { { value => $_->{'styleid'},
text => $_->{'styledes'},
disabled => 1 } }
grep { ! $capstyles && $u->{"s1_${view}_style"} != $_->{'styleid'} }
@{$userstyles{$view} || []};
push @list, { value => '',
text => "--- $ML{'.availablestyles.disabledstyles'} ---",
disabled => 1 }, @disabled_list
if @disabled_list;
}
$ret .= LJ::html_select({ 'name' => "s1_${view}_style",
'selected' => $u->{"s1_${view}_style"} }, @list);
$ret .= "</td></tr>\n";
}
$ret .= "</table>\n\n";
###
### COLOR THEME OPTIONS
###
$ret .= "<?h2 $ML{'.colortheme.head'} h2?><?p $ML{'.colortheme.about'} p?>\n";
$ret .= "<div style='margin-left: 30px; margin-bottom: 20px;'>\n";
$ret .= LJ::html_check({ 'type' => 'radio', 'name' => 'themetype',
'value' => 'default', 'selected' => $u->{'themeid'} > 0 });
$ret .= "<b>$ML{'.colortheme.defaulttheme'}</b>: ";
my @list;
$sth = $dbr->prepare("SELECT themeid, name FROM themelist ORDER BY name");
$sth->execute;
while ($_ = $sth->fetchrow_hashref) {
push @list, ($_->{'themeid'}, $_->{'name'});
}
$ret .= LJ::html_select({ 'name' => 'themeid', 'selected' => $u->{'themeid'} }, @list) . "<br />\n";
$ret .= LJ::html_check({ 'type' => 'radio', 'name' => 'themetype', 'id' => 'themetype:custom',
'value' => 'custom', 'selected' => $u->{'themeid'} == 0 }) . "\n";
$ret .= "<b>$ML{'.colortheme.customcolors'}</b>:";
$ret .= "<table border='1' align='center' cellpadding='2'>\n";
$ret .= "<tr valign='top' bgcolor='#d0d0d0'><td align='right'><b>$ML{'.colortheme.area.head'}</b></td><td><b>$ML{'.colortheme.color.head1'}</b><br /><font size='-1'>$ML{'.colortheme.color.head2'}</font></td></tr>\n";
# get the user's custom colors
my %custcolors = ();
if ($u->{'themeid'} == 0) {
my $dbcr = LJ::get_cluster_reader($u);
my $stor = $dbcr->selectrow_array("SELECT color_stor FROM s1usercache WHERE userid=?",
undef, $u->{'userid'});
if ($stor) {
%custcolors = %{ Storable::thaw($stor) };
} else {
# ancient table.
$sth = $dbr->prepare("SELECT coltype, color FROM themecustom WHERE user=?");
$sth->execute($u->{'user'});
$custcolors{$_->{'coltype'}} = $_->{'color'} while $_ = $sth->fetchrow_hashref;
}
} else {
$sth = $dbr->prepare("SELECT coltype, color FROM themedata WHERE themeid=?");
$sth->execute($u->{'themeid'});
$custcolors{$_->{'coltype'}} = $_->{'color'} while $_ = $sth->fetchrow_hashref;
}
my $dig;
foreach my $col (@LJ::S1::themecoltypes) {
$ret .= "<tr><td align='right'>$col->[1]</td><td>";
$ret .= LJ::html_text({ 'name' => "theme_cust:$col->[0]", 'size' => '20',
'maxlength' => '30', 'value' => $custcolors{$col->[0]},
'onchange' => "checkRadioButton('themetype:custom');" });
$ret .= "</td></tr>\n";
$dig .= $col->[0];
}
$dig = Digest::MD5::md5_hex($dig);
$ret .= LJ::html_hidden("themecolors_dig", $dig) unless $u->{'themeid'};
$ret .= "</table></div>\n\n";
###
### FRIENDS VIEW OPTIONS
###
$ret .= "<?h2 $ML{'.friends.head'} h2?><?p $ML{'.friends.about'} p?>";
$ret .= "<table style='margin-left: 30px; margin-bottom: 20px;' cellspacing='0'>\n";
$ret .= "<tr valign='middle'><td>";
$ret .= LJ::html_check({ 'type' => 'check', 'name' => 'opt_usesharedpic', 'selected' => $u->{'opt_usesharedpic'} });
$ret .= "</td><td><b>$ML{'.friends.opt.usesharedpic.head'}</b></td></tr>\n";
$ret .= "<tr><td>&nbsp;</td><td>$ML{'.friends.opt.usesharedpic.about'}</td></tr>\n";
$ret .= "</table>\n\n";
###
### STYLE OVERRIDES
###
# first, load the overrides if they use 'em:
my $overrides = "";
if ($u->{'useoverrides'} eq "Y") {
$overrides = LJ::S1::get_overrides($u);
LJ::text_out(\$overrides);
}
$ret .= "<div style='margin-bottom: 20px'>\n";
$ret .= "<?h1 $ML{'.overrides.head'} h1?><?p $ML{'.overrides.about'} p?>\n";
$ret .= "<?p <font size='+1'><b>$ML{'.overrides.warning'}</b></font> p?>\n";
$ret .= "<?p $ML{'.overrides.note'} p?>\n";
$ret .= "<?standout <b>$ML{'.overrides.box.head'}</b><br />";
$ret .= LJ::html_textarea({ 'name' => 'overrides', 'cols' => '60', 'rows' => '15',
'wrap' => 'off', 'value' => $overrides }) . " standout?>";
$ret .= "</div>\n\n";
}
###
### MOOD THEME OPTIONS
###
$ret .= "<?h2 $ML{'.moodicons.head'} h2?><?p $ML{'.moodicons.about'} p?>\n";
$sth = $dbr->prepare("SELECT moodthemeid, name FROM moodthemes WHERE is_public='Y'");
$sth->execute;
my @themes = ({ 'moodthemeid' => 0, 'name' => '(None)' });
push @themes, $_ while ($_ = $sth->fetchrow_hashref);
### user's private themes
{
my @theme_user;
$sth = $dbr->prepare("SELECT moodthemeid, name FROM moodthemes WHERE ownerid=? AND is_public='N'");
$sth->execute($u->{'userid'});
push @theme_user, $_ while ($_ = $sth->fetchrow_hashref);
if (@theme_user) {
push @themes, { 'moodthemeid' => 0, 'name' => "--- $ML{'.moodicons.personal'} ---" };
push @themes, @theme_user;
}
}
$ret .= "<div style='margin-left: 30px; margin-bottom: 20px;'><b>$ML{'.moodicons.select'} </b>\n";
$ret .= LJ::html_select({ 'name' => 'moodthemeid', 'selected' => $u->{'moodthemeid'} },
map { $_->{'moodthemeid'}, $_->{'name'} } @themes) . "\n";
$ret .= "(<a href='$LJ::SITEROOT/moodlist.bml' target='moods'>$ML{'.moodicons.preview'}</a>)\n";
$ret .= "<br />" . LJ::html_check({ 'type' => 'check', 'name' => 'opt_forcemoodtheme',
'id' => 'opt_forcemoodtheme',
'selected' => $u->{'opt_forcemoodtheme'} eq 'Y' }) . "\n";
$ret .= "<label for='opt_forcemoodtheme'>$ML{'.moodicons.opt.forcefriends.about'}</label></div>\n\n";
###
### JOURNAL DOMAIN OPTIONS
###
my $has_cap = LJ::get_cap($u, 'userdomain');
my $has_dom = $u->{journaldomain} ? 1 : 0;
if ($LJ::OTHER_VHOSTS && ($has_cap || $has_dom)) {
$ret .= "<?h2 $ML{'.domainalias.head'} h2?><?p $ML{'.domainalias.about'} p?>\n";
$ret .= "<div style='margin: 20px 0 20px 30px'>";
$ret .= "<table><tr><td align='left'><b>$ML{'.domainalias.domainname'}</b></td><td>";
$ret .= LJ::html_text({ 'name' => 'journaldomain', 'size' => '30',
'maxlength' => '80', 'value' => $u->{'journaldomain'},
'disabled' => ! $has_cap });
$ret .= LJ::html_submit('journaldomain_del' => "Remove") unless $has_cap;
$ret .= "</td></tr>";
$ret .= "<tr><td>&nbsp;</td><td>$ML{'.domainalias.example'}</td></tr></table>";
$ret .= "<?p " . BML::ml(".domainalias.helptext", {'sitename' => $LJ::SITENAME})." p?></div>\n\n";
}
### ending submit block
$ret .= "<?h1 $ML{'.done.head'} h1?><?p $ML{'.done.text'} p?>\n";
$ret .= "<?standout " . LJ::html_submit(undef, $ML{'.done.btn.savechanges'}) . " standout?>\n";
$ret .= "</form>\n";
return $ret;
}
_code?>
<=body
page?><?_c <LJDEP>
link: htdocs/moodlist.bml, htdocs/developer/index.bml, htdocs/developer/varlist.bml, htdocs/styles/create.bml
post: htdocs/modify_do.bml
</LJDEP> _c?>