diff --git a/app/assets/images/no_group_avatar.png b/app/assets/images/no_group_avatar.png new file mode 100644 index 00000000000..dac3ab1bb89 Binary files /dev/null and b/app/assets/images/no_group_avatar.png differ diff --git a/app/assets/javascripts/groups.js.coffee b/app/assets/javascripts/groups.js.coffee index c0ffccd8f70..7850eb14e74 100644 --- a/app/assets/javascripts/groups.js.coffee +++ b/app/assets/javascripts/groups.js.coffee @@ -4,3 +4,14 @@ class GroupMembers $(this).fadeOut() @GroupMembers = GroupMembers + +$ -> + # avatar + $('.js-choose-group-avatar-button').bind "click", -> + form = $(this).closest("form") + form.find(".js-group-avatar-input").click() + + $('.js-group-avatar-input').bind "change", -> + form = $(this).closest("form") + filename = $(this).val().replace(/^.*[\\\/]/, '') + form.find(".js-avatar-filename").text(filename) \ No newline at end of file diff --git a/app/controllers/groups/avatars_controller.rb b/app/controllers/groups/avatars_controller.rb new file mode 100644 index 00000000000..38071410f40 --- /dev/null +++ b/app/controllers/groups/avatars_controller.rb @@ -0,0 +1,12 @@ +class Groups::AvatarsController < ApplicationController + layout "profile" + + def destroy + @group = Group.find_by(path: params[:group_id]) + @group.remove_avatar! + + @group.save + + redirect_to edit_group_path(@group) + end +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index e60cba2bb2b..be57b60382e 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -49,6 +49,15 @@ module ApplicationHelper args.any? { |v| v.to_s.downcase == action_name } end + def group_icon(group_path) + group = Group.find_by(path: group_path) + if group && group.avatar.present? + group.avatar.url + else + '/assets/no_group_avatar.png' + end + end + def avatar_icon(user_email = '', size = nil) user = User.find_by(email: user_email) if user && user.avatar.present? diff --git a/app/models/group.rb b/app/models/group.rb index 0b64d5b4f7f..8de0c78c158 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -12,10 +12,20 @@ # description :string(255) default(""), not null # +require 'carrierwave/orm/activerecord' +require 'file_size_validator' + class Group < Namespace has_many :users_groups, dependent: :destroy has_many :users, through: :users_groups + attr_accessible :avatar + + validate :avatar_type, if: ->(user) { user.avatar_changed? } + validates :avatar, file_size: { maximum: 100.kilobytes.to_i } + + mount_uploader :avatar, AttachmentUploader + def human_name name end @@ -50,4 +60,10 @@ class Group < Namespace def members users_groups end + + def avatar_type + unless self.avatar.image? + self.errors.add :avatar, "only images allowed" + end + end end diff --git a/app/models/namespace.rb b/app/models/namespace.rb index 8f837c72ff5..d5b98f588e8 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -10,6 +10,7 @@ # updated_at :datetime not null # type :string(255) # description :string(255) default(""), not null +# avatar :string(255) # class Namespace < ActiveRecord::Base diff --git a/app/views/dashboard/_groups.html.haml b/app/views/dashboard/_groups.html.haml index d6937ca4813..dd8d85971b3 100644 --- a/app/views/dashboard/_groups.html.haml +++ b/app/views/dashboard/_groups.html.haml @@ -10,6 +10,7 @@ - groups.each do |group| %li.group-row = link_to group_path(id: group.path), class: dom_class(group) do + = image_tag group_icon(group.path), class: "avatar s32" %span.group-name.filter-title = truncate(group.name, length: 35) %span.arrow diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml index 77734815b8a..e274a799674 100644 --- a/app/views/groups/edit.html.haml +++ b/app/views/groups/edit.html.haml @@ -20,7 +20,7 @@ %strong= @group.name group settings: %div.form-holder - = form_for @group, html: { class: "form-horizontal" } do |f| + = form_for @group, html: { multipart: true, class: "form-horizontal" }, authenticity_token: true do |f| - if @group.errors.any? .alert.alert-danger %span= @group.errors.full_messages.first @@ -35,6 +35,26 @@ .col-sm-10 = f.text_area :description, maxlength: 250, class: "form-control js-gfm-input", rows: 4 + .form-group + .col-sm-2 + .col-sm-10 + = image_tag group_icon(@group.to_param), alt: '', class: 'avatar s160' + %p.light + - if @group.avatar? + You can change your group avatar here + - else + You can upload an group avatar here + %a.choose-btn.btn.btn-small.js-choose-group-avatar-button + %i.icon-paper-clip + %span Choose File ... +   + %span.file_name.js-avatar-filename File name... + = f.file_field :avatar, class: "js-group-avatar-input hidden" + .light The maximum file size allowed is 100KB. + - if @group.avatar? + %hr + = link_to 'Remove avatar', group_avatar_path(@group.to_param), data: { confirm: "Group avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-small remove-avatar" + .form-actions = f.submit 'Save group', class: "btn btn-save" diff --git a/config/routes.rb b/config/routes.rb index 611e497c9e5..77247163def 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -156,6 +156,9 @@ Gitlab::Application.routes.draw do end resources :users_groups, only: [:create, :update, :destroy] + scope module: :groups do + resource :avatar, only: [:destroy] + end end resources :projects, constraints: { id: /[^\/]+/ }, only: [:new, :create] diff --git a/db/migrate/20140127170938_add_group_avatars.rb b/db/migrate/20140127170938_add_group_avatars.rb new file mode 100644 index 00000000000..2911096dd5d --- /dev/null +++ b/db/migrate/20140127170938_add_group_avatars.rb @@ -0,0 +1,5 @@ +class AddGroupAvatars < ActiveRecord::Migration + def change + add_column :namespaces, :avatar, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 75a44d9aa04..acbb793bbe8 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20140122122549) do +ActiveRecord::Schema.define(version: 20140127170938) do create_table "broadcast_messages", force: true do |t| t.text "message", null: false @@ -152,6 +152,7 @@ ActiveRecord::Schema.define(version: 20140122122549) do t.datetime "updated_at", null: false t.string "type" t.string "description", default: "", null: false + t.string "avatar" end add_index "namespaces", ["name"], name: "index_namespaces_on_name", using: :btree diff --git a/features/group/group.feature b/features/group/group.feature index 9fec19a4dc1..ca3e67d2c1d 100644 --- a/features/group/group.feature +++ b/features/group/group.feature @@ -31,3 +31,17 @@ Feature: Groups And I change group name Then I should see new group name + Scenario: I edit my group avatar + When I visit group settings page + And I change my group avatar + And I visit group settings page + Then I should see new group avatar + And I should see the "Remove avatar" button + + Scenario: I remove my group avatar + When I visit group settings page + And I have an group avatar + And I visit group settings page + And I remove my group avatar + Then I should not see my group avatar + And I should not see the "Remove avatar" button diff --git a/features/steps/group/group.rb b/features/steps/group/group.rb index 15d7c46c694..0b0f401c3ba 100644 --- a/features/steps/group/group.rb +++ b/features/steps/group/group.rb @@ -98,6 +98,40 @@ class Groups < Spinach::FeatureSteps end end + step 'I change my group avatar' do + attach_file(:group_avatar, File.join(Rails.root, 'public', 'gitlab_logo.png')) + click_button "Save group" + @group.reload + end + + step 'I should see new group avatar' do + @group.avatar.should be_instance_of AttachmentUploader + @group.avatar.url.should == "/uploads/group/avatar/#{ @group.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 group avatar' do + attach_file(:group_avatar, File.join(Rails.root, 'public', 'gitlab_logo.png')) + click_button "Save group" + @group.reload + end + + step 'I remove my group avatar' do + click_link "Remove avatar" + @group.reload + end + + step 'I should not see my group avatar' do + @group.avatar?.should be_false + end + + step 'I should not see the "Remove avatar" button' do + page.should_not have_link("Remove avatar") + end + protected def current_group diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 3644410e46d..c58c83a2970 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -39,6 +39,23 @@ describe ApplicationHelper do end end + describe "group_icon" do + avatar_file_path = File.join(Rails.root, 'public', 'gitlab_logo.png') + + it "should return an url for the avatar" do + group = create(:group) + group.avatar = File.open(avatar_file_path) + group.save! + group_icon(group.path).to_s.should == "/uploads/group/avatar/#{ group.id }/gitlab_logo.png" + end + + it "should give default avatar_icon when no avatar is present" do + group = create(:group) + group.save! + group_icon(group.path).to_s.should == "/assets/no_group_avatar.png" + end + end + describe "avatar_icon" do avatar_file_path = File.join(Rails.root, 'public', 'gitlab_logo.png') diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 12b84700eb1..686e43d8d10 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -54,4 +54,19 @@ describe Group do group.users_groups.guests.map(&:user).should_not include(user) end end + + describe :avatar_type do + let(:user) { create(:user) } + before { group.add_user(user, UsersGroup::MASTER) } + + it "should be true if avatar is image" do + group.update_attribute(:avatar, 'uploads/avatar.png') + group.avatar_type.should be_true + end + + it "should be false if avatar is html page" do + group.update_attribute(:avatar, 'uploads/avatar.html') + group.avatar_type.should == ["only images allowed"] + end + end end