radiant-vhost-extension 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. data/.gitmodules +3 -0
  2. data/README +64 -0
  3. data/Rakefile +125 -0
  4. data/VERSION +1 -0
  5. data/app/controllers/admin/sites_controller.rb +16 -0
  6. data/app/models/site.rb +26 -0
  7. data/app/models/site_association_observer.rb +8 -0
  8. data/app/views/admin/sites/_form.html.haml +19 -0
  9. data/app/views/admin/sites/edit.html.haml +5 -0
  10. data/app/views/admin/sites/index.html.haml +24 -0
  11. data/app/views/admin/sites/new.html.haml +5 -0
  12. data/app/views/admin/sites/remove.html.haml +19 -0
  13. data/app/views/admin/users/_edit_sites.html.haml +4 -0
  14. data/app/views/admin/users/_site_admin_roles.html.haml +5 -0
  15. data/app/views/admin/users/_sites_td.html.haml +2 -0
  16. data/app/views/admin/users/_sites_th.html.haml +2 -0
  17. data/config/routes.rb +5 -0
  18. data/db/migrate/001_create_sites.rb +11 -0
  19. data/db/migrate/002_add_sites_users.rb +18 -0
  20. data/db/migrate/003_replace_snippet_name_unique_index.rb +10 -0
  21. data/db/migrate/004_add_site_admin_to_users.rb +9 -0
  22. data/db/templates/empty.yml +7 -0
  23. data/db/templates/simple-blog.yml +213 -0
  24. data/lib/bootstrap_with_site_id.rb +50 -0
  25. data/lib/radiant-vhost-extension.rb +0 -0
  26. data/lib/site_scope.rb +65 -0
  27. data/lib/tasks/add_site_columns.rb +44 -0
  28. data/lib/tasks/vhost_extension_tasks.rake +115 -0
  29. data/lib/vhost/admin_users_controller_extensions.rb +22 -0
  30. data/lib/vhost/admin_users_helper_extensions.rb +17 -0
  31. data/lib/vhost/application_controller_extensions.rb +36 -0
  32. data/lib/vhost/application_helper_extensions.rb +15 -0
  33. data/lib/vhost/controller_access_extensions.rb +16 -0
  34. data/lib/vhost/pages_controller_extensions.rb +11 -0
  35. data/lib/vhost/radiant_cache_extensions.rb +53 -0
  36. data/lib/vhost/site_scoped_model_extensions.rb +46 -0
  37. data/lib/vhost_default_config.yml +22 -0
  38. data/spec/controllers/admin/pages_controller_spec.rb +173 -0
  39. data/spec/controllers/admin/sites_controller_spec.rb +33 -0
  40. data/spec/controllers/site_controller_spec.rb +33 -0
  41. data/spec/datasets/site_home_pages_dataset.rb +76 -0
  42. data/spec/datasets/site_pages_dataset.rb +31 -0
  43. data/spec/datasets/site_users_dataset.rb +50 -0
  44. data/spec/datasets/sites_dataset.rb +10 -0
  45. data/spec/datasets/sites_site_users_and_site_pages_dataset.rb +8 -0
  46. data/spec/datasets/sites_site_users_dataset.rb +13 -0
  47. data/spec/fixtures/page_parts.yml +11 -0
  48. data/spec/fixtures/pages.yml +19 -0
  49. data/spec/fixtures/sites.yml +7 -0
  50. data/spec/fixtures/sites_users.yml +6 -0
  51. data/spec/fixtures/users.yml +35 -0
  52. data/spec/models/page_spec.rb +22 -0
  53. data/spec/models/site_spec.rb +19 -0
  54. data/spec/models/user_spec.rb +16 -0
  55. data/spec/spec.opts +6 -0
  56. data/spec/spec_helper.rb +42 -0
  57. data/test/fixtures/page_parts.yml +11 -0
  58. data/test/fixtures/pages.yml +19 -0
  59. data/test/fixtures/sites.yml +7 -0
  60. data/test/fixtures/sites_users.yml +6 -0
  61. data/test/fixtures/users.yml +35 -0
  62. data/test/functional/admin/pages_controller_test.rb +142 -0
  63. data/test/functional/admin/site_controller_test.rb +53 -0
  64. data/test/functional/vhost_extension_test.rb +37 -0
  65. data/test/helpers/page_part_test_helper.rb +49 -0
  66. data/test/test_helper.rb +17 -0
  67. data/test/unit/site_test.rb +26 -0
  68. data/vhost_extension.rb +154 -0
  69. metadata +167 -0
data/.gitmodules ADDED
@@ -0,0 +1,3 @@
1
+ [submodule "vendor/scoped_access"]
2
+ path = vendor/scoped_access
3
+ url = git://github.com/maiha/scoped_access.git
data/README ADDED
@@ -0,0 +1,64 @@
1
+ Host multiple separate websites on the same Radiant installation each with their
2
+ own users, pages, snippets and layouts (soon to be supporting other extensions).
3
+ Administer users and sites from any domain using your administrative accounts
4
+ and manage website content by logging into each domain.
5
+
6
+ IMPORTANT NOTES ABOUT VHOST
7
+ - Not compatible with the multi_site extension
8
+ - Uses the scoped_access plugin, make sure none of your extensions have a
9
+ conflicting version of the plugin.
10
+ - Hooks into the Radiant 'bootstrap' functionality and currently overwrites the
11
+ standard templates with a modified version of the Simple Blog (i.e. no Styled
12
+ Blog or Coffee template)
13
+
14
+ INSTRUCTIONS
15
+ Currently (April 26th, 2009) you need the freshest version of Radiant (0.7.1)
16
+ which includes Rails 2.2.2 to run vhost. The following instructions use git
17
+ to directly check out the latest version of Radiant so you may need to adjust
18
+ them slightly. Once the Radiant gem supports Rails 2.2.2 these instructions
19
+ will reflect the proper way to run and install vhost.
20
+
21
+ * Run 'git clone git://github.com/radiant/radiant.git yoursite'
22
+ * In /yoursite run:
23
+ * git submodule init
24
+ * git submodule update
25
+ * Create production, development and test database schemas
26
+ * Update /yoursite/config/database.yml to point to the schemas
27
+ * In /yoursite/vendor/extensions run:
28
+ * git clone git://github.com/saturnflyer/radiant-vhost-extension.git vhost
29
+ * In /yoursite/vendor/extensions/vhost run:
30
+ * git submodule init
31
+ * git submodule update
32
+ * In /yoursite run:
33
+ * rake development db:bootstrap
34
+ * rake db:test:clone_structure (this one may be unnecessary)
35
+ * rake db:test:clone
36
+ * Finally, in /yoursite run:
37
+ * rake spec:extensions EXT=vhost
38
+
39
+ You should see a number of spec examples running and passing. If you don't,
40
+ or they're failing, something has gone wrong!
41
+
42
+ VHOST SUPPORT FOR OTHER EXTENSIONS
43
+ Vhost support for other extensions is enabled by creating a /config/vhost.yml
44
+ file containing the names of the models that should be scoped down per site. If
45
+ site scoping for an extension cannot be specified through the model (i.e. it
46
+ uses the file system to present data or otherwise doesn't use an ActiveRecord)
47
+ then currently you cannot enable site scoping.
48
+
49
+ Example vhost.yml:
50
+
51
+ models:
52
+ # Class name
53
+ ManagedFile:
54
+ # Property requiring definition of validates_uniqueness_of
55
+ filename:
56
+ # Parameters to pass to validates_uniqueness_of
57
+ scope:
58
+ - site_id
59
+ message:
60
+ 'file name is already in use'
61
+ # Any classes used in Single Table Inheritance(STI)
62
+ sti_classes:
63
+ - OneClass
64
+ - TwoClass
data/Rakefile ADDED
@@ -0,0 +1,125 @@
1
+ require 'rake'
2
+
3
+ begin
4
+ require 'jeweler'
5
+ Jeweler::Tasks.new do |gem|
6
+ gem.name = "radiant-vhost-extension"
7
+ gem.summary = %Q{Vhost Extension for Radiant CMS}
8
+ gem.description = %Q{Host more than one site in a single instance of Radiant.}
9
+ gem.email = "jim@saturnflyer.com"
10
+ gem.homepage = "http://github.com/saturnflyer/radiant-vhost-extension"
11
+ gem.authors = ["Jason Garber",'Kaleb Walton', 'Jim Gay']
12
+ gem.add_development_dependency "radiant"
13
+ end
14
+ rescue LoadError
15
+ puts "Jeweler (or a dependency) not available. This is only required if you plan to package vhost as a gem."
16
+ end
17
+
18
+
19
+ # Determine where the RSpec plugin is by loading the boot
20
+ unless defined? RADIANT_ROOT
21
+ ENV["RAILS_ENV"] = "test"
22
+ case
23
+ when ENV["RADIANT_ENV_FILE"]
24
+ require File.dirname(ENV["RADIANT_ENV_FILE"]) + "/boot"
25
+ when File.dirname(__FILE__) =~ %r{vendor/radiant/vendor/extensions}
26
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../")}/config/boot"
27
+ else
28
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../")}/config/boot"
29
+ end
30
+ end
31
+
32
+ require 'rake/rdoctask'
33
+ require 'rake/testtask'
34
+
35
+ if defined? RADIANT_ROOT
36
+ rspec_base = File.expand_path(RADIANT_ROOT + '/vendor/plugins/rspec/lib')
37
+ $LOAD_PATH.unshift(rspec_base) if File.exist?(rspec_base)
38
+ end
39
+
40
+ require 'spec/rake/spectask'
41
+
42
+ # Cleanup the RADIANT_ROOT constant so specs will load the environment
43
+ Object.send(:remove_const, :RADIANT_ROOT)
44
+
45
+ extension_root = File.expand_path(File.dirname(__FILE__))
46
+
47
+ task :default => :spec
48
+ task :stats => "spec:statsetup"
49
+
50
+ desc "Run all specs in spec directory"
51
+ Spec::Rake::SpecTask.new(:spec) do |t|
52
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
53
+ t.spec_files = FileList['spec/**/*_spec.rb']
54
+ end
55
+
56
+ namespace :spec do
57
+ desc "Run all specs in spec directory with RCov"
58
+ Spec::Rake::SpecTask.new(:rcov) do |t|
59
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
60
+ t.spec_files = FileList['spec/**/*_spec.rb']
61
+ t.rcov = true
62
+ t.rcov_opts = ['--exclude', 'spec', '--rails']
63
+ end
64
+
65
+ desc "Print Specdoc for all specs"
66
+ Spec::Rake::SpecTask.new(:doc) do |t|
67
+ t.spec_opts = ["--format", "specdoc", "--dry-run"]
68
+ t.spec_files = FileList['spec/**/*_spec.rb']
69
+ end
70
+
71
+ [:models, :controllers, :views, :helpers].each do |sub|
72
+ desc "Run the specs under spec/#{sub}"
73
+ Spec::Rake::SpecTask.new(sub) do |t|
74
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
75
+ t.spec_files = FileList["spec/#{sub}/**/*_spec.rb"]
76
+ end
77
+ end
78
+
79
+ # Setup specs for stats
80
+ task :statsetup do
81
+ require 'code_statistics'
82
+ ::STATS_DIRECTORIES << %w(Model\ specs spec/models)
83
+ ::STATS_DIRECTORIES << %w(View\ specs spec/views)
84
+ ::STATS_DIRECTORIES << %w(Controller\ specs spec/controllers)
85
+ ::STATS_DIRECTORIES << %w(Helper\ specs spec/views)
86
+ ::CodeStatistics::TEST_TYPES << "Model specs"
87
+ ::CodeStatistics::TEST_TYPES << "View specs"
88
+ ::CodeStatistics::TEST_TYPES << "Controller specs"
89
+ ::CodeStatistics::TEST_TYPES << "Helper specs"
90
+ ::STATS_DIRECTORIES.delete_if {|a| a[0] =~ /test/}
91
+ end
92
+
93
+ namespace :db do
94
+ namespace :fixtures do
95
+ desc "Load fixtures (from spec/fixtures) into the current environment's database. Load specific fixtures using FIXTURES=x,y"
96
+ task :load => :environment do
97
+ require 'active_record/fixtures'
98
+ ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym)
99
+ (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir.glob(File.join(RAILS_ROOT, 'spec', 'fixtures', '*.{yml,csv}'))).each do |fixture_file|
100
+ Fixtures.create_fixtures('spec/fixtures', File.basename(fixture_file, '.*'))
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ desc 'Generate documentation for the vhost extension.'
108
+ Rake::RDocTask.new(:rdoc) do |rdoc|
109
+ rdoc.rdoc_dir = 'rdoc'
110
+ rdoc.title = 'VhostExtension'
111
+ rdoc.options << '--line-numbers' << '--inline-source'
112
+ rdoc.rdoc_files.include('README')
113
+ rdoc.rdoc_files.include('lib/**/*.rb')
114
+ end
115
+
116
+ # For extensions that are in transition
117
+ desc 'Test the vhost extension.'
118
+ Rake::TestTask.new(:test) do |t|
119
+ t.libs << 'lib'
120
+ t.pattern = 'test/**/*_test.rb'
121
+ t.verbose = true
122
+ end
123
+
124
+ # Load any custom rakefiles for extension
125
+ Dir[File.dirname(__FILE__) + '/tasks/*.rake'].sort.each { |f| require f }
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 2.1.0
@@ -0,0 +1,16 @@
1
+ class Admin::SitesController < Admin::ResourceController
2
+ only_allow_access_to :index, :show, :new, :create, :edit, :update, :remove, :destroy, :switch_to,
3
+ :when => :site_admin,
4
+ :denied_url => { :controller => 'pages', :action => 'index' },
5
+ :denied_message => 'You must have administrative privileges to perform this action.'
6
+
7
+ def switch_to
8
+ site = Site.find(params[:id])
9
+ if site
10
+ redirect_to "http://#{site.hostname}#{request.port.to_s == '80' ? '' : ":#{request.port}"}/admin"
11
+ else
12
+ render :index
13
+ end
14
+ end
15
+
16
+ end
@@ -0,0 +1,26 @@
1
+ class Site < ActiveRecord::Base
2
+ has_and_belongs_to_many :users
3
+ has_many :pages
4
+
5
+ accepts_nested_attributes_for :users
6
+ VhostExtension.MODELS.each do |model|
7
+ has_many model.tableize.to_sym unless model.tableize.match(/pages|users/) # unless already defined
8
+ end
9
+
10
+ def allow_access_for(user)
11
+ # Site Admins can access all sites. Users can only access sites to which they belong
12
+ user.site_admin? || self.users.include?(user)
13
+ end
14
+
15
+ def homepage
16
+ self.pages.find(:first, :conditions => {:parent_id => nil})
17
+ end
18
+
19
+ def self.find_by_hostname(hostname)
20
+ # allow vhost to be added to existing sites
21
+ if Site.count == 0
22
+ Site.create!(:hostname => hostname)
23
+ end
24
+ self.find(:first, :conditions => ["hostname LIKE ?", "%#{hostname}%"])
25
+ end
26
+ end
@@ -0,0 +1,8 @@
1
+ class SiteAssociationObserver < ActiveRecord::Observer
2
+ observe *VhostExtension::SITE_SPECIFIC_MODELS.collect(&:constantize)
3
+
4
+ def before_validation(model)
5
+ # Set the site_id automatically if it's not already set
6
+ model.site_id ||= model.class.current_site.id
7
+ end
8
+ end
@@ -0,0 +1,19 @@
1
+ - form_for [:admin, @site] do |f|
2
+ = render_region :form_top
3
+ .form-area
4
+ - render_region :form do |form|
5
+ - form.edit_hostname do
6
+ %p.hostname
7
+ %label{:for=>"site_hostname"} Hostname
8
+ = f.text_field "hostname", :class => 'textbox', :maxlength => 100
9
+ - form.edit_users do
10
+ %p.users
11
+ %label{:for=>"site_users"} Users
12
+ = f.collection_select :user_ids, User.find(:all), :id, :name, {}, :multiple => true, :name => 'site[user_ids][]', :size => '10'
13
+ - render_region :form_bottom do |form_bottom|
14
+ - form_bottom.edit_buttons do
15
+ %p.buttons
16
+ = save_model_button(@site)
17
+ = save_model_and_continue_editing_button(@site)
18
+ or
19
+ = link_to 'Cancel', admin_sites_url
@@ -0,0 +1,5 @@
1
+ - render_region :main do |main|
2
+ - main.edit_header do
3
+ %h1 Edit Site
4
+ - main.edit_form do
5
+ = render :partial => 'form'
@@ -0,0 +1,24 @@
1
+ .outset
2
+ %table#sites.index{:cellpadding=>"0", :cellspacing=>"0", :border=>"0"}
3
+ %thead
4
+ %tr
5
+ %th.hostname Host
6
+ %th Administration
7
+ %th.users Users
8
+ %th.modify Modify
9
+ %tbody
10
+ - unless @sites.empty?
11
+ - for site in @sites
12
+ %tr.node.level-1
13
+ %td.site
14
+ = link_to site.hostname, edit_admin_site_url(:id => site)
15
+ %td.site
16
+ = link_to 'Go', switch_to_admin_site_url(site)
17
+ %td.users= site.users.collect(&:name).join(', ')
18
+ %td.remove= link_to('Remove Site', remove_admin_site_url(:id => site))
19
+ - else
20
+ %tr
21
+ %td.note{:colspan=>3} No Sites
22
+ #actions
23
+ %ul
24
+ %li= link_to 'New Site', new_admin_site_url
@@ -0,0 +1,5 @@
1
+ - render_region :main do |main|
2
+ - main.edit_header do
3
+ %h1 New Site
4
+ - main.edit_form do
5
+ = render :partial => 'form'
@@ -0,0 +1,19 @@
1
+ %h1 Remove Site
2
+
3
+ %p
4
+ Are you sure you want to
5
+ %strong.warning permanently remove
6
+ the following site?
7
+
8
+ %table.index#sites{:cellpadding=>0, :cellspacing=>0, :border=>0}
9
+ %tbody
10
+ %tr.node.level-1
11
+ %td.site
12
+ = image('page', :alt => "page-icon")
13
+ = @site.hostname
14
+
15
+ - form_for [:admin, @site], :html => {:method => :delete} do
16
+ %p.buttons
17
+ %input.button{:type=>"submit", :value=>"Delete Site"}/
18
+ or
19
+ = link_to 'Cancel', admin_sites_url
@@ -0,0 +1,4 @@
1
+ - if current_user.site_admin?
2
+ %p
3
+ = f.label :site_ids, 'Sites', :class => "optional"
4
+ ~ f.collection_select :site_ids, current_user.site_admin? ? Site.find(:all) : current_user.sites, :id, :hostname, {}, :multiple => true, :name => 'user[site_ids][]', :size => '10', :class => "textarea"
@@ -0,0 +1,5 @@
1
+ - if current_user.site_admin?
2
+ %p
3
+ = f.check_box "site_admin", :class => "checkbox"
4
+ = f.label :site_admin, 'Site admin', :class => "checkbox"
5
+ A site admin can make changes to all sites.
@@ -0,0 +1,2 @@
1
+ - if current_user.site_admin?
2
+ %td.sites= sites(user)
@@ -0,0 +1,2 @@
1
+ - if current_user.site_admin?
2
+ %th Sites
data/config/routes.rb ADDED
@@ -0,0 +1,5 @@
1
+ ActionController::Routing::Routes.draw do |map|
2
+ map.namespace :admin, :member => { :remove => :get } do |admin|
3
+ admin.resources :sites, :member => {:switch_to => :get}
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ class CreateSites < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :sites do |t|
4
+ t.column :hostname, :string
5
+ end
6
+ end
7
+
8
+ def self.down
9
+ drop_table :sites
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ class AddSitesUsers < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :sites_users, :id => false do |t|
4
+ t.column :site_id, :integer
5
+ t.column :user_id, :integer
6
+ end
7
+
8
+ add_index :sites_users, [:site_id, :user_id], :unique => true
9
+ add_index :sites_users, :user_id
10
+ end
11
+
12
+
13
+ def self.down
14
+ remove_index :sites_users, [:site_id, :user_id]
15
+ remove_index :sites_users, :user_id
16
+ drop_table :sites_users
17
+ end
18
+ end
@@ -0,0 +1,10 @@
1
+ class ReplaceSnippetNameUniqueIndex < ActiveRecord::Migration
2
+ def self.up
3
+ remove_index :snippets, :name => :name
4
+ end
5
+
6
+
7
+ def self.down
8
+ add_index "snippets", ["name"], :name => "name", :unique => true
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ class AddSiteAdminToUsers < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :users, :site_admin, :boolean
4
+ end
5
+
6
+ def self.down
7
+ remove_column :users, :site_admin
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ name: Empty
2
+ description: Don't create any pages, layouts, or snippets.
3
+ records:
4
+ Sites:
5
+ main:
6
+ id: 1
7
+ hostname: '*'
@@ -0,0 +1,213 @@
1
+ name: Simple Blog
2
+ description: Setup Radiant as a simple weblog.
3
+ records:
4
+ Sites:
5
+ main:
6
+ id: 1
7
+ hostname: '*'
8
+ Layouts:
9
+ main:
10
+ id: 1
11
+ site_id: 1
12
+ name: Normal
13
+ content: |
14
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
15
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
16
+ <html>
17
+ <head>
18
+ <title><r:title /></title>
19
+ <link href="/rss/" rel="alternate" title="RSS" type="application/rss+xml" />
20
+ <link rel="stylesheet" type="text/css" href="/styles.css" />
21
+ </head>
22
+ <body>
23
+ <r:snippet name="header" />
24
+ <div id="content">
25
+ <r:content />
26
+ <div id="extended">
27
+ <r:content part="extended" />
28
+ </div>
29
+ </div>
30
+ <r:snippet name="footer" />
31
+ </body>
32
+ </html>
33
+ css:
34
+ id: 2
35
+ site_id: 1
36
+ name: Stylesheet
37
+ content_type: text/css
38
+ content: |
39
+ <r:content />
40
+ xml_feed:
41
+ id: 3
42
+ site_id: 1
43
+ name: XML Feed
44
+ content_type: text/xml
45
+ content: |
46
+ <r:content />
47
+ Snippets:
48
+ header:
49
+ id: 1
50
+ site_id: 1
51
+ name: header
52
+ content: |
53
+ <div id="header">
54
+ <h1><r:title /></h1>
55
+ </div>
56
+ <hr />
57
+ footer:
58
+ id: 2
59
+ site_id: 1
60
+ name: footer
61
+ content: |
62
+ <hr />
63
+ <div id="footer">
64
+ <p>Powered by <a href="http://radiantcms.org/">Radiant CMS</a></p>
65
+ </div>
66
+ Pages:
67
+ home_page:
68
+ id: 1
69
+ site_id: 1
70
+ title: Home Page
71
+ breadcrumb: Home
72
+ slug: /
73
+ layout_id: 1
74
+ status_id: 100
75
+ file_not_found:
76
+ id: 2
77
+ site_id: 1
78
+ title: File Not Found
79
+ breadcrumb: File Not Found
80
+ slug: file-not-found
81
+ class_name: FileNotFoundPage
82
+ parent_id: 1
83
+ status_id: 100
84
+ rss_feed:
85
+ id: 3
86
+ site_id: 1
87
+ title: RSS Feed
88
+ breadcrumb: RSS Feed
89
+ slug: rss
90
+ layout_id: 3
91
+ parent_id: 1
92
+ status_id: 100
93
+ articles:
94
+ id: 4
95
+ site_id: 1
96
+ title: Articles
97
+ breadcrumb: Articles
98
+ slug: articles
99
+ class_name: ArchivePage
100
+ parent_id: 1
101
+ status_id: 100
102
+ first_post:
103
+ id: 5
104
+ site_id: 1
105
+ title: First Post
106
+ breadcrumb: First Post
107
+ slug: first-post
108
+ parent_id: 4
109
+ status_id: 100
110
+ second_post:
111
+ id: 6
112
+ site_id: 1
113
+ title: Second Post
114
+ breadcrumb: Second Post
115
+ slug: second-post
116
+ parent_id: 4
117
+ status_id: 100
118
+ styles:
119
+ id: 7
120
+ site_id: 1
121
+ title: Styles
122
+ breadcrumb: Styles
123
+ slug: styles.css
124
+ parent_id: 1
125
+ layout_id: 2
126
+ status_id: 100
127
+ PageParts:
128
+ home_page:
129
+ id: 1
130
+ name: body
131
+ page_id: 1
132
+ content: |
133
+ <r:find url="/articles/">
134
+ <r:children:each limit="5" order="desc">
135
+ <div class="entry">
136
+ <h3><r:link /> <small><r:author /></small></h3>
137
+ <r:content />
138
+ <r:if_content part="extended"><r:link anchor="extended">Continue Reading&#8230;</r:link></r:if_content>
139
+ </div>
140
+ </r:children:each>
141
+ </r:find>
142
+ file_not_found:
143
+ id: 2
144
+ name: body
145
+ page_id: 2
146
+ filter_id: Textile
147
+ content: |
148
+ The file you were looking for could not be found.
149
+
150
+ Attempted URL: @<r:attempted_url />@
151
+
152
+ It is possible that you typed the URL incorrectly or that you clicked on a bad link.
153
+
154
+ "<< Back to Home Page":/
155
+ rss_feed:
156
+ id: 3
157
+ name: body
158
+ page_id: 3
159
+ content: |
160
+ <?xml version="1.0" encoding="UTF-8"?>
161
+ <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
162
+ <channel>
163
+ <title>Article RSS Feed</title>
164
+ <link>http://your-web-site.com<r:url /></link>
165
+ <language>en-us</language>
166
+ <ttl>40</ttl>
167
+ <description>The main blog feed for my Web site.</description>
168
+ <r:find url="/articles/">
169
+ <r:children:each limit="10">
170
+ <item>
171
+ <title><r:title /></title>
172
+ <description><r:escape_html><r:content /></r:escape_html></description>
173
+ <pubDate><r:rfc1123_date /></pubDate>
174
+ <guid>http://your-web-site.com<r:url /></guid>
175
+ <link>http://your-web-site.com<r:url /></link>
176
+ </item>
177
+ </r:children:each>
178
+ </r:find>
179
+ </channel>
180
+ </rss>
181
+ articles:
182
+ id: 4
183
+ name: body
184
+ page_id: 4
185
+ content: |
186
+ <ul>
187
+ <r:children:each order="desc">
188
+ <li><r:link /></li>
189
+ </r:children:each>
190
+ </ul>
191
+ first_post:
192
+ id: 5
193
+ name: body
194
+ page_id: 5
195
+ filter_id: Textile
196
+ content: |
197
+ This post uses "textile":http://www.textism.com/tools/textile/.
198
+ second_post:
199
+ id: 6
200
+ name: body
201
+ page_id: 6
202
+ filter_id: Markdown
203
+ content: |
204
+ This post uses **Markdown**.
205
+ styles:
206
+ id: 7
207
+ name: body
208
+ page_id: 7
209
+ content: |
210
+ body {
211
+ font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
212
+ font-size: 80%;
213
+ }