From 3883188dcda9b01ce5171ab8bf33e1db5586e482 Mon Sep 17 00:00:00 2001 From: Michael Ball Date: Tue, 14 Jul 2020 21:06:15 -0700 Subject: [PATCH 1/4] 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 From 10d58ef050a4cb46bb7c9f11849edd8e8b8ff981 Mon Sep 17 00:00:00 2001 From: Michael Ball Date: Wed, 15 Jul 2020 23:27:22 -0700 Subject: [PATCH 2/4] Support selecting various sizes of profile pics --- app/assets/stylesheets/osem.scss | 5 +++++ app/models/user.rb | 14 +++++++++++--- app/uploaders/picture_uploader.rb | 4 ++++ app/views/layouts/_navigation.html.haml | 2 +- app/views/users/edit.html.haml | 9 +++++---- 5 files changed, 26 insertions(+), 8 deletions(-) diff --git a/app/assets/stylesheets/osem.scss b/app/assets/stylesheets/osem.scss index bcf37d4f..7b913fe6 100644 --- a/app/assets/stylesheets/osem.scss +++ b/app/assets/stylesheets/osem.scss @@ -51,6 +51,11 @@ body { margin: 0 auto; } +nav #current-user-detail .profile-thumnail { + max-height: 20px; + max-width: 20px; +} + /* centered columns styles */ .row-centered { text-align:center; diff --git a/app/models/user.rb b/app/models/user.rb index 4ff39043..8d5a935c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -158,9 +158,17 @@ class User < ApplicationRecord ## # 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) + def profile_picture(opts = {}) + return gravatar_url(opts) unless picture.present? + puts "ASKED FOR PROFILE PIC!! #{opts[:size]}" + size = (opts[:size] || 0).to_i + if size < 50 + picture.tiny.url + elsif size <= 100 + picture.thumb.url + else + picture.large.url + end end def self.for_ichain_username(username, attributes) diff --git a/app/uploaders/picture_uploader.rb b/app/uploaders/picture_uploader.rb index 4cad1594..47e86f8b 100644 --- a/app/uploaders/picture_uploader.rb +++ b/app/uploaders/picture_uploader.rb @@ -62,6 +62,10 @@ class PictureUploader < CarrierWave::Uploader::Base process resize_to_fit: [100, 100] end + version :tiny do + process resize_to_fit: [32, 32] + end + version :first, if: :sponsor? version :first do process resize_and_pad: [320, 180, 'white'] diff --git a/app/views/layouts/_navigation.html.haml b/app/views/layouts/_navigation.html.haml index 97779a45..239c053f 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.profile_picture(size: '18'), title: "Yo #{current_user.name}!", alt: '') + = image_tag(current_user.profile_picture(size: '18'), class: 'profile-thumbnail', alt: '') %b.caret %ul.dropdown-menu = render 'layouts/user_menu' diff --git a/app/views/users/edit.html.haml b/app/views/users/edit.html.haml index 73d4f4b1..e5235099 100644 --- a/app/views/users/edit.html.haml +++ b/app/views/users/edit.html.haml @@ -12,13 +12,14 @@ = "Avatar" = 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.' + - if @user.picture? + %p + Current Picture + %br + = image_tag(@user.picture.thumb.url, width: '20%') = f.input :affiliation, as: :string, hint: 'This could be a company, a user group, or nothing at all.' From d5a9b79f6e50a3fae48833cd07ab2b9104da987b Mon Sep 17 00:00:00 2001 From: Michael Ball Date: Wed, 15 Jul 2020 23:37:40 -0700 Subject: [PATCH 3/4] Show profile pictures to admins and allow them to upload pics --- app/controllers/admin/users_controller.rb | 3 ++- app/models/user.rb | 1 - app/views/admin/users/_form.html.haml | 12 ++++++++++++ app/views/admin/users/show.html.haml | 3 +++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 4d7925dd..e49c02f5 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -43,7 +43,8 @@ module Admin # Variable @show_attributes holds the attributes that are visible for the 'show' action # If you want to change the attributes that are shown in the 'show' action of users # add/remove the attributes in the following string array - @show_attributes = %w(name email username nickname affiliation biography registered attended roles created_at + @show_attributes = %w(name email username nickname affiliation biography + profile_picture registered attended roles created_at updated_at sign_in_count current_sign_in_at last_sign_in_at current_sign_in_ip last_sign_in_ip) end diff --git a/app/models/user.rb b/app/models/user.rb index 8d5a935c..1a2b19b1 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -160,7 +160,6 @@ class User < ApplicationRecord # Partials should *not* directly call `gravatar_url` def profile_picture(opts = {}) return gravatar_url(opts) unless picture.present? - puts "ASKED FOR PROFILE PIC!! #{opts[:size]}" size = (opts[:size] || 0).to_i if size < 50 picture.tiny.url diff --git a/app/views/admin/users/_form.html.haml b/app/views/admin/users/_form.html.haml index 7604f0d3..845065dc 100644 --- a/app/views/admin/users/_form.html.haml +++ b/app/views/admin/users/_form.html.haml @@ -19,6 +19,18 @@ = f.input :username, :as => :string if @user.new_record? = f.input :email = f.input :password if @user.new_record? + .control-label + Gravatar + = image_tag(@user.profile_picture(size: '48'), alt: '') + %p + Or upload a picture. + = f.input :picture, hint: 'If you upload a picture, it will be used in place of Gravatar.' + - if @user.picture? + %p + Current Picture + %br + = image_tag(@user.picture.url, width: '20%') + = f.input :affiliation, as: :string = f.input :biography, input_html: { rows: 10, data: { provide: 'markdown' } }, hint: markdown_hint diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index c9048be4..b90e72d9 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -26,6 +26,9 @@ - elsif attr == 'biography' %td = markdown(@user.biography) + - elsif attr == 'profile_picture' + %td + = image_tag @user.profile_picture(size: '100'), alt: '' - elsif attr == 'email' %td = @user.send(attr) From 43c0d4a3f5cd9f45ac8fbeb7fe6a75a935ead2a5 Mon Sep 17 00:00:00 2001 From: Michael Ball Date: Thu, 16 Jul 2020 00:32:32 -0700 Subject: [PATCH 4/4] I think this fixes a bug in changing conference times --- app/models/conference.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/conference.rb b/app/models/conference.rb index b4b19e2c..c91939ae 100644 --- a/app/models/conference.rb +++ b/app/models/conference.rb @@ -127,7 +127,7 @@ class Conference < ApplicationRecord event_schedules = program.event_schedules.select do |event_schedule| event_schedule.start_time.hour < start_hour || event_schedule.end_time.hour > end_hour || - (event_schedule.end_time.hour == end_hour && event_schedule.end_time.minute > 0) + (event_schedule.end_time.hour == end_hour && event_schedule.end_time.min > 0) end event_schedules.each(&:destroy) end