diff --git a/Gemfile b/Gemfile index 853db02d..17f26b7c 100644 --- a/Gemfile +++ b/Gemfile @@ -69,7 +69,7 @@ gem 'whenever' gem 'rqrcode-rails3' gem 'exception_notification' gem 'rack-canonical-host' -gem 'bootstrap_forms' +gem 'bootstrap_forms', github: 'sigmike/bootstrap_forms', branch: 'sanitize_value_in_radio_label_for' group :test do gem 'cucumber-rails', :require => false diff --git a/Gemfile.lock b/Gemfile.lock index 9fccff62..c66fe8cd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -26,6 +26,13 @@ GIT rails (>= 3.1) railties (>= 3.1) +GIT + remote: git://github.com/sigmike/bootstrap_forms.git + revision: e69b6834d36b198d36a8f4a892d1bac6633e7545 + branch: sanitize_value_in_radio_label_for + specs: + bootstrap_forms (4.0.1) + GEM remote: https://rubygems.org/ specs: @@ -60,7 +67,6 @@ GEM arel (4.0.2) atomic (1.1.14) bcrypt-ruby (3.1.2) - bootstrap_forms (4.0.1) builder (3.1.4) capistrano (3.0.1) i18n @@ -277,7 +283,7 @@ PLATFORMS DEPENDENCIES airbrake - bootstrap_forms + bootstrap_forms! capistrano (~> 3.0) capistrano-bundler (>= 1.1.0) capistrano-rails diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 3bd23bdc..01758224 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -28,6 +28,21 @@ def update end end + def decide_tip_amounts + @project = Project.find params[:id] + if request.patch? + @project.attributes = params.require(:project).permit(tips_attributes: [:id, :amount_percentage]) + if @project.save + message = "The tip amounts have been defined" + if @project.has_undecided_tips? + redirect_to decide_tip_amounts_project_path(@project), notice: message + else + redirect_to @project, notice: message + end + end + end + end + def qrcode @project = Project.find params[:id] respond_to do |format| diff --git a/app/models/project.rb b/app/models/project.rb index 251ee04a..50eb2a45 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1,6 +1,7 @@ class Project < ActiveRecord::Base has_many :deposits # todo: only confirmed deposits that have amount > paid_out - has_many :tips + has_many :tips, inverse_of: :project + accepts_nested_attributes_for :tips has_many :collaborators validates :full_name, uniqueness: true, presence: true @@ -115,13 +116,7 @@ def tip_for commit commit: commit.sha }) - # notify user - if tip && tip.amount && user.bitcoin_address.blank? && !user.unsubscribed - if !user.notified_at || (user.notified_at < (Time.now - 30.days)) - UserMailer.new_tip(user, tip).deliver - user.touch :notified_at - end - end + tip.notify_user Rails.logger.info " Tip created #{tip.inspect}" end @@ -185,10 +180,18 @@ def update_info end def tips_to_pay - tips.unpaid.with_address + tips.to_pay end def amount_to_pay tips_to_pay.sum(:amount) end + + def has_undecided_tips? + tips.undecided.any? + end + + def commit_url(commit) + "https://github.com/#{full_name}/commit/#{commit}" + end end diff --git a/app/models/tip.rb b/app/models/tip.rb index 63ae2e12..792a4b51 100644 --- a/app/models/tip.rb +++ b/app/models/tip.rb @@ -1,14 +1,16 @@ class Tip < ActiveRecord::Base belongs_to :user belongs_to :sendmany - belongs_to :project + belongs_to :project, inverse_of: :tips - validates :amount, numericality: {greater_than: 0, allow_nil: true} + validates :amount, numericality: {greater_or_equal_than: 0, allow_nil: true} scope :not_sent, -> { where(sendmany_id: nil) } scope :unpaid, -> { non_refunded.not_sent } + scope :to_pay, -> { unpaid.decided.with_address } + scope :paid, -> { where('sendmany_id is not ?', nil) } scope :refunded, -> { where('refunded_at is not ?', nil) } @@ -21,11 +23,16 @@ class Tip < ActiveRecord::Base scope :with_address, -> { joins(:user).where('users.bitcoin_address IS NOT NULL AND users.bitcoin_address != ?', "") } + scope :undecided, -> { where(amount: nil) } + scope :decided, -> { where.not(amount: nil) } + + after_save :notify_user_if_just_decided + def paid? !!sendmany_id end - def amount_undecided? + def undecided? amount.nil? end @@ -36,4 +43,31 @@ def self.refund_unclaimed tip.touch :refunded_at end end + + def commit_url + project.commit_url(commit) + end + + def amount_percentage + nil + end + + def amount_percentage=(percentage) + if undecided? and percentage.present? + self.amount = project.available_amount * (percentage.to_f / 100) + end + end + + def notify_user + if amount and amount > 0 and user.bitcoin_address.blank? and !user.unsubscribed + if user.notified_at.nil? or user.notified_at < 30.days.ago + UserMailer.new_tip(user, self).deliver + user.touch :notified_at + end + end + end + + def notify_user_if_just_decided + notify_user if amount_was.nil? and amount + end end diff --git a/app/views/projects/decide_tip_amounts.html.haml b/app/views/projects/decide_tip_amounts.html.haml new file mode 100644 index 00000000..f37d3e70 --- /dev/null +++ b/app/views/projects/decide_tip_amounts.html.haml @@ -0,0 +1,25 @@ += bootstrap_form_for @project, url: decide_tip_amounts_project_path(@project) do |f| + %table.table + %thead + %tr + %th Commit + %th Tip (relative to the project balance) + %tbody + = f.fields_for(:tips, @project.tips.undecided) do |tip_fields| + = tip_fields.hidden_field :id + - tip = tip_fields.object + %tr + %td + = link_to tip.commit, tip.commit_url + %td + - radios = {} + - radios["Undecided"] = "" + - radios["Free: 0%"] = "0" + - radios["Tiny: 0.1%"] = "0.1" + - radios["Small: 0.5%"] = "0.5" + - radios["Normal: 1%"] = "1" + - radios["Big: 2%"] = "2" + - radios["Huge: 5%"] = "5" + = tip_fields.radio_buttons(:amount_percentage, radios, inline: true, label: false) + .text-center + = f.submit 'Send the selected tip amounts' diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index db634e0c..dd79d504 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -8,6 +8,8 @@ = @project.full_name %small= link_to glyph(:github), @project.github_url, target: '_blank' = link_to "Change project settings", edit_project_path(@project), class: "btn btn-default" + - if @project.has_undecided_tips? + = link_to "Decide tip amounts", decide_tip_amounts_project_path(@project), class: "btn btn-primary" .row .col-md-4 diff --git a/app/views/tips/index.html.haml b/app/views/tips/index.html.haml index dca6a51a..df75befd 100644 --- a/app/views/tips/index.html.haml +++ b/app/views/tips/index.html.haml @@ -32,6 +32,8 @@ - if tip.sendmany.nil? - if tip.refunded_at Refunded to project's deposit + - elsif tip.undecided? + The amount of tips has not been decided yet - elsif tip.user.bitcoin_address.blank? User didn't specify withdrawal address - elsif tip.project.amount_to_pay < CONFIG["min_payout"].to_d * PeercoinBalanceUpdater::COIN diff --git a/config/routes.rb b/config/routes.rb index bb16e470..6ee4ad84 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -14,6 +14,8 @@ resources :tips, :only => [:index] member do get :qrcode + get :decide_tip_amounts + patch :decide_tip_amounts end end resources :tips, :only => [:index] diff --git a/features/step_definitions/common.rb b/features/step_definitions/common.rb index a3a924b8..8e10884a 100644 --- a/features/step_definitions/common.rb +++ b/features/step_definitions/common.rb @@ -6,6 +6,10 @@ ActionMailer::Base.deliveries.size.should eq(arg1.to_i) end +When(/^the email counters are reset$/) do + ActionMailer::Base.deliveries.clear +end + Given(/^the tip for commit is "(.*?)"$/) do |arg1| CONFIG["tip"] = arg1.to_f end @@ -67,11 +71,13 @@ def find_new_commit(id) end Then(/^there should be a tip of "(.*?)" for commit "(.*?)"$/) do |arg1, arg2| - (Tip.find_by(commit: arg2).amount.to_d / PeercoinBalanceUpdater::COIN).should eq(arg1.to_d) + amount = Tip.find_by(commit: arg2).amount + amount.should_not be_nil + (amount.to_d / PeercoinBalanceUpdater::COIN).should eq(arg1.to_d) end Then(/^the tip amount for commit "(.*?)" should be undecided$/) do |arg1| - Tip.find_by(commit: arg1).amount_undecided?.should be_true + Tip.find_by(commit: arg1).undecided?.should be_true end Then(/^the new last known commit should be "(.*?)"$/) do |arg1| diff --git a/features/step_definitions/tip_modifier_interface.rb b/features/step_definitions/tip_modifier_interface.rb index e69de29b..ad2bbb05 100644 --- a/features/step_definitions/tip_modifier_interface.rb +++ b/features/step_definitions/tip_modifier_interface.rb @@ -0,0 +1,5 @@ +When(/^I choose the amount "(.*?)" on commit "(.*?)"$/) do |arg1, arg2| + within find("tr", text: arg2) do + choose arg1 + end +end diff --git a/features/step_definitions/web.rb b/features/step_definitions/web.rb index c3ee3013..78fbe4a9 100644 --- a/features/step_definitions/web.rb +++ b/features/step_definitions/web.rb @@ -28,3 +28,7 @@ page.should have_content(arg1) end +Then(/^I should not see "(.*?)"$/) do |arg1| + page.should have_no_content(arg1) +end + diff --git a/features/tip_modifier_interface.feature b/features/tip_modifier_interface.feature index 4be55301..b250b2a0 100644 --- a/features/tip_modifier_interface.feature +++ b/features/tip_modifier_interface.feature @@ -6,13 +6,16 @@ Feature: A project collaborator can change the tips of commits | daneel | And our fee is "0" And a deposit of "500" - And the last known commit is "A" - And a new commit "B" with parent "A" - And the author of commit "B" is "yugo" + And the last known commit is "AAA" + And a new commit "BBB" with parent "AAA" + And a new commit "CCC" with parent "BBB" + And the author of commit "BBB" is "yugo" + And the author of commit "CCC" is "seldon" Scenario: Without anything modified When the new commits are read - Then there should be a tip of "5" for commit "B" + Then there should be a tip of "5" for commit "BBB" + And there should be a tip of "4.95" for commit "CCC" And there should be 1 email sent Scenario: A collaborator wants to alter the tips @@ -24,6 +27,26 @@ Feature: A project collaborator can change the tips of commits Then I should see "The project settings have been updated" When the new commits are read - Then the tip amount for commit "B" should be undecided + Then the tip amount for commit "BBB" should be undecided + And the tip amount for commit "CCC" should be undecided + And there should be 0 email sent + + When I go to the project page + And I click on "Decide tip amounts" + Then I should see "BBB" + And I should see "CCC" + And I should not see "AAA" + + When I choose the amount "Tiny: 0.1%" on commit "BBB" + And I click on "Send the selected tip amounts" + Then there should be a tip of "0.5" for commit "BBB" + And the tip amount for commit "CCC" should be undecided + And there should be 1 email sent + + When the email counters are reset + And I choose the amount "Free: 0%" on commit "CCC" + And I click on "Send the selected tip amounts" + Then there should be a tip of "0.5" for commit "BBB" + And there should be a tip of "0" for commit "CCC" And there should be 0 email sent