From 72389df821a36f109f621b0ef7161a29a9f287a1 Mon Sep 17 00:00:00 2001 From: James Taylor Date: Mon, 15 Feb 2021 16:15:07 +0000 Subject: [PATCH] Add CLA support Signed-off-by: James Taylor --- .env.example | 3 ++- app/controllers/edit_controller.rb | 6 ++--- app/controllers/proposals_controller.rb | 4 +++ app/controllers/users_controller.rb | 18 +++++++++++++- app/models/concerns/github_pull_request.rb | 13 ++++++++++ app/models/concerns/user_admin.rb | 1 + app/models/concerns/votable.rb | 1 + app/models/proposal.rb | 10 +++++++- app/views/edit/commit.html.erb | 18 ++++++-------- app/views/proposals/show.html.erb | 6 +++++ app/views/shared/_cla_warning.html.erb | 17 +++++++++++++ app/views/users/edit.html.erb | 29 ++++++++++++++++++++++ config/locales/en.yml | 11 ++++++-- spec/models/proposal_spec.rb | 3 ++- 14 files changed, 120 insertions(+), 20 deletions(-) create mode 100644 app/views/shared/_cla_warning.html.erb diff --git a/.env.example b/.env.example index f670cc990..d5921a766 100644 --- a/.env.example +++ b/.env.example @@ -12,4 +12,5 @@ MAX_AGE: 90 PASS_THRESHOLD: 2 BLOCK_THRESHOLD: -1 PROJECT_URL: https://openpolitics.org.uk/manifesto -PROJECT_NAME: The OpenPolitics Manifesto \ No newline at end of file +PROJECT_NAME: The OpenPolitics Manifesto +CLA_URL: https://openpolitics.org.uk/manifesto/cla.html \ No newline at end of file diff --git a/app/controllers/edit_controller.rb b/app/controllers/edit_controller.rb index 25549966f..75e1a39b3 100644 --- a/app/controllers/edit_controller.rb +++ b/app/controllers/edit_controller.rb @@ -49,9 +49,9 @@ def commit pull_from = forked ? "#{@current_user.login}:#{new_branch}" : branch_name @pr = open_pr(pull_from, @branch, @summary, @description) # Check for CLA - @cla_url = "#{ENV.fetch("SITE_URL")}/cla.html" - r = Faraday.get @cla_url - @has_cla = (r.status == 200) + @cla_url = ENV.fetch("CLA_URL") + @has_cla = ENV["CLA_URL"].present? + @unsigned_cla = @has_cla && !current_user.cla_accepted? end private diff --git a/app/controllers/proposals_controller.rb b/app/controllers/proposals_controller.rb index 95d8df793..44531b83d 100644 --- a/app/controllers/proposals_controller.rb +++ b/app/controllers/proposals_controller.rb @@ -20,6 +20,10 @@ def show # Get activity list presenter = ProposalPresenter.new(@proposal) @activity = presenter.activity_log + # Does the proposer still need to sign the CLA? + @cla_url = ENV.fetch("CLA_URL") + @has_cla = ENV["CLA_URL"].present? + @unsigned_cla = @is_author && @has_cla && !current_user.cla_accepted? end def webhook diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 4a019ae82..fc23895c6 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -26,10 +26,18 @@ def show end def edit + @cla_url = ENV.fetch("CLA_URL") + @has_cla = ENV["CLA_URL"].present? + @unsigned_cla = @has_cla && !@user.cla_accepted end def update - @user.update!(user_params) + if params.has_key?(:cla_accepted) + accept_cla + else + @user.update!(user_params) + end + redirect_to edit_user_path(@user) end @@ -48,4 +56,12 @@ def authorise def user_params params.require(:user).permit(:email, :notify_new) end + + def accept_cla + @user.update!(cla_accepted: true) + + @user.proposed.each do |pr| + UpdateProposalJob.perform_later pr.number + end + end end diff --git a/app/models/concerns/github_pull_request.rb b/app/models/concerns/github_pull_request.rb index 904059ffc..bfc6bf48d 100644 --- a/app/models/concerns/github_pull_request.rb +++ b/app/models/concerns/github_pull_request.rb @@ -63,6 +63,19 @@ def set_time_build_status end end + def set_cla_build_status + status = "groupthink/cla" + if cla_required? + if cla_accepted? + set_build_status(:success, I18n.t("build_status.cla.accepted"), status) + else + set_build_status(:pending, I18n.t("build_status.cla.pending"), status) + end + else + set_build_status(:success, I18n.t("build_status.cla.none"), status) + end + end + def merge_pr! Octokit.merge_pull_request(ENV.fetch("GITHUB_REPO"), number) true diff --git a/app/models/concerns/user_admin.rb b/app/models/concerns/user_admin.rb index 7ce3f0a52..f79efc146 100644 --- a/app/models/concerns/user_admin.rb +++ b/app/models/concerns/user_admin.rb @@ -21,6 +21,7 @@ module UserAdmin field :role field :author field :voter + field :cla_accepted end end end diff --git a/app/models/concerns/votable.rb b/app/models/concerns/votable.rb index 6b964a558..4688882fb 100644 --- a/app/models/concerns/votable.rb +++ b/app/models/concerns/votable.rb @@ -43,6 +43,7 @@ def count_votes! unless closed? set_vote_build_status set_time_build_status + set_cla_build_status end end diff --git a/app/models/proposal.rb b/app/models/proposal.rb index cb18134c3..5200a370a 100644 --- a/app/models/proposal.rb +++ b/app/models/proposal.rb @@ -52,6 +52,14 @@ def too_new? age < Rules.min_age end + def cla_required? + ENV["CLA_URL"].present? + end + + def cla_accepted? + proposer.cla_accepted + end + def update_state! state = pr_closed? ? closed_state : open_state update!(state: state) @@ -90,7 +98,7 @@ def closed_state def open_state return nil if pr_closed? return "dead" if too_old? - return "blocked" if blocked? + return "blocked" if blocked? || (cla_required? && !cla_accepted?) if passed? return too_new? ? "agreed" : "passed" end diff --git a/app/views/edit/commit.html.erb b/app/views/edit/commit.html.erb index 825c6eedb..c1154b98a 100644 --- a/app/views/edit/commit.html.erb +++ b/app/views/edit/commit.html.erb @@ -1,24 +1,20 @@ -
+
<%= fa_icon 'check-circle' %> <%= t 'help.success_title' %>
-
+

<%= t 'help.success' %>

- <% if @has_cla %> -

- <%= t :cla %> -

-

- <%= link_to "#{t(:view_cla)}".html_safe, @cla_url, class: 'btn btn-primary' %> -

- <% end %>
-
+
<%= link_to "#{fa_icon('globe')} #{t(:return)}".html_safe, @return_to, class: 'btn btn-primary' if @return_to %> <%= link_to "#{fa_icon('code-fork')} #{t(:view)}".html_safe, proposal_path(@pr), class: 'btn btn-default' %> <%= link_to "#{fa_icon('list')} #{t(:view_all)}".html_safe, proposals_path, class: 'btn btn-default' %>
+ +<% if @unsigned_cla %> + <%= render partial: 'shared/cla_warning', locals: { user: current_user } %> +<% end %> diff --git a/app/views/proposals/show.html.erb b/app/views/proposals/show.html.erb index 7f016a45e..1d77e0a01 100644 --- a/app/views/proposals/show.html.erb +++ b/app/views/proposals/show.html.erb @@ -38,6 +38,12 @@
+<% if @unsigned_cla %> +
+ <%= render partial: 'shared/cla_warning', locals: { user: @proposal.proposer } %> +
+<% end %> +
diff --git a/app/views/shared/_cla_warning.html.erb b/app/views/shared/_cla_warning.html.erb new file mode 100644 index 000000000..a0a2d3b85 --- /dev/null +++ b/app/views/shared/_cla_warning.html.erb @@ -0,0 +1,17 @@ +
+ <%= fa_icon 'exclamation-circle' %> + <%= t 'cla_title' %> +
+ +
+

+ <%= t 'cla' %> +

+

+ Please <%= link_to 'edit your profile', edit_user_path(user) %> and accept the license agreement to unblock your proposal. +

+
+ +
+ <%= link_to "#{fa_icon('cog lg')} #{t(:edit_profile)}".html_safe, edit_user_path(user), class: 'btn btn-primary' %> +
diff --git a/app/views/users/edit.html.erb b/app/views/users/edit.html.erb index 65bd66d3a..fa95680ba 100644 --- a/app/views/users/edit.html.erb +++ b/app/views/users/edit.html.erb @@ -28,3 +28,32 @@
<% end %> + +<% if @has_cla %> +

Contributor License Agreement

+ +

+ <%= t :cla %> +

+ + <% if @unsigned_cla %> + <%= form_for @user, html: {class: "form-horizontal", style: 'clear: right'} do |f| %> + <%= hidden_field_tag "cla_accepted", true %> + +
+
+ <%= link_to "#{t(:view_cla)}".html_safe, @cla_url, class: 'btn btn-default', target: :_blank, rel: 'noopener noreferrer' %> + <%= f.submit class: "btn btn-primary", value: t(:sign_cla) %> +
+
+ <% end %> + <% else %> +
+ <%= fa_icon 'check' %> + You have signed the contributor license agreement. +
+ <% end %> + +   + +<% end %> diff --git a/config/locales/en.yml b/config/locales/en.yml index f3d869e9d..9d7df9d70 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -27,9 +27,12 @@ en: return: Return to site view: View your proposal view_all: View all proposals + edit_profile: Edit profile signed_out_site_intro: To contribute you need to log in with a free GitHub account. GitHub is a popular code-sharing site which hosts the site content. signed_in_site_intro: There is no way at the moment to explore github content here. Please go to the project you want to edit on GitHub and follow a link to the editor. Thanks! - cla: This project has a CLA (Contributor License Agreement). You may need to agree to it before your change can be accepted, if you haven't already. + cla_title: Your proposal is blocked until you accept the contributor license agreement. + cla: This manifesto has a Contributor License Agreement (CLA) which you must accept before any of your proposals can be included. + sign_cla: Accept CLA view_cla: View CLA help: edit: Make your changes in the editor below, then hit "Submit changes" at the bottom. @@ -70,4 +73,8 @@ en: time: too_old: "The change has been open for more than %{max_age} days, and should be closed (age: %{age}d)." too_new: "The change has not yet been open for %{min_age} days (age: %{age}d)." - success: "The change has been open long enough to be merged (age: %{age}d)." \ No newline at end of file + success: "The change has been open long enough to be merged (age: %{age}d)." + cla: + none: No contributor license agreement required. + pending: The contributor license agreement has not been accepted. + accepted: The contributor license agreement has been accepted. \ No newline at end of file diff --git a/spec/models/proposal_spec.rb b/spec/models/proposal_spec.rb index 2c87ffca4..6124e4932 100644 --- a/spec/models/proposal_spec.rb +++ b/spec/models/proposal_spec.rb @@ -4,7 +4,8 @@ RSpec.describe Proposal, type: :model do context "when checking overall state" do - let(:pr) { create :proposal } + let(:proposer) { create :user, cla_accepted: true } + let(:pr) { create :proposal, proposer: proposer } context "when the upstream PR has been closed" do before do