Commit 251df827a5308d483a95242970569075ab655703
1 parent
5221dbfe
Exists in
spb-stable
and in
3 other branches
added group avatars
Showing
15 changed files
with
161 additions
and
2 deletions
Show diff stats
704 Bytes
app/assets/javascripts/groups.js.coffee
@@ -4,3 +4,14 @@ class GroupMembers | @@ -4,3 +4,14 @@ class GroupMembers | ||
4 | $(this).fadeOut() | 4 | $(this).fadeOut() |
5 | 5 | ||
6 | @GroupMembers = GroupMembers | 6 | @GroupMembers = GroupMembers |
7 | + | ||
8 | +$ -> | ||
9 | + # avatar | ||
10 | + $('.js-choose-group-avatar-button').bind "click", -> | ||
11 | + form = $(this).closest("form") | ||
12 | + form.find(".js-group-avatar-input").click() | ||
13 | + | ||
14 | + $('.js-group-avatar-input').bind "change", -> | ||
15 | + form = $(this).closest("form") | ||
16 | + filename = $(this).val().replace(/^.*[\\\/]/, '') | ||
17 | + form.find(".js-avatar-filename").text(filename) | ||
7 | \ No newline at end of file | 18 | \ No newline at end of file |
app/helpers/application_helper.rb
@@ -49,6 +49,15 @@ module ApplicationHelper | @@ -49,6 +49,15 @@ module ApplicationHelper | ||
49 | args.any? { |v| v.to_s.downcase == action_name } | 49 | args.any? { |v| v.to_s.downcase == action_name } |
50 | end | 50 | end |
51 | 51 | ||
52 | + def group_icon(group_path) | ||
53 | + group = Group.find_by(path: group_path) | ||
54 | + if group && group.avatar.present? | ||
55 | + group.avatar.url | ||
56 | + else | ||
57 | + '/assets/no_group_avatar.png' | ||
58 | + end | ||
59 | + end | ||
60 | + | ||
52 | def avatar_icon(user_email = '', size = nil) | 61 | def avatar_icon(user_email = '', size = nil) |
53 | user = User.find_by(email: user_email) | 62 | user = User.find_by(email: user_email) |
54 | if user && user.avatar.present? | 63 | if user && user.avatar.present? |
app/models/group.rb
@@ -12,10 +12,20 @@ | @@ -12,10 +12,20 @@ | ||
12 | # description :string(255) default(""), not null | 12 | # description :string(255) default(""), not null |
13 | # | 13 | # |
14 | 14 | ||
15 | +require 'carrierwave/orm/activerecord' | ||
16 | +require 'file_size_validator' | ||
17 | + | ||
15 | class Group < Namespace | 18 | class Group < Namespace |
16 | has_many :users_groups, dependent: :destroy | 19 | has_many :users_groups, dependent: :destroy |
17 | has_many :users, through: :users_groups | 20 | has_many :users, through: :users_groups |
18 | 21 | ||
22 | + attr_accessible :avatar | ||
23 | + | ||
24 | + validate :avatar_type, if: ->(user) { user.avatar_changed? } | ||
25 | + validates :avatar, file_size: { maximum: 100.kilobytes.to_i } | ||
26 | + | ||
27 | + mount_uploader :avatar, AttachmentUploader | ||
28 | + | ||
19 | def human_name | 29 | def human_name |
20 | name | 30 | name |
21 | end | 31 | end |
@@ -50,4 +60,10 @@ class Group < Namespace | @@ -50,4 +60,10 @@ class Group < Namespace | ||
50 | def members | 60 | def members |
51 | users_groups | 61 | users_groups |
52 | end | 62 | end |
63 | + | ||
64 | + def avatar_type | ||
65 | + unless self.avatar.image? | ||
66 | + self.errors.add :avatar, "only images allowed" | ||
67 | + end | ||
68 | + end | ||
53 | end | 69 | end |
app/models/namespace.rb
@@ -10,6 +10,7 @@ | @@ -10,6 +10,7 @@ | ||
10 | # updated_at :datetime not null | 10 | # updated_at :datetime not null |
11 | # type :string(255) | 11 | # type :string(255) |
12 | # description :string(255) default(""), not null | 12 | # description :string(255) default(""), not null |
13 | +# avatar :string(255) | ||
13 | # | 14 | # |
14 | 15 | ||
15 | class Namespace < ActiveRecord::Base | 16 | class Namespace < ActiveRecord::Base |
app/views/dashboard/_groups.html.haml
@@ -10,6 +10,7 @@ | @@ -10,6 +10,7 @@ | ||
10 | - groups.each do |group| | 10 | - groups.each do |group| |
11 | %li.group-row | 11 | %li.group-row |
12 | = link_to group_path(id: group.path), class: dom_class(group) do | 12 | = link_to group_path(id: group.path), class: dom_class(group) do |
13 | + = image_tag group_icon(group.path), class: "avatar s32" | ||
13 | %span.group-name.filter-title | 14 | %span.group-name.filter-title |
14 | = truncate(group.name, length: 35) | 15 | = truncate(group.name, length: 35) |
15 | %span.arrow | 16 | %span.arrow |
app/views/groups/edit.html.haml
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | %strong= @group.name | 20 | %strong= @group.name |
21 | group settings: | 21 | group settings: |
22 | %div.form-holder | 22 | %div.form-holder |
23 | - = form_for @group, html: { class: "form-horizontal" } do |f| | 23 | + = form_for @group, html: { multipart: true, class: "form-horizontal" }, authenticity_token: true do |f| |
24 | - if @group.errors.any? | 24 | - if @group.errors.any? |
25 | .alert.alert-danger | 25 | .alert.alert-danger |
26 | %span= @group.errors.full_messages.first | 26 | %span= @group.errors.full_messages.first |
@@ -35,6 +35,26 @@ | @@ -35,6 +35,26 @@ | ||
35 | .col-sm-10 | 35 | .col-sm-10 |
36 | = f.text_area :description, maxlength: 250, class: "form-control js-gfm-input", rows: 4 | 36 | = f.text_area :description, maxlength: 250, class: "form-control js-gfm-input", rows: 4 |
37 | 37 | ||
38 | + .form-group | ||
39 | + .col-sm-2 | ||
40 | + .col-sm-10 | ||
41 | + = image_tag group_icon(@group.to_param), alt: '', class: 'avatar s160' | ||
42 | + %p.light | ||
43 | + - if @group.avatar? | ||
44 | + You can change your group avatar here | ||
45 | + - else | ||
46 | + You can upload an group avatar here | ||
47 | + %a.choose-btn.btn.btn-small.js-choose-group-avatar-button | ||
48 | + %i.icon-paper-clip | ||
49 | + %span Choose File ... | ||
50 | + | ||
51 | + %span.file_name.js-avatar-filename File name... | ||
52 | + = f.file_field :avatar, class: "js-group-avatar-input hidden" | ||
53 | + .light The maximum file size allowed is 100KB. | ||
54 | + - if @group.avatar? | ||
55 | + %hr | ||
56 | + = 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" | ||
57 | + | ||
38 | .form-actions | 58 | .form-actions |
39 | = f.submit 'Save group', class: "btn btn-save" | 59 | = f.submit 'Save group', class: "btn btn-save" |
40 | 60 |
config/routes.rb
@@ -156,6 +156,9 @@ Gitlab::Application.routes.draw do | @@ -156,6 +156,9 @@ Gitlab::Application.routes.draw do | ||
156 | end | 156 | end |
157 | 157 | ||
158 | resources :users_groups, only: [:create, :update, :destroy] | 158 | resources :users_groups, only: [:create, :update, :destroy] |
159 | + scope module: :groups do | ||
160 | + resource :avatar, only: [:destroy] | ||
161 | + end | ||
159 | end | 162 | end |
160 | 163 | ||
161 | resources :projects, constraints: { id: /[^\/]+/ }, only: [:new, :create] | 164 | resources :projects, constraints: { id: /[^\/]+/ }, only: [:new, :create] |
db/schema.rb
@@ -11,7 +11,7 @@ | @@ -11,7 +11,7 @@ | ||
11 | # | 11 | # |
12 | # It's strongly recommended that you check this file into your version control system. | 12 | # It's strongly recommended that you check this file into your version control system. |
13 | 13 | ||
14 | -ActiveRecord::Schema.define(version: 20140122122549) do | 14 | +ActiveRecord::Schema.define(version: 20140127170938) do |
15 | 15 | ||
16 | create_table "broadcast_messages", force: true do |t| | 16 | create_table "broadcast_messages", force: true do |t| |
17 | t.text "message", null: false | 17 | t.text "message", null: false |
@@ -152,6 +152,7 @@ ActiveRecord::Schema.define(version: 20140122122549) do | @@ -152,6 +152,7 @@ ActiveRecord::Schema.define(version: 20140122122549) do | ||
152 | t.datetime "updated_at", null: false | 152 | t.datetime "updated_at", null: false |
153 | t.string "type" | 153 | t.string "type" |
154 | t.string "description", default: "", null: false | 154 | t.string "description", default: "", null: false |
155 | + t.string "avatar" | ||
155 | end | 156 | end |
156 | 157 | ||
157 | add_index "namespaces", ["name"], name: "index_namespaces_on_name", using: :btree | 158 | add_index "namespaces", ["name"], name: "index_namespaces_on_name", using: :btree |
features/group/group.feature
@@ -31,3 +31,17 @@ Feature: Groups | @@ -31,3 +31,17 @@ Feature: Groups | ||
31 | And I change group name | 31 | And I change group name |
32 | Then I should see new group name | 32 | Then I should see new group name |
33 | 33 | ||
34 | + Scenario: I edit my group avatar | ||
35 | + When I visit group settings page | ||
36 | + And I change my group avatar | ||
37 | + And I visit group settings page | ||
38 | + Then I should see new group avatar | ||
39 | + And I should see the "Remove avatar" button | ||
40 | + | ||
41 | + Scenario: I remove my group avatar | ||
42 | + When I visit group settings page | ||
43 | + And I have an group avatar | ||
44 | + And I visit group settings page | ||
45 | + And I remove my group avatar | ||
46 | + Then I should not see my group avatar | ||
47 | + And I should not see the "Remove avatar" button |
features/steps/group/group.rb
@@ -98,6 +98,40 @@ class Groups < Spinach::FeatureSteps | @@ -98,6 +98,40 @@ class Groups < Spinach::FeatureSteps | ||
98 | end | 98 | end |
99 | end | 99 | end |
100 | 100 | ||
101 | + step 'I change my group avatar' do | ||
102 | + attach_file(:group_avatar, File.join(Rails.root, 'public', 'gitlab_logo.png')) | ||
103 | + click_button "Save group" | ||
104 | + @group.reload | ||
105 | + end | ||
106 | + | ||
107 | + step 'I should see new group avatar' do | ||
108 | + @group.avatar.should be_instance_of AttachmentUploader | ||
109 | + @group.avatar.url.should == "/uploads/group/avatar/#{ @group.id }/gitlab_logo.png" | ||
110 | + end | ||
111 | + | ||
112 | + step 'I should see the "Remove avatar" button' do | ||
113 | + page.should have_link("Remove avatar") | ||
114 | + end | ||
115 | + | ||
116 | + step 'I have an group avatar' do | ||
117 | + attach_file(:group_avatar, File.join(Rails.root, 'public', 'gitlab_logo.png')) | ||
118 | + click_button "Save group" | ||
119 | + @group.reload | ||
120 | + end | ||
121 | + | ||
122 | + step 'I remove my group avatar' do | ||
123 | + click_link "Remove avatar" | ||
124 | + @group.reload | ||
125 | + end | ||
126 | + | ||
127 | + step 'I should not see my group avatar' do | ||
128 | + @group.avatar?.should be_false | ||
129 | + end | ||
130 | + | ||
131 | + step 'I should not see the "Remove avatar" button' do | ||
132 | + page.should_not have_link("Remove avatar") | ||
133 | + end | ||
134 | + | ||
101 | protected | 135 | protected |
102 | 136 | ||
103 | def current_group | 137 | def current_group |
spec/helpers/application_helper_spec.rb
@@ -39,6 +39,23 @@ describe ApplicationHelper do | @@ -39,6 +39,23 @@ describe ApplicationHelper do | ||
39 | end | 39 | end |
40 | end | 40 | end |
41 | 41 | ||
42 | + describe "group_icon" do | ||
43 | + avatar_file_path = File.join(Rails.root, 'public', 'gitlab_logo.png') | ||
44 | + | ||
45 | + it "should return an url for the avatar" do | ||
46 | + group = create(:group) | ||
47 | + group.avatar = File.open(avatar_file_path) | ||
48 | + group.save! | ||
49 | + group_icon(group.path).to_s.should == "/uploads/group/avatar/#{ group.id }/gitlab_logo.png" | ||
50 | + end | ||
51 | + | ||
52 | + it "should give default avatar_icon when no avatar is present" do | ||
53 | + group = create(:group) | ||
54 | + group.save! | ||
55 | + group_icon(group.path).to_s.should == "/assets/no_group_avatar.png" | ||
56 | + end | ||
57 | + end | ||
58 | + | ||
42 | describe "avatar_icon" do | 59 | describe "avatar_icon" do |
43 | avatar_file_path = File.join(Rails.root, 'public', 'gitlab_logo.png') | 60 | avatar_file_path = File.join(Rails.root, 'public', 'gitlab_logo.png') |
44 | 61 |
spec/models/group_spec.rb
@@ -54,4 +54,19 @@ describe Group do | @@ -54,4 +54,19 @@ describe Group do | ||
54 | group.users_groups.guests.map(&:user).should_not include(user) | 54 | group.users_groups.guests.map(&:user).should_not include(user) |
55 | end | 55 | end |
56 | end | 56 | end |
57 | + | ||
58 | + describe :avatar_type do | ||
59 | + let(:user) { create(:user) } | ||
60 | + before { group.add_user(user, UsersGroup::MASTER) } | ||
61 | + | ||
62 | + it "should be true if avatar is image" do | ||
63 | + group.update_attribute(:avatar, 'uploads/avatar.png') | ||
64 | + group.avatar_type.should be_true | ||
65 | + end | ||
66 | + | ||
67 | + it "should be false if avatar is html page" do | ||
68 | + group.update_attribute(:avatar, 'uploads/avatar.html') | ||
69 | + group.avatar_type.should == ["only images allowed"] | ||
70 | + end | ||
71 | + end | ||
57 | end | 72 | end |