• R/O
  • HTTP
  • SSH
  • HTTPS

newslash: Commit

newslash


Commit MetaInfo

Revisiónd1d8eecbe0eedeeb9498777c7924253e781f407a (tree)
Tiempo2019-02-01 19:28:58
Autorhylom <hylom@user...>
Commiterhylom

Log Message

fix and inregrate text formatting functions

Cambiar Resumen

Diferencia incremental

--- a/src/newslash_web/lib/Newslash/Plugin/NewslashHelpers.pm
+++ b/src/newslash_web/lib/Newslash/Plugin/NewslashHelpers.pm
@@ -8,16 +8,122 @@ use DateTime::Format::MySQL;
88 use DateTime::Format::ISO8601;
99 use Data::Dumper;
1010
11+use Newslash::Util::TextFormatter;
12+
13+=encoding utf8
14+
15+=head1 NAME
16+
17+Newslash::Plugin::NewslashHelper - Newslash helpers plugin
18+
19+=head1 SYNOPSIS
20+
21+ # Mojolicious
22+ $app->plugin('Newslash::Plugin::NewslashHelpers');
23+
24+=head1 DESCRIPTION
25+
26+L<Newslash::Plugin::NewslashHelpers> is collection of helpers for L<Newslash>.
27+
28+
29+=head1 METHODS
30+
31+=head2 register
32+
33+ $plugin->register(Mojolicious->new);
34+
35+Register helpers in L<Mojolicious> application.
36+
37+=cut
38+
1139 sub register {
1240 my ($self, $app, $conf) = @_;
1341 $self->{app} = $app;
1442
1543 for my $k (qw[boxes format_timestamp page_type content_type site_config
16- declare insert_code]) {
44+ declare insert_code
45+ tidy_html clean_html escape_html escape_title escape_plaintext strip_by_mode
46+ ]) {
1747 $app->helper($k => $self->can("_$k"))
1848 }
1949 }
2050
51+=head1 HELPERS
52+
53+L<Mojolicious::Plugin::NewslashHelpers> implements the following helpers.
54+
55+=head2 tidy_html($html)
56+
57+ tidy HTML, then returns result.
58+
59+=cut
60+
61+sub _tidy_html {
62+ my ($c, $html) = @_;
63+ return Newslash::Util::TextFormatter::tidy_html($html);
64+}
65+
66+=head2 escape_html($html)
67+
68+ escape HTML, then returns result.
69+
70+=cut
71+
72+sub _escape_html {
73+ my ($c, $html) = @_;
74+ my $allowed = $c->app->config->{Editor}->{allowed_tags};
75+ return Newslash::Util::TextFormatter::escape_html($allowed, $html);
76+}
77+
78+=head2 clean_html($html, $type)
79+
80+ escape and tidy HTML, then returns result.
81+
82+=cut
83+
84+sub _clean_html {
85+ my ($c, $html, $type) = @_;
86+ my $allowed = $c->app->config->{Editor}->{allowed_tags};
87+ return Newslash::Util::TextFormatter::clean_html($allowed, $html);
88+}
89+
90+=head2 escape_plaintext($text)
91+
92+ escape plaintext, then returns result.
93+
94+=cut
95+
96+sub _escape_plaintext {
97+ my ($c, $text) = @_;
98+ return Newslash::Util::TextFormatter::escape_plaintext($text);
99+}
100+
101+=head2 escape_title($text)
102+
103+ escape title, then returns result.
104+
105+=cut
106+
107+sub _escape_title {
108+ my ($c, $text) = @_;
109+ return Newslash::Util::TextFormatter::escape_plaintext($text);
110+}
111+
112+=head2 strip_by_mode($html, $post_type)
113+
114+ strip HTML, then returns result.
115+
116+=cut
117+
118+sub _strip_by_mode {
119+ my ($c, $html, $post_type) = @_;
120+ my $allowed = $c->app->config->{Editor}->{allowed_tags};
121+ return Newslash::Util::TextFormatter::strip_by_mode($html, $post_type, $allowed);
122+}
123+
124+######################################################################
125+#
126+
21127 use constant MARKERS => qw(begin_footer);
22128 my $marker_contents = {};
23129
@@ -36,6 +142,7 @@ sub _declare {
36142 return join("\n", @$contents);
37143 }
38144
145+
39146 sub _generate_site_config {
40147 my $c = shift;
41148 my $epoch = $c->stash('epoch');
@@ -114,6 +221,14 @@ sub _content_type {
114221 return;
115222 }
116223
224+=head2 boxes
225+
226+ [% helpers.boxes() %]
227+
228+Fetch box contents for current user and returns them.
229+
230+=cut
231+
117232 sub _boxes {
118233 my $c = shift;
119234 my $user = $c->stash("user");
@@ -188,6 +303,15 @@ sub _get_sidebar_item {
188303
189304 }
190305
306+=head2 format_timestamp
307+
308+ $c->format_timestamp(user => $user, epoch => $epoch, format => "user")
309+ $c->format_timestamp(datetime => $dt, format => "simple")
310+
311+Return formated string.
312+
313+=cut
314+
191315 sub _format_timestamp {
192316 my $c = shift;
193317 my $params = {};
@@ -244,47 +368,6 @@ sub _format_timestamp {
244368
245369 1;
246370
247-=encoding utf8
248-
249-=head1 NAME
250-
251-Newslash::Plugin::NewslashHelper - Newslash helpers plugin
252-
253-=head1 SYNOPSIS
254-
255- # Mojolicious
256- $app->plugin('Newslash::Plugin::NewslashHelpers');
257-
258-=head1 DESCRIPTION
259-
260-L<Newslash::Plugin::NewslashHelpers> is collection of helpers for L<Newslash>.
261-
262-
263-=head1 HELPERS
264-
265-L<Mojolicious::Plugin::NewslashHelpers> implements the following helpers.
266-
267-=head2 boxes
268-
269- [% helpers.boxes() %]
270-
271-Fetch box contents for current user and returns them.
272-
273-=head2 format_timestamp
274-
275- $c->format_timestamp(user => $user, epoch => $epoch, format => "user")
276- $c->format_timestamp(datetime => $dt, format => "simple")
277-
278-Return formated string.
279-
280-=head1 METHODS
281-
282-=head2 register
283-
284- $plugin->register(Mojolicious->new);
285-
286-Register helpers in L<Mojolicious> application.
287-
288371 =head1 SEE ALSO
289372
290373 L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicious.org>.
--- a/src/newslash_web/lib/Newslash/Util/TextFormatter.pm
+++ b/src/newslash_web/lib/Newslash/Util/TextFormatter.pm
@@ -10,12 +10,10 @@ use utf8;
1010 use feature ':5.10';
1111
1212 use Exporter 'import';
13-
1413 our @EXPORT_OK = qw(strip_by_mode);
1514
1615 use EscapeHTML qw();
1716 use HTML::Tidy;
18-use Encode;
1917 use Data::Dumper;
2018
2119 use constant ANCHOR => -4;
@@ -28,7 +26,6 @@ use constant HTML => 2;
2826 use constant EXTRANS => 3;
2927 use constant CODE => 4;
3028
31-
3229 use constant APPROVED_URL_SCHEMES_REGEX => qr/(?-xism:(?:ftp|http|gopher|mailto|news|nntp|telnet|wais|https))/;
3330
3431 #========================================================================
@@ -483,8 +480,6 @@ sub strip_by_mode {
483480 for my $action (@actions) {
484481 $actions{$action}->(\$str, $fmode, $opts);
485482 }
486- # check utf8 flags
487- #$str = Encode::is_utf8($str) ? $str : decode_utf8($str);
488483 return $str;
489484 }
490485
@@ -498,41 +493,57 @@ sub strip_code {
498493 return strip_by_mode(shift, CODE);
499494 }
500495
501-# sub strip_anchor { stripByMode($_[0], ANCHOR, @_[1 .. $#_]) }
502-# sub strip_attribute { stripByMode($_[0], ATTRIBUTE, @_[1 .. $#_]) }
503-# sub strip_code { stripByMode($_[0], CODE, @_[1 .. $#_]) }
504-# sub strip_extrans { stripByMode($_[0], EXTRANS, @_[1 .. $#_]) }
505-# sub strip_html { stripByMode($_[0], HTML, @_[1 .. $#_]) }
506-# sub strip_literal { stripByMode($_[0], LITERAL, @_[1 .. $#_]) }
507-# sub strip_nohtml { stripByMode($_[0], NOHTML, @_[1 .. $#_]) }
508-# sub strip_notags { stripByMode($_[0], NOTAGS, @_[1 .. $#_]) }
509-# sub strip_plaintext { stripByMode($_[0], PLAINTEXT, @_[1 .. $#_]) }
510-
511-
512-
513-#======================================================================
514-
515-=head2 tidy_html($html)
516-
517-tidy HTML
518-
519-=over 4
520-
521-=item Parameters
522-
523-=over 4
496+sub contextual_strip {
497+ my ($text, $max_chars, $min_chars) = @_;
498+ return if !$text;
499+ return if !$max_chars;
500+ $min_chars ||= 0;
524501
525-=item $html
502+ # split by "。"
503+ my @tmp = split(/(。)/, $text);
504+ my @sentences;
505+ my $prev;
506+ for my $s (@tmp) {
507+ if ($s eq "。") {
508+ $prev = $prev . $s;
509+ } else {
510+ push @sentences, $prev if $prev;
511+ $prev = $s;
512+ }
513+ }
514+ push @sentences, $prev;
526515
527-input HTML
516+ my $result = "";
517+ if (@sentences == 0) {
518+ $result = $text;
519+ }
520+ elsif (@sentences == 1) {
521+ $result = $sentences[0];
522+ }
523+ else {
524+ for my $sentence (@sentences) {
525+ my $tmp = $result . $sentence;
526+ if (length($tmp) > $max_chars) {
527+ last if (length($tmp) > $min_chars);
528+ $result = $tmp;
529+ last;
530+ }
531+ $result = $tmp;
532+ }
533+ }
534+ if (length($result) > $max_chars) {
535+ $result = substr($result, 0, $max_chars);
536+ $result = $result . " ...";
537+ }
528538
529-=back
539+ return $result;
540+}
530541
531-=item Return value
542+=head1 FUNCTIONS
532543
533-tidied HTML
544+=head2 tidy_html($html)
534545
535-=back
546+ tidy HTML, then returns result.
536547
537548 =cut
538549
@@ -543,35 +554,24 @@ sub tidy_html {
543554 doctype => 'omit',
544555 'show-body-only' => 1,
545556 } );
546- my $tidied = $tidy->clean($html);
547- return $tidied;
557+ my $tidyed = $tidy->clean($html);
558+ return $tidyed;
548559 }
549560
550-=head2 clean_html(\%allowed, $html)
551-
552-escape and tidy HTML
553-
554-=over 4
555-
556-=item Parameters
557-
558-=over 4
559-
560-=item $html
561-
562-input HTML
563-
564-=item \%allowed
561+=head2 escape_html(\%allowed, $html)
565562
566-allowed tag and attribute
563+ escape HTML, then returns result.
567564
568-=back
565+=cut
569566
570-=item Return value
567+sub escape_html {
568+ my ($allowed, $html) = @_;
569+ return EscapeHTML::escape($allowed, $html);
570+}
571571
572-tidied HTML
572+=head2 clean_html(\%allowed, $html)
573573
574-=back
574+ escape and tidy HTML, then returns result.
575575
576576 =cut
577577
@@ -585,66 +585,14 @@ sub clean_html {
585585 doctype => 'omit',
586586 'show-body-only' => 1,
587587 } );
588- my $tidied = $tidy->clean($escaped);
589- return $tidied;
588+ my $tidyed = $tidy->clean($escaped);
589+ chomp($tidyed);
590+ return $tidyed;
590591 }
591592
592-
593-=head2 escape_html(\%allowed, $html)
594-
595-escape HTML
596-
597-=over 4
598-
599-=item Parameters
600-
601-=over 4
602-
603-=item $html
604-
605-input HTML
606-
607-=item \%allowed
608-
609-allowed tag and attribute
610-
611-=back
612-
613-=item Return value
614-
615-escaped HTML
616-
617-=back
618-
619-=cut
620-
621-sub escape_html {
622- my ($allowed, $html) = @_;
623- return EscapeHTML::escape($allowed, $html);
624-}
625-
626-
627593 =head2 escape_plaintext($text)
628594
629-escape HTML
630-
631-=over 4
632-
633-=item Parameters
634-
635-=over 4
636-
637-=item $text
638-
639-input plain text
640-
641-=back
642-
643-=item Return value
644-
645-escaped text
646-
647-=back
595+ escape plaintext, then returns result.
648596
649597 =cut
650598
@@ -658,51 +606,5 @@ sub escape_plaintext {
658606 return $text;
659607 }
660608
661-sub contextual_strip {
662- my ($text, $max_chars, $min_chars) = @_;
663- return if !$text;
664- return if !$max_chars;
665- $min_chars ||= 0;
666-
667- # split by "。"
668- my @tmp = split(/(。)/, $text);
669- my @sentences;
670- my $prev;
671- for my $s (@tmp) {
672- if ($s eq "。") {
673- $prev = $prev . $s;
674- } else {
675- push @sentences, $prev if $prev;
676- $prev = $s;
677- }
678- }
679- push @sentences, $prev;
680-
681- my $result = "";
682- if (@sentences == 0) {
683- $result = $text;
684- }
685- elsif (@sentences == 1) {
686- $result = $sentences[0];
687- }
688- else {
689- for my $sentence (@sentences) {
690- my $tmp = $result . $sentence;
691- if (length($tmp) > $max_chars) {
692- last if (length($tmp) > $min_chars);
693- $result = $tmp;
694- last;
695- }
696- $result = $tmp;
697- }
698- }
699- if (length($result) > $max_chars) {
700- $result = substr($result, 0, $max_chars);
701- $result = $result . " ...";
702- }
703-
704- return $result;
705-}
706-
707609 1;
708610
--- a/src/newslash_web/lib/Newslash/Web/Controller/API/Comment.pm
+++ b/src/newslash_web/lib/Newslash/Web/Controller/API/Comment.pm
@@ -22,15 +22,13 @@ sub post {
2222
2323 my $comments = $c->model('comments');
2424 my $discussions = $c->model('discussions');
25- my $util = $c->model('util');
2625
2726 my $conf = $c->config->{Comments} || {};
28- my $allowed_tags = $conf->{allowed_tags} || {};
2927 my $data = $c->req->json;
3028 my $message = "";
3129
32- $params->{title} = $util->escape_html({}, $data->{title});
33- $params->{comment} = $util->clean_html($allowed_tags, $data->{comment});
30+ $params->{title} = $c->escape_title($data->{title});
31+ $params->{comment} = $c->clean_html($data->{comment}, "comment");
3432 $params->{discussion_id} = $data->{discussion_id};
3533 $params->{stoid} = $data->{stoid};
3634 $params->{pid} = $data->{pid};
--- a/src/newslash_web/lib/Newslash/Web/Controller/API/Journal.pm
+++ b/src/newslash_web/lib/Newslash/Web/Controller/API/Journal.pm
@@ -63,15 +63,12 @@ sub post {
6363
6464 my $journals = $c->model('journals');
6565 my $users = $c->model('users');
66- my $util = $c->model('util');
67-
68- my $allowed = $c->app->config->{Editor}->{allowed_tags};
6966
7067 my $data = $c->req->json;
7168 my $item = $data->{item};
7269 my $message = "";
7370
74- $params->{description} = $util->escape_html({}, $item->{title});
71+ $params->{description} = $c->escape_title($item->{title});
7572 $message = "no title!" if !$params->{description};
7673
7774 # check user is valid
@@ -120,12 +117,10 @@ sub post {
120117
121118 if ($data->{action} eq 'preview') {
122119 if ($item->{formatter} && $item->{formatter} eq 'legacy') {
123- $item->{introtext} = Newslash::Util::TextFormatter::strip_by_mode($params->{article},
124- $params->{posttype},
125- allowed_tags => $allowed);
120+ $item->{introtext} = $c->strip_by_mode($params->{article}, $params->{posttype});
126121 }
127122 else {
128- $item->{introtext} = $util->clean_html($allowed, $params->{article});
123+ $item->{introtext} = $c->clean_html($params->{article}, "journal");
129124 }
130125 $item->{intro_text} = $item->{intro_text};
131126 $item->{title} = $params->{description};
--- a/src/newslash_web/lib/Newslash/Web/Controller/API/Story.pm
+++ b/src/newslash_web/lib/Newslash/Web/Controller/API/Story.pm
@@ -50,10 +50,8 @@ sub post {
5050 my $stories = $c->model('stories');
5151 my $users = $c->model('users');
5252 my $topics = $c->model('topics');
53- my $util = $c->model('util');
5453 my $submissions = $c->model('submissions');
5554
56- my $allowed = $c->app->config->{Editor}->{allowed_tags};
5755 my $data = $c->req->json;
5856 my $item = $data->{item};
5957 my $message = "";
@@ -67,7 +65,7 @@ sub post {
6765 # client send data like this:
6866 # {"item":{"title":"ほげ","introtext":"ほんぶん","bodytext":"","createtime":"2017-06-30T21:50:04","author":"hylom","dept":"テスト","commentstatus":"enabled","submissioncopy":0,"url":"","email":"","tags_string":"news","related_urls":"http://sdtest.osdn.co.jp:3000/story/16/01/28/0610215/"},"action":"preview"}
6967
70- $params->{title} = $util->escape_html({}, $item->{title});
68+ $params->{title} = $c->escape_plaintext($item->{title});
7169 $message = "no_title" if !$params->{title};
7270
7371 # convert time
@@ -94,14 +92,14 @@ sub post {
9492
9593 # check: introtext exists ?
9694 my $intro_text = $item->{intro_text} || $item->{introtext} || "";
97- $params->{introtext} = $util->clean_html($allowed, $intro_text);
95+ $params->{introtext} = $c->clean_html($intro_text, "story");
9896 if (!$params->{introtext}) {
9997 $message = "introtext_not_given";
10098 }
10199
102100 # bodytext (omittable)
103101 my $body_text = $item->{body_text} || $item->{bodytext} || "";
104- $params->{bodytext} = $util->clean_html($allowed, $body_text);
102+ $params->{bodytext} = $c->clean_html($body_text, "story");
105103
106104 # TODO: related urls
107105 #$params->{add_related} = $item->{add_related} || $item->{related_urls} || "";
@@ -153,7 +151,7 @@ sub post {
153151 $params->{stoid} = $item->{stoid};
154152 my $rs = $stories->update(user => $user, %$params);
155153 $stoid = $rs ? $item->{stoid} : 0;
156- $sid = $item->{sid} : 0;
154+ $sid = $rs ? $item->{sid} : 0;
157155 }
158156 else {
159157 # create story
--- a/src/newslash_web/lib/Newslash/Web/Controller/API/Submission.pm
+++ b/src/newslash_web/lib/Newslash/Web/Controller/API/Submission.pm
@@ -82,9 +82,7 @@ sub post {
8282 }
8383
8484 my $submissions = $c->model('submissions');
85- my $util = $c->model('util');
8685
87- my $allowed = $c->app->config->{Editor}->{allowed_tags};
8886 my $data = $c->req->json;
8987 my $item = $data->{item};
9088 my $message = "";
@@ -93,7 +91,7 @@ sub post {
9391 if ($item->{introtext} || $item->{intro_text}) {
9492 my $text = $item->{introtext} || $item->{intro_text};
9593 $text =~ s/\s+\z//m;
96- $params->{introtext} = $util->clean_html($allowed, $text);
94+ $params->{introtext} = $c->clean_html($text, "submission");
9795 $params->{introtext} =~ s/\s+\z//m;
9896 }
9997 else {
@@ -102,7 +100,7 @@ sub post {
102100 $message = "no_content" if (!$params->{introtext} && !$item->{url});
103101
104102 # check title
105- $params->{title} = $util->escape_html({}, $item->{title});
103+ $params->{title} = $c->escape_title($item->{title});
106104 $message = "no_title" if !$params->{title};
107105
108106 # check URL
--- a/src/newslash_web/t/api/story.t
+++ b/src/newslash_web/t/api/story.t
@@ -6,33 +6,46 @@ use Mojo::Date;
66 use Test::More;
77 use Test::Mojo;
88 use Data::Dumper;
9-use Newslash::Util::Test qw(create_admin_user create_user delete_user);
9+use Newslash::Util::TestMan;
1010
1111 use POSIX qw(strftime);
1212
1313 my $t = Test::Mojo->new('Newslash::Web');
14+my $test_man = Newslash::Util::TestMan->new($t);
15+my $admin;
1416
1517 if ($t->app->mode eq 'test') {
16- my $user = create_admin_user($t->app, "test01", "foobar");
17- ok($user, "create test user");
18+ $admin = $test_man->create_admin("story_test", "foobar");
1819 }
1920
2021 SKIP: {
2122 skip "mode is not 'test'", 4 if ($t->app->mode ne 'test');
22-
23- $t->post_ok('/login' => {Accept => '*/*'} => form => {nickname => 'test01', passwd => 'foobar'})
24- ->status_is(302);
23+ $test_man->login($admin);
2524
2625 subtest 'story post/update' => sub {
26+
27+ my $test_title = "テストタイトル";
28+ my $test_introtext = <<"EOT";
29+hylom 曰く、<blockquote><div><p>英国のEU離脱問題についてEUは厳しい姿勢を見せており、離脱後は英市民や英企業が.euドメイン名を取得・更新できなくなる可能性があるそうだ(<a href="https://www.theregister.co.uk/2019/01/07/brit_eu_domain_owners/">The Registerの記事</a>、
30+<a href="https://www.forbes.com/sites/annatobin/2019/01/09/brits-could-be-locked-out-of-their-eu-domain-names-after-brexit/">Forbesの記事</a>)。
31+<br> <br>
32+
33+現在英国とEUは離脱条件について議論を進めているが、3月29日までに両者が同意せず「合意なしでの離脱」に至った場合、英市民や他のEU域内に拠点を持たない英企業は.euドメインの利用資格を失う。既存のドメインが即座に失効することはないようだが、ドメイン名の更新や新規ドメイン名登録はできなくなる。そのため、英国政府はそういった事態に備えて.comや.co.ukドメインを取得しておくようアドバイスを行っているという。
34+<br> <br>
35+
36+英国内では.ukドメインの利用が多いものの、英市民・企業が登録した.euドメインは登録済み.euドメインの10%近くを占めるとのことで、影響は少なくないようだ。</p></div></blockquote>
37+EOT
38+ my $tidyed_introtext = $t->app->clean_html($test_introtext);
39+ my $test_dept = "テストdept";
2740 my $createtime = strftime('%FT%T', gmtime);
2841 my $test_data = {
2942 action => 'preview',
3043 item => {
31- title => "テストストーリー",
44+ title => $test_title,
3245 createtime => $createtime,
33- author => "test01",
34- dept => "テストdept",
35- introtext => "テスト本文\nてすとてすと",
46+ author => $admin->{nickname},
47+ dept => $test_dept,
48+ introtext => $test_introtext,
3649 bodytext => "",
3750 add_related => "",
3851 url => "",
@@ -48,7 +61,7 @@ SKIP: {
4861 $t->post_ok('/api/v1/story' => {Accept => '*/*'} => json => $test_data)
4962 ->status_is(200)
5063 ->json_has('/item')
51- ->json_is('/item/title' => "テストストーリー");
64+ ->json_is('/item/title' => $test_title);
5265 diag $t->tx->res->json->{message} if $t->tx->res->json && $t->tx->res->code != 200;
5366
5467 # create
@@ -66,7 +79,10 @@ SKIP: {
6679 $t->get_ok("/api/v1/story?stoid=$stoid")
6780 ->status_is(200)
6881 ->json_has('/item')
69- ->json_is('/item/stoid', $stoid);
82+ ->json_is('/item/stoid', $stoid)
83+ ->json_is('/item/title', $test_title)
84+ ->json_is('/item/intro_text', $tidyed_introtext)
85+ ->json_is('/item/dept', $test_dept);
7086 diag "message: " . $t->tx->res->json("/message") if $t->tx->res->code != 200;
7187
7288 # update
@@ -86,13 +102,11 @@ SKIP: {
86102 ->json_has('/item')
87103 ->json_is('/item/stoid', $stoid)
88104 ->json_is('/item/title', $new_title);
89- };
90105
91- $t->get_ok('/logout')->status_is(302);
92-}
106+ };
93107
94-if ($t->app->mode eq 'test') {
95- delete_user($t->app, "test01");
108+ $test_man->logout;
96109 }
97110
111+$test_man->cleanup;
98112 done_testing();
Show on old repository browser