").addClass("alert alert-danger").text(data.error))
16 | else
17 | recipients.append(data.result)
18 | form[0].reset()
19 | false
20 | error: ->
21 | form.append($("
").addClass("alert alert-danger").text("An error occured."))
22 | false
23 |
24 | $(".commit-autocomplete[data-project-id]").each ->
25 | input = $(this)
26 | projectId = input.data("project-id")
27 | source = new Bloodhound
28 | datumTokenizer: Bloodhound.tokenizers.obj.whitespace("sha")
29 | queryTokenizer: Bloodhound.tokenizers.whitespace
30 | remote: "/projects/#{projectId}/commit_suggestions.json?query=%QUERY"
31 |
32 | source.initialize()
33 |
34 | input.typeahead {minLength: 2, highlight: true},
35 | displayKey: "sha"
36 | source: source.ttAdapter()
37 | templates:
38 | suggestion: (object) ->
39 | object.description
40 |
41 | if input.data("submit")
42 | input.bind "typeahead:selected", ->
43 | setTimeout ->
44 | input.closest("form").submit()
45 | input.typeahead('val', '')
46 | , 100
47 |
48 | $(".github-user-autocomplete[data-project-id]").each ->
49 | input = $(this)
50 | projectId = input.data("project-id")
51 | source = new Bloodhound
52 | datumTokenizer: Bloodhound.tokenizers.obj.whitespace("login")
53 | queryTokenizer: Bloodhound.tokenizers.whitespace
54 | remote: "/projects/#{projectId}/github_user_suggestions.json?query=%QUERY"
55 |
56 | source.initialize()
57 |
58 | input.typeahead {minLength: 1, highlight: true},
59 | displayKey: "login"
60 | source: source.ttAdapter()
61 | templates:
62 | suggestion: (object) ->
63 | object.description
64 |
65 | if input.data("submit")
66 | input.bind "typeahead:selected", ->
67 | setTimeout ->
68 | input.closest("form").submit()
69 | input.typeahead('val', '')
70 | , 100
71 |
72 | $(".user-autocomplete").each ->
73 | input = $(this)
74 | source = new Bloodhound
75 | datumTokenizer: Bloodhound.tokenizers.obj.whitespace("identifier")
76 | queryTokenizer: Bloodhound.tokenizers.whitespace
77 | remote: "/users/suggestions.json?query=%QUERY"
78 |
79 | source.initialize()
80 |
81 | input.typeahead {minLength: 1, highlight: true},
82 | displayKey: "identifier"
83 | source: source.ttAdapter()
84 | templates:
85 | suggestion: (object) ->
86 | object.description
87 |
88 | if input.data("submit")
89 | input.bind "typeahead:selected", ->
90 | setTimeout ->
91 | input.closest("form").submit()
92 | input.typeahead('val', '')
93 | , 100
94 |
--------------------------------------------------------------------------------
/app/assets/javascripts/home.js.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://coffeescript.org/
4 |
--------------------------------------------------------------------------------
/app/assets/javascripts/projects.js.coffee:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sigmike/peer4commit/c63313c7281d28186849adb23fae93873c52da33/app/assets/javascripts/projects.js.coffee
--------------------------------------------------------------------------------
/app/assets/javascripts/qrcode/jquery.qr.js:
--------------------------------------------------------------------------------
1 | (function( $ ){
2 | $.fn.qrcode = function(options) {
3 | // if options is string,
4 | if( typeof options === 'string' ){
5 | options = { text: options };
6 | }
7 |
8 | // set default values
9 | // typeNumber < 1 for automatic calculation
10 | options = $.extend( {}, {
11 | render : "canvas",
12 | width : 256,
13 | height : 256,
14 | typeNumber : -1,
15 | correctLevel : QRErrorCorrectLevel.H,
16 | background : "#ffffff",
17 | foreground : "#000000"
18 | }, options);
19 |
20 | var createCanvas = function(){
21 | // create the qrcode itself
22 | var qrcode = new QRCode(options.typeNumber, options.correctLevel);
23 | qrcode.addData(options.text);
24 | qrcode.make();
25 |
26 | // create canvas element
27 | var canvas = document.createElement('canvas');
28 | canvas.width = options.width;
29 | canvas.height = options.height;
30 | var ctx = canvas.getContext('2d');
31 |
32 | // compute tileW/tileH based on options.width/options.height
33 | var tileW = options.width / qrcode.getModuleCount();
34 | var tileH = options.height / qrcode.getModuleCount();
35 |
36 | // draw in the canvas
37 | for( var row = 0; row < qrcode.getModuleCount(); row++ ){
38 | for( var col = 0; col < qrcode.getModuleCount(); col++ ){
39 | ctx.fillStyle = qrcode.isDark(row, col) ? options.foreground : options.background;
40 | var w = (Math.ceil((col+1)*tileW) - Math.floor(col*tileW));
41 | var h = (Math.ceil((row+1)*tileW) - Math.floor(row*tileW));
42 | ctx.fillRect(Math.round(col*tileW),Math.round(row*tileH), w, h);
43 | }
44 | }
45 | // return just built canvas
46 | return canvas;
47 | }
48 |
49 | // from Jon-Carlos Rivera (https://github.com/imbcmdth)
50 | var createTable = function(){
51 | // create the qrcode itself
52 | var qrcode = new QRCode(options.typeNumber, options.correctLevel);
53 | qrcode.addData(options.text);
54 | qrcode.make();
55 |
56 | // create table element
57 | var $table = $('
')
58 | .css("width", options.width+"px")
59 | .css("height", options.height+"px")
60 | .css("border", "0px")
61 | .css("border-collapse", "collapse")
62 | .css('background-color', options.background);
63 |
64 | // compute tileS percentage
65 | var tileW = options.width / qrcode.getModuleCount();
66 | var tileH = options.height / qrcode.getModuleCount();
67 |
68 | // draw in the table
69 | for(var row = 0; row < qrcode.getModuleCount(); row++ ){
70 | var $row = $('
|
').css('height', tileH+"px").appendTo($table);
71 |
72 | for(var col = 0; col < qrcode.getModuleCount(); col++ ){
73 | $('
| ')
74 | .css('width', tileW+"px")
75 | .css('background-color', qrcode.isDark(row, col) ? options.foreground : options.background)
76 | .appendTo($row);
77 | }
78 | }
79 | // return just built canvas
80 | return $table;
81 | }
82 |
83 |
84 | return this.each(function(){
85 | var element = options.render == "canvas" ? createCanvas() : createTable();
86 | $(element).appendTo(this);
87 | });
88 | };
89 | })( jQuery );
--------------------------------------------------------------------------------
/app/assets/javascripts/sessions.js.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://coffeescript.org/
4 |
--------------------------------------------------------------------------------
/app/assets/javascripts/users.js.coffee:
--------------------------------------------------------------------------------
1 | # Place all the behaviors and hooks related to the matching controller here.
2 | # All this logic will automatically be available in application.js.
3 | # You can use CoffeeScript in this file: http://coffeescript.org/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/application.css:
--------------------------------------------------------------------------------
1 | /*
2 | * This is a manifest file that'll be compiled into application.css, which will include all the files
3 | * listed below.
4 | *
5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6 | * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7 | *
8 | * You're free to add application-wide styles to this file and they'll appear at the top of the
9 | * compiled file, but it's generally better to create a new file per style scope.
10 | *
11 | *= require rails_bootstrap_forms
12 | *= require_self
13 | *= require_tree .
14 | */
15 |
16 |
17 | @font-face {font-family: 'Code-Pro-Light-Demo';src: url('/webfonts/28BE49_0_0.eot');src: url('/webfonts/28BE49_0_0.eot?#iefix') format('embedded-opentype'),url('/webfonts/28BE49_0_0.woff') format('woff'),url('/webfonts/28BE49_0_0.ttf') format('truetype');}
18 | .code-pro { font-family: Code-Pro-Light-Demo; }
19 |
20 | .addthis_counter
21 | {
22 | -webkit-box-sizing: content-box;
23 | -moz-box-sizing: content-box;
24 | box-sizing: content-box;
25 | }
26 | .form-devise {
27 | max-width: 430px;
28 | padding: 15px;
29 | margin: 0 auto;
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/bootstrap_and_overrides.css.less:
--------------------------------------------------------------------------------
1 | @import "twitter/bootstrap/bootstrap";
2 |
3 | // Set the correct sprite paths
4 | @iconSpritePath: image-url("twitter/bootstrap/glyphicons-halflings.png");
5 | @iconWhiteSpritePath: image-url("twitter/bootstrap/glyphicons-halflings-white.png");
6 |
7 | // Set the Font Awesome (Font Awesome is default. You can disable by commenting below lines)
8 | @fontAwesomeEotPath: asset-url("fontawesome-webfont.eot");
9 | @fontAwesomeEotPath_iefix: asset-url("fontawesome-webfont.eot?#iefix");
10 | @fontAwesomeWoffPath: asset-url("fontawesome-webfont.woff");
11 | @fontAwesomeTtfPath: asset-url("fontawesome-webfont.ttf");
12 | @fontAwesomeSvgPath: asset-url("fontawesome-webfont.svg#fontawesomeregular");
13 |
14 | // Font Awesome
15 | @import "fontawesome/font-awesome";
16 |
17 | // Glyphicons
18 | //@import "twitter/bootstrap/sprites.less";
19 |
20 | // Your custom LESS stylesheets goes here
21 | //
22 | // Since bootstrap was imported above you have access to its mixins which
23 | // you may use and inherit here
24 | //
25 | // If you'd like to override bootstrap's own variables, you can do so here as well
26 | // See http://twitter.github.com/bootstrap/customize.html#variables for their names and documentation
27 | //
28 | // Example:
29 | // @linkColor: #ff0000;
30 |
31 | .thread_new_comment {
32 | input {
33 | &:extend(.btn, .btn-default);
34 | }
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/distribution.css.sass:
--------------------------------------------------------------------------------
1 | @import compass/css3
2 |
3 | #distribution-form
4 | td.amount
5 | width: 170px
6 | input
7 | text-align: right
8 | .distribution-action
9 | +inline-block
10 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/flash_message.css.sass:
--------------------------------------------------------------------------------
1 | .flash-message
2 | margin-top: 20px
3 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/justified-nav.css:
--------------------------------------------------------------------------------
1 | .footer {
2 | border-top: 1px solid #eee;
3 | margin-top: 40px;
4 | padding-top: 40px;
5 | padding-bottom: 40px;
6 | }
7 |
8 | /* Responsive: Portrait tablets and up */
9 | @media screen and (min-width: 768px) {
10 | /* Remove the padding we set earlier */
11 | .masthead,
12 | .marketing,
13 | .footer {
14 | padding-left: 0;
15 | padding-right: 0;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/oldsansblack-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sigmike/peer4commit/c63313c7281d28186849adb23fae93873c52da33/app/assets/stylesheets/oldsansblack-webfont.eot
--------------------------------------------------------------------------------
/app/assets/stylesheets/oldsansblack-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sigmike/peer4commit/c63313c7281d28186849adb23fae93873c52da33/app/assets/stylesheets/oldsansblack-webfont.ttf
--------------------------------------------------------------------------------
/app/assets/stylesheets/oldsansblack-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sigmike/peer4commit/c63313c7281d28186849adb23fae93873c52da33/app/assets/stylesheets/oldsansblack-webfont.woff
--------------------------------------------------------------------------------
/app/assets/stylesheets/oldsansblack.sass:
--------------------------------------------------------------------------------
1 | /* Generated by Font Squirrel (http://www.fontsquirrel.com) on June 13, 2014
2 |
3 | @font-face
4 | font-family: 'oldsansblack'
5 | src: asset-url('oldsansblack-webfont.eot')
6 | src: asset-url('oldsansblack-webfont.eot?#iefix') format("embedded-opentype"), asset-url('oldsansblack-webfont.woff') format("woff"), asset-url('oldsansblack-webfont.ttf') format("truetype"), asset-url('oldsansblack-webfont.svg#oldsansblackregular') format("svg")
7 | font-weight: normal
8 | font-style: normal
9 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/projects.css.sass:
--------------------------------------------------------------------------------
1 | .commit-sha
2 | font-family: monospace
3 |
4 | .qrcode
5 | text-align: center
6 |
7 | .project-panel
8 | overflow: auto
9 |
10 | .bitcoin-address
11 | word-wrap: break-word
12 |
13 | .donor-list
14 | .amount
15 | text-align: right
16 |
17 | .txid abbr
18 | font-variant: none
19 | text-decoration: none
20 | border-bottom: none
21 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/same-height-columns.sass:
--------------------------------------------------------------------------------
1 | .container-xs-height
2 | display: table
3 | padding-left: 0px
4 | padding-right: 0px
5 |
6 | .row-xs-height
7 | display: table-row
8 |
9 | .col-xs-height
10 | display: table-cell
11 | float: none
12 |
13 | @media (min-width: 768px)
14 | .container-sm-height
15 | display: table
16 | padding-left: 0px
17 | padding-right: 0px
18 | .row-sm-height
19 | display: table-row
20 | .col-sm-height
21 | display: table-cell
22 | float: none
23 |
24 | @media (min-width: 992px)
25 | .container-md-height
26 | display: table
27 | padding-left: 0px
28 | padding-right: 0px
29 | .row-md-height
30 | display: table-row
31 | .col-md-height
32 | display: table-cell
33 | float: none
34 |
35 | @media (min-width: 1200px)
36 | .container-lg-height
37 | display: table
38 | padding-left: 0px
39 | padding-right: 0px
40 | .row-lg-height
41 | display: table-row
42 | .col-lg-height
43 | display: table-cell
44 | float: none
45 |
46 | .col-top
47 | vertical-align: top
48 |
49 | .col-middle
50 | vertical-align: middle
51 |
52 | .col-bottom
53 | vertical-align: bottom
54 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/sessions.css.sass:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the sessions controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/typeahead.css.sass:
--------------------------------------------------------------------------------
1 | .twitter-typeahead
2 | .tt-query, .tt-hint
3 | margin-bottom: 0
4 |
5 | .tt-dropdown-menu
6 | min-width: 160px
7 | margin-top: 2px
8 | padding: 5px 0
9 | background-color: #fff
10 | border: 1px solid #ccc
11 | border: 1px solid rgba(0, 0, 0, 0.2)
12 | *border-right-width: 2px
13 | *border-bottom-width: 2px
14 | -webkit-border-radius: 6px
15 | -moz-border-radius: 6px
16 | border-radius: 6px
17 | -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2)
18 | -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2)
19 | box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2)
20 | -webkit-background-clip: padding-box
21 | -moz-background-clip: padding
22 | background-clip: padding-box
23 |
24 | .tt-suggestion
25 | display: block
26 | padding: 3px 20px
27 | cursor: pointer
28 | &.tt-is-under-cursor, &:hover
29 | color: #fff
30 | background-color: #0081c2
31 | background-image: -moz-linear-gradient(top, #0088cc, #0077b3)
32 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3))
33 | background-image: -webkit-linear-gradient(top, #0088cc, #0077b3)
34 | background-image: -o-linear-gradient(top, #0088cc, #0077b3)
35 | background-image: linear-gradient(to bottom, #0088cc, #0077b3)
36 | background-repeat: repeat-x
37 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0)
38 | a
39 | color: #fff
40 | p
41 | margin: 0
42 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/users.css.sass:
--------------------------------------------------------------------------------
1 | // Place all the styles related to the Users controller here.
2 | // They will automatically be included in application.css.
3 | // You can use Sass (SCSS) here: http://sass-lang.com/
4 |
5 | #error_explanation
6 | h2
7 | font-size: 16px
8 |
--------------------------------------------------------------------------------
/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | class ApplicationController < ActionController::Base
2 | # Prevent CSRF attacks by raising an exception.
3 | # For APIs, you may want to use :null_session instead.
4 | protect_from_forgery with: :exception
5 |
6 | rescue_from CanCan::AccessDenied do |exception|
7 | if request.xhr?
8 | raise exception
9 | else
10 | redirect_to root_path, :alert => "Access denied"
11 | end
12 | end
13 |
14 | before_filter :configure_permitted_parameters, if: :devise_controller?
15 |
16 | before_filter :closed
17 |
18 | protected
19 | def after_sign_in_path_for(user)
20 | params[:return_url].presence ||
21 | session["user_return_to"].presence ||
22 | root_path
23 | end
24 |
25 | def configure_permitted_parameters
26 | devise_parameter_sanitizer.permit(:account_update, keys: [:email, :name, :bitcoin_address, :current_password, :password, :password_confirmation])
27 | end
28 |
29 | def closed
30 | return if controller_name == "home" and action_name == "audit"
31 |
32 | render "layouts/closed", status: 404
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/app/controllers/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sigmike/peer4commit/c63313c7281d28186849adb23fae93873c52da33/app/controllers/concerns/.keep
--------------------------------------------------------------------------------
/app/controllers/distributions_controller.rb:
--------------------------------------------------------------------------------
1 | class DistributionsController < ApplicationController
2 | load_and_authorize_resource :project
3 | load_and_authorize_resource :distribution, :through => :project
4 |
5 | def index
6 | @distributions = @distributions.order(created_at: :desc).page(params[:page]).per(30)
7 | end
8 |
9 | def new
10 | end
11 |
12 | def create
13 | @distribution.project = @project
14 | finalize_distribution
15 | if @distribution.save
16 | redirect_to [@project, @distribution], notice: "Distribution created"
17 | else
18 | render "new"
19 | end
20 | end
21 |
22 | def edit
23 | end
24 |
25 | def update
26 | @distribution.attributes = distribution_params
27 | finalize_distribution
28 | if @distribution.save
29 | redirect_to [@project, @distribution], notice: "Distribution updated"
30 | else
31 | render "edit"
32 | end
33 | end
34 |
35 | def show
36 | commontator_thread_show(@distribution)
37 | end
38 |
39 | def send_transaction
40 | @distribution.send_transaction!
41 | redirect_to [@project, @distribution], flash: {notice: "Transaction sent"}
42 | rescue RuntimeError => e
43 | redirect_to [@project, @distribution], flash: {error: e.message}
44 | end
45 |
46 | def new_recipient_form
47 | @tips = []
48 | if params[:user] and params[:user][:nickname].present?
49 | user = User.enabled.where(nickname: params[:user][:nickname]).first_or_initialize
50 | if user.new_record?
51 | raise "Invalid GitHub user" unless user.valid_github_user?
52 | user.confirm
53 | user.save!
54 | end
55 | @tips << Tip.new(user: user)
56 | elsif params[:user] and params[:user][:identifier].present?
57 | user = User.enabled.find_by(identifier: params[:user][:identifier])
58 | @tips << Tip.new(user: user)
59 | elsif params[:not_rewarded_commits]
60 | @project.commits.each do |commit|
61 | next if Tip.where(reason: commit).any?
62 | next if Tip.where(commit: commit.sha).where.not(amount: nil).any?
63 | tip = Tip.build_from_commit(commit)
64 | @tips << tip if tip
65 | end
66 | elsif params[:commit] and sha = params[:commit][:sha]
67 | commits = @project.commits.where("sha LIKE ?", "#{sha}%")
68 | count = commits.count
69 | raise "Commit not found" if count == 0
70 | raise "Multiple commits match this prefix" if count > 1
71 | commit = commits.first
72 | @tips << Tip.build_from_commit(commit)
73 | else
74 | raise "Unrecognized recipient"
75 | end
76 | result = render_to_string(layout: false)
77 | render json: {result: result}
78 | rescue RuntimeError => e
79 | render json: {error: e.message}
80 | end
81 |
82 | private
83 |
84 | def distribution_params
85 | if params[:distribution]
86 | params.require(:distribution).permit(tips_attributes: [:id, :coin_amount, :user_id, :comment, :reason_type, :reason_id, :_destroy])
87 | else
88 | {}
89 | end
90 | end
91 |
92 | def finalize_distribution
93 | @distribution.tips.each do |tip|
94 | tip.project = @project
95 | if tip.user.new_record?
96 | tip.user.skip_confirmation_notification!
97 | end
98 | end
99 | end
100 | end
101 |
--------------------------------------------------------------------------------
/app/controllers/home_controller.rb:
--------------------------------------------------------------------------------
1 | class HomeController < ApplicationController
2 | def index
3 | end
4 | end
5 |
--------------------------------------------------------------------------------
/app/controllers/registrations_controller.rb:
--------------------------------------------------------------------------------
1 | class RegistrationsController < Devise::RegistrationsController
2 | def update
3 | @user = User.enabled.find(current_user.id)
4 |
5 | user_params = devise_parameter_sanitizer.sanitize(:account_update)
6 |
7 | successfully_updated = if @user.has_password?
8 | @user.update_with_password(user_params)
9 | else
10 | @user.update(user_params)
11 | end
12 |
13 | if successfully_updated
14 | set_flash_message :notice, :updated
15 | # Sign in the user bypassing validation in case their password changed
16 | bypass_sign_in @user
17 | redirect_to after_update_path_for(@user)
18 | else
19 | render "edit"
20 | end
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/app/controllers/tips_controller.rb:
--------------------------------------------------------------------------------
1 | class TipsController < ApplicationController
2 | def index
3 | if params[:project_id] && @project = Project.find(params[:project_id])
4 | @tips = @project.tips.includes(:user).order(created_at: :desc).page(params[:page]).per(30)
5 | else
6 | @tips = Tip.includes(:user, :project).order(created_at: :desc).page(params[:page]).per(30)
7 | end
8 | end
9 | end
--------------------------------------------------------------------------------
/app/controllers/users/omniauth_callbacks_controller.rb:
--------------------------------------------------------------------------------
1 | class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
2 | def github
3 | # render text: "#{request.env["omniauth.auth"].to_json}"
4 | info = request.env["omniauth.auth"]["info"]
5 | @user = User.enabled.find_by :nickname => info["nickname"]
6 | if @user.nil? and info["verified_emails"].any?
7 | @user = User.enabled.find_by :email => info["verified_emails"]
8 | end
9 | unless @user
10 | if info['primary_email']
11 | @user = User.new(
12 | :email => info['primary_email'],
13 | :nickname => info['nickname']
14 | )
15 | @user.confirm
16 | @user.save!
17 | else
18 | set_flash_message(:error, :failure, kind: 'GitHub', reason: 'your primary email address should be verified.')
19 | redirect_to new_user_session_path and return
20 | end
21 | end
22 |
23 | @user.name ||= info['name']
24 | @user.image ||= info['image']
25 | @user.save
26 |
27 | Collaborator.where(login: @user.nickname, user_id: nil).each do |collaborator|
28 | collaborator.update(user: @user)
29 | end
30 |
31 | sign_in(@user)
32 | redirect_to request.env["omniauth.origin"].presence || after_sign_in_path_for(@user)
33 | set_flash_message(:notice, :success, :kind => "GitHub") if is_navigational_format?
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/app/controllers/users_controller.rb:
--------------------------------------------------------------------------------
1 | class UsersController < ApplicationController
2 |
3 | before_action except: [:show, :login, :index, :set_password_and_address, :suggestions] do
4 | @user = User.enabled.where(id: params[:id]).first
5 | if current_user
6 | if current_user != @user
7 | redirect_to root_path, alert: "Access denied"
8 | end
9 | else
10 | redirect_to new_user_session_path(return_url: request.url)
11 | end
12 | end
13 |
14 | def show
15 | @user = User.find(params[:id])
16 | commontator_thread_show(@user)
17 | end
18 |
19 | def index
20 | @users = User.order(withdrawn_amount: :desc, commits_count: :desc).where('commits_count > 0').page(params[:page]).per(30)
21 | end
22 |
23 | def update
24 | if @user.update(users_params)
25 | redirect_to @user, notice: 'Your information was saved.'
26 | else
27 | render :show, alert: 'Error updating peercoin address'
28 | end
29 | end
30 |
31 | def login
32 | @user = User.where(login_token: params[:token]).first
33 | if @user
34 | if params[:unsubscribe]
35 | @user.update unsubscribed: true
36 | flash[:alert] = 'You unsubscribed! Sorry for bothering you. Although, you still can leave us your peercoin address to get your tips.'
37 | end
38 | sign_in_and_redirect @user, event: :authentication
39 | else
40 | redirect_to root_url, alert: 'User not found'
41 | end
42 | end
43 |
44 | def send_tips_back
45 | @user.tips.not_sent.non_refunded.each do |tip|
46 | tip.touch :refunded_at
47 | end
48 | redirect_to @user, notice: 'All your tips have been refunded to their project'
49 | end
50 |
51 | def set_password_and_address
52 | @user = User.enabled.find(params[:id])
53 | raise "Blank token" if params[:token].blank?
54 |
55 | if @user.confirmed?
56 | redirect_to new_session_path(User), notice: "Your account is already confirmed. Please sign in to set your Peercoin address."
57 | return
58 | end
59 |
60 | raise "Invalid token" unless Devise.secure_compare(params[:token], @user.confirmation_token)
61 | if params[:user]
62 | @user.attributes = params.require(:user).permit(:password, :password_confirmation, :bitcoin_address)
63 | if @user.password.present? and @user.bitcoin_address.present? and @user.save
64 | @user.confirm!
65 | redirect_to root_path, notice: "Information saved"
66 | else
67 | flash.now[:alert] = "Please fill all the information"
68 | end
69 | end
70 | end
71 |
72 | def suggestions
73 | respond_to do |format|
74 | format.json do
75 | query = params[:query]
76 | users = User.enabled.where('identifier LIKE ? OR name LIKE ?', "%#{query}%", "%#{query}%")
77 | users = users.map do |user|
78 | {
79 | identifier: user.identifier,
80 | description: [
81 | user.name,
82 | "(#{user.identifier})",
83 | ].reject(&:blank?).join(" "),
84 | }
85 | end
86 | render json: users
87 | end
88 | end
89 | end
90 |
91 | private
92 | def users_params
93 | params.require(:user).permit(:bitcoin_address)
94 | end
95 | end
96 |
--------------------------------------------------------------------------------
/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | module ApplicationHelper
2 | def btc_human amount, options = {}
3 | return nil unless amount
4 | options = (@default_btc_human_options || {}).merge(options)
5 | nobr = options.has_key?(:nobr) ? options[:nobr] : true
6 | currency = options[:currency] || false
7 | precision = options[:precision] || 2
8 | display_currency = options.fetch(:display_currency, true)
9 | btc = "%.#{precision}f" % to_btc(amount)
10 | btc += " PPC" if display_currency
11 | btc = "
#{btc}" if currency
12 | btc = "
#{btc}" if nobr
13 | btc.html_safe
14 | end
15 |
16 | def with_btc_human_defaults(defaults)
17 | @old_btc_human_defaults ||= []
18 | @old_btc_human_defaults << @default_btc_human_options
19 | @default_btc_human_options = defaults.dup
20 | yield
21 | @default_btc_human_options = @old_btc_human_defaults.pop
22 | end
23 |
24 | def to_btc satoshies
25 | satoshies.to_d / COIN if satoshies
26 | end
27 |
28 | def transaction_url(txid)
29 | "https://peercoin.mintr.org/tx/#{txid}"
30 | end
31 |
32 | def address_explorers
33 | [:mintr, :blockr]
34 | end
35 |
36 | def address_url(address, explorer = address_explorers.first)
37 | case explorer
38 | when :blockr then "http://ppc.blockr.io/address/info/#{address}"
39 | when :mintr then "https://peercoin.mintr.org/address/#{address}"
40 | else raise "Unknown provider: #{provider.inspect}"
41 | end
42 | end
43 |
44 | def truncate_commit(sha1)
45 | truncate(sha1, length: 10, omission: "")
46 | end
47 |
48 | def commit_tag(sha1)
49 | content_tag(:span, truncate_commit(sha1), class: "commit-sha")
50 | end
51 |
52 | def render_flash_message
53 | html = []
54 | flash.each do |type, message|
55 | alert_type = case type
56 | when :notice then :success
57 | when :alert, :error then :danger
58 | else type
59 | end
60 | html << content_tag(:div, message, class: "flash-message text-center alert alert-#{alert_type}")
61 | end
62 | html.join("\n").html_safe
63 | end
64 |
65 | def render_markdown(source)
66 | return nil unless source
67 |
68 | markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML.new(safe_links_only: true, filter_html: true), autolink: true)
69 | html = markdown.render(source)
70 | clean = Sanitize.clean(html, Sanitize::Config::RELAXED)
71 | clean.html_safe
72 | end
73 | end
74 |
--------------------------------------------------------------------------------
/app/helpers/home_helper.rb:
--------------------------------------------------------------------------------
1 | module HomeHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/projects_helper.rb:
--------------------------------------------------------------------------------
1 | module ProjectsHelper
2 |
3 | def shield_btc_amount amount
4 | btc_amount = to_btc amount
5 | "%.#{6 - btc_amount.to_i.to_s.length}f PPC" % btc_amount
6 | end
7 |
8 | def shield_color project
9 | last_tip = project.tips.order(:created_at).last
10 | if last_tip.nil? || (Time.now - last_tip.created_at > 30.days)
11 | 'red'
12 | elsif (Time.now - last_tip.created_at > 7.days)
13 | 'yellow'
14 | elsif (Time.now - last_tip.created_at > 1.day)
15 | 'yellowgreen'
16 | else
17 | 'green'
18 | end
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/app/helpers/sessions_helper.rb:
--------------------------------------------------------------------------------
1 | module SessionsHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/helpers/users_helper.rb:
--------------------------------------------------------------------------------
1 | module UsersHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/mailers/user_mailer.rb:
--------------------------------------------------------------------------------
1 | class UserMailer < ActionMailer::Base
2 | add_template_helper(ApplicationHelper)
3 |
4 | def new_tip user, tip
5 | @user = user
6 | @tip = tip
7 |
8 | mail to: user.email, subject: "You received a tip for your commit"
9 | end
10 |
11 | def security_issue(user)
12 | @user = user
13 | mail to: user.email, subject: "Security issue on peer4commit.com"
14 | end
15 |
16 | def address_request(tip, collaborator)
17 | @collaborator = collaborator
18 | @tip = tip
19 | @user = tip.user
20 | mail to: @user.email, subject: "[#{tip.project.name}] Provide an address to get your reward"
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/app/models/ability.rb:
--------------------------------------------------------------------------------
1 | class Ability
2 | include CanCan::Ability
3 |
4 | def initialize(user)
5 | can [:read, :donate, :donors], Project
6 | can :read, Distribution
7 |
8 | if user
9 | can [:update, :decide_tip_amounts, :commit_suggestions, :github_user_suggestions], Project, {collaborators: {user_id: user.id}}
10 | can [:create], Project, {collaborators: {user_id: user.id}}
11 | can [:create], Distribution, project: {collaborators: {user_id: user.id}}
12 | can [:update, :new_recipient_form], Distribution, project: {collaborators: {user_id: user.id}}, txid: nil, sent_at: nil
13 | can [:send_transaction], Distribution do |distribution|
14 | distribution.can_be_sent?
15 | end
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/app/models/cold_storage_transfer.rb:
--------------------------------------------------------------------------------
1 | class ColdStorageTransfer < ActiveRecord::Base
2 | belongs_to :project
3 |
4 | def confirmed?
5 | confirmations and confirmations >= 1
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/app/models/collaborator.rb:
--------------------------------------------------------------------------------
1 | class Collaborator < ActiveRecord::Base
2 | belongs_to :project
3 | belongs_to :user
4 | end
5 |
--------------------------------------------------------------------------------
/app/models/commit.rb:
--------------------------------------------------------------------------------
1 | class Commit < ActiveRecord::Base
2 | belongs_to :project
3 |
4 | validates :sha, uniqueness: {scope: :project_id}
5 | end
6 |
--------------------------------------------------------------------------------
/app/models/concerns/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sigmike/peer4commit/c63313c7281d28186849adb23fae93873c52da33/app/models/concerns/.keep
--------------------------------------------------------------------------------
/app/models/deposit.rb:
--------------------------------------------------------------------------------
1 | class Deposit < ActiveRecord::Base
2 | belongs_to :project
3 | belongs_to :donation_address, inverse_of: :deposits
4 |
5 | def fee
6 | (amount * CONFIG["our_fee"]).to_i
7 | end
8 |
9 | def available_amount
10 | [amount - fee, 0].max
11 | end
12 |
13 | end
14 |
--------------------------------------------------------------------------------
/app/models/distribution.rb:
--------------------------------------------------------------------------------
1 | class Distribution < ActiveRecord::Base
2 | belongs_to :project, inverse_of: :distributions
3 | has_many :tips
4 | accepts_nested_attributes_for :tips, allow_destroy: true
5 |
6 | record_changes(include: :tips)
7 |
8 | acts_as_commontable
9 |
10 | validate :validate_funds
11 |
12 | scope :to_send, -> { where(txid: nil) }
13 | scope :error, -> { where(is_error: true) }
14 |
15 | def sent?
16 | sent_at or txid
17 | end
18 |
19 | def total_amount
20 | tips.map(&:amount).compact.sum
21 | end
22 |
23 | def send_transaction!
24 | Distribution.transaction do
25 | lock!
26 | raise "Already sent" if sent?
27 | raise "Transaction already sent and failed" if is_error?
28 | raise "Project disabled" if project.disabled?
29 |
30 | update!(sent_at: Time.now, is_error: true) # it's a lock to prevent duplicates
31 | end
32 |
33 | data = generate_data
34 | update_attribute(:data, data)
35 |
36 | raise "Not enough funds on Distribution##{id}" if Project.find(project.id).available_amount < 0
37 |
38 | txid = BitcoinDaemon.instance.send_many(project.address_label, JSON.parse(data))
39 |
40 | update!(txid: txid, is_error: false)
41 | end
42 |
43 | def generate_data
44 | outs = Hash.new { 0.to_d }
45 | tips.each do |tip|
46 | outs[tip.user.bitcoin_address] += tip.amount.to_d / COIN if tip.amount > 0
47 | end
48 | outs.to_json
49 | end
50 |
51 | def all_addresses_known?
52 | tips.all? { |tip| tip.user.try(:bitcoin_address).present? }
53 | end
54 |
55 | def can_be_sent?
56 | !sent? and all_addresses_known? and tips.any? and tips.all?(&:decided?)
57 | end
58 |
59 | def to_label
60 | "##{id} on project #{project.to_label}"
61 | end
62 |
63 | def validate_funds
64 | tips = project.tips.to_a
65 | tips -= self.tips
66 | tips += self.tips
67 | if project.total_deposited < tips.reject(&:refunded?).map(&:amount).compact.sum
68 | errors.add(:base, "Not enough funds")
69 | end
70 | end
71 | end
72 |
--------------------------------------------------------------------------------
/app/models/donation_address.rb:
--------------------------------------------------------------------------------
1 | class DonationAddress < ActiveRecord::Base
2 | belongs_to :project, inverse_of: :donation_addresses
3 | has_many :deposits, inverse_of: :donation_address
4 |
5 | validates :sender_address, bitcoin_address: true, presence: true
6 | validates :donation_address, bitcoin_address: true
7 |
8 | before_create :generate_donation_address
9 |
10 | def generate_donation_address
11 | return if donation_address.present?
12 | raise "The project has no address label" if project.address_label.blank?
13 | self.donation_address = BitcoinDaemon.instance.get_new_address(project.address_label)
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/app/models/record_change.rb:
--------------------------------------------------------------------------------
1 | class RecordChange < ActiveRecord::Base
2 | belongs_to :record, polymorphic: true
3 | end
4 |
--------------------------------------------------------------------------------
/app/models/tipping_policies_text.rb:
--------------------------------------------------------------------------------
1 | class TippingPoliciesText < ActiveRecord::Base
2 | belongs_to :project
3 | belongs_to :user
4 | end
5 |
--------------------------------------------------------------------------------
/app/views/common/_menu.html.haml:
--------------------------------------------------------------------------------
1 | %nav#main-menu
2 | %ul.nav
3 | %li{class: controller_name == 'home' ? 'active' : ''}
4 | %a{href: root_path} Home
5 | %li{class: controller_name == 'projects' || @project ? 'active' : ''}
6 | %a{href: projects_path} Projects
7 | / %li
8 | / %a{href: "#"} About
9 | / %li
10 | / %a{href: "#"} Contact
11 |
--------------------------------------------------------------------------------
/app/views/devise/confirmations/new.html.haml:
--------------------------------------------------------------------------------
1 | = twitter_bootstrap_form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post, class: 'form-devise' }) do |f|
2 | %h2 Resend confirmation instructions
3 | = devise_error_messages!
4 | = f.email_field :email, :autofocus => true
5 | = f.submit "Resend confirmation instructions"
6 | %p
7 | = render "devise/shared/links"
8 |
--------------------------------------------------------------------------------
/app/views/devise/mailer/confirmation_instructions.html.haml:
--------------------------------------------------------------------------------
1 | %p
2 | Welcome #{@email}!
3 | %p You can confirm your account email through the link below:
4 | %p= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @token)
5 |
--------------------------------------------------------------------------------
/app/views/devise/mailer/reset_password_instructions.html.haml:
--------------------------------------------------------------------------------
1 | %p
2 | Hello #{@resource.email}!
3 | %p Someone has requested a link to change your password. You can do this through the link below.
4 | %p= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @token)
5 | %p If you didn't request this, please ignore this email.
6 | %p Your password won't change until you access the link above and create a new one.
7 |
--------------------------------------------------------------------------------
/app/views/devise/mailer/unlock_instructions.html.haml:
--------------------------------------------------------------------------------
1 | %p
2 | Hello #{@resource.email}!
3 | %p Your account has been locked due to an excessive number of unsuccessful sign in attempts.
4 | %p Click the link below to unlock your account:
5 | %p= link_to 'Unlock my account', unlock_url(@resource, :unlock_token => @token)
6 |
--------------------------------------------------------------------------------
/app/views/devise/passwords/edit.html.haml:
--------------------------------------------------------------------------------
1 | = twitter_bootstrap_form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put, class: 'form-devise' }) do |f|
2 | %h2 Change your password
3 | = devise_error_messages!
4 | = f.hidden_field :reset_password_token
5 | = f.password_field :password, :autofocus => true
6 | = f.password_field :password_confirmation
7 | = f.submit "Change my password"
8 | %p
9 | = render "devise/shared/links"
10 |
--------------------------------------------------------------------------------
/app/views/devise/passwords/new.html.haml:
--------------------------------------------------------------------------------
1 | = twitter_bootstrap_form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post, class: 'form-devise', role: 'form' }) do |f|
2 | %h2 Forgot your password?
3 | = devise_error_messages!
4 | = f.email_field :email, :autofocus => true
5 | = f.submit "Send me reset password instructions"
6 | %p
7 | = render "devise/shared/links"
8 |
--------------------------------------------------------------------------------
/app/views/devise/registrations/edit.html.haml:
--------------------------------------------------------------------------------
1 | .form-devise
2 | = bootstrap_form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put, class: 'form-devise' }) do |f|
3 | %h2
4 | Edit #{resource_name.to_s.humanize}
5 | = devise_error_messages!
6 | = f.static_control :identifier
7 | = f.text_field :name
8 | = f.email_field :email
9 | - if devise_mapping.confirmable? && resource.pending_reconfirmation?
10 | %div
11 | Currently waiting confirmation for: #{resource.unconfirmed_email}
12 |
13 | = f.text_field :bitcoin_address, placeholder: 'Your peercoin address'
14 | %div
15 | = f.password_field :password, autocomplete: 'off', help: "(leave blank if you don't want to change it)"
16 | %div
17 | = f.password_field :password_confirmation, autocomplete: 'off'
18 | - if f.object.has_password?
19 | %div
20 | = f.password_field :current_password, help: "(we need your current password to confirm your changes)"
21 | %div= f.submit "Update", class: 'btn btn-primary btn-block'
22 |
23 | - if @user.balance > 0
24 | %h3 Send tips back
25 | .send-tips-back-block
26 | %p
27 | If you don't want the tips, you can send the funds back to the supported projects:
28 | = button_to "Send all my tips back to their project", send_tips_back_user_path(@user), class: "btn btn-danger btn-block", confirm: "All the #{to_btc @user.balance} peercoins you received will be sent back to their project. Are you sure?"
29 |
30 | %h3 Cancel my account
31 | %p
32 | Unhappy? #{button_to "Cancel my account", registration_path(resource_name), :data => { :confirm => "Are you sure?" }, :method => :delete, class: 'btn btn-danger btn-block'}
33 | = link_to "Back", :back
34 |
--------------------------------------------------------------------------------
/app/views/devise/registrations/new.html.haml:
--------------------------------------------------------------------------------
1 | = twitter_bootstrap_form_for(resource, :as => resource_name, :url => registration_path(resource_name), html: { class: 'form-devise'}) do |f|
2 | %h2 Sign up
3 | = devise_error_messages!
4 | = f.email_field :email, :autofocus => true
5 | = f.password_field :password
6 | = f.password_field :password_confirmation
7 | = f.submit "Sign up"
8 | %p
9 | = render "devise/shared/links"
10 |
--------------------------------------------------------------------------------
/app/views/devise/sessions/new.html.haml:
--------------------------------------------------------------------------------
1 | #sign-in-form
2 | .row
3 | .col-md-4
4 | %h4 Sign in with your email
5 | = twitter_bootstrap_form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f|
6 | = hidden_field_tag :return_url, params[:return_url]
7 | = f.email_field :email, :autofocus => true
8 | = f.password_field :password
9 | - if devise_mapping.rememberable?
10 | %div
11 | = f.check_box :remember_me, "Remember me"
12 | = f.submit "Sign in", class: 'btn btn-primary btn-block'
13 | .col-md-4
14 | - if devise_mapping.omniauthable?
15 | %h4 Sign in with a provider
16 | - resource_class.omniauth_providers.each do |provider|
17 | = link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider, origin: params[:return_url]), class: "btn btn-primary btn-block", method: :post
18 | .col-md-4
19 | %h4 Other options
20 | = render "devise/shared/links"
21 |
--------------------------------------------------------------------------------
/app/views/devise/shared/_links.haml:
--------------------------------------------------------------------------------
1 | - if controller_name != 'sessions'
2 | = link_to "Sign in", new_session_path(resource_name)
3 | %br/
4 | - if devise_mapping.registerable? && controller_name != 'registrations'
5 | = link_to "Sign up", new_registration_path(resource_name)
6 | %br/
7 | - if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations'
8 | = link_to "Forgot your password?", new_password_path(resource_name)
9 | %br/
10 | - if devise_mapping.confirmable? && controller_name != 'confirmations'
11 | = link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name)
12 | %br/
13 | - if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks'
14 | = link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name)
15 | %br/
16 |
--------------------------------------------------------------------------------
/app/views/devise/unlocks/new.html.haml:
--------------------------------------------------------------------------------
1 | %h2 Resend unlock instructions
2 | = form_for(resource, :as => resource_name, :url => unlock_path(resource_name), :html => { :method => :post }) do |f|
3 | = devise_error_messages!
4 | %div
5 | = f.label :email
6 | %br/
7 | = f.email_field :email, :autofocus => true
8 | %div= f.submit "Resend unlock instructions"
9 | = render "devise/shared/links"
10 |
--------------------------------------------------------------------------------
/app/views/distributions/_form.html.haml:
--------------------------------------------------------------------------------
1 | .row
2 | .col-md-12
3 | = bootstrap_form_for [@project, @distribution], html: {id: "distribution-form"} do |f|
4 | - if (errors = f.object.errors[:base]).any?
5 | .alert.alert-danger
6 | Unable to save the distribution: #{errors.join(", ")}
7 | %table.table
8 | %thead
9 | %th Recipient
10 | %th Reason
11 | %th Amount
12 | %th
13 | %tbody#recipients
14 | - f.object.tips.each do |tip|
15 | = render "tip_form", tip: tip, form: f
16 | .text-center
17 | = f.submit "Save the distribution", class: 'btn btn-primary'
18 | #add-recipient-panels
19 | .row
20 | .col-md-12
21 | %label{for: "add-recipients-input"} Add recipient(s)
22 | .row
23 | .col-md-3
24 | .panel.panel-default
25 | .panel-heading
26 | %h3.panel-title Peer4commit user
27 | .panel-body
28 | .input-group
29 | = bootstrap_form_for User.new, url: new_recipient_form_project_distributions_path(@project) do |f|
30 | = f.text_field :identifier, hide_label: true, append: content_tag(:button, "Add", class: "btn btn-default add-recipient-button"), class: "user-autocomplete", data: {submit: true}
31 | .col-md-3
32 | .panel.panel-default
33 | .panel-heading
34 | %h3.panel-title GitHub user
35 | .panel-body
36 | = bootstrap_form_for User.new, url: new_recipient_form_project_distributions_path(@project) do |f|
37 | = f.text_field :nickname, hide_label: true, append: content_tag(:button, "Add", class: "btn btn-default add-recipient-button"), class: "github-user-autocomplete", data: {project_id: @project.id, submit: true}
38 | .col-md-3
39 | .panel.panel-default
40 | .panel-heading
41 | %h3.panel-title Author of a commit
42 | .panel-body
43 | = bootstrap_form_for Commit.new, url: new_recipient_form_project_distributions_path(@project) do |f|
44 | = f.text_field :sha, hide_label: true, append: content_tag(:button, "Add", class: "btn btn-default add-recipient-button"), class: "commit-autocomplete", data: {project_id: @project.id, submit: true}
45 | .col-md-3
46 | .panel.panel-default
47 | .panel-heading
48 | %h3.panel-title Authors of commits
49 | .panel-body
50 | = bootstrap_form_for User.new, url: new_recipient_form_project_distributions_path(@project) do |f|
51 | = hidden_field_tag :not_rewarded_commits, "1"
52 | %button.btn-block.btn.btn-default Commits not rewarded
53 |
--------------------------------------------------------------------------------
/app/views/distributions/_reason.html.haml:
--------------------------------------------------------------------------------
1 | - case tip.reason
2 | - when Commit
3 | - commit = tip.reason
4 | Commit #{link_to truncate_commit(commit.sha), "https://github.com/#{commit.project.full_name}/commit/#{commit.sha}"}:
5 | %pre= commit.message
6 | - when nil
7 | - if tip.commit.present?
8 | - if tip.project
9 | Commit #{link_to truncate_commit(tip.commit), "https://github.com/#{tip.project.full_name}/commit/#{tip.commit}"}:
10 | - else
11 | Commit #{tip.commit}
12 | - if tip.commit_message.present?
13 | %pre= tip.commit_message
14 | - else
15 | = render_markdown tip.comment
16 |
--------------------------------------------------------------------------------
/app/views/distributions/_tip_form.html.haml:
--------------------------------------------------------------------------------
1 | - index = "#{(Time.now.to_f * 1000000).round}#{SecureRandom.random_number(1_000_000).to_s.rjust(6, '0')}"
2 | = form.fields_for :tips, tip, child_index: index do |fields|
3 | - user = tip.user
4 | - raise "An user is required" unless user
5 | %tr
6 | %td.recipient
7 | = fields.hidden_field :id unless tip.new_record?
8 | - if user.new_record?
9 | = fields.fields_for :user do |user_fields|
10 | = user_fields.hidden_field :email
11 | = user_fields.hidden_field :nickname
12 | = user.recipient_label
13 | - else
14 | = fields.hidden_field :user_id
15 | = link_to user.recipient_label, user
16 | %td.reason
17 | - if tip.reason
18 | = fields.hidden_field :reason_type
19 | = fields.hidden_field :reason_id
20 | = render "reason", tip: tip
21 | - else
22 | = fields.text_area :comment, hide_label: true, rows: 2
23 | %td.amount= fields.text_field :coin_amount, hide_label: true, append: "PPC"
24 | %td.remove= fields.check_box :_destroy
25 |
--------------------------------------------------------------------------------
/app/views/distributions/edit.html.haml:
--------------------------------------------------------------------------------
1 | = render "form"
2 |
--------------------------------------------------------------------------------
/app/views/distributions/index.html.haml:
--------------------------------------------------------------------------------
1 | %h1 Distributions
2 | - if @project
3 | %h2= @project.name
4 | %p
5 | %table.table
6 | %thead
7 | %tr
8 | %th Created At
9 | %th Sent at
10 | %th.text-right Amount
11 | %th Transaction
12 | %th Result
13 | %th
14 | %tbody
15 | - @distributions.each do |distribution|
16 | %tr
17 | %td= l distribution.created_at
18 | %td= l distribution.sent_at if distribution.sent_at
19 | %td.text-right= btc_human distribution.total_amount
20 | %td= link_to truncate(distribution.txid), transaction_url(distribution.txid), target: '_blank' if distribution.txid.present?
21 | %td= distribution.is_error ? "Error" : "Success" if distribution.sent?
22 | %td= link_to "Details", [distribution.project, distribution], class: "btn btn-success"
23 |
--------------------------------------------------------------------------------
/app/views/distributions/new.html.haml:
--------------------------------------------------------------------------------
1 | = render "form"
2 |
--------------------------------------------------------------------------------
/app/views/distributions/new_recipient_form.html.haml:
--------------------------------------------------------------------------------
1 | - output = nil
2 | - bootstrap_form_for Distribution.new do |f|
3 | - output = capture_haml do
4 | - @tips.each do |tip|
5 | = render "tip_form", form: f, tip: tip
6 | = output
7 |
--------------------------------------------------------------------------------
/app/views/distributions/show.html.haml:
--------------------------------------------------------------------------------
1 | #distribution-show-page
2 | - total = @distribution.tips.map(&:amount).sum if @distribution.tips.all?(&:amount)
3 | %table.table
4 | %thead
5 | %tr
6 | %th Recipient
7 | %th Reason
8 | %th Address
9 | %th Amount
10 | %th Percentage
11 | %tbody
12 | - @distribution.tips.each do |tip|
13 | %tr
14 | %td.recipient
15 | - if tip.user
16 | - if tip.user.new_record?
17 | = tip.user.recipient_label
18 | - else
19 | = link_to tip.user.recipient_label, tip.user
20 | - else
21 | Nobody
22 | %td.reason= render "reason", tip: tip
23 | %td.address
24 | - if tip.user.try(:bitcoin_address).present?
25 | = tip.user.bitcoin_address
26 | %td.amount
27 | - if tip.amount
28 | = btc_human tip.amount
29 | - else
30 | %em Undecided
31 | %td.percentage= number_to_percentage(tip.amount.to_f * 100 / total, precision: 1) if total and tip.amount and total > 0
32 |
33 | - if total
34 | %p
35 | %strong
36 | Total amount: #{btc_human total}
37 |
38 | - if @distribution.is_error?
39 | %p.alert.alert-danger
40 | The transaction failed.
41 | - elsif @distribution.sent?
42 | %p.alert.alert-success
43 | Transaction sent
44 | - if @distribution.sent_at
45 | on #{l(@distribution.sent_at)}
46 | - elsif !@distribution.all_addresses_known?
47 | %p.alert.alert-warning
48 | The transaction cannot be sent because some addresses are missing. Ask the recipients to sign in and provide an address.
49 | .distribution-actions
50 | - if can? :update, @distribution
51 | .distribution-action
52 | = link_to "Edit the distribution", edit_project_distribution_path(@project, @distribution), class: "btn btn-default"
53 | - if total and can? :send_transaction, @distribution
54 | .distribution-action
55 | = button_to "Send the transaction", send_transaction_project_distribution_path(@project, @distribution), class: "btn btn-danger", data: {confirm: "#{total.to_f / COIN} peercoins will be sent. Are you sure?"}
56 |
57 | %hr
58 | = commontator_thread(@distribution)
59 |
--------------------------------------------------------------------------------
/app/views/home/index.html.haml:
--------------------------------------------------------------------------------
1 | - content_for :main_content do
2 | #home-page
3 | / Jumbotron
4 | .jumbotron
5 | .container
6 | %h1 Make anything happen
7 | %p.lead
8 |
9 | %a.btn.btn-lg.btn-success{href: projects_path} See projects
10 |
11 | .container.container-md-height
12 | / Example row of columns
13 | .row.row-md-height
14 | .col-lg-3.col-md-height.col-top.main-panel.donate
15 | .panel-content
16 | %h2 Donate
17 | %p
18 | Donate to projects to make them happen.
19 | .button-container
20 | %a.btn.btn-primary.btn-block{href: projects_path} See projects
21 | .col-lg-3.col-md-height.col-top.main-panel.contribute
22 | .panel-content
23 | %h2 Contribute
24 | %p
25 | Get paid to contribute to a project.
26 | .button-container
27 | %a.btn.btn-primary.btn-block{href: projects_path} See projects
28 | .col-lg-3.col-md-height.col-top.main-panel.raise
29 | .panel-content
30 | %h2 Raise funds
31 | %p
32 | Make something happen by raising funds and distributing them.
33 | .button-container
34 | %a.btn.btn-primary.btn-block{href: new_project_path} Create a project
35 | .col-lg-3.col-md-height.col-top.main-panel.how-it-works
36 | .panel-content
37 | %h2 How it works?
38 | %p
39 | Fundraisers collect funds and distribute them to contributors.
40 | .button-container
41 | %a.btn.btn-primary.btn-block{href: faq_path} FAQ
42 |
--------------------------------------------------------------------------------
/app/views/kaminari/_first_page.html.haml:
--------------------------------------------------------------------------------
1 | %li
2 | = link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, :remote => remote
3 |
--------------------------------------------------------------------------------
/app/views/kaminari/_gap.html.haml:
--------------------------------------------------------------------------------
1 | %li.disabled
2 | = link_to raw(t 'views.pagination.truncate'), '#'
3 |
--------------------------------------------------------------------------------
/app/views/kaminari/_last_page.html.haml:
--------------------------------------------------------------------------------
1 | %li
2 | = link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, {:remote => remote}
3 |
--------------------------------------------------------------------------------
/app/views/kaminari/_next_page.html.haml:
--------------------------------------------------------------------------------
1 | %li
2 | = link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, :rel => 'next', :remote => remote
3 |
--------------------------------------------------------------------------------
/app/views/kaminari/_page.html.haml:
--------------------------------------------------------------------------------
1 | %li{class: "#{'active' if page.current?}"}
2 | = link_to page, page.current? ? '#' : url, {:remote => remote, :rel => page.next? ? 'next' : page.prev? ? 'prev' : nil}
3 |
--------------------------------------------------------------------------------
/app/views/kaminari/_paginator.html.haml:
--------------------------------------------------------------------------------
1 | = paginator.render do
2 | %ul.pagination
3 | = first_page_tag unless current_page.first?
4 | = prev_page_tag unless current_page.first?
5 | - each_page do |page|
6 | - if page.left_outer? || page.right_outer? || page.inside_window?
7 | = page_tag page
8 | - elsif !page.was_truncated?
9 | = gap_tag
10 | = next_page_tag unless current_page.last?
11 | = last_page_tag unless current_page.last?
--------------------------------------------------------------------------------
/app/views/kaminari/_prev_page.html.haml:
--------------------------------------------------------------------------------
1 | %li
2 | = link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, :rel => 'prev', :remote => remote
3 |
--------------------------------------------------------------------------------
/app/views/layouts/application.html.haml:
--------------------------------------------------------------------------------
1 | !!!
2 | %html{lang: "en"}
3 | %head
4 | %meta{charset: "utf-8"}/
5 | %meta{content: "width=device-width, initial-scale=1.0", name: "viewport"}/
6 | %meta{content: "", name: "description"}/
7 | %meta{content: "", name: "author"}/
8 | %link{href: image_path("ppcoin.png"), rel: "shortcut icon"}/
9 |
10 | %title= content_for?(:title) ? yield(:title) : "Peer4commit"
11 |
12 | %meta{name: 'description', content: (content_for?(:title) ? yield(:title) : "Donate peercoins to open source projects or make commits and get tips for it.")}
13 | %meta{name: 'keywords', content: 'open source,contribute,github,community,git,bitcoin,peercoin,ppc,tips,perks'}
14 | / %meta{:property => 'og:image', :content => asset_path('logo.png')}
15 | / %link{:rel => 'image_src', :type => 'image/png', :href => asset_path('logo.png')}
16 |
17 | = stylesheet_link_tag "application", media: "all", data: { "turbolinks-track" => true }
18 | = javascript_include_tag "application", data: { "turbolinks-track" => true }
19 |
20 | /[if lt IE 9]
21 | %script{:src => "https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"}
22 | %script{:src => "https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"}
23 |
24 |
25 |
26 | = csrf_meta_tags
27 | %body{data: {environment: Rails.env}}
28 | - if Rails.env.production?
29 | :javascript
30 | (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
31 | (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
32 | m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
33 | })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
34 |
35 | ga('create', 'UA-11108334-6', 'peer4commit.com');
36 | ga('send', 'pageview');
37 | #top-bar
38 | .container
39 | %a#main-logo{href: root_path}
40 | %h3 Peer4commit
41 | = render_flash_message
42 | #main-content
43 | - if content_for?(:main_content)
44 | = yield :main_content
45 | - else
46 | .container#main-container
47 | = yield
48 | #footer
49 | .container
50 | / Site footer
51 | .footer
52 | %p
53 | ©
54 | = link_to 'Peer4commit', 'http://peer4commit.com/', target: '_blank'
55 | 2014-2019. Source code is available at #{link_to('github', 'https://github.com/sigmike/peer4commit', target: '_blank')},
56 | based on #{link_to "Tip4commit", "http://tip4commit.com/"}.
57 | / /container
58 | /
59 | Bootstrap core JavaScript
60 | \==================================================
61 | / Placed at the end of the document so the pages load faster\
62 |
--------------------------------------------------------------------------------
/app/views/layouts/closed.html.haml:
--------------------------------------------------------------------------------
1 | %h1 Closed
2 |
3 | %p
4 | Peer4commit is now closed. All the remaining funds have been sent to #{link_to "the Peercoin Foundation", "https://peercoin.net/foundation.html"}.
5 | See #{link_to "this post", "https://talk.peercoin.net/t/notice-the-peercoin-team-will-be-closing-peer4commit-please-withdraw-all-coins-before-sept-21st/9759"} for more information and discussion.
6 |
--------------------------------------------------------------------------------
/app/views/projects/_form.html.haml:
--------------------------------------------------------------------------------
1 | = bootstrap_form_for @project, layout: :horizontal do |f|
2 | = f.alert_message "Please fix the errors below."
3 | = f.text_field :name
4 | = f.text_field :description
5 | = f.text_area :detailed_description, rows: 10
6 | = f.fields_for :tipping_policies_text, @project.tipping_policies_text || @project.build_tipping_policies_text do |fields|
7 | = fields.text_area :text, rows: 10, label: "Tipping policies"
8 | = f.text_field :full_name, label: "GitHub URL (optional)"
9 | = f.form_group do
10 | = f.check_box :auto_tip_commits, {label: "Automatically send 1% of the balance to each commit added to the default branch of the GitHub project. It only works if the user has registered an account on this site."}
11 | = f.form_group do
12 | = f.primary "Save"
13 |
--------------------------------------------------------------------------------
/app/views/projects/decide_tip_amounts.html.haml:
--------------------------------------------------------------------------------
1 | %h1 Decide tip amounts
2 | %p
3 | Project balance: #{btc_human @project.available_amount}
4 | = bootstrap_form_for @project, url: decide_tip_amounts_project_path(@project) do |f|
5 | %table.table.table-hover.decide-tip-amounts-table
6 | %thead
7 | %tr
8 | %th Commit
9 | %th Author
10 | %th Message
11 | %th Percentage of balance
12 | %th Free amount
13 | %tbody
14 | = f.fields_for(:tips, @project.tips.select(&:was_undecided?)) do |tip_fields|
15 | = tip_fields.hidden_field :id
16 | - tip = tip_fields.object
17 | - next unless tip.user
18 | %tr
19 | %td= link_to commit_tag(tip.commit), tip.commit_url
20 | %td= tip.user.nickname
21 | %td= simple_format tip.commit_message
22 | %td.col-sm-2
23 | - options = [["Free: 0%", "0"], ["Tiny: 0.1%", "0.1"], ["Small: 0.5%", "0.5"], ["Normal: 1%", "1"], ["Big: 2%", "2"], ["Huge: 5%", "5"]]
24 | = tip_fields.select :decided_amount_percentage, options, hide_label: true, include_blank: true
25 | %td.col-sm-2
26 | = tip_fields.text_field :decided_free_amount, inline: true, hide_label: true, append: "PPC"
27 |
28 | .text-center
29 | = f.submit 'Send the selected tip amounts'
30 |
--------------------------------------------------------------------------------
/app/views/projects/donate.html.haml:
--------------------------------------------------------------------------------
1 | .row
2 | .col-md-12
3 | %h1 Donate to #{@project.name}
4 | - fundraisers = @project.users
5 | - if fundraisers.any?
6 | %p
7 | - if fundraisers.size > 1
8 | Before you donate make sure the project collaborators #{fundraisers.map { |user| link_to user.full_name, user }.join(", ").html_safe} are trustworthy and able to achieve what they promised.
9 | - else
10 | - user = fundraisers.first
11 | Before you donate make sure the fundraiser #{link_to user.full_name, user} is trustworthy and able to achieve what he promised.
12 |
13 | - if @donation_address.persisted? and @donation_address.donation_address.present?
14 | %p
15 | To donate to #{link_to @project.name, @project} send Peercoins to this address: #{@donation_address.donation_address}
16 | - else
17 | To donate to this project you can provide a return address. This address will be used if Peer4Commit or the fundraiser ever need to send funds back to you. In the future, this address may also be used to cast a vote. For a vote to be valid, it will need to be signed by the address that the donation was sent from.
18 |
19 | = bootstrap_form_for @donation_address, url: donate_project_path(@project) do |f|
20 | = f.text_field :sender_address, label: 'Return address'
21 | = f.submit "Generate my donation address"
22 |
23 |
24 | %hr
25 | %p If you want to donate without providing a return address, you can just send Peercoins to this address: #{@project.bitcoin_address}
26 |
--------------------------------------------------------------------------------
/app/views/projects/donors.html.haml:
--------------------------------------------------------------------------------
1 | - content_for :title do
2 | = "#{@project.name} - Donor list"
3 |
4 | .row
5 | .col-md-12
6 | %h1
7 | = content_for(:title)
8 | %table.table.table-hover.donor-list
9 | %thead
10 | %tr
11 | %th.date Date
12 | %th.amount Amount
13 | %th.sender-address Sender address
14 | %th.transactions Transaction
15 | %tbody
16 | - @project.deposits.includes(:donation_address).order(created_at: :desc).each do |deposit|
17 | %tr.donor-row
18 | %td.date= l(deposit.created_at)
19 | %td.amount= btc_human deposit.amount
20 | %td.sender-address= deposit.donation_address.try(:sender_address).presence || 'No address provided'
21 | %td.transactions.txid
22 | = link_to transaction_url(deposit.txid) do
23 | %abbr{title: deposit.txid}= truncate(deposit.txid, length: 10)
24 |
--------------------------------------------------------------------------------
/app/views/projects/edit.html.haml:
--------------------------------------------------------------------------------
1 | - content_for :title do
2 | = @project.name
3 |
4 | %h1= @project.name
5 | .row
6 | .col-md-12
7 | = render "form"
8 |
--------------------------------------------------------------------------------
/app/views/projects/index.html.haml:
--------------------------------------------------------------------------------
1 | #project-index
2 | .row
3 | .col-md-10
4 | %h1 Projects
5 | .col-md-2
6 | .text-right
7 | = link_to "Create a project", new_project_path, class: 'btn btn-default btn-block'
8 | %p
9 | %table.table.table-hover
10 | %thead
11 | %tr
12 | %th.name Name
13 | %th.description Description
14 | %th.amount Funds
15 | %th.actions
16 | %tbody
17 | - @projects.each do |project|
18 | %tr
19 | %td.name
20 | %strong= link_to project.name, project
21 | %td.description= project.description
22 | %td.amount= btc_human project.available_amount_cache
23 | %td.actions= link_to 'Details', project, class: 'btn btn-default btn-sm'
24 | = paginate @projects
25 |
--------------------------------------------------------------------------------
/app/views/projects/new.html.haml:
--------------------------------------------------------------------------------
1 | - content_for :title do
2 | New project
3 |
4 | %h1 New project
5 | .row
6 | .col-md-12
7 | = render "form"
8 |
--------------------------------------------------------------------------------
/app/views/tips/index.html.haml:
--------------------------------------------------------------------------------
1 | %h1
2 | - if @project
3 | = link_to @project.full_name, @project
4 | tips
5 | - else
6 | Tips
7 | %p
8 | %table.table
9 | %thead
10 | %tr
11 | %th Created At
12 | %th Commiter
13 | - unless @project
14 | %th Project
15 | %th Commit
16 | %th Amount
17 | %th Withdrawal
18 | %tbody
19 | - @tips.each do |tip|
20 | %tr
21 | %td= l tip.created_at, format: :short
22 | %td
23 | - if tip.user
24 | - if tip.user.nickname.blank?
25 | = tip.user.full_name
26 | - else
27 | = link_to tip.user.full_name, "https://github.com/#{tip.user.nickname}", target: '_blank'
28 | - unless @project
29 | %td= link_to tip.project.full_name, tip.project
30 | %td
31 | - if tip.commit.present?
32 | = link_to tip.commit[0..6], "https://github.com/#{tip.project.full_name}/commit/#{tip.commit}", target: :blank
33 | %td= btc_human tip.amount
34 | %td{class: tip.distribution.try(:is_error?) ? "danger" : nil}
35 | - if tip.distribution.nil?
36 | - if tip.refunded_at
37 | Refunded to project's deposit
38 | - elsif tip.undecided?
39 | The amount of the tip has not been decided yet
40 | - elsif tip.free?
41 | - elsif tip.user and tip.user.bitcoin_address.blank?
42 | User didn't specify withdrawal address
43 | - elsif tip.project.amount_to_pay < CONFIG["min_payout"].to_d * COIN
44 | The amount of tips for this project is below withdrawal threshold
45 | - else
46 | Waiting for withdrawal
47 | - else
48 | - if tip.distribution.is_error?
49 | Transaction failed
50 | - if tip.distribution.txid.present?
51 | = link_to tip.distribution.txid, transaction_url(tip.distribution.txid), target: :blank
52 | = paginate @tips
53 |
--------------------------------------------------------------------------------
/app/views/user_mailer/address_request.html.haml:
--------------------------------------------------------------------------------
1 | %h4 Hello,
2 |
3 | %p
4 | #{@collaborator.nickname} wants to reward you #{@tip.amount ? btc_human(@tip.amount) : ""} on his project #{@tip.project.name}.
5 | = link_to "More details on the distribution", project_distribution_url(@tip.project, @tip.distribution)
6 |
7 | %p
8 | To get your reward you must provide a Peercoin address.
9 |
10 | - if @user.confirmed?
11 | %p= link_to "Set your Peercoin address", edit_registration_url(@user)
12 | - else
13 | %p= link_to 'Set your password and Peercoin address', set_password_and_address_user_url(@user, token: @user.confirmation_token)
14 |
15 | %p Thank you.
16 |
17 | %p= link_to "peer4commit.com", "http://peer4commit.com/"
18 |
19 | %p
20 | %small
21 | = link_to "Don't notify me anymore.", login_users_url(token: @user.login_token, unsubscribe: true)
22 |
23 |
--------------------------------------------------------------------------------
/app/views/user_mailer/new_tip.html.haml:
--------------------------------------------------------------------------------
1 | %h4 Hello, #{@user.full_name}!
2 |
3 | %p You were tipped #{btc_human @tip.amount} for your commit on Project #{@tip.project.full_name}. Please, log in and tell us your peercoin address to get it.
4 |
5 | %p Your current balance is #{btc_human @user.balance}. If you don't enter a peercoin address your tips will be returned to the project in 30 days.
6 |
7 | %p= link_to 'Set your password and Peercoin address', set_password_and_address_user_url(@user, token: @user.confirmation_token)
8 |
9 | %p Thanks for contributing to Open Source!
10 |
11 | %p= link_to "peer4commit.com", "http://peer4commit.com/"
12 |
13 | %p
14 | %small
15 | = link_to "Don't notify me anymore, I don't need tips.", login_users_url(token: @user.login_token, unsubscribe: true)
16 |
--------------------------------------------------------------------------------
/app/views/user_mailer/security_issue.html.haml:
--------------------------------------------------------------------------------
1 | %h4 Hello #{@user.full_name},
2 |
3 | %p We recently discovered a security issue on Peer4commit. This issue allowed someone to change the Peercoin address of other users.
4 |
5 | %p
6 | The problem is now fixed. To ensure our database is clean we decided to clear all the addresses.
7 | Please set your Peercoin address again:
8 | = link_to('Sign in', login_users_url(token: @user.login_token)) + "."
9 |
10 | %p We think only one tip was stolen. It will be sent again to its owner when he sets his address.
11 |
12 | %p Sorry for this inconvenience.
13 |
14 | %p= link_to "peer4commit.com", "http://peer4commit.com/"
15 |
16 | %p
17 | %small
18 | = link_to "Don't notify me anymore.", login_users_url(token: @user.login_token, unsubscribe: true)
19 |
--------------------------------------------------------------------------------
/app/views/users/index.html.haml:
--------------------------------------------------------------------------------
1 | %h1 Top Contributors
2 | %p
3 | %table.table
4 | %thead
5 | %tr
6 | %th Name
7 | %th Commits tipped
8 | %th Withdrawn
9 | %tbody
10 | - @users.each do |user|
11 | %tr
12 | %td
13 | - if user.nickname.blank?
14 | = user.full_name
15 | - else
16 | = link_to user.full_name, "https://github.com/#{user.nickname}", target: '_blank'
17 | %td= user.commits_count
18 | %td= btc_human user.withdrawn_amount
19 | = paginate @users
20 |
--------------------------------------------------------------------------------
/app/views/users/set_password_and_address.html.haml:
--------------------------------------------------------------------------------
1 | = bootstrap_form_for @user, url: request.url do |f|
2 | = f.password_field :password
3 | = f.password_field :password_confirmation
4 | = f.text_field :bitcoin_address
5 | = f.submit "Save"
6 |
--------------------------------------------------------------------------------
/app/views/users/show.html.haml:
--------------------------------------------------------------------------------
1 | %h1= @user.name
2 | %p
3 | %strong Identifier:
4 | = @user.identifier
5 |
6 | - if @user.nickname.present?
7 | %p
8 | %strong GitHub account:
9 | = link_to @user.nickname, "https://github.com/#{@user.nickname}"
10 |
11 | - if (projects = @user.projects).any?
12 | %h2 Projects
13 | %ul
14 | - projects.each do |project|
15 | %li= link_to project.to_label, project
16 |
17 | %hr
18 | = commontator_thread(@user)
19 |
--------------------------------------------------------------------------------
/app/views/users/update.html.haml:
--------------------------------------------------------------------------------
1 | %h1 Users#update
2 | %p Find me in app/views/users/update.html.haml
--------------------------------------------------------------------------------
/bin/airbrake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'airbrake' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('airbrake', 'airbrake')
17 |
--------------------------------------------------------------------------------
/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3 | load Gem.bin_path('bundler', 'bundle')
4 |
--------------------------------------------------------------------------------
/bin/bundler:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'bundler' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('bundler', 'bundler')
17 |
--------------------------------------------------------------------------------
/bin/cap:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'cap' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('capistrano', 'cap')
17 |
--------------------------------------------------------------------------------
/bin/cdiff:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'cdiff' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('term-ansicolor', 'cdiff')
17 |
--------------------------------------------------------------------------------
/bin/colortab:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'colortab' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('term-ansicolor', 'colortab')
17 |
--------------------------------------------------------------------------------
/bin/decolor:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'decolor' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('term-ansicolor', 'decolor')
17 |
--------------------------------------------------------------------------------
/bin/erubis:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'erubis' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('erubis', 'erubis')
17 |
--------------------------------------------------------------------------------
/bin/haml:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'haml' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('haml', 'haml')
17 |
--------------------------------------------------------------------------------
/bin/lessc:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'lessc' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('less', 'lessc')
17 |
--------------------------------------------------------------------------------
/bin/rackup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'rackup' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('rack', 'rackup')
17 |
--------------------------------------------------------------------------------
/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | APP_PATH = File.expand_path('../../config/application', __FILE__)
3 | require_relative '../config/boot'
4 | require 'rails/commands'
5 |
--------------------------------------------------------------------------------
/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require_relative '../config/boot'
3 | require 'rake'
4 | Rake.application.run
5 |
--------------------------------------------------------------------------------
/bin/rdoc:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'rdoc' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('rdoc', 'rdoc')
17 |
--------------------------------------------------------------------------------
/bin/ri:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'ri' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('rdoc', 'ri')
17 |
--------------------------------------------------------------------------------
/bin/sass:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'sass' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('sass', 'sass')
17 |
--------------------------------------------------------------------------------
/bin/sass-convert:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'sass-convert' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('sass', 'sass-convert')
17 |
--------------------------------------------------------------------------------
/bin/scss:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'scss' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('sass', 'scss')
17 |
--------------------------------------------------------------------------------
/bin/sdoc:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'sdoc' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('sdoc', 'sdoc')
17 |
--------------------------------------------------------------------------------
/bin/sdoc-merge:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'sdoc-merge' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('sdoc', 'sdoc-merge')
17 |
--------------------------------------------------------------------------------
/bin/slimrb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'slimrb' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('slim', 'slimrb')
17 |
--------------------------------------------------------------------------------
/bin/sprockets:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'sprockets' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('sprockets', 'sprockets')
17 |
--------------------------------------------------------------------------------
/bin/term_display:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'term_display' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('term-ansicolor', 'term_display')
17 |
--------------------------------------------------------------------------------
/bin/term_mandel:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'term_mandel' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('term-ansicolor', 'term_mandel')
17 |
--------------------------------------------------------------------------------
/bin/thor:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'thor' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('thor', 'thor')
17 |
--------------------------------------------------------------------------------
/bin/tilt:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'tilt' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('tilt', 'tilt')
17 |
--------------------------------------------------------------------------------
/bin/tt:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'tt' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('treetop', 'tt')
17 |
--------------------------------------------------------------------------------
/config.ru:
--------------------------------------------------------------------------------
1 | # This file is used by Rack-based servers to start the application.
2 |
3 | require ::File.expand_path('../config/environment', __FILE__)
4 |
5 | if host = CONFIG["canonical_host"]
6 | use Rack::CanonicalHost, host
7 | end
8 |
9 | run Rails.application
10 |
--------------------------------------------------------------------------------
/config/application.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../boot', __FILE__)
2 |
3 | require 'rails/all'
4 |
5 | # Require the gems listed in Gemfile, including any gems
6 | # you've limited to :test, :development, or :production.
7 | Bundler.require(:default, Rails.env)
8 |
9 | CONFIG ||= YAML::load(File.open("config/config.yml"))
10 |
11 | COIN = 1000000 # ppcoin/src/util.h
12 |
13 | module T4c
14 | class Application < Rails::Application
15 |
16 | # Settings in config/environments/* take precedence over those specified here.
17 | # Application configuration should go into files in config/initializers
18 | # -- all .rb files in that directory are automatically loaded.
19 |
20 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
21 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
22 | # config.time_zone = 'Central Time (US & Canada)'
23 |
24 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
25 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
26 | # config.i18n.default_locale = :de
27 |
28 | config.autoload_paths += %W(#{config.root}/lib)
29 |
30 | I18n.enforce_available_locales = false
31 |
32 | config.active_record.raise_in_transactional_callbacks = true
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/config/boot.rb:
--------------------------------------------------------------------------------
1 | # Set up gems listed in the Gemfile.
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3 |
4 | require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
5 |
--------------------------------------------------------------------------------
/config/config.yml.sample:
--------------------------------------------------------------------------------
1 | github:
2 | key: "111111111111"
3 | secret: "111111111111"
4 |
5 | daemon:
6 | username: rpcuser
7 | password: rpcpassword
8 | host: localhost
9 | port: 9904
10 | path: /path/to/ppcoin/src/ppcoind
11 |
12 | devise:
13 | secret: "111111111111"
14 |
15 | application:
16 | secret: "111111111111"
17 |
18 | smtp_settings:
19 | address: smtp.gmail.com
20 | port: 587
21 | domain: foobar.com
22 | user_name: example@foobar.com
23 | password: MY_PASSWORD
24 | authentication: plain
25 | enable_starttls_auto: true
26 |
27 | default_from: contact@example.com
28 | send_all_emails_to: # put an email here if you're testing and you don't want any email sent to others
29 | exception_email: admin@example.com # an email will be sent to this address if an unhandled exception occurs
30 |
31 | # Uncomment to use airbrake/errbit
32 |
33 | # airbrake:
34 | # api_key: 111111111111
35 | # host: errbit.tip4commit.com
36 |
37 | tip: 0.01
38 | min_payout: 1.0 # in PPC
39 | our_fee: 0.05
40 | tipper_delay: "1.hour"
41 |
42 | address_versions: # 55/117 for peercoin, 111/196 for testnet, see base58.h
43 | - 111
44 | - 196
45 |
46 | # canonical_host: peer4commit.example.com # will redirect all other hostnames to this one
47 |
--------------------------------------------------------------------------------
/config/cucumber.yml:
--------------------------------------------------------------------------------
1 | <%
2 | rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : ""
3 | rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}"
4 | std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --strict --tags ~@wip"
5 | %>
6 | default: <%= std_opts %> features
7 | wip: --tags @wip:3 --wip features
8 | rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip
9 |
--------------------------------------------------------------------------------
/config/database.yml.sample:
--------------------------------------------------------------------------------
1 | # SQLite version 3.x
2 | # gem install sqlite3
3 | #
4 | # Ensure the SQLite 3 gem is defined in your Gemfile
5 | # gem 'sqlite3'
6 | development:
7 | adapter: sqlite3
8 | database: db/development.sqlite3
9 | pool: 5
10 | timeout: 5000
11 |
12 | # Warning: The database defined as "test" will be erased and
13 | # re-generated from your development database when you run "rake".
14 | # Do not set this db to the same as development or production.
15 | test:
16 | adapter: sqlite3
17 | database: db/test.sqlite3
18 | pool: 5
19 | timeout: 5000
20 |
21 | production:
22 | adapter: mysql2
23 | encoding: utf8
24 | database: peer4commit
25 | username: root
26 | password:
27 | socket: /var/run/mysqld/mysqld.sock
28 |
--------------------------------------------------------------------------------
/config/deploy.rb:
--------------------------------------------------------------------------------
1 | set :application, 't4c'
2 | set :repo_url, 'git@github.com:sigmike/peer4commit.git'
3 |
4 | # ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }
5 |
6 | set :deploy_to, "/home/apps/p4c"
7 | set :scm, :git
8 |
9 | set :rvm_type, :user
10 | set :rvm_ruby_version, '2.0.0-p247'
11 | set :rvm_custom_path, '~/.rvm'
12 |
13 | set :format, :pretty
14 | # set :log_level, :debug
15 | # set :pty, true
16 |
17 | set :linked_files, %w{config/database.yml config/config.yml}
18 | set :linked_dirs, %w{log tmp}
19 |
20 | # set :default_env, { path: "/opt/ruby/bin:$PATH" }
21 | set :keep_releases, 5
22 |
23 | namespace :deploy do
24 |
25 | desc 'Restart application'
26 | task :restart do
27 | on roles(:app), in: :sequence, wait: 5 do
28 | execute :touch, release_path.join('tmp/restart.txt')
29 | end
30 | end
31 |
32 | after :restart, :clear_cache do
33 | on roles(:web), in: :groups, limit: 3, wait: 10 do
34 | # Here we can do anything such as:
35 | # within release_path do
36 | # execute :rake, 'cache:clear'
37 | # end
38 | end
39 | end
40 |
41 | after :finishing, 'deploy:cleanup'
42 |
43 | end
44 |
--------------------------------------------------------------------------------
/config/deploy/production.rb:
--------------------------------------------------------------------------------
1 | set :stage, :production
2 |
3 | # Simple Role Syntax
4 | # ==================
5 | # Supports bulk-adding hosts to roles, the primary
6 | # server in each group is considered to be the first
7 | # unless any hosts have the primary property set.
8 | role :app, %w{apps@50.116.2.58}
9 | role :web, %w{apps@50.116.2.58}
10 | role :db, %w{apps@50.116.2.58}
11 |
12 | set :rails_env, 'production'
13 | set :migration_role, 'db'
14 |
15 | # Extended Server Syntax
16 | # ======================
17 | # This can be used to drop a more detailed server
18 | # definition into the server list. The second argument
19 | # something that quacks like a has can be used to set
20 | # extended properties on the server.
21 | #server 'example.com', user: 'deploy', roles: %w{web app}, my_property: :my_value
22 |
23 | # you can set custom ssh options
24 | # it's possible to pass any option but you need to keep in mind that net/ssh understand limited list of options
25 | # you can see them in [net/ssh documentation](http://net-ssh.github.io/net-ssh/classes/Net/SSH.html#method-c-start)
26 | # set it globally
27 | # set :ssh_options, {
28 | # keys: %w(/home/rlisowski/.ssh/id_rsa),
29 | # forward_agent: false,
30 | # auth_methods: %w(password)
31 | # }
32 | # and/or per server
33 | # server 'example.com',
34 | # user: 'user_name',
35 | # roles: %w{web app},
36 | # ssh_options: {
37 | # user: 'user_name', # overrides user setting above
38 | # keys: %w(/home/user_name/.ssh/id_rsa),
39 | # forward_agent: false,
40 | # auth_methods: %w(publickey password)
41 | # # password: 'please use keys'
42 | # }
43 | # setting per server overrides global ssh_options
44 |
45 | # fetch(:default_env).merge!(rails_env: :production)
46 |
--------------------------------------------------------------------------------
/config/deploy/staging.rb:
--------------------------------------------------------------------------------
1 | set :stage, :staging
2 |
3 | # Simple Role Syntax
4 | # ==================
5 | # Supports bulk-adding hosts to roles, the primary
6 | # server in each group is considered to be the first
7 | # unless any hosts have the primary property set.
8 | role :app, %w{deploy@example.com}
9 | role :web, %w{deploy@example.com}
10 | role :db, %w{deploy@example.com}
11 |
12 | # Extended Server Syntax
13 | # ======================
14 | # This can be used to drop a more detailed server
15 | # definition into the server list. The second argument
16 | # something that quacks like a has can be used to set
17 | # extended properties on the server.
18 | server 'example.com', user: 'deploy', roles: %w{web app}, my_property: :my_value
19 |
20 | # you can set custom ssh options
21 | # it's possible to pass any option but you need to keep in mind that net/ssh understand limited list of options
22 | # you can see them in [net/ssh documentation](http://net-ssh.github.io/net-ssh/classes/Net/SSH.html#method-c-start)
23 | # set it globally
24 | # set :ssh_options, {
25 | # keys: %w(/home/rlisowski/.ssh/id_rsa),
26 | # forward_agent: false,
27 | # auth_methods: %w(password)
28 | # }
29 | # and/or per server
30 | # server 'example.com',
31 | # user: 'user_name',
32 | # roles: %w{web app},
33 | # ssh_options: {
34 | # user: 'user_name', # overrides user setting above
35 | # keys: %w(/home/user_name/.ssh/id_rsa),
36 | # forward_agent: false,
37 | # auth_methods: %w(publickey password)
38 | # # password: 'please use keys'
39 | # }
40 | # setting per server overrides global ssh_options
41 |
42 | # fetch(:default_env).merge!(rails_env: :staging)
43 |
--------------------------------------------------------------------------------
/config/environment.rb:
--------------------------------------------------------------------------------
1 | # Load the Rails application.
2 | require File.expand_path('../application', __FILE__)
3 |
4 | # Initialize the Rails application.
5 | T4c::Application.initialize!
6 |
--------------------------------------------------------------------------------
/config/environments/development.rb:
--------------------------------------------------------------------------------
1 | T4c::Application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # In the development environment your application's code is reloaded on
5 | # every request. This slows down response time but is perfect for development
6 | # since you don't have to restart the web server when you make code changes.
7 | config.cache_classes = false
8 |
9 | # Do not eager load code on boot.
10 | config.eager_load = false
11 |
12 | # Show full error reports and disable caching.
13 | config.consider_all_requests_local = true
14 | config.action_controller.perform_caching = false
15 |
16 | config.action_mailer.default_url_options = { :host => "localhost:3000" }
17 |
18 | config.action_mailer.delivery_method = :smtp
19 | config.action_mailer.smtp_settings = CONFIG['smtp_settings'].to_options
20 |
21 | config.action_mailer.perform_deliveries = true
22 | config.action_mailer.raise_delivery_errors = true
23 | config.action_mailer.default_options = {from: 'no-reply@' + CONFIG['smtp_settings']['domain'] }
24 |
25 | # Print deprecation notices to the Rails logger.
26 | config.active_support.deprecation = :log
27 |
28 | # Raise an error on page load if there are pending migrations
29 | config.active_record.migration_error = :page_load
30 |
31 | # Debug mode disables concatenation and preprocessing of assets.
32 | # This option may cause significant delays in view rendering with a large
33 | # number of complex assets.
34 | config.assets.debug = true
35 | end
36 |
--------------------------------------------------------------------------------
/config/environments/test.rb:
--------------------------------------------------------------------------------
1 | T4c::Application.configure do
2 | # Settings specified here will take precedence over those in config/application.rb.
3 |
4 | # The test environment is used exclusively to run your application's
5 | # test suite. You never need to work with it otherwise. Remember that
6 | # your test database is "scratch space" for the test suite and is wiped
7 | # and recreated between test runs. Don't rely on the data there!
8 | config.cache_classes = true
9 |
10 | # Do not eager load code on boot. This avoids loading your whole application
11 | # just for the purpose of running a single test. If you are using a tool that
12 | # preloads Rails for running tests, you may have to set it to true.
13 | config.eager_load = false
14 |
15 | # Configure static asset server for tests with Cache-Control for performance.
16 | config.serve_static_files = true
17 | config.static_cache_control = "public, max-age=3600"
18 |
19 | # Show full error reports and disable caching.
20 | config.consider_all_requests_local = true
21 | config.action_controller.perform_caching = false
22 |
23 | # Raise exceptions instead of rendering exception templates.
24 | config.action_dispatch.show_exceptions = false
25 |
26 | # Disable request forgery protection in test environment.
27 | config.action_controller.allow_forgery_protection = false
28 |
29 | # Tell Action Mailer not to deliver emails to the real world.
30 | # The :test delivery method accumulates sent emails in the
31 | # ActionMailer::Base.deliveries array.
32 | config.action_mailer.delivery_method = :test
33 |
34 | config.action_mailer.default_url_options = {host: "www.example.com"}
35 | config.action_mailer.default_options = {from: 'no-reply@example.com'}
36 |
37 | # Print deprecation notices to the stderr.
38 | config.active_support.deprecation = :stderr
39 | end
40 |
--------------------------------------------------------------------------------
/config/initializers/backtrace_silencers.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
5 |
6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7 | # Rails.backtrace_cleaner.remove_silencers!
8 |
--------------------------------------------------------------------------------
/config/initializers/cookies_serializer.rb:
--------------------------------------------------------------------------------
1 | Rails.application.config.action_dispatch.cookies_serializer = :hybrid
2 |
--------------------------------------------------------------------------------
/config/initializers/errbit.rb:
--------------------------------------------------------------------------------
1 | if CONFIG['airbrake']
2 | Airbrake.configure do |config|
3 | config.api_key = CONFIG['airbrake']['api_key']
4 | config.host = CONFIG['airbrake']['host']
5 | config.port = 80
6 | config.secure = config.port == 443
7 | end
8 | end
--------------------------------------------------------------------------------
/config/initializers/filter_parameter_logging.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Configure sensitive parameters which will be filtered from the log file.
4 | Rails.application.config.filter_parameters += [:password]
5 |
--------------------------------------------------------------------------------
/config/initializers/inflections.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new inflection rules using the following format. Inflections
4 | # are locale specific, and you may define rules for as many different
5 | # locales as you wish. All of these examples are active by default:
6 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
7 | # inflect.plural /^(ox)$/i, '\1en'
8 | # inflect.singular /^(ox)en/i, '\1'
9 | # inflect.irregular 'person', 'people'
10 | # inflect.uncountable %w( fish sheep )
11 | # end
12 |
13 | # These inflection rules are supported but not enabled by default:
14 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
15 | # inflect.acronym 'RESTful'
16 | # end
17 |
--------------------------------------------------------------------------------
/config/initializers/intercept_emails.rb:
--------------------------------------------------------------------------------
1 | if (SEND_ALL_EMAILS_TO = CONFIG["send_all_emails_to"]).present? and !Rails.env.test?
2 | class MailInterceptor
3 | def self.delivering_email(message)
4 | message.subject = "[#{CONFIG['smtp_settings']['domain']} to #{message.to.join(", ")}] #{message.subject}"
5 | message.to = SEND_ALL_EMAILS_TO
6 | end
7 | end
8 |
9 | ActionMailer::Base.register_interceptor(MailInterceptor)
10 | end
11 |
--------------------------------------------------------------------------------
/config/initializers/mime_types.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new mime types for use in respond_to blocks:
4 | # Mime::Type.register "text/richtext", :rtf
5 | # Mime::Type.register_alias "text/html", :iphone
6 |
--------------------------------------------------------------------------------
/config/initializers/record_changes.rb:
--------------------------------------------------------------------------------
1 | class ActiveRecord::Base
2 | def self.record_changes(options)
3 | has_many :record_changes, as: :record
4 |
5 | after_save do
6 | state = to_json(options)
7 | last_state = RecordChange.where(record: self).order(created_at: :desc).first.try(:raw_state)
8 | if state != last_state
9 | RecordChange.create!(record: self, raw_state: state)
10 | end
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/config/initializers/secret_token.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Your secret key is used for verifying the integrity of signed cookies.
4 | # If you change this key, all old signed cookies will become invalid!
5 |
6 | # Make sure the secret is at least 30 characters and all random,
7 | # no regular words or you'll be exposed to dictionary attacks.
8 | # You can use `rake secret` to generate a secure secret key.
9 |
10 | # Make sure your secret_key_base is kept private
11 | # if you're sharing your code publicly.
12 | T4c::Application.config.secret_key_base = CONFIG['application']['secret']
13 |
--------------------------------------------------------------------------------
/config/initializers/session_store.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | T4c::Application.config.session_store :cookie_store, key: '_t4c_session'
4 |
--------------------------------------------------------------------------------
/config/initializers/wrap_parameters.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # This file contains settings for ActionController::ParamsWrapper which
4 | # is enabled by default.
5 |
6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7 | ActiveSupport.on_load(:action_controller) do
8 | wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
9 | end
10 |
11 | # To enable root element in JSON for ActiveRecord objects.
12 | # ActiveSupport.on_load(:active_record) do
13 | # self.include_root_in_json = true
14 | # end
15 |
--------------------------------------------------------------------------------
/config/locales/en.bootstrap.yml:
--------------------------------------------------------------------------------
1 | # Sample localization file for English. Add more files in this directory for other locales.
2 | # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
3 |
4 | en:
5 | helpers:
6 | actions: "Actions"
7 | links:
8 | back: "Back"
9 | cancel: "Cancel"
10 | confirm: "Are you sure?"
11 | destroy: "Delete"
12 | new: "New"
13 | edit: "Edit"
14 | titles:
15 | edit: "Edit %{model}"
16 | save: "Save %{model}"
17 | new: "New %{model}"
18 | delete: "Delete %{model}"
19 |
--------------------------------------------------------------------------------
/config/locales/en.yml:
--------------------------------------------------------------------------------
1 | # Files in the config/locales directory are used for internationalization
2 | # and are automatically loaded by Rails. If you want to use locales other
3 | # than English, add the necessary files in this directory.
4 | #
5 | # To use the locales, use `I18n.t`:
6 | #
7 | # I18n.t 'hello'
8 | #
9 | # In views, this is aliased to just `t`:
10 | #
11 | # <%= t('hello') %>
12 | #
13 | # To use a different locale, set it with `I18n.locale`:
14 | #
15 | # I18n.locale = :es
16 | #
17 | # This would use the information in config/locales/es.yml.
18 | #
19 | # To learn more, please read the Rails Internationalization guide
20 | # available at http://guides.rubyonrails.org/i18n.html.
21 |
22 | en:
23 | hello: "Hello world"
24 |
25 | activerecord:
26 | attributes:
27 | user:
28 | bitcoin_address: Peercoin address
29 | project:
30 | github_url: GitHub URL
31 | detailed_description: Detailed description
32 | tip:
33 | coin_amount: Amount
34 | description: Comment
35 | _destroy: Remove
36 |
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 | T4c::Application.routes.draw do
2 | mount Commontator::Engine => '/commontator'
3 |
4 | root 'home#index'
5 |
6 | get 'audit' => 'home#audit'
7 | get 'faq' => 'home#faq'
8 |
9 | devise_for :users,
10 | controllers: {
11 | omniauth_callbacks: "users/omniauth_callbacks",
12 | registrations: "registrations",
13 | }
14 |
15 | resources :users, :only => [:show, :update, :index] do
16 | collection do
17 | get :login
18 | get :suggestions
19 | end
20 | member do
21 | post :send_tips_back
22 | get :set_password_and_address
23 | patch :set_password_and_address
24 | end
25 | end
26 | resources :projects, :only => [:new, :show, :index, :create, :edit, :update] do
27 | resources :tips, :only => [:index]
28 | resources :distributions, :only => [:new, :create, :show, :index, :edit, :update] do
29 | get :new_recipient_form, on: :collection
30 | post :send_transaction, on: :member
31 | end
32 | member do
33 | get :qrcode
34 | get :decide_tip_amounts
35 | patch :decide_tip_amounts
36 | get :commit_suggestions
37 | get :github_user_suggestions
38 | get :donate
39 | post :donate
40 | get :donors
41 | end
42 | end
43 | resources :tips, :only => [:index]
44 | resources :distributions, :only => [:index]
45 | end
46 |
--------------------------------------------------------------------------------
/config/schedule.rb:
--------------------------------------------------------------------------------
1 | # Use this file to easily define all of your cron jobs.
2 | #
3 | # It's helpful, but not entirely necessary to understand cron before proceeding.
4 | # http://en.wikipedia.org/wiki/Cron
5 |
6 | # Example:
7 | #
8 | # set :output, "/path/to/my/cron_log.log"
9 | #
10 | # every 2.hours do
11 | # command "/usr/bin/some_great_command"
12 | # runner "MyModel.some_method"
13 | # rake "some:great:rake:task"
14 | # end
15 | #
16 | # every 4.days do
17 | # runner "AnotherModel.prune_old_records"
18 | # end
19 |
20 | # Learn more: http://github.com/javan/whenever
21 |
22 | require File.expand_path('../../config/environment', __FILE__)
23 | every :reboot do
24 | if daemon = CONFIG['daemon']['path']
25 | command daemon
26 | end
27 | end
28 |
29 | if delay = CONFIG['tipper_delay']
30 | delay = eval(delay)
31 | every delay do
32 | runner "BalanceUpdater.work; BitcoinTipper.work; BalanceUpdater.work"
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/db/migrate/20131019133109_devise_create_users.rb:
--------------------------------------------------------------------------------
1 | class DeviseCreateUsers < ActiveRecord::Migration
2 | def change
3 | create_table(:users) do |t|
4 | ## Database authenticatable
5 | t.string :email, :null => false, :default => ""
6 | t.string :encrypted_password, :null => false, :default => ""
7 |
8 | ## Recoverable
9 | t.string :reset_password_token
10 | t.datetime :reset_password_sent_at
11 |
12 | ## Rememberable
13 | t.datetime :remember_created_at
14 |
15 | ## Trackable
16 | t.integer :sign_in_count, :default => 0, :null => false
17 | t.datetime :current_sign_in_at
18 | t.datetime :last_sign_in_at
19 | t.string :current_sign_in_ip
20 | t.string :last_sign_in_ip
21 |
22 | ## Confirmable
23 | # t.string :confirmation_token
24 | # t.datetime :confirmed_at
25 | # t.datetime :confirmation_sent_at
26 | # t.string :unconfirmed_email # Only if using reconfirmable
27 |
28 | ## Lockable
29 | # t.integer :failed_attempts, :default => 0, :null => false # Only if lock strategy is :failed_attempts
30 | # t.string :unlock_token # Only if unlock strategy is :email or :both
31 | # t.datetime :locked_at
32 |
33 |
34 | t.timestamps
35 | end
36 |
37 | add_index :users, :email, :unique => true
38 | add_index :users, :reset_password_token, :unique => true
39 | # add_index :users, :confirmation_token, :unique => true
40 | # add_index :users, :unlock_token, :unique => true
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/db/migrate/20131019133235_add_columns_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddColumnsToUsers < ActiveRecord::Migration
2 | def change
3 | add_column :users, :nickname, :string
4 | add_column :users, :name, :string
5 | add_column :users, :image, :string
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/db/migrate/20131019144930_add_bitcoin_address_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddBitcoinAddressToUsers < ActiveRecord::Migration
2 | def change
3 | add_column :users, :bitcoin_address, :string
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20131019164745_create_projects.rb:
--------------------------------------------------------------------------------
1 | class CreateProjects < ActiveRecord::Migration
2 | def change
3 | create_table :projects do |t|
4 | t.string :url
5 | t.string :bitcoin_address
6 |
7 | t.timestamps
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/db/migrate/20131019170122_create_deposits.rb:
--------------------------------------------------------------------------------
1 | class CreateDeposits < ActiveRecord::Migration
2 | def change
3 | create_table :deposits do |t|
4 | t.references :project, index: true
5 | t.string :txid
6 | t.integer :confirmations
7 | t.integer :duration, :default => 30.days.to_i
8 | t.integer :paid_out, :limit => 8
9 | t.datetime :paid_out_at
10 |
11 | t.timestamps
12 | end
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/db/migrate/20131019170659_create_sendmanies.rb:
--------------------------------------------------------------------------------
1 | class CreateSendmanies < ActiveRecord::Migration
2 | def change
3 | create_table :sendmanies do |t|
4 | t.string :txid
5 | t.text :data
6 | t.string :result
7 | t.boolean :is_error
8 |
9 | t.timestamps
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/db/migrate/20131019170925_create_tips.rb:
--------------------------------------------------------------------------------
1 | class CreateTips < ActiveRecord::Migration
2 | def change
3 | create_table :tips do |t|
4 | t.references :deposit, index: true
5 | t.references :user, index: true
6 | t.integer :amount, :limit => 8
7 | t.references :sendmany, index: true
8 | t.boolean :is_refunded
9 |
10 | t.timestamps
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/db/migrate/20131019175751_add_some_fields_to_projects.rb:
--------------------------------------------------------------------------------
1 | class AddSomeFieldsToProjects < ActiveRecord::Migration
2 | def change
3 | add_column :projects, :name, :string
4 | add_column :projects, :full_name, :string
5 | add_column :projects, :source_full_name, :string
6 | add_column :projects, :description, :string
7 | add_column :projects, :watchers_count, :integer
8 | add_column :projects, :language, :string
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/db/migrate/20131019205025_add_amount_to_deposit.rb:
--------------------------------------------------------------------------------
1 | class AddAmountToDeposit < ActiveRecord::Migration
2 | def change
3 | add_column :deposits, :amount, :integer, :limit => 8
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20131019211518_add_last_commit_to_projects.rb:
--------------------------------------------------------------------------------
1 | class AddLastCommitToProjects < ActiveRecord::Migration
2 | def change
3 | add_column :projects, :last_commit, :string
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20131020003746_add_commit_to_tip.rb:
--------------------------------------------------------------------------------
1 | class AddCommitToTip < ActiveRecord::Migration
2 | def change
3 | add_column :tips, :commit, :string
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20131020120722_add_login_token_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddLoginTokenToUsers < ActiveRecord::Migration
2 | def change
3 | add_column :users, :login_token, :string
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20131020143021_add_unsubscribed_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddUnsubscribedToUsers < ActiveRecord::Migration
2 | def change
3 | add_column :users, :unsubscribed, :boolean
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20131020145043_add_notified_at_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddNotifiedAtToUsers < ActiveRecord::Migration
2 | def change
3 | add_column :users, :notified_at, :datetime
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20131030142320_add_project_to_tip.rb:
--------------------------------------------------------------------------------
1 | class AddProjectToTip < ActiveRecord::Migration
2 | def change
3 | add_reference :tips, :project, index: true
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20131030142749_drop_deposit_from_tip.rb:
--------------------------------------------------------------------------------
1 | class DropDepositFromTip < ActiveRecord::Migration
2 | def change
3 | remove_column :tips, :deposit_id
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20131030191346_add_available_amount_cache_to_projects.rb:
--------------------------------------------------------------------------------
1 | class AddAvailableAmountCacheToProjects < ActiveRecord::Migration
2 | def change
3 | add_column :projects, :available_amount_cache, :integer
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20131212190037_add_cache_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddCacheToUsers < ActiveRecord::Migration
2 | def change
3 | add_column :users, :commits_count, :integer, default: 0
4 | add_column :users, :withdrawn_amount, :integer, limit: 8, default: 0
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/db/migrate/20140102095035_add_refunded_at_to_tips.rb:
--------------------------------------------------------------------------------
1 | class AddRefundedAtToTips < ActiveRecord::Migration
2 | def change
3 | add_column :tips, :refunded_at, :timestamp
4 | remove_column :tips, :is_refunded, :boolean
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/db/migrate/20140207061855_add_github_id_to_projects.rb:
--------------------------------------------------------------------------------
1 | class AddGithubIdToProjects < ActiveRecord::Migration
2 | def change
3 | add_column :projects, :github_id, :string
4 | end
5 | end
--------------------------------------------------------------------------------
/db/migrate/20140209022632_change_projects_description.rb:
--------------------------------------------------------------------------------
1 | class ChangeProjectsDescription < ActiveRecord::Migration
2 | def up
3 | change_column :projects, :description, :text, :limit => nil
4 | end
5 | def down
6 | change_column :projects, :description, :string
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/db/migrate/20140209041123_create_indexes_for_projects.rb:
--------------------------------------------------------------------------------
1 | class CreateIndexesForProjects < ActiveRecord::Migration
2 | def change
3 | add_index :projects, :full_name, :unique => true
4 | add_index :projects, :github_id, :unique => true
5 | end
6 | end
--------------------------------------------------------------------------------
/db/migrate/20140215062842_add_project_to_sendmany.rb:
--------------------------------------------------------------------------------
1 | class AddProjectToSendmany < ActiveRecord::Migration
2 | def change
3 | add_column :sendmanies, :project_id, :integer
4 | add_index :sendmanies, :project_id
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/db/migrate/20140215094135_add_addres_label_to_project.rb:
--------------------------------------------------------------------------------
1 | class AddAddresLabelToProject < ActiveRecord::Migration
2 | def change
3 | add_column :projects, :address_label, :string
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20140215094549_initialize_project_address_label.rb:
--------------------------------------------------------------------------------
1 | class InitializeProjectAddressLabel < ActiveRecord::Migration
2 | def up
3 | execute "UPDATE projects SET address_label=(full_name || '@peer4commit') WHERE address_label IS NULL"
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20140309161105_change_project_amount_cache_to_big_int.rb:
--------------------------------------------------------------------------------
1 | class ChangeProjectAmountCacheToBigInt < ActiveRecord::Migration
2 | def change
3 | change_column :projects, :available_amount_cache, :integer, limit: 8
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20140309192616_create_collaborators.rb:
--------------------------------------------------------------------------------
1 | class CreateCollaborators < ActiveRecord::Migration
2 | def change
3 | create_table :collaborators do |t|
4 | t.belongs_to :project, index: true
5 | t.string :login
6 |
7 | t.timestamps
8 | end
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/db/migrate/20140323072851_add_hold_tips_to_project.rb:
--------------------------------------------------------------------------------
1 | class AddHoldTipsToProject < ActiveRecord::Migration
2 | def change
3 | add_column :projects, :hold_tips, :boolean, default: false
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20140323165816_add_commit_message_to_tip.rb:
--------------------------------------------------------------------------------
1 | class AddCommitMessageToTip < ActiveRecord::Migration
2 | def change
3 | add_column :tips, :commit_message, :string
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20140323173320_create_tipping_policies_texts.rb:
--------------------------------------------------------------------------------
1 | class CreateTippingPoliciesTexts < ActiveRecord::Migration
2 | def change
3 | create_table :tipping_policies_texts do |t|
4 | t.belongs_to :project, index: true
5 | t.belongs_to :user, index: true
6 | t.text :text
7 |
8 | t.timestamps
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20140330165138_create_cold_storage_transfers.rb:
--------------------------------------------------------------------------------
1 | class CreateColdStorageTransfers < ActiveRecord::Migration
2 | def change
3 | create_table :cold_storage_transfers do |t|
4 | t.belongs_to :project, index: true
5 | t.integer :amount, limit: 8
6 | t.string :address
7 | t.string :txid
8 | t.integer :confirmations
9 |
10 | t.timestamps
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/db/migrate/20140401174927_add_cold_storage_withdrawal_address_to_project.rb:
--------------------------------------------------------------------------------
1 | class AddColdStorageWithdrawalAddressToProject < ActiveRecord::Migration
2 | def change
3 | add_column :projects, :cold_storage_withdrawal_address, :string
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20140402111051_add_disabled_to_project.rb:
--------------------------------------------------------------------------------
1 | class AddDisabledToProject < ActiveRecord::Migration
2 | def change
3 | add_column :projects, :disabled, :boolean, default: false
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20140403062826_add_account_balance_to_project.rb:
--------------------------------------------------------------------------------
1 | class AddAccountBalanceToProject < ActiveRecord::Migration
2 | def change
3 | add_column :projects, :account_balance, :integer, limit: 8
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20140405084351_add_disabled_reason_to_project.rb:
--------------------------------------------------------------------------------
1 | class AddDisabledReasonToProject < ActiveRecord::Migration
2 | def change
3 | add_column :projects, :disabled_reason, :string
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20140406064344_add_fee_to_sendmany.rb:
--------------------------------------------------------------------------------
1 | class AddFeeToSendmany < ActiveRecord::Migration
2 | def change
3 | add_column :sendmanies, :fee, :integer
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20140406071705_add_fee_to_cold_storage_transfer.rb:
--------------------------------------------------------------------------------
1 | class AddFeeToColdStorageTransfer < ActiveRecord::Migration
2 | def change
3 | add_column :cold_storage_transfers, :fee, :integer
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20140529135156_add_detailed_descrition_to_project.rb:
--------------------------------------------------------------------------------
1 | class AddDetailedDescritionToProject < ActiveRecord::Migration
2 | def change
3 | add_column :projects, :detailed_description, :text
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20140530132209_rename_sendmany_to_distribution.rb:
--------------------------------------------------------------------------------
1 | class RenameSendmanyToDistribution < ActiveRecord::Migration
2 | def change
3 | rename_table :sendmanies, :distributions
4 | rename_column :tips, :sendmany_id, :distribution_id
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/db/migrate/20140531080839_add_sent_at_to_distribution.rb:
--------------------------------------------------------------------------------
1 | class AddSentAtToDistribution < ActiveRecord::Migration
2 | def change
3 | add_column :distributions, :sent_at, :datetime
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20140601072522_add_devise_confirmable.rb:
--------------------------------------------------------------------------------
1 | class AddDeviseConfirmable < ActiveRecord::Migration
2 | def change
3 | change_table :users do |t|
4 | t.string :confirmation_token
5 | t.datetime :confirmed_at
6 | t.datetime :confirmation_sent_at
7 | t.string :unconfirmed_email
8 | end
9 |
10 | # Existing users with a GitHub nickname are confirmed
11 | execute "UPDATE users SET confirmed_at='#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}' WHERE nickname IS NOT NULL"
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/db/migrate/20140601103950_new_default_to_hold_tips.rb:
--------------------------------------------------------------------------------
1 | class NewDefaultToHoldTips < ActiveRecord::Migration
2 | def change
3 | change_column :projects, :hold_tips, :boolean, default: true
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20140601104108_remove_unique_constraint_to_project_full_name.rb:
--------------------------------------------------------------------------------
1 | class RemoveUniqueConstraintToProjectFullName < ActiveRecord::Migration
2 | def up
3 | remove_index "projects", "full_name"
4 | end
5 |
6 | def down
7 | add_index "projects", ["full_name"], name: "index_projects_on_full_name", unique: true
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/db/migrate/20140601144116_add_comment_to_tip.rb:
--------------------------------------------------------------------------------
1 | class AddCommentToTip < ActiveRecord::Migration
2 | def change
3 | add_column :tips, :comment, :string
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20140601145337_create_versions.rb:
--------------------------------------------------------------------------------
1 | class CreateVersions < ActiveRecord::Migration
2 | def change
3 | create_table :versions do |t|
4 | t.string :item_type, :null => false
5 | t.integer :item_id, :null => false
6 | t.string :event, :null => false
7 | t.string :whodunnit
8 | t.text :object
9 | t.datetime :created_at
10 | end
11 | add_index :versions, [:item_type, :item_id]
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/db/migrate/20140601145338_add_object_changes_to_versions.rb:
--------------------------------------------------------------------------------
1 | class AddObjectChangesToVersions < ActiveRecord::Migration
2 | def change
3 | add_column :versions, :object_changes, :text
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20140602210025_create_commits.rb:
--------------------------------------------------------------------------------
1 | class CreateCommits < ActiveRecord::Migration
2 | def change
3 | create_table :commits do |t|
4 | t.belongs_to :project, index: true
5 | t.string :sha
6 | t.text :message
7 | t.string :username
8 | t.string :email
9 |
10 | t.timestamps
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/db/migrate/20140607100342_add_origin_to_tip.rb:
--------------------------------------------------------------------------------
1 | class AddOriginToTip < ActiveRecord::Migration
2 | def change
3 | add_reference :tips, :origin, index: true, polymorphic: true
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20140608120038_install_commontator.commontator.rb:
--------------------------------------------------------------------------------
1 | # This migration comes from commontator (originally 0)
2 | class InstallCommontator < ActiveRecord::Migration
3 | def change
4 | create_table 'commontator_comments' do |t|
5 | t.string 'creator_type'
6 | t.integer 'creator_id'
7 | t.string 'editor_type'
8 | t.integer 'editor_id'
9 | t.integer 'thread_id', :null => false
10 | t.text 'body', :null => false
11 | t.datetime 'deleted_at'
12 |
13 | t.integer :cached_votes_up, :default => 0
14 | t.integer :cached_votes_down, :default => 0
15 |
16 | t.timestamps
17 | end
18 |
19 | add_index :commontator_comments, [:creator_id, :creator_type, :thread_id], :name => 'index_commontator_comments_on_c_id_and_c_type_and_t_id'
20 | add_index :commontator_comments, :thread_id
21 |
22 | add_index :commontator_comments, :cached_votes_up
23 | add_index :commontator_comments, :cached_votes_down
24 |
25 | create_table 'commontator_subscriptions' do |t|
26 | t.string 'subscriber_type', :null => false
27 | t.integer 'subscriber_id', :null => false
28 | t.integer 'thread_id', :null => false
29 |
30 | t.timestamps
31 | end
32 |
33 | add_index :commontator_subscriptions, [:subscriber_id, :subscriber_type, :thread_id], :unique => true, :name => 'index_commontator_subscriptions_on_s_id_and_s_type_and_t_id'
34 | add_index :commontator_subscriptions, :thread_id
35 |
36 | create_table 'commontator_threads' do |t|
37 | t.string 'commontable_type'
38 | t.integer 'commontable_id'
39 | t.datetime 'closed_at'
40 | t.string 'closer_type'
41 | t.integer 'closer_id'
42 |
43 | t.timestamps
44 | end
45 |
46 | add_index :commontator_threads, [:commontable_id, :commontable_type], :unique => true, :name => 'index_commontator_threads_on_c_id_and_c_type'
47 | end
48 | end
49 |
50 |
--------------------------------------------------------------------------------
/db/migrate/20140608131519_rename_origin_to_reason.rb:
--------------------------------------------------------------------------------
1 | class RenameOriginToReason < ActiveRecord::Migration
2 | def change
3 | rename_column :tips, :origin_type, :reason_type
4 | rename_column :tips, :origin_id, :reason_id
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/db/migrate/20140609122234_drop_version.rb:
--------------------------------------------------------------------------------
1 | class DropVersion < ActiveRecord::Migration
2 | def change
3 | drop_table :versions
4 | end
5 |
6 | def down
7 | create_table "versions", force: true do |t|
8 | t.string "item_type", null: false
9 | t.integer "item_id", null: false
10 | t.string "event", null: false
11 | t.string "whodunnit"
12 | t.text "object"
13 | t.datetime "created_at"
14 | t.text "object_changes"
15 | end
16 |
17 | add_index "versions", ["item_type", "item_id"], name: "index_versions_on_item_type_and_item_id"
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/db/migrate/20140609122440_create_record_changes.rb:
--------------------------------------------------------------------------------
1 | class CreateRecordChanges < ActiveRecord::Migration
2 | def change
3 | create_table :record_changes do |t|
4 | t.belongs_to :record, index: true, polymorphic: true
5 | t.belongs_to :user
6 | t.text :raw_state, limit: 1.megabyte
7 |
8 | t.timestamps
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20140615122107_create_donation_addresses.rb:
--------------------------------------------------------------------------------
1 | class CreateDonationAddresses < ActiveRecord::Migration
2 | def change
3 | create_table :donation_addresses do |t|
4 | t.belongs_to :project, index: true
5 | t.string :sender_address
6 | t.string :donation_address
7 |
8 | t.timestamps
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/db/migrate/20140615124857_add_donation_address_to_deposit.rb:
--------------------------------------------------------------------------------
1 | class AddDonationAddressToDeposit < ActiveRecord::Migration
2 | def change
3 | add_reference :deposits, :donation_address, index: true
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20140616055815_add_user_to_collaborator.rb:
--------------------------------------------------------------------------------
1 | class AddUserToCollaborator < ActiveRecord::Migration
2 | def change
3 | add_reference :collaborators, :user, index: true
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20140616060504_convert_collaborator_nick_names_to_user.rb:
--------------------------------------------------------------------------------
1 | class ConvertCollaboratorNickNamesToUser < ActiveRecord::Migration
2 | def up
3 | execute("UPDATE collaborators SET user_id = (SELECT id FROM users WHERE users.nickname = collaborators.login LIMIT 1)")
4 | end
5 |
6 | def down
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/db/migrate/20140704060602_add_disabled_to_user.rb:
--------------------------------------------------------------------------------
1 | class AddDisabledToUser < ActiveRecord::Migration
2 | def change
3 | add_column :users, :disabled, :boolean, default: false
4 | add_index :users, :disabled
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/db/migrate/20140706075813_remove_git_hub_id_from_project.rb:
--------------------------------------------------------------------------------
1 | class RemoveGitHubIdFromProject < ActiveRecord::Migration
2 | def change
3 | remove_column :projects, :github_id, :string
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20140714074128_add_identifier_to_user.rb:
--------------------------------------------------------------------------------
1 | class AddIdentifierToUser < ActiveRecord::Migration
2 | def up
3 | add_column :users, :identifier, :string
4 | execute("SELECT id FROM users WHERE identifier IS NULL").each do |row|
5 | id = row["id"]
6 | charset = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'.split(//)
7 | identifier = (0...12).map { charset.sample }.join
8 | execute "UPDATE users SET identifier='#{identifier}' WHERE id = #{id}"
9 | end
10 | change_column :users, :identifier, :string, null: false
11 | add_index :users, :identifier, unique: true
12 | end
13 |
14 | def down
15 | remove_column :users, :identifier
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/db/migrate/20180121184454_add_stake_mint_to_project.rb:
--------------------------------------------------------------------------------
1 | class AddStakeMintToProject < ActiveRecord::Migration
2 | def change
3 | add_column :projects, :stake_mint_amount, :integer, limit: 8
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/seeds.rb:
--------------------------------------------------------------------------------
1 | # This file should contain all the record creation needed to seed the database with its default values.
2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
3 | #
4 | # Examples:
5 | #
6 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
7 | # Mayor.create(name: 'Emanuel', city: cities.first)
8 |
--------------------------------------------------------------------------------
/features/change_github.feature:
--------------------------------------------------------------------------------
1 | Feature: Fundraiser can change the GitHub repository linked to a project
2 | Scenario: A project not holding tips changes github repository
3 | Given a project
4 | And the project does not hold tips
5 | And the project GitHub name is "foo/bar"
6 | And the commits on GitHub for project "foo/bar" are
7 | | sha | author | email |
8 | | 123 | bob | bobby@example.com |
9 | | abc | alice | alicia@example.com |
10 | | 333 | bob | bobby@example.com |
11 | And our fee is "0"
12 | And a deposit of "500"
13 | Given a GitHub user "bob" who has set his address to "mxWfjaZJTNN5QKeZZYQ5HW3vgALFBsnuG1"
14 | And a GitHub user "alice" who has set his address to "mi9SLroAgc8eUNuLwnZmdyqWdShbNtvr3n"
15 |
16 | When the project tips are built from commits
17 | Then the project should have these tips:
18 | | commit | amount |
19 | | 123 | 5.0 |
20 | | abc | 4.95 |
21 | | 333 | 4.9005 |
22 |
23 | When the project GitHub name is "baz/foo"
24 | And the commits on GitHub for project "baz/foo" are
25 | | sha | author | email |
26 | | aaa | bob | bobby@example.com |
27 | | bbb | alice | alicia@example.com |
28 | | ccc | bob | bobby@example.com |
29 | And the project tips are built from commits
30 | Then the project should have these tips:
31 | | commit | amount |
32 | | 123 | 5.0 |
33 | | abc | 4.95 |
34 | | 333 | 4.9005 |
35 | | aaa | 4.851495 |
36 | | bbb | 4.802981 |
37 | | ccc | 4.754951 |
38 |
39 |
--------------------------------------------------------------------------------
/features/cold_storage.feature:
--------------------------------------------------------------------------------
1 | Feature: Some funds are transfered to cold storage
2 | Background:
3 | Given a project
4 | And our fee is "0.01"
5 | And the project address is "mqEtf1CcGtAmoVRHENBVmBRpYppoEcA8LH"
6 | And the project cold storage withdrawal address is "n1g6mxaEpMb6cERcS4bGhmJPjxKc3msvni"
7 | And the cold storage addresses are
8 | | mpjDVmvCgsi2WW9qZJDQN6WgpDTP5iGbpD |
9 | | mr6HkUBp3iUqH6JuvD33banN4vZkifvTGD |
10 |
11 | Scenario: A project receives funds to its non cold storage address
12 | When there's a new incoming transaction of "50" to address "mqEtf1CcGtAmoVRHENBVmBRpYppoEcA8LH" on the project account
13 | And the project balance is updated
14 | Then the project balance should be "49.5"
15 | And the project amount in cold storage should be "0"
16 |
17 | Scenario: A project receives funds to its cold storage address
18 | When there's a new incoming transaction of "50" to address "n1g6mxaEpMb6cERcS4bGhmJPjxKc3msvni" on the project account
19 | And the project balance is updated
20 | Then the project balance should be "0"
21 | And the project amount in cold storage should be "-50"
22 |
23 | Scenario: A project receives funds to an unknown address
24 | When there's a new incoming transaction of "50" to address "mmoS6KKr4Q4v6VQcTQmSWGPgBS8mhJ9f74" on the project account
25 | Then updating the project balance should raise an error
26 | And the project balance should be "0"
27 | And the project amount in cold storage should be "0"
28 |
29 | Scenario: Some funds are sent to cold storage
30 | When there's a new outgoing transaction of "50" to address "mpjDVmvCgsi2WW9qZJDQN6WgpDTP5iGbpD" on the project account
31 | And the project balance is updated
32 | Then the project balance should be "0"
33 | And the project amount in cold storage should be "50"
34 |
35 | Scenario: Unconfirmed transactions are not counted
36 | When there's a new incoming transaction of "50" to address "mqEtf1CcGtAmoVRHENBVmBRpYppoEcA8LH" on the project account with 0 confirmations
37 | And there's a new incoming transaction of "10" to address "n1g6mxaEpMb6cERcS4bGhmJPjxKc3msvni" on the project account with 0 confirmations
38 | And there's a new outgoing transaction of "20" to address "mpjDVmvCgsi2WW9qZJDQN6WgpDTP5iGbpD" on the project account with 0 confirmations
39 | And the project balance is updated
40 | Then the project balance should be "0"
41 | And the project amount in cold storage should be "0"
42 |
43 | Scenario: Sending funds to cold storage
44 | When "50" coins of the project funds are sent to cold storage
45 | Then there should be an outgoing transaction of "50" to address "mpjDVmvCgsi2WW9qZJDQN6WgpDTP5iGbpD" on the project account
46 |
47 | Scenario: Cold storage withdrawal address is created at balance update time if it doesn't exist
48 | Given the project has no cold storage withdrawal address
49 | When the project balance is updated
50 | Then the project should have a cold storage withdrawal address
51 | And the project cold storage withdrawal address should be linked to its account
52 |
--------------------------------------------------------------------------------
/features/commit_from_known_nickname.feature:
--------------------------------------------------------------------------------
1 | Feature: A commit with an identified GitHub nickname should be sent to the right user if he exists
2 | Scenario:
3 | Given a project "a"
4 | And our fee is "0"
5 | And a deposit of "500"
6 | And an user "yugo"
7 | And the email of "yugo" is "yugo1@example.com"
8 | And the last known commit is "A"
9 | And a new commit "B" with parent "A"
10 | And the author of commit "B" is "yugo"
11 | And the email of commit "B" is "yugo2@example.com"
12 |
13 | When the new commits are read
14 | Then there should be a tip of "5" for commit "B"
15 | And the tip for commit "B" is for user "yugo"
16 | And there should be no user with email "yugo2@example.com"
17 |
--------------------------------------------------------------------------------
/features/distribute_to_user_identifier.feature:
--------------------------------------------------------------------------------
1 | Feature: Distribute funds to an user identifier
2 |
3 | @javascript
4 | Scenario:
5 | Given an user with email "bob@example.com"
6 | And the user with email "bob@example.com" has set his address to "mi9SLroAgc8eUNuLwnZmdyqWdShbNtvr3n"
7 |
8 | Given a project managed by "alice"
9 | And our fee is "0"
10 | And a deposit of "500"
11 |
12 | Given I'm logged in as "alice"
13 | And I go to the project page
14 | And I click on "New distribution"
15 | And I add the user with email "bob@example.com" through his identifier to the recipients
16 | And I fill the amount to "
" with "10"
17 | And I save the distribution
18 |
19 | Then I should see these distribution lines:
20 | | recipient | address | amount | percentage |
21 | | | mi9SLroAgc8eUNuLwnZmdyqWdShbNtvr3n | 10 | 100.0 |
22 |
23 | When I click on "Send the transaction"
24 | Then I should see "Transaction sent"
25 | And these amounts should have been sent from the account of the project:
26 | | address | amount |
27 | | mi9SLroAgc8eUNuLwnZmdyqWdShbNtvr3n | 10.0 |
28 | And the project balance should be "490.00"
29 |
--------------------------------------------------------------------------------
/features/donate_to_project.feature:
--------------------------------------------------------------------------------
1 | Feature: A visitor can donate to a project
2 | Background:
3 | Given a project
4 | And our fee is "0.01"
5 |
6 | Scenario: A visitor sends coins to a project
7 | When I visit the project page
8 | And I click on "Donate"
9 | And I fill "Return address" with "mmGen7mZTGi9bciEaEa2W1DLsx3HjaFvcd"
10 | And I click on "Generate my donation address"
11 | Then I should see the project donation address associated with "mmGen7mZTGi9bciEaEa2W1DLsx3HjaFvcd"
12 |
13 | Given there's a new incoming transaction of "50" to the donation address associated with "mmGen7mZTGi9bciEaEa2W1DLsx3HjaFvcd"
14 | And the project balance is updated
15 |
16 | When I visit the project page
17 | Then I should see the project balance is "49.5"
18 |
19 | When I click on "List of donors"
20 | Then I should see the donor "mmGen7mZTGi9bciEaEa2W1DLsx3HjaFvcd" sent "50"
21 |
22 | Scenario: Sending twice with the same return address
23 | Given the project has a donation address "mfbDMySWmo4p31waWE4bUGFqK47V4comdq" associated with "mpbkNzunFtBmu3JYENE62UTLtKyvwrSUfx"
24 | When I visit the project page
25 | And I click on "Donate"
26 | And I fill "Return address" with "mpbkNzunFtBmu3JYENE62UTLtKyvwrSUfx"
27 | And I click on "Generate my donation address"
28 | Then I should see "mfbDMySWmo4p31waWE4bUGFqK47V4comdq"
29 |
30 | Scenario: Sending with an invalid return address
31 | When I visit the project page
32 | And I click on "Donate"
33 | And I click on "Generate my donation address"
34 | Then I should see "can't be blank"
35 | When I fill "Return address" with "mpbkNzunFtBmu3JYENE62UTLtKyvwrSUfy"
36 | And I click on "Generate my donation address"
37 | Then I should see "invalid"
38 |
39 | Scenario: Sending without a return address
40 | When I visit the project page
41 | And I click on "Donate"
42 | Then I should see the project donation address
43 |
44 | Given there's a new incoming transaction of "50" to the project donation address
45 | And the project balance is updated
46 |
47 | When I visit the project page
48 | Then I should see the project balance is "49.5"
49 |
50 | When I click on "List of donors"
51 | Then I should see the donor "No address provided" sent "50"
52 |
53 | Scenario: Multiple donations in a single transaction
54 | Given a project "A" with a donation address "mpD1oHHQqAWWrrfxzAg1gEWbHh2teQjYsU" associated with "mpR1otQoiJo8dfXzxyTmvPLg42n7RFJMMh"
55 | And a project "B" with a donation address "mpD2oDRevAtG5Q24jRQx1GKpaZfxM8wh3y" associated with "mpR1otQoiJo8dfXzxyTmvPLg42n7RFJMMh"
56 | And there's a new incoming transaction of "50" to "mpD1oHHQqAWWrrfxzAg1gEWbHh2teQjYsU" in transaction "tx1"
57 | And there's a new incoming transaction of "75" to "mpD2oDRevAtG5Q24jRQx1GKpaZfxM8wh3y" in transaction "tx1"
58 | And the project balances are updated
59 |
60 | When I visit the project "A" page
61 | Then I should see the project balance is "49.50"
62 |
63 | When I click on "List of donors"
64 | Then I should see the donor "mpR1otQoiJo8dfXzxyTmvPLg42n7RFJMMh" sent "50"
65 |
66 | When I visit the project "B" page
67 | Then I should see the project balance is "74.25"
68 |
69 | When I click on "List of donors"
70 | Then I should see the donor "mpR1otQoiJo8dfXzxyTmvPLg42n7RFJMMh" sent "75"
71 |
--------------------------------------------------------------------------------
/features/project_detailed_description.feature:
--------------------------------------------------------------------------------
1 | Feature: Project detailed description is markdown formatted
2 | Background:
3 | Given a project
4 | And the project single collaborator is "bob"
5 | And I'm logged in as "bob"
6 | And I go to the project page
7 | And I click on "Edit project"
8 |
9 | Scenario: Standard markdown
10 | When I fill "Detailed description" with:
11 | """
12 | foo [bar](http://foo.example.com/)
13 | """
14 | And I click on "Save"
15 | Then I should see a link "bar" to "http://foo.example.com/"
16 |
17 | Scenario: XSS attempt
18 | When I fill "Detailed description" with:
19 | """
20 | foo [bar](javascript:alert('xss'))
21 | """
22 | And I click on "Save"
23 | Then I should not see a link "bar" to "javascript:alert('xss')"
24 |
25 | Scenario: Embeded HTML
26 | When I fill "Detailed description" with:
27 | """
28 | foo bar
29 | """
30 | And I click on "Save"
31 | Then I should not see a link "bar" to "javascript:alert('xss')"
32 |
33 | Scenario: Inline external image
34 | When I fill "Detailed description" with:
35 | """
36 | 
37 | """
38 | And I click on "Save"
39 | Then I should not see the image "http://example.com/img.jpg"
40 |
41 |
--------------------------------------------------------------------------------
/features/step_definitions/cold_storage.rb:
--------------------------------------------------------------------------------
1 | Given(/^the cold storage addresses are$/) do |table|
2 | CONFIG["cold_storage"] ||= {}
3 | CONFIG["cold_storage"]["addresses"] = table.raw.map(&:first)
4 | end
5 |
6 | Given(/^the project address is "(.*?)"$/) do |arg1|
7 | @project.update(bitcoin_address: arg1)
8 | end
9 |
10 | Given(/^the project cold storage withdrawal address is "(.*?)"$/) do |arg1|
11 | @project.update(cold_storage_withdrawal_address: arg1)
12 | end
13 |
14 | When(/^there's a new incoming transaction of "([^"]*?)" on the project account$/) do |arg1|
15 | BitcoinDaemon.instance.add_transaction(account: @project.address_label, amount: arg1.to_d, address: @project.bitcoin_address)
16 | end
17 |
18 | When(/^there's a new incoming transaction of "(.*?)" to address "(.*?)" on the project account$/) do |arg1, arg2|
19 | BitcoinDaemon.instance.add_transaction(account: @project.address_label, amount: arg1.to_d, address: arg2)
20 | end
21 |
22 | When(/^there's a new incoming transaction of "(.*?)" to address "(.*?)" on the project account with (\d+) confirmations$/) do |arg1, arg2, arg3|
23 | BitcoinDaemon.instance.add_transaction(account: @project.address_label, amount: arg1.to_d, address: arg2, confirmations: arg3.to_i)
24 | end
25 |
26 | When(/^there's a new outgoing transaction of "(.*?)" to address "(.*?)" on the project account$/) do |arg1, arg2|
27 | BitcoinDaemon.instance.add_transaction(category: "send", account: @project.address_label, amount: -arg1.to_d, address: arg2)
28 | end
29 |
30 | When(/^there's a new outgoing transaction of "(.*?)" to address "(.*?)" on the project account with (\d+) confirmations$/) do |arg1, arg2, arg3|
31 | BitcoinDaemon.instance.add_transaction(category: "send", account: @project.address_label, amount: -arg1.to_d, address: arg2, confirmations: arg3.to_i)
32 | end
33 |
34 | When(/^the project (?:balance is|balances are) updated$/) do
35 | BalanceUpdater.work
36 | end
37 |
38 | Then(/^updating the project balance should raise an error$/) do
39 | expect { BalanceUpdater.work }.to raise_error(RuntimeError)
40 | end
41 |
42 | Then(/^the project balance should be "(.*?)"$/) do |arg1|
43 | expect(@project.reload.available_amount.to_d / COIN).to eq(arg1.to_d)
44 | end
45 |
46 | Then(/^the project amount in cold storage should be "(.*?)"$/) do |arg1|
47 | expect(@project.reload.cold_storage_amount / COIN).to eq(arg1.to_d)
48 | end
49 |
50 | When(/^"(.*?)" coins of the project funds are sent to cold storage$/) do |arg1|
51 | @project.send_to_cold_storage!((arg1.to_d * COIN).to_i)
52 | end
53 |
54 | Then(/^there should be an outgoing transaction of "(.*?)" to address "(.*?)" on the project account$/) do |arg1, arg2|
55 | transactions = BitcoinDaemon.instance.list_transactions(@project.address_label)
56 | expect(transactions.map { |t| t["category"] }).to eq(["send"])
57 | expect(transactions.map { |t| t["address"] }).to eq([arg2])
58 | expect(transactions.map { |t| -t["amount"].to_d / COIN }).to eq([arg1.to_d])
59 | end
60 |
61 | Given(/^the project has no cold storage withdrawal address$/) do
62 | @project.update(cold_storage_withdrawal_address: nil)
63 | end
64 |
65 | Then(/^the project should have a cold storage withdrawal address$/) do
66 | expect(@project.reload.cold_storage_withdrawal_address).not_to be_blank
67 | end
68 |
69 | Then(/^the project cold storage withdrawal address should be linked to its account$/) do
70 | expect(BitcoinDaemon.instance.get_addresses_by_account(@project.address_label)).to include(@project.reload.cold_storage_withdrawal_address)
71 | end
72 |
--------------------------------------------------------------------------------
/features/step_definitions/commit_from_known_nickname.rb:
--------------------------------------------------------------------------------
1 | Given(/^an user "(.*?)"$/) do |arg1|
2 | create(:user, nickname: arg1, email: "#{arg1}@example.com")
3 | end
4 |
5 | Given(/^the email of "(.*?)" is "(.*?)"$/) do |arg1, arg2|
6 | User.find_by_nickname!(arg1).update(email: arg2)
7 | end
8 |
9 | Then(/^the tip for commit "(.*?)" is for user "(.*?)"$/) do |arg1, arg2|
10 | expect(Tip.find_by_commit!(arg1).user.nickname).to eq(arg2)
11 | end
12 |
13 | Then(/^there should be no user with email "(.*?)"$/) do |arg1|
14 | expect(User.where(email: arg1).size).to eq(0)
15 | end
16 |
17 |
--------------------------------------------------------------------------------
/features/step_definitions/create_project.rb:
--------------------------------------------------------------------------------
1 |
2 | Then(/^there should be a project "(.*?)"$/) do |arg1|
3 | expect(Project.pluck(:name)).to include(arg1)
4 | @project = Project.where(name: arg1).first
5 | end
6 |
7 | Then(/^the description of the project should be$/) do |string|
8 | expect(@project.description).to eq(string)
9 | end
10 |
11 | Then(/^I should be on the project page$/) do
12 | expect(current_url).to eq(project_url(@project))
13 | end
14 |
15 | Then(/^there should be no project$/) do
16 | expect(Project.all).to be_empty
17 | end
18 |
19 | Then(/^the GitHub name of the project should be "(.*?)"$/) do |arg1|
20 | expect(@project.full_name).to eq(arg1)
21 | end
22 |
23 | Then(/^the project single collaborators should be "(.*?)"$/) do |arg1|
24 | if arg1 =~ /@/
25 | expect(@project.collaborators.map(&:user).map(&:email)).to eq([arg1])
26 | else
27 | expect(@project.collaborators.map(&:user).map(&:nickname)).to eq([arg1])
28 | end
29 | end
30 |
31 | Then(/^the project address label should be "(.*?)"$/) do |arg1|
32 | expect(@project.address_label).to eq(arg1)
33 | end
34 |
35 | Then(/^the project donation address should be the same as account "(.*?)"$/) do |arg1|
36 | expect(@project.bitcoin_address).to eq(BitcoinDaemon.instance.get_addresses_by_account(arg1).first)
37 | end
38 |
39 |
--------------------------------------------------------------------------------
/features/step_definitions/donate_to_project.rb:
--------------------------------------------------------------------------------
1 | Given(/^a project "([^"]*)" with a donation address "([^"]*)" associated with "([^"]*)"$/) do |arg1, arg2, arg3|
2 | @project = Project.create!(
3 | name: arg1,
4 | full_name: "example/#{arg1}",
5 | bitcoin_address: 'mq4NtnmQoQoPfNWEPbhSvxvncgtGo6L8WY',
6 | hold_tips: false,
7 | address_label: "project-#{arg1}",
8 | )
9 | step %Q[the project has a donation address "#{arg2}" associated with "#{arg3}"]
10 | end
11 |
12 |
13 | Then(/^I should see the project donation address associated with "(.*?)"$/) do |arg1|
14 | address = @project.donation_addresses.find_by(sender_address: arg1).donation_address
15 | expect(address).not_to be_blank
16 | expect(page).to have_content(address)
17 | end
18 |
19 | Given(/^there's a new incoming transaction of "(.*?)" to the donation address associated with "(.*?)"$/) do |arg1, arg2|
20 | address = @project.donation_addresses.find_by(sender_address: arg2).donation_address
21 | expect(address).not_to be_blank
22 | BitcoinDaemon.instance.add_transaction(account: @project.address_label, amount: arg1.to_d, address: address)
23 | end
24 |
25 | Given(/^there's a new incoming transaction of "([^"]*)" to "([^"]*)" in transaction "([^"]*)"$/) do |arg1, arg2, arg3|
26 | donation_address = DonationAddress.find_by!(donation_address: arg2)
27 | project = donation_address.project
28 | BitcoinDaemon.instance.add_transaction(
29 | account: project.address_label,
30 | amount: arg1.to_d,
31 | address: donation_address.donation_address,
32 | txid: arg3,
33 | )
34 | end
35 |
36 | Then(/^I should see the donor "(.*?)" sent "(.*?)"$/) do |arg1, arg2|
37 | within ".donor-row", text: arg1 do
38 | expect(find(".amount").text.to_d).to eq(arg2.to_d)
39 | end
40 | end
41 |
42 | Given(/^the project has a donation address "(.*?)" associated with "(.*?)"$/) do |arg1, arg2|
43 | @project.donation_addresses.create!(sender_address: arg2, donation_address: arg1)
44 | end
45 |
46 | When(/^there's a new incoming transaction of "([^"]*?)" to the project donation address$/) do |arg1|
47 | BitcoinDaemon.instance.add_transaction(account: @project.address_label, amount: arg1.to_d, address: @project.bitcoin_address)
48 | end
49 |
50 |
--------------------------------------------------------------------------------
/features/step_definitions/github.rb:
--------------------------------------------------------------------------------
1 |
2 | Given(/^"(.*?)" is an user registered on GitHub$/) do |arg1|
3 | GITHUB_USERS[arg1] = {}
4 | end
5 |
6 |
--------------------------------------------------------------------------------
/features/step_definitions/tip_for_commit.rb:
--------------------------------------------------------------------------------
1 |
2 | Given(/^the project does not hold tips$/) do
3 | @project.update(hold_tips: false)
4 | end
5 |
6 | Given(/^the project GitHub name is "(.*?)"$/) do |arg1|
7 | @project.update(full_name: arg1)
8 | end
9 |
10 | Given(/^the commits on GitHub for project "(.*?)" are$/) do |arg1, table|
11 | @project.reload
12 | expect(@project.full_name).to eq(arg1)
13 | commits = []
14 | table.hashes.each do |row|
15 | commit = OpenStruct.new(
16 | sha: row["sha"],
17 | author: OpenStruct.new(
18 | login: row["author"],
19 | ),
20 | commit: OpenStruct.new(
21 | message: row["message"] || "Some changes",
22 | author: OpenStruct.new(
23 | email: row["email"] || "author@example.com",
24 | ),
25 | committer: OpenStruct.new(
26 | date: Time.now,
27 | ),
28 | ),
29 | )
30 | commits << commit
31 | end
32 |
33 | expect(@project).to receive(:get_commits).and_return(commits)
34 | end
35 |
36 | When(/^the project tips are built from commits$/) do
37 | @project.tip_commits
38 | end
39 |
40 | Then(/^the project should have these tips:$/) do |table|
41 | tips = @project.tips.map do |tip|
42 | {
43 | commit: tip.commit,
44 | amount: tip.amount ? (tip.amount.to_f / COIN).to_s : "",
45 | }.with_indifferent_access
46 | end
47 | expect(tips).to eq(table.hashes)
48 | end
49 |
--------------------------------------------------------------------------------
/features/step_definitions/tip_modifier_interface.rb:
--------------------------------------------------------------------------------
1 | When(/^I choose the amount "(.*?)" on commit "(.*?)"$/) do |arg1, arg2|
2 | within find(".decide-tip-amounts-table tbody tr", text: arg2) do
3 | select arg1
4 | end
5 | end
6 |
7 | When(/^I fill the free amount with "(.*?)" on commit "(.*?)"$/) do |arg1, arg2|
8 | within find(".decide-tip-amounts-table tbody tr", text: arg2) do
9 | fill_in "Decided free amount", with: arg1
10 | end
11 | end
12 |
13 | When(/^I choose the amount "(.*?)" on all commits$/) do |arg1|
14 | all(".decide-tip-amounts-table tbody tr").each do |tr|
15 | within tr do
16 | select arg1
17 | end
18 | end
19 | end
20 |
21 | When(/^I go to the edit page of the project$/) do
22 | visit edit_project_path(@project)
23 | end
24 |
25 | When(/^I send a forged request to enable tip holding on the project$/) do
26 | page.driver.browser.process_and_follow_redirects(:patch, project_path(@project), project: {hold_tips: "1"})
27 | end
28 |
29 | Then(/^I should see an access denied$/) do
30 | expect(page).to have_content("Access denied")
31 | end
32 |
33 | Then(/^the project should not hold tips$/) do
34 | expect(@project.reload.hold_tips).to be false
35 | end
36 |
37 | Then(/^the project should hold tips$/) do
38 | expect(@project.reload.hold_tips).to be true
39 | end
40 |
41 | Given(/^the project has undedided tips$/) do
42 | create(:undecided_tip, project: @project)
43 | expect(@project.reload).to have_undecided_tips
44 | end
45 |
46 | Given(/^the project has (\d+) undecided tip$/) do |arg1|
47 | @project.tips.undecided.each(&:destroy)
48 | create(:undecided_tip, project: @project)
49 | expect(@project.reload).to have_undecided_tips
50 | end
51 |
52 | Given(/^I send a forged request to set the amount of the first undecided tip of the project$/) do
53 | tip = @project.tips.undecided.first
54 | expect(tip).not_to be_nil
55 | params = {
56 | project: {
57 | tips_attributes: {
58 | "0" => {
59 | id: tip.id,
60 | decided_amount_percentage: "5",
61 | },
62 | },
63 | },
64 | }
65 |
66 | page.driver.browser.process_and_follow_redirects(:patch, decide_tip_amounts_project_path(@project), params)
67 | end
68 |
69 | When(/^I send a forged request to change the percentage of commit "(.*?)" on project "(.*?)" to "(.*?)"$/) do |arg1, arg2, arg3|
70 | project = find_project(arg2)
71 | tip = project.tips.detect { |t| t.commit == arg1 }
72 | expect(tip).not_to be_nil
73 | params = {
74 | project: {
75 | tips_attributes: {
76 | "0" => {
77 | id: tip.id,
78 | decided_amount_percentage: arg3,
79 | },
80 | },
81 | },
82 | }
83 |
84 | page.driver.browser.process_and_follow_redirects(:patch, decide_tip_amounts_project_path(project), params)
85 | end
86 |
87 | Then(/^the project should have (\d+) undecided tips$/) do |arg1|
88 | expect(@project.tips.undecided.size).to eq(arg1.to_i)
89 | end
90 |
91 | Then(/^there should be (\d+) tip$/) do |arg1|
92 | expect(@project.reload.tips.size).to eq(arg1.to_i)
93 | end
94 |
--------------------------------------------------------------------------------
/features/step_definitions/user_identifier.rb:
--------------------------------------------------------------------------------
1 | Then(/^I should see the identifier of "(.*?)"$/) do |arg1|
2 | identifier = User.find_by(email: arg1).identifier
3 | expect(identifier).to be_present
4 | expect(page).to have_content identifier
5 | end
6 |
--------------------------------------------------------------------------------
/features/support/big_decimal_inspect.rb:
--------------------------------------------------------------------------------
1 | class BigDecimal
2 | def inspect
3 | ""
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/features/support/bitcoin_daemon_mock.rb:
--------------------------------------------------------------------------------
1 | class BitcoinDaemonMock
2 | def initialize
3 | @transactions = []
4 | @addresses_by_account = Hash.new
5 | end
6 |
7 | def random_address
8 | "random_address"
9 | end
10 |
11 | def add_transaction(options)
12 | transaction = {
13 | "account" => "",
14 | "address" => random_address,
15 | "category" => "receive",
16 | "amount" => 10.0,
17 | "confirmations" => 10,
18 | "blockhash" => SecureRandom.hex(64),
19 | "blockindex" => 3,
20 | "txid" => SecureRandom.hex(64),
21 | "time" => Time.now.to_i,
22 | }.merge(options.stringify_keys)
23 | @transactions << transaction
24 | end
25 |
26 | def list_transactions(account = "", count = 10, from = 0)
27 | @transactions.select { |t| account == "*" ? true : (t["account"] == account) }[from, count]
28 | end
29 |
30 | def clear_transaction_history
31 | @transactions.clear
32 | end
33 |
34 | def send_many(account, recipients, minconf = 1)
35 | txid = SecureRandom.hex(64)
36 | recipients.each do |recipient, amount|
37 | @transactions << {
38 | "account" => account,
39 | "address" => recipient,
40 | "category" => "send",
41 | "amount" => -amount.to_f,
42 | "confirmations" => 10,
43 | "blockhash" => SecureRandom.hex(64),
44 | "blockindex" => 3,
45 | "txid" => txid,
46 | "time" => Time.now.to_i,
47 | }
48 | end
49 | txid
50 | end
51 |
52 | def get_new_address(account)
53 | @addresses_by_account[account] ||= []
54 | address = SecureRandom.hex(10)
55 | @addresses_by_account[account] << address
56 | address
57 | end
58 |
59 | def get_addresses_by_account(account)
60 | @addresses_by_account[account] || []
61 | end
62 |
63 | def get_balance(account)
64 | 0
65 | end
66 | end
67 |
68 | Before do
69 | BitcoinDaemon.instance_eval do
70 | @bitcoin_daemon = BitcoinDaemonMock.new
71 | end
72 | end
73 |
--------------------------------------------------------------------------------
/features/support/env.rb:
--------------------------------------------------------------------------------
1 | # IMPORTANT: This file is generated by cucumber-rails - edit at your own peril.
2 | # It is recommended to regenerate this file in the future when you upgrade to a
3 | # newer version of cucumber-rails. Consider adding your own code to a new file
4 | # instead of editing this one. Cucumber will automatically load all features/**/*.rb
5 | # files.
6 |
7 | require 'cucumber/rails'
8 |
9 | # Capybara defaults to CSS3 selectors rather than XPath.
10 | # If you'd prefer to use XPath, just uncomment this line and adjust any
11 | # selectors in your step definitions to use the XPath syntax.
12 | # Capybara.default_selector = :xpath
13 |
14 | # By default, any exception happening in your Rails application will bubble up
15 | # to Cucumber so that your scenario will fail. This is a different from how
16 | # your application behaves in the production environment, where an error page will
17 | # be rendered instead.
18 | #
19 | # Sometimes we want to override this default behaviour and allow Rails to rescue
20 | # exceptions and display an error page (just like when the app is running in production).
21 | # Typical scenarios where you want to do this is when you test your error pages.
22 | # There are two ways to allow Rails to rescue exceptions:
23 | #
24 | # 1) Tag your scenario (or feature) with @allow-rescue
25 | #
26 | # 2) Set the value below to true. Beware that doing this globally is not
27 | # recommended as it will mask a lot of errors for you!
28 | #
29 | ActionController::Base.allow_rescue = false
30 |
31 | # Remove/comment out the lines below if your app doesn't have a database.
32 | # For some databases (like MongoDB and CouchDB) you may need to use :truncation instead.
33 | begin
34 | DatabaseCleaner.strategy = :transaction
35 | rescue NameError
36 | raise "You need to add database_cleaner to your Gemfile (in the :test group) if you wish to use it."
37 | end
38 |
39 | # You may also want to configure DatabaseCleaner to use different strategies for certain features and scenarios.
40 | # See the DatabaseCleaner documentation for details. Example:
41 | #
42 | # Before('@no-txn,@selenium,@culerity,@celerity,@javascript') do
43 | # # { :except => [:widgets] } may not do what you expect here
44 | # # as Cucumber::Rails::Database.javascript_strategy overrides
45 | # # this setting.
46 | # DatabaseCleaner.strategy = :truncation
47 | # end
48 | #
49 | # Before('~@no-txn', '~@selenium', '~@culerity', '~@celerity', '~@javascript') do
50 | # DatabaseCleaner.strategy = :transaction
51 | # end
52 | #
53 |
54 | # Possible values are :truncation and :transaction
55 | # The :transaction strategy is faster, but might give you threading problems.
56 | # See https://github.com/cucumber/cucumber-rails/blob/master/features/choose_javascript_database_strategy.feature
57 | Cucumber::Rails::Database.javascript_strategy = :truncation
58 |
59 | require 'capybara/poltergeist'
60 | if ENV["FIREFOX"]
61 | Capybara.javascript_driver = :selenium
62 | else
63 | Capybara.register_driver :poltergeist do |app|
64 | Capybara::Poltergeist::Driver.new(app, inspector: true)
65 | end
66 | Capybara.javascript_driver = :poltergeist
67 | end
68 |
69 | require 'capybara-screenshot/cucumber'
70 |
--------------------------------------------------------------------------------
/features/support/factory_girl.rb:
--------------------------------------------------------------------------------
1 | World(FactoryGirl::Syntax::Methods)
2 |
--------------------------------------------------------------------------------
/features/support/finders.rb:
--------------------------------------------------------------------------------
1 | def find_project(name)
2 | project = Project.where(full_name: "example/#{name}").first
3 | project or raise "Project #{name.inspect} not found"
4 | end
5 |
--------------------------------------------------------------------------------
/features/support/octokit_mock.rb:
--------------------------------------------------------------------------------
1 | class Octokit::Client
2 | def initialize(*args)
3 | end
4 |
5 | def commits(*args)
6 | []
7 | end
8 |
9 | def user(login)
10 | GITHUB_USERS.fetch(login) do
11 | raise Octokit::NotFound
12 | end
13 | end
14 | end
15 |
16 | GITHUB_USERS = {}
17 |
18 | Before do
19 | GITHUB_USERS.clear
20 | end
21 |
--------------------------------------------------------------------------------
/features/support/rspec_doubles.rb:
--------------------------------------------------------------------------------
1 | require 'cucumber/rspec/doubles'
2 |
--------------------------------------------------------------------------------
/features/support/to_ostruct.rb:
--------------------------------------------------------------------------------
1 | require 'ostruct'
2 |
3 | class Hash
4 | def to_ostruct
5 | o = OpenStruct.new(self)
6 | each do |k,v|
7 | o.send(:"#{k}=", v.to_ostruct) if v.respond_to? :to_ostruct
8 | end
9 | o
10 | end
11 | end
12 |
13 | class Array
14 | def to_ostruct
15 | map do |item|
16 | if item.respond_to? :to_ostruct
17 | item.to_ostruct
18 | else
19 | item
20 | end
21 | end
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/features/tip_for_commit.feature:
--------------------------------------------------------------------------------
1 | Feature: On projects not holding tips, a tip is created for each new commit
2 | Scenario: A project not holding tips
3 | Given a project
4 | And the project does not hold tips
5 | And the project GitHub name is "foo/bar"
6 | And the commits on GitHub for project "foo/bar" are
7 | | sha | author | email |
8 | | 123 | bob | bobby@example.com |
9 | | abc | alice | alicia@example.com |
10 | | 333 | bob | bobby@example.com |
11 | And our fee is "0"
12 | And a deposit of "500"
13 | Given a GitHub user "bob" who has set his address to "mxWfjaZJTNN5QKeZZYQ5HW3vgALFBsnuG1"
14 |
15 | When the project tips are built from commits
16 | Then the project should have these tips:
17 | | commit | amount |
18 | | 123 | 5.0 |
19 | | 333 | 4.95 |
20 |
21 | When the tipper is started
22 | Then these amounts should have been sent from the account of the project:
23 | | address | amount |
24 | | mxWfjaZJTNN5QKeZZYQ5HW3vgALFBsnuG1 | 9.95 |
25 |
26 | And no email should have been sent
27 |
28 | Scenario: A project holding tips
29 | Given a project
30 | And the project holds tips
31 | And the project GitHub name is "foo/bar"
32 | And the commits on GitHub for project "foo/bar" are
33 | | sha | author | email |
34 | | 123 | bob | bobby@example.com |
35 | | abc | alice | alicia@example.com |
36 | | 333 | bob | bobby@example.com |
37 | And our fee is "0"
38 | And a deposit of "500"
39 | And a GitHub user "bob" who has set his address to "mxWfjaZJTNN5QKeZZYQ5HW3vgALFBsnuG1"
40 |
41 | When the project tips are built from commits
42 | Then the project should have these tips:
43 | | commit | amount |
44 | | 123 | |
45 | | 333 | |
46 |
47 | When the tipper is started
48 | Then no coins should have been sent
49 |
--------------------------------------------------------------------------------
/features/tipping_policies.feature:
--------------------------------------------------------------------------------
1 | Feature: A project collaborator can display the tipping policies of the project
2 | Background:
3 | Given a project
4 | And the project collaborators are:
5 | | seldon |
6 | | daneel |
7 |
8 | Scenario: A collaborator changes the tipping policies
9 | Given I'm logged in as "seldon"
10 | And I go to the project page
11 | And I click on "Edit project"
12 | And I fill "Tipping policies" with:
13 | """
14 | All commits are huge!
15 |
16 | Blah blah
17 | """
18 | And I click on "Save"
19 | Then I should see "The project has been updated"
20 |
21 | Given I'm not logged in
22 | And I go to the project page
23 | Then I should see "All commits are huge!"
24 | And I should see "Blah blah"
25 | And I should see "seldon"
26 |
--------------------------------------------------------------------------------
/features/user_identifier.feature:
--------------------------------------------------------------------------------
1 | Feature: Each user has an unique identifier
2 | Scenario: New email user gets an unique identifier
3 | When I visit the home page
4 | And I click on "Sign in"
5 | And I click on "Sign up"
6 | And I fill "Email" with "bob@example.com"
7 | And I fill "Password" with "password"
8 | And I fill "Password confirmation" with "password"
9 | And I click on "Sign up"
10 | Then I should see "confirmation link"
11 |
12 | And an email should have been sent to "bob@example.com"
13 | When I click on "Confirm my account" in the email
14 | Then I should see "confirmed"
15 |
16 | And I fill "Email" with "bob@example.com"
17 | And I fill "Password" with "password"
18 | And I click on "Sign in" in the sign in form
19 | When I go to edit my profile
20 | Then I should see the identifier of "bob@example.com"
21 |
--------------------------------------------------------------------------------
/lib/assets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sigmike/peer4commit/c63313c7281d28186849adb23fae93873c52da33/lib/assets/.keep
--------------------------------------------------------------------------------
/lib/bitcoin_address_validator.rb:
--------------------------------------------------------------------------------
1 | require 'digest'
2 |
3 | class BitcoinAddressValidator < ActiveModel::EachValidator
4 | def validate_each(record, field, value)
5 | unless value.blank? || valid_bitcoin_address?(value)
6 | record.errors[field] << "Peercoin address is invalid"
7 | end
8 | end
9 |
10 | private
11 |
12 | B58Chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
13 | B58Base = B58Chars.length
14 |
15 | def valid_bitcoin_address?(address)
16 | if (address =~ /^[a-zA-Z1-9]{33,35}$/) and version = version(address)
17 | if (expected_versions = CONFIG["address_versions"]).present?
18 | expected_versions.include?(version.ord)
19 | else
20 | true
21 | end
22 | else
23 | false
24 | end
25 | end
26 |
27 | def version(address)
28 | decoded = b58_decode(address, 25)
29 |
30 | version = decoded[0, 1]
31 | checksum = decoded[-4, decoded.length]
32 | vh160 = decoded[0, decoded.length - 4]
33 |
34 | hashed = (Digest::SHA2.new << (Digest::SHA2.new << vh160).digest).digest
35 |
36 | hashed[0, 4] == checksum ? version[0] : nil
37 | end
38 |
39 | def b58_decode(value, length)
40 | long_value = 0
41 | index = 0
42 | result = ""
43 |
44 | value.reverse.each_char do |c|
45 | long_value += B58Chars.index(c) * (B58Base ** index)
46 | index += 1
47 | end
48 |
49 | while long_value >= 256 do
50 | div, mod = long_value.divmod 256
51 | result = mod.chr + result
52 | long_value = div
53 | end
54 |
55 | result = long_value.chr + result
56 |
57 | if result.length < length
58 | result = 0.chr * (length - result.length) + result
59 | end
60 |
61 | result
62 | end
63 | end
64 |
--------------------------------------------------------------------------------
/lib/bitcoin_daemon.rb:
--------------------------------------------------------------------------------
1 | class BitcoinDaemon
2 | def self.instance
3 | @bitcoin_daemon ||= BitcoinDaemon.new(CONFIG['daemon'])
4 | end
5 |
6 | class RPCError < StandardError
7 | attr_accessor :code
8 | def initialize(code, message)
9 | @code = code
10 | super(message)
11 | end
12 | end
13 |
14 | attr_reader :config
15 |
16 | def initialize(config)
17 | @config = config || {}
18 | end
19 |
20 | def rpc(command, *params)
21 | %w( username password port host ).each do |field|
22 | raise "No #{field} provided in daemon config" if config[field].blank?
23 | end
24 |
25 | uri = URI::HTTP.build(host: config['host'], port: config['port'].to_i)
26 |
27 | auth = config.slice('username', 'password').symbolize_keys
28 |
29 | data = {
30 | method: command,
31 | params: params,
32 | id: 1,
33 | }
34 |
35 | Rails.logger.info "RPC Command: #{data.inspect}"
36 | response = HTTParty.post(uri.to_s, body: data.to_json, basic_auth: auth)
37 |
38 | result = JSON.parse(response.body)
39 | if error = result["error"]
40 | raise RPCError.new(error["code"], error["message"])
41 | end
42 | result["result"]
43 | end
44 |
45 | def get_new_address(account = "")
46 | rpc('getnewaddress', account)
47 | end
48 |
49 | def list_transactions(account = "", count = 10, from = 0)
50 | rpc('listtransactions', account, count, from)
51 | end
52 |
53 | def send_many(account, recipients, minconf = 1)
54 | recipients = recipients.dup
55 | recipients.each do |address, amount|
56 | recipients[address] = amount.to_f
57 | end
58 | rpc('sendmany', account, recipients, minconf)
59 | end
60 |
61 | def get_balance(account = "")
62 | rpc('getbalance', account).to_f
63 | end
64 | end
65 |
--------------------------------------------------------------------------------
/lib/bitcoin_tipper.rb:
--------------------------------------------------------------------------------
1 | class BitcoinTipper
2 | def self.work_forever
3 | while true do
4 | self.work
5 | end
6 | end
7 |
8 | def self.work
9 | Rails.logger.info "Traversing projects..."
10 | Project.enabled.find_each do |project|
11 | Rails.logger.info " Project #{project.id} #{project.full_name}"
12 | project.update_commits
13 | project.tip_commits
14 | end
15 |
16 | Rails.logger.info "Sending tips to commits..."
17 | Project.enabled.find_each do |project|
18 | tips = project.tips_to_pay
19 | amount = tips.sum(&:amount).to_d
20 | if amount > CONFIG["min_payout"].to_d * COIN
21 | distribution = Distribution.create(project_id: project.id)
22 | tips.each do |tip|
23 | tip.update_attribute :distribution_id, distribution.id
24 | end
25 | distribution.reload.send_transaction!
26 | Rails.logger.info " #{distribution.inspect}"
27 | end
28 | end
29 |
30 | Rails.logger.info "Refunding unclaimed tips..."
31 | Tip.refund_unclaimed
32 |
33 | Rails.logger.info "Updating projects cache..."
34 | Project.update_cache
35 |
36 | Rails.logger.info "Updating users cache..."
37 | User.update_cache
38 | end
39 |
40 | def self.create_distributions
41 | Rails.logger.info "Creating distribution"
42 | ActiveRecord::Base.transaction do
43 | end
44 | end
45 |
46 | end
47 |
--------------------------------------------------------------------------------
/lib/tasks/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sigmike/peer4commit/c63313c7281d28186849adb23fae93873c52da33/lib/tasks/.keep
--------------------------------------------------------------------------------
/lib/tasks/cucumber.rake:
--------------------------------------------------------------------------------
1 | # IMPORTANT: This file is generated by cucumber-rails - edit at your own peril.
2 | # It is recommended to regenerate this file in the future when you upgrade to a
3 | # newer version of cucumber-rails. Consider adding your own code to a new file
4 | # instead of editing this one. Cucumber will automatically load all features/**/*.rb
5 | # files.
6 |
7 |
8 | unless ARGV.any? {|a| a =~ /^gems/} # Don't load anything when running the gems:* tasks
9 |
10 | vendored_cucumber_bin = Dir["#{Rails.root}/vendor/{gems,plugins}/cucumber*/bin/cucumber"].first
11 | $LOAD_PATH.unshift(File.dirname(vendored_cucumber_bin) + '/../lib') unless vendored_cucumber_bin.nil?
12 |
13 | begin
14 | require 'cucumber/rake/task'
15 |
16 | namespace :cucumber do
17 | Cucumber::Rake::Task.new({:ok => 'test:prepare'}, 'Run features that should pass') do |t|
18 | t.binary = vendored_cucumber_bin # If nil, the gem's binary is used.
19 | t.fork = true # You may get faster startup if you set this to false
20 | t.profile = 'default'
21 | end
22 |
23 | Cucumber::Rake::Task.new({:wip => 'test:prepare'}, 'Run features that are being worked on') do |t|
24 | t.binary = vendored_cucumber_bin
25 | t.fork = true # You may get faster startup if you set this to false
26 | t.profile = 'wip'
27 | end
28 |
29 | Cucumber::Rake::Task.new({:rerun => 'test:prepare'}, 'Record failing features and run only them if any exist') do |t|
30 | t.binary = vendored_cucumber_bin
31 | t.fork = true # You may get faster startup if you set this to false
32 | t.profile = 'rerun'
33 | end
34 |
35 | desc 'Run all features'
36 | task :all => [:ok, :wip]
37 |
38 | task :statsetup do
39 | require 'rails/code_statistics'
40 | ::STATS_DIRECTORIES << %w(Cucumber\ features features) if File.exist?('features')
41 | ::CodeStatistics::TEST_TYPES << "Cucumber features" if File.exist?('features')
42 | end
43 | end
44 | desc 'Alias for cucumber:ok'
45 | task :cucumber => 'cucumber:ok'
46 |
47 | task :default => :cucumber
48 |
49 | task :features => :cucumber do
50 | STDERR.puts "*** The 'features' task is deprecated. See rake -T cucumber ***"
51 | end
52 |
53 | # In case we don't have the generic Rails test:prepare hook, append a no-op task that we can depend upon.
54 | task 'test:prepare' do
55 | end
56 |
57 | task :stats => 'cucumber:statsetup'
58 | rescue LoadError
59 | desc 'cucumber rake task not available (cucumber not installed)'
60 | task :cucumber do
61 | abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin'
62 | end
63 | end
64 |
65 | end
66 |
--------------------------------------------------------------------------------
/lib/tasks/reassign_noreply_tips.rake:
--------------------------------------------------------------------------------
1 | task :reassign_noreply_tips => :environment do
2 | logger = Rails.logger
3 | logger.info "Reassigning noreply tips"
4 |
5 | User.transaction do
6 | User.where("email like '%@users.noreply.github.com'").each do |user|
7 | next unless user.nickname.present?
8 |
9 | all = User.where(nickname: user.nickname)
10 | users_with_address = all.select(&:bitcoin_address)
11 | next if users_with_address.size != 1
12 |
13 | real_user = users_with_address.first
14 | logger.info "Real user: #{real_user.inspect}"
15 |
16 | all.each do |other|
17 | next if other == real_user
18 | logger.info "Reassigning tips from user #{other.inspect}"
19 | other.tips.each do |tip|
20 | if tip.project.disabled?
21 | logger.info "Skipping disabled project on tip #{tip.inspect}"
22 | next
23 | end
24 | logger.info "Reassigning tip #{tip.inspect}"
25 | tip.user = real_user
26 | if tip.refunded?
27 | logger.info "Canceling refunded state"
28 | tip.refunded_at = nil
29 | end
30 | if ENV["PROCEED"] == "yes"
31 | tip.save!
32 | end
33 | end
34 | end
35 | end
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/lib/tasks/send_security_issue.rake:
--------------------------------------------------------------------------------
1 | task :send_security_issue => :environment do
2 | User.where(unsubscribed: nil).each do |user|
3 | UserMailer.security_issue(user).deliver
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/lib/templates/haml/scaffold/_form.html.haml:
--------------------------------------------------------------------------------
1 | = simple_form_for(@<%= singular_table_name %>) do |f|
2 | = f.error_notification
3 |
4 | .form-inputs
5 | <%- attributes.each do |attribute| -%>
6 | = f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %>
7 | <%- end -%>
8 |
9 | .form-actions
10 | = f.button :submit
11 |
--------------------------------------------------------------------------------
/log/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sigmike/peer4commit/c63313c7281d28186849adb23fae93873c52da33/log/.keep
--------------------------------------------------------------------------------
/public/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The page you were looking for doesn't exist (404)
5 |
48 |
49 |
50 |
51 |
52 |
53 |
The page you were looking for doesn't exist.
54 |
You may have mistyped the address or the page may have moved.
55 |
56 | If you are the application owner check the logs for more information.
57 |
58 |
59 |
--------------------------------------------------------------------------------
/public/422.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The change you wanted was rejected (422)
5 |
48 |
49 |
50 |
51 |
52 |
53 |
The change you wanted was rejected.
54 |
Maybe you tried to change something you didn't have access to.
55 |
56 | If you are the application owner check the logs for more information.
57 |
58 |
59 |
--------------------------------------------------------------------------------
/public/500.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | We're sorry, but something went wrong (500)
5 |
48 |
49 |
50 |
51 |
52 |
53 |
We're sorry, but something went wrong.
54 |
55 | If you are the application owner check the logs for more information.
56 |
57 |
58 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow: /users/
3 |
--------------------------------------------------------------------------------
/public/webfonts/28BE49_0_0.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sigmike/peer4commit/c63313c7281d28186849adb23fae93873c52da33/public/webfonts/28BE49_0_0.eot
--------------------------------------------------------------------------------
/public/webfonts/28BE49_0_0.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sigmike/peer4commit/c63313c7281d28186849adb23fae93873c52da33/public/webfonts/28BE49_0_0.ttf
--------------------------------------------------------------------------------
/public/webfonts/28BE49_0_0.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sigmike/peer4commit/c63313c7281d28186849adb23fae93873c52da33/public/webfonts/28BE49_0_0.woff
--------------------------------------------------------------------------------
/script/cucumber:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | vendored_cucumber_bin = Dir["#{File.dirname(__FILE__)}/../vendor/{gems,plugins}/cucumber*/bin/cucumber"].first
4 | if vendored_cucumber_bin
5 | load File.expand_path(vendored_cucumber_bin)
6 | else
7 | require 'rubygems' unless ENV['NO_RUBYGEMS']
8 | require 'cucumber'
9 | load Cucumber::BINARY
10 | end
11 |
--------------------------------------------------------------------------------
/test/controllers/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sigmike/peer4commit/c63313c7281d28186849adb23fae93873c52da33/test/controllers/.keep
--------------------------------------------------------------------------------
/test/controllers/home_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class HomeControllerTest < ActionController::TestCase
4 | test "should get index" do
5 | get :index
6 | assert_response :success
7 | end
8 |
9 | end
10 |
--------------------------------------------------------------------------------
/test/controllers/projects_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class ProjectsControllerTest < ActionController::TestCase
4 | test "should get index" do
5 | get :index
6 | assert_response :success
7 | end
8 |
9 | test "should get show" do
10 | get :show
11 | assert_response :success
12 | end
13 |
14 | end
15 |
--------------------------------------------------------------------------------
/test/controllers/sessions_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class SessionsControllerTest < ActionController::TestCase
4 | # test "the truth" do
5 | # assert true
6 | # end
7 | end
8 |
--------------------------------------------------------------------------------
/test/controllers/users_controller_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class UsersControllerTest < ActionController::TestCase
4 | test "should get show" do
5 | get :show
6 | assert_response :success
7 | end
8 |
9 | test "should get update" do
10 | get :update
11 | assert_response :success
12 | end
13 |
14 | end
15 |
--------------------------------------------------------------------------------
/test/factories/tips.rb:
--------------------------------------------------------------------------------
1 | # Read about factories at https://github.com/thoughtbot/factory_girl
2 |
3 | FactoryGirl.define do
4 | factory :tip do
5 | association :user
6 | amount 2
7 | commit { Digest::SHA1.hexdigest(SecureRandom.hex) }
8 |
9 | factory :undecided_tip do
10 | amount nil
11 | end
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/test/factories/users.rb:
--------------------------------------------------------------------------------
1 | # Read about factories at https://github.com/thoughtbot/factory_girl
2 |
3 | FactoryGirl.define do
4 | factory :user do
5 | sequence(:email) { |n| "user#{n}@example.com" }
6 | password "password"
7 | confirmed_at { Time.now }
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/test/fixtures/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sigmike/peer4commit/c63313c7281d28186849adb23fae93873c52da33/test/fixtures/.keep
--------------------------------------------------------------------------------
/test/fixtures/commits.yml:
--------------------------------------------------------------------------------
1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
2 |
3 | one:
4 | project_id:
5 | sha: MyString
6 | message: MyText
7 | username: MyString
8 | email: MyString
9 |
10 | two:
11 | project_id:
12 | sha: MyString
13 | message: MyText
14 | username: MyString
15 | email: MyString
16 |
--------------------------------------------------------------------------------
/test/fixtures/deposits.yml:
--------------------------------------------------------------------------------
1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html
2 |
3 | one:
4 | project_id:
5 | txid: MyString
6 | confirmations: 1
7 | duration: 1
8 | paid_out: 1
9 | paid_out_at: 2013-10-19 23:01:22
10 |
11 | two:
12 | project_id:
13 | txid: MyString
14 | confirmations: 1
15 | duration: 1
16 | paid_out: 1
17 | paid_out_at: 2013-10-19 23:01:22
18 |
--------------------------------------------------------------------------------
/test/fixtures/donation_addresses.yml:
--------------------------------------------------------------------------------
1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
2 |
3 | one:
4 | project_id:
5 | sender_address: MyString
6 | donation_address: MyString
7 |
8 | two:
9 | project_id:
10 | sender_address: MyString
11 | donation_address: MyString
12 |
--------------------------------------------------------------------------------
/test/fixtures/projects.yml:
--------------------------------------------------------------------------------
1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html
2 |
3 | one:
4 | url: MyString
5 | bitcoin_address: MyString
6 |
7 | two:
8 | url: MyString
9 | bitcoin_address: MyString
10 |
--------------------------------------------------------------------------------
/test/fixtures/sendmanies.yml:
--------------------------------------------------------------------------------
1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html
2 |
3 | one:
4 | txid: MyString
5 | data: MyText
6 | result: MyString
7 | is_error: false
8 |
9 | two:
10 | txid: MyString
11 | data: MyText
12 | result: MyString
13 | is_error: false
14 |
--------------------------------------------------------------------------------
/test/fixtures/tipping_policies_texts.yml:
--------------------------------------------------------------------------------
1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
2 |
3 | one:
4 | project_id:
5 | user_id:
6 | text: MyText
7 |
8 | two:
9 | project_id:
10 | user_id:
11 | text: MyText
12 |
--------------------------------------------------------------------------------
/test/fixtures/tips.yml:
--------------------------------------------------------------------------------
1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html
2 |
3 | one:
4 | user_id:
5 | amount: 1
6 | distribution_id:
7 | refunded_at: false
8 |
9 | two:
10 | user_id:
11 | amount: 1
12 | distribution_id:
13 | refunded_at: false
14 |
--------------------------------------------------------------------------------
/test/fixtures/users.yml:
--------------------------------------------------------------------------------
1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html
2 |
3 | # This model initially had no columns defined. If you add columns to the
4 | # model remove the '{}' from the fixture names and add the columns immediately
5 | # below each fixture, per the syntax in the comments below
6 | #
7 | one: {}
8 | # column: value
9 | #
10 | two: {}
11 | # column: value
12 |
--------------------------------------------------------------------------------
/test/helpers/home_helper_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class HomeHelperTest < ActionView::TestCase
4 | end
5 |
--------------------------------------------------------------------------------
/test/helpers/projects_helper_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class ProjectsHelperTest < ActionView::TestCase
4 | end
5 |
--------------------------------------------------------------------------------
/test/helpers/sessions_helper_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class SessionsHelperTest < ActionView::TestCase
4 | end
5 |
--------------------------------------------------------------------------------
/test/helpers/users_helper_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class UsersHelperTest < ActionView::TestCase
4 | end
5 |
--------------------------------------------------------------------------------
/test/integration/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sigmike/peer4commit/c63313c7281d28186849adb23fae93873c52da33/test/integration/.keep
--------------------------------------------------------------------------------
/test/mailers/user_mailer_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class UserMailerTest < ActionMailer::TestCase
4 | test "new_tip" do
5 | mail = UserMailer.new_tip
6 | assert_equal "New tip", mail.subject
7 | assert_equal ["to@example.org"], mail.to
8 | assert_equal ["from@example.com"], mail.from
9 | assert_match "Hi", mail.body.encoded
10 | end
11 |
12 | end
13 |
--------------------------------------------------------------------------------
/test/models/commit_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class CommitTest < ActiveSupport::TestCase
4 | # test "the truth" do
5 | # assert true
6 | # end
7 | end
8 |
--------------------------------------------------------------------------------
/test/models/deposit_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class DepositTest < ActiveSupport::TestCase
4 | # test "the truth" do
5 | # assert true
6 | # end
7 | end
8 |
--------------------------------------------------------------------------------
/test/models/donation_address_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class DonationAddressTest < ActiveSupport::TestCase
4 | # test "the truth" do
5 | # assert true
6 | # end
7 | end
8 |
--------------------------------------------------------------------------------
/test/models/project_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class ProjectTest < ActiveSupport::TestCase
4 | # test "the truth" do
5 | # assert true
6 | # end
7 | end
8 |
--------------------------------------------------------------------------------
/test/models/record_change_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class RecordChangeTest < ActiveSupport::TestCase
4 | # test "the truth" do
5 | # assert true
6 | # end
7 | end
8 |
--------------------------------------------------------------------------------
/test/models/tip_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class TipTest < ActiveSupport::TestCase
4 | # test "the truth" do
5 | # assert true
6 | # end
7 | end
8 |
--------------------------------------------------------------------------------
/test/models/tipping_policies_text_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class TippingPoliciesTextTest < ActiveSupport::TestCase
4 | # test "the truth" do
5 | # assert true
6 | # end
7 | end
8 |
--------------------------------------------------------------------------------
/test/models/user_test.rb:
--------------------------------------------------------------------------------
1 | require 'test_helper'
2 |
3 | class UserTest < ActiveSupport::TestCase
4 | # test "the truth" do
5 | # assert true
6 | # end
7 | end
8 |
--------------------------------------------------------------------------------
/test/test_helper.rb:
--------------------------------------------------------------------------------
1 | ENV["RAILS_ENV"] ||= "test"
2 | require File.expand_path('../../config/environment', __FILE__)
3 | require 'rails/test_help'
4 |
5 | class ActiveSupport::TestCase
6 | ActiveRecord::Migration.check_pending!
7 |
8 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
9 | #
10 | # Note: You'll currently still have to declare fixtures explicitly in integration tests
11 | # -- they do not yet inherit this setting
12 | fixtures :all
13 |
14 | # Add more helper methods to be used by all tests here...
15 | end
16 |
--------------------------------------------------------------------------------
/vendor/assets/javascripts/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sigmike/peer4commit/c63313c7281d28186849adb23fae93873c52da33/vendor/assets/javascripts/.keep
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sigmike/peer4commit/c63313c7281d28186849adb23fae93873c52da33/vendor/assets/stylesheets/.keep
--------------------------------------------------------------------------------