adding avatar to project settings page added avatar removal show project avatar on dashboard, projects page, project page added rspec and feature tests added project avatar from repository new default project icon added added copying af avatar to forking of project added generated icon fixed avatar fork hound fix style fix test fix
This commit is contained in:
parent
c8c05edcd5
commit
42bac7f9f2
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
|
@ -18,3 +18,13 @@ class @Project
|
|||
$.cookie('hide_no_ssh_message', 'false', { path: path })
|
||||
$(@).parents('.no-ssh-key-message').hide()
|
||||
e.preventDefault()
|
||||
|
||||
# avatar
|
||||
$('.js-choose-project-avatar-button').bind "click", ->
|
||||
form = $(this).closest("form")
|
||||
form.find(".js-project-avatar-input").click()
|
||||
|
||||
$('.js-project-avatar-input').bind "change", ->
|
||||
form = $(this).closest("form")
|
||||
filename = $(this).val().replace(/^.*[\\\/]/, '')
|
||||
form.find(".js-avatar-filename").text(filename)
|
||||
|
|
|
@ -23,3 +23,16 @@
|
|||
&.s90 { width: 90px; height: 90px; margin-right: 15px; }
|
||||
&.s160 { width: 160px; height: 160px; margin-right: 20px; }
|
||||
}
|
||||
|
||||
.identicon {
|
||||
text-align: center;
|
||||
vertical-align: top;
|
||||
|
||||
&.s16 { font-size: 12px; line-height: 1.33; }
|
||||
&.s24 { font-size: 18px; line-height: 1.33; }
|
||||
&.s26 { font-size: 20px; line-height: 1.33; }
|
||||
&.s32 { font-size: 24px; line-height: 1.33; }
|
||||
&.s60 { font-size: 45px; line-height: 1.33; }
|
||||
&.s90 { font-size: 68px; line-height: 1.33; }
|
||||
&.s160 { font-size: 120px; line-height: 1.33; }
|
||||
}
|
|
@ -75,6 +75,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
.project-avatar {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.project-description {
|
||||
overflow: hidden;
|
||||
|
@ -92,6 +95,9 @@
|
|||
}
|
||||
}
|
||||
|
||||
.dash-project-avatar {
|
||||
float: left;
|
||||
}
|
||||
.dash-project-access-icon {
|
||||
float: left;
|
||||
margin-right: 3px;
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
class Projects::AvatarsController < Projects::ApplicationController
|
||||
layout 'project'
|
||||
|
||||
before_filter :project
|
||||
|
||||
def show
|
||||
@blob = @project.repository.blob_at_branch('master', @project.avatar_in_git)
|
||||
if @blob
|
||||
headers['X-Content-Type-Options'] = 'nosniff'
|
||||
send_data(
|
||||
@blob.data,
|
||||
type: @blob.mime_type,
|
||||
disposition: 'inline',
|
||||
filename: @blob.name
|
||||
)
|
||||
else
|
||||
not_found!
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@project.remove_avatar!
|
||||
|
||||
@project.save
|
||||
@project.reset_events_cache
|
||||
|
||||
redirect_to edit_project_path(@project)
|
||||
end
|
||||
end
|
|
@ -50,6 +50,31 @@ module ApplicationHelper
|
|||
args.any? { |v| v.to_s.downcase == action_name }
|
||||
end
|
||||
|
||||
def project_icon(project_id, options = {})
|
||||
project = Project.find_with_namespace(project_id)
|
||||
if project.avatar.present?
|
||||
image_tag project.avatar.url, options
|
||||
elsif options[:only_uploaded]
|
||||
image_tag '/assets/no_project_icon.png', options
|
||||
elsif project.avatar_in_git
|
||||
image_tag project_avatar_path(project), options
|
||||
else # generated icon
|
||||
project_identicon(project, options)
|
||||
end
|
||||
end
|
||||
|
||||
def project_identicon(project, options = {})
|
||||
options[:class] ||= ''
|
||||
options[:class] << ' identicon'
|
||||
bg_color = Digest::MD5.hexdigest(project.name)[0, 6]
|
||||
brightness = bg_color[0, 2].hex + bg_color[2, 2].hex + bg_color[4, 2].hex
|
||||
text_color = (brightness > 375) ? '#000' : '#fff'
|
||||
content_tag(:div, class: options[:class],
|
||||
style: "background-color: ##{ bg_color }; color: #{ text_color }") do
|
||||
project.name[0, 1].upcase
|
||||
end
|
||||
end
|
||||
|
||||
def group_icon(group_path)
|
||||
group = Group.find_by(path: group_path)
|
||||
if group && group.avatar.present?
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
# star_count :integer default(0), not null
|
||||
# import_type :string(255)
|
||||
# import_source :string(255)
|
||||
# avatar :string(255)
|
||||
#
|
||||
|
||||
class Project < ActiveRecord::Base
|
||||
|
@ -119,6 +120,11 @@ class Project < ActiveRecord::Base
|
|||
if: :import?
|
||||
validates :star_count, numericality: { greater_than_or_equal_to: 0 }
|
||||
validate :check_limit, on: :create
|
||||
validate :avatar_type,
|
||||
if: ->(project) { project.avatar && project.avatar_changed? }
|
||||
validates :avatar, file_size: { maximum: 100.kilobytes.to_i }
|
||||
|
||||
mount_uploader :avatar, AttachmentUploader
|
||||
|
||||
# Scopes
|
||||
scope :without_user, ->(user) { where("projects.id NOT IN (:ids)", ids: user.authorized_projects.map(&:id) ) }
|
||||
|
@ -338,6 +344,24 @@ class Project < ActiveRecord::Base
|
|||
@ci_service ||= ci_services.select(&:activated?).first
|
||||
end
|
||||
|
||||
def avatar_type
|
||||
unless avatar.image?
|
||||
errors.add :avatar, 'only images allowed'
|
||||
end
|
||||
end
|
||||
|
||||
def avatar_in_git
|
||||
@avatar_file ||= 'logo.png' if repository.blob_at_branch('master', 'logo.png')
|
||||
@avatar_file ||= 'logo.jpg' if repository.blob_at_branch('master', 'logo.jpg')
|
||||
@avatar_file ||= 'logo.gif' if repository.blob_at_branch('master', 'logo.gif')
|
||||
@avatar_file
|
||||
end
|
||||
|
||||
# For compatibility with old code
|
||||
def code
|
||||
path
|
||||
end
|
||||
|
||||
def items_for(entity)
|
||||
case entity
|
||||
when 'issue' then
|
||||
|
@ -529,6 +553,7 @@ class Project < ActiveRecord::Base
|
|||
# Since we do cache @event we need to reset cache in special cases:
|
||||
# * when project was moved
|
||||
# * when project was renamed
|
||||
# * when the project avatar changes
|
||||
# Events cache stored like events/23-20130109142513.
|
||||
# The cache key includes updated_at timestamp.
|
||||
# Thus it will automatically generate a new fragment
|
||||
|
|
|
@ -14,6 +14,9 @@ module Projects
|
|||
project.name = @from_project.name
|
||||
project.path = @from_project.path
|
||||
project.creator = @current_user
|
||||
if @from_project.avatar && @from_project.avatar.image?
|
||||
project.avatar = @from_project.avatar
|
||||
end
|
||||
|
||||
if namespace = @params[:namespace]
|
||||
project.namespace = namespace
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
= link_to project_path(project), class: dom_class(project) do
|
||||
.dash-project-avatar
|
||||
= project_icon(project.to_param, alt: '', class: 'avatar s24')
|
||||
.dash-project-access-icon
|
||||
= visibility_level_icon(project.visibility_level)
|
||||
%span.str-truncated
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
- @projects.each do |project|
|
||||
%li.my-project-row
|
||||
%h4.project-title
|
||||
.project-avatar
|
||||
= project_icon(project.to_param, alt: '', class: 'avatar s60')
|
||||
.project-access-icon
|
||||
= visibility_level_icon(project.visibility_level)
|
||||
= link_to project_path(project), class: dom_class(project) do
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
.project-home-panel{:class => ("empty-project" if empty_repo)}
|
||||
.project-home-row
|
||||
.project-home-desc
|
||||
= project_icon(@project.to_param, alt: '', class: 'avatar s32')
|
||||
- if @project.description.present?
|
||||
= escaped_autolink(@project.description)
|
||||
- if can?(current_user, :admin_project, @project)
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
%p.light Some settings, such as "Transfer Project", are hidden inside the danger area below.
|
||||
%hr
|
||||
.panel-body
|
||||
= form_for @project, remote: true, html: { class: "edit_project form-horizontal" } do |f|
|
||||
= form_for @project, remote: true, html: { multipart: true, class: "edit_project form-horizontal" }, authenticity_token: true do |f|
|
||||
|
||||
%fieldset
|
||||
.form-group.project_name_holder
|
||||
= f.label :name, class: 'control-label' do
|
||||
|
@ -80,6 +81,31 @@
|
|||
= f.check_box :snippets_enabled
|
||||
%span.descr Share code pastes with others out of git repository
|
||||
|
||||
%fieldset.features
|
||||
%legend
|
||||
Project avatar:
|
||||
.form-group
|
||||
.col-sm-2
|
||||
.col-sm-10
|
||||
= project_icon(@project.to_param, alt: '', class: 'avatar s160', only_uploaded: true)
|
||||
%p.light
|
||||
- if @project.avatar_in_git
|
||||
Project avatar in repository: #{ @project.avatar_in_git }
|
||||
%p.light
|
||||
- if @project.avatar?
|
||||
You can change your project avatar here
|
||||
- else
|
||||
You can upload an project avatar here
|
||||
%a.choose-btn.btn.btn-small.js-choose-project-avatar-button
|
||||
%i.icon-paper-clip
|
||||
%span Choose File ...
|
||||
|
||||
%span.file_name.js-avatar-filename File name...
|
||||
= f.file_field :avatar, class: "js-project-avatar-input hidden"
|
||||
.light The maximum file size allowed is 100KB.
|
||||
- if @project.avatar?
|
||||
%hr
|
||||
= link_to 'Remove avatar', project_avatar_path(@project), data: { confirm: "Project avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-small remove-avatar"
|
||||
|
||||
.form-actions
|
||||
= f.submit 'Save changes', class: "btn btn-save"
|
||||
|
|
|
@ -353,6 +353,8 @@ Gitlab::Application.routes.draw do
|
|||
delete :delete_attachment
|
||||
end
|
||||
end
|
||||
|
||||
resource :avatar, only: [:show, :destroy]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
class AddAvatarToProjects < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :projects, :avatar, :string
|
||||
end
|
||||
end
|
|
@ -327,6 +327,7 @@ ActiveRecord::Schema.define(version: 20150116234544) do
|
|||
t.integer "star_count", default: 0, null: false
|
||||
t.string "import_type"
|
||||
t.string "import_source"
|
||||
t.string "avatar"
|
||||
end
|
||||
|
||||
add_index "projects", ["creator_id"], name: "index_projects_on_creator_id", using: :btree
|
||||
|
|
|
@ -5,6 +5,19 @@ Feature: Project
|
|||
And project "Shop" has push event
|
||||
And I visit project "Shop" page
|
||||
|
||||
Scenario: I edit the project avatar
|
||||
Given I visit edit project "Shop" page
|
||||
When I change the project avatar
|
||||
And I should see new project avatar
|
||||
And I should see the "Remove avatar" button
|
||||
|
||||
Scenario: I remove the project avatar
|
||||
Given I visit edit project "Shop" page
|
||||
And I have an project avatar
|
||||
When I remove my project avatar
|
||||
Then I should see the default project avatar
|
||||
And I should not see the "Remove avatar" button
|
||||
|
||||
@javascript
|
||||
Scenario: I should see project activity
|
||||
When I visit project "Shop" page
|
||||
|
|
|
@ -17,12 +17,53 @@ class Spinach::Features::Project < Spinach::FeatureSteps
|
|||
end
|
||||
|
||||
step 'change project path settings' do
|
||||
fill_in "project_path", with: "new-path"
|
||||
click_button "Rename"
|
||||
fill_in 'project_path', with: 'new-path'
|
||||
click_button 'Rename'
|
||||
end
|
||||
|
||||
step 'I should see project with new path settings' do
|
||||
project.path.should == "new-path"
|
||||
project.path.should == 'new-path'
|
||||
end
|
||||
|
||||
step 'I change the project avatar' do
|
||||
attach_file(
|
||||
:project_avatar,
|
||||
File.join(Rails.root, 'public', 'gitlab_logo.png')
|
||||
)
|
||||
click_button 'Save changes'
|
||||
@project.reload
|
||||
end
|
||||
|
||||
step 'I should see new project avatar' do
|
||||
@project.avatar.should be_instance_of AttachmentUploader
|
||||
url = @project.avatar.url
|
||||
url.should == "/uploads/project/avatar/#{ @project.id }/gitlab_logo.png"
|
||||
end
|
||||
|
||||
step 'I should see the "Remove avatar" button' do
|
||||
page.should have_link('Remove avatar')
|
||||
end
|
||||
|
||||
step 'I have an project avatar' do
|
||||
attach_file(
|
||||
:project_avatar,
|
||||
File.join(Rails.root, 'public', 'gitlab_logo.png')
|
||||
)
|
||||
click_button 'Save changes'
|
||||
@project.reload
|
||||
end
|
||||
|
||||
step 'I remove my project avatar' do
|
||||
click_link 'Remove avatar'
|
||||
@project.reload
|
||||
end
|
||||
|
||||
step 'I should see the default project avatar' do
|
||||
@project.avatar?.should be_false
|
||||
end
|
||||
|
||||
step 'I should not see the "Remove avatar" button' do
|
||||
page.should_not have_link('Remove avatar')
|
||||
end
|
||||
|
||||
step 'I should see project "Shop" version' do
|
||||
|
|
|
@ -56,6 +56,28 @@ describe ApplicationHelper do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'project_icon' do
|
||||
avatar_file_path = File.join(Rails.root, 'public', 'gitlab_logo.png')
|
||||
|
||||
it 'should return an url for the avatar' do
|
||||
project = create(:project)
|
||||
project.avatar = File.open(avatar_file_path)
|
||||
project.save!
|
||||
project_icon(project.to_param).to_s.should ==
|
||||
"/uploads/project/avatar/#{ project.id }/gitlab_logo.png"
|
||||
end
|
||||
|
||||
it "should give uploaded icon when present" do
|
||||
project = create(:project)
|
||||
project.save!
|
||||
|
||||
Project.any_instance.stub(:avatar_in_git).and_return(true)
|
||||
|
||||
project_icon(project.to_param).to_s.should match(
|
||||
image_tag(project_avatar_path(project)))
|
||||
end
|
||||
end
|
||||
|
||||
describe "avatar_icon" do
|
||||
avatar_file_path = File.join(Rails.root, 'public', 'gitlab_logo.png')
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
# star_count :integer default(0), not null
|
||||
# import_type :string(255)
|
||||
# import_source :string(255)
|
||||
# avatar :string(255)
|
||||
#
|
||||
|
||||
require 'spec_helper'
|
||||
|
@ -310,4 +311,18 @@ describe Project do
|
|||
expect(project.star_count).to eq(0)
|
||||
end
|
||||
end
|
||||
|
||||
describe :avatar_type do
|
||||
let(:project) { create(:project) }
|
||||
|
||||
it 'should be true if avatar is image' do
|
||||
project.update_attribute(:avatar, 'uploads/avatar.png')
|
||||
project.avatar_type.should be_true
|
||||
end
|
||||
|
||||
it 'should be false if avatar is html page' do
|
||||
project.update_attribute(:avatar, 'uploads/avatar.html')
|
||||
project.avatar_type.should == ['only images allowed']
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -489,4 +489,11 @@ describe Projects::ForksController, "routing" do
|
|||
it "to #create" do
|
||||
post("/gitlab/gitlabhq/fork").should route_to("projects/forks#create", project_id: 'gitlab/gitlabhq')
|
||||
end
|
||||
|
||||
# project_avatar DELETE /project/avatar(.:format) projects/avatars#destroy
|
||||
describe Projects::AvatarsController, 'routing' do
|
||||
it 'to #destroy' do
|
||||
delete('/gitlab/gitlabhq/avatar').should route_to(
|
||||
'projects/avatars#destroy', project_id: 'gitlab/gitlabhq')
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue