milk 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -7,22 +7,29 @@ autoload 'FileUtils', 'fileutils'
7
7
 
8
8
  # Set up our main namespace with autoloaded parts
9
9
  module Milk
10
- VERSION = '0.0.1'
10
+ VERSION = '0.0.5'
11
11
 
12
12
  LIB_DIR = File.dirname(__FILE__)
13
- BIN_DIR = File.absolute_path(File.dirname(__FILE__)+"/../../local/bin")
13
+ BIN_DIR ||= File.absolute_path(File.dirname(__FILE__)+"/../../local/bin")
14
14
  def self.get_milk_root
15
15
  c = caller(1).collect { |line| line.split(':').first }
16
16
  c = c.select { |line| line !~ /\/gems\// }
17
17
  File.absolute_path(File.dirname(c.first))
18
18
  end
19
- MILK_ROOT ||= get_milk_root
20
- COMPONENTS_DIR = MILK_ROOT + "/design"
21
- PAGES_DIR = MILK_ROOT + "/pages"
19
+ MILK_ROOT = get_milk_root
22
20
  CONFIG_DIR = MILK_ROOT + "/config"
23
- PUBLIC_DIR = MILK_ROOT + "/public"
24
- FIELDS_DIR = LIB_DIR + "/milk/fields"
25
-
21
+
22
+ # Load overrides from config file
23
+ YAML.load(open(CONFIG_DIR+"/config.yaml")).each_pair do |key, value|
24
+ eval("#{key} = #{value.inspect}")
25
+ end
26
+
27
+ # Set defaults otherwise
28
+ COMPONENTS_DIR ||= MILK_ROOT + "/design"
29
+ PAGES_DIR ||= MILK_ROOT + "/pages"
30
+ PUBLIC_DIR ||= MILK_ROOT + "/public"
31
+ FIELDS_DIR ||= LIB_DIR + "/milk/fields"
32
+
26
33
  $LOAD_PATH.unshift(LIB_DIR) unless $LOAD_PATH.include?(LIB_DIR)
27
34
  autoload :Application, "milk/application"
28
35
  autoload :Component, "milk/component"
@@ -1,12 +1,11 @@
1
1
  module Milk
2
2
  class Application
3
3
 
4
- PAGE_PATH_REGEX = /^\/([A-Z][a-zA-Z]+(\/[A-Z][a-zA-Z]+)*)+\/*$/
5
- EDIT_PATH_REGEX = /^\/([A-Z][a-zA-Z]+(\/[A-Z][a-zA-Z]+)*)+\/edit\/*$/
6
- HAXE_PATH_REGEX = /^\/(.*).hx$/
4
+ PAGE_PATH_REGEX = /^\/([a-zA-Z0-9_]+(\/[a-zA-Z0-9_]+)*)+\/*$/
5
+ EDIT_PATH_REGEX = /^\/([a-zA-Z0-9_]+(\/[a-zA-Z0-9_]+)*)+\/edit\/*$/
7
6
 
8
- def route(req)
9
- path = req.path_info
7
+ def route
8
+ path = @req.path_info
10
9
 
11
10
  if path == '/'
12
11
  # Special case for root
@@ -18,29 +17,31 @@ module Milk
18
17
 
19
18
  # Route the request to the right callback
20
19
  action = case
21
- when req.get?
20
+ when @req.get?
22
21
  case
23
- when path =~ HAXE_PATH_REGEX
24
- regex = HAXE_PATH_REGEX
25
- :haxe
26
- when path =~ PAGE_PATH_REGEX
27
- regex = PAGE_PATH_REGEX
28
- :view
22
+ when path == "/logout"
23
+ :logout
29
24
  when path =~ EDIT_PATH_REGEX
30
25
  regex = EDIT_PATH_REGEX
31
26
  :edit
27
+ when path =~ PAGE_PATH_REGEX
28
+ regex = PAGE_PATH_REGEX
29
+ :view
32
30
  end
33
- when req.delete?
31
+ when @req.delete?
34
32
  if path =~ PAGE_PATH_REGEX
35
33
  regex = PAGE_PATH_REGEX
36
34
  :delete
37
35
  end
38
- when req.post?
36
+ when @req.post?
39
37
  if path =~ PAGE_PATH_REGEX
40
38
  regex = PAGE_PATH_REGEX
41
39
  :preview
42
40
  end
43
- when req.put?
41
+ if path == '/login'
42
+ :login
43
+ end
44
+ when @req.put?
44
45
  if path =~ PAGE_PATH_REGEX
45
46
  regex = PAGE_PATH_REGEX
46
47
  :save
@@ -52,57 +53,130 @@ module Milk
52
53
  if (action == :view || action == :edit)
53
54
  begin
54
55
  page = Milk::Page.find(page_name)
56
+ page.instance_variable_set(:@app, self)
55
57
  rescue Milk::PageNotFoundError
56
58
  action = :not_found
57
59
  end
58
60
  end
59
61
 
60
- if (action == :haxe)
61
- begin
62
- page = Milk::Haxe.new(page_name)
63
- rescue Milk::PageNotFoundError
64
- action = :not_found
65
- end
66
- end
67
-
68
62
  if (action == :preview || action == :save)
69
- page = Milk::Page.json_unserialize(YAML.load(req.body.read), page_name)
63
+ page = Milk::Page.json_unserialize(YAML.load(@req.body.read), page_name)
64
+ page.instance_variable_set(:@app, self)
70
65
  end
71
66
 
67
+ if !@user && [:edit, :save, :delete].include?(action)
68
+ action = :login_form
69
+ end
70
+
72
71
  return action, page_name, page
73
72
  end
74
73
 
74
+ def obfuscate(value)
75
+ require 'base64'
76
+ len = Milk::SECRET.length
77
+ result = (0...value.length).collect { |i| value[i].ord ^ Milk::SECRET[i%len].ord }
78
+ Base64.encode64(result.pack("C*"))
79
+ end
80
+
81
+ def decode(code)
82
+ require 'base64'
83
+ len = Milk::SECRET.length
84
+ value = Base64.decode64(code)
85
+ result = (0...value.length).collect { |i| value[i].ord ^ Milk::SECRET[i%len].ord }
86
+ result.pack("C*")
87
+ end
88
+
89
+ def hash(email, password)
90
+ require 'digest/md5'
91
+ Digest::MD5.hexdigest("#{password}")
92
+ end
93
+
94
+ def logout()
95
+ @resp.delete_cookie('auth', :path => "/")
96
+ @resp.redirect(@req.params['dest'])
97
+ end
98
+
99
+ def flash(message=nil)
100
+ @resp.delete_cookie('flash', :path => "/") unless message
101
+ @resp.set_cookie('flash', :path => "/", :value => message) if message
102
+ @req.cookies['flash']
103
+ end
104
+
105
+ def login()
106
+ email = @req.params['email']
107
+ user = users[email]
108
+ if user
109
+ expected = user["hash"]
110
+ actual = hash(email, @req.params['password'])
111
+ if actual == expected
112
+ @resp.set_cookie('auth', :path => "/", :value => obfuscate(email))
113
+ else
114
+ flash "Incorrect password for user #{email}"
115
+ end
116
+ else
117
+ flash "User #{email} not found"
118
+ end
119
+ @resp.redirect(@req.params['dest'])
120
+ end
121
+
122
+ def users
123
+ users_file = Milk::CONFIG_DIR+"/users.yaml"
124
+ YAML.load(open(users_file).read)
125
+ end
126
+
127
+ def load_user
128
+ @user = nil
129
+ if current = @req.cookies['auth']
130
+ email = decode(current)
131
+ @user = users[email]
132
+ @resp.delete_cookie('auth', :path => "/") unless @user
133
+ end
134
+ end
135
+
75
136
  # Rack call interface
76
137
  def call(env)
77
- req = Rack::Request.new(env)
138
+ @req = Rack::Request.new(env)
139
+ @resp = Rack::Response.new
140
+ load_user
78
141
 
79
142
  # Route the request
80
- action, page_name, page = route(req)
143
+ action, page_name, @page = route
81
144
 
82
145
  # Send proper mime types for browsers that claim to accept it
146
+ @resp["Content-Type"] =
83
147
  if env['HTTP_ACCEPT'].include? "application/xhtml+xml"
84
- html_type = "application/xhtml+xml"
148
+ "application/xhtml+xml"
85
149
  else
86
- html_type = "text/html"
150
+ "text/html"
87
151
  end
88
- # html_type = "text/html"
89
152
 
90
153
  case action
91
- when :haxe
92
- [200, {"Content-Type"=>"application/x-shockwave-flash"}, [page]]
93
154
  when :not_found
94
- [404, {"Content-Type"=>html_type}, [Milk::Page.find('NotFound').view]]
155
+ @resp.status = 404
156
+ @resp.write Milk::Page.find('NotFound').view
95
157
  when :view
96
- [200, {"Content-Type"=>html_type}, [page.view]]
158
+ @resp.write @page.view
97
159
  when :edit
98
- [200, {"Content-Type"=>html_type}, [page.edit]]
160
+ @resp.write @page.edit
99
161
  when :save
100
- [200, {"Content-Type"=>html_type}, [page.save]]
162
+ @resp.write @page.save
101
163
  when :preview
102
- [200, {"Content-Type"=>html_type}, [page.preview]]
164
+ @resp.write @page.preview
165
+ when :login_form
166
+ filename = FIELDS_DIR + "/login.haml"
167
+ @resp.write(::Haml::Engine.new(File.read(filename), :filename => filename).render(self))
168
+ when :login
169
+ login
170
+ when :logout
171
+ logout
172
+ when :access_denied
173
+ @resp.staus = 403
174
+ @resp.write "Access Denied"
103
175
  else
104
- [500, {"Content-Type"=>html_type}, [action.to_s]]
176
+ @resp.status = 500
177
+ @resp.write action.to_s
105
178
  end
179
+ @resp.finish
106
180
  end
107
181
  end
108
182
 
@@ -0,0 +1,79 @@
1
+ !!! xml
2
+ !!! 1.1
3
+ %html{:xmlns =>"http://www.w3.org/1999/xhtml"}
4
+ %head
5
+ %title Please Login
6
+ %style{:type=>"text/css"}
7
+ :sass
8
+ !width = 400
9
+ !height = 150
10
+ table, #shadow, .ui-widget-shadow
11
+ :width = !width + "px"
12
+ :height = !height + "px"
13
+ table, #shadow
14
+ :position absolute
15
+ :top 50%
16
+ :left 50%
17
+ :margin
18
+ :top = (-!height/2)+"px"
19
+ :left = (-!width/2)+"px"
20
+ #flash
21
+ :padding 0pt 0.7em
22
+ span
23
+ :float left
24
+ :margin-right 0.3em
25
+ button
26
+ :cursor pointer
27
+ :line-height 1em
28
+ :padding 2px 5px 2px 2px
29
+ .ui-icon
30
+ :float left
31
+ :line-height 1em
32
+
33
+ %link{ :rel => "shortcut icon", :href => "/favicon.ico", :type => "image/x-icon"}/
34
+ %link{ :href => "http://static.creationix.com/skins/ui-lightness/jquery-ui-1.7.1.custom.css", :media => "screen", :rel => "stylesheet", :type => "text/css" }/
35
+ %link{ :href => "/style/style.css", :media => "screen", :rel => "stylesheet", :type => "text/css" }/
36
+ %script{:src=>"http://static.creationix.com/scripts/jquery-1.3.2.min.js", :type=>"text/javascript"}
37
+ %script{:src=>"http://static.creationix.com/scripts/jquery.json-1.3.min.js", :type=>"text/javascript"}
38
+ %script{:src=>"http://static.creationix.com/scripts/jquery-ui-1.7.1.custom.min.js", :type=>"text/javascript"}
39
+ %body
40
+ - if f = flash
41
+ #flash{:class => "ui-state-error ui-corner-all"}
42
+ %p
43
+ %span{:class => "ui-icon ui-icon-alert"}
44
+ %strong Alert:
45
+ &= f
46
+ %form{:action => "/login", :method=>"post"}
47
+ %input{:type=>"hidden", :name => "dest", :value => @req.path_info}
48
+ #shadow
49
+ .ui-widget-shadow
50
+ %table{:class => "ui-widget ui-widget-content ui-corner-all"}
51
+ %thead
52
+ %tr
53
+ %th{:colspan=>2, :class=>"ui-widget-header ui-corner-all"}
54
+ &= "Please Login to edit '#{@page.pagename}'"
55
+ %tr
56
+ %th Email
57
+ %td
58
+ %input{:name => "email"}
59
+ %tr
60
+ %th Password
61
+ %td
62
+ %input{:type=>"password", :name => "password"}
63
+ %tr
64
+ %th
65
+ %td
66
+ %button{:type =>"submit", :title=>'Login to the backend to edit this page.'}
67
+ %span{:class=>'ui-icon ui-icon-unlocked'}
68
+ Login
69
+ :javascript
70
+ $(function() {
71
+ $("button")
72
+ .addClass("ui-state-default ui-corner-all")
73
+ .hover(
74
+ function() { $(this).addClass('ui-state-hover'); },
75
+ function() { $(this).removeClass('ui-state-hover'); }
76
+ );
77
+ });
78
+
79
+
@@ -130,6 +130,9 @@
130
130
  %button#cancel_button.toolitem{:title=>'Cancel changes and go to live page.'}
131
131
  %span{:class=>'ui-icon ui-icon-cancel'}
132
132
  Cancel
133
+ %button#logout_button.toolitem{:title=>'Cancel changes and logout and go to live page.'}
134
+ %span{:class=>'ui-icon ui-icon-circle-close'}
135
+ Logout
133
136
  #preview
134
137
  = preview
135
138
  #divider
@@ -244,6 +247,9 @@
244
247
  $("#cancel_button").click(function(){
245
248
  window.location = $("form")[0].action;
246
249
  });
250
+ $("#logout_button").click(function(){
251
+ window.location = "/logout?dest="+$("form")[0].action;
252
+ });
247
253
 
248
254
  $(".component").click(function(evt){
249
255
  evt.stopPropagation();
@@ -1,23 +1,22 @@
1
- require 'rake/gempackagetask'
2
- spec = Gem::Specification.new do |s|
1
+ Gem::Specification.new do |s|
3
2
  s.rubyforge_project = "milk"
4
3
  s.name = "milk"
5
4
  s.summary = "Milk is a rack based content management system built for ease of use and simplicity. Milk tastes great with and without cookies."
6
- s.description= File.read(File.join(File.dirname(__FILE__), 'README'))
5
+ s.description= "Milk is a rack based cms system built for ease of use and simplicity. Milk
6
+ tastes great with and without cookies. The public facing aspect is static html
7
+ files, and the admin side is super easy to use."
7
8
  s.requirements << 'none'
8
- s.version = "0.0.4"
9
+ s.version = "0.0.5"
9
10
  s.author = "Tim Caswell"
10
11
  s.email = "tim@creationix.com"
11
12
  s.homepage = "http://milk.rubyforge.org"
12
13
  s.platform = Gem::Platform::RUBY
13
14
  s.required_ruby_version = '>=1.9'
14
15
  s.files = Dir['**/**']
15
- s.executables = [ 'milk' ]
16
16
  s.add_dependency('rack', '>= 1.0.0')
17
17
  s.add_dependency('maruku', '>= 0.6.0')
18
18
  s.add_dependency('haml', '>= 2.0.9')
19
19
  s.test_files = Dir["test/test*.rb"]
20
- s.has_rdoc = false
20
+ s.has_rdoc = true
21
21
  end
22
- Rake::GemPackageTask.new(spec).define
23
22
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: milk
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
  - Tim Caswell
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-06-11 00:00:00 -05:00
12
+ date: 2009-06-16 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -44,8 +44,8 @@ dependencies:
44
44
  version:
45
45
  description: Milk is a rack based cms system built for ease of use and simplicity. Milk tastes great with and without cookies. The public facing aspect is static html files, and the admin side is super easy to use.
46
46
  email: tim@creationix.com
47
- executables:
48
- - milk
47
+ executables: []
48
+
49
49
  extensions: []
50
50
 
51
51
  extra_rdoc_files: []
@@ -62,6 +62,7 @@ files:
62
62
  - lib/milk/fields/page_chooser.haml
63
63
  - lib/milk/fields/text_field.rb
64
64
  - lib/milk/fields/image_chooser.haml
65
+ - lib/milk/fields/login.haml
65
66
  - lib/milk/fields/text_field.haml
66
67
  - lib/milk/fields/sprite_chooser.rb
67
68
  - lib/milk/fields/xhtml.haml
@@ -82,15 +83,8 @@ files:
82
83
  - lib/milk/templates/rackup
83
84
  - lib/milk.rb
84
85
  - LICENSE
85
- - README
86
- - pkg
87
- - pkg/milk-0.0.3.gem
88
- - Rakefile
89
- - Milk.tmproj
90
- - INSTALL
91
- - bin
92
- - bin/milk
93
- has_rdoc: false
86
+ - milk.gemspec
87
+ has_rdoc: true
94
88
  homepage: http://milk.rubyforge.org
95
89
  post_install_message:
96
90
  rdoc_options: []
data/INSTALL DELETED
@@ -1,8 +0,0 @@
1
- To install:
2
-
3
- rake gem
4
-
5
- sudo gem install pkg/milk-0.0.1.gem
6
-
7
- This should install milk, all it's dependencies and the `milk` command line tool
8
- to generate new sites.
@@ -1,65 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
- <plist version="1.0">
4
- <dict>
5
- <key>currentDocument</key>
6
- <string>lib/milk/page.rb</string>
7
- <key>documents</key>
8
- <array>
9
- <dict>
10
- <key>expanded</key>
11
- <true/>
12
- <key>name</key>
13
- <string>Milk</string>
14
- <key>regexFolderFilter</key>
15
- <string>!.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$</string>
16
- <key>selected</key>
17
- <true/>
18
- <key>sourceDirectory</key>
19
- <string></string>
20
- </dict>
21
- </array>
22
- <key>fileHierarchyDrawerWidth</key>
23
- <integer>200</integer>
24
- <key>metaData</key>
25
- <dict>
26
- <key>lib/milk.rb</key>
27
- <dict>
28
- <key>caret</key>
29
- <dict>
30
- <key>column</key>
31
- <integer>12</integer>
32
- <key>line</key>
33
- <integer>19</integer>
34
- </dict>
35
- <key>firstVisibleColumn</key>
36
- <integer>0</integer>
37
- <key>firstVisibleLine</key>
38
- <integer>10</integer>
39
- </dict>
40
- <key>lib/milk/page.rb</key>
41
- <dict>
42
- <key>caret</key>
43
- <dict>
44
- <key>column</key>
45
- <integer>2</integer>
46
- <key>line</key>
47
- <integer>6</integer>
48
- </dict>
49
- <key>firstVisibleColumn</key>
50
- <integer>0</integer>
51
- <key>firstVisibleLine</key>
52
- <integer>0</integer>
53
- </dict>
54
- </dict>
55
- <key>openDocuments</key>
56
- <array>
57
- <string>lib/milk.rb</string>
58
- <string>lib/milk/page.rb</string>
59
- </array>
60
- <key>showFileHierarchyDrawer</key>
61
- <true/>
62
- <key>windowFrame</key>
63
- <string>{{281, 240}, {840, 469}}</string>
64
- </dict>
65
- </plist>
data/README DELETED
@@ -1,3 +0,0 @@
1
- Milk is a rack based cms system built for ease of use and simplicity. Milk
2
- tastes great with and without cookies. The public facing aspect is static html
3
- files, and the admin side is super easy to use.
data/bin/milk DELETED
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'milk'
4
-
5
- p MILK
Binary file