orange 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -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