social-avatar-proxy 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -27,7 +27,7 @@ Or install it yourself as:
27
27
 
28
28
  ## Usage
29
29
 
30
- # Rails
30
+ ### Rails
31
31
 
32
32
  In your `config/routes.rb` file:
33
33
 
@@ -51,7 +51,18 @@ image_tag(facebook_avatar_path("username"))
51
51
  image_tag(facebook_avatar_path(12345))
52
52
  ```
53
53
 
54
- # Rack
54
+ You might wish to configure a default image which will be rendered if an avatar could not be found, or if the remote service has an error (e.g. times out or has a redirect loop), this is simple with an initializer:
55
+
56
+ ```ruby
57
+ require "social_avatar_proxy/config"
58
+
59
+ # choose our image
60
+ image_path = Rails.root.join("public", "default_avatar.jpg")
61
+ # set the config
62
+ SocialAvatarProxy::Config.default_image = image_path
63
+ ```
64
+
65
+ ### Rack
55
66
 
56
67
  The Rack app is available at: SocialAvatarProxy::App.
57
68
 
@@ -1,4 +1,5 @@
1
1
  require "social_avatar_proxy/version"
2
+ require "social_avatar_proxy/config"
2
3
  require "social_avatar_proxy/app"
3
4
  require "social_avatar_proxy/avatar"
4
5
  require "social_avatar_proxy/facebook_avatar"
@@ -1,3 +1,4 @@
1
+ require "social_avatar_proxy/config"
1
2
  require "social_avatar_proxy/facebook_avatar"
2
3
  require "social_avatar_proxy/twitter_avatar"
3
4
  require "social_avatar_proxy/routes"
@@ -54,25 +55,13 @@ module SocialAvatarProxy
54
55
  if avatar.exist?
55
56
  # render the avatar to the response
56
57
  Rack::Response.new do |response|
57
- # set the last modified header
58
- response["Last-Modified"] = avatar.last_modified
59
- # set the content type header
60
- response["Content-Type"] = avatar.content_type
61
- # if we want to expire in a set time, calculate the header
62
- if options[:expires]
63
- response["Expires"] = (Time.now + options[:expires]).httpdate
64
- end
65
- # if we want to set cache control settings
66
- if cc = options[:cache_control]
67
- directives = []
68
- directives << "no-cache" if cc[:no_cache]
69
- directives << "max-stale=#{cc[:max_stale]}" if cc[:max_stale]
70
- directives << "max-age=#{cc[:max_age]}" if cc[:max_age]
71
- directives << (cc[:public] ? "public" : "private")
72
- response["Cache-Control"] = directives.join(", ")
73
- end
74
- # set the data
58
+ # set the response data
75
59
  response.write(avatar.body)
60
+ # set the response headers
61
+ response = set_avatar_headers(response, avatar)
62
+ response = set_caching_headers(response)
63
+ # return the response
64
+ response
76
65
  end
77
66
  # if the avatar doesn't exist
78
67
  else
@@ -81,15 +70,39 @@ module SocialAvatarProxy
81
70
  end
82
71
 
83
72
  def not_found
84
- Rack::Response.new("Not Found", 404)
73
+ Rack::Response.new([], 404) do |response|
74
+ # if we have a custom default image
75
+ if Config.default_image
76
+ render_default_image(response)
77
+ # without a default image
78
+ else
79
+ response.write "Not Found"
80
+ end
81
+ end
85
82
  end
86
83
 
87
84
  def timeout
88
- Rack::Response.new("Remote server timeout", 504)
85
+ Rack::Response.new([], 504) do |response|
86
+ # if we have a custom default image
87
+ if Config.default_image
88
+ render_default_image(response)
89
+ # without a default image
90
+ else
91
+ response.write "Remote server timeout"
92
+ end
93
+ end
89
94
  end
90
95
 
91
96
  def bad_gateway
92
- Rack::Response.new("Bad response from remote server", 502)
97
+ Rack::Response.new([], 502) do |response|
98
+ # if we have a custom default image
99
+ if Config.default_image
100
+ render_default_image(response)
101
+ # without a default image
102
+ else
103
+ response.write "Bad response from remote server"
104
+ end
105
+ end
93
106
  end
94
107
 
95
108
  def routes
@@ -97,6 +110,44 @@ module SocialAvatarProxy
97
110
  end
98
111
 
99
112
  private
113
+ def render_default_image(response)
114
+ # render the image
115
+ response.write(Config.default_image_data)
116
+ # set the content type
117
+ response["Content-Type"] = Config.default_image_content_type
118
+ # set expiry
119
+ response = set_caching_headers(response)
120
+ # return the response
121
+ response
122
+ end
123
+
124
+ def set_avatar_headers(response, avatar)
125
+ # set the last modified header
126
+ response["Last-Modified"] = avatar.last_modified
127
+ # set the content type header
128
+ response["Content-Type"] = avatar.content_type
129
+ # return the response
130
+ response
131
+ end
132
+
133
+ def set_caching_headers(response)
134
+ # if we want to expire in a set time, calculate the header
135
+ if options[:expires]
136
+ response["Expires"] = (Time.now + options[:expires]).httpdate
137
+ end
138
+ # if we want to set cache control settings
139
+ if cc = options[:cache_control]
140
+ directives = []
141
+ directives << "no-cache" if cc[:no_cache]
142
+ directives << "max-stale=#{cc[:max_stale]}" if cc[:max_stale]
143
+ directives << "max-age=#{cc[:max_age]}" if cc[:max_age]
144
+ directives << (cc[:public] ? "public" : "private")
145
+ response["Cache-Control"] = directives.join(", ")
146
+ end
147
+ # return the response
148
+ response
149
+ end
150
+
100
151
  def load_avatar(service, id)
101
152
  # titleize the service name
102
153
  service = service.gsub(/[\_\-]/, " ").gsub(/\b([a-z])/) do |match|
@@ -0,0 +1,30 @@
1
+ module SocialAvatarProxy
2
+ class Config
3
+ class << self
4
+ attr_accessor :default_image
5
+
6
+ def default_image_file
7
+ default_image && File.new(default_image)
8
+ end
9
+
10
+ def default_image_data
11
+ default_image_file.read
12
+ end
13
+
14
+ def default_image_content_type
15
+ case File.extname(default_image).downcase
16
+ when /^\.jpe?g$/
17
+ "image/jpeg"
18
+ when /^\.png$/
19
+ "image/png"
20
+ when /^\.gif$/
21
+ "image/gif"
22
+ when /^\.svg$/
23
+ "image/svg+xml"
24
+ else
25
+ "application/octet-stream"
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,3 +1,3 @@
1
1
  module SocialAvatarProxy
2
- VERSION = "1.1.0"
2
+ VERSION = "1.2.0"
3
3
  end
Binary file
@@ -57,10 +57,22 @@ describe SocialAvatarProxy::App do
57
57
  end
58
58
 
59
59
  context "given an invalid path" do
60
+ let(:path) { "/unknown" }
61
+
60
62
  it "should return a 404 response" do
61
- path = "/unknown"
62
63
  expect(subject.get(path).status).to eq(404)
63
64
  end
65
+
66
+ context "with a custom image" do
67
+ before(:each) do
68
+ image_path = File.join(File.dirname(__FILE__), "../fixtures/image.jpg")
69
+ SocialAvatarProxy::Config.default_image = image_path
70
+ end
71
+
72
+ it "should render the image" do
73
+ expect(subject.get(path)["Content-Type"]).to eq("image/jpeg")
74
+ end
75
+ end
64
76
  end
65
77
 
66
78
  context "given a valid path" do
@@ -0,0 +1,57 @@
1
+ require "spec_helper"
2
+
3
+ describe SocialAvatarProxy::Config do
4
+ subject { SocialAvatarProxy::Config }
5
+
6
+ after(:each) do
7
+ subject.default_image = nil
8
+ end
9
+
10
+ describe "::default_image" do
11
+ it "should default to nil" do
12
+ expect(subject.default_image).to be_nil
13
+ end
14
+
15
+ it "should store a path" do
16
+ subject.default_image = "/test.jpg"
17
+ expect(subject.default_image).to eq "/test.jpg"
18
+ end
19
+ end
20
+
21
+ describe "::default_image_content_type" do
22
+ context "with a JPEG" do
23
+ it "should return image/jpeg" do
24
+ subject.default_image = "/test.JPG"
25
+ expect(subject.default_image_content_type).to eq "image/jpeg"
26
+ end
27
+ end
28
+
29
+ context "with a PNG" do
30
+ it "should return image/png" do
31
+ subject.default_image = "/test.png"
32
+ expect(subject.default_image_content_type).to eq "image/png"
33
+ end
34
+ end
35
+
36
+ context "with a GIF" do
37
+ it "should return image/gif" do
38
+ subject.default_image = "/test.gif"
39
+ expect(subject.default_image_content_type).to eq "image/gif"
40
+ end
41
+ end
42
+
43
+ context "with a SVG" do
44
+ it "should return image/svg+xml" do
45
+ subject.default_image = "/test.svg"
46
+ expect(subject.default_image_content_type).to eq "image/svg+xml"
47
+ end
48
+ end
49
+
50
+ context "with an unknown type" do
51
+ it "should return application/octet-stream" do
52
+ subject.default_image = "/test"
53
+ expect(subject.default_image_content_type).to eq "application/octet-stream"
54
+ end
55
+ end
56
+ end
57
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: social-avatar-proxy
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -126,6 +126,7 @@ files:
126
126
  - lib/social_avatar_proxy.rb
127
127
  - lib/social_avatar_proxy/app.rb
128
128
  - lib/social_avatar_proxy/avatar.rb
129
+ - lib/social_avatar_proxy/config.rb
129
130
  - lib/social_avatar_proxy/engine.rb
130
131
  - lib/social_avatar_proxy/facebook_avatar.rb
131
132
  - lib/social_avatar_proxy/path_helpers.rb
@@ -136,9 +137,11 @@ files:
136
137
  - lib/social_avatar_proxy/twitter_avatar.rb
137
138
  - lib/social_avatar_proxy/version.rb
138
139
  - social-avatar-proxy.gemspec
140
+ - spec/fixtures/image.jpg
139
141
  - spec/internal/config/routes.rb
140
142
  - spec/social_avatar_proxy/app_spec.rb
141
143
  - spec/social_avatar_proxy/avatar_spec.rb
144
+ - spec/social_avatar_proxy/config_spec.rb
142
145
  - spec/social_avatar_proxy/engine_spec.rb
143
146
  - spec/social_avatar_proxy/facebook_avatar_spec.rb
144
147
  - spec/social_avatar_proxy/path_helpers_spec.rb
@@ -173,9 +176,11 @@ signing_key:
173
176
  specification_version: 3
174
177
  summary: This gem acts as a proxy for avatars on Twitter & Facebook.
175
178
  test_files:
179
+ - spec/fixtures/image.jpg
176
180
  - spec/internal/config/routes.rb
177
181
  - spec/social_avatar_proxy/app_spec.rb
178
182
  - spec/social_avatar_proxy/avatar_spec.rb
183
+ - spec/social_avatar_proxy/config_spec.rb
179
184
  - spec/social_avatar_proxy/engine_spec.rb
180
185
  - spec/social_avatar_proxy/facebook_avatar_spec.rb
181
186
  - spec/social_avatar_proxy/path_helpers_spec.rb