orange 0.0.4 → 0.0.5

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.
@@ -99,12 +99,14 @@ Make sure github gems can be downloaded:
99
99
 
100
100
  * dm-core (+ do_[sqlite3|mysql|...] )
101
101
  * dm-more
102
+ * dm-is-awesome_set
102
103
  * rack
103
104
  * haml
104
105
  * mynyml-rack-abstract-format (github)
105
106
  * ruby-openid
106
107
  * rack-openid
107
108
  * meekish-openid_dm_store
109
+ * radius
108
110
 
109
111
  Also, you'll need a web server of some kind and need to set it up for rack.
110
112
 
@@ -124,6 +126,10 @@ The following are useful rake tasks for testing purposes:
124
126
  * rake doc => runs yardoc (no, not really necessary)
125
127
  * rake clean => clear out the temporary files not included in the repo
126
128
  * rake rcov => runs rspec with rcov
129
+
130
+ For my own reference - jeweler rake task for deploying the new gem:
131
+
132
+ * rake version:bump:patch release
127
133
 
128
134
  Programming Info
129
135
  ================
@@ -22,7 +22,7 @@ module Orange
22
22
  # class and just include DataMapper::Resource. All carton methods are to
23
23
  # improve scaffolding capability.
24
24
  class Carton
25
- SCAFFOLD_OPTIONS = [:display_name] unless defined?(SCAFFOLD_OPTIONS)
25
+ SCAFFOLD_OPTIONS = [:display_name, :levels] unless defined?(SCAFFOLD_OPTIONS)
26
26
  # Declares a ModelResource subclass that scaffolds this carton
27
27
  # The Subclass will have the name of the carton followed by "_Resource"
28
28
  def self.as_resource
@@ -80,7 +80,7 @@ module Orange
80
80
  end
81
81
 
82
82
  def self.add_scaffold(name, type, dm_type, opts)
83
- scaffold_properties << {:name => name, :type => type, :levels => @levels}.merge(opts) if @levels
83
+ scaffold_properties << {:name => name, :type => type, :levels => @levels}.merge(opts) if @levels || opts.has_key?(:levels)
84
84
  opts = opts.delete_if{|k,v| SCAFFOLD_OPTIONS.include?(k)} # DataMapper doesn't like arbitrary opts
85
85
  self.property(name, dm_type, opts)
86
86
  end
@@ -0,0 +1,13 @@
1
+ require 'dm-timestamps'
2
+
3
+ module Orange
4
+ class Page < Orange::Carton
5
+ id
6
+ front do
7
+ title :title
8
+ fulltext :body
9
+ end
10
+ property :updated_at, DateTime
11
+ has n, :versions, "Orange::PageVersion"
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ require 'dm-timestamps'
2
+ module Orange
3
+ class PageVersion < Orange::Carton
4
+ id
5
+ title :title
6
+ fulltext :body
7
+ property :updated_at, DateTime
8
+ property :version, Integer, :default => 0
9
+ belongs_to :orange_page, "Orange::Page"
10
+ end
11
+ end
@@ -106,6 +106,7 @@ module Orange
106
106
  # Doesn't necessarily need to be a symbol, but generally is.
107
107
  # Set to the class name lowercase as a symbol by default.
108
108
  def load(resource, name = false)
109
+ name = resource.orange_name if(!name)
109
110
  name = resource.class.to_s.gsub(/::/, '_').downcase.to_sym if(!name)
110
111
  @resources[name] = resource.set_orange(self, name)
111
112
  end
@@ -1,19 +1,21 @@
1
1
  # Monkey Patch the extract_options! stolen from ActiveSupport
2
- class ::Array
3
- def extract_options!
2
+ # @private
3
+ class ::Array #:nodoc:
4
+ def extract_options!
4
5
  last.is_a?(::Hash) ? pop : {}
5
6
  end
6
- def extract_with_defaults(defaults)
7
+ def extract_with_defaults(defaults)
7
8
  extract_options!.with_defaults(defaults)
8
9
  end
9
10
  end
10
11
 
11
12
  # Monkey Patch for merging defaults into a hash
12
- class ::Hash
13
- def with_defaults(defaults)
13
+ # @private
14
+ class ::Hash #:nodoc:
15
+ def with_defaults(defaults)
14
16
  self.merge(defaults){ |key, old, new| old.nil? ? new : old }
15
17
  end
16
- def with_defaults!(defaults)
18
+ def with_defaults!(defaults)
17
19
  self.merge!(defaults){ |key, old, new| old.nil? ? new : old }
18
20
  end
19
21
  end
@@ -28,13 +30,15 @@ end
28
30
  # end
29
31
  #
30
32
  # # => {:x => 32, :y => 63, :z => 91}
31
- module Enumerable
33
+ # @private
34
+ module Enumerable #:nodoc:
32
35
  def inject_hash(hash = {})
33
36
  inject(hash) {|(h,item)| yield(h,item); h}
34
37
  end
35
38
  end
36
39
 
37
- module ClassInheritableAttributes
40
+ # @private
41
+ module ClassInheritableAttributes #:nodoc:
38
42
  def cattr_inheritable(*args)
39
43
  @cattr_inheritable_attrs ||= [:cattr_inheritable_attrs]
40
44
  @cattr_inheritable_attrs += args
@@ -99,4 +103,106 @@ module Orange
99
103
  end
100
104
  end
101
105
  end
102
- end
106
+
107
+ # @private
108
+ module Inflector
109
+ extend self
110
+ # @private
111
+ def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)
112
+ if first_letter_in_uppercase
113
+ lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
114
+ else
115
+ lower_case_and_underscored_word.to_s[0].chr.downcase + camelize(lower_case_and_underscored_word)[1..-1]
116
+ end
117
+ end
118
+
119
+ if Module.method(:const_get).arity == 1
120
+ def constantize(camel_cased_word)
121
+ names = camel_cased_word.split('::')
122
+ names.shift if names.empty? || names.first.empty?
123
+
124
+ constant = Object
125
+ names.each do |name|
126
+ constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
127
+ end
128
+ constant
129
+ end
130
+ else
131
+ def constantize(camel_cased_word) #:nodoc:
132
+ names = camel_cased_word.split('::')
133
+ names.shift if names.empty? || names.first.empty?
134
+
135
+ constant = Object
136
+ names.each do |name|
137
+ constant = constant.const_get(name, false) || constant.const_missing(name)
138
+ end
139
+ constant
140
+ end
141
+ end
142
+
143
+ end
144
+
145
+ end
146
+
147
+ # @private
148
+ class Object #:nodoc:
149
+ # An object is blank if it's false, empty, or a whitespace string.
150
+ # For example, "", " ", +nil+, [], and {} are blank.
151
+ #
152
+ # This simplifies
153
+ #
154
+ # if !address.nil? && !address.empty?
155
+ #
156
+ # to
157
+ #
158
+ # if !address.blank?
159
+ def blank?
160
+ respond_to?(:empty?) ? empty? : !self
161
+ end
162
+ end
163
+
164
+ # @private
165
+ class NilClass #:nodoc:
166
+ def blank?
167
+ true
168
+ end
169
+ end
170
+
171
+ # @private
172
+ class FalseClass #:nodoc:
173
+ def blank?
174
+ true
175
+ end
176
+ end
177
+
178
+ # @private
179
+ class TrueClass #:nodoc:
180
+ def blank?
181
+ false
182
+ end
183
+ end
184
+
185
+ # @private
186
+ class Array #:nodoc:
187
+ alias_method :blank?, :empty?
188
+ end
189
+
190
+ # @private
191
+ class Hash #:nodoc:
192
+ alias_method :blank?, :empty?
193
+ end
194
+
195
+ # @private
196
+ class String #:nodoc:
197
+ def blank?
198
+ self !~ /\S/
199
+ end
200
+ end
201
+
202
+ # @private
203
+ class Numeric #:nodoc:
204
+ def blank?
205
+ false
206
+ end
207
+ end
208
+
@@ -16,12 +16,13 @@ module Orange::Middleware
16
16
  # @option opts [Boolean] :config_id Whether to use the id set in a config file
17
17
 
18
18
  def init(opts = {})
19
- defs = {:locked => [:admin, :orange], :login => '/login',
19
+ defs = {:locked => [:admin, :orange], :login => '/login', :logout => '/logout',
20
20
  :handle_login => true, :openid => true, :config_id => true}
21
21
  opts = opts.with_defaults!(defs)
22
22
  @openid = opts[:openid]
23
23
  @locked = opts[:locked]
24
24
  @login = opts[:login]
25
+ @logout = opts[:logout]
25
26
  @handle = opts[:handle_login]
26
27
  @single = opts[:config_id]
27
28
  end
@@ -59,11 +60,20 @@ module Orange::Middleware
59
60
  end
60
61
 
61
62
  def need_to_handle?(packet)
62
- @handle && (packet.env['REQUEST_PATH'] == @login)
63
+ @handle && ([@login, @logout].include? packet.env['REQUEST_PATH'])
63
64
  end
64
65
 
65
66
  def handle_openid(packet)
67
+ if packet.env['REQUEST_PATH'] == @logout
68
+ packet.session['user.id'] = nil
69
+ packet['user.id'] = nil
70
+ after = packet.session['user.after_login'].blank? ?
71
+ '/' : packet.session['user.after_login']
72
+ packet.reroute(after)
73
+ false
74
+ end
66
75
  packet.reroute('/') if packet['user.id'] # Reroute to index if we're logged in.
76
+
67
77
  # If login set
68
78
  if packet.request.post?
69
79
  packet['template.disable'] = true
@@ -71,8 +81,28 @@ module Orange::Middleware
71
81
  if resp = packet.env["rack.openid.response"]
72
82
  if resp.status == :success
73
83
  packet['user.id'] = resp.identity_url
84
+
74
85
  packet['user.openid.url'] = resp.identity_url
75
86
  packet['user.openid.response'] = resp
87
+ # Load in any registration data gathered
88
+ profile_data = {}
89
+ # merge the SReg data and the AX data into a single hash of profile data
90
+ [ OpenID::SReg::Response, OpenID::AX::FetchResponse ].each do |data_response|
91
+ if data_response.from_success_response( resp )
92
+ profile_data.merge! data_response.from_success_response( resp ).data
93
+ end
94
+ end
95
+
96
+ if packet['user.id'] =~ /^https?:\/\/(www.)?google.com\/accounts/
97
+ packet['user.id'] = profile_data["http://axschema.org/contact/email"]
98
+ packet['user.id'] = packet['user.id'].first if packet['user.id'].kind_of?(Array)
99
+ end
100
+
101
+ if packet['user.id'] =~ /^https?:\/\/(www.)?yahoo.com/
102
+ packet['user.id'] = profile_data["http://axschema.org/contact/email"]
103
+ packet['user.id'] = packet['user.id'].first if packet['user.id'].kind_of?(Array)
104
+ end
105
+
76
106
 
77
107
  after = packet.session.has_key?('user.after_login') ?
78
108
  packet.session['user.after_login'] : '/'
@@ -94,8 +124,10 @@ module Orange::Middleware
94
124
  packet[:status] = 401
95
125
  packet[:headers] = {}
96
126
  packet.add_header('WWW-Authenticate', Rack::OpenID.build_header(
97
- :identifier => packet.request.params["openid_identifier"]
98
- ))
127
+ :identifier => packet.request.params["openid_identifier"],
128
+ :required => [:email, "http://axschema.org/contact/email"]
129
+ )
130
+ )
99
131
  packet[:content] = 'Got openID?'
100
132
  packet.finish
101
133
  end
@@ -63,10 +63,22 @@ module Orange::Middleware
63
63
  if @app.respond_to?(:packet_call)
64
64
  @app.packet_call(packet)
65
65
  else
66
- @app.call(packet.env)
66
+ recapture(@app.call(packet.env), packet)
67
67
  end
68
68
  end
69
69
 
70
+ # After the pass has been completed, we should recapture the contents and make
71
+ # sure they are placed in the packet, in case the downstream app is not Orange aware.
72
+ # @param [Array] the standard Rack striplet of status, headers and content
73
+ # @param [Orange::Packet] packet the packet to pass to downstream apps
74
+ # @return [Array] the standard Rack striplet of status, headers and content
75
+ def recapture(response, packet)
76
+ packet[:status] = response[0]
77
+ packet[:headers] = response[1]
78
+ packet[:content] = response[2].first
79
+ response
80
+ end
81
+
70
82
  # Accessor for @core, which is the stack's instance of Orange::Core
71
83
  # @return [Orange::Core] the stack's instance of Orange::Core
72
84
  def orange; @core; end
@@ -1,59 +1,30 @@
1
1
  require 'orange/middleware/base'
2
2
 
3
3
  module Orange::Middleware
4
+ # The FlexRouter middleware takes a resource that can route paths and
5
+ # then intercepts routes for that resource. By default,
6
+ # it uses the Orange::SitemapResource.
7
+ #
8
+ # The resource is automatically loaded into the core as
9
+ # :sitemap. The resource must respond to "route?(path)"
10
+ # and "route(packet)".
11
+ #
12
+ # Pass a different routing resource using the :resource arg
4
13
  class FlexRouter < Base
5
- def init(*args)
6
- opts = args.extract_options!.with_defaults(:contexts => [:admin, :orange], :root_resource => :not_found)
7
- @contexts = opts[:contexts]
8
- @root_resource = opts[:root_resource]
14
+ def init(opts = {})
15
+ @resource = opts[:resource] || Orange::SitemapResource
16
+ orange.load @resource.new, :sitemap
9
17
  end
10
18
 
11
- # sets resource, resource_id, resource_action and resource_path
12
- # /resource/id/action/[resource/path/if/any]
13
- # /resource/action/[resource/path/if/any]
14
- #
15
- # In future - support for nested resources
19
+ # Sets the sitemap resource as the router if the resource can accept
20
+ # the path.
16
21
  def packet_call(packet)
17
22
  return (pass packet) if packet['route.router'] # Don't route if other middleware
18
23
  # already has
19
- if(@contexts.include?(packet['route.context']))
20
- path = packet['route.path'] || packet.request.path_info
21
- parts = path.split('/')
22
- pad = parts.shift
23
- if !parts.empty?
24
- resource = parts.shift
25
- if orange.loaded?(resource.to_sym)
26
- packet['route.resource'] = resource.to_sym
27
- if !parts.empty?
28
- second = parts.shift
29
- if second =~ /^\d+$/
30
- packet['route.resource_id'] = second
31
- if !parts.empty?
32
- packet['route.resource_action'] = parts.shift.to_sym
33
- end
34
- else
35
- packet['route.resource_action'] = second.to_sym
36
- end
37
- end # end check for second part
38
- else
39
- parts.unshift(resource)
40
- end # end check for loaded resource
41
- end # end check for nonempty route
42
-
43
- packet['route.resource'] ||= @root_resource
44
- packet['route.resource_path'] = parts.unshift(pad).join('/')
45
- packet['route.router'] = self
46
- end # End context match if
47
-
24
+ path = packet['route.path'] || packet.request.path_info
25
+ packet['route.router'] = orange[:sitemap] if orange[:sitemap].route?(packet, path)
48
26
  pass packet
49
27
  end
50
28
 
51
- def route(packet)
52
- resource = packet['route.resource']
53
- raise 'resource not found' unless orange.loaded? resource
54
- mode = packet['route.resource_action'] ||
55
- (packet['route.resource_id'] ? :show : :list)
56
- packet[:content] = orange[resource].view packet
57
- end
58
29
  end
59
30
  end
@@ -0,0 +1,13 @@
1
+ require 'orange/middleware/base'
2
+ module Orange::Middleware
3
+ class Loader < Base
4
+ def init(*args)
5
+ Dir.glob(File.join(orange.app_dir, 'resources', '*.rb')).each do |f|
6
+ require f
7
+ orange.load Orange::Inflector.constantize(Orange::Inflector.camelize(File.basename(f, '.rb'))).new
8
+ end
9
+ Dir.glob(File.join(orange.app_dir, 'cartons', '*.rb')).each { |f| require f }
10
+ Dir.glob(File.join(orange.app_dir, 'middleware', '*.rb')).each { |f| require f }
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,24 @@
1
+ require 'orange/middleware/base'
2
+
3
+ module Orange::Middleware
4
+ # The RadiusParser middleware will parse all outgoing content with
5
+ # Radius.
6
+ #
7
+ # For more details on how Radius works, see http://radius.rubyforge.org/
8
+ # This middleware also loads a resource: "Orange::Radius", for the
9
+ # purpose of exposing the context object.
10
+ class RadiusParser < Base
11
+ def init(opts = {})
12
+ @contexts = opts[:contexts] || [:live]
13
+ orange.load Orange::Radius.new, :radius
14
+ end
15
+
16
+ # Passes packet then parses the return
17
+ def packet_call(packet)
18
+ pass packet
19
+ orange[:radius].parse packet if @contexts.include? packet['route.context']
20
+ packet.finish
21
+ end
22
+
23
+ end
24
+ end
@@ -3,9 +3,9 @@ require 'orange/middleware/base'
3
3
  module Orange::Middleware
4
4
  class RestfulRouter < Base
5
5
  def init(*args)
6
- opts = args.extract_options!.with_defaults(:contexts => [:admin, :orange], :root_resource => :not_found)
6
+ opts = args.extract_options!.with_defaults(:contexts => [:admin, :orange], :not_found => false)
7
7
  @contexts = opts[:contexts]
8
- @root_resource = opts[:root_resource]
8
+ @not_found = opts[:not_found]
9
9
  end
10
10
 
11
11
  # sets resource, resource_id, resource_action and resource_path
@@ -40,9 +40,14 @@ module Orange::Middleware
40
40
  end # end check for loaded resource
41
41
  end # end check for nonempty route
42
42
 
43
- packet['route.resource'] ||= @root_resource
44
- packet['route.resource_path'] = parts.unshift(pad).join('/')
45
- packet['route.router'] = self
43
+ if(packet['route.resource', false])
44
+ packet['route.resource_path'] = parts.unshift(pad).join('/')
45
+ packet['route.router'] = self
46
+ elsif(@not_found)
47
+ packet['route.resource'] = @not_found
48
+ packet['route.resource_path'] = parts.unshift(pad).join('/')
49
+ packet['route.router'] = self
50
+ end
46
51
  end # End context match if
47
52
 
48
53
  pass packet
@@ -13,8 +13,6 @@ module Orange::Middleware
13
13
  site = Orange::Site.first(:url.like => url)
14
14
  if site
15
15
  packet['site'] = site
16
- elsif
17
- nil
18
16
  else
19
17
  s = Orange::Site.new({:url => packet['route.site_url'],
20
18
  :name => 'An Orange Site'})
@@ -12,6 +12,8 @@ module Orange::Middleware
12
12
  @core.template_chooser do |packet|
13
13
  if packet['route.context'] == :admin
14
14
  packet.add_css('admin.css', :module => '_orange_')
15
+ packet.add_js('jquery.js', :module => '_orange_')
16
+ packet.add_js('admin.js', :module => '_orange_')
15
17
  'admin.haml'
16
18
  else
17
19
  false
@@ -25,9 +27,10 @@ module Orange::Middleware
25
27
  if needs_wrapped?(packet)
26
28
  content = wrap(packet, content)
27
29
  packet[:content] = content.first
28
- end
29
- orange.fire(:wrapped, packet)
30
- [status, headers, packet.content]
30
+ orange.fire(:wrapped, packet)
31
+ end
32
+ orange.fire(:after_wrap, packet)
33
+ packet.finish
31
34
  end
32
35
 
33
36
  def needs_wrapped?(packet)
@@ -3,8 +3,13 @@ require 'orange/core'
3
3
  module Orange
4
4
  # Orange Resource for being subclassed
5
5
  class Resource
6
+ extend ClassInheritableAttributes
7
+ # Defines a model class as an inheritable class attribute and also an instance
8
+ # attribute
9
+ cattr_inheritable :called
10
+
6
11
  def initialize(*args, &block)
7
- @options = Options.new(*args, &block).hash
12
+ @options = DefaultHash.new.merge!(Options.new(*args, &block).hash)
8
13
  end
9
14
 
10
15
  def set_orange(orange, name)
@@ -22,6 +27,10 @@ module Orange
22
27
  true
23
28
  end
24
29
 
30
+ def self.call_me(name)
31
+ self.called = name
32
+ end
33
+
25
34
  def orange
26
35
  @orange
27
36
  end
@@ -35,7 +44,7 @@ module Orange
35
44
  end
36
45
 
37
46
  def orange_name
38
- @my_orange_name
47
+ @my_orange_name || self.class.called || false
39
48
  end
40
49
 
41
50
  def options
@@ -9,6 +9,8 @@ module Orange
9
9
  def add_link(section, *args)
10
10
  opts = args.extract_with_defaults(:position => 0)
11
11
  @links[section] = [] unless @links.has_key?(section)
12
+ matches = @links[section].select{|i| i[:resource] == opts[:resource] && i[:text] == opts[:text]}
13
+ return @links[section] unless matches.empty?
12
14
  @links[section].insert(opts.delete(:position), opts)
13
15
  @links[section].compact!
14
16
  @links[section].uniq!
@@ -23,9 +23,10 @@ module Orange
23
23
  orange[:mapper].route_to(self, resource, *args)
24
24
  end
25
25
 
26
- def reroute(url, type = :real)
26
+ def reroute(url, type = :real, *args)
27
27
  packet['reroute.to'] = url
28
28
  packet['reroute.type'] = type
29
+ packet['reroute.args'] = *args if args
29
30
  raise Reroute.new(self), 'Unhandled reroute'
30
31
  end
31
32
 
@@ -44,7 +45,7 @@ module Orange
44
45
  packet['reroute.to']
45
46
  # Parsing for orange urls or something
46
47
  when :orange
47
- packet.route_to(packet['reroute.to'])
48
+ packet.route_to(packet['reroute.to'], packet['reroute.args', []])
48
49
  else
49
50
  packet['reroute.to']
50
51
  end
@@ -2,7 +2,6 @@ require 'orange/resources/routable_resource'
2
2
 
3
3
  module Orange
4
4
  class ModelResource < RoutableResource
5
- extend ClassInheritableAttributes
6
5
  # Defines a model class as an inheritable class attribute and also an instance
7
6
  # attribute
8
7
  cattr_inheritable :model_class
@@ -29,12 +28,11 @@ module Orange
29
28
  # Calling view is equivalent to calling a viewable method directly, view just
30
29
  # sets up safe defaults so method missing errors are less likely.
31
30
  # @param [Orange::Packet] packet the packet calling view on this resource
32
- def view(packet, *args)
33
- opts = args.last || {}
31
+ def view(packet, opts = {})
34
32
  resource_id = opts[:id] || packet['route.resource_id', false]
35
33
  mode = opts[:mode] || packet['route.resource_action'] ||
36
34
  (resource_id ? :show : :index)
37
- self.__send__(mode, packet, *args)
35
+ self.__send__(mode, packet, opts)
38
36
  end
39
37
 
40
38
  # Renders a view, with all options set for haml to access.
@@ -215,7 +213,7 @@ module Orange
215
213
  # Returns a scaffolded attribute
216
214
  def view_attribute(prop, model_name, *args)
217
215
  args = args.extract_options!
218
- val = args[:value] || ''
216
+ val = (args[:value] || '')
219
217
  label = args[:label] || false
220
218
  show = args[:show] || false
221
219
  name = prop[:name]
@@ -223,16 +221,19 @@ module Orange
223
221
  unless show
224
222
  case prop[:type]
225
223
  when :title
226
- ret = "<input class='title' type='text' value='#{val}' name='#{model_name}[#{name}]' />"
224
+ val.gsub!('"', '&quot;')
225
+ ret = "<input class=\"title\" type=\"text\" value=\"#{val}\" name=\"#{model_name}[#{name}]\" />"
227
226
  when :text
228
- ret = "<input type='text' value='#{val}' name='#{model_name}[#{name}]' />"
227
+ val.gsub!('"', '&quot;')
228
+ ret = "<input type=\"text\" value=\"#{val}\" name=\"#{model_name}[#{name}]\" />"
229
229
  when :fulltext
230
230
  ret = "<textarea name='#{model_name}[#{name}]'>#{val}</textarea>"
231
231
  when :boolean
232
232
  human_readable_name = human_readable_name + '?'
233
233
  ret = "<input type='hidden' name='#{model_name}[#{name}]' value='0' /><input type='checkbox' name='#{model_name}[#{name}]' value='1' #{'checked="checked"' if (val && val != '')}/>"
234
234
  else
235
- ret = "<input type='text' value='#{val}' name='#{model_name}[#{name}]' />"
235
+ val.gsub!('"', '&quot;')
236
+ ret = "<input type=\"text\" value=\"#{val}\" name=\"#{model_name}[#{name}]\" />"
236
237
  end
237
238
  display_name = prop[:display_name] || human_readable_name
238
239
  ret = "<label for=''>#{display_name}</label><br />" + ret if label
@@ -248,7 +249,7 @@ module Orange
248
249
  ret = "<div class='#{model_name}-#{name}'>#{val}</div>"
249
250
  end
250
251
  end
251
- ret
252
+ return ret
252
253
  end
253
254
  end
254
255
  end
@@ -3,11 +3,8 @@ module Orange
3
3
  def afterLoad
4
4
  orange.add_pulp Orange::Pulp::PageParts
5
5
  end
6
- end
7
-
8
- module Pulp::PageParts
9
6
 
10
- def part
7
+ def part(packet)
11
8
  unless packet[:page_parts, false]
12
9
  packet[:page_parts] = DefaultHash.new
13
10
  packet[:page_parts].default = ''
@@ -15,33 +12,56 @@ module Orange
15
12
  packet[:page_parts]
16
13
  end
17
14
 
18
- # Feels like part should be plural, no?
19
- def parts; part; end
20
-
21
15
 
22
- def add_css(file, opts = {})
16
+ def add_css(packet, file, opts = {})
23
17
  ie = opts[:ie] || false
24
18
  mod = opts[:module] || 'public'
25
19
  # module set to false gives the root assets dir
26
20
  assets = File.join('assets', mod)
27
21
  file = File.join('', assets, 'css', file)
28
- if ie
29
- part[:ie_css] = part[:ie_css] + "<link rel=\"stylesheet\" href=\"#{file}\" type=\"text/css\" media=\"screen\" charset=\"utf-8\" />"
30
- else
31
- part[:css] = part[:css] + "<link rel=\"stylesheet\" href=\"#{file}\" type=\"text/css\" media=\"screen\" charset=\"utf-8\" />"
22
+ unless packet[:css_files, []].include?(file)
23
+ if ie
24
+ part(packet)[:ie_css] = part(packet)[:ie_css] + "<link rel=\"stylesheet\" href=\"#{file}\" type=\"text/css\" media=\"screen\" charset=\"utf-8\" />"
25
+ else
26
+ part(packet)[:css] = part(packet)[:css] + "<link rel=\"stylesheet\" href=\"#{file}\" type=\"text/css\" media=\"screen\" charset=\"utf-8\" />"
27
+ end
28
+ packet[:css_files] ||= []
29
+ packet[:css_files] << file
32
30
  end
33
31
  end
34
32
 
35
- def add_js(file, opts = {})
33
+ def add_js(packet, file, opts = {})
36
34
  ie = opts[:ie] || false
37
35
  mod = opts[:module] || 'public'
38
36
  assets = File.join('assets', mod)
39
37
  file = File.join('', assets, 'js', file)
40
- if ie
41
- part[:ie_js] = part[:ie_js] + "<script src=\"#{file}\" type=\"text/javascript\"></script>"
42
- else
43
- part[:js] = part[:js] + "<script src=\"#{file}\" type=\"text/javascript\"></script>"
38
+ unless packet[:js_files, []].include?(file)
39
+ if ie
40
+ part(packet)[:ie_js] = part(packet)[:ie_js] + "<script src=\"#{file}\" type=\"text/javascript\"></script>"
41
+ else
42
+ part(packet)[:js] = part(packet)[:js] + "<script src=\"#{file}\" type=\"text/javascript\"></script>"
43
+ end
44
+ packet[:js_files] ||= []
45
+ packet[:js_files] << file
44
46
  end
45
47
  end
46
48
  end
49
+
50
+ module Pulp::PageParts
51
+ def part
52
+ orange[:page_parts].part(packet)
53
+ end
54
+
55
+ # Feels like part should be plural, no?
56
+ def parts; part; end
57
+
58
+
59
+ def add_css(file, opts = {})
60
+ orange[:page_parts].add_css(packet, file, opts)
61
+ end
62
+
63
+ def add_js(file, opts = {})
64
+ orange[:page_parts].add_js(packet, file, opts)
65
+ end
66
+ end
47
67
  end
@@ -0,0 +1,58 @@
1
+ module Orange
2
+ class PageResource < Orange::ModelResource
3
+ use Orange::Page
4
+ call_me :pages
5
+ def afterLoad
6
+ orange[:admin, true].add_link("Content", :resource => @my_orange_name, :text => 'Pages')
7
+ options[:sitemappable] = true
8
+
9
+ end
10
+ # Creates a new model object and saves it (if a post), then reroutes to the main page
11
+ # @param [Orange::Packet] packet the packet being routed
12
+ def new(packet, *opts)
13
+ if packet.request.post?
14
+ m = model_class.new(packet.request.params[@my_orange_name.to_s])
15
+ m.versions.new(packet.request.params[@my_orange_name.to_s].merge(:version => 1))
16
+ m.save
17
+ end
18
+ packet.reroute(@my_orange_name, :orange)
19
+ end
20
+
21
+ # Saves updates to an object specified by packet['route.resource_id'], then reroutes to main
22
+ # @param [Orange::Packet] packet the packet being routed
23
+ def save(packet, *opts)
24
+ if packet.request.post?
25
+ m = model_class.get(packet['route.resource_id'])
26
+ if m
27
+ m.update(packet.request.params[@my_orange_name.to_s])
28
+ max = m.versions.max(:version)
29
+ m.versions.new(packet.request.params[@my_orange_name.to_s].merge(:version => max + 1))
30
+ m.save
31
+ end
32
+ end
33
+ packet.reroute(@my_orange_name, :orange)
34
+ end
35
+
36
+ # Returns a single object found by the model class, given an id.
37
+ # If id isn't given, we return false.
38
+ # @param [Orange::Packet] packet the packet we are returning a view for
39
+ # @param [Symbol] mode the mode we are trying to view (used to find template name)
40
+ # @param [Numeric] id the id to lookup on the model class
41
+ # @return [Object] returns an object of type set by #use, if one found with same id
42
+ def find_one(packet, mode, id = false)
43
+ return false unless id
44
+ m = model_class.get(id)
45
+ if packet['route.resource_path',''] =~ /version\//
46
+ parts = packet['route.resource_path'].split('/')
47
+ version = parts[2]
48
+ v = m.versions.first(:version => version)
49
+ if v
50
+ attrs = v.attributes
51
+ [:version, :orange_page_id, :page_id, :id].each { |i| attrs.delete(i) }
52
+ m.attributes = attrs
53
+ end
54
+ end
55
+ m
56
+ end
57
+ end
58
+ end
@@ -52,9 +52,11 @@ module Orange
52
52
  module Pulp::ParserPulp
53
53
  def html(&block)
54
54
  if block_given?
55
- doc = orange[:parser].hpricot(packet[:content])
56
- yield doc
57
- packet[:content] = doc.to_s
55
+ unless(packet[:content].blank?)
56
+ doc = orange[:parser].hpricot(packet[:content])
57
+ yield doc
58
+ packet[:content] = doc.to_s
59
+ end
58
60
  end
59
61
  end
60
62
  end
@@ -0,0 +1,23 @@
1
+ require 'radius'
2
+
3
+ module Orange
4
+ # Radius resource is for exposing the Radius context
5
+ # and allowing parsing.
6
+ class Radius < Resource
7
+ def afterLoad
8
+ @context = ::Radius::Context.new
9
+ end
10
+
11
+ def context
12
+ @context
13
+ end
14
+
15
+ def parse(packet)
16
+ content = packet[:content, false]
17
+ unless content.blank?
18
+ parser = ::Radius::Parser.new(context, :tag_prefix => 'o')
19
+ packet[:content] = parser.parse(content)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -8,21 +8,82 @@ module Orange
8
8
  admin do
9
9
  text :slug
10
10
  text :link_text
11
- boolean :show_in_nav, :default => false, :display_name => 'Show?'
11
+ boolean :show_in_nav, :default => false, :display_name => 'Show in Navigation?'
12
12
  end
13
13
  orange do
14
14
  string :resource
15
15
  string :resource_id
16
+ string :resource_action
17
+ boolean :accept_args, :default => true
16
18
  end
17
- include DataMapper::Transaction::Resource # Make sure Transactions are included
19
+ include DataMapper::Transaction::Resource # Make sure Transactions are included (for awesome_set)
18
20
  is :awesome_set, :scope => [:orange_site_id]
19
21
 
22
+ def full_path
23
+ self_and_ancestors.inject('') do |path, part|
24
+ if part.parent # Check if this is a child
25
+ path = path + part.slug + '/'
26
+ else # The root slug is just the initial '/'
27
+ path = path + '/'
28
+ end
29
+ end
30
+ end
31
+
32
+ def self.home_for_site(site_id)
33
+ root(:orange_site_id => site_id)
34
+ end
35
+
36
+
37
+ def self.create_home_for_site(site_id)
38
+ home = self.new({:orange_site_id => site_id, :slug => '_index_', :accept_args => false, :link_text => 'Home'})
39
+ home.move(:root)
40
+ home.save
41
+ home
42
+ end
20
43
  end
21
44
 
22
45
  class SitemapResource < ModelResource
23
46
  use Orange::Route
47
+
24
48
  def afterLoad
25
49
  orange[:admin, true].add_link('Content', :resource => @my_orange_name, :text => 'Sitemap')
50
+
51
+ end
52
+
53
+ def route(packet)
54
+ resource = packet['route.resource']
55
+ raise 'resource not found' unless orange.loaded? resource
56
+ unless (packet['route.resource_action'])
57
+ packet['route.resource_action'] = (packet['route.resource_id'] ? :show : :index)
58
+ end
59
+
60
+ packet[:content] = (orange[resource].view packet)
61
+ end
62
+
63
+ def route?(packet, path)
64
+ parts = path.split('/')
65
+ pad = parts.shift
66
+ matched = home(packet)
67
+ extras = ''
68
+ while (!parts.empty?)
69
+ next_part = parts.shift
70
+ matches = matched.children.first(:slug => next_part)
71
+ if(matches)
72
+ matched = matches
73
+ else
74
+ extras = parts.unshift(next_part).unshift(pad).join('/')
75
+ parts = []
76
+ end
77
+ end
78
+ return false if(extras.length > 0 && !matched.accept_args)
79
+ packet['route.path'] = path
80
+ packet['route.route'] = matched
81
+ packet['route.resource'] = matched.resource.to_sym unless matched.resource.blank?
82
+ packet['route.resource_id'] = matched.resource_id.to_i unless matched.resource_id.blank?
83
+ packet['route.resource_action'] = matched.resource_action.to_sym unless matched.resource_action.blank?
84
+ # allow "resource_paths" - extra arguments added as path parts
85
+ packet['route.resource_path'] = extras
86
+ return true
26
87
  end
27
88
 
28
89
  # Creates a new model object and saves it (if a post), then reroutes to the main page
@@ -75,22 +136,58 @@ module Orange
75
136
 
76
137
  def home(packet)
77
138
  site_id = packet['site'].id
78
- home_for_site(site_id) || create_home_for_site(site_id)
139
+ model_class.home_for_site(site_id) || model_class.create_home_for_site(site_id)
79
140
  end
80
141
 
81
- def home_for_site(site_id)
82
- model_class.first(:slug => '_index_', :orange_site_id => site_id, :order => :lft.asc)
142
+ def routes_for(packet)
143
+ keys = {}
144
+ keys[:resource] = packet['route.resource'] unless packet['route.resource'].blank?
145
+ keys[:resource_id] = packet['route.resource_id'] unless packet['route.resource_id'].blank?
146
+ keys[:orange_site_id] = packet['site'].id unless packet['site'].blank?
147
+ model_class.all(keys)
83
148
  end
84
149
 
85
- def create_home_for_site(site_id)
86
- home = model_class.new({:orange_site_id => site_id, :slug => '_index_'})
87
- home.move(:root)
88
- home.save
89
- home
150
+ def add_link_for(packet)
151
+ linky = ['add_route']
152
+ linky << (packet['site'].blank? ? '0' : packet['site'].id)
153
+ linky << (packet['route.resource'].blank? ? '0' : packet['route.resource'])
154
+ linky << (packet['route.resource_id'].blank? ? '0' : packet['route.resource_id'])
155
+ packet.route_to(:sitemap, linky.join('/') )
156
+ end
157
+
158
+ def add_route(packet, opts = {})
159
+ args = packet['route.resource_path'].split('/')
160
+ args.shift
161
+ args = [:orange_site_id, :resource, :resource_id, :slug].inject_hash{|results, key|
162
+ results[key] = args.shift
163
+ }
164
+ me = model_class.new(args)
165
+ me.save
166
+ me.move(:into => home(packet))
167
+ packet.reroute(@my_orange_name, :orange, me.id, 'edit')
168
+ do_view(packet, :add_route, {})
169
+ end
170
+
171
+ def slug_for(model, props)
172
+ hash = model.attributes
173
+ return slug(model.title) if hash.has_key?(:title)
174
+ return slug(model.name) if hash.has_key?(:name)
175
+ return 'route-'+model.id
176
+ end
177
+
178
+ def slug(str)
179
+ str.downcase.gsub(/[']+/, "").gsub(/[^a-z0-9]+/, "_")
180
+ end
181
+
182
+ def find_list(packet, mode, *args)
183
+ home(packet).self_and_descendants
90
184
  end
91
185
 
92
- def find_list(packet, mode)
93
- Orange::Route.all(:order => :lft) || []
186
+ def sitemap_links(packet, opts = {})
187
+ packet.add_js('sitemap.js', :module => '_orange_')
188
+ opts.with_defaults!({:list => routes_for(packet) })
189
+ opts.merge!({:add_route_link => add_link_for(packet)})
190
+ do_list_view(packet, :sitemap_links, opts)
94
191
  end
95
192
  end
96
193
  end
@@ -46,10 +46,8 @@ module Orange
46
46
  def prebuild(choice)
47
47
  case choice
48
48
  when :none
49
- no_recapture
50
49
  run @main_app
51
50
  else
52
- no_recapture
53
51
  run @main_app
54
52
  end
55
53
  end
@@ -150,15 +148,10 @@ module Orange
150
148
  orange.add_pulp(mod)
151
149
  end
152
150
 
153
- # The exit point for the middleware stack,
154
- # this method will add the Orange::Middleware::Recapture if applicable
151
+ # The exit point for the middleware stack,
155
152
  # add the app to @main_app and then call Rack::Builder#run with the main app
156
153
  def run(app, *args)
157
154
  opts = args.extract_options!
158
- if @recapture
159
- stack Orange::Middleware::Recapture
160
- @recapture = false
161
- end
162
155
  @main_app = app
163
156
  @build.run(app)
164
157
  end
@@ -21,7 +21,7 @@ describe Orange::Middleware::Base do
21
21
  app = mock("downstream")
22
22
  app2 = mock("downstream_orange")
23
23
  my_hash = {:foo => :bar}
24
- app.should_receive(:call).with(my_hash)
24
+ app.should_receive(:call).with(my_hash).and_return([{},200,[]])
25
25
  app2.should_receive(:packet_call).with(an_instance_of(Orange::Packet))
26
26
  mid = MockOrangeBasedMiddlewareTwo.new(app, nil)
27
27
  mid2 = MockOrangeBasedMiddlewareTwo.new(app2, nil)
@@ -34,4 +34,5 @@ describe Orange::Middleware::Base do
34
34
  mid = MockOrangeBasedMiddlewareTwo.new(nil, c)
35
35
  mid.orange.should equal c
36
36
  end
37
+
37
38
  end
@@ -10,8 +10,8 @@ describe Orange::Middleware::SiteLoad do
10
10
  Orange::Site.should_receive(:first).with(an_instance_of(Hash)).and_return('foo')
11
11
  app = Orange::Middleware::SiteLoad.new(return_env_app, Orange::Core.new)
12
12
  ret = app.call({})
13
- ret['orange.env'].should have_key('site')
14
- ret['orange.env']['site'].should == 'foo'
13
+ ret[0]['orange.env'].should have_key('site')
14
+ ret[0]['orange.env']['site'].should == 'foo'
15
15
  end
16
16
 
17
17
  it "should create a new site object, if one doesn't exist" do
@@ -21,6 +21,6 @@ describe Orange::Middleware::SiteLoad do
21
21
  m.should_receive(:save).and_return(true)
22
22
  app = Orange::Middleware::SiteLoad.new(return_env_app, Orange::Core.new)
23
23
  ret = app.call({})
24
- ret['orange.env'].should have_key('site')
24
+ ret[0]['orange.env'].should have_key('site')
25
25
  end
26
26
  end
@@ -170,7 +170,7 @@ describe Orange::ModelResource do
170
170
  it "should call carton's destroy! on DELETE delete and reroute" do
171
171
  a= MockModelResourceTwo.new
172
172
  m= mock("carton", :null_object => true)
173
- m.should_receive(:destroy!)
173
+ m.should_receive(:destroy)
174
174
  a.stub!(:model_class).and_return(m)
175
175
  p2 = mock("packet", :null_object => true)
176
176
  p2.should_receive(:reroute)
@@ -46,6 +46,6 @@ end
46
46
 
47
47
  def return_env_app
48
48
  lambda { |env|
49
- env
49
+ [env, 200, ["ok"]]
50
50
  }
51
51
  end
@@ -104,6 +104,7 @@ describe Orange::Stack do
104
104
  it "should rebuild stack if auto_reload! set" do
105
105
  x= Orange::Stack.new do
106
106
  auto_reload!
107
+ use MockMiddleware
107
108
  run MockExitware.new
108
109
  end
109
110
  x.app.should_not eql(x.app)
@@ -157,18 +158,11 @@ describe Orange::Stack do
157
158
  restfuls.should have(1).items
158
159
  end
159
160
 
160
- it "should have not have recapture middleware for a default stack" do
161
+ it "should have not have extra middleware for a default stack" do
161
162
  x= Orange::Stack.new MockApplication
162
163
  x.middlewarez.should have(1).middlewares
163
164
  end
164
-
165
- it "should have recapture middleware by default if stack created with block" do
166
- x= Orange::Stack.new do
167
- run MockExitware.new
168
- end
169
- x.middlewarez.should have(2).middlewares
170
- end
171
-
165
+
172
166
  it "should not include Rack::OpenID unless openid_access_control enabled" do
173
167
  defined?(Rack::OpenID).should be_nil
174
168
  x= Orange::Stack.new do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: orange
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Haslem
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-01-25 00:00:00 -05:00
12
+ date: 2010-02-16 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -70,7 +70,7 @@ dependencies:
70
70
  requirements:
71
71
  - - ">="
72
72
  - !ruby/object:Gem::Version
73
- version: 0.2.0
73
+ version: 0.2.2
74
74
  version:
75
75
  - !ruby/object:Gem::Dependency
76
76
  name: meekish-openid_dm_store
@@ -82,6 +82,26 @@ dependencies:
82
82
  - !ruby/object:Gem::Version
83
83
  version: 0.1.2
84
84
  version:
85
+ - !ruby/object:Gem::Dependency
86
+ name: dm-is-awesome_set
87
+ type: :runtime
88
+ version_requirement:
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: 0.11.0
94
+ version:
95
+ - !ruby/object:Gem::Dependency
96
+ name: radius
97
+ type: :runtime
98
+ version_requirement:
99
+ version_requirements: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 0.6.1
104
+ version:
85
105
  - !ruby/object:Gem::Dependency
86
106
  name: rspec
87
107
  type: :development
@@ -114,6 +134,8 @@ files:
114
134
  - lib/orange.rb
115
135
  - lib/orange/application.rb
116
136
  - lib/orange/carton.rb
137
+ - lib/orange/cartons/page_carton.rb
138
+ - lib/orange/cartons/page_version_carton.rb
117
139
  - lib/orange/cartons/site_carton.rb
118
140
  - lib/orange/core.rb
119
141
  - lib/orange/magick.rb
@@ -122,7 +144,8 @@ files:
122
144
  - lib/orange/middleware/database.rb
123
145
  - lib/orange/middleware/flex_router.rb
124
146
  - lib/orange/middleware/globals.rb
125
- - lib/orange/middleware/recapture.rb
147
+ - lib/orange/middleware/loader.rb
148
+ - lib/orange/middleware/radius.rb
126
149
  - lib/orange/middleware/rerouter.rb
127
150
  - lib/orange/middleware/restful_router.rb
128
151
  - lib/orange/middleware/route_context.rb
@@ -138,7 +161,9 @@ files:
138
161
  - lib/orange/resources/mapper.rb
139
162
  - lib/orange/resources/model_resource.rb
140
163
  - lib/orange/resources/page_parts.rb
164
+ - lib/orange/resources/page_resource.rb
141
165
  - lib/orange/resources/parser.rb
166
+ - lib/orange/resources/radius.rb
142
167
  - lib/orange/resources/routable_resource.rb
143
168
  - lib/orange/resources/singleton_model_resource.rb
144
169
  - lib/orange/resources/sitemap_resource.rb
@@ -181,7 +206,6 @@ test_files:
181
206
  - spec/orange/middleware/base_spec.rb
182
207
  - spec/orange/middleware/database_spec.rb
183
208
  - spec/orange/middleware/globals_spec.rb
184
- - spec/orange/middleware/recapture_spec.rb
185
209
  - spec/orange/middleware/rerouter_spec.rb
186
210
  - spec/orange/middleware/restful_router_spec.rb
187
211
  - spec/orange/middleware/route_context_spec.rb
@@ -1,19 +0,0 @@
1
- require 'orange/middleware/base'
2
- module Orange::Middleware
3
-
4
- # Middleware to recapture return info and put it back into the
5
- # packet. Since the Orange::Stack is all middleware, this is
6
- # important for adding after filters into the orange stack
7
- # that can interact with the returns of external apps
8
- class Recapture < Base
9
-
10
- def packet_call(packet)
11
- ret = pass packet
12
- packet[:status] = ret[0]
13
- packet[:headers] = ret[1]
14
- packet[:content] = ret[2].first
15
- ret
16
- end
17
-
18
- end
19
- end
@@ -1,3 +0,0 @@
1
- describe Orange::Middleware::Recapture do
2
- it "should be spec'ed"
3
- end