From 714f7201d3362793d11f33793e5ef6dc83bdd2f0 Mon Sep 17 00:00:00 2001 From: Ciro Santilli Date: Thu, 26 Jun 2014 09:49:14 +0200 Subject: Add project stars. --- CHANGELOG | 1 + app/assets/stylesheets/behaviors.scss | 6 +++ app/assets/stylesheets/generic/buttons.scss | 3 +- app/assets/stylesheets/main/variables.scss | 2 + app/assets/stylesheets/sections/projects.scss | 16 ++++++++ app/controllers/projects_controller.rb | 5 +++ app/models/project.rb | 6 +++ app/models/user.rb | 15 +++++++ app/models/users_star_project.rb | 19 +++++++++ app/views/projects/_home_panel.html.haml | 26 ++++++++++-- app/views/projects/_link_to_toggle_star.html.haml | 13 ++++++ config/routes.rb | 1 + .../20140625115202_create_users_star_projects.rb | 13 ++++++ db/schema.rb | 13 +++++- features/project/star.feature | 48 ++++++++++++++++++++++ features/steps/project/star.rb | 29 +++++++++++++ features/steps/public/projects.rb | 24 ----------- features/steps/shared/authentication.rb | 4 ++ features/steps/shared/paths.rb | 32 +++++++++++++-- features/steps/shared/project.rb | 8 ++++ features/steps/shared/user.rb | 5 +++ spec/controllers/projects_controller_spec.rb | 14 +++++++ spec/models/project_spec.rb | 18 ++++++++ spec/models/user_spec.rb | 13 ++++++ spec/support/login_helpers.rb | 2 +- 25 files changed, 301 insertions(+), 35 deletions(-) create mode 100644 app/models/users_star_project.rb create mode 100644 app/views/projects/_link_to_toggle_star.html.haml create mode 100644 db/migrate/20140625115202_create_users_star_projects.rb create mode 100644 features/project/star.feature create mode 100644 features/steps/project/star.rb diff --git a/CHANGELOG b/CHANGELOG index 66244ae0723..95eee7421a5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -24,6 +24,7 @@ v 7.1.0 - Increased default git max_size value from 5MB to 20MB in gitlab.yml. Please update your configs! - Show error message in case of timeout in satellite when create MR - Show first 100 files for huge diff instead of hiding all + - Add project stars (Ciro Santilli) v 7.0.0 - The CPU no longer overheats when you hold down the spacebar diff --git a/app/assets/stylesheets/behaviors.scss b/app/assets/stylesheets/behaviors.scss index 23f206ce3dc..034692a67e1 100644 --- a/app/assets/stylesheets/behaviors.scss +++ b/app/assets/stylesheets/behaviors.scss @@ -4,3 +4,9 @@ .js-details-container .content.hide { display: block; } .js-details-container.open .content { display: block; } .js-details-container.open .content.hide { display: none; } + +// Toggle between two states. +.js-toggler-container .turn-on { display: inline-block; } +.js-toggler-container .turn-off { display: none; } +.js-toggler-container.on .turn-on { display: none; } +.js-toggler-container.on .turn-off { display: inline-block; } diff --git a/app/assets/stylesheets/generic/buttons.scss b/app/assets/stylesheets/generic/buttons.scss index 046e5040fb2..d098f1ecaa2 100644 --- a/app/assets/stylesheets/generic/buttons.scss +++ b/app/assets/stylesheets/generic/buttons.scss @@ -6,7 +6,7 @@ vertical-align: middle; cursor: pointer; background-image: none; - border: 1px solid transparent; + border: $btn-border; white-space: nowrap; padding: 6px 12px; font-size: 13px; @@ -19,7 +19,6 @@ user-select: none; color: #444444; background-color: #fff; - border-color: #ccc; text-shadow: none; &.hover, diff --git a/app/assets/stylesheets/main/variables.scss b/app/assets/stylesheets/main/variables.scss index c49f7db788e..02ce2c8338f 100644 --- a/app/assets/stylesheets/main/variables.scss +++ b/app/assets/stylesheets/main/variables.scss @@ -10,6 +10,8 @@ $hover: #D9EDF7; $link_color: #446e9b; $link_hover_color: #2FA0BB; +$btn-border: 1px solid #ccc; + /* * Success colors (green) */ diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss index c9188fb751c..eecc49620fd 100644 --- a/app/assets/stylesheets/sections/projects.scss +++ b/app/assets/stylesheets/sections/projects.scss @@ -50,6 +50,22 @@ margin-left: 10px; font-weight: 500; } + + .star .btn { + font-weight: bold; + line-height: 22px; + padding: 0px; + $margin-x: 6px; + .toggle { + display: inline-block; + padding: 0px $margin-x; + } + .count { + border-left: $btn-border; + display: inline-block; + padding: 0px $margin-x; + } + } } } diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 597efa40ded..cf7209b05e6 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -167,6 +167,11 @@ class ProjectsController < ApplicationController end end + def toggle_star + current_user.toggle_star(@project) + render json: { star_count: @project.star_count } + end + private def upload_path diff --git a/app/models/project.rb b/app/models/project.rb index 339143196a7..fdd7840aac6 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -81,6 +81,8 @@ class Project < ActiveRecord::Base has_many :users, through: :users_projects has_many :deploy_keys_projects, dependent: :destroy has_many :deploy_keys, through: :deploy_keys_projects + has_many :users_star_projects, dependent: :destroy + has_many :starrers, through: :users_star_projects, source: :user delegate :name, to: :owner, allow_nil: true, prefix: true delegate :members, to: :team, prefix: true @@ -575,4 +577,8 @@ class Project < ActiveRecord::Base def update_repository_size update_attribute(:repository_size, repository.size) end + + def star_count + starrers.count + end end diff --git a/app/models/user.rb b/app/models/user.rb index 19104336598..f5aab99c6a9 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -91,6 +91,8 @@ class User < ActiveRecord::Base has_many :personal_projects, through: :namespace, source: :projects has_many :projects, through: :users_projects has_many :created_projects, foreign_key: :creator_id, class_name: 'Project' + has_many :users_star_projects, dependent: :destroy + has_many :starred_projects, through: :users_star_projects, source: :project has_many :snippets, dependent: :destroy, foreign_key: :author_id, class_name: "Snippet" has_many :users_projects, dependent: :destroy @@ -508,4 +510,17 @@ class User < ActiveRecord::Base def system_hook_service SystemHooksService.new end + + def starred?(project) + starred_projects.exists?(project) + end + + def toggle_star(project) + user_star_project = users_star_projects.where(project: project).take + if user_star_project + user_star_project.destroy + else + UsersStarProject.create!(project: project, user: self) + end + end end diff --git a/app/models/users_star_project.rb b/app/models/users_star_project.rb new file mode 100644 index 00000000000..1f5ae37b02b --- /dev/null +++ b/app/models/users_star_project.rb @@ -0,0 +1,19 @@ +# == Schema Information +# +# Table name: users_star_projects +# +# id :integer not null, primary key +# starrer_id :integer not null +# project_id :integer not null +# created_at :datetime +# updated_at :datetime +# + +class UsersStarProject < ActiveRecord::Base + belongs_to :project + belongs_to :user + + validates :user, presence: true + validates :user_id, uniqueness: { scope: [:project_id] } + validates :project, presence: true +end diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml index ddf815ebd99..6d7f859c22a 100644 --- a/app/views/projects/_home_panel.html.haml +++ b/app/views/projects/_home_panel.html.haml @@ -27,10 +27,30 @@ = link_to project_blob_path(@project, tree_join(@repository.root_ref, readme.name)) do = readme.name - - unless empty_repo - .col-md-5 - .project-home-links + .col-md-5 + .project-home-links + - unless empty_repo = link_to pluralize(number_with_delimiter(@repository.commit_count), 'commit'), project_commits_path(@project, @ref || @repository.root_ref) = link_to pluralize(number_with_delimiter(@repository.branch_names.count), 'branch'), project_branches_path(@project) = link_to pluralize(number_with_delimiter(@repository.tag_names.count), 'tag'), project_tags_path(@project) %span.light.prepend-left-20= repository_size + %span.star.js-toggler-container.on + - if current_user + = render 'link_to_toggle_star', + title: 'Star this project.', + starred: false, + signed_in: true + = render 'link_to_toggle_star', + title: 'Unstar this project.', + starred: true, + signed_in: true + :coffeescript + $('.star').on 'ajax:success', (e, data, status, xhr) -> + $(@).toggleClass('on').find('.count').html(data.star_count) + .on 'ajax:error', (e, xhr, status, error) -> + new Flash('Star toggle failed. Try again later.', 'alert') + - else + = render 'link_to_toggle_star', + title: 'You must sign in to star a project.', + starred: false, + signed_in: false diff --git a/app/views/projects/_link_to_toggle_star.html.haml b/app/views/projects/_link_to_toggle_star.html.haml new file mode 100644 index 00000000000..7d41578c8f3 --- /dev/null +++ b/app/views/projects/_link_to_toggle_star.html.haml @@ -0,0 +1,13 @@ +- cls = 'btn' +- cls += ' disabled' unless signed_in +%span{class: starred ? 'turn-on' : 'turn-off'} + = link_to toggle_star_project_path(@project), title: title, + class: cls, method: :post, remote: true, data: {type: 'json'} do + %span.toggle<> + %i.icon-star + - if starred + Unstar + - else + Star + %span.count<> + = @project.star_count diff --git a/config/routes.rb b/config/routes.rb index f73fd7a87fa..bd639e18932 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -175,6 +175,7 @@ Gitlab::Application.routes.draw do post :archive post :unarchive post :upload_image + post :toggle_star get :autocomplete_sources get :import put :retry_import diff --git a/db/migrate/20140625115202_create_users_star_projects.rb b/db/migrate/20140625115202_create_users_star_projects.rb new file mode 100644 index 00000000000..70475535d54 --- /dev/null +++ b/db/migrate/20140625115202_create_users_star_projects.rb @@ -0,0 +1,13 @@ +class CreateUsersStarProjects < ActiveRecord::Migration + def change + create_table :users_star_projects do |t| + t.integer :project_id, null: false + t.integer :user_id, null: false + t.timestamps + end + + add_index :users_star_projects, :user_id + add_index :users_star_projects, :project_id + add_index :users_star_projects, [:user_id, :project_id], unique: true + end +end diff --git a/db/schema.rb b/db/schema.rb index 345b6fd3b68..fd0f15a7fa6 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: 20140611135229) do +ActiveRecord::Schema.define(version: 20140625115202) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -369,6 +369,17 @@ ActiveRecord::Schema.define(version: 20140611135229) do add_index "users_projects", ["project_id"], name: "index_users_projects_on_project_id", using: :btree add_index "users_projects", ["user_id"], name: "index_users_projects_on_user_id", using: :btree + create_table "users_star_projects", force: true do |t| + t.integer "project_id", null: false + t.integer "user_id", null: false + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "users_star_projects", ["project_id"], name: "index_users_star_projects_on_project_id", using: :btree + add_index "users_star_projects", ["user_id", "project_id"], name: "index_users_star_projects_on_user_id_and_project_id", unique: true, using: :btree + add_index "users_star_projects", ["user_id"], name: "index_users_star_projects_on_user_id", using: :btree + create_table "web_hooks", force: true do |t| t.string "url" t.integer "project_id" diff --git a/features/project/star.feature b/features/project/star.feature new file mode 100644 index 00000000000..e6cbc78125b --- /dev/null +++ b/features/project/star.feature @@ -0,0 +1,48 @@ +Feature: Project Star + Scenario: New projects have 0 stars + Given public project "Community" + When I visit project "Community" page + Then The project has 0 stars + + Scenario: Empty projects show star count + Given public empty project "Empty Public Project" + When I visit empty project page + Then The project has 0 stars + + Scenario: Signed off users can't star projects + Given public project "Community" + And I visit project "Community" page + When I click on the star toggle button + Then The project has 0 stars + + @javascript + Scenario: Signed in users can toggle star + Given I sign in as "John Doe" + And public project "Community" + And I visit project "Community" page + When I click on the star toggle button + Then The project has 1 star + When I click on the star toggle button + Then The project has 0 stars + + @javascript + Scenario: Star count sums stars + Given I sign in as "John Doe" + And public project "Community" + And I visit project "Community" page + And I click on the star toggle button + And I logout + And I sign in as "Mary Jane" + And I visit project "Community" page + When I click on the star toggle button + Then The project has 2 stars + + @javascript + Scenario: If an user deletes his account his stars are destroyed + Given I sign in as "John Doe" + And public project "Community" + And I visit project "Community" page + And I click on the star toggle button + And I delete my account + When I visit project "Community" page + Then The project has 0 stars diff --git a/features/steps/project/star.rb b/features/steps/project/star.rb new file mode 100644 index 00000000000..11102900ed4 --- /dev/null +++ b/features/steps/project/star.rb @@ -0,0 +1,29 @@ +class Spinach::Features::ProjectStar < Spinach::FeatureSteps + include SharedAuthentication + include SharedProject + include SharedPaths + include SharedUser + + step "The project has 0 stars" do + has_n_stars(0) + end + + step "The project has 1 star" do + has_n_stars(1) + end + + step "The project has 2 stars" do + has_n_stars(2) + end + + # Requires @javascript + step "I click on the star toggle button" do + page.find(".star .toggle", visible: true).click + end + + protected + + def has_n_stars(n) + expect(page).to have_css(".star .count", text: /^#{n}$/, visible: true) + end +end diff --git a/features/steps/public/projects.rb b/features/steps/public/projects.rb index 7c7311bb91c..f6ed838d2dc 100644 --- a/features/steps/public/projects.rb +++ b/features/steps/public/projects.rb @@ -3,10 +3,6 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps include SharedPaths include SharedProject - step 'public empty project "Empty Public Project"' do - create :empty_project, :public, name: 'Empty Public Project' - end - step 'I should see project "Empty Public Project"' do page.should have_content "Empty Public Project" end @@ -20,16 +16,6 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps page.should have_content 'README.md' end - step 'I visit empty project page' do - project = Project.find_by(name: 'Empty Public Project') - visit project_path(project) - end - - step 'I visit project "Community" page' do - project = Project.find_by(name: 'Community') - visit project_path(project) - end - step 'I should see empty public project details' do page.should have_content 'Git global setup' end @@ -48,22 +34,12 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps end end - step 'I visit project "Enterprise" page' do - project = Project.find_by(name: 'Enterprise') - visit project_path(project) - end - step 'I should see project "Community" home page' do within '.project-home-title' do page.should have_content 'Community' end end - step 'I visit project "Internal" page' do - project = Project.find_by(name: 'Internal') - visit project_path(project) - end - step 'I should see project "Internal" home page' do within '.project-home-title' do page.should have_content 'Internal' diff --git a/features/steps/shared/authentication.rb b/features/steps/shared/authentication.rb index b8c11ce0a23..b48021dc146 100644 --- a/features/steps/shared/authentication.rb +++ b/features/steps/shared/authentication.rb @@ -24,6 +24,10 @@ module SharedAuthentication current_path.should == new_user_session_path end + step "I logout" do + logout + end + def current_user @user || User.first end diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index 2090b642059..dc1f3eb64a0 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -319,6 +319,34 @@ module SharedPaths visit project_wiki_path(@project, :home) end + # ---------------------------------------- + # Visibility Projects + # ---------------------------------------- + + step 'I visit project "Community" page' do + project = Project.find_by(name: "Community") + visit project_path(project) + end + + step 'I visit project "Internal" page' do + project = Project.find_by(name: "Internal") + visit project_path(project) + end + + step 'I visit project "Enterprise" page' do + project = Project.find_by(name: "Enterprise") + visit project_path(project) + end + + # ---------------------------------------- + # Empty Projects + # ---------------------------------------- + + step "I visit empty project page" do + project = Project.find_by(name: "Empty Public Project") + visit project_path(project) + end + # ---------------------------------------- # Public Projects # ---------------------------------------- @@ -327,10 +355,6 @@ module SharedPaths visit public_root_path end - step 'I visit public page for "Community" project' do - visit public_project_path(Project.find_by(name: "Community")) - end - # ---------------------------------------- # Snippets # ---------------------------------------- diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb index ddb87daeeb7..ba6f090a706 100644 --- a/features/steps/shared/project.rb +++ b/features/steps/shared/project.rb @@ -122,4 +122,12 @@ module SharedProject project ||= create :empty_project, :public, name: 'Community', namespace: user.namespace project.team << [user, :master] end + + # ---------------------------------------- + # Empty projects + # ---------------------------------------- + + step 'public empty project "Empty Public Project"' do + create :empty_project, :public, name: "Empty Public Project" + end end diff --git a/features/steps/shared/user.rb b/features/steps/shared/user.rb index 209d77c7acf..f52551c9dc7 100644 --- a/features/steps/shared/user.rb +++ b/features/steps/shared/user.rb @@ -9,6 +9,11 @@ module SharedUser user_exists("Mary Jane", {username: "mary_jane"}) end + step "I delete my account" do + visit profile_account_path + click_link "Delete account" + end + protected def user_exists(name, options = {}) diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index 944df5314bd..c7a48898c56 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -2,6 +2,7 @@ require('spec_helper') describe ProjectsController do let(:project) { create(:project) } + let(:public_project) { create(:project, :public) } let(:user) { create(:user) } let(:jpg) { fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg') } let(:txt) { fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') } @@ -40,4 +41,17 @@ describe ProjectsController do end end end + + describe "POST #toggle_star" do + it "increases star count if user is signed in" do + sign_in(user) + post :toggle_star, id: public_project.to_param + expect(public_project.star_count).to eq(1) + end + + it "does nothing if user is not signed in" do + post :toggle_star, id: public_project.to_param + expect(public_project.star_count).to eq(0) + end + end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index c3263ed0fe7..c2ebfbd9229 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -240,4 +240,22 @@ describe Project do it { project.open_branches.map(&:name).should include('bootstrap') } it { project.open_branches.map(&:name).should_not include('master') } end + + describe "#count_star" do + it "counts stars" do + user1 = create :user + user2 = create :user + project = create :project, :public + + expect(project.star_count).to eq(0) + user1.toggle_star(project) + expect(project.star_count).to eq(1) + user2.toggle_star(project) + expect(project.star_count).to eq(2) + user1.toggle_star(project) + expect(project.star_count).to eq(1) + user2.toggle_star(project) + expect(project.star_count).to eq(0) + end + end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index a36b57a95de..b6ffb6ac24b 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -355,4 +355,17 @@ describe User do expect(user.short_website_url).to eq 'test.com' end end + + describe "#toggle_star" do + it "toggles stars" do + user = create :user + project = create :project, :public + + expect(user.starred?(project)).to be_false + user.toggle_star(project) + expect(user.starred?(project)).to be_true + user.toggle_star(project) + expect(user.starred?(project)).to be_false + end + end end diff --git a/spec/support/login_helpers.rb b/spec/support/login_helpers.rb index 7713e9f17d7..88e4d0419cb 100644 --- a/spec/support/login_helpers.rb +++ b/spec/support/login_helpers.rb @@ -20,6 +20,6 @@ module LoginHelpers end def logout - click_link "Logout" rescue nil + page.find(:css, ".icon-signout").click rescue nil end end -- cgit v1.2.1 From c589029667644df4593572e2c94226bd2a5f7740 Mon Sep 17 00:00:00 2001 From: Ciro Santilli Date: Fri, 4 Jul 2014 09:26:59 +0200 Subject: Fix failing spec. --- spec/features/issues_spec.rb | 4 ++-- spec/support/login_helpers.rb | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb index d7f3f3a302c..f0daf081018 100644 --- a/spec/features/issues_spec.rb +++ b/spec/features/issues_spec.rb @@ -226,7 +226,7 @@ describe "Issues", feature: true do issue.save end - it 'shows assignee text' do + it "shows assignee text", js: true do logout login_with guest @@ -262,7 +262,7 @@ describe "Issues", feature: true do issue.save end - it 'shows milestone text' do + it "shows milestone text", js: true do logout login_with guest diff --git a/spec/support/login_helpers.rb b/spec/support/login_helpers.rb index 88e4d0419cb..238ac7c6611 100644 --- a/spec/support/login_helpers.rb +++ b/spec/support/login_helpers.rb @@ -19,7 +19,8 @@ module LoginHelpers Thread.current[:current_user] = user end + # Requires Javascript driver. def logout - page.find(:css, ".icon-signout").click rescue nil + page.find(:css, ".icon-signout").click end end -- cgit v1.2.1 From ecd771ccdfe54b08ea7f80f64667228b7938238d Mon Sep 17 00:00:00 2001 From: Ciro Santilli Date: Mon, 14 Jul 2014 11:50:35 +0200 Subject: Move coffee to assets/project --- app/assets/javascripts/project.js.coffee | 5 +++++ app/views/projects/_home_panel.html.haml | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/project.js.coffee b/app/assets/javascripts/project.js.coffee index 4262418fd5e..d81cc087df9 100644 --- a/app/assets/javascripts/project.js.coffee +++ b/app/assets/javascripts/project.js.coffee @@ -46,3 +46,8 @@ $ -> $.cookie('hide_no_ssh_message', 'false', { path: path }) $(@).parents('.no-ssh-key-message').hide() e.preventDefault() + + $('.project-home-panel .star').on 'ajax:success', (e, data, status, xhr) -> + $(@).toggleClass('on').find('.count').html(data.star_count) + .on 'ajax:error', (e, xhr, status, error) -> + new Flash('Star toggle failed. Try again later.', 'alert') diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml index 6d7f859c22a..48f5a90cf23 100644 --- a/app/views/projects/_home_panel.html.haml +++ b/app/views/projects/_home_panel.html.haml @@ -44,11 +44,6 @@ title: 'Unstar this project.', starred: true, signed_in: true - :coffeescript - $('.star').on 'ajax:success', (e, data, status, xhr) -> - $(@).toggleClass('on').find('.count').html(data.star_count) - .on 'ajax:error', (e, xhr, status, error) -> - new Flash('Star toggle failed. Try again later.', 'alert') - else = render 'link_to_toggle_star', title: 'You must sign in to star a project.', -- cgit v1.2.1 From 9b5c7a4d6026265cfeaeac9ad5101f8826515dbe Mon Sep 17 00:00:00 2001 From: Ciro Santilli Date: Mon, 14 Jul 2014 15:17:59 +0200 Subject: Add star count, view logic, more tests. --- app/controllers/projects_controller.rb | 3 ++ app/models/project.rb | 6 +-- app/models/user.rb | 3 +- app/models/users_star_project.rb | 2 +- app/views/projects/_home_panel.html.haml | 2 +- .../20140625115202_create_users_star_projects.rb | 4 +- db/schema.rb | 2 + spec/controllers/projects_controller_spec.rb | 11 +++-- spec/models/project_spec.rb | 52 +++++++++++++++++++--- spec/models/user_spec.rb | 27 +++++++++++ 10 files changed, 95 insertions(+), 17 deletions(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index cf7209b05e6..9c9677a22c8 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -60,6 +60,8 @@ class ProjectsController < ApplicationController @events = event_filter.apply_filter(@events) @events = @events.limit(limit).offset(params[:offset] || 0) + @show_star = !(current_user and current_user.starred?(@project)) + respond_to do |format| format.html do if @project.empty_repo? @@ -169,6 +171,7 @@ class ProjectsController < ApplicationController def toggle_star current_user.toggle_star(@project) + @project.reload render json: { star_count: @project.star_count } end diff --git a/app/models/project.rb b/app/models/project.rb index fdd7840aac6..10882ea97cc 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -22,6 +22,7 @@ # visibility_level :integer default(0), not null # archived :boolean default(FALSE), not null # import_status :string(255) +# star_count :integer # class Project < ActiveRecord::Base @@ -109,6 +110,7 @@ class Project < ActiveRecord::Base validates :import_url, format: { with: URI::regexp(%w(git http https)), message: "should be a valid url" }, if: :import? + validates :star_count, numericality: { greater_than_or_equal_to: 0 } validate :check_limit, on: :create # Scopes @@ -577,8 +579,4 @@ class Project < ActiveRecord::Base def update_repository_size update_attribute(:repository_size, repository.size) end - - def star_count - starrers.count - end end diff --git a/app/models/user.rb b/app/models/user.rb index f5aab99c6a9..39d2d9cce7f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -516,7 +516,8 @@ class User < ActiveRecord::Base end def toggle_star(project) - user_star_project = users_star_projects.where(project: project).take + user_star_project = users_star_projects. + where(project: project, user: self).take if user_star_project user_star_project.destroy else diff --git a/app/models/users_star_project.rb b/app/models/users_star_project.rb index 1f5ae37b02b..80e756bd00c 100644 --- a/app/models/users_star_project.rb +++ b/app/models/users_star_project.rb @@ -10,7 +10,7 @@ # class UsersStarProject < ActiveRecord::Base - belongs_to :project + belongs_to :project, counter_cache: :star_count belongs_to :user validates :user, presence: true diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml index 48f5a90cf23..419b50a1141 100644 --- a/app/views/projects/_home_panel.html.haml +++ b/app/views/projects/_home_panel.html.haml @@ -34,7 +34,7 @@ = link_to pluralize(number_with_delimiter(@repository.branch_names.count), 'branch'), project_branches_path(@project) = link_to pluralize(number_with_delimiter(@repository.tag_names.count), 'tag'), project_tags_path(@project) %span.light.prepend-left-20= repository_size - %span.star.js-toggler-container.on + %span.star.js-toggler-container{class: @show_star ? 'on' : ''} - if current_user = render 'link_to_toggle_star', title: 'Star this project.', diff --git a/db/migrate/20140625115202_create_users_star_projects.rb b/db/migrate/20140625115202_create_users_star_projects.rb index 70475535d54..412f0f6f34b 100644 --- a/db/migrate/20140625115202_create_users_star_projects.rb +++ b/db/migrate/20140625115202_create_users_star_projects.rb @@ -5,9 +5,11 @@ class CreateUsersStarProjects < ActiveRecord::Migration t.integer :user_id, null: false t.timestamps end - add_index :users_star_projects, :user_id add_index :users_star_projects, :project_id add_index :users_star_projects, [:user_id, :project_id], unique: true + + add_column :projects, :star_count, :integer, default: 0, null: false + add_index :projects, :star_count, using: :btree end end diff --git a/db/schema.rb b/db/schema.rb index fd0f15a7fa6..e4dcdf5bea2 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -224,11 +224,13 @@ ActiveRecord::Schema.define(version: 20140625115202) do t.boolean "archived", default: false, null: false t.string "import_status" t.float "repository_size", default: 0.0 + t.integer "star_count", default: 0, null: false end add_index "projects", ["creator_id"], name: "index_projects_on_creator_id", using: :btree add_index "projects", ["last_activity_at"], name: "index_projects_on_last_activity_at", using: :btree add_index "projects", ["namespace_id"], name: "index_projects_on_namespace_id", using: :btree + add_index "projects", ["star_count"], name: "index_projects_on_star_count", using: :btree create_table "protected_branches", force: true do |t| t.integer "project_id", null: false diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index c7a48898c56..71bc49787cc 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -43,15 +43,20 @@ describe ProjectsController do end describe "POST #toggle_star" do - it "increases star count if user is signed in" do + it "toggles star if user is signed in" do sign_in(user) + expect(user.starred?(public_project)).to be_false post :toggle_star, id: public_project.to_param - expect(public_project.star_count).to eq(1) + expect(user.starred?(public_project)).to be_true + post :toggle_star, id: public_project.to_param + expect(user.starred?(public_project)).to be_false end it "does nothing if user is not signed in" do post :toggle_star, id: public_project.to_param - expect(public_project.star_count).to eq(0) + expect(user.starred?(public_project)).to be_false + post :toggle_star, id: public_project.to_param + expect(user.starred?(public_project)).to be_false end end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index c2ebfbd9229..72673a1f812 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -241,21 +241,61 @@ describe Project do it { project.open_branches.map(&:name).should_not include('master') } end - describe "#count_star" do - it "counts stars" do + describe "#star_count" do + it "counts stars from multiple users" do user1 = create :user user2 = create :user project = create :project, :public expect(project.star_count).to eq(0) + user1.toggle_star(project) - expect(project.star_count).to eq(1) + expect(project.reload.star_count).to eq(1) + user2.toggle_star(project) - expect(project.star_count).to eq(2) + project.reload + expect(project.reload.star_count).to eq(2) + user1.toggle_star(project) - expect(project.star_count).to eq(1) + project.reload + expect(project.reload.star_count).to eq(1) + user2.toggle_star(project) - expect(project.star_count).to eq(0) + project.reload + expect(project.reload.star_count).to eq(0) + end + + it "counts stars on the right project" do + user = create :user + project1 = create :project, :public + project2 = create :project, :public + + expect(project1.star_count).to eq(0) + expect(project2.star_count).to eq(0) + + user.toggle_star(project1) + project1.reload + project2.reload + expect(project1.star_count).to eq(1) + expect(project2.star_count).to eq(0) + + user.toggle_star(project1) + project1.reload + project2.reload + expect(project1.star_count).to eq(0) + expect(project2.star_count).to eq(0) + + user.toggle_star(project2) + project1.reload + project2.reload + expect(project1.star_count).to eq(0) + expect(project2.star_count).to eq(1) + + user.toggle_star(project2) + project1.reload + project2.reload + expect(project1.star_count).to eq(0) + expect(project2.star_count).to eq(0) end end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index b6ffb6ac24b..ef6b8a94502 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -356,6 +356,33 @@ describe User do end end + describe "#starred?" do + it "determines if user starred a project" do + user = create :user + project1 = create :project, :public + project2 = create :project, :public + + expect(user.starred?(project1)).to be_false + expect(user.starred?(project2)).to be_false + + star1 = UsersStarProject.create!(project: project1, user: user) + expect(user.starred?(project1)).to be_true + expect(user.starred?(project2)).to be_false + + star2 = UsersStarProject.create!(project: project2, user: user) + expect(user.starred?(project1)).to be_true + expect(user.starred?(project2)).to be_true + + star1.destroy + expect(user.starred?(project1)).to be_false + expect(user.starred?(project2)).to be_true + + star2.destroy + expect(user.starred?(project1)).to be_false + expect(user.starred?(project2)).to be_false + end + end + describe "#toggle_star" do it "toggles stars" do user = create :user -- cgit v1.2.1 From 0a6e978db70bb4d84ce7993f5376f395c6bea11e Mon Sep 17 00:00:00 2001 From: Ciro Santilli Date: Tue, 15 Jul 2014 12:00:51 +0200 Subject: Fix hound. --- app/controllers/projects_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 9c9677a22c8..837b6d5b23d 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -60,7 +60,7 @@ class ProjectsController < ApplicationController @events = event_filter.apply_filter(@events) @events = @events.limit(limit).offset(params[:offset] || 0) - @show_star = !(current_user and current_user.starred?(@project)) + @show_star = !(current_user && current_user.starred?(@project)) respond_to do |format| format.html do -- cgit v1.2.1 From 1591467655b6045108f88e8ac2d8b6a069ef4bb1 Mon Sep 17 00:00:00 2001 From: Ciro Santilli Date: Thu, 17 Jul 2014 22:45:16 +0200 Subject: Helper instead of template. --- app/helpers/projects_helper.rb | 22 ++++++++++++++++++++++ app/views/projects/_home_panel.html.haml | 15 +++------------ app/views/projects/_link_to_toggle_star.html.haml | 13 ------------- 3 files changed, 25 insertions(+), 25 deletions(-) delete mode 100644 app/views/projects/_link_to_toggle_star.html.haml diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index bc2ec84302d..1304e2dea23 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -122,6 +122,28 @@ module ProjectsHelper options_for_select(values, current_tracker) end + def link_to_toggle_star(title, starred, signed_in) + cls = 'btn' + cls += ' disabled' unless signed_in + content_tag 'span', class: starred ? 'turn-on' : 'turn-off' do + link_to toggle_star_project_path(@project), + title: title, class: cls, method: :post, remote: true, + data: {type: 'json'} do + content_tag('span', class: 'toggle') do + content_tag('i', ' ', class: 'icon-star') << + if starred + 'Unstar' + else + 'Star' + end + end << + content_tag('span', class: 'count') do + @project.star_count.to_s + end + end + end + end + private def get_project_nav_tabs(project, current_user) diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml index 419b50a1141..bf9301d70c4 100644 --- a/app/views/projects/_home_panel.html.haml +++ b/app/views/projects/_home_panel.html.haml @@ -36,16 +36,7 @@ %span.light.prepend-left-20= repository_size %span.star.js-toggler-container{class: @show_star ? 'on' : ''} - if current_user - = render 'link_to_toggle_star', - title: 'Star this project.', - starred: false, - signed_in: true - = render 'link_to_toggle_star', - title: 'Unstar this project.', - starred: true, - signed_in: true + = link_to_toggle_star('Star this project.', false, true) + = link_to_toggle_star('Unstar this project.', true, true) - else - = render 'link_to_toggle_star', - title: 'You must sign in to star a project.', - starred: false, - signed_in: false + = link_to_toggle_star('You must sign in to star a project.', false, false) diff --git a/app/views/projects/_link_to_toggle_star.html.haml b/app/views/projects/_link_to_toggle_star.html.haml deleted file mode 100644 index 7d41578c8f3..00000000000 --- a/app/views/projects/_link_to_toggle_star.html.haml +++ /dev/null @@ -1,13 +0,0 @@ -- cls = 'btn' -- cls += ' disabled' unless signed_in -%span{class: starred ? 'turn-on' : 'turn-off'} - = link_to toggle_star_project_path(@project), title: title, - class: cls, method: :post, remote: true, data: {type: 'json'} do - %span.toggle<> - %i.icon-star - - if starred - Unstar - - else - Star - %span.count<> - = @project.star_count -- cgit v1.2.1 From e1d307bf4b88afa59d851918c29ffbb61b01e8c5 Mon Sep 17 00:00:00 2001 From: Ciro Santilli Date: Thu, 17 Jul 2014 23:22:40 +0200 Subject: Move destroy user feature to spec. --- features/project/star.feature | 10 ---------- features/steps/shared/user.rb | 5 ----- spec/models/project_spec.rb | 17 ++++++++++++++--- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/features/project/star.feature b/features/project/star.feature index e6cbc78125b..d8d898155fe 100644 --- a/features/project/star.feature +++ b/features/project/star.feature @@ -36,13 +36,3 @@ Feature: Project Star And I visit project "Community" page When I click on the star toggle button Then The project has 2 stars - - @javascript - Scenario: If an user deletes his account his stars are destroyed - Given I sign in as "John Doe" - And public project "Community" - And I visit project "Community" page - And I click on the star toggle button - And I delete my account - When I visit project "Community" page - Then The project has 0 stars diff --git a/features/steps/shared/user.rb b/features/steps/shared/user.rb index f52551c9dc7..209d77c7acf 100644 --- a/features/steps/shared/user.rb +++ b/features/steps/shared/user.rb @@ -9,11 +9,6 @@ module SharedUser user_exists("Mary Jane", {username: "mary_jane"}) end - step "I delete my account" do - visit profile_account_path - click_link "Delete account" - end - protected def user_exists(name, options = {}) diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 72673a1f812..bc537b7312b 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -241,8 +241,8 @@ describe Project do it { project.open_branches.map(&:name).should_not include('master') } end - describe "#star_count" do - it "counts stars from multiple users" do + describe '#star_count' do + it 'counts stars from multiple users' do user1 = create :user user2 = create :user project = create :project, :public @@ -265,7 +265,7 @@ describe Project do expect(project.reload.star_count).to eq(0) end - it "counts stars on the right project" do + it 'counts stars on the right project' do user = create :user project1 = create :project, :public project2 = create :project, :public @@ -297,5 +297,16 @@ describe Project do expect(project1.star_count).to eq(0) expect(project2.star_count).to eq(0) end + + it 'is decremented when an upvoter account is deleted' do + user = create :user + project = create :project, :public + user.toggle_star(project) + project.reload + expect(project.star_count).to eq(1) + user.destroy + project.reload + expect(project.star_count).to eq(0) + end end end -- cgit v1.2.1