boxlet 0.2.8 → 1.0.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 956d2071a94833442316b9e97b35eaaf40284976
4
- data.tar.gz: a6997a8a7258f156543cddc80eff0b6527d740b3
3
+ metadata.gz: e0446d59f5924ddab50d982f411f5cc9d0f0c663
4
+ data.tar.gz: d8100c4c6811458fe5c1918177cb1054c738ba45
5
5
  SHA512:
6
- metadata.gz: b2162347f5df7546e58b33372afe319fca9360d46551a8bcdc1e549f47961be04fc207c0b4404f899d04e316415f7749e81d1f0902db5d939989c276f646b55f
7
- data.tar.gz: a550939df3ccbd8588f7a9a62af995f36aa3d6a9fc941b2066a7c9491d03a9665ac81e58a41c598f2137011eadc52b0e522df553603baeb806c93b5455b9aeb0
6
+ metadata.gz: dbb800ce150cef6bc836367b19d853df6c6d4be5144125c895ffb9c0dd52a8419544f310aad4fe6028b9631e67d2c77afe7af67e48656323f40fadc4b389817e
7
+ data.tar.gz: 3b8642b22e637aa03a46d151ce4d94ff2bb7c78b3327376c075a05e0fd9eda9be2526ca7e2ff4b2c411fe59c20ef788e5f0eab915afaf1cde8d0d62a3acd50c8
@@ -16,6 +16,7 @@ Gem::Specification.new do |spec|
16
16
  spec.files = %w[config.yml LICENSE.txt README.md Rakefile boxlet.gemspec]
17
17
  spec.files += Dir.glob('lib/**/*.rb')
18
18
  spec.files += Dir.glob('lib/boxlet/app/*.rb')
19
+ spec.files += Dir.glob('lib/boxlet/app/views/*.html')
19
20
 
20
21
  spec.executables = 'boxlet'
21
22
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
data/config.yml CHANGED
@@ -22,6 +22,9 @@ pid_file: server.pid
22
22
  log_file: server.log
23
23
  public_url: http://localhost:8077
24
24
 
25
+ gallery_username: asdf
26
+ gallery_password: asdf
27
+
25
28
  #use s3
26
29
  s3:
27
30
  enabled: false
@@ -12,6 +12,11 @@ module Boxlet
12
12
  extend self
13
13
  extend Boxlet::Config
14
14
 
15
+ PUBLIC_COMMANDS = {
16
+ run: "Run the Boxlet server",
17
+ stop: "Stop a daemonized server"
18
+ }.freeze
19
+
15
20
  attr_accessor :runner, :config, :raw_params, :raw_config
16
21
 
17
22
  def run!(argv, command='run', config_file='config.yml', &blk)
@@ -68,13 +73,24 @@ module Boxlet
68
73
  def print_menu
69
74
  puts "Usage: boxlet command [args]"
70
75
  puts
71
- puts "Available commands are as follows:"
72
- commands_with_descriptions = App::PUBLIC_COMMANDS.merge run: "Run the Boxlet server"
76
+ puts "Common commands:"
77
+ commands_with_descriptions = PUBLIC_COMMANDS.merge(App::PUBLIC_COMMANDS)
73
78
  commands = commands_with_descriptions.keys
74
- max_chars = commands.sort { |a, b| a.length <=> b.length }.last.length
75
- commands.sort.each do |command|
76
- puts " #{command.to_s.ljust(max_chars)} #{commands_with_descriptions[command]}"
79
+ max_command_chars = commands.sort { |a, b| a.length <=> b.length }.last.length
80
+ PUBLIC_COMMANDS.each do |command, description|
81
+ print_menu_command command, max_command_chars, description
82
+ end
83
+
84
+ puts
85
+ puts "Additional commands:"
86
+ App::PUBLIC_COMMANDS.each do |command, description|
87
+ print_menu_command command, max_command_chars, description
77
88
  end
89
+
90
+ end
91
+
92
+ def print_menu_command(command, max_command_chars, description)
93
+ puts " #{command.to_s.ljust(max_command_chars)} #{description}"
78
94
  end
79
95
  end
80
96
 
@@ -4,6 +4,7 @@ require 'rack/response'
4
4
  require 'rack/file_upload'
5
5
  require 'boxlet/db'
6
6
  require 'boxlet/util'
7
+ require 'handlers/auth'
7
8
  require 'boxlet/app/router'
8
9
  require 'boxlet/app/models'
9
10
 
@@ -29,7 +30,9 @@ module Boxlet
29
30
  ["/file_list"] => :file_list,
30
31
  ["/file_info"] => :file_info,
31
32
  ["/resync", :get] => :resync,
32
- ["/flashback", :post] => :flashback
33
+ ["/flashback", :post] => :flashback,
34
+ ["/gallery", :get] => :gallery,
35
+ ["/gallery/images", :get] => :gallery_images,
33
36
  }
34
37
  end
35
38
 
@@ -3,17 +3,21 @@ require 'digest'
3
3
  require 'thread'
4
4
  require 'ImageResize'
5
5
  require 'aws-sdk'
6
+ require 'boxlet/app/templates'
6
7
 
7
8
  # routes = {
8
- # ["/", :get] => :index,
9
- # ["/auth"] => :auth,
10
- # ["/register_device", :post] => :register_device,
11
- # ["/notifications", :post] => :notifications,
12
- # ["/push_files", :post] => :push_files,
13
- # ["/file_list"] => :file_list,
14
- # ["/file_info"] => :file_info,
15
- # ["/resync", :get] => :resync,
16
- # ["/flashback", :post] => :flashback
9
+ # ["/", :get] => :index,
10
+ # ["/auth"] => :auth,
11
+ # ["/register_device", :post] => :register_device,
12
+ # ["/notifications", :*] => :notifications,
13
+ # ["/stats", :post] => :stats,
14
+ # ["/push_files", :post] => :push_files,
15
+ # ["/file_list"] => :file_list,
16
+ # ["/file_info"] => :file_info,
17
+ # ["/resync", :get] => :resync,
18
+ # ["/flashback", :post] => :flashback,
19
+ # ["/gallery", :get] => :gallery,
20
+ # ["/gallery/images", :get] => :gallery_images,
17
21
  # }
18
22
 
19
23
 
@@ -27,18 +31,25 @@ module Boxlet
27
31
  Boxlet.log(:info, request.params)
28
32
 
29
33
  @format = :html
34
+ @status = 200
35
+ @headers = {}
30
36
  end
31
37
 
32
38
  def action(action)
33
39
  action_response = self.send(action)
34
40
  set_user if action =~ /push_files|file_list|file_info/
35
41
 
36
- {format: @format, content: action_response}
42
+ {
43
+ format: @format,
44
+ content: action_response,
45
+ status: @status,
46
+ headers: @headers
47
+ }
37
48
  end
38
49
 
39
50
  # actions
40
51
  def index
41
- '<html><body><form action="/push_files" method="post" enctype="multipart/form-data">UUID:<input type="text" name="uuid"><br><input type="file" name="file"><input type="submit"></form>'
52
+ Templates.index
42
53
  end
43
54
 
44
55
  # def auth
@@ -180,6 +191,28 @@ module Boxlet
180
191
  }).to_a)
181
192
  end
182
193
 
194
+ def gallery
195
+ @format = :html
196
+
197
+ authorized_request do
198
+ Templates.gallery
199
+ end
200
+ end
201
+
202
+ def gallery_images
203
+ @format = :json
204
+
205
+ authorized_request do
206
+ limit = (@params[:limit] || 50).to_i
207
+ skip = ((params[:page] || 1).to_i - 1) * limit
208
+ {
209
+ count: db.collection('assets').count(),
210
+ base_path: base_upload_path,
211
+ images: db.collection('assets').find().limit(limit).skip(skip).to_a
212
+ }
213
+ end
214
+ end
215
+
183
216
 
184
217
  private
185
218
 
@@ -192,24 +225,7 @@ module Boxlet
192
225
  end
193
226
 
194
227
  def user_upload_dir
195
- dir_name = @params[:uuid] || ''
196
- user_upload_dir_name = Boxlet.config[:upload_dir] + "/" + dir_name
197
- Dir.mkdir(user_upload_dir_name) unless File.exists?(user_upload_dir_name)
198
-
199
- if @params[:uuid]
200
- dir_shortname = Digest::MD5.hexdigest(dir_name)
201
- user_upload_dir_shortname = Boxlet.config[:upload_dir] + "/" + dir_shortname
202
-
203
- File.symlink(dir_name, user_upload_dir_shortname) if !File.symlink? user_upload_dir_shortname
204
-
205
- if File.symlink?(user_upload_dir_shortname)
206
- user_upload_dir_shortname
207
- else
208
- user_upload_dir_name
209
- end
210
- else
211
- user_upload_dir_name
212
- end
228
+ Boxlet::Util.user_upload_dir(@params[:uuid])
213
229
  end
214
230
 
215
231
  def free_space?
@@ -217,11 +233,19 @@ module Boxlet
217
233
  end
218
234
 
219
235
  def base_upload_path
220
- if Boxlet.config[:s3][:enabled]
221
- "https://s3.amazonaws.com/#{Boxlet.config[:s3][:bucket]}/#{@params[:uuid]}"
222
- else
223
- "#{Boxlet.config[:public_url]}/#{Boxlet.config[:upload_dir]}/#{Digest::MD5.hexdigest(@params[:uuid])}".gsub('/./', '/')
236
+ Boxlet::Util.base_upload_path(@params[:uuid])
237
+ end
238
+
239
+ def authorized_request(&action)
240
+ auth = Boxlet::Handlers::Auth.new(
241
+ Boxlet.config[:gallery_username],
242
+ Boxlet.config[:gallery_password]
243
+ )
244
+ @status, @headers, content = auth.authorize(request) do
245
+ action.call
224
246
  end
247
+
248
+ content
225
249
  end
226
250
  end
227
251
  end
@@ -23,7 +23,10 @@ module Boxlet
23
23
  if @method == :* || (request.get? && @method == :get) || (request.post? && @method == :post)
24
24
  Boxlet.log(:info, "INFO: Responding: #{@method.upcase} => #{@action}")
25
25
  action_response = controller.action(@action)
26
- response.status = 200
26
+ response.status = action_response[:status]
27
+ action_response[:headers].each do |key, value|
28
+ response.header[key] = value
29
+ end
27
30
  else
28
31
  response.status = 404
29
32
  action_response = {format: :html, content: "404 not found"}
@@ -0,0 +1,12 @@
1
+ module Boxlet
2
+ class Templates
3
+ def self.method_missing(method, *arguments, &block)
4
+ filename = "#{File.dirname(__FILE__)}/views/#{method}.html"
5
+ if File.exist?(filename)
6
+ File.open(filename).read
7
+ else
8
+ raise "Template file not found for #{method}"
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,114 @@
1
+ <html>
2
+ <head>
3
+ <style>
4
+ * {
5
+ margin: 0;
6
+ padding: 0;
7
+ box-sizing: border-box;
8
+ }
9
+
10
+ #gallery {
11
+ max-width: 100%;
12
+ margin: 1em auto;
13
+ padding: 1em;
14
+ box-shadow: 2px 2px 3px #fff;
15
+ }
16
+ .image-row {
17
+ display:block;
18
+ margin: 0.25em;
19
+ }
20
+ .image-row:after {
21
+ display: block;
22
+ content: " ";
23
+ clear: both;
24
+ }
25
+ .image-row li {
26
+ background-position: center center;
27
+ background-size: cover;
28
+ cursor: pointer;
29
+ float: left;
30
+ height: 5em;
31
+ list-style: none;
32
+ margin: 0.25em;
33
+ transition: opacity 300ms;
34
+ width: 5em;
35
+ }
36
+ .image-row li:hover {
37
+ opacity: 0.5;
38
+ }
39
+ .image-row li img {
40
+ width: 100%;
41
+ }
42
+
43
+ .hero-image {
44
+ display: block;
45
+ text-align: center;
46
+ height: 80%;
47
+ }
48
+ .hero-image img {
49
+ max-width: 100%;
50
+ max-height: 100%;
51
+ }
52
+ </style>
53
+
54
+ <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular.min.js"></script>
55
+ <script type="text/javascript">
56
+ angular.module("gallery", []);
57
+ angular.module("gallery").controller("GalleryController", function($scope, $location, $http) {
58
+ var basePath = '';
59
+ uuid = $location.search().uuid;
60
+
61
+ $scope.page = 1;
62
+ $scope.limit = 50;
63
+ $scope.images = [];
64
+ $scope.heroImage = null;
65
+ $scope.counter = function() {
66
+ var a = [],
67
+ pages = Math.ceil($scope.count / $scope.limit);
68
+ for (var i = 1; i <= pages; i++) {
69
+ a.push(i);
70
+ }
71
+ return a;
72
+ };
73
+
74
+ $scope.imageSource = function(image, size) {
75
+ console.log( basePath + "/" + image[size])
76
+ return basePath + "/" + image[size];
77
+ };
78
+
79
+ $scope.setHeroImage = function(image) {
80
+ $scope.heroImage = image;
81
+ };
82
+
83
+ $scope.fetchImages = function() {
84
+ var imagesUrl = "/gallery/images?page=" + $scope.page + "&limit=" + $scope.limit + "&uuid=" + uuid;
85
+ console.log(imagesUrl);
86
+
87
+ $http.get(imagesUrl).then(function(results) {
88
+ basePath = results.data.base_path;
89
+ $scope.basePath = basePath;
90
+ $scope.count = results.data.count;
91
+ $scope.images = results.data.images;
92
+ $scope.heroImage = $scope.images[0];
93
+ });
94
+ }
95
+
96
+ $scope.fetchImages();
97
+ });
98
+ </script>
99
+ </head>
100
+ <body ng-app="gallery">
101
+ <div ng-controller="GalleryController">
102
+ <div class="hero-image">
103
+ <img ng-src="{{basePath}}/{{heroImage.filename}}" />
104
+ </div>
105
+
106
+ <select ng-change="fetchImages()" ng-model="page" ng-options="page for page in counter() track by page">
107
+ <option ng-repeat="page in counter()" value="page">{{page}}</option>
108
+ </select>
109
+ <ul class="image-row">
110
+ <li ng-repeat="image in images" style="background-image: url({{imageSource(image, 'thumbnail')}})" ng-click="setHeroImage(image)"></li>
111
+ </ul>
112
+ </div>
113
+ </body>
114
+ </html>
@@ -0,0 +1,12 @@
1
+ <html>
2
+ <body>
3
+ <form action="/push_files" method="post" enctype="multipart/form-data">
4
+ UUID:<input type="text" name="uuid">
5
+ <br>
6
+ Asset Path:<input type="text" name="asset_path">
7
+ <br>
8
+ <input type="file" name="file">
9
+ <input type="submit">
10
+ </form>
11
+ </body>
12
+ </html>
@@ -48,5 +48,35 @@ module Boxlet
48
48
  stat = Filesystem.stat(Boxlet.config[:file_system_root])
49
49
  (stat.block_size * stat.blocks).to_mb
50
50
  end
51
+
52
+ # Directory paths
53
+ def self.user_upload_dir(uuid)
54
+ dir_name = uuid || ''
55
+ user_upload_dir_name = Boxlet.config[:upload_dir] + "/" + dir_name
56
+ Dir.mkdir(user_upload_dir_name) unless File.exists?(user_upload_dir_name)
57
+
58
+ if uuid
59
+ dir_shortname = Digest::MD5.hexdigest(dir_name)
60
+ user_upload_dir_shortname = Boxlet.config[:upload_dir] + "/" + dir_shortname
61
+
62
+ File.symlink(dir_name, user_upload_dir_shortname) if !File.symlink? user_upload_dir_shortname
63
+
64
+ if File.symlink?(user_upload_dir_shortname)
65
+ user_upload_dir_shortname
66
+ else
67
+ user_upload_dir_name
68
+ end
69
+ else
70
+ user_upload_dir_name
71
+ end
72
+ end
73
+
74
+ def self.base_upload_path(uuid)
75
+ if Boxlet.config[:s3][:enabled]
76
+ "https://s3.amazonaws.com/#{Boxlet.config[:s3][:bucket]}/#{uuid}"
77
+ else
78
+ "#{Boxlet.config[:public_url]}/#{Boxlet.config[:upload_dir]}/#{Digest::MD5.hexdigest(uuid)}".gsub('/./', '/')
79
+ end
80
+ end
51
81
  end
52
82
  end
@@ -1,3 +1,3 @@
1
1
  module Boxlet
2
- VERSION = "0.2.8"
2
+ VERSION = "1.0.2"
3
3
  end
@@ -0,0 +1,98 @@
1
+ module Boxlet
2
+ module Handlers
3
+ class Auth
4
+ def initialize(username, password)
5
+ @username = username
6
+ @password = password
7
+ @realm = "Boxlet"
8
+ end
9
+
10
+ def authorize(request)
11
+ @auth = Request.new(request.env)
12
+
13
+ return unauthorized unless @auth.provided?
14
+ return bad_request unless @auth.basic?
15
+
16
+ if valid?(@username, @password)
17
+ headers = {'REMOTE_USER' => @username}
18
+
19
+ [200, headers, yield]
20
+ else
21
+ unauthorized
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def challenge
28
+ 'Basic realm="%s"' % @realm
29
+ end
30
+
31
+ def valid?(username, password)
32
+ @auth.credentials[0] == username &&
33
+ @auth.credentials[1] == password
34
+ end
35
+
36
+ def unauthorized(www_authenticate = challenge)
37
+ content_hash = {
38
+ 'CONTENT_TYPE' => 'text/plain',
39
+ 'CONTENT_LENGTH' => '0',
40
+ 'WWW-Authenticate' => www_authenticate.to_s
41
+ }
42
+ return [401, content_hash, []]
43
+ end
44
+
45
+ def bad_request
46
+ content_hash = {
47
+ 'CONTENT_TYPE' => 'text/plain',
48
+ 'CONTENT_LENGTH' => '0'
49
+ }
50
+ return [400, content_hash, []]
51
+ end
52
+
53
+
54
+ class Request
55
+ def initialize(env)
56
+ @env = env
57
+ end
58
+
59
+ def basic?
60
+ "basic" == scheme
61
+ end
62
+
63
+ def credentials
64
+ @credentials ||= params.unpack("m*").first.split(/:/, 2)
65
+ end
66
+
67
+ def username
68
+ credentials.first
69
+ end
70
+
71
+ def provided?
72
+ !authorization_key.nil?
73
+ end
74
+
75
+ def parts
76
+ @parts ||= @env[authorization_key].split(' ', 2)
77
+ end
78
+
79
+ def scheme
80
+ @scheme ||= parts.first && parts.first.downcase
81
+ end
82
+
83
+ def params
84
+ @params ||= parts.last
85
+ end
86
+
87
+
88
+ private
89
+
90
+ AUTHORIZATION_KEYS = ['HTTP_AUTHORIZATION', 'X-HTTP_AUTHORIZATION', 'X_HTTP_AUTHORIZATION']
91
+
92
+ def authorization_key
93
+ @authorization_key ||= AUTHORIZATION_KEYS.detect { |key| @env.has_key?(key) }
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: boxlet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.8
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - arktisklada
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-05 00:00:00.000000000 Z
11
+ date: 2016-06-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -207,12 +207,16 @@ files:
207
207
  - lib/boxlet/app/controller.rb
208
208
  - lib/boxlet/app/models.rb
209
209
  - lib/boxlet/app/router.rb
210
+ - lib/boxlet/app/templates.rb
211
+ - lib/boxlet/app/views/gallery.html
212
+ - lib/boxlet/app/views/index.html
210
213
  - lib/boxlet/config.rb
211
214
  - lib/boxlet/db.rb
212
215
  - lib/boxlet/log.rb
213
216
  - lib/boxlet/runner.rb
214
217
  - lib/boxlet/util.rb
215
218
  - lib/boxlet/version.rb
219
+ - lib/handlers/auth.rb
216
220
  - lib/handlers/thin.rb
217
221
  - lib/rack/boxlet_url_builder.rb
218
222
  - lib/rack/boxlet_url_map.rb
@@ -237,7 +241,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
237
241
  version: '0'
238
242
  requirements: []
239
243
  rubyforge_project:
240
- rubygems_version: 2.5.0
244
+ rubygems_version: 2.4.8
241
245
  signing_key:
242
246
  specification_version: 4
243
247
  summary: Upload pics from your phone