This commit is contained in:
2019-02-06 00:49:12 +03:00
commit 8dbb1bb605
4796 changed files with 506072 additions and 0 deletions

View File

@@ -0,0 +1,614 @@
<?page
title=>Email gateway settings
head<=
<style type="text/css">
fieldset
{
border: 1px solid #cdcdcd;
margin-bottom: 15px;
}
legend
{
padding: 2px 10px 2px 10px;
border: 1px solid #cdcdcd;
font-size: 14px;
font-weight: bold;
}
.settings td
{
padding: 3px;
}
</style>
<=head
body<=
<?_code
{
use strict;
use vars qw(%POST %GET);
LJ::set_active_crumb('emailgateway');
return "Sorry, this site is not configured to allow updating your
journal via email." unless $LJ::EMAIL_POST_DOMAIN;
return LJ::server_down_html() if $LJ::SERVER_DOWN;
my $u = LJ::get_remote();
return $LJ::MSG_READONLY_USER if LJ::get_cap($u, "readonly");
my @props =
qw/
emailpost_pin emailpost_allowfrom
emailpost_userpic emailpost_security
emailpost_comments emailpost_gallery
emailpost_imgsecurity emailpost_imgsize
emailpost_imglayout emailpost_imgcut
/;
my ($mode, $type) = ($GET{mode}, $GET{type});
if ($u) {
LJ::load_user_props( $u, @props );
} else {
$mode = 'help';
}
#--------------------------------------------------------------------------
# Help text
if ($mode eq 'help') {
my $ret;
my $user = $u ? $u->{user} : 'exampleusername';
my $need_login = (! $u && ! $GET{mode}) ? 1 : 0;
my @address = split(/\s*,\s*/, $u->{emailpost_allowfrom});
my $addr = $address[0] || 'allowed_sender@example.com';
$addr =~ s/\(\w\)$//;
my $pin = $u->{emailpost_pin} || 'PIN';
my $to = "To: $user" . '@' . $LJ::EMAIL_POST_DOMAIN . '<br />';
my $to_pin = "To: $user+$pin" . '@' . $LJ::EMAIL_POST_DOMAIN . '<br />';
my $subject = "Subject: Neat, I can post via email." . '<br /><br />';
my $from = "From: $addr <br />";
my $body = "This is the body of my post.";
if ($need_login) {
$ret .= '<?h1 Please log in! h1?>';
$ret .= "<?p $ML{'error.noremote'} p?>";
}
my @topics = (
{
name => 'pin',
title => 'Pin usage examples',
url => '?mode=help&type=pin',
text => qq{
<?h1 PIN usage examples h1?><br />
<fieldset><legend>PIN in email address</legend>
<?emailex
To: $user<b>+$pin</b>\@$LJ::EMAIL_POST_DOMAIN<br />
$from
$subject
$body
emailex?></fieldset>
<fieldset><legend>PIN in subject</legend>
<?emailex
$to
$from
Subject: <b>+$pin</b> Post subject <br /><br />
$body
emailex?></fieldset>
<fieldset><legend>PIN in body</legend>
<?emailex
$to
$from
$subject
<b>+$pin</b> $body
emailex?></fieldset>
}
},
{
name => 'optional',
title => 'Optional features',
url => '?mode=help&type=optional',
text => qq{
<?h1 Optional features h1?><br />
<fieldset><legend>Posting to a community</legend>
<?p Simply embed the community name in the email address. p?>
<?emailex
To: $user.<b>community</b>+$pin\@$LJ::EMAIL_POST_DOMAIN<br />
$from
$subject
$body
emailex?></fieldset>
<fieldset><legend>Removing unwanted text</legend>
<?p All text below two or more dashes or underscores ("--" or "__")
on a line by itself will be automatically removed.
The red text below won't show up in your posting. p?>
<?emailex
$to_pin
$from
$subject
$body
<br />--<br />
<font color='red'>
This text and anything underneath it will be ignored,
including automatic signatures added by free email services.<br />
__________________________________________________<br />
Try the all new SUPER FREE MAIL version 17 today!!!<br />
</font>emailex?></fieldset>
<fieldset><legend>Hyphens and underscores</legend>
<?p To compensate for mobile phones that don't have an underscore key,
you may substitute a hyphen in their place inside any user or
community account name. The hyphens will be automatically converted
to underscores. p?>
<?emailex
To: <b>some-user.some-community</b>+$pin</b>\@$LJ::EMAIL_POST_DOMAIN<br />
$from
$subject
$body
emailex?></fieldset>
}
},
{
name => 'headers',
title => 'LJ headers and security',
url => '?mode=help&type=headers',
text => qq{
<?h1 LJ headers h1?><br />
<fieldset><legend>Journal entry options</legend>
<?p Most journal specific features can be set via "lj-headers" in the
body of your message. The lj-headers should be at the top of your message,
separated by a newline. All lj-headers are completely optional, and simply
override your journal defaults. p?>
<?emailex
$to_pin
$from
$subject
<b>lj-userpic:</b> pict keywords<br />
<b>lj-tags:</b> greyhounds, potato, wool<br />
<b>lj-mood:</b> happy<br />
<b>lj-music:</b> The Pixies: Where is my mind?<br />
<b>lj-comments:</b> ("off" or "noemail")<br />
<br />
$body
emailex?></fieldset>
<fieldset><legend>Journal entry security</legend>
<?p Security options are set via the lj-header "lj-security".
If the security type specified is unknown, the journal entry defaults
to private. If no security is specified, the entry is posted according
to your default journal security. p?>
<div style="margin-left:40px">
<b>lj-security:</b> public<br />
<div style="margin-left:40px">The post is posted publicly.</div><br />
</div>
<div style="margin-left:40px">
<b>lj-security:</b> private<br />
<div style="margin-left:40px">The post is posted privately.</div><br />
</div>
<div style="margin-left:40px">
<b>lj-security:</b> friends<br />
<div style="margin-left:40px">The post can only be viewed by those on your friends list.</div><br />
</div>
<div style="margin-left:40px">
<b>lj-security:</b> friendgroup<br />
<div style="margin-left:40px">This is literally the name of a friend group.
Only friends belonging to that group can view the post.
<br />Example: lj-security: <b>my friends</b></div><br />
</div></fieldset>
}
},
{
name => 'advanced',
title => 'Advanced usage',
url => '?mode=help&type=advanced',
text => qq{
<?h1 Advanced usage h1?><br />
<a name="pgp"></a>
<fieldset><legend>PGP/GPG message signing <img src="/img/key.gif" width="16" height="16"></legend>
<?p If you specify "<b>PGP</b>" instead of your PIN,
allowed sender addresses and the saved PIN are completely ignored.
Your email will only be posted if it is signed with a valid PGP/GPG private key. p?>
<?p You must first upload your public key <a href="/manage/pubkey.bml">here</a>. p?>
<?emailex
To: $user<b>+PGP</b>\@$LJ::EMAIL_POST_DOMAIN<br />
From: anywhere\@example.com <br />
$subject
$body
<br />This body should be properly signed with my private key.
emailex?></fieldset>
}
},
);
if ($LJ::FB_SITEROOT && %LJ::FOTOBILDER_IP && ! $LJ::DISABLED{fb_email_docs}) {
$subject = "Subject: Neat, I can post pictures via email.<br /><br />";
$body = "This is the body of my post, with image attachments.";
splice @topics, -1, 0,
{
name => 'images',
title => 'Image attachments',
url => '?mode=help&type=images',
subject =>
body =>
text => qq{
<?h1 Attaching images h1?><br />
<?p
If you have Photo Hosting access (and enough disk quota),
any image you attach to your email message will be
automatically uploaded to your
<a href='$LJ::FB_SITEROOT'>$LJ::FB_DOMAIN</a> account
and displayed in your journal entry.
All images are displayed under a <a
href='/support/faqbrowse.bml?faqid=75'>lj-cut</a>.
Using <a href='?mode=help&type=headers'>lj-headers</a>,
You can change the way the images look in your journal,
as well as set various image attributes.
p?><br />
<fieldset><legend>Choosing a gallery</legend>
<?p You can specify what photo gallery you want your
attachments uploaded into using the <b>lj-gallery</b> header.
If unspecified, the default gallery is 'LJ_emailpost'. If
you decide to move your images into different galleries in
the future, the images posted in your journal will still
work correctly. p?>
<?emailex
$to_pin
$from
$subject
<b>lj-gallery:</b> vacation photos<br />
<br />
$body
emailex?></fieldset>
<fieldset><legend>Image security</legend>
<?p Images are publicly viewable by default. Use the
<b>lj-imgsecurity</b> header to change this behavior.
Please note that image security is separate from your
journal entry security! For example, you can have a
journal entry that is private, while the pictures within
it are public. This feature only changes the security
on the images themselves - not the journal entry. p?>
<p? Valid options are "private", "regusers", or "friends". p?>
<?emailex
$to_pin
$from
$subject
<b>lj-imgsecurity:</b> private<br />
<br />
$body
emailex?></fieldset>
<fieldset><legend>Changing the image display size</legend>
<?p You may attach images of any size. They will be displayed
in your journal at a maximum size of 640x480. The default size
is 320x240. You may specify a size using the <b>lj-imgsize</b>
header. p?>
<?p Valid sizes are "100x100", "320x240", and "640x480". p?>
<?emailex
$to_pin
$from
$subject
<b>lj-imgsize:</b> 640x480<br />
<br />
$body
emailex?></fieldset>
<fieldset><legend>Changing image layout</legend>
<?p If you attach multiple images, you can change the way they
appear in your journal via the <b>lj-imglayout</b> header.<br /><br />
By default, multiple images will be placed in a vertical layout:<br />
<img src='$LJ::IMGPREFIX/imageplaceholder3.png' width='35' height='35'><br />
<img src='$LJ::IMGPREFIX/imageplaceholder3.png' width='35' height='35'><br />
<img src='$LJ::IMGPREFIX/imageplaceholder3.png' width='35' height='35'><br />
<br />
Currently, the only other option is "horizontal". p?>
<span style='white-space: nowrap;'>
<img src='$LJ::IMGPREFIX/imageplaceholder3.png' width='35' height='35'>
<img src='$LJ::IMGPREFIX/imageplaceholder3.png' width='35' height='35'>
<img src='$LJ::IMGPREFIX/imageplaceholder3.png' width='35' height='35'>
</span>
<br /><br />
<?emailex
$to_pin
$from
$subject
<b>lj-imglayout:</b> horizontal<br />
<br />
$body
emailex?></fieldset>
<fieldset><legend>lj-cut behavior</legend>
<?p All images are placed in your journal under a
<a href='/support/faqbrowse.bml?faqid=75'>lj-cut</a>.
By default, the cut description is the number of images uploaded.
If you attached 3 images in your email message, the lj-cut would
read, "( 3 images )". Setting the <b>lj-imgcut</b> header to
"titles" changes the cut caption to the title of the filename,
one cut per image. "( emo.jpg ) ( pict002.jpg ) ( me_and_bob.jpg )" p?>
<?emailex
$to_pin
$from
$subject
<b>lj-imgcut:</b> titles<br />
<br />
$body
emailex?></fieldset>
}
};
}
# index by name, record order
my %topics_by_name;
my $ct = 0;
foreach my $t (@topics) {
$t->{order} = $ct;
$topics_by_name{$t->{name}} = $t;
$ct++;
}
my $topic = $topics_by_name{$type};
if (! $type) {
$ret .= <<EOT;
<?h1 How does this feature work? h1?>
<?p Email posting uses normal email messages to post to your journal or a community.
Your PIN needs to be embedded in the email address, subject, or body of the message.
Embed your PIN by prefixing it with the <b>+</b> symbol. You must be sending the message
from an email address on your "Allowed sender addresses" list. If you embed your PIN
in either the subject or the body, it will be automatically removed before posting. p?>
<?p Posting via email permits many options to be set on a per message basis. Because
of this complexity, we've separated examples into different topics.
Please select from the list below: p?>
EOT
}
# list of topics
$ret .= '<ul>';
foreach (@topics) {
$ret .= '<li>';
if ($type eq $_->{name}) {
$ret .= "<b>$_->{title}</b>";
} else {
$ret .= "<a href='$_->{url}'>$_->{title}</a>";
}
$ret .= '</li>';
}
$ret .= "<li><a href='emailpost.bml'>Manage your emailpost settings</a></li>";
$ret .= '</ul>';
$ret .= '<hr /><br />' if $type;
# content
$ret .= $topic->{text} if $topic;
$ret .= "<br />";
# next/last links
if ($topic->{order} && $topics[$topic->{order} - 1]) {
my $lastt = $topics[$topic->{order} - 1];
$ret .= "[ &lt;&lt; <a href='$lastt->{url}'>$lastt->{title}</a> ] &nbsp; ";
}
if ($topics[$topic->{order} + 1]) {
$topic->{order} = -1 if ! $type;
my $nextt = $topics[$topic->{order} + 1];
$ret .= "[ <a href='$nextt->{url}'>$nextt->{title}</a> &gt;&gt; ]";
}
return $ret;
}
#--------------------------------------------------------------------------
# Update settings
if ($POST{userid} == $u->{userid}) {
my @errors;
my $addresses = $POST{addresses};
my $pin = $POST{pin};
# needs $ML{'.error.pin'}
$pin =~ s/\s+//g;
push @errors, "Your PIN is currently limited to alphabet
characters and numbers, and needs to be at least 4
characters long." unless $pin =~ /^([a-z0-9]){4,20}$/i or $pin eq '';
push @errors, "This PIN is invalid. You should change it to something that does <b>NOT</b>
have anything to do with your $LJ::SITENAMESHORT account."
if $pin eq $u->{password} or $pin eq $u->{user};
# Check email, add flags if needed.
my %allowed;
my $addrcount = 0;
foreach (split(/\0/, $addresses)) {
s/\s+//g;
next unless $_;
next if length > 80;
$_ = lc;
push @errors, "Invalid email address: " . LJ::ehtml($_) unless /\@/;
$allowed{$_} = {};
$allowed{$_}->{'get_errors'} = 1 if $POST{"check_$addrcount"};
$addrcount++;
}
if ( $POST{'emailpost_imgcut'} eq 'none' &&
$POST{'email_imgsize'} ne 'default' ) {
my ($w, $h) = split 'x', $POST{'emailpost_imgsize'};
push @errors, "Image size must be 320x240 or less to disable the lj-cut."
if $w > 320 || $h > 240;
}
return LJ::bad_input(@errors) if @errors;
LJ::Emailpost::set_allowed_senders($u, \%allowed);
foreach my $prop (@props) {
next if $prop =~ /emailpost_(allowfrom|pin)/;
next if $u->{'prop'} eq $POST{$prop};
if ($POST{$prop} && $POST{$prop} ne 'default') {
$POST{$prop} = undef if $prop eq 'emailpost_gallery' &&
$POST{$prop} eq 'LJ_emailpost';
LJ::set_userprop($u, $prop, $POST{$prop});
} else {
LJ::set_userprop($u, $prop, undef);
}
}
LJ::set_userprop($u, "emailpost_pin", $pin);
my $ret;
$ret .= "<?h1 Success h1?>";
$ret .= "<?p Your email gateway settings have been saved. p?>";
$ret .= "<?p Click <a href='emailpost.bml?mode=help'>here</a> for information on how to use this feature. p?>";
if ($LJ::HELPURL{emailpost}) {
$ret .= "<?h1 Instructions h1?>";
$ret .= "<?p FIXME: link to helpurl p?>";
}
return $ret;
}
#--------------------------------------------------------------------------
# Initial page
my $addrlist = LJ::Emailpost::get_allowed_senders($u);
my (@address, $res, $ret);
push @address, $_ foreach sort keys %$addrlist;
# get userpics and friendgroups
$res = LJ::Protocol::do_request(
"login",
{
"ver" => ( $LJ::UNICODE ? "1" : "0" ),
"username" => $u->{'user'},
"friendgroups" => 1,
"getpickws" => 1,
},
undef,
{ "noauth" => 1, }
);
my @groups = map { $_->{'name'} } @{ $res->{'friendgroups'} };
unshift @groups, $_ foreach qw/ -------- friends private public default /;
my @userpics = @{ $res->{'pickws'} };
unshift @userpics, $_ foreach qw/ default /;
$ret .= "<?p If you'd like to be able to update your journal via email, please fill out the following fields.
For more help using this feature, check out the <a href='emailpost.bml?mode=help'>instructions</a>. p?><br />";
unless (LJ::get_cap($u, 'emailpost')) {
$ret .= "Sorry, updating your journal via email is not available for your account type.";
return $ret;
}
$ret .= "<?h1 Allowed sender addresses h1?>";
$ret .= "<?p Only the addresses listed below are allowed to post to your account via the email gateway.
If no addresses are listed, posting via the email gateway will be disabled for your account.
Marked addresses will receive errors if there are any to send. p?>";
$ret .= "<form method='post' action='emailpost.bml'>\n";
$ret .= LJ::html_hidden(userid => $u->{userid});
$ret .= "<div style='margin-left:40px;'>";
$ret .= '<table border="0"><tr><td>Address:</td><td>Send errors?</td></tr>';
for(0..2) { # Limited to 3 addresses.
$ret .= '<tr><td>';
my $selected = 0;
$ret .= LJ::html_text({name=>'addresses',
value=>$address[$_], size=>40, maxlength=>80});
$ret .= '</td><td>';
$selected = 1 if $addrlist->{$address[$_]}->{'get_errors'};
$ret .= '<center>' .
LJ::html_check({name => "check_$_", selected => $selected})
. '</center>';
$ret .= '</td></tr>';
}
$ret .= '</table></div><br />';
$ret .= "<?h1 PIN h1?>";
$ret .= "<?p Your PIN is used only for the email gateway. Do not
use your regular password for this. This way, if someone obtains
your PIN, they can't obtain full access to your journal. The PIN
should be at least 4 characters long, and may only contain alphabet
characters and/or numbers. p?>";
$ret .= "<div style='margin-left:40px;'>";
$ret .= LJ::html_text({name=>'pin', value=>$u->{emailpost_pin}, maxlength=>20});
$ret .= '</div><br />';
$ret .= "<?h1 Default settings h1?>";
$ret .= "<?p
These settings apply to all journal updates via email. You can leave these options
alone to let your journal defaults take over, or override on a per message basis using
lj-headers. These settings (and lj-header overrides) are described
<a href='emailpost.bml?mode=help'>here</a>. p?>";
$ret .= "<div style='margin-left:40px;'>";
$ret .= "<table cellspacing='0' class='settings'>";
$ret .= "<tr><td colspan='2'><?h2 Journal entry defaults h2?></td></tr>";
$ret .= "<tr><td>Userpic:</td><td>";
$ret .= LJ::html_select({ name=> 'emailpost_userpic', selected => $u->{'emailpost_userpic'} },
map { $_ => $_ } @userpics);
$ret .= "</td></tr>";
$ret .= "<tr><td>Security:</td><td>";
$ret .= LJ::html_select({ name=> 'emailpost_security', selected => $u->{'emailpost_security'} },
map { $_ => $_ } @groups);
$ret .= "</td></tr>";
$ret .= "<tr><td>Comments:</td><td>";
$ret .= LJ::html_select({ name=> 'emailpost_comments', selected => $u->{'emailpost_comments'} },
'default','default','noemail','No email','off','off');
$ret .= "</td></tr>";
if ($LJ::FB_SITEROOT && %LJ::FOTOBILDER_IP && LJ::get_cap($u, 'fb_account')) {
$ret .= "<tr><td colspan='2'>&nbsp;</td></tr>";
$ret .= "<tr><td colspan='2'><?h2 Image hosting defaults h2?></td></tr>";
$ret .= "<tr><td>Gallery name:</td><td>";
$ret .= LJ::html_text({ name=> 'emailpost_gallery',
value => $u->{'emailpost_gallery'} || 'LJ_emailpost' });
$ret .= "</td></tr>";
$ret .= "<tr><td>Image security:</td><td>";
$ret .= LJ::html_select({ name=> 'emailpost_imgsecurity', selected => $u->{'emailpost_imgsecurity'} },
default => 'default',public => 'public',
regusers => 'registered users',
friends => 'friends', private => 'private');
$ret .= "</td></tr>";
$ret .= "<tr><td>Image size:</td><td>";
$ret .= LJ::html_select({ name=> 'emailpost_imgsize', selected => $u->{'emailpost_imgsize'} },
map { $_ => $_ } qw/ default 100x100 320x240 640x480 /);
$ret .= "</td></tr>";
$ret .= "<tr><td>Image layout:</td><td>";
$ret .= LJ::html_select({ name=> 'emailpost_imglayout', selected => $u->{'emailpost_imglayout'} },
map { $_ => $_ } qw/ default horizontal vertical /);
$ret .= "</td></tr>";
$ret .= "<tr><td>Image cut type:</td><td>";
$ret .= LJ::html_select({ name=> 'emailpost_imgcut', selected => $u->{'emailpost_imgcut'} },
map { $_ => $_ } qw/ default titles none /);
$ret .= "</td></tr>";
}
$ret .= "</table>";
$ret .= '</div><br />';
$ret .= "<?standout ";
$ret .= LJ::html_submit($ML{'/manage/phonepost.bml.save'});
$ret .= " standout?>";
$ret .= "</form>";
return $ret;
} _code?>
<=body
page?>

View File

@@ -0,0 +1,199 @@
<?_code
{
use strict;
use vars qw (%GET);
LJ::set_active_crumb('manage');
my $remote = LJ::get_remote();
my $authas = $GET{'authas'} || $remote->{'user'};
my $u = LJ::get_authas_user($authas);
if ($u) {
LJ::load_user_props($u, "stylesys");
$u->{'stylesys'} ||= 1;
}
$BMLCodeBlock::u = $u;
$BMLCodeBlock::authas = "?authas=$authas";
return;
}
_code?>
<?_info
localblocks<=
block<=
{F}<?h2 %%header%% h2?>
<div style="margin-left: 2em">%%about%%
<ul style="padding-left: 2em; font-weight: bold">
%%list%%
</ul></div>
<=block
authas=>{s}<?_code return $BMLCodeBlock::authas if ref $BMLCodeBlock::u; _code?>
<=localblocks
_info?>
<?page
head<=
<style type="text/css">
#ExtraInfo
{
float: right;
width: 20em;
border: 2px solid <?emcolor?>;
padding-top: 0.5em;
padding-bottom: 0.5em;
padding-right: 1em;
padding-left: 1em;
color: #333;
}
#ExtraInfo ul {
padding-left: 1em;
}
</style>
<=head
title=><?_ml .title _ml?>
body<=
<?_code
{
use strict;
use vars qw (%GET);
my $ret;
my $remote = LJ::get_remote();
return $ML{'.login'} unless $remote;
my $u = $BMLCodeBlock::u;
return LJ::bad_input("You could not be authenticated as the specified user.")
unless $u;
$ret .= "</a><form action='/manage/index.bml' method='get'>\n";
$ret .= LJ::make_authas_select($remote, { 'authas' => $GET{'authas'} });
$ret .= "</form>\n\n";
my $status = $u->{'status'} eq "A" ? "Validated" : "Not Validated";
$ret .= "<?h1 Your Account: h1?><div style='margin-left: 2em;'>";
$ret .= "<table width='50%'>";
$ret .= "<tr><th align='left'>User:</th><td>" . LJ::ljuser($u) . "</td></tr>";
$ret .= "<tr><th align='left'>Name:</th><td>$u->{'name'}</td></tr>";
$ret .= "<tr><th align='left'>E-mail Address:</th><td>$u->{'email'} (<em>$status</em>)</td></tr>";
$ret .= "</table></div>";
return $ret;
}
_code?>
<table style="width: 100%; clear: both">
<tr valign="top"><td style="width: 50%">
<?block
header=><?_ml .information.header _ml?>
about=><?_ml .information _ml?>
list<=
<li><a href="/editinfo.bml<?authas?>" title="<?_ml .information.editinfo.about _ml?>"><?_ml /editinfo.bml.title _ml?></a></li>
<li><a href="/accountstatus.bml<?authas?>" title="<?_ml .information.status.about _ml?>"><?_ml .information.status _ml?></a></li>
<li><a href="/changepassword.bml" title="<?_ml .information.changepass.about _ml?>"><?_ml .information.changepass _ml?></a></li>
<li><a href="./siteopts.bml" title="<?_ml .information.siteopts.about _ml?>"><?_ml /manage/siteopts.bml.title _ml?></a></li>
<li><a href="./emailpost.bml" title="<?_ml .information.emailpost.about _ml?>"><?_ml .information.emailpost _ml?></a></li>
<li><a href="./pubkey.bml" title="Upload your public key">PGP/GPG public key</a></li>
<li><a href="/manage/invites.bml" title="<?_ml .communities.invites.about _ml?>"><?_ml /manage/invites.bml.title _ml?></a></li>
<=list
block?>
<?block
header=><?_ml .customization.header _ml?>
about=><?_ml .customization _ml?>
list<=
<?_code
{
my $u = $BMLCodeBlock::u;
my $authas = ref $u ? "?authas=$u->{user}" : "";
my $customization;
if ($u->{'stylesys'} == 1) {
$customization .= "<li><a href='/modify.bml$authas'>$ML{'/modify.bml.title'}</a></li>";
} else {
$customization .= "<li><a href='/customize/index.bml$authas' title='$ML{'.customization.customize.about'}'><?_ml .customization.customize _ml?></a></li>";
$customization .= "<li><a href='/customize/advanced/index.bml$authas' title='$ML{'.customization.advanced.about'}'><?_ml .customization.advanced _ml?></a></li>";
$customization .= "<li><a href='./links.bml$authas' title='$ML{'.customization.links.about'}'><?_ml .customization.links _ml?></a></li>";
}
return $customization;
}
_code?>
<li><a href="/modify.bml<?authas?>" title="<?_ml .customization.moodtheme.set _ml?>"><?_ml .customization.moodtheme.set.header _ml?></a></li>
<li><a href="./moodthemes.bml<?authas?>" title="<?_ml .customization.moodtheme.editor _ml?>"><?_ml .customization.moodtheme.editor.header _ml?></a></li>
<=list
block?>
<?block
header=><?_ml .entries.header _ml?>
about=><?_ml .entries _ml?>
list<=
<li><a href="/editjournal.bml" title="<?_ml .entries.edit.about _ml?>"><?_ml /editjournal.bml.title _ml?></a></li>
<li><a href="/tools/memories.bml<?authas?>" title="<?_ml .entries.memories.about _ml?>"><?_ml /tools/memories.bml.title.memorable _ml?></a></li>
<?_code
my $u = $BMLCodeBlock::u;
my $authas = ref $u ? "?authas=$u->{user}" : "";
return $LJ::DISABLED{tags} ? "" :
"<li><a href='/manage/tags.bml$authas' title='<?_ml .entries.tags.about _ml?>'><?_ml .entries.tags.header _ml?></a></li>";
_code?>
<=list
block?>
</td><td>
<?_code
{
my $u = $BMLCodeBlock::u; my $ret;
LJ::run_hook('control_panel_column', $u, \$ret);
return $ret;
}
_code?>
<?block
header=><?_ml .userpictures.header _ml?>
about=><?_ml .userpictures _ml?>
list<=
<li><a href="/editpics.bml<?authas?>"><?_ml .userpictures.edit.about _ml?></a></li>
<=list
block?>
<?block
header=><?_ml .friends.header _ml?>
about=><?_ml .friends _ml?>
list<=
<li><a href="/friends/edit.bml" title="<?_ml .friends.edit.about _ml?>"><?_ml /friends/edit.bml.title _ml?></a></li>
<li><a href="/friends/editgroups.bml" title="<?_ml .friends.groups.about _ml?>"><?_ml /friends/editgroups.bml.title _ml?></a></li>
<li><a href="/friends/filter.bml" title="<?_ml .friends.filter.about _ml?>"><?_ml .friends.filter _ml?></a></li>
<=list
block?>
<?block
header=><?_ml .communities.header _ml?>
about=><?_ml .communities _ml?>
list<=
<li><a href="/community/create.bml" title="<?_ml .communities.create.about _ml?>"><?_ml /community/create.bml.title _ml?></a></li>
<li><a href="/community/manage.bml" title="<?_ml .communities.manage.about _ml?>"><?_ml /community/manage.bml.title _ml?></a></li>
<=list
block?>
</tr></table>
<=body
pretitle<=
<?_code
{
use strict;
my $u = $BMLCodeBlock::u; my $ret;
# user switcher
LJ::run_hook('control_panel_extra_info', $u, \$ret) if $u;
return $ret;
}
_code?>
<=pretitle
page?>

View File

@@ -0,0 +1,147 @@
<?page
title=><?_ml .title _ml?>
body<=
<?_code
{
use strict;
use vars qw(%POST);
LJ::set_active_crumb('comminvites');
return LJ::server_down_html()
if $LJ::SERVER_DOWN;
my $remote = LJ::get_remote();
return "<?needlogin?>"
unless $remote;
# for now, assume we're operating on $remote. maybe in the future we'll be able to
# manage other P type accounts, but we can't yet
my $u = $remote;
return $LJ::MSG_READONLY_USER
if LJ::get_cap($u, "readonly");
# always have links at top
my $ret = BML::ml('Backlink', {
'link' => '/manage/index.bml',
'text' => $ML{'/manage/invites.bml.manage'},
});
# get pending invites
my $pending = LJ::get_pending_invites($u) || [];
# short out?
return "<?h1 $ML{'.none.title'} h1?><?p $ML{'.none.body'} p?>"
unless @$pending;
# load communities and maintainers
my @ids;
push @ids, ($_->[0], $_->[1]) foreach @$pending;
my $us = LJ::load_userids(@ids);
# all possible attributes
my @allattribs = ('member', 'post', 'preapprove', 'moderate', 'admin');
# see if they posted and if we should take actions
if (LJ::did_post()) {
# change the back link
$ret = BML::ml('Backlink', {
'link' => '/manage/invites.bml',
'text' => $ML{'/manage/invites.bml.back'},
});
my (@accepted, @rejected, @undecided);
foreach my $invite (@$pending) {
my ($commid, $maintid, $date, $argline) = @$invite;
my $args = {};
LJ::decode_url_string($invite->[3], $args);
# now take actions?
if ($POST{"pending_$commid"} eq 'yes') {
my $rval = LJ::accept_comm_invite($u, $us->{$commid});
push @accepted, [ $commid, $args ] if $rval;
} elsif ($POST{"pending_$commid"} eq 'no') {
my $rval = LJ::reject_comm_invite($u, $us->{$commid});
push @rejected, $commid if $rval;
} else {
push @undecided, $commid;
}
}
# communities they've joined
if (@accepted) {
$ret .= "<?h1 $ML{'.accepted.title'} h1?><?p $ML{'.accepted.body'} p?><ul>";
foreach my $row (@accepted) {
$ret .= "<li>" . LJ::ljuser($us->{$row->[0]}, { type => 'C' }) . ": ";
foreach my $attrib (@allattribs) {
$ret .= "$ML{\".label.$attrib\"}, " if $row->[1]{$attrib};
}
chop $ret; chop $ret;
$ret .= "</li>\n";
}
$ret .= "</ul>";
}
# communities they rejected
if (@rejected) {
$ret .= "<?h1 $ML{'.rejected.title'} h1?><?p $ML{'.rejected.body'} p?><ul>";
$ret .= "<li>" . LJ::ljuser($us->{$_}, { type => 'C' }) . "</li>\n" foreach @rejected;
$ret .= "</ul>";
}
# now print out undecided results
if (@undecided) {
$ret .= "<?h1 $ML{'.undecided.title'} h1?><?p $ML{'.undecided.body'} p?><ul>";
$ret .= "<li>" . LJ::ljuser($us->{$_}, { type => 'C' }) . "</li>\n" foreach @undecided;
$ret .= "</ul>";
}
return $ret;
}
# prepare table
$ret .= "<br /><form method='post'><div align='center'><table class='borderedtable' cellspacing='0' cellpadding='2'>";
$ret .= "<tr><th>$ML{'.community.title'}</th><th>$ML{'.abilities.title'}</th>";
$ret .= "<th colspan='2'>$ML{'.actions.title'}</th>";
$ret .= "</tr>";
# now list memberships
my $rc = 0;
foreach my $invite (@$pending) {
# get variables we'll need for HTML generatrion
my $rstyle = ($rc++ & 1) ? "<?altcolor1?>" : "<?altcolor2?>";
my $cu = $us->{$invite->[0]};
my $key = "pending_$invite->[0]";
my @tags = ();
my $args = {};
LJ::decode_url_string($invite->[3], $args);
foreach (@allattribs) {
push @tags, $ML{".label.$_"} if $args->{$_};
}
my $ename = LJ::ehtml($cu->{name});
my $date = LJ::mysql_time($invite->[2]);
# now generate HTML
$ret .= "<tr style='background-color: $rstyle;'><td>" . LJ::ljuser($cu, { type => 'C' }) . " - $ename</td>";
$ret .= "<td>" . join(', ', @tags) . "</td>";
$ret .= "<td nowrap='nowrap'>" . LJ::html_check({ type => 'radio', name => $key, id => "yes$key", value => 'yes' });
$ret .= " <label for='yes$key'>$ML{'.accept'}</label></td>";
$ret .= "<td nowrap='nowrap'>" . LJ::html_check({ type => 'radio', name => $key, id => "no$key", value => 'no' });
$ret .= " <label for='no$key'>$ML{'.decline'}</label></td>";
$ret .= "</tr><tr>";
$ret .= "<td colspan='4' style='background-color: $rstyle;'>";
$ret .= BML::ml('.fromline', { user => LJ::ljuser($us->{$invite->[1]}, { type => 'P' }), date => $date });
$ret .= "</td></tr>\n";
}
# all done
$ret .= "</table><br />";
$ret .= LJ::html_submit('submit', $ML{'.submit'});
$ret .= "</div></form>";
return $ret;
} _code?>
<=body
page?>

View File

@@ -0,0 +1,68 @@
<?page
title=><?_ml .title _ml?>
body<=
<?_code
{
use strict;
use vars qw(%GET %POST);
LJ::set_active_crumb('linkslist');
my $remote = LJ::get_remote();
return LJ::bad_input($ML{'error.noremote'})
unless $remote;
my $authas = $GET{'authas'} || $remote->{'user'};
my $u = LJ::get_authas_user($authas);
return LJ::bad_input($ML{'error.invalidauth'})
unless $u;
my $getextra = $u->{'userid'} == $remote->{'userid'} ? '' : "?authas=$u->{'user'}";
# need stylesys prop for error checking
LJ::load_user_props($u, "stylesys");
my $ret;
# authas switcher form
$ret .= "<form method='get' action='links.bml'>\n";
$ret .= LJ::make_authas_select($remote, { 'authas' => $GET{'authas'} }) . "\n";
$ret .= "</form>\n\n";
# require S2
unless ($u->{'stylesys'} == 2) {
my $link = "<a href=\"$LJ::SITEROOT/customize/$getextra\">$ML{'/customize/index.bml.title'}</a>";
$ret .= "<?h1 $ML{'.error.s2required.header'} h1?><?p " . BML::ml('.error.s2required',{'link'=>$link}) . " p?>";
return $ret;
}
# build link object, either from db or form
my $linkobj;
if (LJ::did_post()) {
$linkobj = LJ::Links::make_linkobj_from_form($u, \%POST);
} else {
$linkobj = LJ::Links::load_linkobj($u, "master");
}
# save any changes to the database
if ($POST{'action:savelinks'}) {
LJ::Links::save_linkobj($u, $linkobj);
$ret .= "<p><b>$ML{'.success'}</b></p>";
}
# intro paragraph
$ret .= "<?p $ML{'.about'} p?>";
$ret .= "<ul><li>$ML{'.about.reorder'}</li>";
$ret .= "<li>$ML{'.about.blank'}</li>";
$ret .= "<li>$ML{'.about.heading'}</li></ul>";
# link modify form
$ret .= "<form method='post' action='links.bml$getextra' style='margin-top: 1.5em;'>";
$ret .= LJ::Links::make_modify_form($u, $linkobj, \%POST);
$ret .= "</form>";
return $ret;
}
_code?>
<=body
page?>

View File

@@ -0,0 +1,453 @@
<?page
title=>Custom Mood Theme Editor
head<=
<script language="Javascript" type="text/javascript">
<!--
// Since JavaScript is dumb, we must get the page URL and save it here, to compare
// against later when we're seeing if we actually loaded an image or not...
var page_url = document.URL;
// Designed to update the fields for the image just changed as well as
// well as all those that inherit from it.
function update_children(id) {
if (! document.getElementById) return true;
var i = id+'img';
var url = document.getElementById(id);
var img = document.getElementById(i);
// If they actually have us something useful
if (url.value != "") {
var newimage = new Image();
newimage.src=url.value;
var oldurl = img.src;
// Update itself
img.src = url.value;
img.width = newimage.width;
img.height = newimage.height;
var w = id+'w';
var h = id+'h';
var width = document.getElementById(w);
var height = document.getElementById(h);
width.value = newimage.width;
height.value = newimage.height;
var form = document.getElementById('editform');
// Update everything to be its parent
for (var z = 0; z < form.elements.length; z++) {
var inherit = document.getElementById(form[z].id+'inherit');
var parent = document.getElementById(form[z].id+'parent');
if ((parent != undefined) && (inherit != undefined && inherit.checked == true)) {
// our ids and stuff
var pid = parent.value; // our parent's id
var oid = form[z].id; // our id
// at this point we explode!
var par_img = document.getElementById(pid+'img');
if (par_img.src == page_url) {
continue;
}
var our_img = document.getElementById(oid+'img');
our_img.src = par_img.src;
our_img.width = par_img.width;
our_img.height = par_img.height;
// now copy our_img info into text fields
var our_url = document.getElementById(oid);
var our_width = document.getElementById(oid+'w');
var our_height = document.getElementById(oid+'h');
our_url.value = par_img.src;
our_width.value = par_img.width;
our_height.value = par_img.height;
}
}
}
return false;
}
// Logic behind grabbing the parent when checking inherit
function enable(id, parent) {
if (! document.getElementById) return true;
var check = document.getElementById(id+'inherit');
var url = document.getElementById(id);
var w = document.getElementById(id+'w');
var h = document.getElementById(id+'h');
var fill = switchdisable(id, check, url, w, h);
var pi = document.getElementById(parent+'img');
// For some dumb reason an img tag with no source has the src of the pages url
if(fill && parent != id && pi.src != page_url) {
url.value = pi.src;
w.value = pi.width;
h.value = pi.height;
var i = document.getElementById(id+'img');
i.src = pi.src;
i.width = pi.width;
i.height = pi.height;
}
}
// If a set of fields is disabled, it enables them and vice versa
function switchdisable(id, check, url, w, h) {
if (! document.getElementById) return true;
if (check == undefined) {
var check = document.getElementById(id+'inherit');
var url = document.getElementById(id);
var w = document.getElementById(id+'w');
var h = document.getElementById(id+'h');
}
if (check.checked == true) {
url.disabled = true;
w.disabled = true;
h.disabled = true;
return true;
} else {
url.disabled = false;
w.disabled = false;
h.disabled = false;
return false;
}
}
// Since not all browsers support JS, we need to use JS to disable form fields
// instead of doing it in Perl land.
function pageload() {
if (! document.getElementById) return true;
var form = document.getElementById('editform');
if (form == undefined) {
return false;
}
for (var z = 0; z < form.elements.length; z++) {
var inherit = document.getElementById(form[z].id+'inherit');
if (inherit != undefined && inherit.checked == true) {
switchdisable(form[z].id, undefined, undefined, undefined, undefined);
}
}
}
// -->
</script>
<=head
body<=
<?_code
{
use strict;
use vars qw(%POST %GET);
my $remote = LJ::get_remote();
return "<?needlogin?>" 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;
my $self_uri = "/manage/moodthemes.bml";
$self_uri .= "?authas=$authas" if $authas ne $remote->{'user'};
# Populated with all the moods later in editform
my %lists;
my $ret;
#### Closure Definitions ####
my $make_tree;
$make_tree = sub {
my ($num, $tid) = @_;
return unless $lists{$num};
$ret .= "<ul>\n";
foreach my $mood (@{$lists{$num}}) {
$ret .= "<li><b>$mood->{'name'}</b>";
my %pic;
LJ::get_mood_picture($tid, $mood->{'id'}, \%pic);
$ret .= "<img id='$mood->{'id'}img' align='absmiddle' src=\"$pic{'pic'}\" width='$pic{'w'}' height='$pic{'h'}' hspace='2' vspace='2' /></li>\n";
# Figure out if this picture is really just inherited from a parent
my $inherited;
if ($pic{'moodid'} != $mood->{'id'}) {
$inherited = 1;
} else {
$inherited = 0;
}
$ret .= "<table>";
if ($mood->{'parent'}) {
$ret .= "<tr><td colspan='2'><label for='$mood->{id}inherit'>Inherit from ";
$ret .= LJ::mood_name($mood->{'parent'}) . "</label>";
$ret .= ": " . LJ::html_check({ type => 'check', name => "$mood->{id}inherit",
id => "$mood->{id}inherit",
onclick => "enable($mood->{id}, $mood->{parent})",
selected => $inherited });
$ret .= "</td></tr>\n";
}
$ret .= "<tr><td>URL: </td><td>";
$ret .= LJ::html_text({ name => $mood->{id}, id => $mood->{id}, value => $pic{pic},
size => 75, onchange => "update_children($mood->{id})" });
$ret .= "</td></tr>\n";
$ret .= "<tr><td>Width: </td><td>";
$ret .= LJ::html_text({ name => "$mood->{id}w", id => "$mood->{id}w", value => $pic{w}, size => 4 });
$ret .= " Height: " . LJ::html_text({ name => "$mood->{id}h", id => "$mood->{id}h",
value => $pic{h}, size => 4 });
$ret .= "<br /><br /></td></tr>\n";
$ret .= LJ::html_hidden({ name => "$mood->{id}parent", id => "$mood->{id}parent", value => $mood->{parent} });
$ret .= "</table>\n";
$make_tree->($mood->{'id'}, $tid, 0);
}
$ret .= "</ul>\n";
};
my $editform = sub {
my $id = shift;
# Get a list of all possible moods
my $moods = LJ::get_moods();
foreach (sort { $moods->{$a}->{'name'} cmp $moods->{$b}->{'name'} } keys %$moods) {
my $m = $moods->{$_};
push @{$lists{$m->{'parent'}}}, $m;
}
$make_tree->(0, $id);
};
#### End Closure Definitions ####
if (LJ::did_post()) { # They actually did something, figure out what
my $themeid = $POST{'themeid'};
my $info;
# Figure out if they are editing a theme and which one they are
my @ids = split ',', $POST{'themeids'};
foreach (@ids) {
$themeid = $_ if $POST{"edit:$_"};
}
if (!$themeid) { # They decided to actually use a custom theme
my $use_theme;
foreach (@ids) {
$use_theme = $_ if $POST{"use:$_"};
}
if ($use_theme) {
my %update;
$update{'moodthemeid'} = $use_theme;
foreach (keys %update) {
delete $update{$_} if $u->{$_} eq $update{$_};
}
LJ::update_user($u, \%update);
return BML::redirect($self_uri);
}
}
elsif ($POST{'isnew'} != 1) { # Make sure they can even edit this theme and fill in the $info variable for later use
my $dbr = LJ::get_db_reader();
my $sth = $dbr->prepare("SELECT name FROM moodthemes WHERE moodthemeid=? AND ownerid=?");
$sth->execute($themeid, $u->{'userid'});
$info = $sth->fetchrow_hashref;
return LJ::bad_input("You do not have permission to edit this theme.")
unless defined $info;
}
# are we deleting a theme?
foreach my $tid (@ids) {
if ($POST{"delete:$tid"}) {
# good, delete this one
my $dbh = LJ::get_db_writer();
my $c = $dbh->do("DELETE FROM moodthemes WHERE moodthemeid = ? AND ownerid = ?", undef, $tid, $u->{userid})+0;
return "<?h1 $ML{'Error'} h1?><?p There was an error deleting this moodtheme. p?>" unless $c;
$dbh->do("DELETE FROM moodthemedata WHERE moodthemeid = ?", undef, $tid); # safe since we verified $c
return BML::redirect($self_uri);
}
}
# We are either making changes to an existing theme or showing the edit form for a new theme
if ($themeid && $POST{'edit'} == 1 || $POST{'isnew'} == 1) {
# Insert the new theme name and description into the db and grab its new themeid
if ($POST{'isnew'} == 1) {
return LJ::bad_input("You must specify a name for this theme.")
unless LJ::trim($POST{'name'});
my $dbh = LJ::get_db_writer();
my $i = $dbh->do("INSERT INTO moodthemes (ownerid, name, is_public) VALUES (?, ?, 'N')", undef, $u->{'userid'}, $POST{'name'});
return "<?h1 $ML{'Error'} h1?><?p There was an error creating this moodtheme. p?>" unless $i;
$themeid = $dbh->{'mysql_insertid'};
$info->{'name'} = $POST{'name'};
}
$ret .= "<?hr?>\n";
$ret .= "<?h2 Editing Theme $info->{name} h2?>\n";
# Make the form
$ret .= "<?p <form action='$self_uri' method='post' id='editform' name='editform'>\n";
$ret .= "<b>Theme Name:</b> ";
$ret .= LJ::html_text({ name => 'name', value => $info->{name}, size => 50, maxlength => 255 });
$ret .= "<br /><br />\n";
$ret .= LJ::html_hidden('themeid' => $themeid) . "\n";
# Actually make the editor form
$editform->($themeid);
$ret .= LJ::html_submit('save' => "Save Changes") . "</form> p?>\n";
} elsif ($themeid) { # Save their changes
my $dbh = LJ::get_db_writer();
# Update the name or description if needed
if ($info->{'name'} ne $POST{'name'}) {
my $u = $dbh->do("UPDATE moodthemes SET name=? WHERE moodthemeid=?", undef, $POST{'name'}, $POST{'themeid'});
return "<?h1 $ML{'Error'} h1?><?p There was an error updating this moodtheme. p?>" unless $u;
}
# The fun part of figuring out what needs to be changed in the db
my (@repl_values, @repl_bind, @del_values, @del_bind);
foreach my $key (keys %POST) {
# A key that is fully numeric signifies an actual mood theme.
# We then build off this id number to get other information needed
# about what the user specified.
if ($key =~ /(^\d+$)/) {
my $mid = $1;
my $width = $POST{$mid.'w'};
my $height = $POST{$mid.'h'};
my $picurl = $POST{$key};
my $mname = LJ::mood_name($mid);
if (($POST{$mid.'check'} ne 'checked') && (!$picurl || $width == 0 || $height == 0)) { # Delete this picture
push @del_values, $mid;
push @del_bind, ("?");
next;
}
if ($POST{$mid.'check'} eq 'checked') { # Inherited, thus don't represent it in the db
push @del_values, ($themeid, $mid);
push @del_bind, ("(moodthemeid=? AND moodid=?)");
$ret .= "$mname($mid) was deleted and will now be represented by its parent.<br />\n";
} else { # Not inherited, it is different than its parent or it is actually a parent
if ($picurl) {
push @repl_values, ($themeid, $mid, $picurl, $width, $height);
push @repl_bind, ("(?, ?, ?, ?, ?)");
$ret .= "$mname($mid) is set to $picurl.<br />\n";
}
}
}
}
if (@del_values) {
my $bind = join(",", @del_bind);
my $p = $dbh->do("DELETE FROM moodthemedata WHERE moodthemeid=? AND moodid IN($bind)",
undef, $themeid, @del_values);
return "<?h1 $ML{'Error'} h1?><?p There was an error updating this moodtheme. p?>" unless $p;
}
my $bind = join(",", @repl_bind);
my $i = $dbh->do("REPLACE INTO moodthemedata (moodthemeid, moodid, " .
"picurl, width, height) VALUES $bind", undef, @repl_values);
return "<?h1 $ML{'Error'} h1?><?p There was an error updating this moodtheme. p?>" unless $i;
# Kill any memcache data about this moodtheme
LJ::MemCache::delete([$themeid, "moodthemedata:$themeid"]);
delete $LJ::CACHE_MOOD_THEME{$themeid};
$ret .= "<br />Changes have been successfully saved.<br /><br />\n";
return BML::redirect($self_uri);
}
$ret .= BML::ml('Backlink', {
'link' => $self_uri,
'text' => 'Return To Editor',
});
} else { # Show the first form to select user, which one to edit, or create a new one
# user switcher
$ret .= "<form action='/manage/moodthemes.bml' method='get'>\n";
$ret .= LJ::make_authas_select($remote, { 'authas' => $GET{'authas'} });
$ret .= "</form>\n\n";
unless (LJ::get_cap($u, "moodthemecreate")) {
$ret .= "Sorry, your account type does not allow creation of custom mood themes."
} else {
# form to allow users to create new mood themes
$ret .= "<?h1 Create a New Theme h1?>\n";
$ret .= "<form action='$self_uri' method='post' id='editform' name='editform' style='margin-left: 30px;'>\n";
$ret .= LJ::html_hidden('isnew' => 1) . "\n";
$ret .= "<?p <b>Name:</b> " . LJ::html_text({ name => 'name', size => 30, maxlength => 50 });
$ret .= LJ::html_submit('create' => "Create") . " p?></form>\n";
# Make up the form to choose to edit a theme or create a new one
$ret .= "<?h1 Your Mood Themes h1?>\n";
# Get data to figure out if they have any themes already
my $dbr = LJ::get_db_reader();
my $sth = $dbr->prepare("SELECT moodthemeid, name FROM moodthemes WHERE ownerid=?");
$sth->execute($u->{userid});
my @user_themes = ();
push @user_themes, $_ while $_ = $sth->fetchrow_hashref;
if (@user_themes) { # The have some custom themes already defined
$ret .= "<form action='$self_uri' method='post' id='selectform' name='selectform' style='margin-left: 30px;'>\n";
$ret .= LJ::html_hidden('edit' => 1,
'themeids' => join(",", map { $_->{moodthemeid} } @user_themes));
$ret .= "<table>";
$ret .= "<tr><th></th><th>Happy</th><th>Sad</th><th>Angry</th><th></th></tr>";
foreach my $theme (@user_themes) {
my $name = $theme->{'name'};
my $tid = $theme->{'moodthemeid'};
my $use_dis = 0;
if ($tid == $u->{'moodthemeid'}) {
$ret .= "<tr><td><b><a href='/moodlist.bml?moodtheme=$tid&ownerid=$u->{'userid'}'>$name</a></b></td>";
$use_dis = 1;
} else {
$ret .= "<tr><td><a href='/moodlist.bml?moodtheme=$tid&ownerid=$u->{'userid'}'>$name</a></td>";
}
my @head_moods = (15, 25, 2); # happy, sad, angry
foreach my $moodid (@head_moods) {
my %pic = ();
LJ::get_mood_picture($tid, $moodid, \%pic);
$ret .= "<td>";
if (%pic) {
$ret .= "<img align='absmiddle' src=\"$pic{'pic'}\" width='$pic{'w'}' height='$pic{'h'}' hspace='2' vspace='2' />";
} else {
$ret .= "<i>[no image]</i>";
}
$ret .= "</td>";
}
$ret .= "<td>" . LJ::html_submit("edit:$tid" => "Edit") . " " .
LJ::html_submit("use:$tid", "Use", {'disabled' => $use_dis}) . " " .
LJ::html_submit("delete:$tid", "Delete",
{ onclick => 'return confirm("Are you sure you want to delete this mood theme?");' }) . "</td>";
$ret .= "</tr>";
}
$ret .= "</table>";
$ret .= "</form>\n";
} else {
$ret .= "<?p You have not yet made any custom mood themes. p?>\n";
}
}
$ret .= "<?p Select a public mood theme as your default at the <a href='$LJ::SITEROOT/modify.bml'>Modify Journal page</a>. p?>";
}
return $ret;
}
_code?>
<=body
bodyopts=> onload="pageload();"
page?>

View File

@@ -0,0 +1,94 @@
<?page
title=><?_ml .title _ml?>
body<=
<?_code
{
use strict;
use vars qw(%POST);
LJ::set_active_crumb('setpgpkey');
return $ML{'.error.notconfigured'} unless $LJ::USE_PGP;
return LJ::server_down_html() if $LJ::SERVER_DOWN;
my $u = LJ::get_remote();
return "<?needlogin?>"
unless $u;
return BML::redirect("$LJ::SITEROOT/agecheck/?s=1")
if $u->underage;
return $LJ::MSG_READONLY_USER if $u->readonly;
my $check_key = sub {
my $key = shift;
# make sure it is a public key, not a private or a signature,
# before we bother with other checks
my $kt = $1 if $key =~ /-{5}BEGIN PGP (\w+) /;
return 0 unless $kt eq 'PUBLIC';
# pull key data, return if suspicious
my $ks = "$kt KEY BLOCK";
my $data = $1 if $key =~ /$ks-{5}(.+?)-{5}.+?$ks(?:-)+/s;
foreach ($data =~ /^(\w+):/mg) {
return 0 unless $1 =~ /(Version|Hash|Comment|MessageID|Charset)/i;
}
$data =~ s/^(\s|\w+:).*//mg;
$data =~ s/(?:\r)?\n//sg;
return 0 if $data =~ tr/[ \t]// || length $data < 500;
return 1;
};
# Update settings
my $error;
if ($POST{userid} == $u->{userid}) {
my @errors;
my $key = $POST{key};
push(@errors, $ML{'.error.invalidkey'})
if ! $check_key->($key) && length $key != 0;
$error = LJ::error_list(@errors) if @errors;
unless (@errors) {
$key = LJ::trim($key);
LJ::set_userprop($u, 'public_key', $key);
# This page shows them their key saved
# eventually add a confirmation bar on it
return BML::redirect('/pubkey.bml');
}
}
# Initial page
LJ::load_user_props($u, qw(public_key));
my $ret;
$ret .= "<?p ";
$ret .= BML::ml('.info', {
aoptsinfo => "href='/userinfo.bml'",
aoptshelp => "href='emailpost.bml?mode=help&type=advanced\#pgp'",
});
$ret .= " p?>";
$ret .= "<?p ";
$ret .= BML::ml('.whatis', {
aoptspgp => "href='http://www.pgp.com/'",
aoptsgpg => "href='http://www.gnupg.org/'",
});
$ret .= " p?>";
$ret .= "<?h1 $ML{'.header'} <img src='/img/key.gif' height='16' width='16'> h1?>";
$ret .= "<form method='post' action='pubkey.bml'>\n";
$ret .= $error if $error;
$ret .= "<?p $ML{'.pastekey'} p?>\n";
$ret .= LJ::html_hidden(userid => $u->{userid});
my $val = LJ::did_post() ? $POST{'key'} : $u->{'public_key'};
$ret .= LJ::html_textarea({name=>'key', value=>$val, rows=>20, cols=>70 });
$ret .= "<br /><br /><?standout ";
$ret .= LJ::html_submit($ML{'.save'});
$ret .= " standout?>";
$ret .= "</form>";
return $ret;
} _code?>
<=body
page?>

View File

@@ -0,0 +1,243 @@
<?_code
{
use strict;
use vars qw(%GET %POST $title $body);
LJ::set_active_crumb('siteopts');
# set $title later because we may be changing languages
$title = "";
$body = "";
# error handling closures
my $redir = sub { BML::redirect("siteopts.bml"); };
# thumb schemes have thumbnails
# text schemes are in a drop-down
my @thumb_schemes;
my @text_schemes;
foreach (@LJ::SCHEMES) {
if (ref $_->{'thumb'} eq 'ARRAY') {
push @thumb_schemes, $_;
} else {
push @text_schemes, $_;
}
}
# saving changes
if (LJ::did_post()) {
my $remote = LJ::get_remote();
# was a scheme change posted?
my $scheme;
if (exists $POST{'action:setscheme'}) {
foreach (@text_schemes) {
$scheme = $_->{'scheme'} if $POST{'scheme'} eq $_->{'scheme'};
}
} else {
foreach (@thumb_schemes) {
$scheme = $_->{'scheme'} if exists $POST{"action:setscheme:$_->{'scheme'}.x"};
}
}
# set scheme
if ($scheme) {
my $cval = $scheme;
# don't set cookie for default scheme
if ($scheme eq $LJ::SCHEMES[0]->{'scheme'}) {
$cval = '';
delete $COOKIE{'BMLschemepref'};
}
# logged in?
if ($remote) {
# set a userprop to remember their schemepref
LJ::set_userprop($remote, 'schemepref', $cval);
# cookie expires when session expires
if ($remote->{'_session'}->{'exptype'} eq 'long') {
$cval = [ $scheme, $remote->{'_session'}->{'timeexpire'} ];
}
}
# set cookie
$COOKIE{'BMLschemepref'} = $cval if $cval;
# redirect to refresh cookie settings
return $redir->();
}
# set language
if (exists $POST{'action:setlang'} && $POST{'lang'}) {
my $l = LJ::Lang::get_lang($POST{'lang'});
return $redir->() unless $l;
# default cookie value to set
my $cval = $l->{'lncode'} . "/" . time();
# if logged in, change userprop and make cookie expiration
# the same as their login expiration
my $remote = LJ::get_remote();
if ($remote) {
LJ::set_userprop($remote, "browselang", $l->{'lncode'});
if ($remote->{'_session'}->{'exptype'} eq 'long') {
$cval = [ $cval, $remote->{'_session'}->{'timeexpire'} ];
}
}
# set cookie
$COOKIE{'langpref'} = $cval;
# set language through BML so it will apply immediately
BML::set_language($l->{'lncode'});
}
}
# set title now that we have the correct language
$title = $ML{'.title'};
# preferences page output
# wrapper box to to keep tables from scrolling horizontally
$body .= "<table><tr><td>";
# scheme selector
if (@LJ::SCHEMES) {
$body .= "<?h1 $ML{'.head.scheme'} h1?>";
$body .= "<form method='post' action='siteopts.bml'>";
my $scheme = $BML::COOKIE{'BMLschemepref'};
$scheme = $LJ::SCHEMES[0]->{'scheme'} unless $scheme;
if (@thumb_schemes) {
my $ct = 0;
my $cols = 3;
my $width = int(100 / $cols +.5) . "%";
my $switch = @thumb_schemes / $cols;
$body .= "<table border='0' width='100%' cellpadding='2'>";
$body .= "<tr valign='top' align='left'>";
foreach my $sh (@thumb_schemes) {
if ($ct == 0) {
$body .= "<td width='$width' align='left' valign='top'>";
}
my $th = $sh->{'thumb'};
$body .= "<div style='float: left'><?h2 $sh->{'title'} h2?> <input type='image' ";
$body .= "name='action:setscheme:$sh->{'scheme'}' ";
$body .= "src='$LJ::IMGPREFIX/$th->[0]'";
$body .= " width='$th->[1]'" if $th->[1];
$body .= " height='$th->[2]'" if $th->[2];
if ($sh->{'scheme'} eq $scheme) {
$body .= "style='border: solid 2px blue;' ";
} else {
$body .= "style='border: solid 1px black;' ";
}
my $alt = BML::ml('.scheme.preview', {'title' => $sh->{'title'},});
$body .= " alt='$alt' title='$sh->{'title'}'/></div>";
if (++$ct >= $switch) {
$body .= "</td>";
$ct = 0;
}
}
$body .= "</tr></table>";
}
if (@text_schemes) {
my $ct = 0;
my $cols = 3;
my $width = int(100 / $cols +.5) . "%";
my $switch = @text_schemes / $cols;
$body .= "<table border='0' width='100%' cellpadding='2'>";
$body .= "<tr valign='top' align='left'>";
foreach my $sh (@text_schemes) {
if ($ct == 0) {
$body .= "<td width='$width' align='left'>";
}
$body .= "<p>" .
LJ::html_check({ 'type' => 'radio', 'name' => 'scheme',
'value' => $sh->{'scheme'},
'id' => "scheme-$sh->{'scheme'}",
'selected' => $scheme eq $sh->{'scheme'} });
$body .= "<label for='scheme-$sh->{'scheme'}'>$sh->{'title'}</label></p>";
if (++$ct >= $switch) {
$body .= "</td>";
$ct = 0;
}
}
$body .= "</tr><tr><td colspan='$cols' align='left'>";
$body .= LJ::html_submit('action:setscheme', $ML{'.btn.scheme'});
$body .= "</td></tr></table>";
}
$body .= "</form>";
}
# language selector
$body .= "<?h1 $ML{'.head.lang'} h1?>";
$body .= "<form method='post' action='siteopts.bml'>";
my $ct = 0;
my $cols = 3;
my $width = int(100 / $cols +.5) . "%";
my $switch = @LJ::LANGS / $cols;
my $curr = BML::get_language();
$body .= "<table border='0' width='100%' cellpadding='2'>";
$body .= "<tr valign='top' align='left'>";
my @inc;
push @inc, $GET{'addlang'} if $GET{'addlang'};
foreach my $code (@LJ::LANGS, @inc) {
my $l = LJ::Lang::get_lang($code);
next unless $l;
my $item = "langname.$code";
my $namethislang = BML::ml($item);
my $namenative = LJ::Lang::get_text($l->{'lncode'}, $item);
if ($ct == 0) {
$body .= "<td width='$width' align='left'>";
}
$body .= "<p>" . LJ::html_check({ 'type' => 'radio', 'name' => 'lang',
'value' => $code, 'id' => "sel_$code",
'selected' => $code eq $curr });
$body .= " <label for='sel_$code'>$namenative";
$body .= " ($namethislang)" if $namethislang ne $namenative;
$body .= "</label></p>\n";
if (++$ct >= $switch) {
$body .= "</td>";
$ct = 0;
}
}
$body .= "<tr><td colspan='$cols' align='left'>";
$body .= LJ::html_submit('action:setlang', $ML{'.btn.lang'});
$body .= "</td></tr>";
$body .= "</table></form>";
$body .= "</td></tr></table>";
return;
}
_code?><?page
title=><?_code return $title; _code?>
body=><?_code return $body; _code?>
page?>

View File

@@ -0,0 +1,267 @@
<?page
title=><?_code return $ML{'.title'}; _code?>
body<=
<?_code
{
use strict;
use vars qw(%POST %GET);
LJ::set_active_crumb('tags');
return "<?h1 $ML{'Error'} h1?><?p $ML{'/edittags.bml.disabled'} p?>"
if $LJ::DISABLED{tags};
my $remote = LJ::get_remote();
return "<?needlogin?>" unless $remote;
my $authas = $GET{'authas'} || $remote->{'user'};
my $u = LJ::get_authas_user($authas);
return LJ::bad_input($ML{'error.invalidauth'})
unless $u;
# do user requested changes
my $add_text = $ML{'.addnew'};
if (LJ::did_post()) {
# Adding new tags
$POST{add} = 1 if $POST{'add.x'} or $POST{'add.y'}; # image submit
if ($POST{add} or ($POST{'add_field'} && $POST{'add_field'} ne $add_text)) {
LJ::Tags::create_usertag($u, $POST{'add_field'}, { display => 1 });
}
# Deleting tags
if ($POST{delete}) {
foreach my $id (split /\0/, $POST{tags}) {
$id =~ s/_.*//;
LJ::Tags::delete_usertag( $u, 'id', $id );
}
}
if ($POST{rename}) {
my @tagnames = map { s/\d+_//; $_; } split /\0/, $POST{tags};
my $new_tag = LJ::trim($POST{rename_field});
$new_tag =~ s/,.*//;
# FIXME: merge support later
LJ::Tags::rename_usertag( $u, 'name', $tagnames[0], $new_tag );
}
if ($POST{'show posts'}) {
# this should do some cute ajax display later.
my $tags = LJ::Tags::get_usertags( $u ); # we redirect, so we don't double load anyway
my $taglist = LJ::eurl(join ',', map { $tags->{$_}->{name} } map { /^(\d+)_/; $1; } split /\0/, $POST{tags});
BML::redirect( LJ::journal_base($u) . "/tag/$taglist" );
}
}
# get tags list!
my $tags = LJ::Tags::get_usertags( $u );
my $tagcount = scalar keys %$tags;
# create histogram usage levels from 'uses' counts
# for 'cell bars' icon display
if ($tagcount) {
my (
@data,
$groups,
$max, $min,
$width,
%range,
);
$groups = 5;
# order by use
@data = map { [ $_, $tags->{$_}->{uses} ] }
sort { $tags->{$a}->{uses} <=> $tags->{$b}->{uses} } keys %$tags;
# get min use, max use, and group 'width'
$max = $data[-1]->[1];
$min = $data[0]->[1];
$width = ($max - $min) / $groups || 1;
# pre calculate ranges for groups
for (1..$groups) {
$range{$_} = [];
@{$range{$_}}[0] = $min + ($_ - 1) * $width; # low
@{$range{$_}}[1] = $min + ($_ * $width); # high
}
# iterate through sorted data, adding
# histogram group to the tags data structure.
foreach (@data) {
my ($id, $use) = (@$_);
GROUP:
for (1..$groups) {
if ($use >= @{$range{$_}}[0] && $use <= @{$range{$_}}[1]) {
$tags->{$id}->{histogram_group} = $_;
last GROUP;
}
}
}
}
# button titles (mouseovers)
my $mo = {
create => $ML{'.hint.create'},
rename => $ML{'.hint.rename'},
delete => $ML{'.hint.delete'},
entries => $ML{'.hint.entries'},
};
my $sp = '&nbsp;&nbsp;';
my $ret;
# user switcher
$ret .= "<form method='GET'>\n";
$ret .= LJ::make_authas_select($remote, { authas => $u->{user} });
$ret .= "</form>\n";
$ret .= "<?p $ML{'.intro'} p?>";
# convert tags data structure to javascript array for quick prop display.
# this is temporary, we'll eventually do a smarter
# xml-rpc call instead of requiring this.
$ret .= "\n<script type='text/javascript'>\n";
$ret .= "var tags = new Array();\n";
foreach (sort keys %$tags) {
my $tag = $tags->{$_};
my $sec = $tag->{security};
my ($pub, $pri, $fr, $tot) =
($sec->{public}, $sec->{private},
$sec->{friends}, $tag->{uses});
my $grp = $tot - ($pub+$pri+$fr);
$ret .= "tags[$_] = [ '" . LJ::ejs($tag->{name}) . "', '$tag->{security_level}', $pub, $pri, $fr, $grp, $tot ];\n";
}
$ret .= "</script>\n";
# the extra 'padding' div is a workaround for how
# IE incorrectly renders fieldsets.
$ret .= qq{
<form method="POST" name="tagform" id="tagform">
<table cellpadding="0" cellspacing="0">
<tr><td valign="top">
<fieldset>
<legend>$ML{'.label.yours'}</legend>
<div style="padding-top: 6px;">
};
my $tagsort = sub {
$GET{sort} eq 'use' ?
$tags->{$b}->{uses} <=> $tags->{$a}->{uses} :
$tags->{$a}->{name} cmp $tags->{$b}->{name};
};
if ($tagcount) {
$ret .= "<select name='tags' id='tags' multiple='multiple' class='tagbox' " .
"onChange='tagselect(this)'>";
foreach (sort { $tagsort->() } keys %$tags) {
my $tag = $tags->{$_};
my $etag = LJ::ehtml( $tag->{name} );
# keep id and value for both JS and perl
# double escape for javascript div display (so &amp; stays '&amp;')
my $value = $_ . '_' . LJ::ehtml( $etag );
$ret .= "<option class='level$tag->{histogram_group}' ";
$ret .= "value='$value'>$etag</option>";
}
$ret .= "</select>";
$ret .= "<div class='tagsort'>";
$ret .= $GET{sort} eq 'use' ? BML::ml('.sort.a', { aopts => "href='$LJ::SITEROOT/manage/tags.bml?authas=$u->{user}&sort=alpha'" }) :
BML::ml('.sort.b', { aopts => "href='$LJ::SITEROOT/manage/tags.bml?authas=$u->{user}&sort=use'" });
$ret .= '</div>';
} else {
$ret .= "<div class='taginfo'>$ML{'.none'}</div>"
}
$ret .= '<div style="margin-top: 10px">';
$ret .= LJ::html_text(
{
name => 'add_field',
size => 20,
style => 'width: 260px',
class => 'tagfield',
value => LJ::did_post() ? "" : $add_text,
onClick => "reset_field(this, '$add_text')",
}
);
$ret .= '&nbsp;';
$ret .= "<input type='image' name='add' src='/img/rte/post_button_text_larger.gif'
border='0' align='middle' title='$mo->{create}'
onClick='return validate_input(this, \"add_field\", \"$add_text\")'>";
$ret .= '
</div>
</div>
</fieldset>
</td>
<td valign="top">';
unless ($tagcount) {
$ret .= '&nbsp;</td></tr></table></form>';
return $ret;
}
$ret .= "<fieldset><legend>$ML{'.label.tags'}</legend>";
$ret .= '<div style="padding-top: 6px;">';
$ret .= "<div id='selected_tags'>&nbsp;</div>";
$ret .= "<div style='white-space: nowrap'>";
$ret .= LJ::html_text(
{
name => 'rename_field',
size => 30,
class => 'tagfield',
onClick => 'reset_field(this)',
}
);
$ret .= $sp;
$ret .= LJ::html_submit(
'rename', $ML{'.button.rename'},
{
class => 'btn',
title => $mo->{rename},
onClick => 'return validate_input(this, "rename_field")',
}
);
$ret .= '<br /><br />';
my $del_conf = $ML{'.confirm.delete'};
$ret .= LJ::html_submit(
'delete', $ML{'.button.delete'},
{
class => 'btn',
title => $mo->{delete},
onClick => "return confirm('$del_conf')",
}
) . $sp;
$ret .= LJ::html_submit(
'show posts', $ML{'.button.show'},
{
class => 'btn',
title => $mo->{entries},
}
);
$ret .= '</div><br /><div id="tag_props">&nbsp;</div>';
$ret .= '
</div>
</fieldset>
</td></tr></table>
</form>
';
return $ret;
} _code?>
<=body
head<=
<link rel='stylesheet' type='text/css' href='/styles/tags.css' />
<script type="text/javascript" src="/js/tags.js"></script>
<=head
bodyopts=>onLoad="initTagPage()"
page?>