radiant 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of radiant might be problematic. Click here for more details.
- data/CHANGELOG +1 -0
- data/CONTRIBUTORS +12 -0
- data/LICENSE +9 -0
- data/README +91 -0
- data/Rakefile +10 -0
- data/app/behaviors/archive_behavior.rb +42 -0
- data/app/behaviors/archive_day_index_behavior.rb +30 -0
- data/app/behaviors/archive_month_index_behavior.rb +30 -0
- data/app/behaviors/archive_year_index_behavior.rb +30 -0
- data/app/behaviors/env_behavior.rb +18 -0
- data/app/behaviors/page_missing_behavior.rb +31 -0
- data/app/controllers/admin/export_controller.rb +8 -0
- data/app/controllers/admin/layout_controller.rb +23 -0
- data/app/controllers/admin/model_controller.rb +119 -0
- data/app/controllers/admin/page_controller.rb +119 -0
- data/app/controllers/admin/snippet_controller.rb +6 -0
- data/app/controllers/admin/user_controller.rb +45 -0
- data/app/controllers/admin/welcome_controller.rb +39 -0
- data/app/controllers/application.rb +32 -0
- data/app/controllers/site_controller.rb +54 -0
- data/app/filters/markdown_filter.rb +9 -0
- data/app/filters/textile_filter.rb +9 -0
- data/app/helpers/admin/export_helper.rb +2 -0
- data/app/helpers/admin/layout_helper.rb +2 -0
- data/app/helpers/admin/page_helper.rb +10 -0
- data/app/helpers/admin/snippet_helper.rb +2 -0
- data/app/helpers/admin/user_helper.rb +2 -0
- data/app/helpers/admin/welcome_helper.rb +2 -0
- data/app/helpers/application_helper.rb +141 -0
- data/app/helpers/site_helper.rb +2 -0
- data/app/models/archive_finder.rb +66 -0
- data/app/models/behavior.rb +194 -0
- data/app/models/layout.rb +13 -0
- data/app/models/page.rb +91 -0
- data/app/models/page_context.rb +526 -0
- data/app/models/page_part.rb +13 -0
- data/app/models/radiant/config.rb +53 -0
- data/app/models/radiant/exporter.rb +11 -0
- data/app/models/response_cache.rb +112 -0
- data/app/models/snippet.rb +16 -0
- data/app/models/status.rb +31 -0
- data/app/models/text_filter.rb +11 -0
- data/app/models/user.rb +70 -0
- data/app/models/user_action_observer.rb +13 -0
- data/app/views/admin/layout/index.rhtml +38 -0
- data/app/views/admin/layout/new.rhtml +37 -0
- data/app/views/admin/layout/remove.rhtml +17 -0
- data/app/views/admin/page/_node.rhtml +51 -0
- data/app/views/admin/page/_part.rhtml +17 -0
- data/app/views/admin/page/children.rhtml +4 -0
- data/app/views/admin/page/index.rhtml +172 -0
- data/app/views/admin/page/new.rhtml +164 -0
- data/app/views/admin/page/remove.rhtml +14 -0
- data/app/views/admin/snippet/index.rhtml +36 -0
- data/app/views/admin/snippet/new.rhtml +28 -0
- data/app/views/admin/snippet/remove.rhtml +16 -0
- data/app/views/admin/user/index.rhtml +43 -0
- data/app/views/admin/user/new.rhtml +48 -0
- data/app/views/admin/user/preferences.rhtml +29 -0
- data/app/views/admin/user/remove.rhtml +16 -0
- data/app/views/admin/welcome/login.rhtml +51 -0
- data/app/views/layouts/application.rhtml +75 -0
- data/app/views/site/not_found.rhtml +3 -0
- data/bin/radiant +305 -0
- data/config/boot.rb +80 -0
- data/config/database.mysql.yml +20 -0
- data/config/database.postgresql.yml +20 -0
- data/config/database.sqlite.yml +20 -0
- data/config/environment.rb +76 -0
- data/config/environments/development.rb +20 -0
- data/config/environments/production.rb +22 -0
- data/config/environments/test.rb +20 -0
- data/config/locomotive.yml +6 -0
- data/config/routes.rb +64 -0
- data/db/development_structure.sql +80 -0
- data/db/migrate/001_create_radiant_tables.rb +73 -0
- data/db/migrate/002_insert_initial_data.rb +45 -0
- data/db/migrate/003_rename_behavior_column.rb +9 -0
- data/db/migrate/004_rename_filter_column.rb +11 -0
- data/db/migrate/005_add_virtual_column_to_page.rb +9 -0
- data/db/migrate/006_integer_columns_to_boolean.rb +11 -0
- data/db/migrate/007_remove_virtual_column_from_page.rb +9 -0
- data/db/migrate/008_add_virtual_column_to_page_again.rb +9 -0
- data/db/migrate/009_add_content_type_field_to_layout.rb +9 -0
- data/db/schema.rb +74 -0
- data/db/templates/empty.yml +2 -0
- data/db/templates/simple-blog.yml +197 -0
- data/db/templates/styled-blog.yml +472 -0
- data/lib/advanced_delegation.rb +21 -0
- data/lib/archive_index_behavior_tags_and_methods.rb +48 -0
- data/lib/generators/behavior/USAGE +16 -0
- data/lib/generators/behavior/behavior_generator.rb +22 -0
- data/lib/generators/behavior/templates/model.rb.template +9 -0
- data/lib/generators/behavior/templates/unit_test.rb.template +16 -0
- data/lib/generators/filter/USAGE +16 -0
- data/lib/generators/filter/filter_generator.rb +22 -0
- data/lib/generators/filter/templates/model.rb.template +8 -0
- data/lib/generators/filter/templates/unit_test.rb.template +7 -0
- data/lib/inheritable_class_attributes.rb +65 -0
- data/lib/login_system.rb +80 -0
- data/lib/plugins/index_quoting_fix/init.rb +32 -0
- data/lib/plugins/string_io/init.rb +2 -0
- data/lib/radiant.rb +5 -0
- data/lib/registerable.rb +70 -0
- data/lib/tasks/release.rake +84 -0
- data/public/404.html +8 -0
- data/public/500.html +8 -0
- data/public/dispatch.cgi +10 -0
- data/public/dispatch.fcgi +24 -0
- data/public/dispatch.rb +10 -0
- data/public/favicon.ico +0 -0
- data/public/images/add-child.png +0 -0
- data/public/images/brown-bottom-line.gif +0 -0
- data/public/images/clear-page-cache.png +0 -0
- data/public/images/collapse.png +0 -0
- data/public/images/expand.png +0 -0
- data/public/images/minus.png +0 -0
- data/public/images/new-homepage.png +0 -0
- data/public/images/new-layout.png +0 -0
- data/public/images/new-snippet.png +0 -0
- data/public/images/new-user.png +0 -0
- data/public/images/page.png +0 -0
- data/public/images/plus.png +0 -0
- data/public/images/remove-disabled.png +0 -0
- data/public/images/remove.png +0 -0
- data/public/images/snippet.png +0 -0
- data/public/images/spinner.gif +0 -0
- data/public/images/view-site.gif +0 -0
- data/public/images/virtual-page.png +0 -0
- data/public/javascripts/application.js +2 -0
- data/public/javascripts/controls.js +815 -0
- data/public/javascripts/dragdrop.js +913 -0
- data/public/javascripts/effects.js +958 -0
- data/public/javascripts/pngfix.js +78 -0
- data/public/javascripts/prototype.js +2006 -0
- data/public/javascripts/ruledtable.js +28 -0
- data/public/javascripts/string.js +23 -0
- data/public/javascripts/tabcontrol.js +140 -0
- data/public/robots.txt +1 -0
- data/public/stylesheets/admin.css +464 -0
- data/script/about +3 -0
- data/script/breakpointer +3 -0
- data/script/console +3 -0
- data/script/destroy +3 -0
- data/script/generate +3 -0
- data/script/performance/benchmarker +3 -0
- data/script/performance/profiler +3 -0
- data/script/plugin +3 -0
- data/script/process/reaper +3 -0
- data/script/process/spawner +3 -0
- data/script/process/spinner +3 -0
- data/script/runner +3 -0
- data/script/server +3 -0
- data/script/setup_database +297 -0
- data/test/fixtures/layouts.yml +26 -0
- data/test/fixtures/page_parts.yml +99 -0
- data/test/fixtures/pages.yml +359 -0
- data/test/fixtures/pages.yml.rej +28 -0
- data/test/fixtures/snippets.yml +18 -0
- data/test/fixtures/users.yml +30 -0
- data/test/functional/admin/export_controller_test.rb +22 -0
- data/test/functional/admin/layout_controller_test.rb +40 -0
- data/test/functional/admin/model_controller_test.rb +152 -0
- data/test/functional/admin/page_controller_test.rb +179 -0
- data/test/functional/admin/snippet_controller_test.rb +11 -0
- data/test/functional/admin/user_controller_test.rb +71 -0
- data/test/functional/admin/welcome_controller_test.rb +48 -0
- data/test/functional/application_controller_test.rb +44 -0
- data/test/functional/login_system_test.rb +155 -0
- data/test/functional/site_controller_test.rb +172 -0
- data/test/helpers/archive_index_test_helper.rb +35 -0
- data/test/helpers/behavior_render_test_helper.rb +34 -0
- data/test/helpers/behavior_test_helper.rb +47 -0
- data/test/helpers/caching_test_helper.rb +41 -0
- data/test/helpers/layout_test_helper.rb +35 -0
- data/test/helpers/page_part_test_helper.rb +49 -0
- data/test/helpers/page_test_helper.rb +36 -0
- data/test/helpers/snippet_test_helper.rb +32 -0
- data/test/helpers/user_test_helper.rb +34 -0
- data/test/helpers/validation_test_helper.rb +42 -0
- data/test/test_helper.rb +54 -0
- data/test/unit/behavior_test.rb +196 -0
- data/test/unit/behaviors/archive_behavior_test.rb +33 -0
- data/test/unit/behaviors/archive_day_index_behavior_test.rb +21 -0
- data/test/unit/behaviors/archive_month_index_behavior_test.rb +21 -0
- data/test/unit/behaviors/archive_year_index_behavior_test.rb +21 -0
- data/test/unit/behaviors/page_missing_behavior_test.rb +27 -0
- data/test/unit/filters/markdown_filter_test.rb +14 -0
- data/test/unit/filters/textile_filter_test.rb +14 -0
- data/test/unit/inheritable_class_attributes_test.rb +47 -0
- data/test/unit/layout_test.rb +29 -0
- data/test/unit/page_context_test.rb +375 -0
- data/test/unit/page_context_test.rb.rej +26 -0
- data/test/unit/page_part_test.rb +44 -0
- data/test/unit/page_test.rb +224 -0
- data/test/unit/radiant/config_test.rb +46 -0
- data/test/unit/radiant/exporter_test.rb +26 -0
- data/test/unit/registerable_test.rb +68 -0
- data/test/unit/response_cache_test.rb +133 -0
- data/test/unit/snippet_test.rb +47 -0
- data/test/unit/status_test.rb +43 -0
- data/test/unit/text_filter_test.rb +14 -0
- data/test/unit/user_action_observer_test.rb +40 -0
- data/test/unit/user_test.rb +138 -0
- metadata +355 -0
@@ -0,0 +1,13 @@
|
|
1
|
+
class PagePart < ActiveRecord::Base
|
2
|
+
|
3
|
+
# Associations
|
4
|
+
belongs_to :page
|
5
|
+
|
6
|
+
# Validations
|
7
|
+
validates_presence_of :name, :message => 'required'
|
8
|
+
validates_length_of :name, :maximum => 100, :message => '%d-character limit'
|
9
|
+
validates_length_of :filter_id, :maximum => 25, :allow_nil => true, :message => '%d-character limit'
|
10
|
+
validates_numericality_of :id, :page_id, :allow_nil => true, :only_integer => true, :message => 'must be a number'
|
11
|
+
|
12
|
+
registered_attr :filter, TextFilter
|
13
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Radiant
|
2
|
+
#
|
3
|
+
# The Radiant::Config object emulates a hash with simple bracket methods
|
4
|
+
# which allow you to get and set values in the configuration table:
|
5
|
+
#
|
6
|
+
# Radiant::Config['setting.name'] = 'value'
|
7
|
+
# Radiant::Config['setting.name'] #=> "value"
|
8
|
+
#
|
9
|
+
# Currently, there is not a way to edit configuration through the admin
|
10
|
+
# system so it must be done manually. The console script is probably the
|
11
|
+
# easiest way to this:
|
12
|
+
#
|
13
|
+
# % script/console production
|
14
|
+
# Loading production environment.
|
15
|
+
# >> Radiant::Config['setting.name'] = 'value'
|
16
|
+
# => "value"
|
17
|
+
# >>
|
18
|
+
#
|
19
|
+
# Radiant currently uses the following settings:
|
20
|
+
#
|
21
|
+
# admin.title :: the title of the admin system
|
22
|
+
# admin.subtitle :: the subtitle of the admin system
|
23
|
+
# default.parts :: a comma separated list of default page parts
|
24
|
+
# dev.host :: the hostname where draft pages are viewable
|
25
|
+
#
|
26
|
+
class Config < ActiveRecord::Base
|
27
|
+
set_table_name "config"
|
28
|
+
|
29
|
+
class << self
|
30
|
+
def [](key)
|
31
|
+
pair = find_by_key(key)
|
32
|
+
pair.value unless pair.nil?
|
33
|
+
end
|
34
|
+
|
35
|
+
def []=(key, value)
|
36
|
+
pair = find_by_key(key)
|
37
|
+
unless pair
|
38
|
+
pair = new
|
39
|
+
pair.key, pair.value = key, value
|
40
|
+
pair.save
|
41
|
+
else
|
42
|
+
pair.value = value
|
43
|
+
pair.save
|
44
|
+
end
|
45
|
+
value
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_hash
|
49
|
+
Hash[ *find_all.map { |pair| [pair.key, pair.value] }.flatten ]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Radiant
|
2
|
+
class Exporter
|
3
|
+
def self.export
|
4
|
+
hash = {}
|
5
|
+
[Radiant::Config, User, Page, PagePart, Snippet, Layout].each do |klass|
|
6
|
+
hash[klass.name.pluralize] = klass.find(:all).inject({}) { |h, record| h[record.id.to_i] = record.attributes; h }
|
7
|
+
end
|
8
|
+
hash.to_yaml
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
class ResponseCache
|
2
|
+
include ActionController::Benchmarking::ClassMethods
|
3
|
+
include ActionController::Caching::Pages::ClassMethods
|
4
|
+
|
5
|
+
@@defaults = {
|
6
|
+
:directory => ActionController::Base.page_cache_directory,
|
7
|
+
:expire_time => 5.minutes,
|
8
|
+
:default_extension => '.yml',
|
9
|
+
:perform_caching => true,
|
10
|
+
:logger => ActionController::Base.logger
|
11
|
+
}
|
12
|
+
cattr_accessor :defaults
|
13
|
+
|
14
|
+
attr_accessor :directory, :expire_time, :default_extension, :perform_caching, :logger
|
15
|
+
alias :page_cache_directory :directory
|
16
|
+
alias :page_cache_extension :default_extension
|
17
|
+
private :expire_page, :cache_page, :caches_page, :benchmark, :silence, :page_cache_directory,
|
18
|
+
:page_cache_extension
|
19
|
+
|
20
|
+
# Creates a ResponseCache object with the specified options.
|
21
|
+
#
|
22
|
+
# Options are as follows:
|
23
|
+
# :directory :: the path to the temporary cache directory
|
24
|
+
# :expire_time :: the number of seconds a cached response is considered valid (defaults to 5 min)
|
25
|
+
# :default_extension :: the extension cached files should use (defaults to '.html')
|
26
|
+
# :peform_caching :: boolean value that turns caching on or off (defaults to true)
|
27
|
+
# :logger :: the application logging object (defaults to ActionController::Base.logger)
|
28
|
+
#
|
29
|
+
def initialize(options = {})
|
30
|
+
options = options.symbolize_keys.reverse_merge(defaults)
|
31
|
+
self.directory = options[:directory]
|
32
|
+
self.expire_time = options[:expire_time]
|
33
|
+
self.default_extension = options[:default_extension]
|
34
|
+
self.perform_caching = options[:perform_caching]
|
35
|
+
self.logger = options[:logger]
|
36
|
+
end
|
37
|
+
|
38
|
+
# Caches a response object for path to disk.
|
39
|
+
def cache_response(path, response)
|
40
|
+
path = clean(path)
|
41
|
+
write_response(path, response)
|
42
|
+
response
|
43
|
+
end
|
44
|
+
|
45
|
+
# If peform_caching is set to true, updates a response object so that it mirrors the
|
46
|
+
# cached version.
|
47
|
+
def update_response(path, response)
|
48
|
+
if perform_caching
|
49
|
+
path = clean(path)
|
50
|
+
read_response(path, response)
|
51
|
+
end
|
52
|
+
response
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns true if a response is cached at the specified path.
|
56
|
+
def response_cached?(path)
|
57
|
+
path = clean(path)
|
58
|
+
name = page_cache_path(path)
|
59
|
+
File.exists?(name) and not File.directory?(name) and not (File.stat(name).mtime < (Time.now - @expire_time))
|
60
|
+
end
|
61
|
+
|
62
|
+
# Expires the cached response for the specified path.
|
63
|
+
def expire_response(path)
|
64
|
+
path = clean(path)
|
65
|
+
expire_page(path)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Expires the entire cache.
|
69
|
+
def clear
|
70
|
+
Dir["#{directory}/*"].each do |f|
|
71
|
+
FileUtils.rm_rf f
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Returns the singleton instance for an application.
|
76
|
+
def self.instance
|
77
|
+
@@instance ||= new
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
# Ensures that path begins with a slash and remove extra slashes.
|
83
|
+
def clean(path)
|
84
|
+
path = path.gsub(%{/+}, '/')
|
85
|
+
%r{^/?(.*?)/?$}.match(path)
|
86
|
+
"/#{$1}"
|
87
|
+
end
|
88
|
+
|
89
|
+
# Reads a cached string from disk.
|
90
|
+
def read_page(path)
|
91
|
+
File.open(page_cache_path(path), "rb") { |f| f.read } if response_cached?(path)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Reads a cached response from disk and updates a response object.
|
95
|
+
def read_response(path, response)
|
96
|
+
if content = read_page(path)
|
97
|
+
updates = YAML::load(content)
|
98
|
+
response.headers.merge!(updates['headers'] || {})
|
99
|
+
response.body = updates['body']
|
100
|
+
end
|
101
|
+
response
|
102
|
+
end
|
103
|
+
|
104
|
+
# Writes a response to disk.
|
105
|
+
def write_response(path, response)
|
106
|
+
content = {
|
107
|
+
'headers' => response.headers,
|
108
|
+
'body' => response.body
|
109
|
+
}.to_yaml
|
110
|
+
cache_page(content, path)
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Snippet < ActiveRecord::Base
|
2
|
+
|
3
|
+
# Associations
|
4
|
+
belongs_to :created_by, :class_name => 'User', :foreign_key => 'created_by'
|
5
|
+
belongs_to :updated_by, :class_name => 'User', :foreign_key => 'updated_by'
|
6
|
+
|
7
|
+
# Validations
|
8
|
+
validates_presence_of :name, :message => 'required'
|
9
|
+
validates_length_of :name, :maximum => 100, :message => '%d-character limit'
|
10
|
+
validates_length_of :filter_id, :maximum => 25, :allow_nil => true, :message => '%d-character limit'
|
11
|
+
validates_format_of :name, :with => %r{^\S*$}, :message => 'cannot contain spaces or tabs'
|
12
|
+
validates_uniqueness_of :name, :message => 'name already in use'
|
13
|
+
|
14
|
+
registered_attr :filter, TextFilter
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Status
|
2
|
+
attr_accessor :id, :name
|
3
|
+
|
4
|
+
def initialize(options = {})
|
5
|
+
options = options.symbolize_keys
|
6
|
+
@id, @name = options[:id], options[:name]
|
7
|
+
end
|
8
|
+
|
9
|
+
def symbol
|
10
|
+
@name.to_s.downcase.intern
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.[](value)
|
14
|
+
@@statuses.select { |status| status.symbol == value.to_s.downcase.intern }.first
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.find(id)
|
18
|
+
@@statuses.select { |status| status.id.to_s == id.to_s }.first
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.find_all
|
22
|
+
@@statuses.dup
|
23
|
+
end
|
24
|
+
|
25
|
+
@@statuses = [
|
26
|
+
Status.new(:id => 1, :name => 'Draft' ),
|
27
|
+
Status.new(:id => 50, :name => 'Reviewed' ),
|
28
|
+
Status.new(:id => 100, :name => 'Published'),
|
29
|
+
Status.new(:id => 101, :name => 'Hidden' )
|
30
|
+
]
|
31
|
+
end
|
data/app/models/user.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
|
3
|
+
class User < ActiveRecord::Base
|
4
|
+
|
5
|
+
# Associations
|
6
|
+
belongs_to :created_by, :class_name => 'User', :foreign_key => 'created_by'
|
7
|
+
belongs_to :updated_by, :class_name => 'User', :foreign_key => 'updated_by'
|
8
|
+
|
9
|
+
# Validations
|
10
|
+
validates_uniqueness_of :login, :message => 'login already in use'
|
11
|
+
|
12
|
+
validates_confirmation_of :password, :message => 'must match confirmation', :if => :confirm_password?
|
13
|
+
|
14
|
+
validates_presence_of :name, :login, :message => 'required'
|
15
|
+
validates_presence_of :password, :password_confirmation, :message => 'required', :if => :new_record?
|
16
|
+
|
17
|
+
validates_format_of :email, :message => 'invalid e-mail address', :allow_nil => true, :with => /^$|^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
|
18
|
+
|
19
|
+
validates_length_of :name, :maximum => 100, :allow_nil => true, :message => '%d-character limit'
|
20
|
+
validates_length_of :login, :within => 3..40, :allow_nil => true, :too_long => '%d-character limit', :too_short => '%d-character minimum'
|
21
|
+
validates_length_of :password, :within => 5..40, :allow_nil => true, :too_long => '%d-character limit', :too_short => '%d-character minimum', :if => :validate_length_of_password?
|
22
|
+
validates_length_of :email, :maximum => 255, :allow_nil => true, :message => '%d-character limit'
|
23
|
+
|
24
|
+
validates_numericality_of :id, :only_integer => true, :allow_nil => true, :message => 'must be a number'
|
25
|
+
|
26
|
+
cattr_accessor :salt
|
27
|
+
@@salt = 'sweet harmonious biscuits' # historic value
|
28
|
+
|
29
|
+
attr_writer :confirm_password
|
30
|
+
|
31
|
+
def self.sha1(phrase)
|
32
|
+
Digest::SHA1.hexdigest("--#{@@salt}--#{phrase}--")
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.authenticate(login, password)
|
36
|
+
find_by_login_and_password(login, sha1(password))
|
37
|
+
end
|
38
|
+
|
39
|
+
def after_initialize
|
40
|
+
@confirm_password = true
|
41
|
+
end
|
42
|
+
|
43
|
+
def confirm_password?
|
44
|
+
@confirm_password
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def validate_length_of_password?
|
50
|
+
new_record? or not password.to_s.empty?
|
51
|
+
end
|
52
|
+
|
53
|
+
before_create :encrypt_password
|
54
|
+
def encrypt_password
|
55
|
+
self.password = self.class.sha1(password)
|
56
|
+
end
|
57
|
+
|
58
|
+
before_update :encrypt_password_unless_empty_or_unchanged
|
59
|
+
def encrypt_password_unless_empty_or_unchanged
|
60
|
+
user = self.class.find(self.id)
|
61
|
+
case password
|
62
|
+
when ''
|
63
|
+
self.password = user.password
|
64
|
+
when user.password
|
65
|
+
else
|
66
|
+
encrypt_password
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class UserActionObserver < ActiveRecord::Observer
|
2
|
+
observe User, Page, Layout, Snippet
|
3
|
+
|
4
|
+
cattr_accessor :current_user
|
5
|
+
|
6
|
+
def before_create(model)
|
7
|
+
model.created_by = @@current_user
|
8
|
+
end
|
9
|
+
|
10
|
+
def before_update(model)
|
11
|
+
model.updated_by = @@current_user
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
<h1>Layouts</h1>
|
2
|
+
|
3
|
+
<p>Use layouts to apply a visual look to a Web page. Layouts can contain special tags to include
|
4
|
+
page content and other elements such as the header or footer. Click on a layout name below to
|
5
|
+
edit it or click <code>Remove</code> to delete it.</p>
|
6
|
+
|
7
|
+
<table id="layouts" class="index" cellpadding="0" cellspacing="0" border="0">
|
8
|
+
<thead>
|
9
|
+
<tr>
|
10
|
+
<th class="layout">Layout</th>
|
11
|
+
<th class="modify">Modify</th>
|
12
|
+
</tr>
|
13
|
+
</thead>
|
14
|
+
<tbody>
|
15
|
+
<% unless @layouts.empty? -%>
|
16
|
+
<% for layout in @layouts -%>
|
17
|
+
<tr class="node level-1">
|
18
|
+
<td class="layout">
|
19
|
+
<%= image_tag 'page', :alt => 'layout-icon', :title => '', :align => 'center' %>
|
20
|
+
<%= link_to layout.name, layout_edit_url(:id => layout) %>
|
21
|
+
</td>
|
22
|
+
<td class="remove"><%= link_to image_tag('remove', :alt => 'Remove Layout'), layout_remove_url(:id => layout) %></td>
|
23
|
+
</tr>
|
24
|
+
<% end -%>
|
25
|
+
<% else -%>
|
26
|
+
<tr>
|
27
|
+
<td colspan="2" class="note">No Layouts</td>
|
28
|
+
</tr>
|
29
|
+
<% end -%>
|
30
|
+
</tbody>
|
31
|
+
</table>
|
32
|
+
<script type="text/javascript">
|
33
|
+
// <![CDATA[
|
34
|
+
new RuledTable('layouts');
|
35
|
+
// ]]>
|
36
|
+
</script>
|
37
|
+
|
38
|
+
<p><%= link_to image_tag('new-layout', :alt => 'New Layout'), layout_new_url %></p>
|
@@ -0,0 +1,37 @@
|
|
1
|
+
<% if @layout.new_record? -%>
|
2
|
+
<h1>New Layout</h1>
|
3
|
+
<% else -%>
|
4
|
+
<h1>Edit Layout</h1>
|
5
|
+
<% end -%>
|
6
|
+
|
7
|
+
<form method="post">
|
8
|
+
<div class="form-area">
|
9
|
+
<p class="title">
|
10
|
+
<label for="layout_name">Name</label>
|
11
|
+
<%= text_field "layout", "name", :class => 'textbox', :maxlength => 100 %>
|
12
|
+
</p>
|
13
|
+
<div id="extended-metadata" class="row"<%= meta_visible(:meta) %>>
|
14
|
+
<table class="fieldset" cellpadding="0" cellspacing="0" border="0">
|
15
|
+
<tr>
|
16
|
+
<td><label for="layout_content_type">Content-Type</label></td>
|
17
|
+
<td class="field"><%= text_field "layout", "content_type", :class => 'textbox', :maxlength => 40 %></td>
|
18
|
+
</tr>
|
19
|
+
</table>
|
20
|
+
</div>
|
21
|
+
<p>
|
22
|
+
<small>
|
23
|
+
<a id="more-extended-metadata" href="<%= toggle_javascript_for('extended-metadata') %>"<%= meta_visible(:meta_more) %>>More</a>
|
24
|
+
<a id="less-extended-metadata" href="<%= toggle_javascript_for('extended-metadata') %>"<%= meta_visible(:meta_less) %>>Less</a>
|
25
|
+
</small>
|
26
|
+
</p>
|
27
|
+
<p class="content">
|
28
|
+
<label for="layout_content">Body</label>
|
29
|
+
<%= text_area "layout", "content", :class => "textarea", :style => "width: 100%" %></p>
|
30
|
+
<%= updated_stamp @layout %>
|
31
|
+
</div>
|
32
|
+
<p class="buttons">
|
33
|
+
<%= save_model_button(@layout) %> <%= save_model_and_continue_editing_button(@layout) %> or <%= link_to "Cancel", layout_index_url %>
|
34
|
+
</p>
|
35
|
+
</form>
|
36
|
+
|
37
|
+
<%= focus 'layout_name' %>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<h1>Remove Layout</h1>
|
2
|
+
<p>Are you sure you want to <strong class="warning">permanently remove</strong> the following layout?</p>
|
3
|
+
|
4
|
+
<table id="site-map" class="index" cellpadding="0" cellspacing="0" border="0">
|
5
|
+
<tbody>
|
6
|
+
<tr class="node level-1" onmouseover="Element.addClassName(this, 'highlight');" onmouseout="Element.removeClassName(this, 'highlight');">
|
7
|
+
<td class="layout">
|
8
|
+
<%= image_tag 'page', :alt => 'layout-icon', :title => '', :align => 'center' %>
|
9
|
+
<%= @layout.name %>
|
10
|
+
</td>
|
11
|
+
</tr>
|
12
|
+
</tbody>
|
13
|
+
</table>
|
14
|
+
|
15
|
+
<form method="post">
|
16
|
+
<p class="buttons"><%= submit_tag "Delete Layout", :class => 'button' %> or <%= link_to 'Cancel', layout_index_url %></p>
|
17
|
+
</form>
|
@@ -0,0 +1,51 @@
|
|
1
|
+
<%
|
2
|
+
count = page.children.count
|
3
|
+
children = count > 0
|
4
|
+
expand = expand - 1
|
5
|
+
expanded = expand > 0
|
6
|
+
padding_left = (level * 22) + 4
|
7
|
+
|
8
|
+
children_class = children ? (expanded ? ' children-visible' : ' children-hidden') : ' no-children'
|
9
|
+
virtual_class = page.virtual? ? " virtual": ""
|
10
|
+
|
11
|
+
expander = children ? image_tag((expanded ? "collapse" : "expand"), :class => "expander", :alt => 'toggle children', :title => '', :align => 'center') : ""
|
12
|
+
|
13
|
+
icon_name = page.virtual? ? "virtual-page" : "page"
|
14
|
+
icon = image_tag(icon_name, :class => "icon", :alt => 'page-icon', :title => '', :align => 'center')
|
15
|
+
|
16
|
+
title = %{<span class="title">#{ page.title }</span>}
|
17
|
+
|
18
|
+
behavior_id = page.behavior_id.to_s.strip
|
19
|
+
behavior = behavior_id.empty? ? '' : %{<small class="info">(#{ behavior_id })</small>}
|
20
|
+
|
21
|
+
spinner = image_tag("spinner.gif", :class => 'busy', :id => "busy-#{page.id}", :alt => "", :title => "", :align => "center", :style => 'display: none;')
|
22
|
+
-%>
|
23
|
+
<tr id="page-<%= page.id %>" class="node level-<%= level %><%= children_class %><%= virtual_class %>">
|
24
|
+
<td class="page" style="padding-left: <%= padding_left %>px">
|
25
|
+
<span class="w1">
|
26
|
+
<% if simple -%>
|
27
|
+
<%= icon %>
|
28
|
+
<%= title %>
|
29
|
+
<% else -%>
|
30
|
+
<%= expander %><a href="<%= page_edit_url(:id => page) %>"><%= icon %> <%= title %></a>
|
31
|
+
<%= behavior %>
|
32
|
+
<%= spinner %>
|
33
|
+
<% end -%>
|
34
|
+
</span>
|
35
|
+
</td>
|
36
|
+
<% unless simple -%>
|
37
|
+
<td class="status <%= page.status.name.downcase %>-status"><%= page.status.name %></td>
|
38
|
+
<td class="add-child"><%= link_to image_tag('add-child', :alt => 'add child'), page_new_url(:parent_id => page) %></td>
|
39
|
+
<td class="remove"><%= link_to image_tag('remove', :alt => 'remove page'), page_remove_url(:id => page) %></td>
|
40
|
+
<% end -%>
|
41
|
+
</tr>
|
42
|
+
<% level = level + 1 -%>
|
43
|
+
<%
|
44
|
+
if expanded
|
45
|
+
page.children.each do |child|
|
46
|
+
-%>
|
47
|
+
<%= render_node child, :level => level, :expand => expand, :simple => simple -%>
|
48
|
+
<%
|
49
|
+
end
|
50
|
+
end
|
51
|
+
-%>
|