Skip to content

Commit

Permalink
Handle distribution to user without an address set
Browse files Browse the repository at this point in the history
  • Loading branch information
sigmike committed May 31, 2014
1 parent 7f0e8fe commit ac23eb7
Show file tree
Hide file tree
Showing 16 changed files with 194 additions and 57 deletions.
1 change: 1 addition & 0 deletions Gemfile
Expand Up @@ -83,4 +83,5 @@ group :test do
gem 'rspec-rails'
gem 'factory_girl_rails'
gem 'poltergeist'
gem 'timecop'
end
2 changes: 2 additions & 0 deletions Gemfile.lock
Expand Up @@ -284,6 +284,7 @@ GEM
thread_safe (0.1.3)
atomic
tilt (1.4.1)
timecop (0.7.1)
tins (0.13.1)
treetop (1.4.15)
polyglot
Expand Down Expand Up @@ -345,6 +346,7 @@ DEPENDENCIES
sdoc
sqlite3
therubyracer
timecop
turbolinks
twitter-bootstrap-rails!
uglifier (>= 1.3.0)
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/distributions_controller.rb
Expand Up @@ -30,9 +30,9 @@ def show

def send_transaction
@distribution.send_transaction!
redirect_to [@project, @distribution], notice: "Transaction sent"
redirect_to [@project, @distribution], flash: {notice: "Transaction sent"}
rescue RuntimeError => e
redirect_to [@project, @distribution], error: e.message
redirect_to [@project, @distribution], flash: {error: e.message}
end

private
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/users_controller.rb
Expand Up @@ -16,7 +16,7 @@ def index

def update
if @user.update(users_params)
redirect_to @user, notice: 'Your information saved!'
redirect_to @user, notice: 'Your information was saved.'
else
render :show, alert: 'Error updating peercoin address'
end
Expand Down
19 changes: 11 additions & 8 deletions app/models/distribution.rb
Expand Up @@ -7,21 +7,21 @@ class Distribution < ActiveRecord::Base
scope :error, -> { where(is_error: true) }

def sent?
!!txid
sent_at or txid
end

def total_amount
JSON.parse(data).values.map(&:to_d).sum if data
tips.map(&:amount).compact.sum
end

def send_transaction!
Distribution.transaction do
lock!
return if sent?
return if is_error?
return if project.disabled?
raise "Already sent" if sent?
raise "Transaction already sent and failed" if is_error?
raise "Project disabled" if project.disabled?

update_attribute :is_error, true # it's a lock to prevent duplicates
update!(sent_at: Time.now, is_error: true) # it's a lock to prevent duplicates
end

data = generate_data
Expand All @@ -31,8 +31,7 @@ def send_transaction!

txid = BitcoinDaemon.instance.send_many(project.address_label, JSON.parse(data))

update_attribute :txid, txid
update_attribute :is_error, false
update!(txid: txid, is_error: false)
end

def generate_data
Expand All @@ -42,4 +41,8 @@ def generate_data
end
outs.to_json
end

def all_addresses_known?
tips.all? { |tip| tip.user.bitcoin_address.present? }
end
end
1 change: 1 addition & 0 deletions app/models/tip.rb
Expand Up @@ -91,6 +91,7 @@ def notify_user
end

def notify_user_if_just_decided
return if distribution_id
notify_user if amount_was.nil? and amount
end

Expand Down
12 changes: 9 additions & 3 deletions app/views/distributions/index.html.haml
@@ -1,14 +1,20 @@
%h1 Last Withdrawals
%h1 Distributions
- if @project
%h2= @project.name
%p
%table.table
%thead
%tr
%th Created At
%th Sent at
%th Transaction
%th Result
%th
%tbody
- @distributions.each do |distribution|
%tr
%td= l distribution.created_at, format: :short
%td= link_to distribution.txid, transaction_url(distribution.txid), target: '_blank'
%td= distribution.is_error ? "Error" : "Success"
%td= l distribution.sent_at, format: :short if distribution.sent_at
%td= link_to distribution.txid, transaction_url(distribution.txid), target: '_blank' if distribution.txid.present?
%td= distribution.is_error ? "Error" : "Success" if distribution.sent?
%td= link_to "Details", [distribution.project, distribution], class: "btn btn-success"
17 changes: 15 additions & 2 deletions app/views/distributions/show.html.haml
Expand Up @@ -16,7 +16,20 @@
%td.address= tip.user.bitcoin_address
%td.amount= btc_human tip.amount
%td.percentage= number_to_percentage(tip.amount.to_f * 100 / total, precision: 1)
- if @distribution.sent?
Sent
- if @distribution.is_error?
%p.alert.alert-danger
The transaction failed.
- elsif @distribution.sent?
%p.alert.alert-success
Transaction sent
- if @distribution.sent_at
on #{l(@distribution.sent_at)}
- elsif !@distribution.all_addresses_known?
%p.alert.alert-warning
The transaction cannot be sent because some addresses are missing. Ask the recipients to log in with their GitHub account.
- elsif can? :send_transaction, @distribution
= button_to "Send the transaction", send_transaction_project_distribution_path(@project, @distribution), class: "btn btn-primary", data: {confirm: "#{total.to_f / COIN} peercoins will be sent. Are you sure?"}

- if @distribution.data.present?
%h4 Raw data
%pre= @distribution.data
81 changes: 50 additions & 31 deletions app/views/projects/show.html.haml
Expand Up @@ -19,42 +19,11 @@
= link_to "New distribution", new_project_distribution_path(@project), class: "btn btn-warning"

.row
.col-md-4
- if @project.disabled?
.panel.panel-danger
.panel-heading
%h4.panel-title
Project Disabled
.panel-body.text-center
%p
This project has been disabled.
It doesn't accept donation and it will not distribute tips.
- if (reason = @project.disabled_reason).present?
%p Reason: #{reason}

- else
.panel.panel-default.project-panel
.panel-heading
%h4.panel-title
Project Sponsors
.panel-body.text-center
%p To give to this project, send peercoins to this address:
%p.bitcoin-address
= @project.bitcoin_address
%p
= image_tag qrcode_project_path(@project, format: :svg), alt: @project.bitcoin_address, class: 'project qrcode'
%p #{100-(CONFIG["our_fee"]*100).round}% of deposited funds will be used to tip for new commits.
.col-md-8
- unless @project.description.blank?
%h3= @project.description
- unless @project.detailed_description.blank?
= render_markdown @project.detailed_description
%h4 Balance
= btc_human @project.available_amount
- if @project.auto_tip_commits?
(each new commit receives #{(CONFIG["tip"]*100).round}% of available balance)
- if (unconfirmed_amount = @project.unconfirmed_amount) > 0
(#{btc_human unconfirmed_amount} unconfirmed)

- if @project.tipping_policies_text.try(:text).present?
%h4 Tipping policies
Expand Down Expand Up @@ -138,3 +107,53 @@
%p= link_to image_tag(project_url(@project, format: :svg), alt: 'Peer4Commit'), project_url(@project)
%p
%input.form-control{type: 'text', value: "[![tip for next commit](#{project_url(@project, format: :svg)})](#{project_url(@project)})"}

.col-md-4
- if @project.disabled?
.panel.panel-danger
.panel-heading
%h4.panel-title
Project Disabled
.panel-body.text-center
%p
This project has been disabled.
It doesn't accept donation and it will not distribute tips.
- if (reason = @project.disabled_reason).present?
%p Reason: #{reason}

- else
.panel.panel-default.project-panel
.panel-heading
%h4.panel-title
Project informations
.panel-body.text-center
%table.table.text-left
%tr
%td Funds
%td= btc_human @project.available_amount
%tr
%td Distributions
%td
%ul.list-unstyled#distribution-list
- @project.distributions.order(created_at: :desc).limit(5).each do |distribution|
%li.distribution-link
- label = btc_human(distribution.total_amount)
- if distribution.sent?
- label << " sent #{time_ago_in_words(distribution.sent_at)} ago"
- else
- label << " not sent"
= link_to label, [@project, distribution]
= link_to "All distributions", project_distributions_path(@project)


.panel.panel-default.project-panel
.panel-heading
%h4.panel-title
Donate
.panel-body.text-center
%p To give to this project, send peercoins to this address:
%p.bitcoin-address
= @project.bitcoin_address
%p
= image_tag qrcode_project_path(@project, format: :svg), alt: @project.bitcoin_address, class: 'project qrcode'
%p #{100-(CONFIG["our_fee"]*100).round}% of deposited funds will be used to tip for new commits.
2 changes: 1 addition & 1 deletion config/routes.rb
Expand Up @@ -17,7 +17,7 @@
end
resources :projects, :only => [:new, :show, :index, :create, :edit, :update] do
resources :tips, :only => [:index]
resources :distributions, :only => [:new, :create, :show] do
resources :distributions, :only => [:new, :create, :show, :index] do
get :recipient_suggestions, on: :collection
post :send_transaction, on: :member
end
Expand Down
5 changes: 5 additions & 0 deletions db/migrate/20140531080839_add_sent_at_to_distribution.rb
@@ -0,0 +1,5 @@
class AddSentAtToDistribution < ActiveRecord::Migration
def change
add_column :distributions, :sent_at, :datetime
end
end
3 changes: 2 additions & 1 deletion db/schema.rb
Expand Up @@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 20140530132209) do
ActiveRecord::Schema.define(version: 20140531080839) do

create_table "cold_storage_transfers", force: true do |t|
t.integer "project_id"
Expand Down Expand Up @@ -58,6 +58,7 @@
t.datetime "updated_at"
t.integer "project_id"
t.integer "fee"
t.datetime "sent_at"
end

add_index "distributions", ["project_id"], name: "index_distributions_on_project_id"
Expand Down
59 changes: 53 additions & 6 deletions features/distribution.feature
@@ -1,6 +1,6 @@
Feature: Fundraisers can distribute funds
@javascript
Scenario:
Scenario: Send distribution to a single user who has set his address
Given a GitHub user "bob" who has set his address to "mxWfjaZJTNN5QKeZZYQ5HW3vgALFBsnuG1"

Given a project managed by "alice"
Expand All @@ -23,12 +23,14 @@ Feature: Fundraisers can distribute funds
When the tipper is started
Then no coins should have been sent

Given the current time is "2014-03-01 12:35:02 UTC"
When I click on "Send the transaction"
Then these amounts should have been sent from the account of the project:
Then I should see "Transaction sent"
And I should see "Transaction sent on Sat, 01 Mar 2014 12:35:02 +0000"
And these amounts should have been sent from the account of the project:
| address | amount |
| mxWfjaZJTNN5QKeZZYQ5HW3vgALFBsnuG1 | 10.0 |
And the project balance should be "490"
And I should see "Sent"

@javascript
Scenario: Send distribution to multiple users
Expand Down Expand Up @@ -60,11 +62,56 @@ Feature: Fundraisers can distribute funds
Then no coins should have been sent

When I click on "Send the transaction"
Then these amounts should have been sent from the account of the project:
Then I should see "Transaction sent"
And these amounts should have been sent from the account of the project:
| address | amount |
| mxWfjaZJTNN5QKeZZYQ5HW3vgALFBsnuG1 | 10.0 |
| mi9SLroAgc8eUNuLwnZmdyqWdShbNtvr3n | 13.56 |
And the project balance should be "476.44"
And I should see "Sent"

Scenario: Send to an user without address
@javascript
Scenario: Send to an user without an address
Given a GitHub user "bob"

Given a project managed by "alice"
And our fee is "0"
And a deposit of "500"

Given I'm logged in as "alice"
And I go to the project page
And I click on "New distribution"
And I type "bob" in the recipient field
And I select the recipient "bob (GitHub user)"
And I fill the amount to "bob (GitHub user)" with "10"
And I click on "Save"

Then I should see these distribution lines:
| recipient | address | amount | percentage |
| bob (GitHub user) | | 10 | 100.0 |
And I should see "Total amount: 10.00 PPC"
And I should not see "Send the transaction"
And I should see "The transaction cannot be sent because some addresses are missing"

And no email should have been sent

When the tipper is started
Then no coins should have been sent

When I log out
And I log in as "bob"
And I set my address to "mnVba8qrpy5uxYD7dV4NZMQPWjgdt2QC1i"

When I log out
And I log in as "alice"
And I go to the project page
And I click on the last distribution
Then I should see these distribution lines:
| recipient | address | amount | percentage |
| bob (GitHub user) | mnVba8qrpy5uxYD7dV4NZMQPWjgdt2QC1i | 10 | 100.0 |

When I click on "Send the transaction"
Then I should see "Transaction sent"
And these amounts should have been sent from the account of the project:
| address | amount |
| mnVba8qrpy5uxYD7dV4NZMQPWjgdt2QC1i | 10.0 |
And the project balance should be "490.00"
13 changes: 13 additions & 0 deletions features/step_definitions/common.rb
Expand Up @@ -6,6 +6,10 @@
ActionMailer::Base.deliveries.size.should eq(arg1.to_i)
end

Then(/^no email should have been sent$/) do
ActionMailer::Base.deliveries.should eq([])
end

When(/^the email counters are reset$/) do
ActionMailer::Base.deliveries.clear
end
Expand Down Expand Up @@ -136,3 +140,12 @@ def find_new_commit(id)
Given(/^an illustration of the history is:$/) do |string|
# not checked
end

Given(/^the current time is "(.*?)"$/) do |arg1|
Timecop.travel(Time.parse(arg1))
end

After do
Timecop.return
end

0 comments on commit ac23eb7

Please sign in to comment.