Skip to content

Commit

Permalink
Merge pull request #149 from loftwah/dl/default-avatar-bug
Browse files Browse the repository at this point in the history
Dl/default avatar bug
  • Loading branch information
loftwah authored Sep 14, 2024
2 parents 98c7406 + f8f1a5c commit 732125b
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 99 deletions.
29 changes: 18 additions & 11 deletions app/models/user.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# app/models/user.rb
class User < ApplicationRecord

FALLBACK_AVATAR_URL = 'https://pbs.twimg.com/profile_images/1581014308397502464/NPogKMyk_400x400.jpg'

attr_accessor :invite_code
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
Expand Down Expand Up @@ -40,33 +43,37 @@ def generate_open_graph_image
end

def download_and_store_avatar
return if avatar.blank?

if avatar.blank?
self.avatar = FALLBACK_AVATAR_URL
save(validate: false)
return
end

begin
avatar_dir = Rails.root.join('public', 'avatars')
FileUtils.mkdir_p(avatar_dir) unless File.directory?(avatar_dir)

uri = URI.parse(avatar)
filename = "#{username}_avatar#{File.extname(avatar)}"
filepath = File.join(avatar_dir, filename)

response = Net::HTTP.get_response(uri)
if response.is_a?(Net::HTTPSuccess)
File.open(filepath, 'wb') do |local_file|
local_file.write(response.body)
end
Rails.logger.info "Avatar downloaded for user #{username}"
else
Rails.logger.error "Failed to download avatar for user #{username}. HTTP Error: #{response.code} #{response.message}. Using default avatar."
self.avatar = 'greg.jpg' # Set to default avatar
save(validate: false) # Save without triggering validations
Rails.logger.error "Failed to download avatar for user #{username}. HTTP Error: #{response.code} #{response.message}. Using fallback avatar."
self.avatar = FALLBACK_AVATAR_URL
save(validate: false)
end
rescue StandardError => e
Rails.logger.error "Failed to download avatar for user #{username}: #{e.message}"
self.avatar = 'greg.jpg' # Set to default avatar
save(validate: false) # Save without triggering validations
Rails.logger.error "Failed to download avatar for user #{username}: #{e.message}. Using fallback avatar."
self.avatar = FALLBACK_AVATAR_URL
save(validate: false)
end
end
end

private

Expand Down
25 changes: 7 additions & 18 deletions app/services/open_graph_image_generator.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
# app/services/open_graph_image_generator.rb
class OpenGraphImageGenerator
IMAGE_WIDTH = 1200
IMAGE_HEIGHT = 630
AVATAR_SIZE = 200
BORDER_SIZE = 10
# Constants for sizes and paths
FALLBACK_AVATAR_URL = 'https://pbs.twimg.com/profile_images/1581014308397502464/NPogKMyk_400x400.jpg'

def initialize(user)
@user = user
Expand All @@ -14,7 +11,7 @@ def generate
output_path = Rails.root.join('public', 'uploads', 'og_images', "#{@user.username}_og.png")
image = MiniMagick::Image.open(template_path)

avatar = @user.avatar.present? ? download_image(@user.avatar) : default_avatar
avatar = @user.avatar.present? ? download_image(@user.avatar) : download_image(FALLBACK_AVATAR_URL)

# Resize avatar and add a white square border
avatar.resize "#{AVATAR_SIZE}x#{AVATAR_SIZE}"
Expand Down Expand Up @@ -64,23 +61,15 @@ def download_image(url)
tempfile.rewind
MiniMagick::Image.open(tempfile.path)
else
Rails.logger.error("Failed to download image from URL: #{url}. HTTP Error: #{response.code} #{response.message}. Using default avatar.")
MiniMagick::Image.open(default_avatar_path)
Rails.logger.error("Failed to download image from URL: #{url}. HTTP Error: #{response.code} #{response.message}.")
MiniMagick::Image.open(FALLBACK_AVATAR_URL)
end
rescue SocketError, Errno::ENOENT => e
Rails.logger.error("Failed to download image from URL: #{url}. Error: #{e.message}. Using default avatar.")
MiniMagick::Image.open(default_avatar_path)
Rails.logger.error("Failed to download image from URL: #{url}. Error: #{e.message}. Using fallback URL.")
MiniMagick::Image.open(FALLBACK_AVATAR_URL)
ensure
tempfile.close
tempfile.unlink # Unlink after we've processed the image
end
end

def default_avatar
MiniMagick::Image.open(default_avatar_path)
end

def default_avatar_path
ActionController::Base.helpers.asset_path('greg.jpg')
end
end
42 changes: 22 additions & 20 deletions app/views/analytics/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
<div class="bg-gray-800 rounded-lg shadow p-4">
<h2 class="text-xl font-semibold mb-4">Daily Views (Last 30 Days)</h2>
<%= line_chart @daily_views,
colors: ["#84CC16"],
colors: ["#3B82F6"],
library: {
backgroundColor: 'transparent',
legend: { display: false },
Expand Down Expand Up @@ -100,30 +100,32 @@
</div>
</div>

<!-- Top Visitor Locations (New Section) -->
<div class="bg-gray-800 rounded-lg shadow p-4 mb-6">
<h2 class="text-xl font-semibold mb-4">Top Visitor Locations</h2>
<div class="overflow-x-auto">
<table class="w-full text-sm text-center table-auto">
<thead class="text-xs uppercase bg-gray-700">
<tr>
<th scope="col" class="px-4 py-3 rounded-tl-lg">City</th>
<th scope="col" class="px-4 py-3">Country</th>
<th scope="col" class="px-4 py-3 rounded-tr-lg">Views</th>
</tr>
</thead>
<tbody>
<% @location_data.each_with_index do |location, index| %>
<!-- Top Visitor Locations (New Section) -->
<div class="bg-gray-800 rounded-lg shadow p-4 mb-6">
<h2 class="text-xl font-semibold mb-4">Top Visitor Locations</h2>
<div class="overflow-x-auto">
<table class="w-full text-sm text-center table-auto">
<thead class="text-xs uppercase bg-gray-700">
<tr>
<th scope="col" class="px-4 py-3 rounded-tl-lg">City</th>
<th scope="col" class="px-4 py-3">Country</th>
<th scope="col" class="px-4 py-3 rounded-tr-lg">Views</th>
</tr>
</thead>
<tbody>
<% @location_data.each_with_index do |location, index| %>
<% unless location[:city] == 'Unknown' && location[:country] == 'Unknown' %>
<tr class="<%= index.even? ? 'bg-gray-800' : 'bg-gray-900' %> border-b border-gray-700">
<td class="px-4 py-3"><%= location[:city] || 'Unknown' %></td>
<td class="px-4 py-3"><%= location[:country] || 'Unknown' %></td>
<td class="px-4 py-3"><%= location[:city].present? && location[:city] != 'Unknown' ? location[:city] : '' %></td>
<td class="px-4 py-3"><%= location[:country].present? && location[:country] != 'Unknown' ? location[:country] : '' %></td>
<td class="px-4 py-3"><%= number_with_delimiter(location[:count]) %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
<% end %>
</tbody>
</table>
</div>
</div>

<!-- Link Analytics Table -->
<div class="bg-gray-800 rounded-lg shadow p-4 mb-6">
Expand Down
62 changes: 21 additions & 41 deletions spec/controllers/users/registrations_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,55 +6,35 @@
end

describe "POST #create" do
let(:valid_attributes) {
{ email: "[email protected]", password: "password", password_confirmation: "password",
username: "testuser", full_name: "Test User", tags: "tag1,tag2", avatar_border: "white", invite_code: "POWEROVERWHELMING" }
}
let(:valid_attributes) {
{ email: "[email protected]", password: "password", password_confirmation: "password",
username: "testuser", full_name: "Test User", tags: "tag1,tag2", avatar_border: "white", invite_code: "POWEROVERWHELMING" }
}

context "when sign-ups are enabled" do
before do
allow(Rails.application.config).to receive(:sign_ups_open).and_return(true)
end

it "creates a new User" do
expect {
post :create, params: { user: valid_attributes }
}.to change(User, :count).by(1)
end
context "when sign-ups are enabled" do
before do
allow(Rails.application.config).to receive(:sign_ups_open).and_return(true)
end

it "correctly processes tags" do
it "creates a new User" do
expect {
post :create, params: { user: valid_attributes }
user = User.last
tags = user.tags.is_a?(String) ? JSON.parse(user.tags) : user.tags
expect(tags).to eq(["tag1", "tag2"])
end
}.to change(User, :count).by(1)
end

context "when sign-ups are disabled" do
before do
allow(Rails.application.config).to receive(:sign_ups_open).and_return(false)
end

it "does not create a new User without a valid invite code and redirects to root path" do
invalid_attributes = valid_attributes.merge(invite_code: "INVALIDCODE")
expect {
post :create, params: { user: invalid_attributes }
}.not_to change(User, :count)
expect(response).to redirect_to(root_path)
expect(flash[:alert]).to eq("Sign-ups are currently disabled.")
end

it "creates a new User with a valid invite code" do
expect(controller).to receive(:after_sign_up_path_for).with(instance_of(User)).and_return("/path/to/redirect")
it "sets the fallback avatar URL if none is provided" do
post :create, params: { user: valid_attributes.merge(avatar: nil) }
user = User.last
expect(user.avatar).to eq('https://pbs.twimg.com/profile_images/1581014308397502464/NPogKMyk_400x400.jpg')
end

expect {
post :create, params: { user: valid_attributes }
}.to change(User, :count).by(1)

expect(response).to redirect_to("/path/to/redirect")
end
it "handles invalid avatar URLs and sets the fallback URL" do
post :create, params: { user: valid_attributes.merge(avatar: 'http://invalid-url.com/avatar.jpg') }
user = User.last
expect(user.avatar).to eq('https://pbs.twimg.com/profile_images/1581014308397502464/NPogKMyk_400x400.jpg')
end
end
end

describe "PUT #update" do
let(:user) { create(:user, tags: ["old_tag1", "old_tag2"].to_json) }
Expand Down
16 changes: 8 additions & 8 deletions spec/models/user_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,18 @@
end

describe 'callbacks' do
it 'does not generate open graph image in test environment' do
user = build(:user)
expect(OpenGraphImageGenerator).not_to receive(:new)
it 'uses the fallback avatar URL when no avatar is provided' do
user = build(:user, avatar: nil)
user.save
expect(user.avatar).to eq(User::FALLBACK_AVATAR_URL)
end

it 'downloads and stores avatar after save' do
user = build(:user, avatar: 'http://example.com/avatar.jpg')
expect(user).to receive(:download_and_store_avatar)

it 'handles invalid avatar URLs and falls back to default' do
user = build(:user, avatar: 'http://invalid-url.com/avatar.jpg')
user.save
expect(user.avatar).to eq(User::FALLBACK_AVATAR_URL)
end
end
end

describe '#parsed_tags' do
it 'returns parsed JSON when tags is a valid JSON string' do
Expand Down
6 changes: 5 additions & 1 deletion spec/rails_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,12 @@
Rake::Task['assets:precompile'].invoke
end

# Clean up uploaded files after each test
# Clean up uploaded files and generated avatars after each test
config.after(:each) do
# Clean up the avatars generated during tests
FileUtils.rm_rf(Dir["#{Rails.root}/public/avatars"])

# Clean up other uploaded files
FileUtils.rm_rf(Dir["#{Rails.root}/spec/support/uploads"])
end

Expand Down

0 comments on commit 732125b

Please sign in to comment.