Skip to content

Commit

Permalink
Merge pull request hotsh#647 from carols10cents/avatar_fixes
Browse files Browse the repository at this point in the history
Adds avatar illustration to profile page.

This addition makes it easier for people to understand how their profile picture is used and displayed. For twitter authorizations, the avatar is linked to that account. For emails, it is linked to gravatar. If neither are used, a default avatar appears.

This visualization of this process in the profile screen will allow users to see their current avatar and suggest how to change it with an easy statement to enter their email and a button to gravatar to make the changes.

closes hotsh#617
  • Loading branch information
wilkie committed Sep 28, 2012
2 parents 02d7a08 + c986d28 commit 626f1fa
Show file tree
Hide file tree
Showing 6 changed files with 271 additions and 148 deletions.
22 changes: 22 additions & 0 deletions app/assets/stylesheets/content.scss.erb
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,28 @@
@include content-block;
}

.avatar {
.avatar-management {
@include clearfix;
img {
vertical-align: middle;
width: 48px;
}
.description {
margin-left: 10px;
}
form {
float: right;
margin-top: 7px;
margin-bottom: 0;
}
.button {
float: right;
margin-top: 7px;
}
}
}

.linked-accounts {
.linked {
@include clearfix;
Expand Down
11 changes: 11 additions & 0 deletions app/controllers/avatar_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Avatar management
class AvatarController < ApplicationController
before_filter :require_user

# Let the user remove the avatar that was saved as their author.image_url
# in case they'd rather use a gravatar with their email address
def destroy
current_user.author.unset(:image_url)
redirect_to edit_user_path(current_user)
end
end
21 changes: 21 additions & 0 deletions app/views/users/edit.haml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,27 @@
%input.button{:type => "submit", :value => "Save"}

- content_for :bottom do
.avatar.bottom-block
%h4 Avatar
.avatar-management
- if @user.author.image_url.present?
= image_tag(@user.author.avatar_url, :class => "photo user-image", :alt => "avatar")
%span.description
Saved from a linked account
= form_tag(avatar_path(@user.author), :method => "delete", :name => "avatar_delete_form", :id => "avatar-delete") do
%input.button.destructive_action{:type => "submit", :value => "Remove Avatar"}
- elsif @user.author.email.present?
= image_tag(@user.author.avatar_url, :class => "photo user-image", :alt => "avatar")
%span.description
= "Gravatar using #{@user.author.email}"
= link_to "Go to Gravatar to change", Author::GRAVATAR_SIGNUP, :class => "button"
- else
= image_tag(asset_path(RstatUs::DEFAULT_AVATAR), :class => "photo user-image", :alt => "avatar")
%span.description
= "Add an email to your profile above in order to use "
= link_to("Gravatar", Author::GRAVATAR_SIGNUP)
= " to set a custom avatar!"

.linked-accounts.bottom-block
%h4 Linked Accounts

Expand Down
11 changes: 8 additions & 3 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,24 @@
# Users
match 'users/:id.:format', :to => "users#show", :constraints => { :id => /[^\/]+/, :format => /json/ }
resources :users, :constraints => { :id => /[^\/]+/ }
match 'users/:id/confirm_delete', :to => "users#confirm_delete", :constraints => { :id => /[^\/]+/ }, :as => "account_deletion_confirmation", :via => :get
match "users/:id/feed", :to => "users#feed", :as => "user_feed", :constraints => { :id => /[^\/]+/ }

# other new route?
match 'users/:id/followers', :to => "users#followers", :constraints => { :id => /[^\/]+/ }, :as => "followers"
match 'users/:id/following', :to => "users#following", :constraints => { :id => /[^\/]+/ }, :as => "following"

# Users - manage avatar
match '/users/:username/avatar', :via => :delete, :to => "avatar#destroy", :constraints => {:username => /[^\/]+/ }, :as => "avatar"

# Users - confirm email
match 'confirm_email/:token', :to => "users#confirm_email"

# Users - forgot/reset password
match 'forgot_password', :to => "users#forgot_password_new", :via => :get, :as => "forgot_password"
match 'forgot_password', :to => "users#forgot_password_create", :via => :post
match 'forgot_password_confirm', :to => "users#forgot_password_confirm", :via => :get, :as => "forgot_password_confirm"
match 'reset_password', :to => "users#reset_password_new", :via => :get
match 'reset_password', :to => "users#reset_password_create", :via => :post
match 'reset_password/:token', :to => "users#reset_password_with_token", :via => :get, :as => "reset_password"
match 'users/:id/confirm_delete', :to => "users#confirm_delete", :constraints => { :id => /[^\/]+/ }, :as => "account_deletion_confirmation", :via => :get

# Updates
resources :updates, :only => [:index, :show, :create, :destroy]
Expand Down
209 changes: 209 additions & 0 deletions test/acceptance/edit_profile_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
require_relative 'acceptance_helper'

describe "edit profile" do
include AcceptanceHelper

describe "logged in" do
before do
Pony.deliveries.clear
log_in_as_some_user
end

it "has a link to edit your own profile" do
visit "/users/#{@u.username}"

assert has_link? "Edit"
end

attributes_without_confirmation = {"name" => "Mark Zuckerberg",
"website" => "http://test.com",
"bio" => "To be or not to be"}

attributes_without_confirmation.each do |key, value|
it "updates your #{key}" do
visit "/users/#{@u.username}/edit"
fill_in key, :with => value

VCR.use_cassette("update_profile_#{key}") do
click_button "Save"
end

within profile(key) do
assert has_content?(value), "Cannot find #{key} with text #{value}"
end
end
end

it "updates your password successfully" do
visit "/users/#{@u.username}/edit"

fill_in "password", :with => "new_password"
fill_in "password_confirm", :with => "new_password"

VCR.use_cassette("update_profile_password") do
click_button "Save"
end

within profile "name" do
assert has_content?(@u.author.name), "Password update failed"
end
end

it "does not update your password if the confirmation doesn't match" do
visit "/users/#{@u.username}/edit"
fill_in "password", :with => "new_password"
fill_in "password_confirm", :with => "bunk"

VCR.use_cassette("update_profile_password_mismatch") do
click_button "Save"
end

within flash do
assert has_content?("Profile could not be saved: Passwords must match")
end

assert has_field?("password")
end

it "verifies your email if you change it" do
visit "/users/#{@u.username}/edit"
email = "new_email@new_email.com"
fill_in "email", :with => email

VCR.use_cassette('update_profile_email') do
click_button "Save"
end

within profile "name" do
assert has_content? @u.author.name
end

assert_equal 1, Pony.deliveries.size
end

it "does not verify your email if you havent specified one" do
user_without_email = Fabricate(:user, :email => nil, :username => "no_email")
a = Fabricate(:authorization, :user => user_without_email)

log_in(user_without_email, a.uid)
visit "/users/#{user_without_email.username}/edit"
name = "Mark Zuckerberg"
fill_in "name", :with => name

VCR.use_cassette('update_profile_no_email') do
click_button "Save"
end

within profile "name" do
assert has_content? name
end

assert Pony.deliveries.empty?
end

it "does not verify your email if you havent changed it" do
visit "/users/#{@u.username}/edit"
name = "Steve Jobs"
fill_in "name", :with => name

VCR.use_cassette('update_profile_no_email') do
click_button "Save"
end

within profile "name" do
assert has_content? name
end

assert Pony.deliveries.empty?
end

describe "avatar" do
describe "with image_url" do
before do
@u.author.image_url = "https://example.com/avatar.png"
@u.author.save
visit "/users/#{@u.username}/edit"
end

it "shows you the avatar whose URL came from twitter" do
within ".avatar .avatar-management" do
assert has_selector?(:xpath, "//img[@src='https://example.com/avatar.png']")
assert has_content?("Saved from a linked account")
end
end

it "lets you remove that avatar from your account" do
within ".avatar .avatar-management" do
click_button "Remove Avatar"
end

within ".avatar .avatar-management" do
assert has_no_selector?(:xpath, "//img[@src='https://example.com/avatar.png']")
end
end
end

describe "with email" do
before do
@u.author.email = "[email protected]"
@u.author.save
visit "/users/#{@u.username}/edit"
end

it "shows you the gravatar with your email address" do
within ".avatar .avatar-management" do
assert has_selector?(:xpath, "//img[@src='#{@u.author.gravatar_url}']")
assert has_content?("Gravatar using [email protected]")
assert has_link?("Go to Gravatar to change")
end
end
end

describe "with neither image_url nor email" do
before do
@u.author.email = ""
@u.author.save
visit "/users/#{@u.username}/edit"
end

it "says you should add an email address and use gravatar" do
within ".avatar .avatar-management" do
assert has_selector?(:xpath, "//img[contains(@src, '#{RstatUs::DEFAULT_AVATAR}')]")
assert has_content?("Add an email to your profile above")
end
end
end
end

it "does let you update your profile even if you use a different case in the url" do
u = Fabricate(:user, :username => "LADY_GAGA")
a = Fabricate(:authorization, :user => u)
log_in(u, a.uid)
visit "/users/lady_gaga/edit"
bio_text = "To be or not to be"
fill_in "bio", :with => bio_text

VCR.use_cassette('update_profile_different_case') do
click_button "Save"
end

within profile "bio" do
assert has_content? bio_text
end
end

it "doesn't let you update someone else's profile" do
u = Fabricate(:user)
visit "/users/#{u.username}/edit"
assert_match /\/users\/#{u.username}$/, page.current_url
end
end

describe "logged out" do
it "doesn't let a logged out user update someone's profile" do
u = Fabricate(:user)
visit "/users/#{u.username}/edit"
page.current_url.wont_match(/\/users\/#{u.username}\/edit/)
end
end
end
Loading

0 comments on commit 626f1fa

Please sign in to comment.