boxlet 0.2.8 → 1.0.2

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