Merge pull request #93 from Retrospring/carrierwave

This commit is contained in:
Dominik M. Kwiatek 2020-05-22 19:10:32 +01:00 committed by GitHub
commit bb4f105017
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 251 additions and 107 deletions

View File

@ -28,8 +28,6 @@ gem 'bootstrap_form'
gem 'font-kit-rails'
gem 'nprogress-rails'
gem 'font-awesome-rails', '~> 4.7.0'
gem "paperclip", "~> 5.2"
gem 'delayed_paperclip'
gem 'fog-core'
gem 'fog-aws'
gem 'fog-local'
@ -39,6 +37,9 @@ gem 'bootstrap4-datetime-picker-rails'
gem 'tiny-color-rails'
gem 'jquery-minicolors-rails'
gem 'colorize'
gem 'carrierwave', '~> 2.0'
gem 'carrierwave_backgrounder', git: 'https://github.com/mltnhm/carrierwave_backgrounder.git'
gem 'mini_magick'
gem "rolify", "~> 5.2"
@ -79,6 +80,7 @@ group :development do
gem 'spring', '~> 2.0'
gem 'byebug'
gem 'web-console', '< 4.0.0'
gem 'binding_of_caller'
end
gem 'puma'

View File

@ -10,6 +10,14 @@ GIT
oauth
simple_oauth
GIT
remote: https://github.com/mltnhm/carrierwave_backgrounder.git
revision: 8fe468957f047ad7039f07679e5952a534d07b6d
specs:
carrierwave_backgrounder (0.4.2)
carrierwave (>= 0.5, <= 2.1)
mime-types (>= 3.0.0)
GIT
remote: https://github.com/retrospring/questiongenerator.git
revision: c5f8362ff769425d42a94b3a611731eadaa5e0ca
@ -77,6 +85,8 @@ GEM
erubi (>= 1.0.0)
rack (>= 0.9.0)
bindex (0.8.1)
binding_of_caller (0.8.0)
debug_inspector (>= 0.0.1)
bootstrap (4.4.1)
autoprefixer-rails (>= 9.1.0)
popper_js (>= 1.14.3, < 2)
@ -100,7 +110,13 @@ GEM
rack-test (>= 0.6.3)
regexp_parser (~> 1.5)
xpath (~> 3.2)
climate_control (0.2.0)
carrierwave (2.1.0)
activemodel (>= 5.0.0)
activesupport (>= 5.0.0)
addressable (~> 2.6)
image_processing (~> 1.1)
mimemagic (>= 0.3.0)
mini_mime (>= 0.1.3)
cliver (0.3.2)
coderay (1.1.2)
coffee-rails (4.2.2)
@ -115,9 +131,7 @@ GEM
connection_pool (2.2.2)
crass (1.0.6)
database_cleaner (1.8.4)
delayed_paperclip (3.0.1)
activejob (>= 4.2)
paperclip (>= 3.3)
debug_inspector (0.0.3)
devise (4.7.1)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
@ -221,8 +235,10 @@ GEM
concurrent-ruby (~> 1.0)
i18n-js (3.0.0.rc10)
i18n (~> 0.6)
image_processing (1.10.3)
mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.17, < 3)
ipaddress (0.8.3)
jaro_winkler (1.5.4)
jbuilder (2.10.0)
activesupport (>= 5.0.0)
jquery-minicolors-rails (2.2.6.2)
@ -272,6 +288,7 @@ GEM
mime-types-data (~> 3.2015)
mime-types-data (3.2019.1009)
mimemagic (0.3.4)
mini_magick (4.10.1)
mini_mime (1.0.2)
mini_portile2 (2.4.0)
minitest (5.14.0)
@ -309,12 +326,6 @@ GEM
omniauth-oauth (~> 1.1)
rack
orm_adapter (0.5.0)
paperclip (5.3.0)
activemodel (>= 4.2.0)
activesupport (>= 4.2.0)
mime-types
mimemagic (~> 0.3.0)
terrapin (~> 0.6.0)
parallel (1.19.1)
parser (2.7.1.2)
ast (~> 2.4.0)
@ -423,8 +434,7 @@ GEM
rspec-core (~> 3.0, >= 3.0.0)
sidekiq (>= 2.4.0)
rspec-support (3.9.2)
rubocop (0.82.0)
jaro_winkler (~> 1.5.1)
rubocop (0.83.0)
parallel (~> 1.10)
parser (>= 2.7.0.1)
rainbow (>= 2.2.2, < 4.0)
@ -432,6 +442,8 @@ GEM
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 2.0)
ruby-progressbar (1.10.1)
ruby-vips (2.0.17)
ffi (~> 1.9)
sanitize (5.1.0)
crass (~> 1.0.2)
nokogiri (>= 1.8.0)
@ -483,8 +495,6 @@ GEM
railties (>= 3.1.0)
sysexits (1.2.0)
temple (0.8.2)
terrapin (0.6.0)
climate_control (>= 0.0.3, < 1.0)
thor (1.0.1)
thread_safe (0.3.6)
tilt (2.0.10)
@ -531,16 +541,18 @@ PLATFORMS
DEPENDENCIES
bcrypt (~> 3.1.7)
better_errors
binding_of_caller
bootstrap (~> 4.4, >= 4.4.1)
bootstrap4-datetime-picker-rails
bootstrap_form
brakeman
byebug
capybara
carrierwave (~> 2.0)
carrierwave_backgrounder!
coffee-rails (~> 4.1)
colorize
database_cleaner
delayed_paperclip
devise (~> 4.0)
devise-async
devise-i18n
@ -562,6 +574,7 @@ DEPENDENCIES
jquery-rails
jquery-turbolinks
letter_opener
mini_magick
moment-timezone-rails (~> 1.0)
momentjs-rails (>= 2.9.0)
newrelic_rpm
@ -569,7 +582,6 @@ DEPENDENCIES
omniauth
omniauth-tumblr
omniauth-twitter
paperclip (~> 5.2)
pg
pghero
poltergeist

View File

@ -30,10 +30,10 @@ if window.URL? or window.webkitURL?
preview = ($ '#profile-picture-preview')
updateVars = (data, action) ->
($ '#crop_x').val Math.floor(data.x / data.scale)
($ '#crop_y').val Math.floor(data.y / data.scale)
($ '#crop_w').val Math.floor(data.w / data.scale)
($ '#crop_h').val Math.floor(data.h / data.scale)
($ '#profile_picture_x').val Math.floor(data.x / data.scale)
($ '#profile_picture_y').val Math.floor(data.y / data.scale)
($ '#profile_picture_w').val Math.floor(data.w / data.scale)
($ '#profile_picture_h').val Math.floor(data.h / data.scale)
# rx = 100 / data.w
# ry = 100 / data.h
# ($ '#profile-picture-preview').css
@ -76,10 +76,10 @@ if window.URL? or window.webkitURL?
preview = ($ '#profile-header-preview')
updateVars = (data, action) ->
($ '#crop_h_x').val Math.floor(data.x / data.scale)
($ '#crop_h_y').val Math.floor(data.y / data.scale)
($ '#crop_h_w').val Math.floor(data.w / data.scale)
($ '#crop_h_h').val Math.floor(data.h / data.scale)
($ '#profile_header_x').val Math.floor(data.x / data.scale)
($ '#profile_header_y').val Math.floor(data.y / data.scale)
($ '#profile_header_w').val Math.floor(data.w / data.scale)
($ '#profile_header_h').val Math.floor(data.h / data.scale)
cropper.on 'load', ->
if ({}.toString).call(src) == "[object URL]"

View File

@ -28,8 +28,9 @@ class UserController < ApplicationController
end
def update
user_attributes = params.require(:user).permit(:display_name, :profile_picture, :profile_header, :motivation_header, :website,
:location, :bio, :crop_x, :crop_y, :crop_w, :crop_h, :crop_h_x, :crop_h_y, :crop_h_w, :crop_h_h, :show_foreign_themes)
user_attributes = params.require(:user).permit(:display_name, :motivation_header, :website, :show_foreign_themes, :location, :bio,
:profile_picture_x, :profile_picture_y, :profile_picture_w, :profile_picture_h,
:profile_header_x, :profile_header_y, :profile_header_w, :profile_header_h, :profile_picture, :profile_header)
if current_user.update_attributes(user_attributes)
text = t('flash.user.update.text')
text += t('flash.user.update.avatar') if user_attributes[:profile_picture]

View File

@ -54,19 +54,9 @@ class User < ApplicationRecord
validates :display_name, length: { maximum: 50 }
validates :bio, length: { maximum: 200 }
# validates :website, format: { with: WEBSITE_REGEX }
has_attached_file :profile_picture, styles: { large: "500x500#", medium: "256x256#", small: "80x80#" },
default_url: "/images/:style/no_avatar.png", use_timestamp: false,
processors: [:cropper]
validates_attachment_content_type :profile_picture, :content_type => /\Aimage\/(png|jpe?g|gif)\Z/
has_attached_file :profile_header, styles: { web: "1500x350#", mobile: "450x105#", retina: "900x210#" },
default_url: '/images/header/:style/no_header.jpg', use_timestamp: false,
processors: [:cropper]
validates_attachment_content_type :profile_header, :content_type => /\Aimage\/(png|jpe?g)\Z/
mount_uploader :profile_picture, ProfilePictureUploader, mount_on: :profile_picture_file_name
process_in_background :profile_picture
mount_uploader :profile_header, ProfileHeaderUploader, mount_on: :profile_header_file_name
process_in_background :profile_header
before_save do
@ -77,7 +67,7 @@ class User < ApplicationRecord
end unless website.blank?
end
# when a user deleted himself, all reports relating to the user are invalid
# when a user has been deleted, all reports relating to the user become invalid
before_destroy do
rep = Report.where(target_id: self.id, type: 'Reports::User')
rep.each do |r|
@ -233,10 +223,6 @@ class User < ApplicationRecord
end
# endregion
def cropping?
!crop_x.blank? && !crop_y.blank? && !crop_w.blank? && !crop_h.blank?
end
# forwards fill
def banned?
self.permanently_banned? or ((not self.banned_until.nil?) and self.banned_until >= DateTime.current)

View File

@ -0,0 +1,32 @@
class BaseUploader < CarrierWave::Uploader::Base
include CarrierWave::Compatibility::Paperclip
include CarrierWave::MiniMagick
include CarrierWave::Backgrounder::Delay
storage :fog
# Store original size
version :original
# Process cropping on upload
process :cropping
def store_dir
"/uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
def paperclip_path
"users/:attachment/:id_partition/:style/:basename.:extension"
end
def cropping
x = model.public_send("#{mounted_as}_x")
y = model.public_send("#{mounted_as}_y")
w = model.public_send("#{mounted_as}_w")
h = model.public_send("#{mounted_as}_h")
manipulate! do |image|
image.crop "#{w}x#{h}+#{x}+#{y}"
end
end
end

View File

@ -0,0 +1,15 @@
class ProfileHeaderUploader < BaseUploader
def default_url(*args)
"/images/header/" + [version_name, "no_header.jpg"].compact.join('/')
end
version :web do
process resize_to_fit: [1500, 350]
end
version :mobile do
process resize_to_fit: [450, 105]
end
version :retina do
process resize_to_fit: [900, 210]
end
end

View File

@ -0,0 +1,15 @@
class ProfilePictureUploader < BaseUploader
def default_url(*args)
"/images/" + [version_name, "no_avatar.png"].compact.join('/')
end
version :large do
process resize_to_fit: [500, 500]
end
version :medium do
process resize_to_fit: [256, 256]
end
version :small do
process resize_to_fit: [80, 80]
end
end

View File

@ -48,10 +48,10 @@
= f.check_box :show_foreign_themes, label: 'Render other user themes when visiting their profile'
- %i[crop_x crop_y crop_w crop_h].each do |attrib|
- %i[profile_picture_x profile_picture_y profile_picture_w profile_picture_h].each do |attrib|
= f.hidden_field attrib, id: attrib
- %i[crop_h_x crop_h_y crop_h_w crop_h_h].each do |attrib|
- %i[profile_header_x profile_header_y profile_header_w profile_header_h].each do |attrib|
= f.hidden_field attrib, id: attrib
= f.submit t('views.actions.save'), class: 'btn btn-primary'

View File

@ -0,0 +1,16 @@
CarrierWave.configure do |config|
config.fog_credentials = {
:provider => "Local",
:local_root => "#{Rails.root}/public",
}
config.fog_directory = "/system"
unless APP_CONFIG["fog"].nil?
config.fog_credentials = APP_CONFIG.dig("fog", "credentials") unless APP_CONFIG.dig("fog", "credentials").nil?
config.fog_directory = APP_CONFIG.dig("fog", "directory") unless APP_CONFIG.dig("fog", "directory").nil?
end
end
CarrierWave::Backgrounder.configure do |c|
c.backend :sidekiq, queue: :carrierwave
end

View File

@ -1,14 +0,0 @@
Paperclip::Attachment.default_options[:storage] = :fog
Paperclip::Attachment.default_options[:fog_credentials] = {:provider => "Local", :local_root => "#{Rails.root}/public"}
Paperclip::Attachment.default_options[:fog_directory] = "/system"
Paperclip::Attachment.default_options[:fog_host] = "/system"
unless APP_CONFIG["fog"].nil?
Paperclip::Attachment.default_options[:fog_credentials] = APP_CONFIG["fog"]["credentials"] unless APP_CONFIG["fog"]["credentials"].nil?
Paperclip::Attachment.default_options[:fog_directory] = APP_CONFIG["fog"]["directory"] unless APP_CONFIG["fog"]["directory"].nil?
Paperclip::Attachment.default_options[:fog_host] = APP_CONFIG["fog"]["host"] unless APP_CONFIG["fog"]["host"].nil?
if not APP_CONFIG["fog"]["credentials"].nil? and APP_CONFIG["fog"]["host"].nil?
Paperclip::Attachment.default_options[:fog_host] = nil
end
end

View File

@ -50,15 +50,15 @@ admins:
about_text: Filippus
subtext: Moderator Management & Support
# delete if using local storage
fog:
# uncomment if using cloud storage
# fog:
# fog credentials
credentials:
provider: 'AWS'
aws_access_key_id: 'ACCESS KEY'
aws_secret_access_key: 'SECRET KEY'
region: 'space-pluto-1'
# credentials:
# provider: 'AWS'
# aws_access_key_id: 'ACCESS KEY'
# aws_secret_access_key: 'SECRET KEY'
# region: 'space-pluto-1'
# URL host, comment out to use default, GENERALLY you don't want to define this
# host: 's3.wherever.com'
# bucket name, required
directory: 'retrospring'
# URL host, comment out to use default, GENERALLY you don't want to define this
# host: ''
# directory: 'retrospring'

View File

@ -1,15 +0,0 @@
# I seriously hope you guys don't do this.
class Paperclip::FileCommandContentTypeDetector
alias old_type_from_file_command type_from_file_command
def type_from_file_command
default = old_type_from_file_command
if default.strip == 'text/x-c' or default.strip == 'text/plain' or default.strip == 'text/stylesheet'
'text/css'
else
default
end
end
end
# Here be monkey patches.

View File

@ -7,7 +7,7 @@ production:
:concurrency: 25
:queues:
- share
- paperclip
- carrierwave
- mailers
- deletion
- question

View File

@ -1,11 +1,17 @@
class AddAttachmentProfilePictureToUsers < ActiveRecord::Migration[4.2]
def self.up
change_table :users do |t|
t.attachment :profile_picture
t.string :profile_picture_file_name
t.string :profile_picture_content_type
t.integer :profile_picture_file_size
t.datetime :profile_picture_updated_at
end
end
def self.down
remove_attachment :users, :profile_picture
remove_column :users, :profile_picture_file_name
remove_column :users, :profile_picture_content_type
remove_column :users, :profile_picture_file_size
remove_column :users, :profile_picture_updated_at
end
end

View File

@ -1,7 +1,10 @@
class AddAttachmentProfileHeaderToUsers < ActiveRecord::Migration[4.2]
def change
change_table :users do |t|
t.attachment :profile_header
t.string :profile_header_file_name
t.string :profile_header_content_type
t.integer :profile_header_file_size
t.datetime :profile_header_updated_at
t.boolean :profile_header_processing
t.integer :crop_h_x
t.integer :crop_h_y

View File

@ -30,7 +30,10 @@ class CreateThemes < ActiveRecord::Migration[4.2]
t.integer :background_text, limit: 4, default: 0x222222
t.integer :background_muted, limit: 4, default: 0xBBBBBB
t.attachment :css
t.string :css_file_name
t.string :css_content_type
t.bigint :css_file_size
t.datetime :css_updated_at
t.timestamps null: false
end

View File

@ -0,0 +1,12 @@
class RenameCropFields < ActiveRecord::Migration[5.2]
def change
rename_column :users, :crop_h, :profile_picture_h
rename_column :users, :crop_w, :profile_picture_w
rename_column :users, :crop_x, :profile_picture_x
rename_column :users, :crop_y, :profile_picture_y
rename_column :users, :crop_h_h, :profile_header_h
rename_column :users, :crop_h_w, :profile_header_w
rename_column :users, :crop_h_x, :profile_header_x
rename_column :users, :crop_h_y, :profile_header_y
end
end

View File

@ -0,0 +1,10 @@
class RemovePaperclipFields < ActiveRecord::Migration[5.2]
def change
remove_column :users, :profile_picture_content_type
remove_column :users, :profile_picture_file_size
remove_column :users, :profile_picture_updated_at
remove_column :users, :profile_header_content_type
remove_column :users, :profile_header_file_size
remove_column :users, :profile_header_updated_at
end
end

View File

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2020_05_09_094402) do
ActiveRecord::Schema.define(version: 2020_05_17_192431) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -249,14 +249,11 @@ ActiveRecord::Schema.define(version: 2020_05_09_094402) do
t.string "location", default: "", null: false
t.text "bio", default: "", null: false
t.string "profile_picture_file_name"
t.string "profile_picture_content_type"
t.integer "profile_picture_file_size"
t.datetime "profile_picture_updated_at"
t.boolean "profile_picture_processing"
t.integer "crop_x"
t.integer "crop_y"
t.integer "crop_w"
t.integer "crop_h"
t.integer "profile_picture_x"
t.integer "profile_picture_y"
t.integer "profile_picture_w"
t.integer "profile_picture_h"
t.boolean "privacy_allow_anonymous_questions", default: true
t.boolean "privacy_allow_public_timeline", default: true
t.boolean "privacy_allow_stranger_answers", default: true
@ -266,14 +263,11 @@ ActiveRecord::Schema.define(version: 2020_05_09_094402) do
t.datetime "banned_until"
t.integer "comment_smiled_count", default: 0, null: false
t.string "profile_header_file_name"
t.string "profile_header_content_type"
t.integer "profile_header_file_size"
t.datetime "profile_header_updated_at"
t.boolean "profile_header_processing"
t.integer "crop_h_x"
t.integer "crop_h_y"
t.integer "crop_h_w"
t.integer "crop_h_h"
t.integer "profile_header_x"
t.integer "profile_header_y"
t.integer "profile_header_w"
t.integer "profile_header_h"
t.string "locale", default: "en"
t.string "confirmation_token"
t.datetime "confirmed_at"

View File

@ -0,0 +1,66 @@
# frozen_string_literal: true
require "rails_helper"
describe UserController, type: :controller do
let(:user) { FactoryBot.create :user }
describe "#edit" do
subject { get :edit }
context "user signed in" do
before(:each) { sign_in user }
it "renders the edit_profile_picture template" do
subject
expect(response).to render_template("user/edit")
end
end
end
describe "#update" do
subject { patch :update, params: { user: avatar_params } }
let(:avatar_params) do
{
profile_picture: fixture_file_upload("files/banana_racc.jpg", "image/jpeg")
}
end
context "user signed in" do
before(:each) { sign_in user }
it "enqueues a Sidekiq job to process the uploaded profile picture" do
subject
expect(::CarrierWave::Workers::ProcessAsset).to have_enqueued_sidekiq_job("User", user.id.to_s, "profile_picture")
end
it "redirects to the edit_user_profile page" do
subject
expect(response).to redirect_to(:edit_user_profile)
end
end
end
describe "#update" do
subject { patch :update, params: { user: header_params } }
let(:header_params) do
{
profile_header: fixture_file_upload("files/banana_racc.jpg", "image/jpeg")
}
end
context "user signed in" do
before(:each) { sign_in user }
it "enqueues a Sidekiq job to process the uploaded profile header" do
subject
expect(::CarrierWave::Workers::ProcessAsset).to have_enqueued_sidekiq_job("User", user.id.to_s, "profile_header")
end
it "redirects to the edit_user_profile page" do
subject
expect(response).to redirect_to(:edit_user_profile)
end
end
end
end

BIN
spec/fixtures/files/banana_racc.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 510 KiB