mirror of
https://github.com/Growstuff/growstuff.git
synced 2026-05-25 09:19:15 -04:00
Compare commits
5 Commits
release84
...
refactor-h
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ee86b6b38 | ||
|
|
dc11a1674d | ||
|
|
4085014e06 | ||
|
|
18986ee133 | ||
|
|
f5a4ba60fe |
2
Gemfile
2
Gemfile
@@ -116,8 +116,6 @@ gem 'xmlrpc' # fixes rake error - can be removed if not needed later
|
||||
|
||||
gem 'puma'
|
||||
|
||||
gem 'rack-attack'
|
||||
|
||||
gem 'loofah', '>= 2.19.1'
|
||||
gem 'rack-protection', '>= 2.0.1'
|
||||
|
||||
|
||||
@@ -503,8 +503,6 @@ GEM
|
||||
query_diet (0.7.3)
|
||||
racc (1.8.1)
|
||||
rack (2.2.23)
|
||||
rack-attack (6.8.0)
|
||||
rack (>= 1.0, < 4)
|
||||
rack-cors (2.0.2)
|
||||
rack (>= 2.0.0)
|
||||
rack-protection (3.2.0)
|
||||
@@ -843,7 +841,6 @@ DEPENDENCIES
|
||||
pry
|
||||
puma
|
||||
query_diet
|
||||
rack-attack
|
||||
rack-cors
|
||||
rack-protection (>= 2.0.1)
|
||||
rails (~> 7.2.0)
|
||||
|
||||
@@ -14,12 +14,9 @@ module Charts
|
||||
|
||||
def harvested_for
|
||||
@crop = Crop.find_by!(slug: params[:crop_slug])
|
||||
data = Rails.cache.fetch("#{@crop.cache_key_with_version}/harvested_for", expires_in: 1.day) do
|
||||
Harvest.joins(:plant_part)
|
||||
.where(crop: @crop)
|
||||
.group("plant_parts.name").count(:id)
|
||||
end
|
||||
render json: data
|
||||
render json: Harvest.joins(:plant_part)
|
||||
.where(crop: @crop)
|
||||
.group("plant_parts.name").count(:id)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ApplicationMailer < ActionMailer::Base
|
||||
default from: 'from@example.com'
|
||||
default from: "Growstuff <#{Rails.configuration.x.email[:from]}>"
|
||||
layout 'mailer'
|
||||
end
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
class NotifierMailer < ApplicationMailer
|
||||
# include NotificationsHelper
|
||||
default from: "Growstuff <#{ENV.fetch('GROWSTUFF_EMAIL', nil)}>"
|
||||
default from: "Growstuff <#{Rails.configuration.x.email[:from]}>"
|
||||
|
||||
def verifier
|
||||
unless ENV['RAILS_SECRET_TOKEN']
|
||||
|
||||
@@ -196,25 +196,4 @@ class Member < ApplicationRecord
|
||||
def get_block(member)
|
||||
blocks.find_by(blocked_id: member.id) if already_blocking?(member)
|
||||
end
|
||||
|
||||
def has_activity?
|
||||
(gardens.exists? && gardens.count > 1) ||
|
||||
plantings.exists? ||
|
||||
harvests.exists? ||
|
||||
seeds.exists? ||
|
||||
photos.exists? ||
|
||||
forums.exists? ||
|
||||
activities.exists? ||
|
||||
posts.exists? ||
|
||||
comments.exists? ||
|
||||
requested_crops.exists? ||
|
||||
created_crops.exists? ||
|
||||
likes.exists? ||
|
||||
created_alternate_names.exists? ||
|
||||
created_scientific_names.exists? ||
|
||||
follows.exists? ||
|
||||
inverse_follows.exists? ||
|
||||
blocks.exists? ||
|
||||
inverse_blocks.exists?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
.form-group
|
||||
= f.label :crop_id, class: 'control-label col-md-2'
|
||||
.col-md-8
|
||||
= select(:alternate_name, :crop_id,
|
||||
Crop.order(:name).pluck(:name, :id),
|
||||
= collection_select(:alternate_name, :crop_id,
|
||||
Crop.all, :id, :name,
|
||||
{ selected: @alternate_name.crop_id || @crop.id },
|
||||
class: 'form-control')
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
|
||||
-# Only crop wranglers see the crop hierarchy (for now)
|
||||
- if can? :wrangle, @crop
|
||||
= f.select(:parent_id, Crop.order(:name).pluck(:name, :id),
|
||||
= f.collection_select(:parent_id, Crop.all.order(:name), :id, :name,
|
||||
{ include_blank: true, label: 'Parent crop'})
|
||||
%span.help-block Optional. For setting up crop hierarchies for varieties etc.
|
||||
|
||||
|
||||
@@ -73,11 +73,10 @@
|
||||
= pie_chart crop_harvested_for_path(@crop, format: :json), legend: "bottom"
|
||||
|
||||
- if @crop.varieties.any?
|
||||
- cache [@crop, 'varieties'] do
|
||||
%section.varieties
|
||||
%h2 Varieties
|
||||
.index-cards
|
||||
= render 'varieties', crop: @crop
|
||||
%section.varieties
|
||||
%h2 Varieties
|
||||
.index-cards
|
||||
= render 'varieties', crop: @crop
|
||||
|
||||
%section.crop-map
|
||||
%h2
|
||||
@@ -135,11 +134,9 @@
|
||||
= render 'harvests', crop: @crop
|
||||
= render 'find_seeds', crop: @crop
|
||||
|
||||
- cache [@crop, 'openfarm_data'] do
|
||||
= render 'openfarm_data', crop: @crop
|
||||
= render 'openfarm_data', crop: @crop
|
||||
|
||||
- cache [@crop, 'nutritional_data'] do
|
||||
= render 'nutritional_data', crop: @crop
|
||||
= render 'nutritional_data', crop: @crop
|
||||
|
||||
= cute_icon
|
||||
.card
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
.form-group
|
||||
= f.label :crop_id, class: 'control-label col-md-2'
|
||||
.col-md-8
|
||||
= select(:scientific_name, :crop_id, Crop.order(:name).pluck(:name, :id),
|
||||
{ selected: @scientific_name.crop_id || @crop.id },
|
||||
= collection_select(:scientific_name, :crop_id, Crop.all.order(:name), :id,
|
||||
:name, { selected: @scientific_name.crop_id || @crop.id },
|
||||
class: 'form-control')
|
||||
.form-group
|
||||
= f.label :name, class: 'control-label col-md-2'
|
||||
|
||||
@@ -62,9 +62,9 @@ module Growstuff
|
||||
|
||||
# Growstuff-specific configuration variables
|
||||
config.currency = 'AUD'
|
||||
config.bot_email = ENV.fetch('GROWSTUFF_EMAIL', nil)
|
||||
config.bot_email = Rails.configuration.x.email[:from]
|
||||
config.user_agent = 'Growstuff'
|
||||
config.user_agent_email = "info@growstuff.org"
|
||||
config.user_agent_email = Rails.configuration.x.email[:from]
|
||||
|
||||
Gibbon::API.api_key = ENV['GROWSTUFF_MAILCHIMP_APIKEY'] || 'notarealkey'
|
||||
# API key can't be blank or tests fail
|
||||
@@ -73,8 +73,6 @@ module Growstuff
|
||||
config.newsletter_list_id = ENV.fetch('GROWSTUFF_MAILCHIMP_NEWSLETTER_ID', nil)
|
||||
|
||||
# config.active_record.raise_in_transactional_callbacks = true
|
||||
config.middleware.insert_before 0, Rack::Attack
|
||||
|
||||
config.middleware.insert_before 0, Rack::Cors do
|
||||
allow do
|
||||
origins '*'
|
||||
|
||||
@@ -6,7 +6,7 @@ Devise.setup do |config|
|
||||
# ==> Mailer Configuration
|
||||
# Configure the e-mail address which will be shown in Devise::Mailer,
|
||||
# note that it will be overwritten if you use your own mailer class with default "from" parameter.
|
||||
config.mailer_sender = "Growstuff <#{ENV.fetch('GROWSTUFF_EMAIL', nil)}>"
|
||||
config.mailer_sender = "Growstuff <#{Rails.configuration.x.email[:from]}>"
|
||||
|
||||
config.secret_key = ENV.fetch('RAILS_SECRET_TOKEN', nil)
|
||||
|
||||
|
||||
9
config/initializers/email.rb
Normal file
9
config/initializers/email.rb
Normal file
@@ -0,0 +1,9 @@
|
||||
module Growstuff
|
||||
class Application < Rails::Application
|
||||
config.x.email = {
|
||||
from: ENV.fetch('GROWSTUFF_EMAIL', 'info@growstuff.org'),
|
||||
admin: ENV.fetch('GROWSTUFF_ADMIN_EMAIL', 'sysadmin@growstuff.org'),
|
||||
support: ENV.fetch('GROWSTUFF_SUPPORT_EMAIL', 'info@growstuff.org')
|
||||
}
|
||||
end
|
||||
end
|
||||
@@ -1,34 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Rack::Attack
|
||||
### Throttle Config ###
|
||||
|
||||
if Rails.env.production?
|
||||
# Throttle requests to /plantings, /harvests, and /members to 10 per minute per IP
|
||||
# Includes API routes
|
||||
throttle('req/ip/restricted_routes', limit: 20, period: 1.minute) do |req|
|
||||
if req.path =~ %r{^/(plantings|harvests|members)(/|$)} || req.path =~ %r{^/api/v1/(plantings|harvests|members)(/|$)}
|
||||
req.ip
|
||||
end
|
||||
end
|
||||
|
||||
### Fail2Ban Config ###
|
||||
|
||||
# Block IPs that make too many requests to suspicious paths
|
||||
# After 5 "bad" requests in 10 minutes, block the IP for 1 hour
|
||||
blocklist('fail2ban/pentesters') do |req|
|
||||
Fail2Ban.filter("pentesters-#{req.ip}", maxretry: 5, findtime: 10.minutes, bantime: 1.hour) do
|
||||
# The count for the IP is incremented if the return value is truthy.
|
||||
req.path.include?('wp-admin') ||
|
||||
req.path.include?('wp-login') ||
|
||||
req.path.include?('cgi-bin') ||
|
||||
req.path.end_with?('.php', '.asp', '.aspx', '.jsp', '.exe', '.env', '.git')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
### Custom Response Headers ###
|
||||
|
||||
# Add Retry-After header to throttled responses
|
||||
self.throttled_response_retry_after_header = true
|
||||
end
|
||||
@@ -1,33 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
namespace :members do
|
||||
desc "Remove inactive members with no activity and last login > 24 months ago"
|
||||
# usage: rake members:cleanup_inactive
|
||||
# usage: DRY_RUN=true rake members:cleanup_inactive
|
||||
task cleanup_inactive: :environment do
|
||||
limit_date = 3.years.ago
|
||||
dry_run = ENV.fetch('DRY_RUN', 'false') == 'true'
|
||||
|
||||
inactive_members = Member.where("last_sign_in_at < ? OR (last_sign_in_at IS NULL AND created_at < ?)", limit_date, limit_date)
|
||||
|
||||
count = 0
|
||||
inactive_members.find_each do |member|
|
||||
# Check for activity using the model method
|
||||
unless member.has_activity?
|
||||
if dry_run
|
||||
puts "[DRY RUN] Would delete inactive member: #{member.login_name} (ID: #{member.id}, Last login: #{member.last_sign_in_at || 'Never'}, Created: #{member.created_at})"
|
||||
else
|
||||
puts "Deleting inactive member: #{member.login_name} (ID: #{member.id}, Last login: #{member.last_sign_in_at || 'Never'}, Created: #{member.created_at})"
|
||||
member.destroy
|
||||
end
|
||||
count += 1
|
||||
end
|
||||
end
|
||||
|
||||
if dry_run
|
||||
puts "Total inactive members that would be deleted: #{count}"
|
||||
else
|
||||
puts "Total inactive members deleted: #{count}"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,68 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
require 'rake'
|
||||
|
||||
describe 'members:cleanup_inactive' do
|
||||
before :all do
|
||||
Rails.application.load_tasks
|
||||
end
|
||||
|
||||
let(:cleanup_task) { Rake::Task['members:cleanup_inactive'] }
|
||||
|
||||
before do
|
||||
cleanup_task.reenable
|
||||
end
|
||||
|
||||
it "deletes inactive members with no gardens and no other activity" do
|
||||
inactive_no_activity = create(:member, last_sign_in_at: 25.months.ago)
|
||||
|
||||
# We must explicitly remove the default garden to test the "no gardens" condition
|
||||
inactive_no_activity.gardens.destroy_all
|
||||
expect(inactive_no_activity.gardens.count).to eq(0)
|
||||
|
||||
cleanup_task.invoke
|
||||
|
||||
expect(Member.exists?(inactive_no_activity.id)).to be_falsey
|
||||
end
|
||||
|
||||
it "does not delete inactive members with a garden (even if empty)" do
|
||||
inactive_with_garden = create(:member, last_sign_in_at: 25.months.ago)
|
||||
# They have 1 default garden
|
||||
expect(inactive_with_garden.gardens.count).to eq(1)
|
||||
|
||||
cleanup_task.invoke
|
||||
|
||||
expect(Member.exists?(inactive_with_garden.id)).to be_truthy
|
||||
end
|
||||
|
||||
it "does not delete members with recent login" do
|
||||
recent_member = create(:member, last_sign_in_at: 1.month.ago)
|
||||
recent_member.gardens.destroy_all
|
||||
|
||||
cleanup_task.invoke
|
||||
|
||||
expect(Member.exists?(recent_member.id)).to be_truthy
|
||||
end
|
||||
|
||||
it "does not delete inactive members with activity (posts)" do
|
||||
inactive_with_post = create(:member, last_sign_in_at: 25.months.ago)
|
||||
inactive_with_post.gardens.destroy_all
|
||||
create(:post, author: inactive_with_post)
|
||||
|
||||
cleanup_task.invoke
|
||||
|
||||
expect(Member.exists?(inactive_with_post.id)).to be_truthy
|
||||
end
|
||||
|
||||
it "honors DRY_RUN environment variable" do
|
||||
inactive_no_activity = create(:member, last_sign_in_at: 25.months.ago)
|
||||
inactive_no_activity.gardens.destroy_all
|
||||
|
||||
ENV['DRY_RUN'] = 'true'
|
||||
cleanup_task.invoke
|
||||
ENV['DRY_RUN'] = nil
|
||||
|
||||
expect(Member.exists?(inactive_no_activity.id)).to be_truthy
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user