diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 000000000..e8f757af5 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,17 @@ +# Number of days of inactivity before an issue becomes stale +daysUntilStale: 120 +# Number of days of inactivity before a stale issue is closed +daysUntilClose: 30 +# Issues with these labels will never be considered stale +exemptLabels: + - pinned + - security +# Label to use when marking an issue as stale +staleLabel: wontfix +# Comment to post when marking an issue as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +# Comment to post when closing a stale issue. Set to `false` to disable +closeComment: false diff --git a/Gemfile.lock b/Gemfile.lock index 7e89b3ed3..e0d8d48d7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -86,7 +86,7 @@ GEM uniform_notifier (~> 1.11) byebug (11.0.1) cancancan (3.0.1) - capybara (3.25.0) + capybara (3.26.0) addressable mini_mime (>= 0.1.3) nokogiri (~> 1.8) @@ -296,8 +296,8 @@ GEM mime-types-data (~> 3.2015) mime-types-data (3.2019.0331) mimemagic (0.3.3) - mini_magick (4.9.3) - mini_mime (1.0.1) + mini_magick (4.9.4) + mini_mime (1.0.2) mini_portile2 (2.4.0) minitest (5.11.3) moneta (1.0.0) @@ -315,7 +315,7 @@ GEM multi_json (~> 1.3) multi_xml (~> 0.5) rack (>= 1.2, < 3) - oj (3.7.12) + oj (3.8.0) omniauth (1.9.0) hashie (>= 3.4.6, < 3.7.0) rack (>= 1.6.2, < 3) @@ -394,7 +394,7 @@ GEM thor (>= 0.19.0, < 2.0) rainbow (3.0.0) raindrops (0.19.0) - rake (12.3.2) + rake (12.3.3) rb-fsevent (0.10.3) rb-inotify (0.10.0) ffi (~> 1.0) @@ -424,7 +424,7 @@ GEM rspec-mocks (~> 3.8.0) rspec-support (~> 3.8.0) rspec-support (3.8.2) - rubocop (0.72.0) + rubocop (0.73.0) jaro_winkler (~> 1.5.1) parallel (~> 1.10) parser (>= 2.6) @@ -434,7 +434,7 @@ GEM rubocop-rails (2.2.1) rack (>= 1.1) rubocop (>= 0.72.0) - rubocop-rspec (1.33.0) + rubocop-rspec (1.34.0) rubocop (>= 0.60.0) ruby-progressbar (1.10.1) ruby-units (2.3.1) @@ -511,7 +511,7 @@ GEM uniform_notifier (1.12.1) warden (1.2.8) rack (>= 2.0.6) - webdrivers (4.1.0) + webdrivers (4.1.1) nokogiri (~> 1.6) rubyzip (~> 1.0) selenium-webdriver (>= 3.0, < 4.0) diff --git a/app/controllers/admin/members_controller.rb b/app/controllers/admin/members_controller.rb index 55cbdcf34..ca35129b3 100644 --- a/app/controllers/admin/members_controller.rb +++ b/app/controllers/admin/members_controller.rb @@ -1,10 +1,17 @@ module Admin class MembersController < ApplicationController before_action :auth! + def index @members = Member.order(:login_name).paginate(page: params[:page]) end + def destroy + @member = Member.find_by!(slug: params[:slug]) + @member.destroy + redirect_to admin_members_path + end + private def auth! diff --git a/app/controllers/members_controller.rb b/app/controllers/members_controller.rb index 76411b0ec..d044836ed 100644 --- a/app/controllers/members_controller.rb +++ b/app/controllers/members_controller.rb @@ -38,11 +38,6 @@ class MembersController < ApplicationController end end - EMAIL_TYPE_STRING = { - send_notification_email: "direct message notifications", - send_planting_reminder: "planting reminders" - }.freeze - def unsubscribe verifier = ActiveSupport::MessageVerifier.new(ENV['RAILS_SECRET_TOKEN']) decrypted_message = verifier.verify(params[:message]) @@ -72,6 +67,11 @@ class MembersController < ApplicationController private + EMAIL_TYPE_STRING = { + send_notification_email: "direct message notifications", + send_planting_reminder: "planting reminders" + }.freeze + def member_params params.require(:member).permit(:login_name, :tos_agreement, :email, :newsletter) end diff --git a/app/views/admin/members/index.html.haml b/app/views/admin/members/index.html.haml index d91b1f8a1..522c659c6 100644 --- a/app/views/admin/members/index.html.haml +++ b/app/views/admin/members/index.html.haml @@ -2,14 +2,19 @@ = page_entries_info @members = will_paginate @members - %table.table.table-striped - %tr - %th Name - %th Email - %th - %th + %thead + %tr + %th{scope: "col"} # + %th{scope: "col"} Login Name + %th{scope: "col"} Email - @members.each do |member| %tr - %td= member.login_name + %td= render 'members/tiny', member: member + %td + = link_to member, member %td= member.email + %td + = link_to admin_member_path(member), method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-light text-danger' do + = icon 'fas', 'ban' + Ban member diff --git a/app/views/members/_follow_buttons.haml b/app/views/members/_follow_buttons.haml index 82a2b7d88..244dc15f4 100644 --- a/app/views/members/_follow_buttons.haml +++ b/app/views/members/_follow_buttons.haml @@ -1,6 +1,6 @@ - if current_member && current_member != member # must be logged in, can't follow yourself - follow = current_member.get_follow(member) - if !follow && can?(:create, Follow) # not already following - = link_to 'Follow', follows_path(followed: member), method: :post, class: 'btn btn-block' + = link_to 'Follow', follows_path(followed: member), method: :post, class: 'btn btn-block btn-success' - if follow && can?(:destroy, follow) # already following = link_to 'Unfollow', follow_path(follow), method: :delete, class: 'btn btn-block' \ No newline at end of file diff --git a/app/views/members/show.html.haml b/app/views/members/show.html.haml index 8031e151a..2560ef9ae 100644 --- a/app/views/members/show.html.haml +++ b/app/views/members/show.html.haml @@ -45,6 +45,13 @@ = render 'members/follow_buttons', member: @member + - if can?(:destroy, @member) + %hr/ + = link_to admin_member_path(slug: @member.slug), method: :delete, data: { confirm: 'Are you sure?' }, class: 'btn btn-block btn-light text-danger' do + = icon 'fas', 'ban' + Ban member + %hr/ + = render "stats", member: @member .card-footer = render "contact", member: @member, twitter_auth: @twitter_auth, diff --git a/app/views/members/show.rss.haml b/app/views/members/show.rss.haml index 075e3fafb..bb28ff632 100644 --- a/app/views/members/show.rss.haml +++ b/app/views/members/show.rss.haml @@ -3,7 +3,7 @@ %channel %title #{@member.login_name}'s recent posts (#{ENV['GROWSTUFF_SITE_NAME']}) %link= member_url(@member) - - @posts.each do |post| + - @member.posts.each do |post| %item %title #{post.subject} by #{post.author.login_name} %pubdate= post.created_at.to_s(:rfc822) diff --git a/app/views/notifications/index.html.haml b/app/views/notifications/index.html.haml index 484fe6c10..d6ac4b5b3 100644 --- a/app/views/notifications/index.html.haml +++ b/app/views/notifications/index.html.haml @@ -21,11 +21,14 @@ %strong unread = n.created_at .col-6.col-md-3.text-right - = link_to n.sender do - %h3 - = render 'members/tiny', member: n.sender - = n.sender - = render 'members/follow_buttons', member: n.sender + - if n.sender.present? + = link_to n.sender do + %h3 + = render 'members/tiny', member: n.sender + = n.sender + = render 'members/follow_buttons', member: n.sender + - else + Member deleted .card-footer = link_to 'Read', n, class: 'btn btn-primary' = link_to 'Reply', reply_link(n), class: 'btn btn-secondary' diff --git a/app/views/notifications/show.html.haml b/app/views/notifications/show.html.haml index 2303c9ea5..84a8a29f2 100644 --- a/app/views/notifications/show.html.haml +++ b/app/views/notifications/show.html.haml @@ -7,9 +7,13 @@ .card-header .card-title= @notification.subject .float-right - = link_to @notification.sender do - = @notification.sender - = render 'members/tiny', member: @notification.sender + - if @notification.sender.present? + = link_to @notification.sender do + = @notification.sender + = render 'members/tiny', member: @notification.sender + - else + Member deleted + .card-body = render @notification diff --git a/config/routes.rb b/config/routes.rb index 28b892018..008033fc1 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -109,7 +109,7 @@ Rails.application.routes.draw do get 'members/auth/:provider/callback' => 'authentications#create' scope :admin do - resources :members, controller: 'admin/members', as: 'admin_members' + resources :members, param: :slug, controller: 'admin/members', as: 'admin_members' get '/' => 'admin#index', as: 'admin' get '/newsletter' => 'admin#newsletter', as: 'admin_newsletter' comfy_route :cms_admin, path: '/cms' diff --git a/lib/tasks/growstuff.rake b/lib/tasks/growstuff.rake index 4f22214ea..d36b7bd95 100644 --- a/lib/tasks/growstuff.rake +++ b/lib/tasks/growstuff.rake @@ -3,14 +3,14 @@ namespace :growstuff do # usage: rake growstuff:admin_user name=skud task admin_user: :environment do - add_role_to_member! ENV['name'], 'admin' + add_role_to_member! ENV['name'], 'Admin' end desc "Add a crop wrangler user, by name" # usage: rake growstuff:cropwrangler_user name=skud task cropwrangler_user: :environment do - add_role_to_member! ENV['name'], 'crop-wrangler' + add_role_to_member! ENV['name'], 'Crop Wrangler' end def add_role_to_member!(login_name, role_name) diff --git a/spec/controllers/member_controller_spec.rb b/spec/controllers/member_controller_spec.rb index 173b0ff0e..87a95ccb0 100644 --- a/spec/controllers/member_controller_spec.rb +++ b/spec/controllers/member_controller_spec.rb @@ -3,7 +3,6 @@ require 'rails_helper' describe MembersController do before do @member = FactoryBot.create(:member) - @posts = [FactoryBot.create(:post, author: @member)] @twitter_auth = FactoryBot.create(:authentication, member: @member) @flickr_auth = FactoryBot.create(:flickr_authentication, member: @member) end @@ -28,11 +27,6 @@ describe MembersController do response.should be_successful end - it "assigns @posts with the member's posts" do - get :show, params: { slug: @member.to_param } - assigns(:posts).should eq(@posts) - end - it "assigns @twitter_auth" do get :show, params: { slug: @member.to_param } assigns(:twitter_auth).should eq(@twitter_auth) diff --git a/spec/features/members/ban_spec.rb b/spec/features/members/ban_spec.rb new file mode 100644 index 000000000..8eb2888e7 --- /dev/null +++ b/spec/features/members/ban_spec.rb @@ -0,0 +1,21 @@ +require 'rails_helper' + +describe "members list" do + let!(:spammer) { FactoryBot.create :member } + let!(:admin) { FactoryBot.create :admin_member } + + context 'logged in as admin' do + before do + login_as admin + visit member_path(spammer) + end + it { expect(page).to have_link "Ban member" } + describe 'bans the user' do + before do + accept_confirm { click_link 'Ban member' } + end + it { expect(page).to have_link admin.login_name } + it { expect(page).not_to have_link spammer.login_name } + end + end +end