zen 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/CHANGELOG.md +12 -2
  2. data/MANIFEST +17 -10
  3. data/ROADMAP.md +8 -4
  4. data/bin/zen +2 -3
  5. data/lib/zen.rb +20 -14
  6. data/lib/zen/bin/{zen_binary.rb → base.rb} +0 -0
  7. data/lib/zen/controller/main_controller.rb +7 -4
  8. data/lib/zen/{base/database.rb → database.rb} +3 -2
  9. data/lib/zen/error/language_error.rb +10 -0
  10. data/lib/zen/error/package_error.rb +10 -0
  11. data/lib/zen/error/plugin_error.rb +10 -0
  12. data/lib/zen/error/theme_error.rb +10 -0
  13. data/lib/zen/helper/acl.rb +11 -4
  14. data/lib/zen/{base/language.rb → language.rb} +11 -3
  15. data/lib/zen/layout/admin.xhtml +21 -12
  16. data/lib/zen/layout/login.xhtml +17 -11
  17. data/lib/zen/liquid/general.rb +1 -27
  18. data/lib/zen/{base/logger.rb → logger.rb} +0 -0
  19. data/lib/zen/{base/package.rb → package.rb} +65 -55
  20. data/lib/zen/package/all.rb +5 -0
  21. data/lib/zen/package/categories/lib/categories.rb +7 -8
  22. data/lib/zen/package/comments/lib/comments.rb +7 -8
  23. data/lib/zen/package/comments/lib/comments/controller/comments_form.rb +1 -1
  24. data/lib/zen/package/comments/lib/comments/liquid/comments.rb +3 -1
  25. data/lib/zen/package/custom_fields/lib/custom_fields.rb +7 -8
  26. data/lib/zen/package/custom_fields/lib/custom_fields/model/custom_field_value.rb +14 -0
  27. data/lib/zen/package/custom_fields/migrations/1295255665_create_schema.rb +1 -1
  28. data/lib/zen/package/menus/lib/menus.rb +5 -6
  29. data/lib/zen/package/sections/lib/sections.rb +4 -5
  30. data/lib/zen/package/sections/lib/sections/language/en/section_entries.yml +2 -2
  31. data/lib/zen/package/sections/lib/sections/liquid/section_entries.rb +9 -2
  32. data/lib/zen/package/settings/lib/settings.rb +7 -8
  33. data/lib/zen/package/users/lib/users.rb +7 -8
  34. data/lib/zen/package/users/lib/users/view/admin/access-rules/form.xhtml +5 -5
  35. data/lib/zen/package/users/lib/users/view/admin/access-rules/index.xhtml +4 -4
  36. data/lib/zen/plugin.rb +172 -0
  37. data/lib/zen/plugin/markup.rb +30 -0
  38. data/lib/zen/public/admin/css/layout.css +17 -0
  39. data/lib/zen/strict_struct.rb +36 -0
  40. data/lib/zen/task/db.rb +14 -4
  41. data/lib/zen/task/package.rb +13 -8
  42. data/lib/zen/task/theme.rb +88 -0
  43. data/lib/zen/theme.rb +129 -0
  44. data/lib/zen/{base/version.rb → version.rb} +1 -1
  45. data/proto/app/config/config.rb +19 -6
  46. data/proto/app/config/database.rb +58 -2
  47. data/proto/app/config/middlewares.rb +69 -4
  48. data/proto/app/config/requires.rb +9 -2
  49. data/proto/app/{logs → log}/.gitkeep +0 -0
  50. data/proto/package/lib/package.rb +3 -13
  51. data/proto/package/lib/package/controller/controllers.rb +5 -9
  52. data/proto/package/lib/package/language/en/languages.yml +4 -0
  53. metadata +66 -26
  54. data/proto/package/LICENSE +0 -0
  55. data/proto/package/README.textile +0 -0
  56. data/proto/package/lib/package/language/en/languages.rb +0 -3
@@ -48,7 +48,7 @@ module Zen
48
48
  # following:
49
49
  #
50
50
  # context = {'username' => 'YorickPeterse'}
51
- # hash = {'selected_user' => 'username'}
51
+ # hash = {'selected_user' => 'username'}
52
52
  #
53
53
  # merge_context(hash, context) # => {'selected_user' => 'YorickPeterse'}
54
54
  #
@@ -89,32 +89,6 @@ module Zen
89
89
  return hash
90
90
  end
91
91
 
92
- ##
93
- # Converts the given input data to HTML using the specified markup engine.
94
- #
95
- # @example
96
- # markup_to_html("h2. Hello world!", :textile)
97
- #
98
- # @author Yorick Peterse
99
- # @since 0.1
100
- # @param [String] markup The raw markup that has to be converted to HTML.
101
- # @param [Symbol] engine The markup engine to use such as Textile.
102
- # @return [String] The HTML generated by the markup engine.
103
- #
104
- def markup_to_html(markup, engine)
105
- engine = engine.to_sym
106
-
107
- case engine
108
- when :textile
109
- markup = RedCloth.new(markup).to_html
110
- when :markdown
111
- markup = RDiscount.new(markup).to_html
112
- when :plain
113
- markup = h(markup)
114
- end
115
-
116
- return markup
117
- end
118
92
  end
119
93
  end
120
94
  end
File without changes
@@ -1,4 +1,7 @@
1
1
  require 'ramaze/gestalt'
2
+ require __DIR__('helper/acl')
3
+ require __DIR__('liquid/controller_behavior')
4
+ require __DIR__('error/package_error')
2
5
 
3
6
  #:nodoc:
4
7
  module Zen
@@ -8,7 +11,8 @@ module Zen
8
11
  # actually be installed using either Rubygems or by storing them in a custom directory.
9
12
  # As long as you require the correct file you're good to go.
10
13
  #
11
- # Packages are added or "described" using a simple block and the add() method as following:
14
+ # Packages are added or "described" using a simple block and the add() method as
15
+ # following:
12
16
  #
13
17
  # Zen::Package.add do |ext|
14
18
  # # ....
@@ -16,10 +20,8 @@ module Zen
16
20
  #
17
21
  # When using this block you're required to set the following attributes:
18
22
  #
19
- # * type: the type of package, can either be "theme" or "extension"
20
23
  # * name: the name of the package
21
24
  # * author: the name of the person who made the package
22
- # * version: the current version, either a string or a numeric value
23
25
  # * about: a small description of the package
24
26
  # * url: the URL to the package's website
25
27
  # * identifier: unique identifier for the package. The format is com.AUTHOR.NAME for
@@ -61,33 +63,29 @@ module Zen
61
63
  # directory of your extension. For example, if your extension is in "foobar" the migrations
62
64
  # should be located in "foobar/migrations", the lib directory in "foobar/lib", etc.
63
65
  #
64
- # Migrations can be executed using the Rake task "extension:migrate" or "db:migrate",
65
- # the latter will install all extensions while the first one will only install the
66
- # specified extension. Migration prototypes can be generated by the Rake task
67
- # "proto:migration[DIRECTORY]" where DIRECTORY is the path to your migrations directory.
66
+ # Migrations can be executed using the Thor task "package:migrate" or "db:migrate",
67
+ # the latter will install all packages while the first one will only install the
68
+ # specified packages. For more information on these tasks execute the following command:
68
69
  #
69
- # ## Themes
70
+ # $ thor -T
70
71
  #
71
- # Themes are essentially packages like the sections or comments module except that they
72
- # have a few limitations and work a bit different. First of all themes can't add
73
- # navigation items to the backend and second they should _always_ have the following
74
- # directories:
72
+ # ## Identifiers
75
73
  #
76
- # * theme/lib/theme/templates
77
- # * theme/lib/theme/public
74
+ # Package identifiers should always have the following format:
78
75
  #
79
- # The templates directory is used to store all Liquid templates and template groups,
80
- # the public directory is used for CSS files, images and so on. Themes can have
81
- # migrations just like extensions which makes it relatively easy to share a theme
82
- # with somebody else.
76
+ # com.VENDOR.NAME
77
+ #
78
+ # For example:
79
+ #
80
+ # com.zen.sections
83
81
  #
84
82
  # @author Yorick Peterse
85
83
  # @since 0.1
84
+ # @attr_reader [Array] packages Array containing the instances of all packages.
86
85
  #
87
86
  module Package
88
87
  class << self
89
- attr_reader :extensions
90
- attr_reader :themes
88
+ attr_reader :packages
91
89
  end
92
90
 
93
91
  ##
@@ -102,7 +100,6 @@ module Zen
102
100
  #
103
101
  # When adding a new extension the following setters are required:
104
102
  #
105
- # * type
106
103
  # * name
107
104
  # * author
108
105
  # * version
@@ -111,21 +108,24 @@ module Zen
111
108
  # * identifier
112
109
  # * directory
113
110
  #
111
+ # You can also set "migration_dir" to a directory with all migrations. By default
112
+ # Zen will assume that it's 2 levels above your root directory.
113
+ #
114
114
  # @author Yorick Peterse
115
115
  # @since 0.1
116
- # @param [Block] block Block containing information about the extension.
116
+ # @yield [package] Object containing all setters and getters for each package.
117
117
  #
118
- def self.add(&block)
119
- package = Struct.new(:type, :name, :author, :version, :about, :url,
120
- :identifier, :directory, :menu).new
121
- required = [:type, :name, :author, :version, :about, :url, :identifier, :directory]
118
+ def self.add
119
+ package = Zen::StrictStruct.new(
120
+ :name, :author, :about, :url, :identifier, :directory, :menu, :migration_dir
121
+ ).new
122
+
123
+ required = [:name, :author, :about, :identifier, :directory]
122
124
 
123
125
  yield package
124
126
 
125
- required.each do |m|
126
- if !package.respond_to?(m) or package.send(m).nil?
127
- raise "A loaded package has no value set for the setter \"#{m}\""
128
- end
127
+ package.validate(required) do |k|
128
+ raise(Zen::PackageError, "The following package key is missing: #{k}")
129
129
  end
130
130
 
131
131
  # Update the root but prevent duplicates
@@ -137,18 +137,18 @@ module Zen
137
137
  if !Zen::Language.options.paths.include?(package.directory)
138
138
  Zen::Language.options.paths.push(package.directory)
139
139
  end
140
-
141
- # Themes and extensions each have a different accessor
142
- if package.type.to_s == 'theme'
143
- # Remove the navigation menu
144
- package.menu = nil if !package.menu.nil?
145
-
146
- @themes = {} if @themes.nil?
147
- @themes[package.identifier.to_s] = package
148
- else
149
- @extensions = {} if @extensions.nil?
150
- @extensions[package.identifier.to_s] = package
140
+
141
+ # Validate the directories
142
+ [:directory, :migration_dir].each do |k|
143
+ if package.respond_to?(k) and !package.send(k).nil?
144
+ if !File.exist?(package.send(k))
145
+ raise(PackageError, "The directory #{package.send(k)} does not exist.")
146
+ end
147
+ end
151
148
  end
149
+
150
+ @packages = {} if @packages.nil?
151
+ @packages[package.identifier.to_s] = package
152
152
  end
153
153
 
154
154
  ##
@@ -160,11 +160,7 @@ module Zen
160
160
  # @return [Object]
161
161
  #
162
162
  def self.[](ident)
163
- if ident.include?('.themes.')
164
- @themes[ident]
165
- else
166
- @extensions[ident]
167
- end
163
+ @packages[ident.to_s]
168
164
  end
169
165
 
170
166
  ##
@@ -174,18 +170,32 @@ module Zen
174
170
  # of which each list item can contain N sub items.
175
171
  #
176
172
  # @author Yorick Peterse
177
- # @param [String] css_class A string of CSS classes to apply to the
178
- # main UL element.
173
+ # @param [String] css_class A string of CSS classes to apply to the main UL element.
174
+ # @param [Hash] permissions Hash containing the permissions as returned by
175
+ # Ramaze::Helper::ACL#extension_permissions
176
+ # @param [Boolean] all When set to true all elements will be displayed opposed to
177
+ # only those the user is allowed to see.
179
178
  # @since 0.1
180
179
  #
181
- def self.build_menu(css_class = '')
182
- @g = Ramaze::Gestalt.new
183
- menu_items = []
180
+ def self.build_menu(css_class = '', permissions = {}, all = false)
181
+ @g = Ramaze::Gestalt.new
182
+ menu_items = []
183
+ identifiers = []
184
+
185
+ # Build a list of all allowed extensions
186
+ permissions.each do |ident, rules|
187
+ if rules.include?(:read)
188
+ identifiers.push(ident)
189
+ end
190
+ end
184
191
 
185
- @extensions.each do |ident, ext|
192
+ @packages.each do |ident, ext|
193
+ # Got a menu for us?
186
194
  if !ext.menu.nil?
187
- ext.menu.each do |m|
188
- menu_items.push(m)
195
+ if identifiers.include?(ext.identifier) or all == true
196
+ ext.menu.each do |m|
197
+ menu_items.push(m)
198
+ end
189
199
  end
190
200
  end
191
201
  end
@@ -235,6 +245,6 @@ module Zen
235
245
  end
236
246
  end
237
247
  end
238
-
248
+
239
249
  end
240
250
  end
@@ -1,3 +1,8 @@
1
+ ##
2
+ # Loads all core packages that ship with Zen. Note that it's important to load these
3
+ # packages in the correct order as otherwise migrations that create foreign keys might
4
+ # not work.
5
+ #
1
6
  require __DIR__('users/lib/users')
2
7
  require __DIR__('sections/lib/sections')
3
8
  require __DIR__('settings/lib/settings')
@@ -8,14 +8,13 @@ require __DIR__ 'categories/controller/categories'
8
8
 
9
9
  # Describe what this package is all about
10
10
  Zen::Package.add do |p|
11
- p.type = 'extension'
12
- p.name = 'Categories'
13
- p.author = 'Yorick Peterse'
14
- p.url = 'http://yorickpeterse.com/'
15
- p.version = '1.0'
16
- p.about = "Module for managing categories. Categories can be used to organize section entries."
17
- p.identifier = 'com.zen.categories'
18
- p.directory = __DIR__('categories')
11
+ p.name = 'Categories'
12
+ p.author = 'Yorick Peterse'
13
+ p.url = 'http://yorickpeterse.com/'
14
+ p.about = "Module for managing categories. Categories can be used to organize section entries."
15
+ p.identifier = 'com.zen.categories'
16
+ p.directory = __DIR__('categories')
17
+ p.migration_dir = __DIR__('../migrations')
19
18
 
20
19
  p.menu = [{
21
20
  :title => "Categories",
@@ -10,14 +10,13 @@ Liquid::Template.register_tag('comments' , Comments::Liquid::Comments)
10
10
  Liquid::Template.register_tag('comment_form', Comments::Liquid::CommentForm)
11
11
 
12
12
  Zen::Package.add do |p|
13
- p.type = 'extension'
14
- p.name = 'Comments'
15
- p.author = 'Yorick Peterse'
16
- p.url = 'http://yorickpeterse.com/'
17
- p.version = '1.0'
18
- p.about = "Allow users to post comments on any given section entry (as long as the section allows it)."
19
- p.identifier = 'com.zen.comments'
20
- p.directory = __DIR__('comments')
13
+ p.name = 'Comments'
14
+ p.author = 'Yorick Peterse'
15
+ p.url = 'http://yorickpeterse.com/'
16
+ p.about = "Allow users to post comments on any given section entry (as long as the section allows it)."
17
+ p.identifier = 'com.zen.comments'
18
+ p.directory = __DIR__('comments')
19
+ p.migration_dir = __DIR__('../migrations')
21
20
 
22
21
  p.menu = [{
23
22
  :title => "Comments",
@@ -127,7 +127,7 @@ module Comments
127
127
  flash[:success] = lang('comments.success.new')
128
128
  end
129
129
  rescue
130
- flash[:error] = lang('comments.errors.new')
130
+ flash[:error] = lang('comments.errors.new')
131
131
  end
132
132
 
133
133
  redirect_referrer
@@ -94,7 +94,9 @@ module Comments
94
94
  comment.values.each { |k, v| context[k.to_s] = v }
95
95
 
96
96
  # Convert the comment body into HTML
97
- context['comment'] = markup_to_html(context['comment'], format)
97
+ context['comment'] = Zen::Plugin.call(
98
+ 'com.zen.plugin.markup', format.to_sym, context['comment']
99
+ )
98
100
 
99
101
  ['email', 'name', 'website'].each do |c|
100
102
  if context[c].nil? or context[c].empty?
@@ -8,14 +8,13 @@ require __DIR__ 'custom_fields/controller/custom_field_groups'
8
8
  require __DIR__ 'custom_fields/controller/custom_fields'
9
9
 
10
10
  Zen::Package.add do |p|
11
- p.type = 'extension'
12
- p.name = 'Custom Fields'
13
- p.author = 'Yorick Peterse'
14
- p.url = 'http://yorickpeterse.com/'
15
- p.version = 1.0
16
- p.about = "The Custom Fields module is used to manage, how original, custom fields and custom field groups."
17
- p.identifier = 'com.zen.custom_fields'
18
- p.directory = __DIR__('custom_fields')
11
+ p.name = 'Custom Fields'
12
+ p.author = 'Yorick Peterse'
13
+ p.url = 'http://yorickpeterse.com/'
14
+ p.about = "The Custom Fields module is used to manage, how original, custom fields and custom field groups."
15
+ p.identifier = 'com.zen.custom_fields'
16
+ p.directory = __DIR__('custom_fields')
17
+ p.migration_dir = __DIR__('../migrations')
19
18
 
20
19
  p.menu = [{
21
20
  :title => "Custom Fields",
@@ -17,6 +17,20 @@ module CustomFields
17
17
  class CustomFieldValue < Sequel::Model
18
18
  many_to_one(:custom_field , :class => "CustomFields::Models::CustomField")
19
19
  many_to_one(:section_entry, :class => "Sections::Models::SectionEntry")
20
+
21
+ ##
22
+ # Hook that is executed before saving a field's value. This hook is used to clean
23
+ # up all values making it easier to process them at a later stage.
24
+ #
25
+ # @author Yorick Peterse
26
+ # @since 0.2.4
27
+ #
28
+ def before_save
29
+ # T-t-t-t-that's all folks!
30
+ if !self.value.nil?
31
+ self.value.gsub!(/\r\n/, "\n")
32
+ end
33
+ end
20
34
  end
21
35
  end
22
36
  end
@@ -23,7 +23,7 @@ Sequel.migration do
23
23
  TrueClass :required, :null => false, :default => false
24
24
  TrueClass :visual_editor, :null => false, :default => true
25
25
  Integer :textarea_rows, :default => 10
26
- Integer :text_limit, :default => 1
26
+ Integer :text_limit
27
27
 
28
28
  foreign_key :custom_field_group_id, :custom_field_groups, :on_delete => :cascade,
29
29
  :on_update => :cascade, :key => :id
@@ -17,9 +17,6 @@ Liquid::Template.register_tag('menus', Menus::Liquid::Menus)
17
17
 
18
18
  # Describe the package
19
19
  Zen::Package.add do |p|
20
- # The type of extension. Can either be "theme" or "extension".
21
- p.type = 'extension'
22
-
23
20
  # The name of the package
24
21
  p.name = 'Menus'
25
22
 
@@ -29,9 +26,6 @@ Zen::Package.add do |p|
29
26
  # A URL to a page about the package
30
27
  p.url = 'http://zen-cms.com/userguide/menus'
31
28
 
32
- # The version number of the package
33
- p.version = '1.0'
34
-
35
29
  # Describe what your theme or extension does.
36
30
  p.about = 'The Menus extension allows you to easily create navigation menus
37
31
  for the frontend.'
@@ -50,6 +44,11 @@ for the frontend.'
50
44
  # Path to the directory containing the controllers, models, etc.
51
45
  #
52
46
  p.directory = __DIR__('menus')
47
+
48
+ ##
49
+ # Path to the directory containing all migrations for this package.
50
+ #
51
+ p.migration_dir = __DIR__('../migrations')
53
52
 
54
53
  # Note that themes can not have menu items (they'll be ignored).
55
54
  p.menu = [{
@@ -14,20 +14,19 @@ Liquid::Template.register_tag('section_entries', Sections::Liquid::SectionEntrie
14
14
 
15
15
  # Describe what this extension is all about
16
16
  Zen::Package.add do |p|
17
- p.type = 'extension'
18
17
  p.name = 'Sections'
19
18
  p.author = 'Yorick Peterse'
20
19
  p.url = 'http://yorickpeterse.com/'
21
- p.version = 1.0
22
20
  p.about = "The sections module allows users to create and manage sections.
23
21
  Sections can be seen as small web applications that live inside the CMS.
24
22
  For example, you could have a section for your blog and for your pages."
25
23
 
26
- p.identifier = 'com.zen.sections'
27
- p.directory = __DIR__('sections')
24
+ p.identifier = 'com.zen.sections'
25
+ p.directory = __DIR__('sections')
26
+ p.migration_dir = __DIR__('../migrations')
28
27
 
29
28
  p.menu = [{
30
29
  :title => "Sections",
31
30
  :url => "admin"
32
31
  }]
33
- end
32
+ end
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  titles:
3
3
  index : 'Entries'
4
- edit : 'EditEntry'
5
- new : 'AddEntry'
4
+ edit : 'Edit Entry'
5
+ new : 'Add Entry'
6
6
 
7
7
  labels:
8
8
  id : '#'