| | 146 | sub files_from_response { |
| | 147 | my ($res, %param) = @_; |
| | 148 | |
| | 149 | my $extensions = $param{css} ? qr{ (?:gif|jpe?g|png|css) }xms |
| | 150 | : qr{ (?:gif|jpe?g|png) }xms |
| | 151 | ; |
| | 152 | |
| | 153 | my $stylesheet = $res->content; |
| | 154 | $stylesheet =~ s!/\*.*?\*/!!gs; # strip all comments first |
| | 155 | my @images = $stylesheet =~ m{ |
| | 156 | \b url\( \s* # opening url() reference |
| | 157 | ['"]? |
| | 158 | ( [\w\.\-/]+\.$extensions ) # a filename ending in an image extension |
| | 159 | ['"]? |
| | 160 | \s* \) # close of url() reference |
| | 161 | }xmsgi; |
| | 162 | |
| | 163 | return @images; |
| | 164 | } |
| | 165 | |
| | 166 | sub download_theme { |
| | 167 | my $app = shift; |
| | 168 | my ($url) = @_; |
| | 169 | |
| | 170 | my $static_path = $app->static_file_path; |
| | 171 | my $themeroot = File::Spec->catdir($static_path, 'support', 'themes'); |
| | 172 | my $ua = $app->new_ua(); |
| | 173 | my $filemgr = file_mgr() |
| | 174 | or return; |
| | 175 | |
| | 176 | my @url = split( /\//, $url ); |
| | 177 | my $stylesheet_filename = pop @url; |
| | 178 | my $theme_url = join(q{/}, @url) . '/'; |
| | 179 | |
| | 180 | my ($basename, $extension) = split /\./, $stylesheet_filename; |
| | 181 | if ($basename eq 'screen' || $basename eq 'style') { |
| | 182 | $basename = $url[-1]; |
| | 183 | } |
| | 184 | |
| | 185 | # Pick up the stylesheet |
| | 186 | my $stylesheet_res = $ua->get($url); |
| | 187 | |
| | 188 | my @images = files_from_response($stylesheet_res, css => 1); |
| | 189 | |
| | 190 | my $theme_path = File::Spec->catdir($themeroot, $basename); |
| | 191 | if (!$filemgr->mkpath($theme_path)) { |
| | 192 | my $error = $app->translate("Could not create [_1] folder - Check that your 'themes' folder is webserver-writable.", |
| | 193 | $basename); |
| | 194 | return $app->json_error($error); |
| | 195 | } |
| | 196 | |
| | 197 | $filemgr->put_data( $stylesheet_res->content, |
| | 198 | File::Spec->catfile($theme_path, $basename . '.css') ); |
| | 199 | |
| | 200 | # Pick up the images we parsed earlier and write them to the theme folder |
| | 201 | my %got_files; |
| | 202 | my @files = ('thumbnail.gif', 'thumbnail-large.gif', @images); |
| | 203 | FILE: while (my $rel_url = shift @files) { |
| | 204 | # Is this safe to get? |
| | 205 | my $full_url = URI->new_abs($rel_url, $theme_url); |
| | 206 | next FILE if !$full_url; |
| | 207 | my $url = $full_url->as_string(); |
| | 208 | next FILE if $url !~ m{ \A \Q$theme_url\E }xms; |
| | 209 | |
| | 210 | next FILE if $got_files{$url}; |
| | 211 | $got_files{$url} = 1; |
| | 212 | my $res = $ua->get($url); |
| | 213 | |
| | 214 | # Skip files that don't download; we were accidentally doing so already. |
| | 215 | next FILE if !$res->is_success(); |
| | 216 | |
| | 217 | my $canon_rel_url = URI->new($rel_url)->rel($theme_url); |
| | 218 | my @image_path = split /\//, $canon_rel_url->as_string(); |
| | 219 | my $image_filename = pop @image_path; |
| | 220 | |
| | 221 | my $image_path = File::Spec->catdir($theme_path, @image_path); |
| | 222 | if (!$filemgr->exists($image_path) && !$filemgr->mkpath($image_path)) { |
| | 223 | my $error = $app->translate("Could not create [_1] folder - Check that your 'themes' folder is webserver-writable.", |
| | 224 | $basename); |
| | 225 | return $app->json_error($error); |
| | 226 | } |
| | 227 | |
| | 228 | my $image_full_path = File::Spec->catfile($image_path, $image_filename); |
| | 229 | $filemgr->put_data($res->content, $image_full_path, 'upload') |
| | 230 | or return $app->json_error( $filemgr->errstr ); |
| | 231 | |
| | 232 | if ($image_filename =~ m{ \.css \z }xmsi) { |
| | 233 | my @new_files = files_from_response($res, css => 0); |
| | 234 | # Schedule these as full URLs so relative references aren't |
| | 235 | # misabsolved relative to the theme directory. |
| | 236 | @new_files = map { |
| | 237 | my $uri = URI->new_abs($_, $url); |
| | 238 | $uri ? $uri->as_string() : (); |
| | 239 | } @new_files; |
| | 240 | push @files, @new_files; |
| | 241 | } |
| | 242 | } |
| | 243 | |
| | 244 | return $basename; |
| | 245 | } |
| | 246 | |
| 176 | | my $filemgr = file_mgr() |
| 177 | | or return $app->json_error( MT::FileMgr->errstr ); |
| 178 | | |
| 179 | | if ( $url !~ m/^(\Q$webthemeroot\E|\Q$mtthemeroot\E)/ ) { |
| 180 | | my $new_url = ''; |
| 181 | | |
| 182 | | for (0..(scalar(@url)-2)) { |
| 183 | | $new_url .= $url[$_] . '/'; |
| 184 | | } |
| 185 | | my ( $basename, $extension ) = split( /\./, $url[-1] ); |
| 186 | | if ($basename eq 'screen') { |
| 187 | | $basename = $url[-2]; |
| 188 | | } |
| 189 | | |
| 190 | | # Pick up the stylesheet |
| 191 | | my $user_agent = $app->new_ua; |
| 192 | | my $css_request = HTTP::Request->new( GET => $url ); |
| 193 | | my $response = $user_agent->request($css_request); |
| 194 | | |
| 195 | | # Pick up the thumbnail and thumbnail-large |
| 196 | | my $thumbnail_request = |
| 197 | | HTTP::Request->new( GET => $new_url . "thumbnail.gif" ); |
| 198 | | my $thumbnail_response = $user_agent->request($thumbnail_request); |
| 199 | | my $thumbnail_large_request = |
| 200 | | HTTP::Request->new( GET => $new_url . "thumbnail-large.gif" ); |
| 201 | | my $thumbnail_large_response = |
| 202 | | $user_agent->request($thumbnail_large_request); |
| 203 | | |
| 204 | | # Parse out image filenames in the css and then write out the css file |
| 205 | | # and thumbnails to our theme folder |
| 206 | | my $content = $response->content; |
| 207 | | $content =~ s!/\*.*?\*/!!gs; # strip all comments first |
| 208 | | my @images = $content =~ |
| 209 | | m/\b(?:url\(\s*)([a-zA-Z0-9_.-]+\.(?:gif|jpe?g|png))(?:\s*?\))/gi; |
| 210 | | $filemgr->mkpath( File::Spec->catdir( $themeroot, $basename ) ) |
| 211 | | or return $app->json_error( |
| 212 | | $app->translate( |
| 213 | | "Could not create [_1] folder - Check that your 'themes' folder is webserver-writable.", |
| 214 | | $basename |
| 215 | | ) |
| 216 | | ); |
| 217 | | $filemgr->put_data( $response->content, |
| 218 | | File::Spec->catfile( $themeroot, $basename, $basename . '.css' ) ); |
| 219 | | if (($thumbnail_response->code >= 200) && ($thumbnail_response->code < 400)) { |
| 220 | | $filemgr->put_data( $thumbnail_response->content, |
| 221 | | File::Spec->catfile( $themeroot, $basename, "thumbnail.gif" ), |
| 222 | | 'upload' ); |
| 223 | | } else { |
| 224 | | return $app->json_error($app->translate("Error downloading image: [_1]", $new_url . 'thumbnail.gif')) |
| 225 | | } |
| 226 | | if (($thumbnail_large_response->code >= 200) && ($thumbnail_large_response->code < 400)) { |
| 227 | | $filemgr->put_data( |
| 228 | | $thumbnail_large_response->content, |
| 229 | | File::Spec->catfile( $themeroot, $basename, "thumbnail-large.gif" ), |
| 230 | | 'upload' |
| 231 | | ); |
| 232 | | } else { |
| 233 | | return $app->json_error($app->translate("Error downloading image: [_1]", $new_url . 'thumbnail-large.gif')) |
| 234 | | } |
| 235 | | |
| 236 | | # Pick up the images we parsed earlier and write them to the theme folder |
| 237 | | for my $image_url (@images) { |
| 238 | | my $image_request = |
| 239 | | HTTP::Request->new( GET => $new_url . $image_url ); |
| 240 | | my $image_response = $user_agent->request($image_request); |
| 241 | | |
| 242 | | my @image_url = split( /\//, $image_url ); |
| 243 | | my $image_filename = $image_url[-1]; |
| 244 | | |
| 245 | | if (($response->code >= 200) && ($response->code < 400)) { |
| 246 | | $filemgr->put_data( $image_response->content, |
| 247 | | File::Spec->catfile( $themeroot, $basename, $image_filename ), |
| 248 | | 'upload' ) |
| 249 | | or return $app->json_error( $filemgr->errstr ); |
| 250 | | } else { |
| 251 | | return $app->json_error($app->translate("Error downloading image: [_1]", $new_url . $image_url)); |
| 252 | | } |
| 253 | | } |
| 254 | | $url = "$webthemeroot$basename/$basename.css"; |
| 255 | | } |
| 256 | | |
| | 268 | my $static_url = $app->static_path; |
| | 269 | if ( $url !~ m{ \A \Q$static_url\E (?:support/)? themes/ }xms ) { |
| | 270 | my $basename = download_theme($app, $url) |
| | 271 | or return; |
| | 272 | $url = "${static_url}support/themes/$basename/$basename.css"; |
| | 273 | } |
| | 274 | |
| | 275 | my $blog = MT->model('blog')->load($blog_id) |
| | 276 | or return $app->json_error( $app->translate('No such blog [_1]', $blog_id) ); |
| | 277 | my $blog_tset = $blog->template_set; |
| | 278 | my $base_css_url = MT->registry('template_sets')->{$blog_tset}->{base_css}; |
| | 279 | |
| | 280 | my $base_css = q{}; |
| | 281 | if ($base_css_url) { |
| | 282 | my $uri = URI->new_abs($base_css_url, $app->static_path); |
| | 283 | $base_css = '@import url(' . $uri->as_string() . ');' |
| | 284 | if $uri; |
| | 285 | } |
| 666 | | my $thumbnail_link; |
| 667 | | $thumbnail_link = $new_url . 'thumbnail.gif'; |
| 668 | | my $thumbnail_large_link; |
| 669 | | $thumbnail_large_link = $new_url . 'thumbnail-large.gif'; |
| | 706 | my %thumbnails; |
| | 707 | THUMB: for my $thumb (qw( thumbnail thumbnail_large )) { |
| | 708 | $thumbnails{$thumb} = $metadata{$thumb}; |
| | 709 | next THUMB if $thumbnails{$thumb}; |
| | 710 | |
| | 711 | my $thumb_filename = $thumb; |
| | 712 | $thumb_filename =~ tr/_/-/; |
| | 713 | $thumb_filename .= '.gif'; |
| | 714 | |
| | 715 | if ($url_is_web) { |
| | 716 | my $thumb_url = $new_url . $thumb_filename; |
| | 717 | |
| | 718 | my $user_agent = $app->new_ua; |
| | 719 | my $css_request = HTTP::Request->new( HEAD => $thumb_url ); |
| | 720 | my $response = $user_agent->request($css_request); |
| | 721 | if ($response->is_success()) { |
| | 722 | $thumbnails{$thumb} = $thumb_url; |
| | 723 | } |
| | 724 | } |
| | 725 | else { |
| | 726 | my $thumb_path = File::Spec->catfile($themeroot, $theme, |
| | 727 | $thumb_filename); |
| | 728 | if (-e $thumb_path) { |
| | 729 | $thumbnails{$thumb} = $new_url . $thumb_filename; |
| | 730 | } |
| | 731 | } |
| | 732 | |
| | 733 | $thumbnails{$thumb} ||= $app->static_path . 'plugins/StyleCatcher/' |
| | 734 | . 'images/' . $thumb_filename; |
| | 735 | } |
| | 736 | |
| | 737 | my %field_map = ( |
| | 738 | title => [ 'name', 'theme name' ], |
| | 739 | author => [ 'designer', 'author' ], |
| | 740 | author_url => [ 'designer_url', 'author_url', 'author uri' ], |
| | 741 | template_set => [ 'template_set', 'template' ], |
| | 742 | description => [ 'description' ], |
| | 743 | ); |
| | 744 | while (my ($best_name, $possible_names) = each %field_map) { |
| | 745 | ($metadata{$best_name}) = grep { defined } |
| | 746 | delete @metadata{ @$possible_names }, q{}; |
| | 747 | $metadata{$best_name} = decode_html(remove_html($metadata{$best_name})); |
| | 748 | } |
| 673 | | name => $theme, |
| 674 | | description => $metadata{description} || '', |
| 675 | | title => $metadata{name} || '(Untitled)', |
| 676 | | url => $url, |
| 677 | | imageSmall => $thumbnail_link, |
| 678 | | imageBig => $thumbnail_large_link, |
| 679 | | author => $metadata{designer} || $metadata{author} || '', |
| 680 | | author_url => $metadata{designer_url} || $metadata{author_url} || '', |
| 681 | | author_affiliation => $metadata{author_affiliation} || '', |
| 682 | | layouts => $metadata{layouts} || '', |
| 683 | | 'sort' => $metadata{name} || '', |
| 684 | | tags => $tags, |
| 685 | | blogs => [], |
| | 752 | name => $theme, |
| | 753 | description => $metadata{description} || q{}, |
| | 754 | title => $metadata{title} || '(Untitled)', |
| | 755 | url => $url, |
| | 756 | imageSmall => $thumbnails{thumbnail}, |
| | 757 | imageBig => $thumbnails{thumbnail_large}, |
| | 758 | layouts => $metadata{layouts} || q{}, |
| | 759 | sort => $metadata{name} || $theme || q{}, |
| | 760 | tags => $tags, |
| | 761 | blogs => [], |
| | 762 | author => $metadata{author}, |
| | 763 | author_url => $metadata{author_url}, |
| | 764 | template_set => $metadata{template_set}, |
| | 765 | author_affiliation => $metadata{author_affiliation} || q{}, |