|
@@ -190,7 +190,12 @@ our %routes = (
|
|
|
method => 'GET',
|
|
method => 'GET',
|
|
|
callback => \&Trog::Routes::HTML::posts,
|
|
callback => \&Trog::Routes::HTML::posts,
|
|
|
data => { format => 'rss' },
|
|
data => { format => 'rss' },
|
|
|
- }
|
|
|
|
|
|
|
+ },
|
|
|
|
|
+ '/emoji' => {
|
|
|
|
|
+ method => 'GET',
|
|
|
|
|
+ callback => \&Trog::Routes::HTML::emojis,
|
|
|
|
|
+ auth => 1,
|
|
|
|
|
+ },
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
# Grab theme routes
|
|
# Grab theme routes
|
|
@@ -944,7 +949,10 @@ sub posts ( $query, $direct = 0 ) {
|
|
|
# Set the eTag so that we don't get a re-fetch
|
|
# Set the eTag so that we don't get a re-fetch
|
|
|
$query->{etag} = "$posts[0]{id}-$posts[0]{version}" if @posts;
|
|
$query->{etag} = "$posts[0]{id}-$posts[0]{version}" if @posts;
|
|
|
|
|
|
|
|
- return _rss( $query, \@posts ) if $fmt eq 'rss';
|
|
|
|
|
|
|
+ #Correct page headers
|
|
|
|
|
+ my $ph = $themed ? _themed_title( $query->{route} ) : $query->{route};
|
|
|
|
|
+
|
|
|
|
|
+ return _rss( $query, $ph, \@posts ) if $fmt eq 'rss';
|
|
|
|
|
|
|
|
#XXX Is used by the sitemap, maybe just fix there?
|
|
#XXX Is used by the sitemap, maybe just fix there?
|
|
|
my @post_aliases = map { $_->{local_href} } _get_series();
|
|
my @post_aliases = map { $_->{local_href} } _get_series();
|
|
@@ -959,9 +967,6 @@ sub posts ( $query, $direct = 0 ) {
|
|
|
|
|
|
|
|
my $styles = _build_themed_styles('posts.css');
|
|
my $styles = _build_themed_styles('posts.css');
|
|
|
|
|
|
|
|
- #Correct page headers
|
|
|
|
|
- my $ph = $themed ? _themed_title( $query->{route} ) : $query->{route};
|
|
|
|
|
-
|
|
|
|
|
# Build page title if it wasn't set by a wrapping sub
|
|
# Build page title if it wasn't set by a wrapping sub
|
|
|
$query->{title} = "$query->{domain} : $query->{title}" if $query->{title} && $query->{domain};
|
|
$query->{title} = "$query->{domain} : $query->{title}" if $query->{title} && $query->{domain};
|
|
|
$query->{title} ||= @$tags && $query->{domain} ? "$query->{domain} : @$tags" : undef;
|
|
$query->{title} ||= @$tags && $query->{domain} ? "$query->{domain} : @$tags" : undef;
|
|
@@ -1258,12 +1263,13 @@ sub sitemap ($query) {
|
|
|
return Trog::Routes::HTML::index( $query, $content, $styles );
|
|
return Trog::Routes::HTML::index( $query, $content, $styles );
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-sub _rss ( $query, $posts ) {
|
|
|
|
|
|
|
+sub _rss ( $query, $subtitle, $posts ) {
|
|
|
require XML::RSS;
|
|
require XML::RSS;
|
|
|
my $rss = XML::RSS->new( version => '2.0', stylesheet => '/styles/rss-style.xsl' );
|
|
my $rss = XML::RSS->new( version => '2.0', stylesheet => '/styles/rss-style.xsl' );
|
|
|
my $now = DateTime->from_epoch( epoch => time() );
|
|
my $now = DateTime->from_epoch( epoch => time() );
|
|
|
$rss->channel(
|
|
$rss->channel(
|
|
|
title => "$query->{domain}",
|
|
title => "$query->{domain}",
|
|
|
|
|
+ subtitle => $subtitle,
|
|
|
link => "http://$query->{domain}/$query->{route}.rss.xml",
|
|
link => "http://$query->{domain}/$query->{route}.rss.xml",
|
|
|
language => 'en', #TODO localization
|
|
language => 'en', #TODO localization
|
|
|
description => "$query->{domain} : $query->{route}",
|
|
description => "$query->{domain} : $query->{route}",
|
|
@@ -1294,9 +1300,9 @@ sub _rss ( $query, $posts ) {
|
|
|
undef,
|
|
undef,
|
|
|
{
|
|
{
|
|
|
etag => $query->{etag},
|
|
etag => $query->{etag},
|
|
|
- contenttype => "application/rss+xml",
|
|
|
|
|
|
|
+ contenttype => "application/xml",
|
|
|
body => encode_utf8( $rss->as_string ),
|
|
body => encode_utf8( $rss->as_string ),
|
|
|
- scheme => $query->{scheme}
|
|
|
|
|
|
|
+ scheme => $query->{scheme},
|
|
|
},
|
|
},
|
|
|
'Content-Disposition' => 'inline; filename="rss.xml"',
|
|
'Content-Disposition' => 'inline; filename="rss.xml"',
|
|
|
);
|
|
);
|
|
@@ -1426,12 +1432,16 @@ sub themed_render ( $template, $data ) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
sub _pick_processor ( $file, $normal, $themed ) {
|
|
sub _pick_processor ( $file, $normal, $themed ) {
|
|
|
- return _dir_for_resource($file) eq $template_dir ? $normal : $themed;
|
|
|
|
|
|
|
+ return _template_dir($file) eq $template_dir ? $normal : $themed;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+sub _template_dir ($template) {
|
|
|
|
|
+ return $theme_dir && -f "www/$theme_dir/$template" ? $theme_dir : $template_dir;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
# Pick appropriate dir based on whether theme override exists
|
|
# Pick appropriate dir based on whether theme override exists
|
|
|
sub _dir_for_resource ($resource) {
|
|
sub _dir_for_resource ($resource) {
|
|
|
- return $theme_dir && -f "www/$theme_dir/$resource" ? $theme_dir : $template_dir;
|
|
|
|
|
|
|
+ return $theme_dir && -f "www/$theme_dir/$resource" ? $theme_dir : '';
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
sub _themed_style ($resource) {
|
|
sub _themed_style ($resource) {
|
|
@@ -1487,9 +1497,9 @@ sub finish_render ( $template, $vars, %headers ) {
|
|
|
$headers{'Referrer-Policy'} = 'no-referrer-when-downgrade';
|
|
$headers{'Referrer-Policy'} = 'no-referrer-when-downgrade';
|
|
|
|
|
|
|
|
#CSP. Yet another layer of 'no mixed content' plus whitelisted execution of remote resources.
|
|
#CSP. Yet another layer of 'no mixed content' plus whitelisted execution of remote resources.
|
|
|
- my $scheme = $vars->{scheme} ? $vars->{scheme} : '';
|
|
|
|
|
|
|
+ my $scheme = $vars->{scheme} ? "$vars->{scheme}:" : '';
|
|
|
my $sites = $conf->param('security.allow_embeds_from') // '';
|
|
my $sites = $conf->param('security.allow_embeds_from') // '';
|
|
|
- $headers{'Content-Security-Policy'} .= ";default-src '$scheme' 'self' 'unsafe-eval' 'unsafe-inline' $sites";
|
|
|
|
|
|
|
+ $headers{'Content-Security-Policy'} .= ";default-src $scheme 'self' 'unsafe-eval' 'unsafe-inline' $sites";
|
|
|
$headers{'Content-Security-Policy'} .= ";object-src 'none'";
|
|
$headers{'Content-Security-Policy'} .= ";object-src 'none'";
|
|
|
|
|
|
|
|
# Force https if we are https
|
|
# Force https if we are https
|
|
@@ -1542,6 +1552,8 @@ sub icon ($query) {
|
|
|
|
|
|
|
|
# TODO make statics, abstract gzipped outputting & header handling
|
|
# TODO make statics, abstract gzipped outputting & header handling
|
|
|
sub rss_style ($query) {
|
|
sub rss_style ($query) {
|
|
|
|
|
+ $query->{port} = ":$query->{port}" if $query->{port};
|
|
|
|
|
+ $query->{rss_css} = _themed_style("rss.css");
|
|
|
my $body = encode_utf8(themed_render('rss-style.tx', $query));
|
|
my $body = encode_utf8(themed_render('rss-style.tx', $query));
|
|
|
my %headers = (
|
|
my %headers = (
|
|
|
'Content-Type' => 'text/xsl',
|
|
'Content-Type' => 'text/xsl',
|
|
@@ -1561,4 +1573,19 @@ sub rss_style ($query) {
|
|
|
return [ 200, [%headers], [$dfh] ];
|
|
return [ 200, [%headers], [$dfh] ];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+sub emojis ($query) {
|
|
|
|
|
+ my $file = 'www/scripts/list.min.json';
|
|
|
|
|
+ die "Run make prereq-frontend first" unless -f $file;
|
|
|
|
|
+
|
|
|
|
|
+ my $raw = File::Slurper::read_binary($file);
|
|
|
|
|
+ my $emojis = Cpanel::JSON::XS::decode_json($raw);
|
|
|
|
|
+ my %categorized;
|
|
|
|
|
+ foreach my $emoji (@{$emojis->{emojis}}) {
|
|
|
|
|
+ $categorized{$emoji->{category}} //= [];
|
|
|
|
|
+ push(@{$categorized{$emoji->{category}}}, $emoji->{emoji});
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return finish_render('emojis.tx', { %$query, categories => \%categorized, scripts => _build_themed_scripts('emoji.js') });
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
1;
|
|
1;
|