| 1 | # Movable Type (r) Open Source (C) 2001-2008 Six Apart, Ltd. |
|---|
| 2 | # This program is distributed under the terms of the |
|---|
| 3 | # GNU General Public License, version 2. |
|---|
| 4 | # |
|---|
| 5 | # $Id$ |
|---|
| 6 | |
|---|
| 7 | package MT::Blog; |
|---|
| 8 | |
|---|
| 9 | use strict; |
|---|
| 10 | use base qw( MT::Object ); |
|---|
| 11 | |
|---|
| 12 | use MT::FileMgr; |
|---|
| 13 | use MT::Util; |
|---|
| 14 | |
|---|
| 15 | __PACKAGE__->install_properties({ |
|---|
| 16 | column_defs => { |
|---|
| 17 | 'id' => 'integer not null auto_increment', |
|---|
| 18 | 'name' => 'string(255) not null', |
|---|
| 19 | 'description' => 'text', |
|---|
| 20 | 'archive_type' => 'string(255)', |
|---|
| 21 | 'archive_type_preferred' => 'string(25)', |
|---|
| 22 | 'site_path' => 'string(255)', |
|---|
| 23 | 'site_url' => 'string(255)', |
|---|
| 24 | 'days_on_index' => 'integer', |
|---|
| 25 | 'entries_on_index' => 'integer', |
|---|
| 26 | 'file_extension' => 'string(10)', |
|---|
| 27 | 'email_new_comments' => 'boolean', |
|---|
| 28 | 'allow_comment_html' => 'boolean', |
|---|
| 29 | 'autolink_urls' => 'boolean', |
|---|
| 30 | 'sort_order_posts' => 'string(8)', |
|---|
| 31 | 'sort_order_comments' => 'string(8)', |
|---|
| 32 | 'allow_comments_default' => 'boolean', |
|---|
| 33 | 'server_offset' => 'float', |
|---|
| 34 | 'convert_paras' => 'string(30)', |
|---|
| 35 | 'convert_paras_comments' => 'string(30)', |
|---|
| 36 | 'allow_pings_default' => 'boolean', |
|---|
| 37 | 'status_default' => 'smallint', |
|---|
| 38 | 'allow_anon_comments' => 'boolean', |
|---|
| 39 | 'words_in_excerpt' => 'smallint', |
|---|
| 40 | 'moderate_unreg_comments' => 'boolean', |
|---|
| 41 | 'moderate_pings' => 'boolean', |
|---|
| 42 | 'allow_unreg_comments' => 'boolean', |
|---|
| 43 | 'allow_reg_comments' => 'boolean', |
|---|
| 44 | 'allow_pings' => 'boolean', |
|---|
| 45 | 'manual_approve_commenters' => 'boolean', |
|---|
| 46 | 'require_comment_emails' => 'boolean', |
|---|
| 47 | 'junk_folder_expiry' => 'integer', |
|---|
| 48 | 'ping_weblogs' => 'boolean', |
|---|
| 49 | 'mt_update_key' => 'string(30)', |
|---|
| 50 | 'language' => 'string(5)', |
|---|
| 51 | 'welcome_msg' => 'text', |
|---|
| 52 | 'google_api_key' => 'string(32)', |
|---|
| 53 | 'email_new_pings' => 'boolean', |
|---|
| 54 | 'ping_blogs' => 'boolean', |
|---|
| 55 | 'ping_technorati' => 'boolean', |
|---|
| 56 | 'ping_google' => 'boolean', |
|---|
| 57 | 'ping_others' => 'text', |
|---|
| 58 | 'autodiscover_links' => 'boolean', |
|---|
| 59 | 'sanitize_spec' => 'string(255)', |
|---|
| 60 | 'cc_license' => 'string(255)', |
|---|
| 61 | 'is_dynamic' => 'boolean', |
|---|
| 62 | 'remote_auth_token' => 'string(50)', |
|---|
| 63 | 'children_modified_on' => 'datetime', |
|---|
| 64 | 'custom_dynamic_templates' => 'string(25)', |
|---|
| 65 | 'junk_score_threshold' => 'float', |
|---|
| 66 | 'internal_autodiscovery' => 'boolean', |
|---|
| 67 | 'basename_limit' => 'smallint', |
|---|
| 68 | 'use_comment_confirmation' => 'boolean', |
|---|
| 69 | 'allow_commenter_regist' => 'boolean', |
|---|
| 70 | ## Have to keep these around for use in mt-upgrade.cgi. |
|---|
| 71 | 'archive_url' => 'string(255)', |
|---|
| 72 | 'archive_path' => 'string(255)', |
|---|
| 73 | 'old_style_archive_links' => 'boolean', |
|---|
| 74 | 'archive_tmpl_daily' => 'string(255)', |
|---|
| 75 | 'archive_tmpl_weekly' => 'string(255)', |
|---|
| 76 | 'archive_tmpl_monthly' => 'string(255)', |
|---|
| 77 | 'archive_tmpl_category' => 'string(255)', |
|---|
| 78 | 'archive_tmpl_individual' => 'string(255)', |
|---|
| 79 | }, |
|---|
| 80 | meta => 1, |
|---|
| 81 | audit => 1, |
|---|
| 82 | indexes => { |
|---|
| 83 | name => 1, |
|---|
| 84 | }, |
|---|
| 85 | defaults => { |
|---|
| 86 | 'custom_dynamic_templates' => 'none', |
|---|
| 87 | }, |
|---|
| 88 | child_classes => ['MT::Entry', 'MT::Page', 'MT::Template', 'MT::Asset', |
|---|
| 89 | 'MT::Category', 'MT::Folder', 'MT::Notification', 'MT::Log', |
|---|
| 90 | 'MT::ObjectTag', 'MT::Association', 'MT::Comment', |
|---|
| 91 | 'MT::TBPing', 'MT::Trackback', 'MT::TemplateMap', |
|---|
| 92 | 'MT::Touch'], |
|---|
| 93 | datasource => 'blog', |
|---|
| 94 | primary_key => 'id', |
|---|
| 95 | }); |
|---|
| 96 | __PACKAGE__->install_meta({ |
|---|
| 97 | columns => [ |
|---|
| 98 | 'image_default_wrap_text', |
|---|
| 99 | 'image_default_align', |
|---|
| 100 | 'image_default_thumb', |
|---|
| 101 | 'image_default_width', |
|---|
| 102 | 'image_default_wunits', |
|---|
| 103 | 'image_default_constrain', |
|---|
| 104 | 'image_default_popup', |
|---|
| 105 | 'commenter_authenticators', |
|---|
| 106 | 'require_typekey_emails', |
|---|
| 107 | 'nofollow_urls', |
|---|
| 108 | 'follow_auth_links', |
|---|
| 109 | 'update_pings', |
|---|
| 110 | 'captcha_provider', |
|---|
| 111 | 'publish_queue', |
|---|
| 112 | 'nwc_smart_replace', |
|---|
| 113 | 'nwc_replace_field', |
|---|
| 114 | 'template_set', |
|---|
| 115 | 'page_layout', |
|---|
| 116 | 'include_system', |
|---|
| 117 | 'include_cache', |
|---|
| 118 | ], |
|---|
| 119 | }); |
|---|
| 120 | |
|---|
| 121 | # Image upload defaults. |
|---|
| 122 | sub ALIGN () { 'none' } |
|---|
| 123 | sub UNITS () { 'pixels' } |
|---|
| 124 | |
|---|
| 125 | sub class_label { |
|---|
| 126 | MT->translate("Blog"); |
|---|
| 127 | } |
|---|
| 128 | |
|---|
| 129 | sub class_label_plural { |
|---|
| 130 | MT->translate("Blogs"); |
|---|
| 131 | } |
|---|
| 132 | |
|---|
| 133 | { |
|---|
| 134 | my $default_text_format; |
|---|
| 135 | sub set_defaults { |
|---|
| 136 | my $blog = shift; |
|---|
| 137 | unless ($default_text_format) { |
|---|
| 138 | if (my $allowed = MT->config('AllowedTextFilters')) { |
|---|
| 139 | $allowed =~ s/\s*,.*//; |
|---|
| 140 | $default_text_format = $allowed; # choose first allowed format |
|---|
| 141 | } else { |
|---|
| 142 | $default_text_format = 'richtext'; # MT system default |
|---|
| 143 | } |
|---|
| 144 | my $filters = MT->registry("text_filters"); |
|---|
| 145 | # If the 'richtext' filter exists, |
|---|
| 146 | # and is uncondition or it meets the condition, use |
|---|
| 147 | # it as the blog default text format. |
|---|
| 148 | if (!($filters->{$default_text_format} && (!$filters->{$default_text_format}{condition} || $filters->{$default_text_format}{condition}->('blog')))) { |
|---|
| 149 | $default_text_format = '__default__'; |
|---|
| 150 | } |
|---|
| 151 | } |
|---|
| 152 | $blog->set_values_internal({ |
|---|
| 153 | days_on_index => 0, |
|---|
| 154 | entries_on_index => 10, |
|---|
| 155 | words_in_excerpt => 40, |
|---|
| 156 | sort_order_posts => 'descend', |
|---|
| 157 | language => MT->config('DefaultLanguage'), |
|---|
| 158 | sort_order_comments => 'ascend', |
|---|
| 159 | file_extension => 'html', |
|---|
| 160 | convert_paras => $default_text_format, |
|---|
| 161 | allow_unreg_comments => 0, |
|---|
| 162 | allow_reg_comments => 1, |
|---|
| 163 | allow_pings => 1, |
|---|
| 164 | moderate_unreg_comments => MT::Blog::MODERATE_UNTRSTD(), |
|---|
| 165 | moderate_pings => 1, |
|---|
| 166 | require_comment_emails => 1, |
|---|
| 167 | allow_comments_default => 1, |
|---|
| 168 | allow_comment_html => 1, |
|---|
| 169 | autolink_urls => 1, |
|---|
| 170 | allow_pings_default => 1, |
|---|
| 171 | require_comment_emails => 0, |
|---|
| 172 | convert_paras_comments => 1, |
|---|
| 173 | email_new_pings => 1, |
|---|
| 174 | email_new_comments => 1, |
|---|
| 175 | allow_commenter_regist => 1, |
|---|
| 176 | use_comment_confirmation => 1, |
|---|
| 177 | sanitize_spec => 0, |
|---|
| 178 | ping_weblogs => 0, |
|---|
| 179 | ping_blogs => 0, |
|---|
| 180 | ping_technorati => 0, |
|---|
| 181 | ping_google => 0, |
|---|
| 182 | archive_type => 'Individual,Monthly,Category,Category-Monthly,Page', |
|---|
| 183 | archive_type_preferred => 'Individual', |
|---|
| 184 | status_default => 2, |
|---|
| 185 | junk_score_threshold => 0, |
|---|
| 186 | junk_folder_expiry => 14, # 14 days |
|---|
| 187 | custom_dynamic_templates => 'none', |
|---|
| 188 | internal_autodiscovery => 0, |
|---|
| 189 | basename_limit => 30, |
|---|
| 190 | server_offset => MT->config('DefaultTimezone') || 0, |
|---|
| 191 | # something far in the future to force dynamic side to read it. |
|---|
| 192 | children_modified_on => '20101231120000', |
|---|
| 193 | }); |
|---|
| 194 | return $blog; |
|---|
| 195 | } |
|---|
| 196 | } |
|---|
| 197 | |
|---|
| 198 | sub create_default_blog { |
|---|
| 199 | my $class = shift; |
|---|
| 200 | my ($blog_name, $blog_template) = @_; |
|---|
| 201 | $blog_name ||= MT->translate("First Blog"); |
|---|
| 202 | $class = ref $class if ref $class; |
|---|
| 203 | |
|---|
| 204 | my $blog = new $class; |
|---|
| 205 | $blog->name($blog_name); |
|---|
| 206 | |
|---|
| 207 | # Enable nofollow options |
|---|
| 208 | $blog->nofollow_urls(1); |
|---|
| 209 | $blog->follow_auth_links(1); |
|---|
| 210 | |
|---|
| 211 | # Enable default commenter authentication |
|---|
| 212 | $blog->commenter_authenticators(MT->config('DefaultCommenterAuth')); |
|---|
| 213 | |
|---|
| 214 | # set default page layout |
|---|
| 215 | $blog->page_layout('layout-wtt'); |
|---|
| 216 | |
|---|
| 217 | $blog->save or return $class->error($blog->errstr); |
|---|
| 218 | $blog->create_default_templates($blog_template || 'mt_blog') |
|---|
| 219 | or return $class->error($blog->errstr); |
|---|
| 220 | return $blog; |
|---|
| 221 | } |
|---|
| 222 | |
|---|
| 223 | sub create_default_templates { |
|---|
| 224 | my $blog = shift; |
|---|
| 225 | |
|---|
| 226 | require MT::DefaultTemplates; |
|---|
| 227 | my $tmpl_list = MT::DefaultTemplates->templates( @_ ); |
|---|
| 228 | return $blog->error(MT->translate("No default templates were found.")) |
|---|
| 229 | if !$tmpl_list || (ref($tmpl_list) ne 'ARRAY') || (!@$tmpl_list); |
|---|
| 230 | |
|---|
| 231 | require MT::Template; |
|---|
| 232 | my @arch_tmpl; |
|---|
| 233 | for my $val (@$tmpl_list) { |
|---|
| 234 | next if $val->{global}; |
|---|
| 235 | |
|---|
| 236 | my $obj = MT::Template->new; |
|---|
| 237 | my $p = $val->{plugin} || 'MT'; # component and/or MT package for translate |
|---|
| 238 | local $val->{name} = $val->{name}; # name field is translated in "templates" call |
|---|
| 239 | local $val->{text} = $p->translate_templatized($val->{text}); |
|---|
| 240 | $obj->build_dynamic(0); |
|---|
| 241 | foreach my $v (keys %$val) { |
|---|
| 242 | $obj->column($v, $val->{$v}) if $obj->has_column($v); |
|---|
| 243 | } |
|---|
| 244 | $obj->blog_id($blog->id); |
|---|
| 245 | if (my $pub_opts = $val->{publishing}) { |
|---|
| 246 | $obj->include_with_ssi(1) if $pub_opts->{include_with_ssi}; |
|---|
| 247 | } |
|---|
| 248 | $obj->save; |
|---|
| 249 | if ($val->{mappings}) { |
|---|
| 250 | push @arch_tmpl, { |
|---|
| 251 | template => $obj, |
|---|
| 252 | mappings => $val->{mappings}, |
|---|
| 253 | exists($val->{preferred}) ? (preferred => $val->{preferred}) : () |
|---|
| 254 | }; |
|---|
| 255 | } |
|---|
| 256 | } |
|---|
| 257 | |
|---|
| 258 | if (@arch_tmpl) { |
|---|
| 259 | require MT::TemplateMap; |
|---|
| 260 | for my $map_set (@arch_tmpl) { |
|---|
| 261 | my $tmpl = $map_set->{template}; |
|---|
| 262 | my $mappings = $map_set->{mappings}; |
|---|
| 263 | foreach my $map_key (keys %$mappings) { |
|---|
| 264 | my $m = $mappings->{$map_key}; |
|---|
| 265 | my $at = $m->{archive_type}; |
|---|
| 266 | # my $preferred = $mappings->{$map_key}{preferred}; |
|---|
| 267 | my $map = MT::TemplateMap->new; |
|---|
| 268 | $map->archive_type($at); |
|---|
| 269 | if ( exists $m->{preferred} ) { |
|---|
| 270 | $map->is_preferred($m->{preferred}); |
|---|
| 271 | } |
|---|
| 272 | else { |
|---|
| 273 | $map->is_preferred(1); |
|---|
| 274 | } |
|---|
| 275 | $map->template_id($tmpl->id); |
|---|
| 276 | $map->file_template($m->{file_template}) if $m->{file_template}; |
|---|
| 277 | $map->blog_id($tmpl->blog_id); |
|---|
| 278 | $map->save; |
|---|
| 279 | } |
|---|
| 280 | } |
|---|
| 281 | } |
|---|
| 282 | |
|---|
| 283 | MT->run_callbacks( |
|---|
| 284 | ref($blog). '::post_create_default_templates', |
|---|
| 285 | $blog, |
|---|
| 286 | $tmpl_list |
|---|
| 287 | ); |
|---|
| 288 | |
|---|
| 289 | return $blog; |
|---|
| 290 | } |
|---|
| 291 | |
|---|
| 292 | # As of MT 4, we always manage fileinfo records. |
|---|
| 293 | sub needs_fileinfo { |
|---|
| 294 | return 1; |
|---|
| 295 | } |
|---|
| 296 | |
|---|
| 297 | sub current_timestamp { |
|---|
| 298 | my $blog = shift; |
|---|
| 299 | require MT::Util; |
|---|
| 300 | my @ts = MT::Util::offset_time_list(time, $blog->id); |
|---|
| 301 | return sprintf '%04d%02d%02d%02d%02d%02d', |
|---|
| 302 | $ts[5]+1900, $ts[4]+1, @ts[3,2,1,0]; |
|---|
| 303 | } |
|---|
| 304 | |
|---|
| 305 | sub site_url { |
|---|
| 306 | my $blog = shift; |
|---|
| 307 | if (!@_ && $blog->is_dynamic) { |
|---|
| 308 | my $cfg = MT->config; |
|---|
| 309 | my $path = $cfg->CGIPath; |
|---|
| 310 | $path .= '/' unless $path =~ m!/$!; |
|---|
| 311 | return $path . $cfg->ViewScript . '/' . $blog->id; |
|---|
| 312 | } else { |
|---|
| 313 | return $blog->SUPER::site_url(@_); |
|---|
| 314 | } |
|---|
| 315 | } |
|---|
| 316 | |
|---|
| 317 | sub archive_url { |
|---|
| 318 | my $blog = shift; |
|---|
| 319 | if (!@_ && $blog->is_dynamic) { |
|---|
| 320 | $blog->site_url; |
|---|
| 321 | } else { |
|---|
| 322 | $blog->SUPER::archive_url(@_) || $blog->site_url; |
|---|
| 323 | } |
|---|
| 324 | } |
|---|
| 325 | |
|---|
| 326 | sub archive_path { |
|---|
| 327 | my $blog = shift; |
|---|
| 328 | $blog->SUPER::archive_path(@_) || $blog->site_path; |
|---|
| 329 | } |
|---|
| 330 | |
|---|
| 331 | sub comment_text_filters { |
|---|
| 332 | my $blog = shift; |
|---|
| 333 | my $filters = $blog->convert_paras_comments; |
|---|
| 334 | return [] unless $filters; |
|---|
| 335 | if ($filters eq '1') { |
|---|
| 336 | return [ '__default__' ]; |
|---|
| 337 | } else { |
|---|
| 338 | return [ split /\s*,\s*/, $filters ]; |
|---|
| 339 | } |
|---|
| 340 | } |
|---|
| 341 | |
|---|
| 342 | sub cc_license_url { |
|---|
| 343 | my $cc = $_[0]->cc_license or return ''; |
|---|
| 344 | MT::Util::cc_url($cc); |
|---|
| 345 | } |
|---|
| 346 | |
|---|
| 347 | sub email_all_comments { |
|---|
| 348 | return $_[0]->email_new_comments == 1; |
|---|
| 349 | } |
|---|
| 350 | |
|---|
| 351 | sub email_attn_reqd_comments { |
|---|
| 352 | return $_[0]->email_new_comments == 2; |
|---|
| 353 | } |
|---|
| 354 | |
|---|
| 355 | sub email_all_pings { |
|---|
| 356 | return $_[0]->email_new_pings == 1; |
|---|
| 357 | } |
|---|
| 358 | |
|---|
| 359 | sub email_attn_reqd_pings { |
|---|
| 360 | return $_[0]->email_new_pings == 2; |
|---|
| 361 | } |
|---|
| 362 | |
|---|
| 363 | sub MODERATE_NONE () { 0 } |
|---|
| 364 | sub MODERATE_ALL () { 1 } |
|---|
| 365 | sub MODERATE_UNTRSTD () { 2 } |
|---|
| 366 | sub MODERATE_UNAUTHD () { 3 } |
|---|
| 367 | |
|---|
| 368 | sub publish_trusted_commenters { |
|---|
| 369 | !($_[0]->moderate_unreg_comments == MODERATE_ALL); |
|---|
| 370 | } |
|---|
| 371 | |
|---|
| 372 | sub publish_authd_untrusted_commenters { |
|---|
| 373 | return $_[0]->moderate_unreg_comments == MODERATE_UNAUTHD |
|---|
| 374 | || $_[0]->moderate_unreg_comments == MODERATE_NONE; |
|---|
| 375 | } |
|---|
| 376 | |
|---|
| 377 | sub publish_unauthd_commenters { |
|---|
| 378 | $_[0]->moderate_unreg_comments == MODERATE_NONE; |
|---|
| 379 | } |
|---|
| 380 | |
|---|
| 381 | sub include_path_parts { |
|---|
| 382 | my $blog = shift; |
|---|
| 383 | my ($name) = @_; |
|---|
| 384 | |
|---|
| 385 | my $filestem = MT::Util::dirify($name); |
|---|
| 386 | my $filename = join q{.}, $filestem, $blog->file_extension; |
|---|
| 387 | return (MT->config('IncludesDir'), substr($filestem, 0, 3), $filename); |
|---|
| 388 | } |
|---|
| 389 | |
|---|
| 390 | sub include_path { |
|---|
| 391 | my $blog = shift; |
|---|
| 392 | my ($name) = @_; |
|---|
| 393 | |
|---|
| 394 | my @parts = $blog->include_path_parts($name); |
|---|
| 395 | my $filename = pop @parts; |
|---|
| 396 | my $path = File::Spec->catdir($blog->site_path, @parts); |
|---|
| 397 | my $file_path = File::Spec->catfile($path, $filename); |
|---|
| 398 | return wantarray ? ($path, $file_path) : $file_path; |
|---|
| 399 | } |
|---|
| 400 | |
|---|
| 401 | sub include_url { |
|---|
| 402 | my $blog = shift; |
|---|
| 403 | my ($name) = @_; |
|---|
| 404 | |
|---|
| 405 | my @parts = $blog->include_path_parts(); |
|---|
| 406 | my $url = join q{/}, $blog->site_url, @parts; |
|---|
| 407 | return $url; |
|---|
| 408 | } |
|---|
| 409 | |
|---|
| 410 | sub include_statement { |
|---|
| 411 | my $blog = shift; |
|---|
| 412 | my ($name) = @_; |
|---|
| 413 | |
|---|
| 414 | my $system = $blog->include_system or return; |
|---|
| 415 | |
|---|
| 416 | my ($statement, $include); |
|---|
| 417 | if ($system eq 'shtml') { |
|---|
| 418 | $statement = q{<!--#include virtual="%s" -->}; |
|---|
| 419 | |
|---|
| 420 | my $site_url = $blog->site_url; |
|---|
| 421 | $site_url =~ s{ \A \w+ :// [^/]+ }{}xms; |
|---|
| 422 | $site_url =~ s{ / \z }{}xms; |
|---|
| 423 | $include = join q{/}, $site_url, $blog->include_path_parts($name); |
|---|
| 424 | } |
|---|
| 425 | else { |
|---|
| 426 | $include = $blog->include_path($name); |
|---|
| 427 | $statement = $system eq 'php' ? q{<?php include("%s") ?>} |
|---|
| 428 | : $system eq 'jsp' ? q{<%@ include file="%s" %>} |
|---|
| 429 | : $system eq 'asp' ? '<!--#include file="%s" -->' |
|---|
| 430 | : return |
|---|
| 431 | ; |
|---|
| 432 | } |
|---|
| 433 | return sprintf $statement, MT::Util::encode_php($include, q{qq}); |
|---|
| 434 | } |
|---|
| 435 | |
|---|
| 436 | sub file_mgr { |
|---|
| 437 | my $blog = shift; |
|---|
| 438 | unless (exists $blog->{__file_mgr}) { |
|---|
| 439 | ## xxx need to add remote_host, remote_user, remote_pwd fields |
|---|
| 440 | ## then pull params from there; if remote_host is defined, we |
|---|
| 441 | ## assume we are using FTP? |
|---|
| 442 | $blog->{__file_mgr} = MT::FileMgr->new('Local'); |
|---|
| 443 | } |
|---|
| 444 | $blog->{__file_mgr}; |
|---|
| 445 | } |
|---|
| 446 | |
|---|
| 447 | sub remove { |
|---|
| 448 | my $blog = shift; |
|---|
| 449 | $blog->remove_children({ key => 'blog_id'}); |
|---|
| 450 | my $res = $blog->SUPER::remove(@_); |
|---|
| 451 | if ((ref $blog) && $res) { |
|---|
| 452 | require MT::Permission; |
|---|
| 453 | MT::Permission->remove({ blog_id => $blog->id }); |
|---|
| 454 | } |
|---|
| 455 | $res; |
|---|
| 456 | } |
|---|
| 457 | |
|---|
| 458 | # deprecated: use $blog->remote_auth_token instead |
|---|
| 459 | sub effective_remote_auth_token { |
|---|
| 460 | my $blog = shift; |
|---|
| 461 | if (scalar @_) { |
|---|
| 462 | return $blog->remote_auth_token(@_); |
|---|
| 463 | } |
|---|
| 464 | if ($blog->remote_auth_token()) { |
|---|
| 465 | return $blog->remote_auth_token(); |
|---|
| 466 | } |
|---|
| 467 | undef; |
|---|
| 468 | } |
|---|
| 469 | |
|---|
| 470 | sub has_archive_type { |
|---|
| 471 | my $blog = shift; |
|---|
| 472 | my ($type) = @_; |
|---|
| 473 | my %at = map { lc $_ => 1 } split(/,/, $blog->archive_type); |
|---|
| 474 | return exists $at{lc $type} ? 1 : 0; |
|---|
| 475 | } |
|---|
| 476 | |
|---|
| 477 | sub accepts_registered_comments { |
|---|
| 478 | $_[0]->allow_reg_comments && $_[0]->commenter_authenticators; |
|---|
| 479 | } |
|---|
| 480 | |
|---|
| 481 | sub accepts_comments { |
|---|
| 482 | $_[0]->accepts_registered_comments || $_[0]->allow_unreg_comments; |
|---|
| 483 | } |
|---|
| 484 | |
|---|
| 485 | sub count_static_templates { |
|---|
| 486 | my $blog = shift; |
|---|
| 487 | my ($archive_type) = @_; |
|---|
| 488 | my $result = 0; |
|---|
| 489 | require MT::TemplateMap; |
|---|
| 490 | my @maps = MT::TemplateMap->load({blog_id => $blog->id, |
|---|
| 491 | archive_type => $archive_type}); |
|---|
| 492 | return 0 unless @maps; |
|---|
| 493 | require MT::Template; |
|---|
| 494 | foreach my $map (@maps) { |
|---|
| 495 | my $tmpl = MT::Template->load($map->template_id); |
|---|
| 496 | $result++ if !$tmpl->build_dynamic; |
|---|
| 497 | } |
|---|
| 498 | #$result ||= 1 if ($blog->custom_dynamic_templates || '') ne 'custom'; |
|---|
| 499 | return $result; |
|---|
| 500 | } |
|---|
| 501 | |
|---|
| 502 | sub touch { |
|---|
| 503 | my $blog = shift; |
|---|
| 504 | my ( @types ) = @_; |
|---|
| 505 | my ($s,$m,$h,$d,$mo,$y) = localtime(time); |
|---|
| 506 | my $mod_time = sprintf("%04d%02d%02d%02d%02d%02d", |
|---|
| 507 | 1900+$y, $mo+1, $d, $h, $m, $s); |
|---|
| 508 | require MT::Touch; |
|---|
| 509 | MT::Touch->touch( $blog->id, @types ); |
|---|
| 510 | $blog->children_modified_on($mod_time); |
|---|
| 511 | $mod_time; |
|---|
| 512 | } |
|---|
| 513 | |
|---|
| 514 | sub clone { |
|---|
| 515 | my $blog = shift; |
|---|
| 516 | my ($param) = @_; |
|---|
| 517 | if ($param && $param->{Children}) { |
|---|
| 518 | $blog->clone_with_children(@_); |
|---|
| 519 | } else { |
|---|
| 520 | $blog->SUPER::clone(@_); |
|---|
| 521 | } |
|---|
| 522 | } |
|---|
| 523 | |
|---|
| 524 | sub clone_with_children { |
|---|
| 525 | my $blog = shift; |
|---|
| 526 | my ($params) = @_; |
|---|
| 527 | my $callback = $params->{Callback} || sub {}; |
|---|
| 528 | my $classes = $params->{Classes}; |
|---|
| 529 | my $blog_name = $params->{BlogName}; |
|---|
| 530 | delete $$params{Children} if ($params->{Children}); |
|---|
| 531 | my $old_blog_id = $blog->id; |
|---|
| 532 | |
|---|
| 533 | # we must clone: |
|---|
| 534 | # Blog record |
|---|
| 535 | # Entry records |
|---|
| 536 | # - Comment records |
|---|
| 537 | # - TrackBack records |
|---|
| 538 | # - TBPing records |
|---|
| 539 | # - ObjectTag records (if running 3.3) |
|---|
| 540 | # Category records |
|---|
| 541 | # Placement records |
|---|
| 542 | # Template records |
|---|
| 543 | # Permission records |
|---|
| 544 | # IPBanList records??? |
|---|
| 545 | # Notification records??? |
|---|
| 546 | |
|---|
| 547 | my $new_blog_id; |
|---|
| 548 | my (%entry_map, %cat_map, %tb_map, %tmpl_map, $counter, $iter); |
|---|
| 549 | |
|---|
| 550 | # Cloning blog |
|---|
| 551 | my $new_blog = $blog->clone($params); |
|---|
| 552 | $new_blog->name(MT->translate($blog_name ? $blog_name : "Clone of [_1]", $blog->name)); |
|---|
| 553 | delete $new_blog->{column_values}->{id}; |
|---|
| 554 | delete $new_blog->{changed_cols}->{id}; |
|---|
| 555 | $new_blog->save or die $new_blog->errstr; |
|---|
| 556 | $new_blog_id = $new_blog->id; |
|---|
| 557 | $callback->(MT->translate("Cloned blog... new id is [_1].", |
|---|
| 558 | $new_blog_id)); |
|---|
| 559 | |
|---|
| 560 | if ((!exists $classes->{'MT::Permission'}) || $classes->{'MT::Permission'}) { |
|---|
| 561 | # Cloning PERMISSIONS records |
|---|
| 562 | $counter = 0; |
|---|
| 563 | my $state = MT->translate("Cloning permissions for blog:"); |
|---|
| 564 | $callback->($state, "perms"); |
|---|
| 565 | require MT::Permission; |
|---|
| 566 | $iter = MT::Permission->load_iter({blog_id => $old_blog_id}); |
|---|
| 567 | while (my $perm = $iter->()) { |
|---|
| 568 | $callback->($state . " " . MT->translate("[_1] records processed...", $counter), 'perms') |
|---|
| 569 | if $counter && ($counter % 100 == 0); |
|---|
| 570 | $counter++; |
|---|
| 571 | delete $perm->{column_values}->{id}; |
|---|
| 572 | delete $perm->{changed_cols}->{id}; |
|---|
| 573 | $perm->blog_id($new_blog_id); |
|---|
| 574 | $perm->save or die $perm->errstr; |
|---|
| 575 | } |
|---|
| 576 | $callback->($state . " " . MT->translate("[_1] records processed.", $counter), 'perms'); |
|---|
| 577 | } |
|---|
| 578 | |
|---|
| 579 | if ((!exists $classes->{'MT::Association'}) || $classes->{'MT::Association'}) { |
|---|
| 580 | # Cloning association records |
|---|
| 581 | $counter = 0; |
|---|
| 582 | my $state = MT->translate("Cloning associations for blog:"); |
|---|
| 583 | $callback->($state, "assoc"); |
|---|
| 584 | require MT::Association; |
|---|
| 585 | $iter = MT::Association->load_iter({blog_id => $old_blog_id}); |
|---|
| 586 | while (my $assoc = $iter->()) { |
|---|
| 587 | $callback->($state . " " . MT->translate("[_1] records processed...", $counter), 'assoc') |
|---|
| 588 | if $counter && ($counter % 100 == 0); |
|---|
| 589 | $counter++; |
|---|
| 590 | delete $assoc->{column_values}->{id}; |
|---|
| 591 | delete $assoc->{changed_cols}->{id}; |
|---|
| 592 | $assoc->blog_id($new_blog_id); |
|---|
| 593 | $assoc->save or die $assoc->errstr; |
|---|
| 594 | } |
|---|
| 595 | $callback->($state . " " . MT->translate("[_1] records processed.", $counter), 'assoc'); |
|---|
| 596 | } |
|---|
| 597 | |
|---|
| 598 | # include/exclude class logic |
|---|
| 599 | # if user has not specified 'Classes' element, clone everything |
|---|
| 600 | # if user has specified Classes, but a particular class is not |
|---|
| 601 | # identified, clone it (forward compatibility). if a class is |
|---|
| 602 | # specified and the flag is '1', clone it. if a class is specified |
|---|
| 603 | # but the flag is '0', skip it. |
|---|
| 604 | |
|---|
| 605 | # MT::Entry -> MT::Category, MT::Comment, MT::Tracback, MT::TBPing |
|---|
| 606 | # MT::Page -> MT::Folder, MT::Comment, MT::Trackback, MT::TBPing |
|---|
| 607 | |
|---|
| 608 | if ((!exists $classes->{'MT::Entry'}) || $classes->{'MT::Entry'}) { |
|---|
| 609 | # Cloning ENTRY records |
|---|
| 610 | my $state = MT->translate("Cloning entries for blog..."); |
|---|
| 611 | $callback->($state, "entries"); |
|---|
| 612 | $counter = 0; |
|---|
| 613 | require MT::Entry; |
|---|
| 614 | $iter = MT::Entry->load_iter({blog_id => $old_blog_id, class => '*'}); |
|---|
| 615 | while (my $entry = $iter->()) { |
|---|
| 616 | $callback->($state . " " . MT->translate("[_1] records processed...", $counter), 'entries') |
|---|
| 617 | if $counter && ($counter % 100 == 0); |
|---|
| 618 | $counter++; |
|---|
| 619 | my $entry_id = $entry->id; |
|---|
| 620 | delete $entry->{column_values}->{id}; |
|---|
| 621 | delete $entry->{changed_cols}->{id}; |
|---|
| 622 | $entry->blog_id($new_blog_id); |
|---|
| 623 | $entry->save or die $entry->errstr; |
|---|
| 624 | $entry_map{$entry_id} = $entry->id; |
|---|
| 625 | } |
|---|
| 626 | $callback->($state . " " . MT->translate("[_1] records processed.", $counter), 'entries'); |
|---|
| 627 | |
|---|
| 628 | if ((!exists $classes->{'MT::Category'}) || $classes->{'MT::Category'}) { |
|---|
| 629 | # Cloning CATEGORY records |
|---|
| 630 | my $state = MT->translate("Cloning categories for blog..."); |
|---|
| 631 | $callback->($state, "cats"); |
|---|
| 632 | $counter = 0; |
|---|
| 633 | require MT::Category; |
|---|
| 634 | $iter = MT::Category->load_iter({ blog_id => $old_blog_id, class => '*' }); |
|---|
| 635 | my %cat_parents; |
|---|
| 636 | while (my $cat = $iter->()) { |
|---|
| 637 | $callback->($state . " " . MT->translate("[_1] records processed...", $counter), 'cats') |
|---|
| 638 | if $counter && ($counter % 100 == 0); |
|---|
| 639 | $counter++; |
|---|
| 640 | my $cat_id = $cat->id; |
|---|
| 641 | my $old_parent = $cat->parent; |
|---|
| 642 | delete $cat->{column_values}->{id}; |
|---|
| 643 | delete $cat->{changed_cols}->{id}; |
|---|
| 644 | $cat->blog_id($new_blog_id); |
|---|
| 645 | # temporarily wipe the parent association |
|---|
| 646 | # to avoid constraint issues. |
|---|
| 647 | $cat->parent(0); |
|---|
| 648 | $cat->save or die $cat->errstr; |
|---|
| 649 | $cat_map{$cat_id} = $cat->id; |
|---|
| 650 | if ($old_parent) { |
|---|
| 651 | $cat_parents{$cat->id} = $old_parent; |
|---|
| 652 | } |
|---|
| 653 | } |
|---|
| 654 | # reassign the new category parents |
|---|
| 655 | foreach (keys %cat_parents) { |
|---|
| 656 | my $cat = MT::Category->load($_); |
|---|
| 657 | if ($cat) { |
|---|
| 658 | $cat->parent($cat_map{$cat_parents{$cat->id}}); |
|---|
| 659 | $cat->save or die $cat->errstr; |
|---|
| 660 | } |
|---|
| 661 | } |
|---|
| 662 | $callback->($state . " " . MT->translate("[_1] records processed.", $counter), 'cats'); |
|---|
| 663 | |
|---|
| 664 | # Placements are automatically cloned if categories are |
|---|
| 665 | # cloned. |
|---|
| 666 | $state = MT->translate("Cloning entry placements for blog..."); |
|---|
| 667 | $callback->($state, "places"); |
|---|
| 668 | require MT::Placement; |
|---|
| 669 | $iter = MT::Placement->load_iter({ blog_id => $old_blog_id }); |
|---|
| 670 | $counter = 0; |
|---|
| 671 | while (my $place = $iter->()) { |
|---|
| 672 | $callback->($state . " " . MT->translate("[_1] records processed...", $counter), 'places') |
|---|
| 673 | if $counter && ($counter % 100 == 0); |
|---|
| 674 | $counter++; |
|---|
| 675 | delete $place->{column_values}->{id}; |
|---|
| 676 | delete $place->{changed_cols}->{id}; |
|---|
| 677 | $place->blog_id($new_blog_id); |
|---|
| 678 | $place->category_id($cat_map{$place->category_id}); |
|---|
| 679 | $place->entry_id($entry_map{$place->entry_id}); |
|---|
| 680 | $place->save or die $place->errstr; |
|---|
| 681 | } |
|---|
| 682 | $callback->($state . " " . MT->translate("[_1] records processed.", $counter), 'places'); |
|---|
| 683 | } |
|---|
| 684 | |
|---|
| 685 | if ((!exists $classes->{'MT::Comment'}) || $classes->{'MT::Comment'}) { |
|---|
| 686 | # Comments can only be cloned if entries are cloned. |
|---|
| 687 | my $state = MT->translate("Cloning comments for blog..."); |
|---|
| 688 | $callback->($state, "comments"); |
|---|
| 689 | require MT::Comment; |
|---|
| 690 | $iter = MT::Comment->load_iter({ blog_id => $old_blog_id }); |
|---|
| 691 | $counter = 0; |
|---|
| 692 | while (my $comment = $iter->()) { |
|---|
| 693 | $callback->($state . " " . MT->translate("[_1] records processed...", $counter), 'comments') |
|---|
| 694 | if $counter && ($counter % 100 == 0); |
|---|
| 695 | $counter++; |
|---|
| 696 | delete $comment->{column_values}->{id}; |
|---|
| 697 | delete $comment->{changed_cols}->{id}; |
|---|
| 698 | $comment->entry_id($entry_map{$comment->entry_id}); |
|---|
| 699 | $comment->blog_id($new_blog_id); |
|---|
| 700 | $comment->save or die $comment->errstr; |
|---|
| 701 | } |
|---|
| 702 | $callback->($state . " " . MT->translate("[_1] records processed.", $counter), 'comments'); |
|---|
| 703 | } |
|---|
| 704 | |
|---|
| 705 | if ((!exists $classes->{'MT::ObjectTag'}) || $classes->{'MT::ObjectTag'}) { |
|---|
| 706 | # conditionally do MT::ObjectTag since it is only |
|---|
| 707 | # available with MT 3.3. |
|---|
| 708 | if ($MT::VERSION >= 3.3) { |
|---|
| 709 | my $state = MT->translate("Cloning entry tags for blog..."); |
|---|
| 710 | $callback->($state, "tags"); |
|---|
| 711 | require MT::ObjectTag; |
|---|
| 712 | $iter = MT::ObjectTag->load_iter({ blog_id => $old_blog_id, object_datasource => 'entry' }); |
|---|
| 713 | $counter = 0; |
|---|
| 714 | while (my $entry_tag = $iter->()) { |
|---|
| 715 | $callback->($state . " " . MT->translate("[_1] records processed...", $counter), "tags") |
|---|
| 716 | if $counter && ($counter % 100 == 0); |
|---|
| 717 | $counter++; |
|---|
| 718 | delete $entry_tag->{column_values}->{id}; |
|---|
| 719 | delete $entry_tag->{changed_cols}->{id}; |
|---|
| 720 | $entry_tag->blog_id($new_blog_id); |
|---|
| 721 | $entry_tag->object_id($entry_map{$entry_tag->object_id}); |
|---|
| 722 | $entry_tag->save or die $entry_tag->errstr; |
|---|
| 723 | } |
|---|
| 724 | $callback->($state . " " . MT->translate("[_1] records processed.", $counter), 'tags'); |
|---|
| 725 | } |
|---|
| 726 | } |
|---|
| 727 | } |
|---|
| 728 | |
|---|
| 729 | if ((!exists $classes->{'MT::Trackback'}) || $classes->{'MT::Trackback'}) { |
|---|
| 730 | my $state = MT->translate("Cloning TrackBacks for blog..."); |
|---|
| 731 | $callback->($state, "tbs"); |
|---|
| 732 | require MT::Trackback; |
|---|
| 733 | $iter = MT::Trackback->load_iter({ blog_id => $old_blog_id }); |
|---|
| 734 | $counter = 0; |
|---|
| 735 | while (my $tb = $iter->()) { |
|---|
| 736 | next unless ($tb->entry_id && $entry_map{$tb->entry_id}) || |
|---|
| 737 | ($tb->category_id && $cat_map{$tb->category_id}); |
|---|
| 738 | |
|---|
| 739 | $callback->($state . " " . MT->translate("[_1] records processed...", $counter), 'tbs') |
|---|
| 740 | if $counter && ($counter % 100 == 0); |
|---|
| 741 | $counter++; |
|---|
| 742 | my $tb_id = $tb->id; |
|---|
| 743 | delete $tb->{column_values}->{id}; |
|---|
| 744 | delete $tb->{changed_cols}->{id}; |
|---|
| 745 | |
|---|
| 746 | if ($tb->category_id) { |
|---|
| 747 | if (my $cid = $cat_map{$tb->category_id}) { |
|---|
| 748 | my $cat_tb = MT::Trackback->load( |
|---|
| 749 | { category_id => $cid } |
|---|
| 750 | ); |
|---|
| 751 | if ($cat_tb) { |
|---|
| 752 | my $changed; |
|---|
| 753 | if ($tb->passphrase) { |
|---|
| 754 | $cat_tb->passphrase($tb->passphrase); |
|---|
| 755 | $changed = 1; |
|---|
| 756 | } |
|---|
| 757 | if ($tb->is_disabled) { |
|---|
| 758 | $cat_tb->is_disabled(1); |
|---|
| 759 | $changed = 1; |
|---|
| 760 | } |
|---|
| 761 | $cat_tb->save if $changed; |
|---|
| 762 | $tb_map{$tb_id} = $cat_tb->id; |
|---|
| 763 | next; |
|---|
| 764 | } |
|---|
| 765 | } |
|---|
| 766 | } |
|---|
| 767 | elsif ($tb->entry_id) { |
|---|
| 768 | if (my $eid = $entry_map{$tb->entry_id}) { |
|---|
| 769 | my $entry_tb = MT::Entry->load($eid)->trackback; |
|---|
| 770 | if ($entry_tb) { |
|---|
| 771 | my $changed; |
|---|
| 772 | if ($tb->passphrase) { |
|---|
| 773 | $entry_tb->passphrase($tb->passphrase); |
|---|
| 774 | $changed = 1; |
|---|
| 775 | } |
|---|
| 776 | if ($tb->is_disabled) { |
|---|
| 777 | $entry_tb->is_disabled(1); |
|---|
| 778 | $changed = 1; |
|---|
| 779 | } |
|---|
| 780 | $entry_tb->save if $changed; |
|---|
| 781 | $tb_map{$tb_id} = $entry_tb->id; |
|---|
| 782 | next; |
|---|
| 783 | } |
|---|
| 784 | } |
|---|
| 785 | } |
|---|
| 786 | |
|---|
| 787 | # A trackback wasn't created when saving the entry/category, |
|---|
| 788 | # (perhaps trackbacks are now disabled for the entry/category?) |
|---|
| 789 | # so create one now |
|---|
| 790 | $tb->entry_id($entry_map{$tb->entry_id}) |
|---|
| 791 | if $tb->entry_id && $entry_map{$tb->entry_id}; |
|---|
| 792 | $tb->category_id($cat_map{$tb->category_id}) |
|---|
| 793 | if $tb->category_id && $cat_map{$tb->category_id}; |
|---|
| 794 | $tb->blog_id($new_blog_id); |
|---|
| 795 | $tb->save or die $tb->errstr; |
|---|
| 796 | $tb_map{$tb_id} = $tb->id; |
|---|
| 797 | } |
|---|
| 798 | $callback->($state . " " . MT->translate("[_1] records processed.", $counter), 'tbs'); |
|---|
| 799 | |
|---|
| 800 | if ((!exists $classes->{'MT::TBPing'}) || $classes->{'MT::TBPing'}) { |
|---|
| 801 | my $state = MT->translate("Cloning TrackBack pings for blog..."); |
|---|
| 802 | $callback->($state, "pings"); |
|---|
| 803 | require MT::TBPing; |
|---|
| 804 | $iter = MT::TBPing->load_iter({ blog_id => $old_blog_id }); |
|---|
| 805 | $counter = 0; |
|---|
| 806 | while (my $ping = $iter->()) { |
|---|
| 807 | next unless $tb_map{$ping->tb_id}; |
|---|
| 808 | $callback->($state . " " . MT->translate("[_1] records processed...", $counter), 'pings') |
|---|
| 809 | if $counter && ($counter % 100 == 0); |
|---|
| 810 | $counter++; |
|---|
| 811 | delete $ping->{column_values}->{id}; |
|---|
| 812 | delete $ping->{changed_cols}->{id}; |
|---|
| 813 | $ping->tb_id($tb_map{$ping->tb_id}); |
|---|
| 814 | $ping->blog_id($new_blog_id); |
|---|
| 815 | $ping->save or die $ping->errstr; |
|---|
| 816 | } |
|---|
| 817 | $callback->($state . " " . MT->translate("[_1] records processed.", $counter), 'pings'); |
|---|
| 818 | } |
|---|
| 819 | } |
|---|
| 820 | |
|---|
| 821 | if ((!exists $classes->{'MT::Template'}) || $classes->{'MT::Template'}) { |
|---|
| 822 | my $state = MT->translate("Cloning templates for blog..."); |
|---|
| 823 | $callback->($state, "tmpls"); |
|---|
| 824 | require MT::Template; |
|---|
| 825 | $iter = MT::Template->load_iter({ blog_id => $old_blog_id }); |
|---|
| 826 | $counter = 0; |
|---|
| 827 | while (my $tmpl = $iter->()) { |
|---|
| 828 | $callback->($state . " " . MT->translate("[_1] records processed...", $counter), 'tmpls') |
|---|
| 829 | if $counter && ($counter % 100 == 0); |
|---|
| 830 | my $tmpl_id = $tmpl->id; |
|---|
| 831 | $counter++; |
|---|
| 832 | delete $tmpl->{column_values}->{id}; |
|---|
| 833 | delete $tmpl->{changed_cols}->{id}; |
|---|
| 834 | # linked_file won't be cloned for now because |
|---|
| 835 | # new blog does not have site_path - breaks relative path |
|---|
| 836 | delete $tmpl->{column_values}->{linked_file}; |
|---|
| 837 | delete $tmpl->{column_values}->{linked_file_mtime}; |
|---|
| 838 | delete $tmpl->{column_values}->{linked_file_size}; |
|---|
| 839 | $tmpl->blog_id($new_blog_id); |
|---|
| 840 | $tmpl->save or die $tmpl->errstr; |
|---|
| 841 | $tmpl_map{$tmpl_id} = $tmpl->id; |
|---|
| 842 | } |
|---|
| 843 | $callback->($state . " " . MT->translate("[_1] records processed.", $counter), 'tmpls'); |
|---|
| 844 | |
|---|
| 845 | $state = MT->translate("Cloning template maps for blog..."); |
|---|
| 846 | $callback->($state, "tmplmaps"); |
|---|
| 847 | require MT::TemplateMap; |
|---|
| 848 | $iter = MT::TemplateMap->load_iter({ blog_id => $old_blog_id }); |
|---|
| 849 | $counter = 0; |
|---|
| 850 | while (my $map = $iter->()) { |
|---|
| 851 | $callback->($state . " " . MT->translate("[_1] records processed...", $counter), 'tmplmaps') |
|---|
| 852 | if $counter && ($counter % 100 == 0); |
|---|
| 853 | $counter++; |
|---|
| 854 | delete $map->{column_values}->{id}; |
|---|
| 855 | delete $map->{changed_cols}->{id}; |
|---|
| 856 | $map->template_id($tmpl_map{$map->template_id}); |
|---|
| 857 | $map->blog_id($new_blog_id); |
|---|
| 858 | $map->save or die $map->errstr; |
|---|
| 859 | } |
|---|
| 860 | $callback->($state . " " . MT->translate("[_1] records processed.", $counter), 'tmplmaps'); |
|---|
| 861 | } |
|---|
| 862 | |
|---|
| 863 | MT->run_callbacks(ref($blog). '::post_clone', |
|---|
| 864 | OldBlogId => $blog->id, old_blog_id => $blog->id, |
|---|
| 865 | NewBlogId => $new_blog->id, new_blog_id => $new_blog->id, |
|---|
| 866 | OldObject => $blog, old_object => $blog, |
|---|
| 867 | NewObject => $new_blog, new_object => $new_blog, |
|---|
| 868 | EntryMap => \%entry_map, entry_map => \%entry_map, |
|---|
| 869 | CategoryMap => \%cat_map, category_map => \%cat_map, |
|---|
| 870 | TrackbackMap => \%tb_map, trackback_map => \%tb_map, |
|---|
| 871 | TemplateMap => \%tmpl_map, template_map => \%tmpl_map, |
|---|
| 872 | Callback => $callback, callback => $callback, |
|---|
| 873 | ); |
|---|
| 874 | $new_blog; |
|---|
| 875 | } |
|---|
| 876 | |
|---|
| 877 | sub smart_replace { |
|---|
| 878 | my $blog = shift; |
|---|
| 879 | if (@_) { |
|---|
| 880 | $blog->nwc_smart_replace(@_); |
|---|
| 881 | return; |
|---|
| 882 | } |
|---|
| 883 | my $val = $blog->nwc_smart_replace; |
|---|
| 884 | return defined($val) ? $val : MT->config->NwcSmartReplace; |
|---|
| 885 | } |
|---|
| 886 | |
|---|
| 887 | sub smart_replace_fields { |
|---|
| 888 | my $blog = shift; |
|---|
| 889 | if (@_) { |
|---|
| 890 | $blog->nwc_replace_field(@_); |
|---|
| 891 | return; |
|---|
| 892 | } |
|---|
| 893 | my $val = $blog->nwc_replace_field; |
|---|
| 894 | return defined($val) ? $val : MT->config->NwcReplaceField; |
|---|
| 895 | } |
|---|
| 896 | |
|---|
| 897 | #trans('blog') |
|---|
| 898 | #trans('blogs') |
|---|
| 899 | |
|---|
| 900 | 1; |
|---|
| 901 | __END__ |
|---|
| 902 | |
|---|
| 903 | =head1 NAME |
|---|
| 904 | |
|---|
| 905 | MT::Blog - Movable Type blog record |
|---|
| 906 | |
|---|
| 907 | =head1 SYNOPSIS |
|---|
| 908 | |
|---|
| 909 | use MT::Blog; |
|---|
| 910 | my $blog = MT::Blog->load($blog_id); |
|---|
| 911 | $blog->name('Some new name'); |
|---|
| 912 | $blog->save |
|---|
| 913 | or die $blog->errstr; |
|---|
| 914 | |
|---|
| 915 | =head1 DESCRIPTION |
|---|
| 916 | |
|---|
| 917 | An I<MT::Blog> object represents a blog in the Movable Type system. It |
|---|
| 918 | contains all of the settings, preferences, and configuration for a particular |
|---|
| 919 | blog. It does not contain any per-author permissions settings--for those, |
|---|
| 920 | look at the I<MT::Permission> object. |
|---|
| 921 | |
|---|
| 922 | =head1 USAGE |
|---|
| 923 | |
|---|
| 924 | As a subclass of I<MT::Object>, I<MT::Blog> inherits all of the |
|---|
| 925 | data-management and -storage methods from that class; thus you should look |
|---|
| 926 | at the I<MT::Object> documentation for details about creating a new object, |
|---|
| 927 | loading an existing object, saving an object, etc. |
|---|
| 928 | |
|---|
| 929 | The following methods are unique to the I<MT::Blog> interface: |
|---|
| 930 | |
|---|
| 931 | =head2 $blog->file_mgr |
|---|
| 932 | |
|---|
| 933 | Returns the I<MT::FileMgr> object specific to this particular blog. |
|---|
| 934 | |
|---|
| 935 | =head1 DATA ACCESS METHODS |
|---|
| 936 | |
|---|
| 937 | The I<MT::Blog> object holds the following pieces of data. These fields can |
|---|
| 938 | be accessed and set using the standard data access methods described in the |
|---|
| 939 | I<MT::Object> documentation. |
|---|
| 940 | |
|---|
| 941 | =over 4 |
|---|
| 942 | |
|---|
| 943 | =item * id |
|---|
| 944 | |
|---|
| 945 | The numeric ID of the blog. |
|---|
| 946 | |
|---|
| 947 | =item * name |
|---|
| 948 | |
|---|
| 949 | The name of the blog. |
|---|
| 950 | |
|---|
| 951 | =item * description |
|---|
| 952 | |
|---|
| 953 | The blog description. |
|---|
| 954 | |
|---|
| 955 | =item * site_path |
|---|
| 956 | |
|---|
| 957 | The path to the directory containing the blog's output index templates. |
|---|
| 958 | |
|---|
| 959 | =item * site_url |
|---|
| 960 | |
|---|
| 961 | The URL corresponding to the I<site_path>. |
|---|
| 962 | |
|---|
| 963 | =item * archive_path |
|---|
| 964 | |
|---|
| 965 | The path to the directory where the blog's archives are stored. |
|---|
| 966 | |
|---|
| 967 | =item * archive_url |
|---|
| 968 | |
|---|
| 969 | The URL corresponding to the I<archive_path>. |
|---|
| 970 | |
|---|
| 971 | =item * server_offset |
|---|
| 972 | |
|---|
| 973 | A slight misnomer, this is actually the timezone that the B<user> has |
|---|
| 974 | selected; the value is the offset from GMT. |
|---|
| 975 | |
|---|
| 976 | =item * archive_type |
|---|
| 977 | |
|---|
| 978 | A comma-separated list of archive types used in this particular blog, where |
|---|
| 979 | an archive type is one of the following: C<Individual>, C<Daily>, C<Weekly>, |
|---|
| 980 | C<Monthly>, or C<Category>. For example, a blog's I<archive_type> would be |
|---|
| 981 | C<Individual,Monthly> if the blog were using C<Individual> and C<Monthly> |
|---|
| 982 | archives. |
|---|
| 983 | |
|---|
| 984 | =item * archive_type_preferred |
|---|
| 985 | |
|---|
| 986 | The "preferred" archive type, which is used when constructing a link to the |
|---|
| 987 | archive page for a particular archive--if multiple archive types are selected, |
|---|
| 988 | for example, the link can only point to one of those archives. The preferred |
|---|
| 989 | archive type (which should be one of the archive types set in I<archive_type>, |
|---|
| 990 | above) specifies to which archive this link should point (among other things). |
|---|
| 991 | |
|---|
| 992 | =item * days_on_index |
|---|
| 993 | |
|---|
| 994 | The number of days to be displayed on the index. |
|---|
| 995 | |
|---|
| 996 | =item * file_extension |
|---|
| 997 | |
|---|
| 998 | The file extension to be used for archive pages. |
|---|
| 999 | |
|---|
| 1000 | =item * email_new_comments |
|---|
| 1001 | |
|---|
| 1002 | A boolean flag specifying whether authors should be notified of new comments |
|---|
| 1003 | posted on entries they have written. |
|---|
| 1004 | |
|---|
| 1005 | =item * allow_comment_html |
|---|
| 1006 | |
|---|
| 1007 | A boolean flag specifying whether HTML should be allowed in comments. If it |
|---|
| 1008 | is not allowed, it is automatically stripped before building the page (note |
|---|
| 1009 | that the content stored in the database is B<not> stripped). |
|---|
| 1010 | |
|---|
| 1011 | =item * autolink_urls |
|---|
| 1012 | |
|---|
| 1013 | A boolean flag specifying whether URLs in comments should be turned into |
|---|
| 1014 | links. Note that this setting is only taken into account if |
|---|
| 1015 | I<allow_comment_html> is turned off. |
|---|
| 1016 | |
|---|
| 1017 | =item * sort_order_posts |
|---|
| 1018 | |
|---|
| 1019 | The default sort order for entries. Valid values are either C<ascend> or |
|---|
| 1020 | C<descend>. |
|---|
| 1021 | |
|---|
| 1022 | =item * sort_order_comments |
|---|
| 1023 | |
|---|
| 1024 | The default sort order for comments. Valid values are either C<ascend> or |
|---|
| 1025 | C<descend>. |
|---|
| 1026 | |
|---|
| 1027 | =item * allow_comments_default |
|---|
| 1028 | |
|---|
| 1029 | The default value for the I<allow_comments> field in the I<MT::Entry> object. |
|---|
| 1030 | |
|---|
| 1031 | =item * convert_paras |
|---|
| 1032 | |
|---|
| 1033 | A comma-separated list of text filters to apply to each entry when it |
|---|
| 1034 | is built. |
|---|
| 1035 | |
|---|
| 1036 | =item * convert_paras_comments |
|---|
| 1037 | |
|---|
| 1038 | A comma-separated list of text filters to apply to each comment when it |
|---|
| 1039 | is built. |
|---|
| 1040 | |
|---|
| 1041 | =item * status_default |
|---|
| 1042 | |
|---|
| 1043 | The default value for the I<status> field in the I<MT::Entry> object. |
|---|
| 1044 | |
|---|
| 1045 | =item * allow_anon_comments |
|---|
| 1046 | |
|---|
| 1047 | A boolean flag specifying whether anonymous comments (those posted without |
|---|
| 1048 | a name or an email address) are allowed. |
|---|
| 1049 | |
|---|
| 1050 | =item * allow_unreg_comments |
|---|
| 1051 | |
|---|
| 1052 | A boolean flag specifying whether unregistered comments (those posted |
|---|
| 1053 | without a validated email/password pair) are allowed. |
|---|
| 1054 | |
|---|
| 1055 | =item * words_in_excerpt |
|---|
| 1056 | |
|---|
| 1057 | The number of words in an auto-generated excerpt. |
|---|
| 1058 | |
|---|
| 1059 | =item * ping_weblogs |
|---|
| 1060 | |
|---|
| 1061 | A boolean flag specifying whether the system should send an XML-RPC ping to |
|---|
| 1062 | I<weblogs.com> after an entry is saved. |
|---|
| 1063 | |
|---|
| 1064 | =item * mt_update_key |
|---|
| 1065 | |
|---|
| 1066 | The Movable Type Recently Updated Key to be sent to I<movabletype.org> after |
|---|
| 1067 | an entry is saved. |
|---|
| 1068 | |
|---|
| 1069 | =item * language |
|---|
| 1070 | |
|---|
| 1071 | The language for date and time display for this particular blog. |
|---|
| 1072 | |
|---|
| 1073 | =item * welcome_msg |
|---|
| 1074 | |
|---|
| 1075 | The welcome message to be displayed on the main Editing Menu for this blog. |
|---|
| 1076 | Should contain all desired HTML formatting. |
|---|
| 1077 | |
|---|
| 1078 | =back |
|---|
| 1079 | |
|---|
| 1080 | =head1 METHODS |
|---|
| 1081 | |
|---|
| 1082 | =over 4 |
|---|
| 1083 | |
|---|
| 1084 | =item * clone( [ \%parameters ] ) |
|---|
| 1085 | |
|---|
| 1086 | MT::Blog provides a clone method that supports cloning of all known child |
|---|
| 1087 | records related to the MT::Blog object. To invoke this behavior, you |
|---|
| 1088 | simply specify a parameter hash with a 'Children' key set. |
|---|
| 1089 | |
|---|
| 1090 | # Clones blog and all data related to this blog within the database. |
|---|
| 1091 | my $new_blog = $original_blog->clone({ Children => 1 }); |
|---|
| 1092 | |
|---|
| 1093 | You may further specify what kind of records are cloned in the process |
|---|
| 1094 | of cloning child objects. Use the 'Classes' parameter to specifically |
|---|
| 1095 | exclude particular classes: |
|---|
| 1096 | |
|---|
| 1097 | # Clones everything except comments and trackback pings |
|---|
| 1098 | my $new_blog = $original_blog->clone({ |
|---|
| 1099 | Children => 1, |
|---|
| 1100 | Classes => { 'MT::Comments' => 0, 'MT::TBPing' => 0 } |
|---|
| 1101 | }); |
|---|
| 1102 | |
|---|
| 1103 | Note: Certain exclusions will prevent the clone process from including |
|---|
| 1104 | other classes. For instance, if you exclude MT::Trackback, all MT::TBPing |
|---|
| 1105 | objects are automatically excluded. |
|---|
| 1106 | |
|---|
| 1107 | =back |
|---|
| 1108 | |
|---|
| 1109 | =head1 DATA LOOKUP |
|---|
| 1110 | |
|---|
| 1111 | In addition to numeric ID lookup, you can look up or sort records by any |
|---|
| 1112 | combination of the following fields. See the I<load> documentation in |
|---|
| 1113 | I<MT::Object> for more information. |
|---|
| 1114 | |
|---|
| 1115 | =over 4 |
|---|
| 1116 | |
|---|
| 1117 | =item * name |
|---|
| 1118 | |
|---|
| 1119 | =back |
|---|
| 1120 | |
|---|
| 1121 | =head1 NOTES |
|---|
| 1122 | |
|---|
| 1123 | =over 4 |
|---|
| 1124 | |
|---|
| 1125 | =item * |
|---|
| 1126 | |
|---|
| 1127 | When you remove a blog using I<MT::Blog::remove>, in addition to removing the |
|---|
| 1128 | blog record, all of the entries, notifications, permissions, comments, |
|---|
| 1129 | templates, and categories in that blog will also be removed. |
|---|
| 1130 | |
|---|
| 1131 | =item * |
|---|
| 1132 | |
|---|
| 1133 | Because the system needs to load I<MT::Blog> objects from disk relatively |
|---|
| 1134 | often during the duration of one request, I<MT::Blog> objects are cached by |
|---|
| 1135 | the I<MT::Blog::load> object so that each blog only need be loaded once. The |
|---|
| 1136 | I<MT::Blog> objects are cached in the I<MT::Request> singleton object; note |
|---|
| 1137 | that this caching B<only occurs> if the blogs are loaded by numeric ID. |
|---|
| 1138 | |
|---|
| 1139 | =back |
|---|
| 1140 | |
|---|
| 1141 | =head1 AUTHOR & COPYRIGHTS |
|---|
| 1142 | |
|---|
| 1143 | Please see the I<MT> manpage for author, copyright, and license information. |
|---|
| 1144 | |
|---|
| 1145 | =cut |
|---|