Skip to content

profile photo for users #635

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jun 14, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ gem 'bootstrap-sass', '~> 3.4'
gem 'sassc-rails', '~> 2.1.2'
gem 'uglifier', '~> 4.2.0'
gem 'select2-rails', '~> 4.0.13'

gem 'aws-sdk-s3', require: false
gem 'mini_magick'
gem 'image_processing', '~> 1.2'
group :development do
gem 'listen', '~> 3.2.0'
gem 'localeapp', '~> 3.1', require: false
Expand Down
27 changes: 27 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,22 @@ GEM
ast (2.4.2)
autoprefixer-rails (10.2.4.0)
execjs
aws-eventstream (1.1.1)
aws-partitions (1.451.0)
aws-sdk-core (3.114.0)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.239.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1.0)
aws-sdk-kms (1.43.0)
aws-sdk-core (~> 3, >= 3.112.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.94.1)
aws-sdk-core (~> 3, >= 3.112.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.1)
aws-sigv4 (1.2.3)
aws-eventstream (~> 1, >= 1.0.2)
bcrypt (3.1.16)
bindex (0.8.1)
bootsnap (1.7.4)
Expand Down Expand Up @@ -154,11 +170,15 @@ GEM
http_accept_language (2.1.1)
i18n (1.8.10)
concurrent-ruby (~> 1.0)
image_processing (1.12.1)
mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.17, < 3)
inherited_resources (1.12.0)
actionpack (>= 5.2, < 6.2)
has_scope (~> 0.6)
railties (>= 5.2, < 6.2)
responders (>= 2, < 4)
jmespath (1.4.0)
jquery-rails (4.3.5)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
Expand Down Expand Up @@ -201,6 +221,8 @@ GEM
mime-types (3.3.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2021.0225)
mimemagic (0.3.5)
mini_magick (4.11.0)
mini_mime (1.0.3)
mini_portile2 (2.5.1)
minitest (5.14.4)
Expand Down Expand Up @@ -324,6 +346,8 @@ GEM
rack (>= 1.1)
rubocop (>= 0.90.0, < 2.0)
ruby-progressbar (1.11.0)
ruby-vips (2.1.0)
ffi (~> 1.12)
ruby2_keywords (0.0.4)
rubyzip (2.3.0)
sassc (2.4.0)
Expand Down Expand Up @@ -405,6 +429,7 @@ PLATFORMS

DEPENDENCIES
activeadmin (~> 2.9.0)
aws-sdk-s3
bootsnap (~> 1.7.3)
bootstrap-sass (~> 3.4)
byebug (~> 11.0)
Expand All @@ -419,12 +444,14 @@ DEPENDENCIES
faker (~> 2.15)
has_scope (~> 0.7.2)
http_accept_language (~> 2.1.1)
image_processing (~> 1.2)
jquery-rails (~> 4.3.5)
json_translate (~> 4.0.0)
kaminari (~> 1.2.1)
letter_opener (~> 1.7.0)
listen (~> 3.2.0)
localeapp (~> 3.1)
mini_magick
pg (~> 1.2.1)
pg_search (~> 2.3.5)
prawn (~> 2.4.0)
Expand Down
105 changes: 105 additions & 0 deletions app/assets/javascripts/application/avatar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@

$(function () {
$('#avatar-js').on("change", () => {
$('#dialog').modal({
show: true
});

preview_image_modal();

const panel = $('#crop_panel');
let m_pos;
let x_axis = true;

//add a listener to the document depending on where you tap in the box
panel.on("pointerdown", function(e) {
const BORDER_SIZE = 20;
if (e.offsetY >= (parseInt(panel.css('height')) - BORDER_SIZE)) {
m_pos = e.y;
x_axis = false;
document.addEventListener("pointermove", resize, false);
}
else if (e.offsetX >= (parseInt(panel.css('width')) - BORDER_SIZE)) {
m_pos = e.x;
x_axis = true;
document.addEventListener("pointermove", resize, false);
}
else {
pos3 = e.clientX;
pos4 = e.clientY;
document.addEventListener("pointermove", drag, false);
}
});

//remove listeners from the document when you stop pressing
document.addEventListener("pointerup", function () {
document.removeEventListener("pointermove", resize, false);
document.removeEventListener("pointermove", drag, false);
document.removeEventListener("pointermove", resize, false);
}, false);

//on submit take the parameters of the box to crop the avatar
$('#form_photo').on("submit", () => {
let total_width = parseInt(getComputedStyle(document.getElementById("containerCrop")).width);
let photo_width = parseInt(getComputedStyle(document.getElementById("foto")).width);
let left_displacement = total_width - photo_width;

$('#height_offset').val(parseInt(panel.css('top')) - 15);
$('#width_offset').val(parseInt(panel.css('left')) - 15 - (left_displacement/2));
$('#height_width').val(parseInt(panel.css('width')));
$('#original_width').val($('#foto').width());
});

function resize(e) {
e = e || window.event;
e.preventDefault();
let mov = x_axis ? e.x : e.y;
const dx = m_pos - mov;
m_pos = mov;
if(can_change(panel, dx, false)){
panel.width(panel.width() - dx);
panel.height(panel.width() - dx);
}
}

function drag(e) {
e = e || window.event;
e.preventDefault();
pos1 = pos3 - e.x;
pos2 = pos4 - e.y;
pos3 = e.x;
pos4 = e.y;
if(can_change(panel, pos1 + pos2, true)){
panel.offset({ top: (panel.offset().top - pos2) , left: (panel.offset().left - pos1)});
}
}

function can_change(el, mov, dragging) {
let canChange = true;
let pos = dragging ? [el.css('top'), el.css('left'), el.css('bottom'), el.css('right')] : [el.css('bottom'), el.css('right')];
pos.forEach((el, ix) => {
let next = dragging && (ix == 0 || ix == 1) ? parseInt(el) - mov : parseInt(el) + mov;
if( next < 14 ) {
canChange = false;
}
});
return canChange;
}

function preview_image_modal() {
var preview = document.querySelector('#foto');
var file = document.querySelector('#avatar-js').files[0];
var reader = new FileReader();

reader.onloadend = function () {
preview.src = reader.result;
}

if (file) {
reader.readAsDataURL(file);
} else {
preview.src = "";
}
}
});
});
37 changes: 37 additions & 0 deletions app/assets/stylesheets/application.scss
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,43 @@ label[required]::after{
}
}

#crop_panel {
position: absolute;
width: 140px;
height: 140px;
border-left: 4px dashed black;
cursor: move;
touch-action: none;
border-top: 4px dashed black;
}

#crop_panel::before {
content: "";
border-right: 8px dashed black;
position: absolute;
right: 0;
width: 16px;
height: 100%;
cursor: w-resize;
}

#crop_panel::after {
content: "";
border-bottom: 8px dashed black;
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 16px;
cursor: n-resize;
}

#form_photo {
border: 0px;
padding: 0px;
margin-bottom: 0px;
}

.inline-checkbox {
vertical-align: middle;
display: inline;
Expand Down
33 changes: 33 additions & 0 deletions app/controllers/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,18 @@ def update
end
end

def change_photo_profile
avatar = params[:avatar]
@user = current_user
if avatar && content_type_permitted(avatar.content_type)
@user.avatar.purge if @user.avatar.attached?
crop_image_and_save(avatar)
else
flash[:error] = t 'users.show.invalid_format'
end
redirect_to @user
end

private

def search_and_load_members(members_scope, default_search_params)
Expand Down Expand Up @@ -116,4 +128,25 @@ def redirect_to_after_create
name: @user.username)
end
end

def crop_image_and_save(avatar)
image = MiniMagick::Image.read(File.read(avatar.tempfile))
get_parameters_to_crop
image.resize "#{@or_width}x#{image.height / (image.width / @or_width)}"
image.crop "#{@width}x#{@width}+#{@left}+#{@top}!"
name = @user.username
content_type = avatar.content_type
@user.avatar.attach(io: File.open(image.path), filename: name, content_type: content_type)
end

def get_parameters_to_crop
@or_width = params[:original_width].to_i
@width = params[:height_width].to_i
@left = params[:width_offset].to_i
@top = params[:height_offset].to_i
end

def content_type_permitted(avatar_content_type)
%w[image/jpeg image/pjpeg image/png image/x-png].include? avatar_content_type
end
end
4 changes: 4 additions & 0 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ def page_title
current_organization || 'TimeOverflow'
end

def select_avatar(user, size = 32)
user.avatar.attached? ? user.avatar.variant(resize: "#{size}x#{size}") : avatar_url(user, size)
end

# from gravatar
def avatar_url(user, size = 32)
gravatar_id = Digest::MD5::hexdigest(user.email).downcase
Expand Down
1 change: 1 addition & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class User < ApplicationRecord

attr_accessor :empty_email

has_one_attached :avatar
has_many :members, dependent: :destroy
has_many :organizations, through: :members
has_many :accounts, through: :members
Expand Down
2 changes: 1 addition & 1 deletion app/views/application/_navbar.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<ul class="nav navbar-nav navbar-right hidden-sm hidden-md hidden-lg">
<% if current_user %>
<li>
<%= image_tag avatar_url(current_user) %>
<%= image_tag select_avatar(current_user) %>
<%= current_user.email %>
</li>
<%= render 'application/menus/user_admin_menu_items' %>
Expand Down
2 changes: 1 addition & 1 deletion app/views/application/menus/_user_admin_menu.html.erb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<li class="dropdown">
<a class="dropdown-toggle" href="#" data-toggle="dropdown">
<%= image_tag avatar_url(current_user), style: "margin: -8px auto" %>
<%= image_tag select_avatar(current_user), style: "margin: -8px auto" %>
<%= current_user.email %>
<b class="caret"></b>
</a>
Expand Down
2 changes: 1 addition & 1 deletion app/views/shared/_post.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
</h3>
</div>
<div class="panel-body">
<%= link_to image_tag(avatar_url(post.user, 100)), post.user %>
<%= link_to image_tag(select_avatar(post.user, 100)), post.user %>
<h3>
<%= t "global.contact_details" %>
</h3>
Expand Down
2 changes: 1 addition & 1 deletion app/views/users/_member_card.html.erb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<div class="col-lg-6 col-sm-12">
<div class="to-member-card">
<div class="to-member-card__header">
<div class="to-member-card__header__avatar"><%= member.avatar_img(48) %></div>
<div class="to-member-card__header__avatar"><%= image_tag select_avatar(member.user, 48) %></div>
<div class="to-member-card__header__text">
<h4><%= member.link_to_self %></h4>
<div class="to-member-card__header__text__activity">
Expand Down
2 changes: 1 addition & 1 deletion app/views/users/_user_row.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<%= content_tag(:tr, class: member.row_css_class) do %>
<td> <%= member.avatar_img %> </td>
<td> <%= image_tag select_avatar(member.user) %> </td>
<td> <%= member.member_uid %> </td>
<td>
<%= member.inactive_icon %>
Expand Down
Loading