sinatra-s3 0.98

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.
Files changed (75) hide show
  1. data/README +23 -0
  2. data/Rakefile +51 -0
  3. data/bin/sinatra-s3 +30 -0
  4. data/db/migrate/001_create_bits.rb +28 -0
  5. data/db/migrate/002_create_users.rb +24 -0
  6. data/db/migrate/003_create_bits_users.rb +16 -0
  7. data/db/migrate/004_create_torrents.rb +22 -0
  8. data/db/migrate/005_create_torrent_peers.rb +26 -0
  9. data/examples/README +9 -0
  10. data/examples/wiki.rb +199 -0
  11. data/examples/wiki.ru +5 -0
  12. data/examples/wikicloth/MIT-LICENSE +20 -0
  13. data/examples/wikicloth/README +81 -0
  14. data/examples/wikicloth/Rakefile +23 -0
  15. data/examples/wikicloth/init.rb +1 -0
  16. data/examples/wikicloth/install.rb +0 -0
  17. data/examples/wikicloth/lib/core_ext.rb +43 -0
  18. data/examples/wikicloth/lib/wiki_buffer/html_element.rb +237 -0
  19. data/examples/wikicloth/lib/wiki_buffer/link.rb +70 -0
  20. data/examples/wikicloth/lib/wiki_buffer/table.rb +159 -0
  21. data/examples/wikicloth/lib/wiki_buffer/var.rb +77 -0
  22. data/examples/wikicloth/lib/wiki_buffer.rb +279 -0
  23. data/examples/wikicloth/lib/wiki_cloth.rb +61 -0
  24. data/examples/wikicloth/lib/wiki_link_handler.rb +138 -0
  25. data/examples/wikicloth/lib/wikicloth.rb +5 -0
  26. data/examples/wikicloth/run_tests.rb +48 -0
  27. data/examples/wikicloth/sample_documents/air_force_one.wiki +170 -0
  28. data/examples/wikicloth/sample_documents/cheatsheet.wiki +205 -0
  29. data/examples/wikicloth/sample_documents/default.css +34 -0
  30. data/examples/wikicloth/sample_documents/elements.wiki +7 -0
  31. data/examples/wikicloth/sample_documents/george_washington.wiki +526 -0
  32. data/examples/wikicloth/sample_documents/images.wiki +15 -0
  33. data/examples/wikicloth/sample_documents/lists.wiki +421 -0
  34. data/examples/wikicloth/sample_documents/pipe_trick.wiki +68 -0
  35. data/examples/wikicloth/sample_documents/random.wiki +55 -0
  36. data/examples/wikicloth/sample_documents/tv.wiki +312 -0
  37. data/examples/wikicloth/sample_documents/wiki.png +0 -0
  38. data/examples/wikicloth/sample_documents/wiki_tables.wiki +410 -0
  39. data/examples/wikicloth/tasks/wikicloth_tasks.rake +0 -0
  40. data/examples/wikicloth/test/test_helper.rb +3 -0
  41. data/examples/wikicloth/test/wiki_cloth_test.rb +8 -0
  42. data/examples/wikicloth/uninstall.rb +0 -0
  43. data/examples/wikicloth/wikicloth-0.1.3.gem +0 -0
  44. data/examples/wikicloth/wikicloth.gemspec +69 -0
  45. data/lib/sinatra-s3/admin.rb +626 -0
  46. data/lib/sinatra-s3/base.rb +526 -0
  47. data/lib/sinatra-s3/errors.rb +51 -0
  48. data/lib/sinatra-s3/ext.rb +20 -0
  49. data/lib/sinatra-s3/helpers/acp.rb +100 -0
  50. data/lib/sinatra-s3/helpers/admin.rb +41 -0
  51. data/lib/sinatra-s3/helpers/tracker.rb +42 -0
  52. data/lib/sinatra-s3/helpers/versioning.rb +27 -0
  53. data/lib/sinatra-s3/helpers.rb +79 -0
  54. data/lib/sinatra-s3/models/bit.rb +180 -0
  55. data/lib/sinatra-s3/models/bucket.rb +81 -0
  56. data/lib/sinatra-s3/models/file_info.rb +3 -0
  57. data/lib/sinatra-s3/models/git_bucket.rb +3 -0
  58. data/lib/sinatra-s3/models/slot.rb +47 -0
  59. data/lib/sinatra-s3/models/torrent.rb +6 -0
  60. data/lib/sinatra-s3/models/torrent_peer.rb +5 -0
  61. data/lib/sinatra-s3/models/user.rb +35 -0
  62. data/lib/sinatra-s3/s3.rb +57 -0
  63. data/lib/sinatra-s3/tasks.rb +62 -0
  64. data/lib/sinatra-s3/tracker.rb +134 -0
  65. data/lib/sinatra-s3.rb +1 -0
  66. data/public/css/control.css +225 -0
  67. data/public/css/wiki.css +47 -0
  68. data/public/images/external-link.gif +0 -0
  69. data/public/js/prototype.js +2539 -0
  70. data/public/js/upload_status.js +117 -0
  71. data/public/test.html +8 -0
  72. data/s3.yml.example +17 -0
  73. data/test/s3api_test.rb +121 -0
  74. data/test/test_helper.rb +25 -0
  75. metadata +156 -0
@@ -0,0 +1,626 @@
1
+ require 'aws/s3'
2
+
3
+ module S3
4
+
5
+ class Admin < Sinatra::Base
6
+
7
+ helpers do
8
+ include S3::Helpers
9
+ include S3::AdminHelpers
10
+ end
11
+
12
+ set :sessions, :on
13
+ enable :inline_templates
14
+
15
+ before do
16
+ ActiveRecord::Base.verify_active_connections!
17
+ end
18
+
19
+ get '/control/?' do
20
+ login_required
21
+ redirect '/control/buckets'
22
+ end
23
+
24
+ get %r{^/control/s/(.*)} do
25
+ open(File.join(PUBLIC_PATH, params[:captures].first))
26
+ end
27
+
28
+ get '/control/login' do
29
+ r :login, "Login"
30
+ end
31
+
32
+ post '/control/login' do
33
+ @user = User.find_by_login params[:login]
34
+ if @user
35
+ if @user.password == hmac_sha1( params[:password], @user.secret )
36
+ session[:user_id] = @user.id
37
+ redirect '/control/buckets'
38
+ else
39
+ @user.errors.add(:password, 'is incorrect')
40
+ end
41
+ else
42
+ @user = User.new
43
+ @user.errors.add(:login, 'not found')
44
+ end
45
+ login_view
46
+ end
47
+
48
+ get '/control/logout' do
49
+ session[:user_id] = nil
50
+ redirect '/control'
51
+ end
52
+
53
+ get '/control/buckets/?' do
54
+ login_required
55
+ load_buckets
56
+ r :buckets, "Buckets"
57
+ end
58
+
59
+ post '/control/buckets/?' do
60
+ login_required
61
+ begin
62
+ Bucket.find_root(params['bucket']['name'])
63
+ load_buckets
64
+ @bucket.errors.add_to_base("A bucket named `#{@input['bucket']['name']}' already exists.")
65
+ rescue NoSuchBucket
66
+ bucket = Bucket.new(params['bucket'])
67
+ redirect '/control/buckets' if bucket.save()
68
+ load_buckets
69
+ @bucket.errors.add_to_base("Invalid bucket name.")
70
+ end
71
+ r :buckets, "Buckets"
72
+ end
73
+
74
+ get '/control/buckets/:bucket/?' do
75
+ login_required
76
+ @bucket = Bucket.find_root(params[:bucket])
77
+ only_can_read @bucket
78
+ @files = Slot.find :all, :conditions => ['deleted = 0 AND parent_id = ?', @bucket.id], :order => 'name'
79
+ r :files, "/#{@bucket.name}"
80
+ end
81
+
82
+ post '/control/buckets/:bucket/?' do
83
+ login_required
84
+ @bucket = Bucket.find_root(params[:bucket])
85
+ only_can_write @bucket
86
+
87
+ if params['upfile'].nil? || params['upfile'].instance_of?(String)
88
+ @files = Slot.find :all, :conditions => ['deleted = 0 AND parent_id = ?', @bucket.id], :order => 'name'
89
+ redirect "/control/buckets/#{params[:bucket]}"
90
+ end
91
+
92
+ tmpf = params['upfile'][:tempfile]
93
+ readlen, md5 = 0, MD5.new
94
+ while part = tmpf.read(BUFSIZE)
95
+ readlen += part.size
96
+ md5 << part
97
+ end
98
+
99
+ fileinfo = FileInfo.new
100
+ fileinfo.mime_type = params['upfile'][:type] || "binary/octet-stream"
101
+ fileinfo.size = readlen
102
+ fileinfo.md5 = md5.hexdigest
103
+ fileinfo.etag = '"' + md5.hexdigest + '"'
104
+
105
+ mdata = {}
106
+ if defined?(EXIFR) && fileinfo.mime_type =~ /jpg|jpeg/
107
+ photo_data = EXIFR::JPEG.new(tmpf.path).to_hash
108
+ photo_data.each_pair do |key,value|
109
+ tmp = key.to_s.gsub(/[^a-z0-9]+/i, '-').downcase.gsub(/-$/,'')
110
+ mdata[tmp] = value.to_s
111
+ end
112
+ end
113
+
114
+ params['fname'] = params['upfile'][:filename] if params['fname'].blank?
115
+ begin
116
+ slot = @bucket.find_slot(params['fname'])
117
+ if slot.versioning_enabled?
118
+ nslot = slot.clone()
119
+ slot.update_attributes(:deleted => true)
120
+ slot = nslot
121
+ end
122
+ fileinfo.path = slot.obj.path
123
+ file_path = File.join(STORAGE_PATH,fileinfo.path)
124
+ slot.update_attributes(:owner_id => @user.id, :meta => mdata, :obj => fileinfo, :size => fileinfo.size)
125
+ FileUtils.mv(tmpf.path, file_path,{ :force => true })
126
+ rescue NoSuchKey
127
+ fileinfo.path = File.join(params[:bucket], rand(10000).to_s(36) + '_' + File.basename(tmpf.path))
128
+ fileinfo.path.succ! while File.exists?(File.join(STORAGE_PATH, fileinfo.path))
129
+ file_path = File.join(STORAGE_PATH,fileinfo.path)
130
+ FileUtils.mkdir_p(File.dirname(file_path))
131
+ FileUtils.mv(tmpf.path, file_path)
132
+ slot = Slot.create(:name => params['fname'], :owner_id => @user.id, :meta => mdata, :obj => fileinfo, :size => fileinfo.size)
133
+ slot.grant(:access => params['facl'].to_i)
134
+ @bucket.add_child(slot)
135
+ end
136
+
137
+ if slot.versioning_enabled?
138
+ begin
139
+ slot.git_repository.add(File.basename(fileinfo.path))
140
+ slot.git_repository.commit("Added #{slot.name} to the Git repository.")
141
+ slot.git_update
142
+ slot.update_attributes(:version => slot.git_object.objectish)
143
+ rescue => err
144
+ puts "[#{Time.now}] GIT: #{err}"
145
+ end
146
+ end
147
+
148
+ redirect "/control/buckets/#{params[:bucket]}"
149
+ end
150
+
151
+ post '/control/buckets/:bucket/versioning/?' do
152
+ login_required
153
+ @bucket = Bucket.find_root(params[:bucket])
154
+ only_can_write @bucket
155
+ @bucket.git_init if defined?(Git)
156
+ redirect "/control/buckets/#{@bucket.name}"
157
+ end
158
+
159
+ get %r{^/control/changes/(.+?)/(.+)$} do
160
+ login_required
161
+ @bucket = Bucket.find_root params[:captures].first
162
+ @file = @bucket.find_slot(params[:captures].last)
163
+ only_owner_of @bucket
164
+ @versions = @bucket.git_repository.log.path(File.basename(@file.obj.path))
165
+ r :changes, "Commit Log", :popup
166
+ end
167
+
168
+ post '/control/delete/:bucket/?' do
169
+ login_required
170
+ @bucket = Bucket.find_root(params[:bucket])
171
+ only_owner_of @bucket
172
+ if Slot.count(:conditions => ['deleted = 0 AND parent_id = ?', @bucket.id]) > 0
173
+ # FIXME: error message, bucket is not empty
174
+ else
175
+ @bucket.remove_from_filesystem()
176
+ @bucket.destroy()
177
+ end
178
+ redirect "/control/buckets"
179
+ end
180
+
181
+ post %r{^/control/delete/(.+?)/(.+)$} do
182
+ login_required
183
+ @bucket = Bucket.find_root(params[:captures].first)
184
+ only_can_write @bucket
185
+ @slot = @bucket.find_slot(params[:captures].last)
186
+
187
+ if @slot.versioning_enabled?
188
+ @slot.git_repository.remove(File.basename(@slot.obj.path))
189
+ @slot.git_repository.commit("Removed #{@slot.name} from the Git repository.")
190
+ @slot.git_update
191
+ end
192
+
193
+ @slot.remove_from_filesystem()
194
+ @slot.destroy()
195
+ redirect "/control/buckets/#{params[:captures].first}"
196
+ end
197
+
198
+ get "/control/profile/?" do
199
+ login_required
200
+ @usero = @user
201
+ r :profile, "Your Profile"
202
+ end
203
+
204
+ post "/control/profile/?" do
205
+ login_required
206
+ @user.update_attributes(params['user'])
207
+ @usero = @user
208
+ r :profile, "Your Profile"
209
+ end
210
+
211
+ get "/control/users/?" do
212
+ login_required
213
+ only_superusers
214
+ @usero = User.new
215
+ @users = User.find :all, :conditions => ['deleted != 1'], :order => 'login'
216
+ r :users, "User List"
217
+ end
218
+
219
+ post "/control/users/?" do
220
+ login_required
221
+ only_superusers
222
+ @usero = User.new params['user'].merge(:activated_at => Time.now)
223
+ if @usero.valid?
224
+ @usero.save()
225
+ redirect "/control/users"
226
+ else
227
+ @users = User.find :all, :conditions => ['deleted != 1'], :order => 'login'
228
+ r :users, "User List"
229
+ end
230
+ end
231
+
232
+ get "/control/users/:login/?" do
233
+ login_required
234
+ only_superusers
235
+ @usero = User.find_by_login params[:login]
236
+ r :profile, @usero.login
237
+ end
238
+
239
+ post "/control/users/:login/?" do
240
+ login_required
241
+ only_superusers
242
+ @usero = User.find_by_login params[:login]
243
+
244
+ # if were not changing passwords remove blank values
245
+ if params['user']['password'].blank? && params['user']['password_confirmation'].blank?
246
+ params['user'].delete('password')
247
+ params['user'].delete('password_confirmation')
248
+ end
249
+
250
+ if @usero.update_attributes(params['user'])
251
+ redirect "/control/users/#{@usero.login}"
252
+ else
253
+ r :profile, @usero.login
254
+ end
255
+ end
256
+
257
+ post "/control/users/delete/:login/?" do
258
+ login_required
259
+ only_superusers
260
+ @usero = User.find_by_login params[:login]
261
+ if @usero.id == @user.id
262
+ # FIXME: notify user they cannot delete themselves
263
+ else
264
+ @usero.destroy
265
+ end
266
+ redirect "/control/users"
267
+ end
268
+
269
+ get %r{^/control/acl/(.+?)/(.+)$} do
270
+ login_required
271
+ @bucket = Bucket.find_root(params[:captures].first)
272
+ only_can_write_acp @bucket
273
+ @slot = @bucket.find_slot(params[:captures].last)
274
+ only_can_write @slot
275
+ r :acl, "Modify File Access", :popup
276
+ end
277
+
278
+ post %r{^/control/acl/(.+?)/(.+)$} do
279
+ login_required
280
+ @bucket = Bucket.find_root(params[:captures].first)
281
+ @slot = @bucket.find_slot(params[:captures].last)
282
+ only_owner_of @slot
283
+ case params[:acl]['type']
284
+ when "email"
285
+ @user = User.find(:first, :conditions => [ 'key = ? OR email = ?', params[:acl]['user_id'], params[:acl]['user_id'] ])
286
+ update_user_access(@slot,@user,"#{Bit.acl_text.invert[params[:acl]['access']]}00".to_i(8)) if @user
287
+ when "http://acs.amazonaws.com/groups/global/AuthenticatedUsers"
288
+ @slot.access &= ~(@slot.access.to_s(8)[1,1].to_i*10)
289
+ @slot.access |= (Bit.acl_text.invert[params[:acl]['access']]*10).to_s.to_i(8)
290
+ when "http://acs.amazonaws.com/groups/global/AllUsers"
291
+ @slot.access &= ~@slot.access.to_s(8)[2,1].to_i
292
+ @slot.access |= Bit.acl_text.invert[params[:acl]['access']].to_s.to_i(8)
293
+ end
294
+ @slot.save()
295
+ redirect "/control/acl/#{@bucket.name}/#{@slot.name}"
296
+ end
297
+
298
+ get %r{^/control/meta/(.+?)/(.+)$} do
299
+ login_required
300
+ @bucket = Bucket.find_root(params[:captures].first)
301
+ @slot = @bucket.find_slot(params[:captures].last)
302
+ only_can_write @slot
303
+ r :meta, "Metadata", :popup
304
+ end
305
+
306
+ post %r{^/control/meta/(.+?)/(.+)$} do
307
+ login_required
308
+ @bucket = Bucket.find_root(params[:captures].first)
309
+ @slot = @bucket.find_slot(params[:captures].last)
310
+ only_can_write @slot
311
+
312
+ newm = {}
313
+ params[:m].each do |k,v|
314
+ newm[k] = v unless v.blank?
315
+ end
316
+ if !params[:meta]['key'].blank? && !params[:meta]['value'].blank?
317
+ if params[:meta]['key'] =~ /^[A-Za-z0-9\-]+$/
318
+ newm[params[:meta]['key']] = params[:meta]['value']
319
+ else
320
+ @slot.errors.add(:key, "can only contain letters, numbers and dashes")
321
+ end
322
+ end
323
+
324
+ @slot.update_attributes({ :meta => newm })
325
+ r :meta, "Metadata", :popup
326
+ end
327
+
328
+ end
329
+
330
+ end
331
+
332
+ __END__
333
+
334
+ @@ layout
335
+ %html
336
+ %head
337
+ %title Control Center &raquo; #{@title}
338
+ %script{ :language => "JavaScript", :type => "text/javascript", :src => "/control/s/js/prototype.js" }
339
+ %style{ :type => "text/css" }
340
+ @import '/control/s/css/control.css';
341
+ %body
342
+ %div#page
343
+ - if @user and not @login
344
+ %div.menu
345
+ %ul
346
+ %li
347
+ %a{ :href => "/control/buckets" } buckets
348
+ - if @user.superuser?
349
+ %a{ :href => "/control/users" } users
350
+ %a{ :href => "/control/profile" } profile
351
+ %a{ :href => "/control/logout" } logout
352
+ %div#header
353
+ %h1 Control Center
354
+ %h2 #{@title}
355
+ %div#content
356
+ = yield
357
+
358
+ @@ popup
359
+ %html
360
+ %head
361
+ %title #{@title}
362
+ %style{ :type => "text/css" }
363
+ @import '/control/s/css/control.css';
364
+ %script{ :language => 'javascript', :src => '/control/s/js/prototype.js' }
365
+ %body
366
+ %div#content
367
+ = yield
368
+
369
+ @@ login
370
+ %form.create{ :method => "post" }
371
+ %div.required
372
+ %label{ :for => "login" } User
373
+ %input#login{ :type => "text", :name => "login" }
374
+ %div.required
375
+ %label{ :for => "password" } Password
376
+ %input#password{ :type => "password", :name => "password" }
377
+ %input#loggo{ :type => "submit", :value => "Login", :name => "loggo" }
378
+
379
+ @@ buckets
380
+ - if @buckets.any?
381
+ %table
382
+ %thead
383
+ %tr
384
+ %th Name
385
+ %th Contains
386
+ %th Updated on
387
+ %th Info
388
+ %th Actions
389
+ %tbody
390
+ - @buckets.each do |bucket|
391
+ %tr
392
+ %th
393
+ %a{ :href => "/control/buckets/#{bucket.name}" } #{bucket.name}
394
+ %td #{bucket.total_children rescue 0} files
395
+ %td #{bucket.updated_at}
396
+ %td #{bucket.access_readable + (bucket.versioning_enabled? ? ",versioned" : "")}
397
+ %td
398
+ %a{ :href => "/control/delete/#{bucket.name}", :onClick => S3::POST, :title => "Delete Bucket #{bucket.name}" } Delete
399
+ - else
400
+ %p A sad day. You have no buckets yet.
401
+ %h3 Create a Bucket
402
+ %form.create{ :method => "post" }
403
+ = preserve errors_for(@bucket)
404
+ %input{ :name => "bucket[owner_id]", :type => "hidden", :value => @bucket.owner_id }
405
+ %div.required
406
+ %label{ :for => "bucket[name]" } Bucket Name
407
+ %input{ :name => "bucket[name]", :type => "text", :value => @bucket.name }
408
+ %div.required
409
+ %label{ :for => "bucket[access]" } Permissions
410
+ %select{ :name => "bucket[access]" }
411
+ - S3::CANNED_ACLS.sort.each do |acl,perm|
412
+ - opts = { :value => perm }
413
+ - opts[:selected] = true if perm == @bucket.access
414
+ %option{ opts } #{acl}
415
+ %input#newbucket{ :type => "submit", :value => "Create", :name => "newbucket" }
416
+
417
+ @@ files
418
+ %p Click on a file name to get file details.
419
+ %table
420
+ %caption
421
+ - if defined?(Git)
422
+ %span{ :style => "float:right" }
423
+ - if !@bucket.versioning_enabled?
424
+ %a{ :href => "/control/buckets/#{@bucket.name}/versioning", :onClick => S3::POST } Enable Versioning For This Bucket
425
+ - else
426
+ Versioning Enabled
427
+ %a{ :href => "/control/buckets" } &larr; Buckets
428
+ %thead
429
+ %tr
430
+ %th File
431
+ %th Size
432
+ %th Permission
433
+ %tbody
434
+ - if @files.empty?
435
+ %tr
436
+ %td{ :colspan => "3", :style => "padding:15px;text-align:center" } No Files
437
+ - @files.each do |file|
438
+ %tr
439
+ %td
440
+ %a{ :href => "javascript:///", :onclick => "$('details-#{file.id}').toggle()" } #{file.name}
441
+ %div.details{ :id => "details-#{file.id}", :style => "display:none" }
442
+ - if @bucket.versioning_enabled? && !file.git_object.nil?
443
+ %p Revision: #{file.git_object.objectish}
444
+ - if file.torrent
445
+ %p #{file.torrent.seeders} seeders &bull; #{file.torrent.leechers} leechers &bull; #{file.torrent.total} downloads
446
+ %p Last modified on #{file.updated_at}
447
+ %p
448
+ %a{ :href => signed_url("/#{@bucket.name}/#{file.name}"), :target => "_blank" } Get
449
+ &bull;
450
+ %a{ :href => "/control/acl/#{@bucket.name}/#{file.name}", :onclick => S3::POPUP } Access
451
+ &bull;
452
+ %a{ :href => "/control/meta/#{@bucket.name}/#{file.name}", :onclick => S3::POPUP } Meta
453
+ &bull;
454
+ - if @bucket.versioning_enabled?
455
+ %a{ :href => "/control/changes/#{@bucket.name}/#{file.name}", :onclick => S3::POPUP } Changes
456
+ &bull;
457
+ - if defined?(RubyTorrent)
458
+ %a{ :href => signed_url("/#{@bucket.name}/#{file.name}") + "&torrent", :target => "_blank" } Torrent
459
+ &bull;
460
+ %a{ :href => "/control/delete/#{@bucket.name}/#{file.name}", :onclick => S3::POST, :title => "Delete file #{file.name}" } Delete
461
+ %td #{number_to_human_size(file.size)}
462
+ %td #{file.access_readable}
463
+ %div#results
464
+ %div#progress-bar{ :style => "display:none" }
465
+ %iframe#upload{ :name => "upload", :style => "display:none" }
466
+ - @upid = Time.now.to_f
467
+ - form_options = { :action => "?upload_id=#{@upid}", :id => "upload-form", :method => 'post', :enctype => 'multipart/form-data' }
468
+ - form_options.merge!({ :onsubmit => "UploadProgress.monitor('#{@upid}')", :target => "upload" }) if $UPLOAD_PROGRESS
469
+ %form.create{ form_options }
470
+ %h3 Upload a File
471
+ %div.required
472
+ %input{ :name => "upfile", :type => "file" }
473
+ %div.optional
474
+ %label{ :for => "fname"} File Name
475
+ %input{ :name => "fname", :type => "text" }
476
+ %div.required
477
+ %label{ :for => "facl" } Permissions
478
+ %select{ :name => "facl" }
479
+ - S3::CANNED_ACLS.sort.each do |acl, perm|
480
+ - opts = { :value => perm }
481
+ - opts[:selected] = true if perm == @bucket.access
482
+ %option{ opts } #{acl}
483
+ %input#newfile{ :name => "newfile", :value => "Create", :type => "submit" }
484
+
485
+ @@ users
486
+ %table
487
+ %thead
488
+ %tr
489
+ %th Login
490
+ %th Activated On
491
+ %th Total Storage
492
+ %th Actions
493
+ %tbody
494
+ - @users.each do |user|
495
+ %tr
496
+ %th
497
+ %a{ :href => "/control/users/#{user.login}" } #{user.login}
498
+ %td #{user.activated_at}
499
+ %td #{number_to_human_size(Bit.sum(:size, :conditions => [ 'owner_id = ?', user.id ]))}
500
+ %td
501
+ %a{ :href => "/control/users/delete/#{user.login}", :onclick => S3::POST, :title => "Delete user #{user.login}" } Delete
502
+ %h3 Create a User
503
+ %form.create{ :action => "/control/users", :method => "post" }
504
+ = preserve errors_for(@usero)
505
+ %div.required
506
+ %label{ :for => "user[login]" } Login
507
+ %input.large{ :type => "text", :value => @usero.login, :name => "user[login]" }
508
+ %div.required.inline
509
+ %label{ :for => "user[superuser]" } Is a super-admin?
510
+ %input{ :type => "checkbox", :name => "user[superuser]", :value => @usero.superuser }
511
+ %div.required
512
+ %label{ :for => "user[password]" } Password
513
+ %input.fixed{ :type => "password", :name => "user[email]" }
514
+ %div.required
515
+ %label{ :for => "user[password_confirmation]" } Password again
516
+ %input.fixed{ :type => "password", :name => "user[password_confirmation]" }
517
+ %div.required
518
+ %label{ :for => "user[email]" } Email
519
+ %input{ :type => "text", :value => @usero.email, :name => "user[email]" }
520
+ %div.required
521
+ %label{ :for => "user[key]" } Key (must be unique)
522
+ %input.fixed.long{ :type => "text", :value => (@usero.key || generate_key), :name => "user[key]" }
523
+ %div.required
524
+ %label{ :for => "user[secret]" } Secret
525
+ %input.fixed.long{ :type => "text", :value => (@usero.secret || generate_secret), :name => "user[secret]" }
526
+ %input.newuser{ :type => "submit", :value => "Create", :name => "newuser" }
527
+
528
+ @@ profile
529
+ %form.create{ :method => "post" }
530
+ = preserve errors_for(@usero)
531
+ - if @user.superuser?
532
+ %div.required.inline
533
+ %label{ :for => "user[superuser]" } Is a super-admin?
534
+ %input{ :type => "checkbox", :name => "user[superuser]", :value => @usero.superuser }
535
+ %div.required
536
+ %label{ :for => "user[password]" } Password
537
+ %input.fixed{ :type => "password", :name => "user[email]" }
538
+ %div.required
539
+ %label{ :for => "user[password_confirmation]" } Password again
540
+ %input.fixed{ :type => "password", :name => "user[password_confirmation]" }
541
+ %div.required
542
+ %label{ :for => "user[email]" } Email
543
+ %input{ :type => "text", :value => @usero.email, :name => "user[email]" }
544
+ %div.required
545
+ %label{ :for => "key" } Key
546
+ %h4 #{@usero.key}
547
+ %div.required
548
+ %label{ :for => "secret" } Secret
549
+ %h4 #{@usero.secret}
550
+ %input#saveuser{ :type => "submit", :value => "Save", :name => "saveuser" }
551
+
552
+ @@ meta
553
+ %form.create{ :method => "post", :style => "text-align:left" }
554
+ = preserve errors_for(@slot)
555
+ %table
556
+ %thead
557
+ %tr
558
+ %th Key
559
+ %th Value
560
+ %tbody
561
+ - if @slot.meta.empty?
562
+ %tr
563
+ %td{ :colspan => "2", :style => "padding:8px;text-align:center" } No Metadata for #{@slot.name}
564
+ - else
565
+ - @slot.meta.each do |k,v|
566
+ %tr
567
+ %td #{k}
568
+ %td
569
+ %input{ :name => "m[#{k}]", :type => "text", :value => v, :style => "width:100%" }
570
+ %thead
571
+ %tr
572
+ %th{ :colspan => "2" } New Key
573
+ %tbody
574
+ %tr
575
+ %td
576
+ %input{ :name => "meta[key]", :type => "text", :style => "width:100%" }
577
+ %td
578
+ %input{ :name => "meta[value]", :type => "text", :style => "width:100%" }
579
+ %div{ :style => "text-align:center;margin-top:15px" }
580
+ %input{ :type => "submit", :value => "Update" }
581
+
582
+ @@ changes
583
+ %table
584
+ %thead
585
+ %tr
586
+ %th Commit Log For #{@file.name}
587
+ %tbody
588
+ - @versions.each do |version|
589
+ %tr
590
+ %td
591
+ %div
592
+ %a{ :target => "_blank", :href => signed_url("/#{@bucket.name}/#{@file.name}") + "&version-id=#{version.sha}" } #{version.sha}
593
+ %div On: #{version.date}
594
+ %div By: #{version.author.name} <#{version.author.email}>
595
+
596
+ @@ acl
597
+ %table
598
+ %thead
599
+ %tr
600
+ %th For
601
+ %th Access
602
+ %tbody
603
+ - @slot.acl_list.each_pair do |key,acl|
604
+ %tr
605
+ %td #{acl[:type] == "CanonicalUser" ? "#{acl[:id]} (#{acl[:name]})" : acl[:uri].split("/").last}
606
+ %td #{acl[:access]}
607
+ %div{ :style => "text-align:left;margin-top:10px" }
608
+ %h3 Modify File Access
609
+ %form.create{ :method => "post" }
610
+ %div.required
611
+ %label{ :for => "acl_type" } For
612
+ %select#acl_type{ :name => "acl[type]", :onchange => "$('user_id_box').style.display = this.value == 'email' ? 'block' : 'none';" }
613
+ %option{ :value => "http://acs.amazonaws.com/groups/global/AllUsers" } AllUsers
614
+ %option{ :value => "http://acs.amazonaws.com/groups/global/AuthenticatedUsers" } AuthenticatedUsers
615
+ %option{ :value => "email" } By ID/Email
616
+ %div#user_id_box.required{ :style => "display:none" }
617
+ %label{ :for => "user_id" } User ID/Email
618
+ %input#user_id{ :type => "text", :name => "acl[user_id]" }
619
+ %div.required
620
+ %label{ :for => "user_access" } Access
621
+ %select#user_access{ :name => "acl[access]" }
622
+ %option{ :value => "READ" } READ
623
+ %option{ :value => "READ_ACP" } READ_ACP
624
+ %option{ :value => "WRITE" } WRITE
625
+ %option{ :value => "WRITE_ACP" } WRITE_ACP
626
+ %input{ :type => "submit", :value => "Update" }