picnic 0.7.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +10 -0
- data/Manifest.txt +30 -13
- data/Rakefile +2 -0
- data/lib/picnic.rb +5 -120
- data/lib/picnic/authentication.rb +40 -4
- data/lib/picnic/cli.rb +86 -43
- data/lib/picnic/conf.rb +45 -43
- data/lib/picnic/logger.rb +41 -0
- data/lib/picnic/server.rb +99 -0
- data/lib/picnic/version.rb +2 -2
- data/picnic.gemspec +44 -0
- data/vendor/{camping-1.5.180 → camping-2.0.20090212}/CHANGELOG +17 -10
- data/vendor/{camping-1.5.180 → camping-2.0.20090212}/COPYING +0 -0
- data/vendor/{camping-1.5.180 → camping-2.0.20090212}/README +2 -2
- data/vendor/{camping-1.5.180 → camping-2.0.20090212}/Rakefile +62 -5
- data/vendor/camping-2.0.20090212/bin/camping +99 -0
- data/vendor/camping-2.0.20090212/doc/camping.1.gz +0 -0
- data/vendor/camping-2.0.20090212/examples/README +5 -0
- data/vendor/camping-2.0.20090212/examples/blog.rb +375 -0
- data/vendor/camping-2.0.20090212/examples/campsh.rb +629 -0
- data/vendor/camping-2.0.20090212/examples/tepee.rb +242 -0
- data/vendor/camping-2.0.20090212/extras/Camping.gif +0 -0
- data/vendor/camping-2.0.20090212/extras/flipbook_rdoc.rb +491 -0
- data/vendor/camping-2.0.20090212/extras/permalink.gif +0 -0
- data/vendor/{camping-1.5.180 → camping-2.0.20090212}/lib/camping-unabridged.rb +168 -294
- data/vendor/camping-2.0.20090212/lib/camping.rb +54 -0
- data/vendor/{camping-1.5.180/lib/camping/db.rb → camping-2.0.20090212/lib/camping/ar.rb} +4 -4
- data/vendor/{camping-1.5.180/lib/camping → camping-2.0.20090212/lib/camping/ar}/session.rb +23 -14
- data/vendor/camping-2.0.20090212/lib/camping/mab.rb +26 -0
- data/vendor/camping-2.0.20090212/lib/camping/reloader.rb +163 -0
- data/vendor/camping-2.0.20090212/lib/camping/server.rb +158 -0
- data/vendor/camping-2.0.20090212/lib/camping/session.rb +74 -0
- data/vendor/camping-2.0.20090212/setup.rb +1551 -0
- data/vendor/camping-2.0.20090212/test/apps/env_debug.rb +65 -0
- data/vendor/camping-2.0.20090212/test/apps/forms.rb +95 -0
- data/vendor/camping-2.0.20090212/test/apps/misc.rb +86 -0
- data/vendor/camping-2.0.20090212/test/apps/sessions.rb +38 -0
- data/vendor/camping-2.0.20090212/test/test_camping.rb +54 -0
- metadata +43 -16
- data/lib/picnic/postambles.rb +0 -292
- data/lib/picnic/utils.rb +0 -36
- data/vendor/camping-1.5.180/lib/camping.rb +0 -57
- data/vendor/camping-1.5.180/lib/camping/fastcgi.rb +0 -244
- data/vendor/camping-1.5.180/lib/camping/reloader.rb +0 -163
- data/vendor/camping-1.5.180/lib/camping/webrick.rb +0 -65
@@ -0,0 +1,99 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
trap("INT") { exit }
|
4
|
+
require 'optparse'
|
5
|
+
require 'ostruct'
|
6
|
+
require 'stringio'
|
7
|
+
require 'yaml'
|
8
|
+
|
9
|
+
$:.unshift File.dirname(__FILE__) + "/../lib"
|
10
|
+
require 'camping'
|
11
|
+
require 'camping/server'
|
12
|
+
|
13
|
+
conf = OpenStruct.new(:host => '0.0.0.0', :port => 3301)
|
14
|
+
|
15
|
+
# Setup paths
|
16
|
+
if home = ENV['HOME'] # POSIX
|
17
|
+
db_path = File.join(home, '.camping.db')
|
18
|
+
rc_path = File.join(home, '.campingrc')
|
19
|
+
elsif home = ENV['APPDATA'] # MSWIN
|
20
|
+
db_path = File.join(home, 'Camping.db')
|
21
|
+
rc_path = File.join(home, 'Campingrc')
|
22
|
+
end
|
23
|
+
|
24
|
+
# Parse options
|
25
|
+
opts = OptionParser.new do |opts|
|
26
|
+
opts.banner = "Usage: camping app1.rb, app2.rb..."
|
27
|
+
opts.define_head "#{File.basename($0)}, the microframework ON-button for ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
|
28
|
+
opts.separator ""
|
29
|
+
opts.separator "Specific options:"
|
30
|
+
|
31
|
+
opts.on("-h", "--host HOSTNAME", "Host for web server to bind to (default is all IPs)") { |conf.host| }
|
32
|
+
opts.on("-p", "--port NUM", "Port for web server (defaults to #{conf.port})") { |conf.port| }
|
33
|
+
opts.on("-d", "--database FILE", "SQLite3 database path (defaults to #{db_path ? db_path : '<none>'})") { |db_path| conf.database = {:adapter => 'sqlite3', :database => db_path} }
|
34
|
+
opts.on("-l", "--log FILE", "Start a database log ('-' for STDOUT)") { |conf.log| }
|
35
|
+
opts.on("-C", "--console", "Run in console mode with IRB") { conf.server = "console" }
|
36
|
+
server_list = ["mongrel", "webrick", "console"]
|
37
|
+
opts.on("-s", "--server NAME", server_list, "Server to force (#{server_list.join(', ')})") { |conf.server| }
|
38
|
+
|
39
|
+
opts.separator ""
|
40
|
+
opts.separator "Common options:"
|
41
|
+
|
42
|
+
# No argument, shows at tail. This will print an options summary.
|
43
|
+
# Try it and see!
|
44
|
+
opts.on_tail("-?", "--help", "Show this message") do
|
45
|
+
puts opts
|
46
|
+
exit
|
47
|
+
end
|
48
|
+
|
49
|
+
# Another typical switch to print the version.
|
50
|
+
opts.on_tail("-v", "--version", "Show version") do
|
51
|
+
class << Gem; attr_accessor :loaded_specs; end
|
52
|
+
puts Gem.loaded_specs['camping'].version
|
53
|
+
exit
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
begin
|
58
|
+
opts.parse! ARGV
|
59
|
+
rescue OptionParser::ParseError => ex
|
60
|
+
STDERR.puts "!! #{ex.message}"
|
61
|
+
puts "** use `#{File.basename($0)} --help` for more details..."
|
62
|
+
exit 1
|
63
|
+
end
|
64
|
+
|
65
|
+
if ARGV.length < 1
|
66
|
+
puts opts
|
67
|
+
exit 1
|
68
|
+
end
|
69
|
+
|
70
|
+
# Load configuration if any
|
71
|
+
if rc_path and File.exists?( rc_path )
|
72
|
+
YAML.load_file(rc_path).each do |k,v|
|
73
|
+
conf.send("#{k}=", v) unless conf.send(k)
|
74
|
+
end
|
75
|
+
puts "** conf file #{rc_path} loaded"
|
76
|
+
end
|
77
|
+
|
78
|
+
# Default db
|
79
|
+
if conf.database.nil? and db_path
|
80
|
+
conf.database = {:adapter => 'sqlite3', :database => db_path} if db_path
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
# get a copy of the paths to pass to the server
|
85
|
+
paths = ARGV.dup
|
86
|
+
|
87
|
+
# Check that mongrel exists
|
88
|
+
if conf.server.nil? || conf.server == "mongrel"
|
89
|
+
begin
|
90
|
+
require 'mongrel'
|
91
|
+
conf.server = "mongrel"
|
92
|
+
rescue LoadError
|
93
|
+
puts "!! could not load mongrel. Falling back to webrick."
|
94
|
+
conf.server = "webrick"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
server = Camping::Server::Base.new(conf, paths)
|
99
|
+
server.start
|
Binary file
|
@@ -0,0 +1,375 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
4
|
+
require 'camping'
|
5
|
+
require 'camping/ar'
|
6
|
+
require 'camping/session'
|
7
|
+
require 'redcloth'
|
8
|
+
|
9
|
+
Camping.goes :Blog
|
10
|
+
|
11
|
+
module Blog
|
12
|
+
include Camping::Session
|
13
|
+
|
14
|
+
module Models
|
15
|
+
class Post < Base
|
16
|
+
belongs_to :user
|
17
|
+
|
18
|
+
before_save do |record|
|
19
|
+
cloth = RedCloth.new(record.body)
|
20
|
+
cloth.hard_breaks = false
|
21
|
+
record.html_body = cloth.to_html
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Comment < Base; belongs_to :user; end
|
26
|
+
class User < Base; end
|
27
|
+
|
28
|
+
class BasicFields < V 1.1
|
29
|
+
def self.up
|
30
|
+
create_table :blog_posts, :force => true do |t|
|
31
|
+
t.integer :user_id, :null => false
|
32
|
+
t.string :title, :limit => 255
|
33
|
+
t.text :body, :html_body
|
34
|
+
t.timestamps
|
35
|
+
end
|
36
|
+
create_table :blog_users, :force => true do |t|
|
37
|
+
t.string :username, :password
|
38
|
+
end
|
39
|
+
create_table :blog_comments, :force => true do |t|
|
40
|
+
t.integer :post_id, :null => false
|
41
|
+
t.string :username
|
42
|
+
t.text :body, :html_body
|
43
|
+
t.timestamps
|
44
|
+
end
|
45
|
+
User.create :username => 'admin', :password => 'camping'
|
46
|
+
end
|
47
|
+
def self.down
|
48
|
+
drop_table :blog_posts
|
49
|
+
drop_table :blog_users
|
50
|
+
drop_table :blog_comments
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
module Controllers
|
56
|
+
class Index
|
57
|
+
def get
|
58
|
+
@posts = Post.all(:order => 'updated_at DESC')
|
59
|
+
render :index
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class PostNew
|
64
|
+
def get
|
65
|
+
require_login!
|
66
|
+
@post = Post.new
|
67
|
+
render :add
|
68
|
+
end
|
69
|
+
|
70
|
+
def post
|
71
|
+
require_login!
|
72
|
+
post = Post.create(:title => input.post_title, :body => input.post_body,
|
73
|
+
:user_id => @state.user_id)
|
74
|
+
redirect PostN, post
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class PostN
|
79
|
+
def get(post_id)
|
80
|
+
@post = Post.find(post_id)
|
81
|
+
render :view
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class Edit < R '/post/(\d+)/edit'
|
86
|
+
def get(post_id)
|
87
|
+
require_login!
|
88
|
+
@post = Post.find(post_id)
|
89
|
+
render :edit
|
90
|
+
end
|
91
|
+
|
92
|
+
def post(post_id)
|
93
|
+
require_login!
|
94
|
+
@post = Post.find(post_id)
|
95
|
+
@post.update_attributes :title => input.post_title, :body => input.post_body
|
96
|
+
redirect PostN, @post
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
class Login
|
101
|
+
def get
|
102
|
+
@to = input.to
|
103
|
+
render :login
|
104
|
+
end
|
105
|
+
|
106
|
+
def post
|
107
|
+
@user = User.find_by_username_and_password(input.username, input.password)
|
108
|
+
@to = input.to
|
109
|
+
|
110
|
+
if @user
|
111
|
+
@state.user_id = @user.id
|
112
|
+
if @to
|
113
|
+
redirect @to
|
114
|
+
else
|
115
|
+
redirect R(Index)
|
116
|
+
end
|
117
|
+
else
|
118
|
+
@info = 'Wrong username or password'
|
119
|
+
end
|
120
|
+
render :login
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class Logout
|
125
|
+
def get
|
126
|
+
@state.user_id = nil
|
127
|
+
redirect Index
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
class Style < R '/styles\.css'
|
132
|
+
STYLE = File.read(__FILE__).gsub(/.*__END__/m, '')
|
133
|
+
|
134
|
+
def get
|
135
|
+
@headers['Content-Type'] = 'text/css; charset=utf-8'
|
136
|
+
STYLE
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
module Helpers
|
142
|
+
def logged_in?
|
143
|
+
!!@state.user_id
|
144
|
+
end
|
145
|
+
|
146
|
+
def require_login!
|
147
|
+
unless logged_in?
|
148
|
+
redirect X::Login, :to => @env.REQUEST_URI
|
149
|
+
throw :halt
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
module Views
|
155
|
+
def layout
|
156
|
+
html do
|
157
|
+
head do
|
158
|
+
title 'My Blog'
|
159
|
+
link :rel => 'stylesheet', :type => 'text/css',
|
160
|
+
:href => '/styles.css', :media => 'screen'
|
161
|
+
end
|
162
|
+
body do
|
163
|
+
h1 { a 'My Blog', :href => R(Index) }
|
164
|
+
|
165
|
+
div.wrapper! do
|
166
|
+
text yield
|
167
|
+
end
|
168
|
+
|
169
|
+
hr
|
170
|
+
|
171
|
+
p.footer! do
|
172
|
+
if logged_in?
|
173
|
+
_admin_menu
|
174
|
+
else
|
175
|
+
a 'Login', :href => R(Login, :to => @env.REQUEST_URI)
|
176
|
+
text ' to the adminpanel'
|
177
|
+
end
|
178
|
+
text ' – Powered by '
|
179
|
+
a 'Camping', :href => 'http://code.whytheluckystiff.net/camping'
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def index
|
186
|
+
if @posts.empty?
|
187
|
+
h2 'No posts'
|
188
|
+
p do
|
189
|
+
text 'Could not find any posts. Feel free to '
|
190
|
+
a 'add one', :href => R(PostNew)
|
191
|
+
text ' yourself'
|
192
|
+
end
|
193
|
+
else
|
194
|
+
@posts.each do |post|
|
195
|
+
_post(post)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def login
|
201
|
+
h2 'Login'
|
202
|
+
p.info @info if @info
|
203
|
+
|
204
|
+
form :action => R(Login), :method => 'post' do
|
205
|
+
input :name => 'to', :type => 'hidden', :value => @to if @to
|
206
|
+
|
207
|
+
label 'Username', :for => 'username'
|
208
|
+
input :name => 'username', :id => 'username', :type => 'text'
|
209
|
+
|
210
|
+
label 'Password', :for => 'password'
|
211
|
+
input :name => 'password', :id => 'password', :type => 'password'
|
212
|
+
|
213
|
+
input :type => 'submit', :class => 'submit', :value => 'Login'
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def add
|
218
|
+
_form(@post, :action => R(PostNew))
|
219
|
+
end
|
220
|
+
|
221
|
+
def edit
|
222
|
+
_form(@post, :action => R(Edit, @post))
|
223
|
+
end
|
224
|
+
|
225
|
+
def view
|
226
|
+
_post(@post)
|
227
|
+
end
|
228
|
+
|
229
|
+
# partials
|
230
|
+
def _admin_menu
|
231
|
+
text [['Log out', R(Logout)], ['New', R(PostNew)]].map { |name, to|
|
232
|
+
capture { a name, :href => to}
|
233
|
+
}.join(' – ')
|
234
|
+
end
|
235
|
+
|
236
|
+
def _post(post)
|
237
|
+
h2 post.title
|
238
|
+
p.info do
|
239
|
+
text "Written by <strong>#{post.user.username}</strong> "
|
240
|
+
text post.updated_at.strftime('%B %M, %Y @ %H:%M ')
|
241
|
+
_post_menu(post)
|
242
|
+
end
|
243
|
+
text post.html_body
|
244
|
+
end
|
245
|
+
|
246
|
+
def _post_menu(post)
|
247
|
+
text '('
|
248
|
+
a 'view', :href => R(PostN, post)
|
249
|
+
if logged_in?
|
250
|
+
text ', '
|
251
|
+
a 'edit', :href => R(Edit, post)
|
252
|
+
end
|
253
|
+
text ')'
|
254
|
+
end
|
255
|
+
|
256
|
+
def _form(post, opts)
|
257
|
+
form({:method => 'post'}.merge(opts)) do
|
258
|
+
label 'Title', :for => 'post_title'
|
259
|
+
input :name => 'post_title', :id => 'post_title', :type => 'text',
|
260
|
+
:value => post.title
|
261
|
+
|
262
|
+
label 'Body', :for => 'post_body'
|
263
|
+
textarea post.body, :name => 'post_body', :id => 'post_body'
|
264
|
+
|
265
|
+
input :type => 'hidden', :name => 'post_id', :value => post.id
|
266
|
+
input :type => 'submit', :class => 'submit', :value => 'Submit'
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
def Blog.create
|
273
|
+
Blog::Models.create_schema :assume => (Blog::Models::Post.table_exists? ? 1.0 : 0.0)
|
274
|
+
end
|
275
|
+
|
276
|
+
__END__
|
277
|
+
* {
|
278
|
+
margin: 0;
|
279
|
+
padding: 0;
|
280
|
+
}
|
281
|
+
|
282
|
+
body {
|
283
|
+
font: normal 14px Arial, 'Bitstream Vera Sans', Helvetica, sans-serif;
|
284
|
+
line-height: 1.5;
|
285
|
+
}
|
286
|
+
|
287
|
+
h1, h2, h3, h4 {
|
288
|
+
font-family: Georgia, serif;
|
289
|
+
font-weight: normal;
|
290
|
+
}
|
291
|
+
|
292
|
+
h1 {
|
293
|
+
background-color: #EEE;
|
294
|
+
border-bottom: 5px solid #6F812D;
|
295
|
+
outline: 5px solid #9CB441;
|
296
|
+
font-weight: normal;
|
297
|
+
font-size: 3em;
|
298
|
+
padding: 0.5em 0;
|
299
|
+
text-align: center;
|
300
|
+
}
|
301
|
+
|
302
|
+
h1 a { color: #143D55; text-decoration: none }
|
303
|
+
h1 a:hover { color: #143D55; text-decoration: underline }
|
304
|
+
|
305
|
+
h2 {
|
306
|
+
font-size: 2em;
|
307
|
+
color: #287AA9;
|
308
|
+
}
|
309
|
+
|
310
|
+
#wrapper {
|
311
|
+
margin: 3em auto;
|
312
|
+
width: 700px;
|
313
|
+
}
|
314
|
+
|
315
|
+
p {
|
316
|
+
margin-bottom: 1em;
|
317
|
+
}
|
318
|
+
|
319
|
+
p.info, p#footer {
|
320
|
+
color: #999;
|
321
|
+
margin-left: 1em;
|
322
|
+
}
|
323
|
+
|
324
|
+
p.info a, p#footer a {
|
325
|
+
color: #999;
|
326
|
+
}
|
327
|
+
|
328
|
+
p.info a:hover, p#footer a:hover {
|
329
|
+
text-decoration: none;
|
330
|
+
}
|
331
|
+
|
332
|
+
a {
|
333
|
+
color: #6F812D;
|
334
|
+
}
|
335
|
+
|
336
|
+
a:hover {
|
337
|
+
color: #9CB441;
|
338
|
+
}
|
339
|
+
|
340
|
+
hr {
|
341
|
+
border-width: 5px 0;
|
342
|
+
border-style: solid;
|
343
|
+
border-color: #9CB441;
|
344
|
+
border-bottom-color: #6F812D;
|
345
|
+
height: 0;
|
346
|
+
}
|
347
|
+
|
348
|
+
p#footer {
|
349
|
+
font-size: 0.9em;
|
350
|
+
margin: 0;
|
351
|
+
padding: 1em;
|
352
|
+
text-align: center;
|
353
|
+
}
|
354
|
+
|
355
|
+
label {
|
356
|
+
display: inline-block;
|
357
|
+
width: 100%;
|
358
|
+
}
|
359
|
+
|
360
|
+
input, textarea {
|
361
|
+
margin-bottom: 1em;
|
362
|
+
width: 200px;
|
363
|
+
}
|
364
|
+
|
365
|
+
input.submit {
|
366
|
+
float: left;
|
367
|
+
width: auto;
|
368
|
+
}
|
369
|
+
|
370
|
+
textarea {
|
371
|
+
font: normal 14px Arial, 'Bitstream Vera Sans', Helvetica, sans-serif;
|
372
|
+
height: 300px;
|
373
|
+
width: 400px;
|
374
|
+
}
|
375
|
+
|