From 3883188dcda9b01ce5171ab8bf33e1db5586e482 Mon Sep 17 00:00:00 2001 From: Michael Ball Date: Tue, 14 Jul 2020 21:06:15 -0700 Subject: [PATCH] Support Users Directly Uploading Profile Pictures. * Adds a `picture` attribute to `User`. * Preserves Gravatar as a fallback option. * Now, you should use `user.profile_picturer` instead of `gravatar_url` * TODO: Ensure `profile_picture` handles sizing right for uploaded images. --- app/controllers/users_controller.rb | 8 ++++---- app/models/user.rb | 12 ++++++++++++ app/views/admin/conferences/_top_submitter.html.haml | 2 +- app/views/conference_registrations/show.html.haml | 4 ++-- app/views/conferences/_highlights.haml | 2 +- app/views/layouts/_navigation.html.haml | 2 +- app/views/proposals/show.html.haml | 6 +++--- app/views/schedules/_event.html.haml | 2 +- app/views/schedules/_schedule_item.html.haml | 3 +-- app/views/users/edit.html.haml | 10 +++++++++- app/views/users/show.html.haml | 2 +- db/migrate/20200715034647_add_picture_to_users.rb | 5 +++++ db/schema.rb | 3 ++- 13 files changed, 43 insertions(+), 18 deletions(-) create mode 100644 db/migrate/20200715034647_add_picture_to_users.rb diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 3db62d11..678c1901 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -24,8 +24,8 @@ class UsersController < ApplicationController private - # Only allow a trusted parameter "white list" through. - def user_params - params.require(:user).permit(:name, :biography, :nickname, :affiliation) - end + def user_params + params.require(:user).permit(:name, :biography, :nickname, :affiliation, + :picture, :picture_cache) + end end diff --git a/app/models/user.rb b/app/models/user.rb index f6d62de3..4ff39043 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -23,9 +23,13 @@ class User < ApplicationRecord has_paper_trail on: [:create, :update], ignore: [:sign_in_count, :remember_created_at, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip, :last_sign_in_ip, :unconfirmed_email, :avatar_content_type, :avatar_file_size, :avatar_updated_at, :updated_at, :confirmation_sent_at, :confirmation_token, :reset_password_token] + # A user may have an uploaded avatar or use gravatar. + # The uploaded picture takes precedence. include Gravtastic gravtastic size: 32 + mount_uploader :picture, PictureUploader, mount_on: :picture + before_create :setup_role after_save :touch_events @@ -151,6 +155,14 @@ class User < ApplicationRecord ticket_purchases.find_by(conference_id: conference.id).present? end + ## + # Returns a user's profile picture URL. + # Partials should *not* directly call `gravatar_url` + def profile_picture(opts) + # TODO: Figure out how to align sizes? + picture.thumb.url || gravatar_url(opts) + end + def self.for_ichain_username(username, attributes) user = find_by(username: username) diff --git a/app/views/admin/conferences/_top_submitter.html.haml b/app/views/admin/conferences/_top_submitter.html.haml index 9f220249..b4f714fd 100644 --- a/app/views/admin/conferences/_top_submitter.html.haml +++ b/app/views/admin/conferences/_top_submitter.html.haml @@ -6,7 +6,7 @@ - @top_submitter.each do |key, value| .row.top-submitter .col-md-2 - = image_tag(key.gravatar_url(size: '25'), title: "Yo #{key.name}!", alt: '', 'class' => 'img-circle img-responsive text-center') + = image_tag(key.profile_picture(size: '25'), title: "Yo #{key.name}!", alt: '', 'class' => 'img-circle img-responsive text-center') .col-md-10 %h4 = link_to key.name, admin_user_path(key) diff --git a/app/views/conference_registrations/show.html.haml b/app/views/conference_registrations/show.html.haml index a5663ef1..49cca609 100644 --- a/app/views/conference_registrations/show.html.haml +++ b/app/views/conference_registrations/show.html.haml @@ -145,7 +145,7 @@ Registered = word_pluralize(@conference.participants.count, 'Attendee') - @conference.participants.each do |participant| - = link_to image_tag(participant.gravatar_url(size: '25'), title: "#{participant.name}!", class: 'img-circle'), user_path(participant) + = link_to image_tag(participant.profile_picture(size: '25'), title: "#{participant.name}!", class: 'img-circle'), user_path(participant) .col-md-4.col-md-offset-2 - if @conference.program.speakers.confirmed.any? %h4 @@ -156,4 +156,4 @@ Confirmed = word_pluralize(@conference.program.speakers.confirmed.count, 'Speaker') - @conference.program.speakers.confirmed.each do |speaker| - = link_to image_tag(speaker.gravatar_url(size: '25'), title: "#{speaker.name}!", class: 'img-circle'), user_path(speaker) + = link_to image_tag(speaker.profile_picture(size: '25'), title: "#{speaker.name}!", class: 'img-circle'), user_path(speaker) diff --git a/app/views/conferences/_highlights.haml b/app/views/conferences/_highlights.haml index b44a24b1..4b2f601c 100644 --- a/app/views/conferences/_highlights.haml +++ b/app/views/conferences/_highlights.haml @@ -11,7 +11,7 @@ = link_to(conference_program_proposal_path(conference_id, event), class: 'thumbnail') do - = image_tag speaker.gravatar_url(size: 300), + = image_tag speaker.profile_picture(size: 300), class: ['img-responsive', 'img-circle'], title: speaker.name .caption diff --git a/app/views/layouts/_navigation.html.haml b/app/views/layouts/_navigation.html.haml index 794caa96..97779a45 100644 --- a/app/views/layouts/_navigation.html.haml +++ b/app/views/layouts/_navigation.html.haml @@ -29,7 +29,7 @@ %li.dropdown %a.dropdown-toggle{"data-toggle" => "dropdown", href: '#', id: "current-user-detail"} = current_user.name - = image_tag(current_user.gravatar_url(size: '18'), title: "Yo #{current_user.name}!", alt: '') + = image_tag(current_user.profile_picture(size: '18'), title: "Yo #{current_user.name}!", alt: '') %b.caret %ul.dropdown-menu = render 'layouts/user_menu' diff --git a/app/views/proposals/show.html.haml b/app/views/proposals/show.html.haml index 217a76b3..0de85205 100644 --- a/app/views/proposals/show.html.haml +++ b/app/views/proposals/show.html.haml @@ -4,8 +4,8 @@ %meta{ property: "og:description", content: @event.abstract } %meta{ property: "og:site_name", content: (ENV['OSEM_NAME'] || 'OSEM') } - if @speakers_ordered.any? - %meta{ property: "og:image", content: @speakers_ordered.first.gravatar_url } - %meta{ property: "og:image:secure_url", content: @speakers_ordered.first.gravatar_url } + %meta{ property: "og:image", content: @speakers_ordered.first.profile_picture } + %meta{ property: "og:image:secure_url", content: @speakers_ordered.first.profile_picture } .container .row.page-header @@ -37,7 +37,7 @@ .speakerinfo .row .col-md-4 - = image_tag speaker.gravatar_url(:size => 120), class: 'img-responsive img-rounded' + = image_tag speaker.profile_picture(:size => 120), class: 'img-responsive img-rounded' .col-md-8 %h4 = link_to speaker.name, user_path(speaker.id) diff --git a/app/views/schedules/_event.html.haml b/app/views/schedules/_event.html.haml index 601afdf5..7ec7122f 100644 --- a/app/views/schedules/_event.html.haml +++ b/app/views/schedules/_event.html.haml @@ -1,7 +1,7 @@ .panel.panel-default.event-panel{ onClick: 'eventClicked(event, this);', "data-url" => "#{url_for(conference_program_proposal_path(@conference.short_title, event.id))}" } .panel-body - event.speakers_ordered.each do |speaker| - = image_tag speaker.gravatar_url, :class => "img-circle pull-right all-speaker-pic", | + = image_tag speaker.profile_picture, :class => "img-circle pull-right all-speaker-pic", | :alt => speaker.name, | :title => speaker.name | diff --git a/app/views/schedules/_schedule_item.html.haml b/app/views/schedules/_schedule_item.html.haml index b6d8708e..e00d9a38 100644 --- a/app/views/schedules/_schedule_item.html.haml +++ b/app/views/schedules/_schedule_item.html.haml @@ -10,8 +10,7 @@ = event.title - event.speakers_ordered.each do |speaker| - = image_tag speaker.gravatar_url, :class => "img-circle pull-right speaker-pic", | + = image_tag speaker.profile_picture, :class => "img-circle pull-right speaker-pic", | :alt => speaker.name, | :title => speaker.name, | :style => "height: #{ speaker_height(@rooms) }px; width: #{ speaker_width(@rooms) }px;" - diff --git a/app/views/users/edit.html.haml b/app/views/users/edit.html.haml index 52c0d57f..73d4f4b1 100644 --- a/app/views/users/edit.html.haml +++ b/app/views/users/edit.html.haml @@ -10,8 +10,16 @@ = f.input :nickname, as: :string, hint: 'This is how the other users see you, not your real name' .control-label = "Avatar" - = image_tag(@user.gravatar_url(size: '48'), title: "Yo #{@user.name}!", alt: '') + = image_tag(@user.profile_picture(size: '48'), title: "Yo #{@user.name}!", alt: '') = link_to 'Change your avatar here', 'https://gravatar.com' + %br + %p + Or upload a picture. + = image_tag f.object.picture.thumb.url if f.object.picture? + - if @user.picture? + = image_tag(@user.picture.thumb.url, width: '20%') + = f.input :picture, hint: 'If you upload a picture, it will be used in place of Gravatar.' + = f.input :affiliation, as: :string, hint: 'This could be a company, a user group, or nothing at all.' = f.input :biography, input_html: { rows: 5, data: { provide: 'markdown' } }, diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index b20891f8..65f8e853 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -3,7 +3,7 @@ .col-md-12 .page-header %h1 - = image_tag(@user.gravatar_url(size: '48'), title: "Yo #{@user.name}!", alt: '') + = image_tag(@user.profile_picture(size: '48'), title: "Yo #{@user.name}!", alt: '') = @user.name %small = @user.nickname diff --git a/db/migrate/20200715034647_add_picture_to_users.rb b/db/migrate/20200715034647_add_picture_to_users.rb new file mode 100644 index 00000000..ec529882 --- /dev/null +++ b/db/migrate/20200715034647_add_picture_to_users.rb @@ -0,0 +1,5 @@ +class AddPictureToUsers < ActiveRecord::Migration[5.2] + def change + add_column :users, :picture, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 07effdca..a29ab329 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2020_07_15_001812) do +ActiveRecord::Schema.define(version: 2020_07_15_034647) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -591,6 +591,7 @@ ActiveRecord::Schema.define(version: 2020_07_15_001812) do t.boolean "is_admin", default: false t.string "username" t.boolean "is_disabled", default: false + t.string "picture" t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true t.index ["email"], name: "index_users_on_email", unique: true t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true