Compare commits

..

7 Commits

Author SHA1 Message Date
Daniel O'Connor
d57ca1b4bb Merge branch 'dev' into fix-3278 2024-07-23 19:44:09 +09:30
Daniel O'Connor
dc4133abd2 Merge branch 'dev' into fix-3278 2024-07-17 20:06:48 +09:30
Daniel O'Connor
0b4bdc6946 Re-add expectation 2024-07-13 09:55:06 +00:00
Daniel O'Connor
3d308db0d9 'Only required for wrangers, and only when approving 2024-07-13 09:54:31 +00:00
Daniel O'Connor
bfa1ae3ae2 Require a name 2024-07-13 09:42:20 +00:00
Daniel O'Connor
71ef2c058b Require a URL 2024-07-13 09:41:35 +00:00
Daniel O'Connor
b42385be14 Fix #3278 by ensuring we rebuild names on error 2024-07-13 09:39:58 +00:00
512 changed files with 7007 additions and 17437 deletions

47
.codeclimate.yml Normal file
View File

@@ -0,0 +1,47 @@
plugins:
brakeman:
enabled: false # codeclimate's brakeman is stuck in rails 5 rules
bundler-audit:
enabled: true
coffeelint:
enabled: true
duplication:
enabled: true
config:
languages:
- ruby
- javascript
editorconfig:
enabled: true
eslint:
enabled: true
fixme:
enabled: true
haml-lint:
enabled: true
nodesecurity:
enabled: true
rubocop:
enabled: true
channel: "rubocop-1-11"
scss-lint:
enabled: true
shellcheck:
enabled: true
ratings:
paths:
- "**.rb"
- "**.ru"
- "**.js"
- "**.coffee"
- "**.scss"
- "**.haml"
- Gemfile.lock
exclude_paths:
- config/
- db/
- spec/
- public/
- app/assets/stylesheets/bootstrap-accessibility.css
- app/assets/javascripts/bootstrap*
- app/assets/stylesheets/leaflet_overrides.scss

View File

@@ -1,4 +1,4 @@
FROM mcr.microsoft.com/devcontainers/ruby:3.4-trixie FROM mcr.microsoft.com/devcontainers/ruby:1-3.3-bullseye
# Install Rails # Install Rails
RUN gem install rails:7.0.8 RUN gem install rails:7.0.8

View File

@@ -27,7 +27,7 @@ services:
command: sleep infinity command: sleep infinity
db: db:
image: postgres:17 image: postgres:latest
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- postgres-data:/var/lib/postgresql/data - postgres-data:/var/lib/postgresql/data

View File

@@ -1,30 +0,0 @@
.git
.github
.devcontainer
log/*
tmp/*
!tmp/keep
node_modules
public/assets
.env
.ruby-gemset
.editorconfig
.esignore
.eslintrc.json
.haml-lint.yml
.overcommit.yml
.rspec
.rubocop.yml
.rubocop_todo.yml
.scss-lint.yml
.travis.yml
.yamllint
CODE_OF_CONDUCT.md
CONTRIBUTING.md
CONTRIBUTORS.md
LICENSE.txt
README.md
TECH.md
docker-compose.yml
Dockerfile
.dockerignore

1
.github/FUNDING.yml vendored
View File

@@ -1 +0,0 @@
ko_fi: jennyscottthompson

View File

@@ -13,4 +13,3 @@ updates:
interval: daily interval: daily
time: "07:00" time: "07:00"
open-pull-requests-limit: 10 open-pull-requests-limit: 10

40
.github/workflows/brakeman-analysis.yml vendored Normal file
View File

@@ -0,0 +1,40 @@
# This workflow integrates Brakeman with GitHub's Code Scanning feature
# Brakeman is a static analysis security vulnerability scanner for Ruby on Rails applications
name: Brakeman Scan
# This section configures the trigger for the workflow. Feel free to customize depending on your convention
on:
pull_request:
branches: [ dev ]
jobs:
brakeman-scan:
name: Brakeman Scan
runs-on: ubuntu-latest
steps:
# Checkout the repository to the GitHub Actions runner
- name: Checkout
uses: actions/checkout@v4
# Customize the ruby version depending on your needs
- name: Setup Ruby
uses: ruby/setup-ruby@v1
- name: Setup Brakeman
env:
BRAKEMAN_VERSION: '5.1.1' # SARIF support is provided in Brakeman version 4.10+
run: |
gem install brakeman --version $BRAKEMAN_VERSION
# Execute Brakeman CLI and generate a SARIF output with the security issues identified during the analysis
- name: Scan
continue-on-error: true
run: |
brakeman -f sarif -o output.sarif.json .
# Upload the SARIF file generated in the previous step
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: output.sarif.json

View File

@@ -1,109 +0,0 @@
name: CI Features - Admin
on: [pull_request]
jobs:
rspec:
runs-on: ubuntu-latest
services:
db:
image: postgres
env:
##
# The Postgres service fails its docker health check unless you
# specify these environment variables
#
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: growstuff_test
ports: ['5432:5432']
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
APP_DOMAIN_NAME: localhost:3000
APP_PROTOCOL: http
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
DATABASE_URL: postgres://postgres:postgres@localhost:5432/growstuff_test
DEVISE_SECRET_KEY: secret
ELASTIC_SEARCH_VERSION: "7.5.1-amd64"
GROWSTUFF_EMAIL: "noreply@test.growstuff.org"
GROWSTUFF_FLICKR_KEY: secretkey"
GROWSTUFF_FLICKR_SECRET: secretsecret
GROWSTUFF_SITE_NAME: "Growstuff (travis)"
RAILS_ENV: test
RAILS_SECRET_TOKEN: supersecret
steps:
- name: Checkout this repo
uses: actions/checkout@v6
- name: Configure sysctl limits
run: |
sudo swapoff -a
sudo sysctl -w vm.swappiness=1
sudo sysctl -w fs.file-max=262144
sudo sysctl -w vm.max_map_count=262144
- name: Start Elasticsearch
uses: elastic/elastic-github-actions/elasticsearch@master
with:
stack-version: 7.5.1
##
# Cache Yarn modules
#
# See https://github.com/actions/cache/blob/master/examples.md#node---yarn for details
#
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Setup yarn cache
uses: actions/cache@v5
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install required OS packages
run: |
sudo apt-get -y install libpq-dev google-chrome-stable
- name: Install NodeJS
uses: actions/setup-node@v6
with:
node-version: '24'
- name: Install Ruby (version given by .ruby-version) and Bundler
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Install required JS packages
run: yarn install
- name: install chrome
run: sudo apt-get install google-chrome-stable
- name: Prepare database for testing
run: bundle exec rails db:prepare
- name: precompile assets
run: bundle exec rails assets:precompile
- name: index into elastic search
run: bundle exec rails search:reindex
- name: Run rspec (admin/)
run: bundle exec rspec spec/features/admin/ -fd -t ~@flaky
- name: Upload screenshots
if: failure()
uses: actions/upload-artifact@v7
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,109 +0,0 @@
name: CI Features - Comments
on: [pull_request]
jobs:
rspec:
runs-on: ubuntu-latest
services:
db:
image: postgres
env:
##
# The Postgres service fails its docker health check unless you
# specify these environment variables
#
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: growstuff_test
ports: ['5432:5432']
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
APP_DOMAIN_NAME: localhost:3000
APP_PROTOCOL: http
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
DATABASE_URL: postgres://postgres:postgres@localhost:5432/growstuff_test
DEVISE_SECRET_KEY: secret
ELASTIC_SEARCH_VERSION: "7.5.1-amd64"
GROWSTUFF_EMAIL: "noreply@test.growstuff.org"
GROWSTUFF_FLICKR_KEY: secretkey"
GROWSTUFF_FLICKR_SECRET: secretsecret
GROWSTUFF_SITE_NAME: "Growstuff (travis)"
RAILS_ENV: test
RAILS_SECRET_TOKEN: supersecret
steps:
- name: Checkout this repo
uses: actions/checkout@v6
- name: Configure sysctl limits
run: |
sudo swapoff -a
sudo sysctl -w vm.swappiness=1
sudo sysctl -w fs.file-max=262144
sudo sysctl -w vm.max_map_count=262144
- name: Start Elasticsearch
uses: elastic/elastic-github-actions/elasticsearch@master
with:
stack-version: 7.5.1
##
# Cache Yarn modules
#
# See https://github.com/actions/cache/blob/master/examples.md#node---yarn for details
#
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Setup yarn cache
uses: actions/cache@v5
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install required OS packages
run: |
sudo apt-get -y install libpq-dev google-chrome-stable
- name: Install NodeJS
uses: actions/setup-node@v6
with:
node-version: '24'
- name: Install Ruby (version given by .ruby-version) and Bundler
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Install required JS packages
run: yarn install
- name: install chrome
run: sudo apt-get install google-chrome-stable
- name: Prepare database for testing
run: bundle exec rails db:prepare
- name: precompile assets
run: bundle exec rails assets:precompile
- name: index into elastic search
run: bundle exec rails search:reindex
- name: Run rspec (comments/)
run: bundle exec rspec spec/features/comments/ -fd -t ~@flaky
- name: Upload screenshots
if: failure()
uses: actions/upload-artifact@v7
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,109 +0,0 @@
name: CI Features - Conversations
on: [pull_request]
jobs:
rspec:
runs-on: ubuntu-latest
services:
db:
image: postgres
env:
##
# The Postgres service fails its docker health check unless you
# specify these environment variables
#
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: growstuff_test
ports: ['5432:5432']
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
APP_DOMAIN_NAME: localhost:3000
APP_PROTOCOL: http
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
DATABASE_URL: postgres://postgres:postgres@localhost:5432/growstuff_test
DEVISE_SECRET_KEY: secret
ELASTIC_SEARCH_VERSION: "7.5.1-amd64"
GROWSTUFF_EMAIL: "noreply@test.growstuff.org"
GROWSTUFF_FLICKR_KEY: secretkey"
GROWSTUFF_FLICKR_SECRET: secretsecret
GROWSTUFF_SITE_NAME: "Growstuff (travis)"
RAILS_ENV: test
RAILS_SECRET_TOKEN: supersecret
steps:
- name: Checkout this repo
uses: actions/checkout@v6
- name: Configure sysctl limits
run: |
sudo swapoff -a
sudo sysctl -w vm.swappiness=1
sudo sysctl -w fs.file-max=262144
sudo sysctl -w vm.max_map_count=262144
- name: Start Elasticsearch
uses: elastic/elastic-github-actions/elasticsearch@master
with:
stack-version: 7.5.1
##
# Cache Yarn modules
#
# See https://github.com/actions/cache/blob/master/examples.md#node---yarn for details
#
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Setup yarn cache
uses: actions/cache@v5
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install required OS packages
run: |
sudo apt-get -y install libpq-dev google-chrome-stable
- name: Install NodeJS
uses: actions/setup-node@v6
with:
node-version: '24'
- name: Install Ruby (version given by .ruby-version) and Bundler
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Install required JS packages
run: yarn install
- name: install chrome
run: sudo apt-get install google-chrome-stable
- name: Prepare database for testing
run: bundle exec rails db:prepare
- name: precompile assets
run: bundle exec rails assets:precompile
- name: index into elastic search
run: bundle exec rails search:reindex
- name: Run rspec (conversations/)
run: bundle exec rspec spec/features/conversations/ -fd -t ~@flaky
- name: Upload screenshots
if: failure()
uses: actions/upload-artifact@v7
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,109 +0,0 @@
name: CI Features - Crops
on: [pull_request]
jobs:
rspec:
runs-on: ubuntu-latest
services:
db:
image: postgres
env:
##
# The Postgres service fails its docker health check unless you
# specify these environment variables
#
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: growstuff_test
ports: ['5432:5432']
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
APP_DOMAIN_NAME: localhost:3000
APP_PROTOCOL: http
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
DATABASE_URL: postgres://postgres:postgres@localhost:5432/growstuff_test
DEVISE_SECRET_KEY: secret
ELASTIC_SEARCH_VERSION: "7.5.1-amd64"
GROWSTUFF_EMAIL: "noreply@test.growstuff.org"
GROWSTUFF_FLICKR_KEY: secretkey"
GROWSTUFF_FLICKR_SECRET: secretsecret
GROWSTUFF_SITE_NAME: "Growstuff (travis)"
RAILS_ENV: test
RAILS_SECRET_TOKEN: supersecret
steps:
- name: Checkout this repo
uses: actions/checkout@v6
- name: Configure sysctl limits
run: |
sudo swapoff -a
sudo sysctl -w vm.swappiness=1
sudo sysctl -w fs.file-max=262144
sudo sysctl -w vm.max_map_count=262144
- name: Start Elasticsearch
uses: elastic/elastic-github-actions/elasticsearch@master
with:
stack-version: 7.5.1
##
# Cache Yarn modules
#
# See https://github.com/actions/cache/blob/master/examples.md#node---yarn for details
#
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Setup yarn cache
uses: actions/cache@v5
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install required OS packages
run: |
sudo apt-get -y install libpq-dev google-chrome-stable
- name: Install NodeJS
uses: actions/setup-node@v6
with:
node-version: '24'
- name: Install Ruby (version given by .ruby-version) and Bundler
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Install required JS packages
run: yarn install
- name: install chrome
run: sudo apt-get install google-chrome-stable
- name: Prepare database for testing
run: bundle exec rails db:prepare
- name: precompile assets
run: bundle exec rails assets:precompile
- name: index into elastic search
run: bundle exec rails search:reindex
- name: Run rspec (crops/)
run: bundle exec rspec spec/features/crops/ -fd -t ~@flaky
- name: Upload screenshots
if: failure()
uses: actions/upload-artifact@v7
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,109 +0,0 @@
name: CI Features - Gardens
on: [pull_request]
jobs:
rspec:
runs-on: ubuntu-latest
services:
db:
image: postgres
env:
##
# The Postgres service fails its docker health check unless you
# specify these environment variables
#
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: growstuff_test
ports: ['5432:5432']
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
APP_DOMAIN_NAME: localhost:3000
APP_PROTOCOL: http
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
DATABASE_URL: postgres://postgres:postgres@localhost:5432/growstuff_test
DEVISE_SECRET_KEY: secret
ELASTIC_SEARCH_VERSION: "7.5.1-amd64"
GROWSTUFF_EMAIL: "noreply@test.growstuff.org"
GROWSTUFF_FLICKR_KEY: secretkey"
GROWSTUFF_FLICKR_SECRET: secretsecret
GROWSTUFF_SITE_NAME: "Growstuff (travis)"
RAILS_ENV: test
RAILS_SECRET_TOKEN: supersecret
steps:
- name: Checkout this repo
uses: actions/checkout@v6
- name: Configure sysctl limits
run: |
sudo swapoff -a
sudo sysctl -w vm.swappiness=1
sudo sysctl -w fs.file-max=262144
sudo sysctl -w vm.max_map_count=262144
- name: Start Elasticsearch
uses: elastic/elastic-github-actions/elasticsearch@master
with:
stack-version: 7.5.1
##
# Cache Yarn modules
#
# See https://github.com/actions/cache/blob/master/examples.md#node---yarn for details
#
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Setup yarn cache
uses: actions/cache@v5
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install required OS packages
run: |
sudo apt-get -y install libpq-dev google-chrome-stable
- name: Install NodeJS
uses: actions/setup-node@v6
with:
node-version: '24'
- name: Install Ruby (version given by .ruby-version) and Bundler
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Install required JS packages
run: yarn install
- name: install chrome
run: sudo apt-get install google-chrome-stable
- name: Prepare database for testing
run: bundle exec rails db:prepare
- name: precompile assets
run: bundle exec rails assets:precompile
- name: index into elastic search
run: bundle exec rails search:reindex
- name: Run rspec (gardens/)
run: bundle exec rspec spec/features/gardens/ -fd -t ~@flaky
- name: Upload screenshots
if: failure()
uses: actions/upload-artifact@v7
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,109 +0,0 @@
name: CI Features - Harvests
on: [pull_request]
jobs:
rspec:
runs-on: ubuntu-latest
services:
db:
image: postgres
env:
##
# The Postgres service fails its docker health check unless you
# specify these environment variables
#
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: growstuff_test
ports: ['5432:5432']
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
APP_DOMAIN_NAME: localhost:3000
APP_PROTOCOL: http
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
DATABASE_URL: postgres://postgres:postgres@localhost:5432/growstuff_test
DEVISE_SECRET_KEY: secret
ELASTIC_SEARCH_VERSION: "7.5.1-amd64"
GROWSTUFF_EMAIL: "noreply@test.growstuff.org"
GROWSTUFF_FLICKR_KEY: secretkey"
GROWSTUFF_FLICKR_SECRET: secretsecret
GROWSTUFF_SITE_NAME: "Growstuff (travis)"
RAILS_ENV: test
RAILS_SECRET_TOKEN: supersecret
steps:
- name: Checkout this repo
uses: actions/checkout@v6
- name: Configure sysctl limits
run: |
sudo swapoff -a
sudo sysctl -w vm.swappiness=1
sudo sysctl -w fs.file-max=262144
sudo sysctl -w vm.max_map_count=262144
- name: Start Elasticsearch
uses: elastic/elastic-github-actions/elasticsearch@master
with:
stack-version: 7.5.1
##
# Cache Yarn modules
#
# See https://github.com/actions/cache/blob/master/examples.md#node---yarn for details
#
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Setup yarn cache
uses: actions/cache@v5
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install required OS packages
run: |
sudo apt-get -y install libpq-dev google-chrome-stable
- name: Install NodeJS
uses: actions/setup-node@v6
with:
node-version: '24'
- name: Install Ruby (version given by .ruby-version) and Bundler
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Install required JS packages
run: yarn install
- name: install chrome
run: sudo apt-get install google-chrome-stable
- name: Prepare database for testing
run: bundle exec rails db:prepare
- name: precompile assets
run: bundle exec rails assets:precompile
- name: index into elastic search
run: bundle exec rails search:reindex
- name: Run rspec (harvests/)
run: bundle exec rspec spec/features/harvests/ -fd -t ~@flaky
- name: Upload screenshots
if: failure()
uses: actions/upload-artifact@v7
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,109 +0,0 @@
name: CI Features - Home
on: [pull_request]
jobs:
rspec:
runs-on: ubuntu-latest
services:
db:
image: postgres
env:
##
# The Postgres service fails its docker health check unless you
# specify these environment variables
#
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: growstuff_test
ports: ['5432:5432']
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
APP_DOMAIN_NAME: localhost:3000
APP_PROTOCOL: http
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
DATABASE_URL: postgres://postgres:postgres@localhost:5432/growstuff_test
DEVISE_SECRET_KEY: secret
ELASTIC_SEARCH_VERSION: "7.5.1-amd64"
GROWSTUFF_EMAIL: "noreply@test.growstuff.org"
GROWSTUFF_FLICKR_KEY: secretkey"
GROWSTUFF_FLICKR_SECRET: secretsecret
GROWSTUFF_SITE_NAME: "Growstuff (travis)"
RAILS_ENV: test
RAILS_SECRET_TOKEN: supersecret
steps:
- name: Checkout this repo
uses: actions/checkout@v6
- name: Configure sysctl limits
run: |
sudo swapoff -a
sudo sysctl -w vm.swappiness=1
sudo sysctl -w fs.file-max=262144
sudo sysctl -w vm.max_map_count=262144
- name: Start Elasticsearch
uses: elastic/elastic-github-actions/elasticsearch@master
with:
stack-version: 7.5.1
##
# Cache Yarn modules
#
# See https://github.com/actions/cache/blob/master/examples.md#node---yarn for details
#
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Setup yarn cache
uses: actions/cache@v5
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install required OS packages
run: |
sudo apt-get -y install libpq-dev google-chrome-stable
- name: Install NodeJS
uses: actions/setup-node@v6
with:
node-version: '24'
- name: Install Ruby (version given by .ruby-version) and Bundler
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Install required JS packages
run: yarn install
- name: install chrome
run: sudo apt-get install google-chrome-stable
- name: Prepare database for testing
run: bundle exec rails db:prepare
- name: precompile assets
run: bundle exec rails assets:precompile
- name: index into elastic search
run: bundle exec rails search:reindex
- name: Run rspec (home/)
run: bundle exec rspec spec/features/home/ -fd -t ~@flaky
- name: Upload screenshots
if: failure()
uses: actions/upload-artifact@v7
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,109 +0,0 @@
name: CI Features - Members
on: [pull_request]
jobs:
rspec:
runs-on: ubuntu-latest
services:
db:
image: postgres
env:
##
# The Postgres service fails its docker health check unless you
# specify these environment variables
#
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: growstuff_test
ports: ['5432:5432']
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
APP_DOMAIN_NAME: localhost:3000
APP_PROTOCOL: http
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
DATABASE_URL: postgres://postgres:postgres@localhost:5432/growstuff_test
DEVISE_SECRET_KEY: secret
ELASTIC_SEARCH_VERSION: "7.5.1-amd64"
GROWSTUFF_EMAIL: "noreply@test.growstuff.org"
GROWSTUFF_FLICKR_KEY: secretkey"
GROWSTUFF_FLICKR_SECRET: secretsecret
GROWSTUFF_SITE_NAME: "Growstuff (travis)"
RAILS_ENV: test
RAILS_SECRET_TOKEN: supersecret
steps:
- name: Checkout this repo
uses: actions/checkout@v6
- name: Configure sysctl limits
run: |
sudo swapoff -a
sudo sysctl -w vm.swappiness=1
sudo sysctl -w fs.file-max=262144
sudo sysctl -w vm.max_map_count=262144
- name: Start Elasticsearch
uses: elastic/elastic-github-actions/elasticsearch@master
with:
stack-version: 7.5.1
##
# Cache Yarn modules
#
# See https://github.com/actions/cache/blob/master/examples.md#node---yarn for details
#
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Setup yarn cache
uses: actions/cache@v5
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install required OS packages
run: |
sudo apt-get -y install libpq-dev google-chrome-stable
- name: Install NodeJS
uses: actions/setup-node@v6
with:
node-version: '24'
- name: Install Ruby (version given by .ruby-version) and Bundler
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Install required JS packages
run: yarn install
- name: install chrome
run: sudo apt-get install google-chrome-stable
- name: Prepare database for testing
run: bundle exec rails db:prepare
- name: precompile assets
run: bundle exec rails assets:precompile
- name: index into elastic search
run: bundle exec rails search:reindex
- name: Run rspec (members/)
run: bundle exec rspec spec/features/members/ -fd -t ~@flaky
- name: Upload screenshots
if: failure()
uses: actions/upload-artifact@v7
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,109 +0,0 @@
name: CI Features - Admin
on: [pull_request]
jobs:
rspec:
runs-on: ubuntu-latest
services:
db:
image: postgres
env:
##
# The Postgres service fails its docker health check unless you
# specify these environment variables
#
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: growstuff_test
ports: ['5432:5432']
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
APP_DOMAIN_NAME: localhost:3000
APP_PROTOCOL: http
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
DATABASE_URL: postgres://postgres:postgres@localhost:5432/growstuff_test
DEVISE_SECRET_KEY: secret
ELASTIC_SEARCH_VERSION: "7.5.1-amd64"
GROWSTUFF_EMAIL: "noreply@test.growstuff.org"
GROWSTUFF_FLICKR_KEY: secretkey"
GROWSTUFF_FLICKR_SECRET: secretsecret
GROWSTUFF_SITE_NAME: "Growstuff (travis)"
RAILS_ENV: test
RAILS_SECRET_TOKEN: supersecret
steps:
- name: Checkout this repo
uses: actions/checkout@v6
- name: Configure sysctl limits
run: |
sudo swapoff -a
sudo sysctl -w vm.swappiness=1
sudo sysctl -w fs.file-max=262144
sudo sysctl -w vm.max_map_count=262144
- name: Start Elasticsearch
uses: elastic/elastic-github-actions/elasticsearch@master
with:
stack-version: 7.5.1
##
# Cache Yarn modules
#
# See https://github.com/actions/cache/blob/master/examples.md#node---yarn for details
#
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Setup yarn cache
uses: actions/cache@v5
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install required OS packages
run: |
sudo apt-get -y install libpq-dev google-chrome-stable
- name: Install NodeJS
uses: actions/setup-node@v6
with:
node-version: '24'
- name: Install Ruby (version given by .ruby-version) and Bundler
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Install required JS packages
run: yarn install
- name: install chrome
run: sudo apt-get install google-chrome-stable
- name: Prepare database for testing
run: bundle exec rails db:prepare
- name: precompile assets
run: bundle exec rails assets:precompile
- name: index into elastic search
run: bundle exec rails search:reindex
- name: Run rspec (places/)
run: bundle exec rspec spec/features/places/ -fd
- name: Upload screenshots
if: failure()
uses: actions/upload-artifact@v7
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,109 +0,0 @@
name: CI Features - Plantings
on: [pull_request]
jobs:
rspec:
runs-on: ubuntu-latest
services:
db:
image: postgres
env:
##
# The Postgres service fails its docker health check unless you
# specify these environment variables
#
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: growstuff_test
ports: ['5432:5432']
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
APP_DOMAIN_NAME: localhost:3000
APP_PROTOCOL: http
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
DATABASE_URL: postgres://postgres:postgres@localhost:5432/growstuff_test
DEVISE_SECRET_KEY: secret
ELASTIC_SEARCH_VERSION: "7.5.1-amd64"
GROWSTUFF_EMAIL: "noreply@test.growstuff.org"
GROWSTUFF_FLICKR_KEY: secretkey"
GROWSTUFF_FLICKR_SECRET: secretsecret
GROWSTUFF_SITE_NAME: "Growstuff (travis)"
RAILS_ENV: test
RAILS_SECRET_TOKEN: supersecret
steps:
- name: Checkout this repo
uses: actions/checkout@v6
- name: Configure sysctl limits
run: |
sudo swapoff -a
sudo sysctl -w vm.swappiness=1
sudo sysctl -w fs.file-max=262144
sudo sysctl -w vm.max_map_count=262144
- name: Start Elasticsearch
uses: elastic/elastic-github-actions/elasticsearch@master
with:
stack-version: 7.5.1
##
# Cache Yarn modules
#
# See https://github.com/actions/cache/blob/master/examples.md#node---yarn for details
#
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Setup yarn cache
uses: actions/cache@v5
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install required OS packages
run: |
sudo apt-get -y install libpq-dev google-chrome-stable
- name: Install NodeJS
uses: actions/setup-node@v6
with:
node-version: '24'
- name: Install Ruby (version given by .ruby-version) and Bundler
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Install required JS packages
run: yarn install
- name: install chrome
run: sudo apt-get install google-chrome-stable
- name: Prepare database for testing
run: bundle exec rails db:prepare
- name: precompile assets
run: bundle exec rails assets:precompile
- name: index into elastic search
run: bundle exec rails search:reindex
- name: Run rspec (plantings/)
run: bundle exec rspec spec/features/plantings/ -fd
- name: Upload screenshots
if: failure()
uses: actions/upload-artifact@v7
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,109 +0,0 @@
name: CI Features - Posts
on: [pull_request]
jobs:
rspec:
runs-on: ubuntu-latest
services:
db:
image: postgres
env:
##
# The Postgres service fails its docker health check unless you
# specify these environment variables
#
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: growstuff_test
ports: ['5432:5432']
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
APP_DOMAIN_NAME: localhost:3000
APP_PROTOCOL: http
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
DATABASE_URL: postgres://postgres:postgres@localhost:5432/growstuff_test
DEVISE_SECRET_KEY: secret
ELASTIC_SEARCH_VERSION: "7.5.1-amd64"
GROWSTUFF_EMAIL: "noreply@test.growstuff.org"
GROWSTUFF_FLICKR_KEY: secretkey"
GROWSTUFF_FLICKR_SECRET: secretsecret
GROWSTUFF_SITE_NAME: "Growstuff (travis)"
RAILS_ENV: test
RAILS_SECRET_TOKEN: supersecret
steps:
- name: Checkout this repo
uses: actions/checkout@v6
- name: Configure sysctl limits
run: |
sudo swapoff -a
sudo sysctl -w vm.swappiness=1
sudo sysctl -w fs.file-max=262144
sudo sysctl -w vm.max_map_count=262144
- name: Start Elasticsearch
uses: elastic/elastic-github-actions/elasticsearch@master
with:
stack-version: 7.5.1
##
# Cache Yarn modules
#
# See https://github.com/actions/cache/blob/master/examples.md#node---yarn for details
#
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Setup yarn cache
uses: actions/cache@v5
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install required OS packages
run: |
sudo apt-get -y install libpq-dev google-chrome-stable
- name: Install NodeJS
uses: actions/setup-node@v6
with:
node-version: '24'
- name: Install Ruby (version given by .ruby-version) and Bundler
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Install required JS packages
run: yarn install
- name: install chrome
run: sudo apt-get install google-chrome-stable
- name: Prepare database for testing
run: bundle exec rails db:prepare
- name: precompile assets
run: bundle exec rails assets:precompile
- name: index into elastic search
run: bundle exec rails search:reindex
- name: Run rspec (posts/)
run: bundle exec rspec spec/features/posts/ -fd
- name: Upload screenshots
if: failure()
uses: actions/upload-artifact@v7
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,109 +0,0 @@
name: CI Features - Seeds
on: [pull_request]
jobs:
rspec:
runs-on: ubuntu-latest
services:
db:
image: postgres
env:
##
# The Postgres service fails its docker health check unless you
# specify these environment variables
#
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: growstuff_test
ports: ['5432:5432']
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
APP_DOMAIN_NAME: localhost:3000
APP_PROTOCOL: http
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
DATABASE_URL: postgres://postgres:postgres@localhost:5432/growstuff_test
DEVISE_SECRET_KEY: secret
ELASTIC_SEARCH_VERSION: "7.5.1-amd64"
GROWSTUFF_EMAIL: "noreply@test.growstuff.org"
GROWSTUFF_FLICKR_KEY: secretkey"
GROWSTUFF_FLICKR_SECRET: secretsecret
GROWSTUFF_SITE_NAME: "Growstuff (travis)"
RAILS_ENV: test
RAILS_SECRET_TOKEN: supersecret
steps:
- name: Checkout this repo
uses: actions/checkout@v6
- name: Configure sysctl limits
run: |
sudo swapoff -a
sudo sysctl -w vm.swappiness=1
sudo sysctl -w fs.file-max=262144
sudo sysctl -w vm.max_map_count=262144
- name: Start Elasticsearch
uses: elastic/elastic-github-actions/elasticsearch@master
with:
stack-version: 7.5.1
##
# Cache Yarn modules
#
# See https://github.com/actions/cache/blob/master/examples.md#node---yarn for details
#
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Setup yarn cache
uses: actions/cache@v5
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install required OS packages
run: |
sudo apt-get -y install libpq-dev google-chrome-stable
- name: Install NodeJS
uses: actions/setup-node@v6
with:
node-version: '24'
- name: Install Ruby (version given by .ruby-version) and Bundler
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Install required JS packages
run: yarn install
- name: install chrome
run: sudo apt-get install google-chrome-stable
- name: Prepare database for testing
run: bundle exec rails db:prepare
- name: precompile assets
run: bundle exec rails assets:precompile
- name: index into elastic search
run: bundle exec rails search:reindex
- name: Run rspec (seeds/)
run: bundle exec rspec spec/features/seeds/ -fd -t ~@flaky
- name: Upload screenshots
if: failure()
uses: actions/upload-artifact@v7
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,109 +0,0 @@
name: CI Features - Timeline
on: [pull_request]
jobs:
rspec:
runs-on: ubuntu-latest
services:
db:
image: postgres
env:
##
# The Postgres service fails its docker health check unless you
# specify these environment variables
#
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: growstuff_test
ports: ['5432:5432']
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
APP_DOMAIN_NAME: localhost:3000
APP_PROTOCOL: http
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
DATABASE_URL: postgres://postgres:postgres@localhost:5432/growstuff_test
DEVISE_SECRET_KEY: secret
ELASTIC_SEARCH_VERSION: "7.5.1-amd64"
GROWSTUFF_EMAIL: "noreply@test.growstuff.org"
GROWSTUFF_FLICKR_KEY: secretkey"
GROWSTUFF_FLICKR_SECRET: secretsecret
GROWSTUFF_SITE_NAME: "Growstuff (travis)"
RAILS_ENV: test
RAILS_SECRET_TOKEN: supersecret
steps:
- name: Checkout this repo
uses: actions/checkout@v6
- name: Configure sysctl limits
run: |
sudo swapoff -a
sudo sysctl -w vm.swappiness=1
sudo sysctl -w fs.file-max=262144
sudo sysctl -w vm.max_map_count=262144
- name: Start Elasticsearch
uses: elastic/elastic-github-actions/elasticsearch@master
with:
stack-version: 7.5.1
##
# Cache Yarn modules
#
# See https://github.com/actions/cache/blob/master/examples.md#node---yarn for details
#
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Setup yarn cache
uses: actions/cache@v5
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install required OS packages
run: |
sudo apt-get -y install libpq-dev google-chrome-stable
- name: Install NodeJS
uses: actions/setup-node@v6
with:
node-version: '24'
- name: Install Ruby (version given by .ruby-version) and Bundler
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Install required JS packages
run: yarn install
- name: install chrome
run: sudo apt-get install google-chrome-stable
- name: Prepare database for testing
run: bundle exec rails db:prepare
- name: precompile assets
run: bundle exec rails assets:precompile
- name: index into elastic search
run: bundle exec rails search:reindex
- name: Run rspec (timeline/)
run: bundle exec rspec spec/features/timeline/ -fd -t ~@flaky
- name: Upload screenshots
if: failure()
uses: actions/upload-artifact@v7
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,118 +0,0 @@
name: CI Features
on: [pull_request]
jobs:
rspec:
runs-on: ubuntu-latest
services:
db:
image: postgres
env:
##
# The Postgres service fails its docker health check unless you
# specify these environment variables
#
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: growstuff_test
ports: ['5432:5432']
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
APP_DOMAIN_NAME: localhost:3000
APP_PROTOCOL: http
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
DATABASE_URL: postgres://postgres:postgres@localhost:5432/growstuff_test
DEVISE_SECRET_KEY: secret
ELASTIC_SEARCH_VERSION: "7.5.1-amd64"
GROWSTUFF_EMAIL: "noreply@test.growstuff.org"
GROWSTUFF_FLICKR_KEY: secretkey"
GROWSTUFF_FLICKR_SECRET: secretsecret
GROWSTUFF_SITE_NAME: "Growstuff (travis)"
RAILS_ENV: test
RAILS_SECRET_TOKEN: supersecret
steps:
- name: Checkout this repo
uses: actions/checkout@v6
- name: Configure sysctl limits
run: |
sudo swapoff -a
sudo sysctl -w vm.swappiness=1
sudo sysctl -w fs.file-max=262144
sudo sysctl -w vm.max_map_count=262144
- name: Start Elasticsearch
uses: elastic/elastic-github-actions/elasticsearch@master
with:
stack-version: 7.5.1
##
# Cache Yarn modules
#
# See https://github.com/actions/cache/blob/master/examples.md#node---yarn for details
#
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Setup yarn cache
uses: actions/cache@v5
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install required OS packages
run: |
sudo apt-get -y install libpq-dev google-chrome-stable
- name: Install NodeJS
uses: actions/setup-node@v6
with:
node-version: '24'
- name: Install Ruby (version given by .ruby-version) and Bundler
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Install required JS packages
run: yarn install
- name: install chrome
run: sudo apt-get install google-chrome-stable
- name: Prepare database for testing
run: bundle exec rails db:prepare
- name: precompile assets
run: bundle exec rails assets:precompile
- name: index into elastic search
run: bundle exec rails search:reindex
- name: Run rspec (*_spec)
run: bundle exec rspec spec/features/*_spec.rb -fd
- name: Run rspec (percy/)
run: bundle exec rspec spec/features/percy/ -fd
- name: Run rspec (photos/)
run: bundle exec rspec spec/features/photos/ -fd
- name: Run rspec (rss/)
run: bundle exec rspec spec/features/rss/ -fd
- name: Upload screenshots
if: failure()
uses: actions/upload-artifact@v7
with:
name: screenshots
path: tmp/screenshots

View File

@@ -6,7 +6,7 @@ jobs:
contributors: contributors:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v4
- name: Install ruby version specified in .ruby-version - name: Install ruby version specified in .ruby-version
uses: ruby/setup-ruby@v1 uses: ruby/setup-ruby@v1
with: with:
@@ -53,7 +53,7 @@ jobs:
steps: steps:
- name: Checkout this repo - name: Checkout this repo
uses: actions/checkout@v6 uses: actions/checkout@v4
- name: Configure sysctl limits - name: Configure sysctl limits
run: | run: |
@@ -76,7 +76,7 @@ jobs:
id: yarn-cache-dir-path id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)" run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Setup yarn cache - name: Setup yarn cache
uses: actions/cache@v5 uses: actions/cache@v4
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with: with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }} path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
@@ -89,9 +89,9 @@ jobs:
sudo apt-get -y install libpq-dev google-chrome-stable sudo apt-get -y install libpq-dev google-chrome-stable
- name: Install NodeJS - name: Install NodeJS
uses: actions/setup-node@v6 uses: actions/setup-node@v4
with: with:
node-version: '24' node-version: '12'
- name: Install Ruby (version given by .ruby-version) and Bundler - name: Install Ruby (version given by .ruby-version) and Bundler
uses: ruby/setup-ruby@v1 uses: ruby/setup-ruby@v1
@@ -106,25 +106,17 @@ jobs:
- name: Prepare database for testing - name: Prepare database for testing
run: bundle exec rails db:prepare run: bundle exec rails db:prepare
- name: precompile assets
run: bundle exec rails assets:precompile
- name: index into elastic search
run: bundle exec rails search:reindex
- name: Run rspec (report results to Percy.io and CodeClimate)
run: bundle exec rspec spec -fd
- name: Run rspec (lib) - name: Report to code climate
run: bundle exec rspec spec/lib/ -fd --fail-fast run: |
gem install codeclimate-test-reporter
- name: Run rspec (services) codeclimate-test-reporter
run: bundle exec rspec spec/services/ -fd --fail-fast
- name: Run rspec (models)
run: bundle exec rspec spec/models/ -fd --fail-fast
- name: Run rspec (controllers)
run: bundle exec rspec spec/controllers/ -fd --fail-fast
- name: Run rspec (views)
run: bundle exec rspec spec/views/ -fd --fail-fast
- name: Run rspec (routing)
run: bundle exec rspec spec/routing/ -fd --fail-fast
- name: Run rspec (request)
run: bundle exec rspec spec/requests/ -fd --fail-fast

View File

@@ -1,43 +0,0 @@
name: Docker Build and Push
on:
push:
branches:
- mainline
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Log in to the Container registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v6
with:
images: ghcr.io/${{ github.repository }}
- name: Build and push Docker image
uses: docker/build-push-action@v7
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

View File

@@ -1,5 +1,5 @@
inherit_from: .rubocop_todo.yml inherit_from: .rubocop_todo.yml
plugins: require:
- rubocop-factory_bot - rubocop-factory_bot
- rubocop-capybara - rubocop-capybara
- rubocop-rails - rubocop-rails
@@ -24,7 +24,6 @@ Naming/FileName:
RSpec/DescribeClass: RSpec/DescribeClass:
Exclude: Exclude:
- 'spec/tasks/import_spec.rb'
- 'spec/views/**/*.rb' - 'spec/views/**/*.rb'
- 'spec/features/**/*.rb' - 'spec/features/**/*.rb'
@@ -72,7 +71,4 @@ Layout/LineLength:
Rails/SkipsModelValidations: Rails/SkipsModelValidations:
Exclude: Exclude:
- 'db/migrate/20190317023129_finished_boolean.rb' - 'db/migrate/20190317023129_finished_boolean.rb'
- 'db/migrate/20251128200506_add_description_to_crops.rb'
- 'db/migrate/20240810160538_set_default_language_for_existing_alternate_names.rb'
- 'db/migrate/20240101010102_populate_crop_fields_from_openfarm_data.rb'
- 'db/seeds.rb' - 'db/seeds.rb'

View File

@@ -1,31 +1,36 @@
# This configuration was generated by # This configuration was generated by
# `rubocop --auto-gen-config` # `rubocop --auto-gen-config`
# on 2026-05-02 06:53:56 UTC using RuboCop version 1.86.1. # on 2024-07-13 05:47:38 UTC using RuboCop version 1.65.0.
# The point is for the user to remove these configuration records # The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base. # one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new # Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again. # versions of RuboCop, may require this file to be generated again.
# Offense count: 407 # Offense count: 231
# This cop supports safe autocorrection (--autocorrect). # Configuration parameters: EnforcedStyle.
Capybara/RSpec/HaveContent: # SupportedStyles: link_or_button, strict
Capybara/ClickLinkOrButtonStyle:
Enabled: false Enabled: false
# Offense count: 21 # Offense count: 39
Capybara/RSpec/NegationMatcherAfterVisit: # This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: DefaultSelector.
Capybara/RSpec/HaveSelector:
Exclude: Exclude:
- 'spec/features/admin/reverting_crops_spec.rb' - 'spec/features/conversations/index_spec.rb'
- 'spec/features/crops/crop_detail_page_spec.rb' - 'spec/features/footer_spec.rb'
- 'spec/features/crops/crop_wranglers_spec.rb' - 'spec/features/gardens/adding_gardens_spec.rb'
- 'spec/features/gardens/gardens_spec.rb' - 'spec/features/harvests/harvesting_a_crop_spec.rb'
- 'spec/features/members/blocking_spec.rb' - 'spec/features/members/list_spec.rb'
- 'spec/features/members/deletion_spec.rb'
- 'spec/features/members/following_spec.rb'
- 'spec/features/members/profile_spec.rb'
- 'spec/features/plantings/planting_a_crop_spec.rb' - 'spec/features/plantings/planting_a_crop_spec.rb'
- 'spec/features/seeds/adding_seeds_spec.rb'
- 'spec/features/shared_examples/crop_suggest.rb'
- 'spec/helpers/application_helper_spec.rb'
- 'spec/support/feature_helpers.rb'
- 'spec/views/posts/show.html.haml_spec.rb'
# Offense count: 14 # Offense count: 14
Capybara/RSpec/SpecificMatcher: Capybara/SpecificMatcher:
Exclude: Exclude:
- 'spec/features/footer_spec.rb' - 'spec/features/footer_spec.rb'
- 'spec/features/gardens/adding_gardens_spec.rb' - 'spec/features/gardens/adding_gardens_spec.rb'
@@ -34,26 +39,25 @@ Capybara/RSpec/SpecificMatcher:
- 'spec/features/seeds/adding_seeds_spec.rb' - 'spec/features/seeds/adding_seeds_spec.rb'
# Offense count: 1 # Offense count: 1
Capybara/RSpec/VisibilityMatcher: Capybara/VisibilityMatcher:
Exclude: Exclude:
- 'spec/features/shared_examples/crop_suggest.rb' - 'spec/features/shared_examples/crop_suggest.rb'
# Offense count: 8 # Offense count: 6
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: EnforcedStyle, NonImplicitAssociationMethodNames. # Configuration parameters: EnforcedStyle, NonImplicitAssociationMethodNames.
# SupportedStyles: explicit, implicit # SupportedStyles: explicit, implicit
FactoryBot/AssociationStyle: FactoryBot/AssociationStyle:
Exclude: Exclude:
- 'spec/factories/alternate_names.rb' - 'spec/factories/alternate_names.rb'
- 'spec/factories/comments.rb'
- 'spec/factories/crop.rb' - 'spec/factories/crop.rb'
- 'spec/factories/like.rb' - 'spec/factories/like.rb'
- 'spec/factories/notifications.rb'
- 'spec/factories/scientific_name.rb' - 'spec/factories/scientific_name.rb'
# Offense count: 3 # Offense count: 3
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: EnforcedStyle, ExplicitOnly. # Configuration parameters: AutoCorrect, Include, EnforcedStyle, ExplicitOnly.
# Include: **/*_spec.rb, **/spec/**/*, **/test/**/*, **/features/support/factories/**/*.rb
# SupportedStyles: create_list, n_times # SupportedStyles: create_list, n_times
FactoryBot/CreateList: FactoryBot/CreateList:
Exclude: Exclude:
@@ -62,93 +66,57 @@ FactoryBot/CreateList:
- 'spec/views/posts/index.html.haml_spec.rb' - 'spec/views/posts/index.html.haml_spec.rb'
# Offense count: 4 # Offense count: 4
# Configuration parameters: MaxAmount. # Configuration parameters: Include, MaxAmount.
# Include: **/*_spec.rb, **/spec/**/*, **/test/**/*, **/features/support/factories/**/*.rb
FactoryBot/ExcessiveCreateList: FactoryBot/ExcessiveCreateList:
Exclude: Exclude:
- 'spec/controllers/posts_controller_spec.rb' - 'spec/controllers/posts_controller_spec.rb'
- 'spec/features/crops/show_spec.rb' - 'spec/features/crops/show_spec.rb'
- 'spec/features/percy/percy_spec.rb' - 'spec/features/percy/percy_spec.rb'
# Offense count: 1 # Offense count: 1127
# This cop supports safe autocorrection (--autocorrect). # This cop supports unsafe autocorrection (--autocorrect-all).
Layout/EmptyLines: # Configuration parameters: Include.
Exclude: # Include: **/*_spec.rb, **/spec/**/*, **/test/**/*, **/features/support/factories/**/*.rb
- 'config/environments/production.rb' FactoryBot/SyntaxMethods:
Enabled: false
# Offense count: 311 # Offense count: 2
# This cop supports safe autocorrection (--autocorrect). # This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle. # Configuration parameters: Max, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns.
# SupportedHashRocketStyles: key, separator, table
# SupportedColonStyles: key, separator, table
# SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit
Layout/HashAlignment:
Exclude:
- 'app/helpers/application_helper.rb'
- 'app/helpers/crops_helper.rb'
- 'app/models/concerns/search_harvests.rb'
- 'app/models/concerns/search_plantings.rb'
- 'app/models/crop.rb'
- 'config/sitemap.rb'
- 'lib/tasks/import.rake'
- 'spec/requests/api/v1/activities_request_spec.rb'
- 'spec/requests/api/v1/members_request_spec.rb'
# Offense count: 8
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
# URISchemes: http, https # URISchemes: http, https
Layout/LineLength: Layout/LineLength:
Exclude: Exclude:
- 'Gemfile' - 'app/helpers/crops_helper.rb'
- 'app/controllers/admin/versions_controller.rb'
- 'app/controllers/crops_controller.rb'
- 'app/models/concerns/predict_planting.rb'
- 'app/models/crop.rb'
- 'db/seeds.rb' - 'db/seeds.rb'
- 'lib/tasks/members.rake'
# Offense count: 3
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyle, IndentationWidth.
# SupportedStyles: aligned, indented, indented_relative_to_receiver
Layout/MultilineMethodCallIndentation:
Exclude:
- 'app/models/activity.rb'
- 'app/models/concerns/predict_harvest.rb'
# Offense count: 1
# This cop supports safe autocorrection (--autocorrect).
Lint/AmbiguousOperatorPrecedence:
Exclude:
- 'app/controllers/activities_controller.rb'
# Offense count: 3 # Offense count: 3
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: RequireParenthesesForMethodChains. # Configuration parameters: RequireParenthesesForMethodChains.
Lint/AmbiguousRange: Lint/AmbiguousRange:
Exclude: Exclude:
- 'app/models/concerns/search_activities.rb'
- 'app/models/concerns/search_harvests.rb' - 'app/models/concerns/search_harvests.rb'
- 'app/models/concerns/search_plantings.rb' - 'app/models/concerns/search_plantings.rb'
- 'db/seeds.rb'
# Offense count: 1
# Configuration parameters: AllowedMethods.
# AllowedMethods: enums
Lint/ConstantDefinitionInBlock:
Exclude:
- 'lib/tasks/import.rake'
# Offense count: 2 # Offense count: 2
# Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches, IgnoreDuplicateElseBranch. # Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches.
Lint/DuplicateBranch: Lint/DuplicateBranch:
Exclude: Exclude:
- 'app/models/harvest.rb' - 'app/models/harvest.rb'
- 'lib/actions/oauth_signup_action.rb' - 'lib/actions/oauth_signup_action.rb'
# Offense count: 1 # Offense count: 8
Lint/DuplicateMethods: # Configuration parameters: AllowComments, AllowEmptyLambdas.
Lint/EmptyBlock:
Exclude: Exclude:
- 'app/models/planting.rb' - 'db/migrate/20171022032108_all_the_predictions.rb'
- 'spec/controllers/home_controller_spec.rb'
- 'spec/controllers/likes_controller_spec.rb'
- 'spec/controllers/plant_parts_controller_spec.rb'
- 'spec/factories/crop_companions.rb'
- 'spec/features/crops/crop_detail_page_spec.rb'
- 'spec/requests/authentications_spec.rb'
# Offense count: 1 # Offense count: 1
# This cop supports safe autocorrection (--autocorrect). # This cop supports safe autocorrection (--autocorrect).
@@ -168,131 +136,114 @@ Lint/SuppressedException:
Exclude: Exclude:
- 'lib/tasks/testing.rake' - 'lib/tasks/testing.rake'
# Offense count: 1 # Offense count: 7
Lint/UselessConstantScoping: # This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: AutoCorrect.
Lint/UselessAssignment:
Exclude: Exclude:
- 'app/controllers/members_controller.rb' - 'config.rb'
- 'config/compass.rb'
# Offense count: 65 # Offense count: 52
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
Metrics/AbcSize: Metrics/AbcSize:
Max: 295 Max: 151
# Offense count: 14 # Offense count: 14
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode. # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode.
# AllowedMethods: refine # AllowedMethods: refine
Metrics/BlockLength: Metrics/BlockLength:
Max: 294 Max: 115
# Offense count: 10 # Offense count: 7
# Configuration parameters: CountComments, CountAsOne. # Configuration parameters: CountComments, CountAsOne.
Metrics/ClassLength: Metrics/ClassLength:
Max: 298 Max: 183
# Offense count: 1 # Offense count: 6
# Configuration parameters: LengthThreshold.
Metrics/CollectionLiteralLength:
Exclude:
- 'lib/tasks/import.rake'
# Offense count: 11
# Configuration parameters: AllowedMethods, AllowedPatterns. # Configuration parameters: AllowedMethods, AllowedPatterns.
Metrics/CyclomaticComplexity: Metrics/CyclomaticComplexity:
Max: 32 Max: 32
# Offense count: 83 # Offense count: 71
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
Metrics/MethodLength: Metrics/MethodLength:
Max: 296 Max: 127
# Offense count: 2 # Offense count: 2
# Configuration parameters: CountComments, CountAsOne. # Configuration parameters: CountComments, CountAsOne.
Metrics/ModuleLength: Metrics/ModuleLength:
Max: 144 Max: 125
# Offense count: 10 # Offense count: 5
# Configuration parameters: AllowedMethods, AllowedPatterns. # Configuration parameters: AllowedMethods, AllowedPatterns.
Metrics/PerceivedComplexity: Metrics/PerceivedComplexity:
Max: 32 Max: 32
# Offense count: 2
# Configuration parameters: Mode, AllowedMethods, AllowedPatterns, AllowBangMethods, WaywardPredicates.
# AllowedMethods: call
# WaywardPredicates: infinite?, nonzero?
Naming/PredicateMethod:
Exclude:
- 'app/models/concerns/finishable.rb'
- 'app/models/seed.rb'
# Offense count: 1
# Configuration parameters: NamePrefix, ForbiddenPrefixes, AllowedMethods, MethodDefinitionMacros, UseSorbetSigs.
# NamePrefix: is_, has_, have_, does_
# ForbiddenPrefixes: is_, has_, have_, does_
# AllowedMethods: is_a?
# MethodDefinitionMacros: define_method, define_singleton_method
Naming/PredicatePrefix:
Exclude:
- 'app/models/member.rb'
# Offense count: 3 # Offense count: 3
RSpec/AnyInstance: RSpec/AnyInstance:
Exclude: Exclude:
- 'spec/controllers/harvests_controller_spec.rb' - 'spec/controllers/harvests_controller_spec.rb'
- 'spec/controllers/photos_controller_spec.rb' - 'spec/controllers/photos_controller_spec.rb'
# Offense count: 2 # Offense count: 292
# This cop supports unsafe autocorrection (--autocorrect-all).
RSpec/BeEq:
Exclude:
- 'spec/requests/api/v1/activities_request_spec.rb'
# Offense count: 2
RSpec/BeforeAfterAll:
Exclude:
- 'spec/tasks/import_spec.rb'
- 'spec/tasks/members_spec.rb'
# Offense count: 311
# Configuration parameters: Prefixes, AllowedPatterns. # Configuration parameters: Prefixes, AllowedPatterns.
# Prefixes: when, with, without # Prefixes: when, with, without
RSpec/ContextWording: RSpec/ContextWording:
Enabled: false Enabled: false
# Offense count: 2 # Offense count: 36
# Configuration parameters: IgnoredMetadata.
RSpec/DescribeClass:
Exclude:
- 'spec/models/harvest_prediction_spec.rb'
- 'spec/tasks/members_spec.rb'
# Offense count: 37
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: SkipBlocks, EnforcedStyle, OnlyStaticConstants. # Configuration parameters: SkipBlocks, EnforcedStyle, OnlyStaticConstants.
# SupportedStyles: described_class, explicit # SupportedStyles: described_class, explicit
RSpec/DescribedClass: RSpec/DescribedClass:
Exclude: Exclude:
- 'spec/mailers/harvest_reminder_mailer_spec.rb'
- 'spec/models/like_spec.rb' - 'spec/models/like_spec.rb'
- 'spec/models/member_spec.rb' - 'spec/models/member_spec.rb'
- 'spec/services/timeline_service_spec.rb' - 'spec/services/timeline_service_spec.rb'
# Offense count: 13
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: AutoCorrect.
RSpec/EmptyExampleGroup:
Exclude:
- 'spec/controllers/authentications_controller_spec.rb'
- 'spec/controllers/forums_controller_spec.rb'
- 'spec/controllers/home_controller_spec.rb'
- 'spec/controllers/likes_controller_spec.rb'
- 'spec/controllers/plant_parts_controller_spec.rb'
- 'spec/controllers/seeds_controller_spec.rb'
- 'spec/features/crops/crop_detail_page_spec.rb'
- 'spec/features/plantings/planting_a_crop_spec.rb'
- 'spec/requests/authentications_spec.rb'
- 'spec/views/home/index_spec.rb'
- 'spec/views/photos/edit.html.haml_spec.rb'
- 'spec/views/posts/_single.html.haml_spec.rb'
# Offense count: 1 # Offense count: 1
# This cop supports safe autocorrection (--autocorrect). # This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: AllowConsecutiveOneLiners. # Configuration parameters: AllowConsecutiveOneLiners.
RSpec/EmptyLineAfterExample: RSpec/EmptyLineAfterExample:
Exclude: Exclude:
- 'spec/controllers/crops_controller_spec.rb' - 'spec/models/ability_spec.rb'
# Offense count: 1 # Offense count: 140
# This cop supports safe autocorrection (--autocorrect).
RSpec/EmptyLineAfterFinalLet:
Exclude:
- 'spec/controllers/crops_controller_spec.rb'
# Offense count: 161
# Configuration parameters: CountAsOne. # Configuration parameters: CountAsOne.
RSpec/ExampleLength: RSpec/ExampleLength:
Max: 27 Max: 25
# Offense count: 32
RSpec/ExpectInHook:
Exclude:
- 'spec/controllers/garden_types_controller_spec.rb'
- 'spec/controllers/gardens_controller_spec.rb'
- 'spec/features/admin/forums_spec.rb'
- 'spec/features/admin/plant_parts_spec.rb'
- 'spec/features/admin/roles_spec.rb'
- 'spec/features/crops/crop_photos_spec.rb'
- 'spec/features/members/list_spec.rb'
- 'spec/features/plantings/planting_a_crop_spec.rb'
- 'spec/features/shared_examples/append_date.rb'
# Offense count: 1 # Offense count: 1
# This cop supports safe autocorrection (--autocorrect). # This cop supports safe autocorrection (--autocorrect).
@@ -304,42 +255,33 @@ RSpec/HookArgument:
# Offense count: 2 # Offense count: 2
# This cop supports safe autocorrection (--autocorrect). # This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: AutoCorrect.
RSpec/HooksBeforeExamples: RSpec/HooksBeforeExamples:
Exclude: Exclude:
- 'spec/features/crops/creating_a_crop_spec.rb' - 'spec/features/crops/creating_a_crop_spec.rb'
# Offense count: 53 # Offense count: 37
# This cop supports unsafe autocorrection (--autocorrect-all).
RSpec/IncludeExamples:
Exclude:
- 'spec/features/conversations/index_spec.rb'
- 'spec/features/crops/alternate_name_spec.rb'
- 'spec/features/crops/browse_crops_spec.rb'
- 'spec/features/crops/creating_a_crop_spec.rb'
- 'spec/features/crops/crop_photos_spec.rb'
- 'spec/features/crops/delete_crop_spec.rb'
- 'spec/features/gardens/actions_spec.rb'
- 'spec/features/gardens/adding_gardens_spec.rb'
- 'spec/features/gardens/index_spec.rb'
- 'spec/features/likeable_spec.rb'
- 'spec/features/signout_spec.rb'
- 'spec/models/crop_spec.rb'
- 'spec/support/feature_helpers.rb'
- 'spec/views/photos/show.html.haml_spec.rb'
- 'spec/views/seeds/index.rss.haml_spec.rb'
# Offense count: 2
# Configuration parameters: Max, AllowedIdentifiers, AllowedPatterns. # Configuration parameters: Max, AllowedIdentifiers, AllowedPatterns.
RSpec/IndexedLet: RSpec/IndexedLet:
Exclude: Exclude:
- 'spec/models/activity_spec.rb' - 'spec/controllers/harvests_controller_spec.rb'
- 'spec/controllers/plantings_controller_spec.rb'
- 'spec/features/crops/crop_photos_spec.rb'
- 'spec/features/members/list_spec.rb'
- 'spec/features/members/profile_spec.rb'
- 'spec/features/percy/percy_spec.rb'
- 'spec/features/planting_reminder_spec.rb'
- 'spec/features/timeline/index_spec.rb'
- 'spec/models/crop_spec.rb'
- 'spec/models/member_spec.rb'
- 'spec/views/forums/index.html.haml_spec.rb'
# Offense count: 711 # Offense count: 720
# Configuration parameters: AssignmentOnly. # Configuration parameters: AssignmentOnly.
RSpec/InstanceVariable: RSpec/InstanceVariable:
Enabled: false Enabled: false
# Offense count: 43 # Offense count: 40
RSpec/LetSetup: RSpec/LetSetup:
Enabled: false Enabled: false
@@ -354,7 +296,7 @@ RSpec/MessageChain:
Exclude: Exclude:
- 'spec/models/member_spec.rb' - 'spec/models/member_spec.rb'
# Offense count: 65 # Offense count: 23
# Configuration parameters: . # Configuration parameters: .
# SupportedStyles: have_received, receive # SupportedStyles: have_received, receive
RSpec/MessageSpies: RSpec/MessageSpies:
@@ -365,49 +307,37 @@ RSpec/MultipleDescribes:
Exclude: Exclude:
- 'spec/features/crops/crop_wranglers_spec.rb' - 'spec/features/crops/crop_wranglers_spec.rb'
# Offense count: 235 # Offense count: 152
RSpec/MultipleExpectations: RSpec/MultipleExpectations:
Max: 19 Max: 19
# Offense count: 171 # Offense count: 138
# Configuration parameters: AllowSubject. # Configuration parameters: AllowSubject.
RSpec/MultipleMemoizedHelpers: RSpec/MultipleMemoizedHelpers:
Max: 16 Max: 14
# Offense count: 183 # Offense count: 133
# Configuration parameters: EnforcedStyle, IgnoreSharedExamples. # Configuration parameters: EnforcedStyle, IgnoreSharedExamples.
# SupportedStyles: always, named_only # SupportedStyles: always, named_only
RSpec/NamedSubject: RSpec/NamedSubject:
Enabled: false Enabled: false
# Offense count: 112 # Offense count: 111
# Configuration parameters: AllowedGroups. # Configuration parameters: AllowedGroups.
RSpec/NestedGroups: RSpec/NestedGroups:
Max: 6 Max: 6
# Offense count: 366 # Offense count: 403
# Configuration parameters: AllowedPatterns. # Configuration parameters: AllowedPatterns.
# AllowedPatterns: ^expect_, ^assert_ # AllowedPatterns: ^expect_, ^assert_
RSpec/NoExpectationExample: RSpec/NoExpectationExample:
Enabled: false Enabled: false
# Offense count: 9 # Offense count: 3
RSpec/PendingWithoutReason: RSpec/PendingWithoutReason:
Exclude: Exclude:
- 'spec/features/members/blocking_spec.rb'
- 'spec/features/plantings/planting_a_crop_spec.rb'
- 'spec/features/seeds/misc_seeds_spec.rb' - 'spec/features/seeds/misc_seeds_spec.rb'
- 'spec/features/unsubscribing_spec.rb' - 'spec/features/unsubscribing_spec.rb'
- 'spec/models/ability_spec.rb'
- 'spec/requests/api/v1/gardens_request_spec.rb'
# Offense count: 5
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: Strict, EnforcedStyle, AllowedExplicitMatchers.
# SupportedStyles: inflected, explicit
RSpec/PredicateMatcher:
Exclude:
- 'spec/tasks/members_spec.rb'
# Offense count: 2 # Offense count: 2
RSpec/RepeatedDescription: RSpec/RepeatedDescription:
@@ -428,27 +358,30 @@ RSpec/RepeatedExampleGroupBody:
# Offense count: 6 # Offense count: 6
# This cop supports safe autocorrection (--autocorrect). # This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: AutoCorrect.
RSpec/ScatteredSetup: RSpec/ScatteredSetup:
Exclude: Exclude:
- 'spec/features/percy/percy_spec.rb' - 'spec/features/percy/percy_spec.rb'
- 'spec/features/plantings/prediction_spec.rb' - 'spec/features/plantings/prediction_spec.rb'
# Offense count: 2 # Offense count: 1
# Configuration parameters: CustomTransform, IgnoreMethods, IgnoreMetadata, InflectorPath, EnforcedInflector. # Configuration parameters: Include, CustomTransform, IgnoreMethods, IgnoreMetadata.
# SupportedInflectors: default, active_support # Include: **/*_spec.rb
RSpec/SpecFilePathFormat: RSpec/SpecFilePathFormat:
Exclude: Exclude:
- 'spec/controllers/member_controller_spec.rb' - 'spec/controllers/member_controller_spec.rb'
- 'spec/mailers/harvest_reminder_mailer_spec.rb'
# Offense count: 2 # Offense count: 3
RSpec/StubbedMock: RSpec/StubbedMock:
Exclude: Exclude:
- 'spec/controllers/photos_controller_spec.rb' - 'spec/controllers/garden_types_controller_spec.rb'
- 'spec/controllers/gardens_controller_spec.rb'
- 'spec/models/member_spec.rb' - 'spec/models/member_spec.rb'
# Offense count: 1 # Offense count: 1
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: EnforcedStyle.
# SupportedStyles: constant, string
RSpec/VerifiedDoubleReference: RSpec/VerifiedDoubleReference:
Exclude: Exclude:
- 'spec/models/member_spec.rb' - 'spec/models/member_spec.rb'
@@ -461,45 +394,47 @@ RSpec/VerifiedDoubles:
- 'spec/controllers/gardens_controller_spec.rb' - 'spec/controllers/gardens_controller_spec.rb'
- 'spec/views/devise/shared/_links_spec.rb' - 'spec/views/devise/shared/_links_spec.rb'
# Offense count: 1 # Offense count: 7
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: ResponseMethods.
# ResponseMethods: response, last_response
RSpecRails/HaveHttpStatus:
Exclude:
- 'spec/controllers/api/v1/plantings_controller_spec.rb'
- 'spec/controllers/harvests_controller_spec.rb'
- 'spec/controllers/likes_controller_spec.rb'
- 'spec/requests/harvests_spec.rb'
# Offense count: 16
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: Inferences. # Configuration parameters: Inferences.
RSpecRails/InferredSpecType: RSpecRails/InferredSpecType:
Exclude: Enabled: false
- 'spec/mailers/harvest_reminder_mailer_spec.rb'
# Offense count: 30 # Offense count: 28
# Configuration parameters: Database. # Configuration parameters: Database, Include.
# SupportedDatabases: mysql, postgresql # SupportedDatabases: mysql, postgresql
# Include: db/**/*.rb
Rails/BulkChangeTable: Rails/BulkChangeTable:
Enabled: false Enabled: false
# Offense count: 4 # Offense count: 4
# Configuration parameters: Include.
# Include: db/**/*.rb
Rails/CreateTableWithTimestamps: Rails/CreateTableWithTimestamps:
Exclude: Exclude:
- 'db/migrate/20150201052245_create_cms.rb' - 'db/migrate/20150201052245_create_cms.rb'
- 'db/migrate/20171022032108_all_the_predictions.rb' - 'db/migrate/20171022032108_all_the_predictions.rb'
# Offense count: 8 # Offense count: 1
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: EnforcedStyle, AllowToTime. # Configuration parameters: EnforcedStyle, AllowToTime.
# SupportedStyles: strict, flexible # SupportedStyles: strict, flexible
Rails/Date: Rails/Date:
Exclude: Exclude:
- 'app/controllers/activities_controller.rb'
- 'app/mailers/notifier_mailer.rb' - 'app/mailers/notifier_mailer.rb'
- 'app/models/concerns/search_seeds.rb'
- 'spec/features/activities/creating_a_recurring_activity_spec.rb'
# Offense count: 1 # Offense count: 11
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyle.
# SupportedStyles: slashes, arguments
Rails/FilePath:
Exclude:
- 'lib/tasks/import.rake'
# Offense count: 12
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: AllowedMethods, AllowedPatterns. # Configuration parameters: AllowedMethods, AllowedPatterns.
# AllowedMethods: order, limit, select, lock # AllowedMethods: order, limit, select, lock
@@ -510,58 +445,41 @@ Rails/FindEach:
- 'db/migrate/20171129041341_create_photographings.rb' - 'db/migrate/20171129041341_create_photographings.rb'
- 'db/migrate/20190130090437_add_crop_to_photographings.rb' - 'db/migrate/20190130090437_add_crop_to_photographings.rb'
- 'db/migrate/20191119030244_cms_tags.rb' - 'db/migrate/20191119030244_cms_tags.rb'
- 'lib/tasks/wikidata.rake'
# Offense count: 2 # Offense count: 2
# Configuration parameters: Include.
# Include: app/models/**/*.rb
Rails/HasAndBelongsToMany: Rails/HasAndBelongsToMany:
Exclude: Exclude:
- 'app/models/member.rb' - 'app/models/member.rb'
- 'app/models/role.rb' - 'app/models/role.rb'
# Offense count: 6 # Offense count: 5
# Configuration parameters: Include.
# Include: app/models/**/*.rb
Rails/HasManyOrHasOneDependent: Rails/HasManyOrHasOneDependent:
Exclude: Exclude:
- 'app/models/crop.rb'
- 'app/models/member.rb' - 'app/models/member.rb'
# Offense count: 7
Rails/HelperInstanceVariable:
Exclude:
- 'app/helpers/crops_helper.rb'
- 'app/helpers/plantings_helper.rb'
# Offense count: 1 # Offense count: 1
# Configuration parameters: Include.
# Include: spec/**/*.rb, test/**/*.rb
Rails/I18nLocaleAssignment: Rails/I18nLocaleAssignment:
Exclude: Exclude:
- 'spec/features/locale_spec.rb' - 'spec/features/locale_spec.rb'
# Offense count: 5 # Offense count: 33
Rails/I18nLocaleTexts: Rails/I18nLocaleTexts:
Exclude: Enabled: false
- 'app/controllers/blocks_controller.rb'
- 'app/controllers/comments_controller.rb'
- 'app/controllers/messages_controller.rb'
- 'config/initializers/comfortable_mexican_sofa.rb'
# Offense count: 1 # Offense count: 3
# Configuration parameters: IgnoreScopes. # Configuration parameters: Include.
Rails/InverseOf: # Include: app/controllers/**/*.rb, app/mailers/**/*.rb
Exclude:
- 'app/models/member.rb'
# Offense count: 4
Rails/LexicallyScopedActionFilter: Rails/LexicallyScopedActionFilter:
Exclude: Exclude:
- 'app/controllers/api/v1/base_controller.rb'
- 'app/controllers/data_controller.rb' - 'app/controllers/data_controller.rb'
- 'app/controllers/registrations_controller.rb' - 'app/controllers/registrations_controller.rb'
# Offense count: 1
# This cop supports unsafe autocorrection (--autocorrect-all).
Rails/OrderArguments:
Exclude:
- 'app/models/activity.rb'
# Offense count: 2 # Offense count: 2
Rails/OutputSafety: Rails/OutputSafety:
Exclude: Exclude:
@@ -574,23 +492,17 @@ Rails/PluralizationGrammar:
Exclude: Exclude:
- 'spec/requests/plantings_spec.rb' - 'spec/requests/plantings_spec.rb'
# Offense count: 3
# This cop supports safe autocorrection (--autocorrect).
Rails/Presence:
Exclude:
- 'app/controllers/photos_controller.rb'
- 'app/controllers/plantings_controller.rb'
- 'app/models/concerns/open_farm_data.rb'
# Offense count: 4 # Offense count: 4
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: Include.
# Include: **/Rakefile, **/*.rake
Rails/RakeEnvironment: Rails/RakeEnvironment:
Exclude: Exclude:
- 'lib/tasks/hooks.rake' - 'lib/tasks/hooks.rake'
- 'lib/tasks/i18n.rake' - 'lib/tasks/i18n.rake'
- 'lib/tasks/testing.rake' - 'lib/tasks/testing.rake'
# Offense count: 8 # Offense count: 9
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: AllowedReceivers. # Configuration parameters: AllowedReceivers.
# AllowedReceivers: ActionMailer::Preview, ActiveSupport::TimeZone # AllowedReceivers: ActionMailer::Preview, ActiveSupport::TimeZone
@@ -601,8 +513,9 @@ Rails/RedundantActiveRecordAllMethod:
- 'app/controllers/forums_controller.rb' - 'app/controllers/forums_controller.rb'
- 'app/controllers/plant_parts_controller.rb' - 'app/controllers/plant_parts_controller.rb'
- 'app/controllers/scientific_names_controller.rb' - 'app/controllers/scientific_names_controller.rb'
- 'spec/features/members/deletion_spec.rb' - 'app/services/openfarm_service.rb'
- 'spec/features/percy/percy_spec.rb' - 'spec/features/percy/percy_spec.rb'
- 'spec/models/harvest_spec.rb'
# Offense count: 5 # Offense count: 5
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
@@ -613,13 +526,14 @@ Rails/RedundantPresenceValidationOnBelongsTo:
- 'app/models/planting.rb' - 'app/models/planting.rb'
- 'app/models/scientific_name.rb' - 'app/models/scientific_name.rb'
# Offense count: 16 # Offense count: 15
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: Include.
# Include: spec/controllers/**/*.rb, spec/requests/**/*.rb, test/controllers/**/*.rb, test/integration/**/*.rb
Rails/ResponseParsedBody: Rails/ResponseParsedBody:
Exclude: Exclude:
- 'spec/controllers/api/v1/plantings_controller_spec.rb' - 'spec/controllers/api/v1/plantings_controller_spec.rb'
- 'spec/controllers/likes_controller_spec.rb' - 'spec/controllers/likes_controller_spec.rb'
- 'spec/requests/api/v1/activities_request_spec.rb'
- 'spec/requests/api/v1/crop_request_spec.rb' - 'spec/requests/api/v1/crop_request_spec.rb'
- 'spec/requests/api/v1/gardens_request_spec.rb' - 'spec/requests/api/v1/gardens_request_spec.rb'
- 'spec/requests/api/v1/harvests_request_spec.rb' - 'spec/requests/api/v1/harvests_request_spec.rb'
@@ -629,35 +543,29 @@ Rails/ResponseParsedBody:
- 'spec/requests/api/v1/seeds_request_spec.rb' - 'spec/requests/api/v1/seeds_request_spec.rb'
# Offense count: 9 # Offense count: 9
# Configuration parameters: Include.
# Include: db/**/*.rb
Rails/ReversibleMigration: Rails/ReversibleMigration:
Exclude: Exclude:
- 'db/migrate/20130326092227_change_planted_at_to_date.rb' - 'db/migrate/20130326092227_change_planted_at_to_date.rb'
- 'db/migrate/20191119020643_upgrade_cms.rb' - 'db/migrate/20191119020643_upgrade_cms.rb'
# Offense count: 6 # Offense count: 2
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
Rails/RootPathnameMethods: Rails/RootPathnameMethods:
Exclude: Exclude:
- 'app/controllers/crops_controller.rb' - 'app/controllers/crops_controller.rb'
- 'app/helpers/icons_helper.rb' - 'app/helpers/icons_helper.rb'
- 'config/application.rb'
- 'lib/tasks/import.rake'
- 'spec/rails_helper.rb'
# Offense count: 21 # Offense count: 21
# Configuration parameters: Include.
# Include: db/**/*.rb
Rails/ThreeStateBooleanColumn: Rails/ThreeStateBooleanColumn:
Enabled: false Enabled: false
# Offense count: 2
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: EnforcedStyle.
# SupportedStyles: strict, flexible
Rails/TimeZone:
Exclude:
- 'app/controllers/activities_controller.rb'
- 'spec/features/harvests/harvesting_a_crop_spec.rb'
# Offense count: 6 # Offense count: 6
# Configuration parameters: Include.
# Include: app/models/**/*.rb
Rails/UniqueValidationWithoutIndex: Rails/UniqueValidationWithoutIndex:
Exclude: Exclude:
- 'app/models/follow.rb' - 'app/models/follow.rb'
@@ -675,39 +583,28 @@ Rails/WhereEquals:
- 'app/models/harvest.rb' - 'app/models/harvest.rb'
- 'app/models/planting.rb' - 'app/models/planting.rb'
# Offense count: 3 # Offense count: 2
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
Rails/WhereRange: Rails/WhereRange:
Exclude: Exclude:
- 'app/models/concerns/predict_planting.rb' - 'app/models/concerns/predict_planting.rb'
- 'app/models/garden.rb' - 'app/models/garden.rb'
- 'app/models/seed.rb'
# Offense count: 1 # Offense count: 1
Rake/MethodDefinitionInTask: Rake/MethodDefinitionInTask:
Exclude: Exclude:
- 'lib/tasks/growstuff.rake' - 'lib/tasks/growstuff.rake'
# Offense count: 5 # Offense count: 3
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: EnforcedStyle, EnforcedStyleForClasses, EnforcedStyleForModules. # Configuration parameters: EnforcedStyle.
# SupportedStyles: nested, compact # SupportedStyles: nested, compact
# SupportedStylesForClasses: ~, nested, compact
# SupportedStylesForModules: ~, nested, compact
Style/ClassAndModuleChildren: Style/ClassAndModuleChildren:
Exclude: Exclude:
- 'app/controllers/admin/crops_controller.rb'
- 'config/initializers/rack_attack.rb'
- 'lib/actions/oauth_signup_action.rb' - 'lib/actions/oauth_signup_action.rb'
- 'lib/haml/filters/escaped_markdown.rb' - 'lib/haml/filters/escaped_markdown.rb'
- 'lib/haml/filters/growstuff_markdown.rb' - 'lib/haml/filters/growstuff_markdown.rb'
# Offense count: 1
# This cop supports unsafe autocorrection (--autocorrect-all).
Style/CollectionQuerying:
Exclude:
- 'app/models/member.rb'
# Offense count: 6 # Offense count: 6
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
Style/CommentedKeyword: Style/CommentedKeyword:
@@ -718,56 +615,30 @@ Style/CommentedKeyword:
- 'spec/models/planting_spec.rb' - 'spec/models/planting_spec.rb'
# Offense count: 3 # Offense count: 3
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: AllowedVars, DefaultToNil.
Style/FetchEnvVar:
Exclude:
- 'config/sitemap.rb'
# Offense count: 2
Style/FileOpen:
Exclude:
- 'app/helpers/application_helper.rb'
- 'db/seeds.rb'
# Offense count: 1
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: EnforcedStyle.
# SupportedStyles: left_coerce, right_coerce, single_coerce, fdiv
Style/FloatDivision:
Exclude:
- 'app/models/concerns/predict_planting.rb'
# Offense count: 2
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: always, always_true, never # SupportedStyles: always, always_true, never
Style/FrozenStringLiteralComment: Style/FrozenStringLiteralComment:
Exclude: Exclude:
- 'db/migrate/20260429132911_add_send_harvest_reminder_to_members.rb' - 'config/initializers/new_framework_defaults_6_0.rb'
- 'db/migrate/20200801084007_add_foreign_key_constraint_to_active_storage_attachments_for_blob_id.active_storage.rb'
- 'spec/lib/haml/filters/growstuff_markdown_spec.rb' - 'spec/lib/haml/filters/growstuff_markdown_spec.rb'
# Offense count: 2 # Offense count: 3
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
Style/GlobalStdStream: Style/GlobalStdStream:
Exclude: Exclude:
- 'config/environments/production.rb' - 'config/environments/production.rb'
- 'lib/tasks/gbif.rake' - 'lib/tasks/gbif.rake'
- 'lib/tasks/openfarm.rake'
# Offense count: 2 # Offense count: 1
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
Style/IdenticalConditionalBranches: # Configuration parameters: AllowedMethods.
# AllowedMethods: nonzero?
Style/IfWithBooleanLiteralBranches:
Exclude: Exclude:
- 'lib/actions/oauth_signup_action.rb' - 'app/controllers/gardens_controller.rb'
# Offense count: 4
# This cop supports safe autocorrection (--autocorrect).
Style/IfUnlessModifier:
Exclude:
- 'app/helpers/crops_helper.rb'
- 'app/models/concerns/predict_planting.rb'
- 'config/initializers/rack_attack.rb'
- 'lib/tasks/growstuff.rake'
# Offense count: 1 # Offense count: 1
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
@@ -789,13 +660,12 @@ Style/MutableConstant:
Exclude: Exclude:
- 'app/models/activity.rb' - 'app/models/activity.rb'
# Offense count: 6 # Offense count: 5
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: EnforcedStyle, AllowedMethods, AllowedPatterns. # Configuration parameters: EnforcedStyle, AllowedMethods, AllowedPatterns.
# SupportedStyles: predicate, comparison # SupportedStyles: predicate, comparison
Style/NumericPredicate: Style/NumericPredicate:
Exclude: Exclude:
- 'app/controllers/activities_controller.rb'
- 'app/helpers/crops_helper.rb' - 'app/helpers/crops_helper.rb'
- 'app/helpers/harvests_helper.rb' - 'app/helpers/harvests_helper.rb'
- 'app/helpers/plantings_helper.rb' - 'app/helpers/plantings_helper.rb'
@@ -806,12 +676,11 @@ Style/OpenStructUse:
Exclude: Exclude:
- 'spec/helpers/event_helper_spec.rb' - 'spec/helpers/event_helper_spec.rb'
# Offense count: 3 # Offense count: 2
# Configuration parameters: AllowedMethods. # Configuration parameters: AllowedMethods.
# AllowedMethods: respond_to_missing? # AllowedMethods: respond_to_missing?
Style/OptionalBooleanParameter: Style/OptionalBooleanParameter:
Exclude: Exclude:
- 'app/helpers/application_helper.rb'
- 'app/models/concerns/member_newsletter.rb' - 'app/models/concerns/member_newsletter.rb'
# Offense count: 1 # Offense count: 1
@@ -821,13 +690,6 @@ Style/RedundantArgument:
Exclude: Exclude:
- 'app/helpers/application_helper.rb' - 'app/helpers/application_helper.rb'
# Offense count: 3
# This cop supports safe autocorrection (--autocorrect).
Style/RedundantBegin:
Exclude:
- 'app/models/concerns/predict_harvest.rb'
- 'app/models/harvest.rb'
# Offense count: 4 # Offense count: 4
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: SafeForConstants. # Configuration parameters: SafeForConstants.
@@ -835,34 +697,20 @@ Style/RedundantFetchBlock:
Exclude: Exclude:
- 'config/puma.rb' - 'config/puma.rb'
# Offense count: 1 # Offense count: 2
# This cop supports unsafe autocorrection (--autocorrect-all).
Style/RedundantInterpolation:
Exclude:
- 'app/helpers/buttons_helper.rb'
# Offense count: 4
# Configuration parameters: Max.
Style/SafeNavigationChainLength:
Exclude:
- 'app/models/ability.rb'
# Offense count: 3
# This cop supports safe autocorrection (--autocorrect). # This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: AllowModifier. # Configuration parameters: AllowModifier.
Style/SoleNestedConditional: Style/SoleNestedConditional:
Exclude: Exclude:
- 'app/controllers/activities_controller.rb'
- 'app/controllers/application_controller.rb' - 'app/controllers/application_controller.rb'
- 'app/controllers/messages_controller.rb' - 'app/controllers/messages_controller.rb'
# Offense count: 27 # Offense count: 24
# This cop supports unsafe autocorrection (--autocorrect-all). # This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: Mode. # Configuration parameters: Mode.
Style/StringConcatenation: Style/StringConcatenation:
Exclude: Exclude:
- 'app/controllers/messages_controller.rb' - 'app/controllers/messages_controller.rb'
- 'app/controllers/registrations_controller.rb'
- 'app/helpers/buttons_helper.rb' - 'app/helpers/buttons_helper.rb'
- 'config/initializers/rswag_api.rb' - 'config/initializers/rswag_api.rb'
- 'spec/helpers/gardens_helper_spec.rb' - 'spec/helpers/gardens_helper_spec.rb'

View File

@@ -1 +1 @@
3.4.9 3.3.4

View File

@@ -248,3 +248,6 @@ linters:
ZeroUnit: ZeroUnit:
enabled: true enabled: true
Compass::*:
enabled: false

31
.travis.yml Normal file
View File

@@ -0,0 +1,31 @@
sudo: required
language: ruby
dist: bionic
branches:
only:
- mainline
- dev
cache:
bundler: true
yarn: true
directories:
- tmp/cache/assets/test/sprockets
env:
global:
- secure: "Z5TpM2jEX4UCvNePnk/LwltQX48U2u9BRc+Iypr1x9QW2o228QJhPIOH39a8RMUrepGnkQIq9q3ZRUn98RfrJz1yThtlNFL3NmzdQ57gKgjGwfpa0e4Dwj/ZJqV2D84tDGjvdVYLP7zzaYZxQcwk/cgNpzKf/jq97HLNP7CYuf4="
before_deploy:
- bundle exec script/heroku_maintenance.rb on
deploy:
provider: heroku
api_key:
secure: "WrQxf0fEKkCdXrjcejurobOnNNz3he4dDwjBbToXbQTQNDObPp7NetJrLsfM8FiUFEeOuvhIHHiDQtMvY720zGGAGxDptvgFS+0QHCUqoTRZA/yFfUmHlG2jROXTzk5uVK0AE4k6Ion5kX8+mM0EnMT/7u+MTFiukrJctSiEXfg="
on:
repo: Growstuff/growstuff
app:
dev: growstuff-staging
mainline: growstuff-prod
run:
- "script/deploy-tasks.sh"
- restart
after_deploy:
- bundle exec script/heroku_maintenance.rb off

View File

@@ -12,7 +12,6 @@ submit the change with your pull request.
- Miles Gould / [pozorvlak](https://github.com/pozorvlak) - Miles Gould / [pozorvlak](https://github.com/pozorvlak)
- Mackenzie Morgan / [maco](https://github.com/maco) - Mackenzie Morgan / [maco](https://github.com/maco)
- Brenda Wallace / [br3nda](https://github.com/br3nda) - Brenda Wallace / [br3nda](https://github.com/br3nda)
- Daniel O'Connor / [CloCkWeRX](https://github.com/CloCkWeRX)
## Contributors ## Contributors
@@ -69,6 +68,7 @@ submit the change with your pull request.
- Jym Paul Carandang / [jacarandang](https://github.com/jacarandang) - Jym Paul Carandang / [jacarandang](https://github.com/jacarandang)
- Anthony Atkinson / [sha1sum](https://github.com/sha1sum) - Anthony Atkinson / [sha1sum](https://github.com/sha1sum)
- Terence Conquest / [twconquest](https://github.com/twconquest) - Terence Conquest / [twconquest](https://github.com/twconquest)
- Daniel O'Connor / [CloCkWeRX](https://github.com/CloCkWeRX)
- DV Dasari / [dv2](https://github.com/dv2) - DV Dasari / [dv2](https://github.com/dv2)
- Eric Tillberg / [Thrillberg](https://github.com/Thrillberg) - Eric Tillberg / [Thrillberg](https://github.com/Thrillberg)
- Lucas Nogueira / [lucasnogueira](https://github.com/lucasnogueira) - Lucas Nogueira / [lucasnogueira](https://github.com/lucasnogueira)
@@ -95,11 +95,10 @@ submit the change with your pull request.
- Ítalo Pires / [italopires](https://github.com/italopires) - Ítalo Pires / [italopires](https://github.com/italopires)
- Bennett Zink / [bennett-zink](https://github.com/bennett-zink) - Bennett Zink / [bennett-zink](https://github.com/bennett-zink)
- Dominick Thornton / [domthor](https://github.com/domthor) - Dominick Thornton / [domthor](https://github.com/domthor)
## Bots ## Bots
### Security and Dependency Updates ### Security and Dependency Updates
- `codefactor-io[bot]` - `codefactor-io[bot]`
- DeppBot / [deppbot](https://github.com/deppbot) - DeppBot / [deppbot](https://github.com/deppbot)
- `dependabot[bot]` [dependabot](https://github.com/dependabot-bot) / [dependabot-preview](https://github.com/apps/dependabot-preview) - `dependabot[bot]` [dependabot](https://github.com/dependabot-bot) / [dependabot-preview](https://github.com/apps/dependabot-preview)
- [google-labs-jules[bot]](https://github.com/apps/google-labs-jules)

View File

@@ -1,52 +0,0 @@
FROM ruby:3.4.9-trixie
# Install system dependencies
RUN apt-get update -qq && \
apt-get install -y --no-install-recommends \
build-essential \
libpq-dev \
git \
curl \
gnupg2 \
shared-mime-info \
libvips \
&& curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
&& npm install -g yarn \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Set production environment
ENV RAILS_ENV=production \
BUNDLE_WITHOUT="development test" \
RAILS_SERVE_STATIC_FILES=true \
RAILS_LOG_TO_STDOUT=true
WORKDIR /app
# Install gems
COPY Gemfile Gemfile.lock ./
RUN bundle config set --local deployment 'true' && \
bundle config set --local without 'development test' && \
bundle install --jobs 4 --retry 3
# Install JavaScript dependencies
COPY package.json yarn.lock ./
RUN yarn install --check-files
# Copy the application code
COPY . .
# Precompile assets
# Secret key base is needed for asset compilation but doesn't need to be the real one
RUN RAILS_ENV=production SECRET_KEY_BASE_DUMMY=1 bundle exec rake assets:precompile
# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000
# Start the main process.
CMD ["bundle", "exec", "puma", "-C", "config/puma.rb"]

28
Gemfile
View File

@@ -5,13 +5,13 @@ source 'https://rubygems.org'
# Match ruby version in .ruby-version # Match ruby version in .ruby-version
ruby File.read('.ruby-version') ruby File.read('.ruby-version')
gem 'rails', '~> 7.2.0' gem 'rails', '~> 7.1.0'
# Keeping old sprockets # Keeping old sprockets
# https://github.com/rails/sprockets-rails/issues/444#issuecomment-637817050 # https://github.com/rails/sprockets-rails/issues/444#issuecomment-637817050
gem "sprockets", "<4" gem "sprockets", "<4"
gem 'bundler', '>= 2.4.22' gem 'bundler', '>= 2.3.10'
gem 'coffee-rails' gem 'coffee-rails'
gem 'haml' gem 'haml'
@@ -91,9 +91,10 @@ gem 'bootstrap-datepicker-rails'
# DRY-er easier bootstrap 4 forms # DRY-er easier bootstrap 4 forms
gem "bootstrap_form", ">= 4.5.0" gem "bootstrap_form", ">= 4.5.0"
# For connecting to other services (eg Flickr) # For connecting to other services (eg Twitter)
gem 'omniauth', '~> 1.3' gem 'omniauth', '~> 1.3'
gem 'omniauth-flickr', '>= 0.0.15' gem 'omniauth-flickr', '>= 0.0.15'
gem 'omniauth-twitter'
# Pretty charts # Pretty charts
gem "chartkick" gem "chartkick"
@@ -116,8 +117,6 @@ gem 'xmlrpc' # fixes rake error - can be removed if not needed later
gem 'puma' gem 'puma'
gem 'rack-attack'
gem 'loofah', '>= 2.19.1' gem 'loofah', '>= 2.19.1'
gem 'rack-protection', '>= 2.0.1' gem 'rack-protection', '>= 2.0.1'
@@ -138,11 +137,6 @@ gem "gbifrb"
gem "msgpack" gem "msgpack"
# Pinned due to RAILS_ENV=production bundle exec rake assets:precompile failing with ArgumentError: wrong number of arguments (given 1, expected 0) (ArgumentError)
# /tmp/build_8301a541/vendor/bundle/ruby/3.3.0/gems/connection_pool-3.0.2/lib/connection_pool.rb:48:in `initialize'
# /tmp/build_8301a541/vendor/bundle/ruby/3.3.0/gems/activesupport-7.2.3/lib/active_support/cache/mem_cache_store.rb:63:in `new'
gem "connection_pool", "< 3"
group :production do group :production do
gem 'bonsai-elasticsearch-rails' # Integration with Bonsa-Elasticsearch on heroku gem 'bonsai-elasticsearch-rails' # Integration with Bonsa-Elasticsearch on heroku
gem 'dalli' gem 'dalli'
@@ -181,10 +175,10 @@ group :development, :test do
gem 'rubocop-rspec_rails' gem 'rubocop-rspec_rails'
gem 'webrat' # provides HTML matchers for view tests gem 'webrat' # provides HTML matchers for view tests
gem 'crowdin-cli' # for translations
gem 'dotenv-rails' gem 'dotenv-rails'
# cli utils # cli utils
gem 'haml-i18n-extractor', require: false
gem 'haml_lint', '>= 0.25.1', require: false # Checks haml files for goodness gem 'haml_lint', '>= 0.25.1', require: false # Checks haml files for goodness
gem 'i18n-tasks', require: false # adds tests for finding missing and unused translations gem 'i18n-tasks', require: false # adds tests for finding missing and unused translations
gem 'rspectre', require: false # finds unused code in specs gem 'rspectre', require: false # finds unused code in specs
@@ -194,17 +188,15 @@ end
group :test do group :test do
gem 'axe-core-capybara' gem 'axe-core-capybara'
gem 'axe-core-rspec' gem 'axe-core-rspec'
gem "percy-capybara", "~> 5.0.0" gem 'codeclimate-test-reporter', require: false
gem 'rails-controller-testing' gem 'rails-controller-testing'
gem "rspec-rebound"
gem 'selenium-webdriver' gem 'selenium-webdriver'
gem 'timecop' gem 'timecop'
gem 'vcr' gem 'vcr'
end end
gem "i18n_data", "~> 1.1" group :travis do
gem 'platform-api'
end
gem "paper_trail", "~> 17.0" gem "percy-capybara", "~> 5.0.0"
gem 'aws-sdk-s3', '~> 1', '>= 1.114.0'
gem 'sitemap_generator'

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,7 @@
# 🌱 Growstuff # 🌱 Growstuff
![Build status](https://github.com/Growstuff/growstuff/workflows/CI/badge.svg) ![Build status](https://github.com/Growstuff/growstuff/workflows/CI/badge.svg)
[![Code Climate](https://codeclimate.com/github/Growstuff/growstuff/badges/gpa.svg)](https://codeclimate.com/github/Growstuff/growstuff)
Welcome to the Growstuff project. Welcome to the Growstuff project.
@@ -17,14 +18,13 @@ encourage participation from people of all backgrounds and skill levels.
## Want to contribute? ## Want to contribute?
Don't ask to ask, the best way to get started is to fork the project, start a codespace and get hacking. Don't ask to ask, the best way to get started is to fork the project, start a codespace and get hacking.
Dive on in and submit your PRs! Dive on in and submit your PRs.
Vibe Coding is more than okay, just make sure you indicate if you have done so and ensure there are tests.
## Important links ## Important links
* [Issues](https://github.com/orgs/Growstuff/projects/1) (features we're * [Issues](https://github.com/orgs/Growstuff/projects/1) (features we're
working on, known bugs, etc) working on, known bugs, etc)
* [![Gitter](https://badges.gitter.im/Growstuff/growstuff.svg)](https://gitter.im/Growstuff/growstuff?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
* [Wiki](https://github.com/Growstuff/growstuff/wiki) (general documentation, etc.) * [Wiki](https://github.com/Growstuff/growstuff/wiki) (general documentation, etc.)
## For coders ## For coders
@@ -36,10 +36,6 @@ frontend features. We welcome contributions -- see
* To set up your development environment, see [Getting started](https://github.com/Growstuff/growstuff/wiki/New-contributor-guide). * To set up your development environment, see [Getting started](https://github.com/Growstuff/growstuff/wiki/New-contributor-guide).
* You may also be interested in our [API](https://github.com/Growstuff/growstuff/wiki/API). * You may also be interested in our [API](https://github.com/Growstuff/growstuff/wiki/API).
### For Home Automation enthusiasts
https://github.com/Growstuff/homeassistant-growstuff/
## For designers, writers, researchers, data wranglers, and other contributors ## For designers, writers, researchers, data wranglers, and other contributors
There are heaps of ways to get involved and contribute no matter what There are heaps of ways to get involved and contribute no matter what
@@ -67,3 +63,5 @@ For more information about this project, contact [info@growstuff.org](mailto:inf
Security Issues: If you find an authorization bypass or data breach, please contact our maintainers directly at [maintainers@growstuff.org](mailto:maintainers@growstuff.org). Security Issues: If you find an authorization bypass or data breach, please contact our maintainers directly at [maintainers@growstuff.org](mailto:maintainers@growstuff.org).
You can also contact us on [Twitter](http://twitter.com/growstufforg/) or
[Facebook](https://www.facebook.com/pages/Growstuff/1531133417099494) or [Github](https://github.com/Growstuff/growstuff/issues)..

View File

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 266 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -1,19 +1,11 @@
$(document).ready(function() { $(document).ready(function() {
$('.like-btn').show(); $('.like-btn').show();
/** $('.post-like').on('ajax:success', function(event, data) {
* Handles the result of an ajax call and updates UI var likeButton = $('#post-' + data.id + ' .post-like');
* var likeBadge = $('#post-'+ data.id + ' .like-badge');
* @param {object} data JSON data from ajax response
* @param {string} type object type (ie: post, activity, etc)
*/
var likeableSuccess = function(data, type) {
var target = '.' + type + '-' + data.id;
var objectClass = type.charAt(0).toUpperCase() + type.slice(1);
var likeButton = $(target + ' .' + type + '-like');
var likeBadge = $(target + ' .like-badge');
$(target + ' .like-count').text(data.like_count); $('#post-' + data.id + ' .like-count').text(data.like_count);
if (data.liked_by_member) { if (data.liked_by_member) {
likeBadge.addClass('liked'); likeBadge.addClass('liked');
likeButton.data('method', 'delete'); likeButton.data('method', 'delete');
@@ -22,26 +14,11 @@ $(document).ready(function() {
} else { } else {
likeBadge.removeClass('liked'); likeBadge.removeClass('liked');
likeButton.data('method', 'post'); likeButton.data('method', 'post');
likeButton.attr('href', '/likes.json?type=' + objectClass + '&id=' + data.id); likeButton.attr('href', '/likes.json?type=Post&id=' + data.id);
likeButton.text('Like'); likeButton.text('Like');
} }
};
$('.post-like').on('ajax:success', function(event, data) {
likeableSuccess(data, 'post');
}); });
$('.activity-like').on('ajax:success', function(event, data) {
likeableSuccess(data, 'activity');
});
$('.planting-like').on('ajax:success', function(event, data) {
likeableSuccess(data, 'planting');
});
$('.harvest-like').on('ajax:success', function(event, data) {
likeableSuccess(data, 'harvest');
});
$('.photo-like').on('ajax:success', function(event, data) { $('.photo-like').on('ajax:success', function(event, data) {
var likeBadge = $('#photo-'+ data.id + ' .like-badge'); var likeBadge = $('#photo-'+ data.id + ' .like-badge');

View File

@@ -1,13 +1,7 @@
.crop-icon { .crop-icon {
height: 1em; height: 1em;
} }
.card-footer {
.btn-group-vertical {
.btn {
text-wrap: initial
}
}
}
.crop-thumbnail { .crop-thumbnail {
.text { .text {
bottom: 0; bottom: 0;

View File

@@ -1,8 +1,6 @@
// stats shown on homepage. eg. "999 members..." // stats shown on homepage. eg. "999 members..."
.stats { .stats {
a { font-weight: bold;
font-weight: bold;
}
} }
.crops, .crops,
@@ -16,27 +14,3 @@
.homepage--list-item { .homepage--list-item {
height: 100px; height: 100px;
} }
.releases {
.card {
.card-header {
}
.card-body {
h2 {
background-color: transparent;
color: black;
box-shadow: none;
}
img {
border: 0.5em solid #111;
margin-left: 5%;
margin-right: 5%;
width: 90%;
}
ul {
margin-bottom: 1em;
margin-top: 1em;
}
}
}
}

View File

@@ -33,6 +33,13 @@
} }
} }
.location-not-set {
background-image: image-url("location-not-set.en.png");
background-position: center;
background-repeat: no-repeat;
height: 250px;
width: 100%;
}
.card { .card {
.badge-location { .badge-location {
background-color: darken($blue, 10%); background-color: darken($blue, 10%);

View File

@@ -47,13 +47,4 @@
margin-left: auto; margin-left: auto;
} }
} }
.card-footer {
max-height: 2em;
-webkit-line-clamp: 1;
overflow: hidden;
text-overflow: ellipsis;
margin-bottom: 0.5em;
padding-top: 0;
}
} }

View File

@@ -30,7 +30,3 @@
@import "predictions"; @import "predictions";
@import "homepage"; @import "homepage";
@import "maps"; @import "maps";
@view-transition {
navigation: auto;
}

View File

@@ -10,33 +10,9 @@
width: 100%; width: 100%;
} }
#navbarSupportedContent { .navbar .nav > li {
ul {
flex-direction: column-reverse;
flex-wrap: nowrap;
li.nav-item {
display: block;
a {
display: grid;
grid-template-columns: 2em 1fr 2em;
}
a.dropdown-toggle::after {
width: 100%;
text-align: right;
}
}
}
}
.crop-actions {
flex-direction: column;
width: 100%;
a {
margin: auto;
display: block; display: block;
} }
}
.navbar .navbar-form { .navbar .navbar-form {
padding-left: 0; padding-left: 0;

View File

@@ -8,10 +8,6 @@ body {
font-family: $default-font; font-family: $default-font;
} }
.navbar {
flex-wrap: nowrap;
align-items: flex-start
}
.navbar-brand { .navbar-brand {
.site-name { .site-name {
font-family: "Modak", cursive; font-family: "Modak", cursive;
@@ -20,7 +16,7 @@ body {
} }
img { img {
height: 100%; height: 60px;
} }
} }
@@ -132,8 +128,6 @@ section {
border-radius: 5%; border-radius: 5%;
margin: 0.5em 0.5em 0.5em 0; margin: 0.5em 0.5em 0.5em 0;
width: 200px; width: 200px;
align-items: stretch;
justify-content: space-between;
.img-card { .img-card {
border-top-left-radius: 5%; border-top-left-radius: 5%;
@@ -370,6 +364,9 @@ ul.thumbnail-buttons {
h1 { h1 {
font-size: 400%; font-size: 400%;
} }
.stats a {
color: $black;
}
// signup widget on homepage // signup widget on homepage
.signup { .signup {

View File

@@ -4,44 +4,33 @@ class ActivitiesController < DataController
def index def index
@show_all = params[:all] == '1' @show_all = params[:all] == '1'
@activities = Activity.includes(:owner).order(created_at: :desc) where = {}
@activities = @activities.active unless @show_all where['active'] = true unless @show_all
if params[:member_slug].present? if params[:member_slug]
@owner = Member.find_by!(slug: params[:member_slug]) @owner = Member.find_by(slug: params[:member_slug])
@activities = @activities.where(owner_id: @owner.id) where['owner_id'] = @owner.id unless @owner.nil?
end end
@activities = @activities.paginate(page: params[:page], per_page: 30) @activities = Activity.search(
where:,
page: params[:page],
limit: 30,
boost_by: [:created_at],
load: false
)
@filename = "Growstuff-#{specifics}Activities-#{Time.zone.now.to_fs(:number)}.csv" @filename = "Growstuff-#{specifics}Activities-#{Time.zone.now.to_fs(:number)}.csv"
respond_with(@activities) respond_with(@activities)
end end
def show def show
if @activity.finished? && @activity.owner == current_member && (@activity.updated_at + 2.weeks) > Time.now
@repeat_link = new_activity_path(
name: @activity.name,
garden_id: @activity.garden_id,
planting_id: @activity.planting_id,
category: @activity.category,
description: @activity.description,
due_date: 2.weeks.from_now.to_date
)
end
respond_with @activity respond_with @activity
end end
def new def new
@activity = Activity.new( @activity = Activity.new(
owner: current_member, owner: current_member
due_date: Date.today
) )
@activity.name = params[:name] if params[:name]
@activity.description = params[:description] if params[:description]
@activity.category = params[:category] if params[:category]
@activity.due_date = params[:due_date] if params[:due_date]
if params[:garden_id] if params[:garden_id]
@activity.garden = Garden.find_by( @activity.garden = Garden.find_by(
owner: current_member, owner: current_member,
@@ -68,21 +57,7 @@ class ActivitiesController < DataController
def create def create
@activity = Activity.new(activity_params) @activity = Activity.new(activity_params)
@activity.owner = current_member @activity.owner = current_member
@activity.due_date ||= Date.today @activity.save
if @activity.save
if params[:repeat_times].to_i > 0
repeat_times = params[:repeat_times].to_i
repeat_weeks = params[:repeat_weeks].to_i
repeat_times.times do |i|
new_activity = @activity.dup
new_activity.due_date = @activity.due_date + (i + 1) * repeat_weeks.weeks
new_activity.save
end
end
end
respond_with @activity respond_with @activity
end end
@@ -101,8 +76,7 @@ class ActivitiesController < DataController
def activity_params def activity_params
params.require(:activity).permit( params.require(:activity).permit(
:name, :description, :category, :finished, :name, :description, :category, :finished,
:garden_id, :planting_id, :due_date, :garden_id, :planting_id, :due_date
:repeat_times, :repeat_weeks
) )
end end

View File

@@ -1,40 +0,0 @@
# frozen_string_literal: true
module Admin
class CropCompanionsController < AdminController
before_action :set_crop
def index
@crop_companions = @crop.crop_companions
end
def new
@crop_companion = @crop.crop_companions.new
end
def create
@crop_companion = @crop.crop_companions.new(crop_companion_params)
if @crop_companion.save
redirect_to admin_crop_crop_companions_path(@crop), notice: t('crop_companions.created')
else
render :new
end
end
def destroy
@crop_companion = @crop.crop_companions.find(params[:id])
@crop_companion.destroy
redirect_to admin_crop_crop_companions_path(@crop), notice: t('crop_companions.deleted')
end
private
def set_crop
@crop = Crop.find_by!(slug: params[:crop_slug])
end
def crop_companion_params
params.require(:crop_companion).permit(:crop_b_id, :source_url)
end
end
end

View File

@@ -1,19 +0,0 @@
# frozen_string_literal: true
class Admin::CropsController < ApplicationController
before_action :authenticate_member!
before_action :authorize_admin!
def index
@versions = PaperTrail::Version.where(item_type: 'Crop').order(created_at: :desc).limit(100)
member_ids = @versions.map(&:whodunnit).compact.map(&:to_i)
@members = Member.where(id: member_ids).index_by(&:id)
@crop_wranglers = Role.crop_wranglers
end
private
def authorize_admin!
authorize! :wrangle, Crop
end
end

View File

@@ -8,9 +8,9 @@ module Admin
responders :flash responders :flash
def index def index
@members = Member.order(:login_name) @members = Member.all
@members = @members.where("login_name ILIKE ?", "%#{search_term}%") if search_term.present? @members = @members.where("login_name ILIKE ?", "%#{search_term}%") unless search_term.nil?
@members = @members.paginate(page: params[:page]) @members = @members.order(:login_name).paginate(page: params[:page])
end end
def edit def edit

View File

@@ -1,24 +0,0 @@
# frozen_string_literal: true
module Admin
class VersionsController < ApplicationController
before_action :authenticate_member!
before_action :authorize_admin!
def revert
@version = PaperTrail::Version.find(params[:id])
@object = @version.reify
if @object.save
redirect_to admin_crops_path, notice: t('messages.revert_success', date: @version.created_at.strftime('%B %d, %Y'))
else
redirect_to admin_crops_path, alert: t('messages.revert_error', date: @version.created_at.strftime('%B %d, %Y'), errors: @object.errors.full_messages.to_sentence)
end
end
private
def authorize_admin!
authorize! :wrangle, Crop
end
end
end

View File

@@ -30,7 +30,7 @@ class AlternateNamesController < ApplicationController
@alternate_name = AlternateName.new(alternate_name_params) @alternate_name = AlternateName.new(alternate_name_params)
if @alternate_name.save if @alternate_name.save
redirect_to @alternate_name.crop, notice: t('alternate_names.created') redirect_to @alternate_name.crop, notice: 'Alternate name was successfully created.'
else else
render action: "new" render action: "new"
end end
@@ -40,7 +40,7 @@ class AlternateNamesController < ApplicationController
# PUT /alternate_names/1.json # PUT /alternate_names/1.json
def update def update
if @alternate_name.update(alternate_name_params) if @alternate_name.update(alternate_name_params)
redirect_to @alternate_name.crop, notice: t('alternate_names.updated') redirect_to @alternate_name.crop, notice: 'Alternate name was successfully updated.'
else else
render action: "edit" render action: "edit"
end end
@@ -51,12 +51,12 @@ class AlternateNamesController < ApplicationController
def destroy def destroy
@crop = @alternate_name.crop @crop = @alternate_name.crop
@alternate_name.destroy @alternate_name.destroy
redirect_to @crop, notice: t('alternate_names.deleted') redirect_to @crop, notice: 'Alternate name was successfully deleted.'
end end
private private
def alternate_name_params def alternate_name_params
params.require(:alternate_name).permit(:crop_id, :name, :creator_id, :language) params.require(:alternate_name).permit(:crop_id, :name, :creator_id)
end end
end end

View File

@@ -1,8 +0,0 @@
# frozen_string_literal: true
module Api
module V1
class ActivitiesController < BaseController
end
end
end

View File

@@ -4,40 +4,6 @@ module Api
module V1 module V1
class BaseController < JSONAPI::ResourceController class BaseController < JSONAPI::ResourceController
abstract abstract
protect_from_forgery with: :null_session
before_action :authenticate_member_from_token!
before_action :enforce_member_for_write_operations!, only: %i(create update destroy)
rescue_from CanCan::AccessDenied do
head :forbidden
end
def context
{
current_user: current_user,
current_ability: current_ability,
controller: self,
action: params[:action]
}
end
private
attr_reader :current_user
def enforce_member_for_write_operations!
head :unauthorized unless current_user
end
def authenticate_member_from_token!
authenticate_with_http_token do |token, _options|
auth = Authentication.find_by(token: token, provider: 'api')
if auth.present?
@current_user = auth.member
return true
end
end
end
end end
end end
end end

View File

@@ -3,36 +3,6 @@
module Api module Api
module V1 module V1
class CropsController < BaseController class CropsController < BaseController
def search
term = params[:term]
page = params.dig(:page, :number) || 1
per_page = params.dig(:page, :size) || Crop.per_page
search_results = CropSearchService.search(
term,
page: page,
per_page: per_page,
load: true
)
resources = search_results.map do |crop|
Api::V1::CropResource.new(crop, context)
end
serializer = JSONAPI::ResourceSerializer.new(Api::V1::CropResource)
data = resources.map do |resource|
serializer.object_hash(resource, {})
end
render json: {
data: data,
meta: {
record_count: search_results.total_count,
page_count: search_results.total_pages
}
}
end
end end
end end
end end

View File

@@ -68,7 +68,7 @@ class ApplicationController < ActionController::Base
# profile stuff # profile stuff
:bio, :location, :latitude, :longitude, :bio, :location, :latitude, :longitude,
# email settings # email settings
:show_email, :newsletter, :send_notification_email, :send_planting_reminder, :send_harvest_reminder) :show_email, :newsletter, :send_notification_email, :send_planting_reminder)
end end
devise_parameter_sanitizer.permit(:account_update) do |member| devise_parameter_sanitizer.permit(:account_update) do |member|
@@ -78,9 +78,8 @@ class ApplicationController < ActionController::Base
:tos_agreement, :tos_agreement,
# profile stuff # profile stuff
:bio, :location, :latitude, :longitude, :bio, :location, :latitude, :longitude,
:website_url, :instagram_handle, :facebook_handle, :bluesky_handle, :other_url,
# email settings # email settings
:show_email, :newsletter, :send_notification_email, :send_planting_reminder, :send_harvest_reminder, :show_email, :newsletter, :send_notification_email, :send_planting_reminder,
# update password # update password
:current_password) :current_password)
end end

View File

@@ -24,9 +24,9 @@ class AuthenticationsController < ApplicationController
name: name:
) )
flash[:notice] = t('messages.auth_success') flash[:notice] = "Authentication successful."
else else
flash[:notice] = t('messages.auth_failed') flash[:notice] = "Authentication failed."
end end
redirect_to request.env['omniauth.origin'] || edit_member_registration_path redirect_to request.env['omniauth.origin'] || edit_member_registration_path
end end

View File

@@ -1,32 +0,0 @@
# frozen_string_literal: true
class BlocksController < ApplicationController
load_and_authorize_resource
skip_load_resource only: :create
def create
@block = current_member.blocks.build(blocked: Member.find(params[:blocked]))
if @block.save
flash[:notice] = "Blocked #{@block.blocked.login_name}"
else
flash[:error] = "Already blocking or error while blocking."
end
redirect_back_or_to(root_path)
end
def destroy
@block = current_member.blocks.find(params[:id])
@unblocked = @block.blocked
@block.destroy
flash[:notice] = "Unblocked #{@unblocked.login_name}"
redirect_to @unblocked
end
private
def block_params
params.permit(:id, :blocked)
end
end

View File

@@ -3,7 +3,6 @@
module Charts module Charts
class CropsController < ApplicationController class CropsController < ApplicationController
respond_to :json respond_to :json
before_action :set_crop
def sunniness def sunniness
pie_chart_query 'sunniness' pie_chart_query 'sunniness'
@@ -14,28 +13,20 @@ module Charts
end end
def harvested_for def harvested_for
data = Rails.cache.fetch("#{@crop.cache_key_with_version}/harvested_for", expires_in: 1.day) do @crop = Crop.find_by!(slug: params[:crop_slug])
Harvest.joins(:plant_part) render json: Harvest.joins(:plant_part)
.where(crop: @crop) .where(crop: @crop)
.group("plant_parts.name").count(:id) .group("plant_parts.name").count(:id)
end
render json: data
end end
private private
def set_crop
@crop = Crop.find_by!(slug: params[:crop_slug])
end
def pie_chart_query(field) def pie_chart_query(field)
data = Rails.cache.fetch("#{@crop.cache_key_with_version}/#{field}", expires_in: 1.day) do @crop = Crop.find_by!(slug: params[:crop_slug])
Planting.where(crop: @crop) render json: Planting.where(crop: @crop)
.where.not(field.to_sym => nil) .where.not(field.to_sym => nil)
.where.not(field.to_sym => '') .where.not(field.to_sym => '')
.group(field.to_sym).count(:id) .group(field.to_sym).count(:id)
end
render json: data
end end
end end
end end

View File

@@ -13,55 +13,43 @@ class CommentsController < ApplicationController
end end
def new def new
@commentable = find_commentable
@comment = Comment.new @comment = Comment.new
if @commentable @post = Post.find_by(id: params[:post_id])
@comments = @commentable.comments
if @post
@comments = @post.comments
respond_with(@comments) respond_with(@comments)
else else
redirect_to(request.referer || root_url, redirect_to(request.referer || root_url,
alert: "Can't post a comment on a non-existent commentable") alert: "Can't post a comment on a non-existent post")
end end
end end
def edit def edit
# TODO: Why does this need a collection of comments? @comments = @comment.post.comments
@comments = @comment.commentable.comments
@commentable = @comment.commentable
end end
def create def create
@comment = Comment.new(comment_params) @comment = Comment.new(comment_params)
@commentable = @comment.commentable
@comment.author = current_member @comment.author = current_member
@comment.save @comment.save
respond_with @comment, location: @commentable respond_with @comment, location: @comment.post
end end
def update def update
@comment.update(body: comment_params['body']) @comment.update(body: comment_params['body'])
respond_with @comment, location: @comment.commentable respond_with @comment, location: @comment.post
end end
def destroy def destroy
@commentable = @comment.commentable @post = @comment.post
@comment.destroy @comment.destroy
respond_with(@commentable) respond_with(@post)
end end
private private
def find_commentable
return unless params[:comment]
if params[:comment][:commentable_type] == 'Photo'
Photo.find(params[:comment][:commentable_id])
elsif params[:comment][:commentable_type] == 'Post'
Post.find(params[:comment][:commentable_id])
end
end
def comment_params def comment_params
params.require(:comment).permit(:body, :commentable_id, :commentable_type) params.require(:comment).permit(:body, :post_id)
end end
end end

View File

@@ -13,7 +13,7 @@ class CropsController < ApplicationController
@crops = Crop.search('*', boost_by: %i(plantings_count harvests_count), @crops = Crop.search('*', boost_by: %i(plantings_count harvests_count),
limit: 100, limit: 100,
page: params[:page], page: params[:page],
load: (request.format.csv? || request.format.rss? ? { include: %i(parent scientific_names seeds harvests creator plantings) } : false)) load: false)
@num_requested_crops = requested_crops.size if current_member @num_requested_crops = requested_crops.size if current_member
@filename = filename @filename = filename
respond_with @crops respond_with @crops
@@ -39,6 +39,12 @@ class CropsController < ApplicationController
respond_with @crops respond_with @crops
end end
def openfarm
@crop = Crop.find(params[:crop_slug])
@crop.update_openfarm_data!
respond_with @crop, location: @crop
end
def gbif def gbif
@crop = Crop.find(params[:crop_slug]) @crop = Crop.find(params[:crop_slug])
@crop.update_gbif_data! @crop.update_gbif_data!
@@ -73,8 +79,6 @@ class CropsController < ApplicationController
format.html do format.html do
@posts = @crop.posts.order(created_at: :desc).paginate(page: params[:page]) @posts = @crop.posts.order(created_at: :desc).paginate(page: params[:page])
@companions = @crop.companions.approved @companions = @crop.companions.approved
member_ids = @crop.versions.map(&:whodunnit).compact.map(&:to_i)
@version_members = Member.where(id: member_ids).index_by(&:id)
end end
format.svg do format.svg do
icon_data = @crop.svg_icon.presence || File.read(Rails.root.join("app/assets/images/icons/sprout.svg")) icon_data = @crop.svg_icon.presence || File.read(Rails.root.join("app/assets/images/icons/sprout.svg"))
@@ -133,6 +137,7 @@ class CropsController < ApplicationController
if @crop.approval_status_changed?(from: "pending", to: "approved") if @crop.approval_status_changed?(from: "pending", to: "approved")
notifier.deliver_now! notifier.deliver_now!
@crop.update_openfarm_data!
@crop.update_gbif_data! @crop.update_gbif_data!
end end
else else
@@ -149,34 +154,6 @@ class CropsController < ApplicationController
respond_with @crop respond_with @crop
end end
def data_improvement
@active_tab = params[:tab] || 'photos'
@crops = case @active_tab
when 'photos'
Crop.approved.where(photo_associations_count: 0).order(plantings_count: :desc)
when 'descriptions'
Crop.approved.where(description: [nil, '']).order(plantings_count: :desc)
when 'youtube'
Crop.approved.where(en_youtube_url: [nil, '']).order(plantings_count: :desc)
when 'alternate_names'
Crop.approved.where.missing(:alternate_names).order(plantings_count: :desc)
when 'wikidata'
crops_with_wikidata = Crop.joins(:scientific_names).where.not(scientific_names: { wikidata_id: nil }).distinct
Crop.approved.where.not(id: crops_with_wikidata).order(plantings_count: :desc)
when 'row_spacing'
Crop.approved.where(row_spacing: nil).order(plantings_count: :desc)
when 'sun_requirements'
Crop.approved.where(sun_requirements: [nil, '']).order(plantings_count: :desc)
when 'height'
Crop.approved.where(height: nil).order(plantings_count: :desc)
when 'public_food_key'
Crop.approved.where(public_food_key: [nil, '']).order(plantings_count: :desc)
else
Crop.none
end
end
private private
def notifier def notifier
@@ -189,7 +166,7 @@ class CropsController < ApplicationController
end end
def save_crop_names def save_crop_names
AlternateName.create!(names_params(:alt_name).map { |n| { name: n, creator_id: current_member.id, crop_id: @crop.id, language: "EN" } }) AlternateName.create!(names_params(:alt_name).map { |n| { name: n, creator_id: current_member.id, crop_id: @crop.id } })
ScientificName.create!(names_params(:sci_name).map { |n| { name: n, creator_id: current_member.id, crop_id: @crop.id } }) ScientificName.create!(names_params(:sci_name).map { |n| { name: n, creator_id: current_member.id, crop_id: @crop.id } })
end end
@@ -204,28 +181,26 @@ class CropsController < ApplicationController
def recreate_names(param_name, name_type) def recreate_names(param_name, name_type)
return if params[param_name].blank? return if params[param_name].blank?
@crop.send("#{name_type}_names").each(&:destroy) destroy_names(name_type)
params[param_name].each_value do |value| params[param_name].each_value do |value|
next if value.empty? create_name!(name_type, value) unless value.empty?
if name_type == 'alternate'
@crop.send("#{name_type}_names").create!(name: value, creator_id: current_member.id, language: "EN")
else
@crop.send("#{name_type}_names").create!(name: value, creator_id: current_member.id)
end
end end
end end
def destroy_names(name_type)
@crop.send("#{name_type}_names").each(&:destroy)
end
def create_name!(name_type, value)
@crop.send("#{name_type}_names").create!(name: value, creator_id: current_member.id)
end
def crop_params def crop_params
params.require(:crop).permit( params.require(:crop).permit(
:name, :en_wikipedia_url, :en_youtube_url, :name, :en_wikipedia_url,
:parent_id, :perennial, :parent_id, :perennial,
:request_notes, :reason_for_rejection, :request_notes, :reason_for_rejection,
:rejection_notes, :rejection_notes,
:description,
:public_food_key,
:row_spacing, :spread, :height,
:sowing_method, :sun_requirements, :growing_degree_days,
scientific_names_attributes: %i(scientific_name _destroy id) scientific_names_attributes: %i(scientific_name _destroy id)
) )
end end
@@ -241,12 +216,12 @@ class CropsController < ApplicationController
def crop_json_fields def crop_json_fields
{ {
include: { include: {
plantings: { plantings: {
include: { include: {
owner: { only: %i(id login_name location latitude longitude) } owner: { only: %i(id login_name location latitude longitude) }
} }
}, },
scientific_names: { only: [:name] }, alternate_names: { only: %i(name language) } scientific_names: { only: [:name] }, alternate_names: { only: [:name] }
} }
} }
end end

View File

@@ -13,11 +13,11 @@ class FollowsController < ApplicationController
@follow = current_member.follows.build(followed: Member.find(params[:followed])) @follow = current_member.follows.build(followed: Member.find(params[:followed]))
if @follow.save if @follow.save
flash[:notice] = t('messages.followed', name: @follow.followed.login_name) flash[:notice] = "Followed #{@follow.followed.login_name}"
else else
flash[:error] = t('messages.follow_error') flash[:error] = "Already following or error while following."
end end
redirect_back_or_to(root_path) redirect_back fallback_location: root_path
end end
def destroy def destroy
@@ -25,7 +25,7 @@ class FollowsController < ApplicationController
@unfollowed = @follow.followed @unfollowed = @follow.followed
@follow.destroy @follow.destroy
flash[:notice] = t('messages.unfollowed', name: @unfollowed.login_name) flash[:notice] = "Unfollowed #{@unfollowed.login_name}"
redirect_to @unfollowed redirect_to @unfollowed
end end

View File

@@ -32,14 +32,14 @@ class ForumsController < ApplicationController
# POST /forums.json # POST /forums.json
def create def create
@forum = Forum.new(forum_params) @forum = Forum.new(forum_params)
flash[:notice] = t('forums.created') if @forum.save flash[:notice] = 'Forum was successfully created.' if @forum.save
respond_with(@forum) respond_with(@forum)
end end
# PUT /forums/1 # PUT /forums/1
# PUT /forums/1.json # PUT /forums/1.json
def update def update
flash[:notice] = t('forums.updated') if @forum.update(forum_params) flash[:notice] = 'Forum was successfully updated.' if @forum.update(forum_params)
respond_with(@forum) respond_with(@forum)
end end
@@ -47,7 +47,7 @@ class ForumsController < ApplicationController
# DELETE /forums/1.json # DELETE /forums/1.json
def destroy def destroy
@forum.destroy @forum.destroy
flash[:notice] = t('forums.deleted') flash[:notice] = 'Forum was successfully deleted'
redirect_to forums_url redirect_to forums_url
end end

View File

@@ -1,87 +0,0 @@
# frozen_string_literal: true
class GardenCollaboratorsController < ApplicationController
before_action :authenticate_member!, except: %i(index show)
before_action :load_garden
load_and_authorize_resource id_param: :slug
respond_to :html
responders :flash
def index
@garden_collaborators = @garden.garden_collaborators.paginate(page: params[:page])
respond_with(@garden_collaborators)
end
def show
@garden_collaborator = GardenCollaborator.find(params[:garden_collaborator_id])
respond_with(@garden_collaborator)
end
def new
@garden_collaborator = GardenCollaborator.new(garden: @garden)
authorize! :create, @garden_collaborator
respond_with(@garden_collaborator)
end
def edit
@garden_collaborator = GardenCollaborator.find(params[:id])
authorize! :update, @garden_collaborator
respond_with(@garden_collaborator)
end
def create
@garden_collaborator = GardenCollaborator.new(garden: @garden)
authorize! :create, @garden_collaborator
@member = Member.find_by(slug: params[:garden_collaborator][:member_slug])
@garden_collaborator.member = @member
if @garden_collaborator.save
redirect_to garden_garden_collaborators_path(@garden)
else
respond_with(@garden_collaborator)
end
end
def update
@garden_collaborator = GardenCollaborator.find(params[:id])
authorize! :update, @garden_collaborator
@member = Member.find_by(slug: params[:garden_collaborator][:member_slug])
@garden_collaborator.member = @member
@garden_collaborator.save
respond_with(@garden_collaborator)
end
def destroy
@garden_collaborator = GardenCollaborator.find(params[:id])
authorize! :destroy, @garden_collaborator
if @garden_collaborator.destroy
redirect_to garden_garden_collaborators_path(@garden)
else
respond_with(@garden_collaborator)
end
end
private
def load_garden
@garden = Garden.find_by(slug: params[:garden_slug])
end
def garden_collaborator_params
params.require(:garden_collaborator).permit(
:member_slug
)
end
end

View File

@@ -2,25 +2,21 @@
class GardensController < DataController class GardensController < DataController
def index def index
@owner = Member.find_by!(slug: params[:member_slug]) if params[:member_slug].present? @owner = Member.find_by(slug: params[:member_slug])
@show_all = params[:all] == '1' @show_all = params[:all] == '1'
@show_jump_to = params[:member_slug].present? || false @show_jump_to = params[:member_slug].present? ? true : false
@gardens = @gardens.includes(:owner) @gardens = @gardens.includes(:owner)
@gardens = @gardens.active unless @show_all @gardens = @gardens.active unless @show_all
if @owner.present? @gardens = @gardens.where(owner: @owner) if @owner.present?
@gardens = @gardens.left_joins(:garden_collaborators)
@gardens = @gardens.where(owner: @owner).or(@gardens.where(garden_collaborators: { member: @owner }))
end
@gardens = @gardens.where.not(members: { confirmed_at: nil }) @gardens = @gardens.where.not(members: { confirmed_at: nil })
.order(:name).paginate(page: params[:page]) .order(:name).paginate(page: params[:page])
respond_with(@gardens) respond_with(@gardens)
end end
def show def show
@current_plantings = @garden.plantings.current.where.not(failed: true).includes(:crop, :owner).order(planted_at: :desc) @current_plantings = @garden.plantings.current.includes(:crop, :owner).order(planted_at: :desc)
@current_activities = @garden.activities.current.includes(:owner).order(created_at: :desc) @current_activities = @garden.activities.current.includes(:owner).order(created_at: :desc)
@finished_activities = @garden.activities.finished.includes(:owner).order(created_at: :desc)
@finished_plantings = @garden.plantings.finished.includes(:crop) @finished_plantings = @garden.plantings.finished.includes(:crop)
@suggested_companions = Crop.approved.where( @suggested_companions = Crop.approved.where(
id: CropCompanion.where(crop_a_id: @current_plantings.select(:crop_id)).select(:crop_b_id) id: CropCompanion.where(crop_a_id: @current_plantings.select(:crop_id)).select(:crop_b_id)
@@ -39,10 +35,7 @@ class GardensController < DataController
def create def create
@garden.owner_id = current_member.id @garden.owner_id = current_member.id
if @garden.save flash[:notice] = I18n.t('gardens.created') if @garden.save
link = new_activity_path(name: 'Weed the garden bed', garden_id: @garden.id, due_date: 2.weeks.from_now.to_date)
flash[:notice] = t('gardens.created_prompt_html', link: link).html_safe
end
respond_with(@garden) respond_with(@garden)
end end
@@ -57,23 +50,12 @@ class GardensController < DataController
redirect_to(member_gardens_path(@garden.owner)) redirect_to(member_gardens_path(@garden.owner))
end end
def fetch_wikidata
if @garden.populate_wikidata_info
@garden.save
flash[:notice] = "Wikidata information updated."
else
flash[:alert] = "Could not find Wikidata information for this location."
end
redirect_to @garden
end
private private
def garden_params def garden_params
params.require(:garden).permit( params.require(:garden).permit(
:name, :slug, :description, :active, :name, :slug, :description, :active,
:location, :latitude, :longitude, :area, :area_unit, :garden_type_id, :location, :latitude, :longitude, :area, :area_unit, :garden_type_id
:location_wikidata_id, :lowest_temp_c, :highest_temp_c
) )
end end
end end

View File

@@ -5,8 +5,8 @@ class HarvestsController < DataController
def index def index
where = {} where = {}
if params[:member_slug].present? if params[:member_slug]
@owner = Member.find_by!(slug: params[:member_slug]) @owner = Member.find_by(slug: params[:member_slug])
where['owner_id'] = @owner.id where['owner_id'] = @owner.id
end end
@@ -23,7 +23,7 @@ class HarvestsController < DataController
@harvests = Harvest.search('*', where:, @harvests = Harvest.search('*', where:,
limit: 100, limit: 100,
page: params[:page], page: params[:page],
load: (request.format.csv? ? { include: %i(crop owner plant_part) } : false), load: false,
boost_by: [:created_at]) boost_by: [:created_at])
@filename = csv_filename @filename = csv_filename
@@ -38,9 +38,9 @@ class HarvestsController < DataController
end end
def new def new
@harvest = Harvest.new(new_harvest_params.merge(harvested_at: Time.zone.today)) @harvest = Harvest.new(harvested_at: Time.zone.today)
@planting = @harvest.planting @planting = Planting.find_by(slug: params[:planting_slug]) if params[:planting_slug]
@crop = @harvest.crop @crop = Crop.find_by(id: params[:crop_id])
respond_with(@harvest) respond_with(@harvest)
end end
@@ -52,7 +52,7 @@ class HarvestsController < DataController
def create def create
@harvest.crop_id = @harvest.planting.crop_id if @harvest.planting_id @harvest.crop_id = @harvest.planting.crop_id if @harvest.planting_id
@harvest.harvested_at = Time.zone.now if @harvest.harvested_at.blank? @harvest.harvested_at = Time.zone.now if @harvest.harvested_at.blank?
update_planting_rating if @harvest.save @harvest.save
if params[:return] == 'planting' if params[:return] == 'planting'
respond_with(@harvest, location: @harvest.planting) respond_with(@harvest, location: @harvest.planting)
else else
@@ -61,7 +61,7 @@ class HarvestsController < DataController
end end
def update def update
update_planting_rating if @harvest.update(harvest_params) @harvest.update(harvest_params)
respond_with(@harvest) respond_with(@harvest)
end end
@@ -76,17 +76,7 @@ class HarvestsController < DataController
params.require(:harvest) params.require(:harvest)
.permit(:planting_id, :crop_id, :harvested_at, :description, .permit(:planting_id, :crop_id, :harvested_at, :description,
:quantity, :unit, :weight_quantity, :weight_unit, :quantity, :unit, :weight_quantity, :weight_unit,
:plant_part_id, :slug, :si_weight, :overall_rating) :plant_part_id, :slug, :si_weight)
.merge(owner_id: current_member.id)
end
def new_harvest_params
return {} unless params[:harvest]
params.require(:harvest)
.permit(:planting_id, :crop_id, :harvested_at, :description,
:quantity, :unit, :weight_quantity, :weight_unit,
:plant_part_id, :slug, :si_weight, :overall_rating)
.merge(owner_id: current_member.id) .merge(owner_id: current_member.id)
end end
@@ -113,10 +103,4 @@ class HarvestsController < DataController
@harvest.planting.update_harvest_days! @harvest.planting.update_harvest_days!
@harvest.crop.update_harvest_medians @harvest.crop.update_harvest_medians
end end
def update_planting_rating
return if @harvest.planting.nil? || params[:harvest][:overall_rating].blank?
@harvest.planting.update(overall_rating: params[:harvest][:overall_rating])
end
end end

View File

@@ -10,6 +10,4 @@ class HomeController < ApplicationController
# the relevant class methods directly in the view, so that fragment # the relevant class methods directly in the view, so that fragment
# caching will be effective. # caching will be effective.
end end
def community_gardens; end
end end

View File

@@ -14,7 +14,7 @@ class LikesController < ApplicationController
@like.likeable.reindex(refresh: true) @like.likeable.reindex(refresh: true)
success(@like, liked_by_member: true, status_code: :created) success(@like, liked_by_member: true, status_code: :created)
else else
failed(@like, message: t('messages.unable_to_like')) failed(@like, message: 'Unable to like')
end end
end end
@@ -29,7 +29,7 @@ class LikesController < ApplicationController
@like.likeable.reindex(refresh: true) @like.likeable.reindex(refresh: true)
success(@like, liked_by_member: false, status_code: :ok) success(@like, liked_by_member: false, status_code: :ok)
else else
failed(@like, message: t('messages.unable_to_unlike')) failed(@like, message: 'Unable to unlike')
end end
end end

View File

@@ -16,6 +16,7 @@ class MembersController < ApplicationController
def show def show
@member = Member.confirmed.kept.find_by!(slug: params[:slug]) @member = Member.confirmed.kept.find_by!(slug: params[:slug])
@twitter_auth = @member.auth('twitter')
@flickr_auth = @member.auth('flickr') @flickr_auth = @member.auth('flickr')
@posts = @member.posts @posts = @member.posts
@@ -90,12 +91,11 @@ class MembersController < ApplicationController
EMAIL_TYPE_STRING = { EMAIL_TYPE_STRING = {
send_notification_email: "direct message notifications", send_notification_email: "direct message notifications",
send_planting_reminder: "planting reminders", send_planting_reminder: "planting reminders"
send_harvest_reminder: "harvest reminders"
}.freeze }.freeze
def member_params def member_params
params.require(:member).permit(:login_name, :tos_agreement, :email, :newsletter, :send_harvest_reminder) params.require(:member).permit(:login_name, :tos_agreement, :email, :newsletter)
end end
def member_json_fields def member_json_fields

View File

@@ -27,21 +27,10 @@ class MessagesController < ApplicationController
def create def create
if params[:conversation_id].present? if params[:conversation_id].present?
@conversation = Mailboxer::Conversation.find(params[:conversation_id]) @conversation = Mailboxer::Conversation.find(params[:conversation_id])
# Check if any of the recipients have blocked the sender
if @conversation.recipients.any? { |recipient| recipient.already_blocking?(current_member) }
flash[:error] = "You cannot reply to this conversation because one of the recipients has blocked you."
redirect_to conversation_path(@conversation)
return
end
current_member.reply_to_conversation(@conversation, params[:body]) current_member.reply_to_conversation(@conversation, params[:body])
redirect_to conversation_path(@conversation) redirect_to conversation_path(@conversation)
else else
recipient = Member.find(params[:recipient_id]) recipient = Member.find(params[:recipient_id])
if recipient.already_blocking?(current_member)
flash[:error] = "You cannot send a message to a member who has blocked you."
redirect_back_or_to(root_path)
return
end
body = params[:body] body = params[:body]
subject = params[:subject] subject = params[:subject]
@conversation = current_member.send_message(recipient, body, subject) @conversation = current_member.send_message(recipient, body, subject)

View File

@@ -10,7 +10,7 @@ require './lib/actions/oauth_signup_action'
# #
class OmniauthCallbacksController < Devise::OmniauthCallbacksController class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def failure def failure
flash[:alert] = t('messages.auth_failed') flash[:alert] = "Authentication failed."
redirect_to request.env['omniauth.origin'] || "/" redirect_to request.env['omniauth.origin'] || "/"
end end
@@ -28,7 +28,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
@authentication = action.establish_authentication(auth, member) @authentication = action.establish_authentication(auth, member)
if action.member_created? if action.member_created?
raise "Invalid provider" unless %w(flickr).index(auth['provider'].to_s) raise "Invalid provider" unless %w(twitter flickr).index(auth['provider'].to_s)
session["devise.#{auth['provider']}_data"] = request.env["omniauth.auth"] session["devise.#{auth['provider']}_data"] = request.env["omniauth.auth"]
sign_in member sign_in member

View File

@@ -21,7 +21,6 @@ class PhotosController < ApplicationController
def show def show
@crops = Crop.distinct.joins(:photo_associations).where(photo_associations: { photo: @photo }) @crops = Crop.distinct.joins(:photo_associations).where(photo_associations: { photo: @photo })
@comment = Comment.new(commentable: @photo)
respond_with(@photo) respond_with(@photo)
end end
@@ -102,12 +101,11 @@ class PhotosController < ApplicationController
end end
@current_set = params[:set] @current_set = params[:set]
@current_tag = params[:tag]
page = params[:page] || 1 page = params[:page] || 1
@sets = current_member.flickr_sets @sets = current_member.flickr_sets
photos, total = current_member.flickr_photos(page, @current_set, @current_tag) photos, total = current_member.flickr_photos(page, @current_set)
@photos = WillPaginate::Collection.create(page, 30, total) do |pager| @photos = WillPaginate::Collection.create(page, 30, total) do |pager|
pager.replace photos pager.replace photos
@@ -119,8 +117,6 @@ class PhotosController < ApplicationController
{ crops: @crop.id } { crops: @crop.id }
elsif params[:planting_id] elsif params[:planting_id]
{ planting_id: @planting.id } { planting_id: @planting.id }
elsif params[:planting_slug]
{ plantings: @planting.id }
else else
{} {}
end end
@@ -129,6 +125,5 @@ class PhotosController < ApplicationController
def set_crop_and_planting def set_crop_and_planting
@crop = Crop.find params[:crop_slug] if params[:crop_slug] @crop = Crop.find params[:crop_slug] if params[:crop_slug]
@planting = Planting.find params[:planting_id] if params[:planting_id] @planting = Planting.find params[:planting_id] if params[:planting_id]
@planting ||= Planting.find params[:planting_slug] if params[:planting_slug]
end end
end end

View File

@@ -33,7 +33,7 @@ class PlacesController < ApplicationController
def search def search
if params[:new_place].empty? if params[:new_place].empty?
redirect_to places_path, alert: t('messages.invalid_location') redirect_to places_path, alert: 'Please enter a valid location'
else else
redirect_to place_path(params[:new_place]) redirect_to place_path(params[:new_place])
end end

View File

@@ -11,9 +11,9 @@ class PlantingsController < DataController
where = {} where = {}
where['active'] = true unless @show_all where['active'] = true unless @show_all
if params[:member_slug].present? if params[:member_slug]
@owner = Member.find_by!(slug: params[:member_slug]) @owner = Member.find_by(slug: params[:member_slug])
where['owner_id'] = @owner.id where['owner_id'] = @owner.id unless @owner.nil?
end end
if params[:crop_slug] if params[:crop_slug]
@@ -37,7 +37,6 @@ class PlantingsController < DataController
@photos = @planting.photos.includes(:owner).order(date_taken: :desc) @photos = @planting.photos.includes(:owner).order(date_taken: :desc)
@harvests = Harvest.search(where: { planting_id: @planting.id }) @harvests = Harvest.search(where: { planting_id: @planting.id })
@current_activities = @planting.activities.current.includes(:owner).order(created_at: :desc) @current_activities = @planting.activities.current.includes(:owner).order(created_at: :desc)
@finished_activities = @planting.activities.finished.includes(:owner).order(created_at: :desc)
@matching_seeds = matching_seeds @matching_seeds = matching_seeds
@crop = @planting.crop @crop = @planting.crop
@@ -46,12 +45,6 @@ class PlantingsController < DataController
.where.not(id: @planting.id) .where.not(id: @planting.id)
.includes(:owner, :crop, :garden) .includes(:owner, :crop, :garden)
.limit(6) .limit(6)
if @planting.finished? && @planting.garden.plantings.current.none? && (@planting.updated_at + 2.weeks) > Time.zone.now
@cultivate_soil_link = new_activity_path(name: 'Cultivate soil', garden_id: @planting.garden_id, category: "Soil Cultivation",
description: "Recently finished #{@planting.crop.name} planting. Prepare for next planting.")
end
respond_with @planting respond_with @planting
end end
@@ -98,32 +91,6 @@ class PlantingsController < DataController
respond_with @planting, location: @planting.garden respond_with @planting, location: @planting.garden
end end
def transplant
# The `load_and_authorize_resource` in DataController will handle finding the
# planting and authorizing the action.
# We still need to authorize the new garden
new_garden = Garden.find(params[:garden_id])
authorize! :update, new_garden
# Mark original planting as finished
@planting.update(finished: true, finished_at: Time.zone.now)
# Create a new planting
new_planting = @planting.dup
new_planting.garden = new_garden
new_planting.slug = nil # let friendly_id generate a new slug
new_planting.finished = false
new_planting.finished_at = nil
if new_planting.save
redirect_to edit_planting_path(new_planting), notice: t('messages.transplant_success')
else
# if the save fails, we should probably roll back the finishing of the original planting
@planting.update(finished: false, finished_at: nil)
redirect_to @planting, alert: t('messages.transplant_error', errors: new_planting.errors.full_messages.to_sentence)
end
end
private private
def update_crop_medians def update_crop_medians
@@ -140,7 +107,7 @@ class PlantingsController < DataController
:crop_id, :description, :garden_id, :planted_at, :crop_id, :description, :garden_id, :planted_at,
:parent_seed_id, :parent_seed_id,
:quantity, :sunniness, :planted_from, :finished, :quantity, :sunniness, :planted_from, :finished,
:finished_at, :failed, :overall_rating :finished_at
) )
end end
@@ -160,7 +127,7 @@ class PlantingsController < DataController
end end
def matching_seeds def matching_seeds
@matching_seeds ||= Seed.where(crop: @planting.crop, owner: @planting.owner) Seed.where(crop: @planting.crop, owner: @planting.owner)
.where('(finished_at IS NULL OR finished_at >= ?)', @planting.planted_at) .where('(finished_at IS NULL OR finished_at >= ?)', @planting.planted_at)
.where('(saved_at IS NULL OR saved_at <= ?)', @planting.planted_at) .where('(saved_at IS NULL OR saved_at <= ?)', @planting.planted_at)
end end

View File

@@ -8,7 +8,7 @@ class PostsController < ApplicationController
respond_to :rss, only: %i(index show) respond_to :rss, only: %i(index show)
def index def index
@author = Member.find_by!(slug: params[:member_slug]) if params[:member_slug].present? @author = Member.find_by(slug: params[:member_slug])
@posts = posts @posts = posts
respond_with(@posts) respond_with(@posts)
end end
@@ -21,10 +21,6 @@ class PostsController < ApplicationController
def new def new
@post = Post.new @post = Post.new
@forum = Forum.find_by(id: params[:forum_id]) @forum = Forum.find_by(id: params[:forum_id])
if params[:crop_id]
@crop = Crop.friendly.find(params[:crop_id])
@post.body = "[#{@crop.name}](crop)"
end
respond_with(@post) respond_with(@post)
end end
@@ -33,17 +29,17 @@ class PostsController < ApplicationController
def create def create
params[:post][:author_id] = current_member.id params[:post][:author_id] = current_member.id
@post = Post.new(post_params) @post = Post.new(post_params)
flash[:notice] = t('posts.created') if @post.save flash[:notice] = 'Post was successfully created.' if @post.save
respond_with(@post) respond_with(@post)
end end
def update def update
flash[:notice] = t('posts.updated') if @post.update(post_params) flash[:notice] = 'Post was successfully updated.' if @post.update(post_params)
respond_with(@post) respond_with(@post)
end end
def destroy def destroy
flash[:notice] = t('posts.deleted') if @post.destroy flash[:notice] = 'Post was deleted.' if @post.destroy
respond_with(@post) respond_with(@post)
end end

View File

@@ -6,7 +6,8 @@ class RegistrationsController < Devise::RegistrationsController
prepend_before_action :check_captcha, only: [:create] # Change this to be any actions you want to protect with recaptcha. prepend_before_action :check_captcha, only: [:create] # Change this to be any actions you want to protect with recaptcha.
def edit def edit
@flickr_auth = current_member.auth('flickr') @twitter_auth = current_member.auth('twitter')
@flickr_auth = current_member.auth('flickr')
render "edit" render "edit"
end end
@@ -38,12 +39,6 @@ class RegistrationsController < Devise::RegistrationsController
end end
end end
def regenerate_api_token
current_member.regenerate_api_token
set_flash_message :notice, :api_token_regenerated
redirect_to edit_member_registration_path + '#apps'
end
def destroy def destroy
if @member.valid_password?(params.require(:member)[:current_password]) if @member.valid_password?(params.require(:member)[:current_password])
@member.discard @member.discard

View File

@@ -54,7 +54,7 @@ class ScientificNamesController < ApplicationController
def destroy def destroy
@crop = @scientific_name.crop @crop = @scientific_name.crop
@scientific_name.destroy @scientific_name.destroy
flash[:notice] = t('scientific_names.deleted') flash[:notice] = 'Scientific name was successfully deleted.'
respond_with(@crop) respond_with(@crop)
end end
@@ -74,7 +74,7 @@ class ScientificNamesController < ApplicationController
end end
def scientific_name_params def scientific_name_params
params.require(:scientific_name).permit(:crop_id, :name, :gbif_key, :wikidata_id) params.require(:scientific_name).permit(:crop_id, :name, :gbif_key)
end end
def gbif_service def gbif_service

View File

@@ -5,7 +5,7 @@ class SeedsController < DataController
where = {} where = {}
if params[:member_slug].present? if params[:member_slug].present?
@owner = Member.find_by!(slug: params[:member_slug]) @owner = Member.find_by(slug: params[:member_slug])
where['owner_id'] = @owner.id where['owner_id'] = @owner.id
end end
@@ -19,8 +19,6 @@ class SeedsController < DataController
where['parent_planting'] = @planting.id where['parent_planting'] = @planting.id
end end
where['tradeable_to'] = params[:tradeable_to] if params[:tradeable_to].present?
@show_all = (params[:all] == '1') @show_all = (params[:all] == '1')
where['finished'] = false unless @show_all where['finished'] = false unless @show_all
@@ -30,7 +28,7 @@ class SeedsController < DataController
page: params[:page], page: params[:page],
limit: 30, limit: 30,
boost_by: [:created_at], boost_by: [:created_at],
load: (request.format.csv? ? { include: %i(crop owner) } : false) load: false
) )
respond_with(@seeds) respond_with(@seeds)
@@ -43,7 +41,6 @@ class SeedsController < DataController
def new def new
@seed = Seed.new @seed = Seed.new
@seed.source = 'my own seed saving'
if params[:planting_slug] if params[:planting_slug]
@planting = Planting.find_by(slug: params[:planting_slug]) @planting = Planting.find_by(slug: params[:planting_slug])
@@ -57,11 +54,9 @@ class SeedsController < DataController
def create def create
@seed = Seed.new(seed_params) @seed = Seed.new(seed_params)
@seed.source ||= 'my own seed saving'
@seed.finished ||= false
@seed.owner = current_member @seed.owner = current_member
@seed.crop = @seed.parent_planting.crop if @seed.parent_planting @seed.crop = @seed.parent_planting.crop if @seed.parent_planting
flash[:notice] = t('seeds.added_to_stash', crop: @seed.crop) if @seed.save flash[:notice] = "Successfully added #{@seed.crop} seed to your stash." if @seed.save
if params[:return] == 'planting' if params[:return] == 'planting'
respond_with(@seed, location: @seed.parent_planting) respond_with(@seed, location: @seed.parent_planting)
else else
@@ -70,7 +65,7 @@ class SeedsController < DataController
end end
def update def update
flash[:notice] = t('seeds.updated') if @seed.update(seed_params) flash[:notice] = 'Seed was successfully updated.' if @seed.update(seed_params)
respond_with(@seed) respond_with(@seed)
end end
@@ -86,7 +81,7 @@ class SeedsController < DataController
:crop_id, :description, :quantity, :plant_before, :crop_id, :description, :quantity, :plant_before,
:parent_planting_id, :saved_at, :parent_planting_id, :saved_at,
:days_until_maturity_min, :days_until_maturity_max, :days_until_maturity_min, :days_until_maturity_max,
:organic, :gmo, :source, :organic, :gmo,
:heirloom, :tradable_to, :slug, :heirloom, :tradable_to, :slug,
:finished, :finished_at :finished, :finished_at
) )

View File

@@ -5,7 +5,7 @@ class SessionsController < Devise::SessionsController
def create def create
super do |_resource| super do |_resource|
flash[:alert] = t('messages.crops_waiting') if Crop.pending_approval.present? && current_member.role?(:crop_wrangler) flash[:alert] = "There are crops waiting to be wrangled." if Crop.pending_approval.present? && current_member.role?(:crop_wrangler)
end end
end end
end end

View File

@@ -1,6 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'nokogiri'
module ApplicationHelper module ApplicationHelper
def parse_date(str) def parse_date(str)
str ||= '' # Date.parse barfs on nil str ||= '' # Date.parse barfs on nil
@@ -22,32 +21,6 @@ module ApplicationHelper
classes classes
end end
# Similar to Rails' time_ago_in_words, but gives a more standard
# output like "in 3 days" or "5 months ago".
# Also handles the case where from_time is a Date and to_time is a Date
# (in which case it just says "today" if they're the same date).
#
# NOTE: This is similar to distance_of_time_in_words but different enough
# that I think it's worth having a separate helper for it.
#
# from_time - the starting time (Time or Date)
# to_time - the ending time (Time or Date). Default: now (Time.zone.now)
# include_seconds - whether to include seconds in the calculation
#
# Returns a string like "in 3 days" or "5 months ago"
def standard_time_distance(from_time, to_time = 0, include_seconds = false)
return 'today' if from_time.is_a?(Date) && (from_time == to_time)
return 'now' if from_time == to_time
return "#{distance_of_time_in_words(from_time, to_time, include_seconds:)} ago" if from_time < to_time
"in #{distance_of_time_in_words(from_time, to_time, include_seconds:)}"
end
def count_github_contibutors
File.open(Rails.root.join('CONTRIBUTORS.md')).readlines.grep(/^-/).size
end
# Produces a cache key for uniquely identifying cached fragments. # Produces a cache key for uniquely identifying cached fragments.
def cache_key_for(klass, identifier = "all") def cache_key_for(klass, identifier = "all")
count = klass.count count = klass.count
@@ -55,6 +28,12 @@ module ApplicationHelper
"#{klass.name.downcase.pluralize}/#{identifier}-#{count}-#{max_updated_at}" "#{klass.name.downcase.pluralize}/#{identifier}-#{count}-#{max_updated_at}"
end end
def required_field_help_text
asterisk = tag.span('*', class: ['red'])
text = tag.em('denotes a required field')
tag.div(asterisk + ' '.html_safe + text, class: ['margin-bottom'])
end
# A helper to replace the complex template compilation mess # A helper to replace the complex template compilation mess
# of HAML, Tilt, and dynamic compilation with interpolated ruby. # of HAML, Tilt, and dynamic compilation with interpolated ruby.
def markdownify(text) def markdownify(text)
@@ -77,6 +56,7 @@ module ApplicationHelper
uri.query = "&width=#{size}&height=#{size}" if uri.host == 'graph.facebook.com' uri.query = "&width=#{size}&height=#{size}" if uri.host == 'graph.facebook.com'
# TODO: Assess twitter - https://dev.twitter.com/overview/general/user-profile-images-and-banners
# TODO: Assess flickr - https://www.flickr.com/services/api/misc.buddyicons.html # TODO: Assess flickr - https://www.flickr.com/services/api/misc.buddyicons.html
return uri.to_s return uri.to_s
@@ -120,22 +100,4 @@ module ApplicationHelper
def og_description(description) def og_description(description)
strip_tags(description).split(' ')[0..20].join(' ') strip_tags(description).split(' ')[0..20].join(' ')
end end
def github_releases
return [] if Rails.env.test?
feed_url = 'https://github.com/Growstuff/growstuff/releases.atom'
Rails.cache.fetch(feed_url, expires_in: 1.day) do
response = Faraday.get(feed_url)
doc = Nokogiri::XML(response.body)
doc.xpath('//xmlns:entry').first(2).map do |entry|
{
title: entry.xpath('xmlns:title').text,
content: entry.xpath('xmlns:content').text,
link: entry.xpath('xmlns:link/@href').text,
updated: entry.xpath('xmlns:updated').text
}
end
end
end
end end

View File

@@ -13,7 +13,7 @@ module AutoSuggestHelper
resource = resource.class.name.downcase resource = resource.class.name.downcase
source_path = Rails.application.routes.url_helpers.send("search_#{source}s_path", format: :json) source_path = Rails.application.routes.url_helpers.send("search_#{source}s_path", format: :json)
%( %(
<input id="#{source}" class="auto-suggest #{options[:class]}" #{'required="required"' if options[:required]} <input id="#{source}" class="auto-suggest #{options[:class]}"
type="text" value="#{default}" data-source-url="#{source_path}", type="text" value="#{default}" data-source-url="#{source_path}",
placeholder="e.g. lettuce"> placeholder="e.g. lettuce">
<noscript class="text-warning"> <noscript class="text-warning">

View File

@@ -2,7 +2,6 @@
module ButtonsHelper module ButtonsHelper
include IconsHelper include IconsHelper
def garden_plant_something_button(garden, classes: "btn btn-default") def garden_plant_something_button(garden, classes: "btn btn-default")
return unless can? :edit, garden return unless can? :edit, garden
@@ -53,7 +52,7 @@ module ButtonsHelper
link_to t('buttons.mark_as_inactive'), link_to t('buttons.mark_as_inactive'),
garden_path(garden, garden: { active: 0 }), garden_path(garden, garden: { active: 0 }),
method: :put, class: classes, method: :put, class: classes,
data: { confirm: I18n.t('gardens.confirm_deactivate') } data: { confirm: 'All plantings associated with this garden will be marked as finished. Are you sure?' }
end end
def create_button(model_to_create, path, icon, label) def create_button(model_to_create, path, icon, label)
@@ -85,20 +84,7 @@ module ButtonsHelper
end end
def activity_edit_button(activity, classes: "btn btn-raised btn-info") def activity_edit_button(activity, classes: "btn btn-raised btn-info")
edit_button(edit_activity_path(slug: activity.slug), classes:) edit_button(edit_activity_path(activity), classes:)
end
def activity_copy_button(activity, classes: 'btn')
link_to new_activity_path(
name: activity.name,
description: activity.description,
category: activity.category,
garden_id: activity.garden_id,
planting_id: activity.planting_id,
due_date: activity.due_date
), class: classes do
copy_icon + ' ' + t('buttons.copy')
end
end end
def activity_finish_button(activity, classes: 'btn btn-default btn-secondary') def activity_finish_button(activity, classes: 'btn btn-default btn-secondary')
@@ -111,7 +97,7 @@ module ButtonsHelper
end end
def planting_finish_button(planting, classes: 'btn btn-default btn-secondary') def planting_finish_button(planting, classes: 'btn btn-default btn-secondary')
return unless can?(:edit, planting) || planting.finished || planting.failed return unless can?(:edit, planting) || planting.finished
link_to planting_path(slug: planting.slug, planting: { finished: 1 }), link_to planting_path(slug: planting.slug, planting: { finished: 1 }),
method: :put, class: "#{classes} append-date" do method: :put, class: "#{classes} append-date" do
@@ -119,15 +105,6 @@ module ButtonsHelper
end end
end end
def planting_failed_button(planting, classes: 'btn btn-default btn-secondary')
return unless can?(:edit, planting) || planting.finished || planting.failed
link_to planting_path(slug: planting.slug, planting: { failed: 1 }),
method: :put, class: "#{classes}" do
finished_icon + ' ' + t('buttons.mark_as_failed')
end
end
def seed_finish_button(seed, classes: 'btn btn-default') def seed_finish_button(seed, classes: 'btn btn-default')
return unless can?(:create, Planting) && seed.active return unless can?(:create, Planting) && seed.active
@@ -145,7 +122,7 @@ module ButtonsHelper
end end
def planting_save_seeds_button(planting, classes: 'btn btn-default') def planting_save_seeds_button(planting, classes: 'btn btn-default')
return unless can?(:edit, planting) && !planting.failed? return unless can?(:edit, planting)
link_to new_planting_seed_path(planting_slug: planting.slug), class: classes do link_to new_planting_seed_path(planting_slug: planting.slug), class: classes do
seed_icon + ' ' + t('buttons.save_seeds') seed_icon + ' ' + t('buttons.save_seeds')

View File

@@ -1,115 +1,20 @@
# frozen_string_literal: true # frozen_string_literal: true
module CropsHelper module CropsHelper
def crop_or_parent(crop, attribute)
@crop_or_parent_cache ||= {}
cache_key = [crop.persisted? ? crop.id : crop.object_id, attribute]
return @crop_or_parent_cache[cache_key] if @crop_or_parent_cache.key?(cache_key)
@crop_or_parent_cache[cache_key] = begin
value = crop.send(attribute)
if value.blank?
parent = crop
while (parent = parent.parent)
parent_value = parent.send(attribute)
if parent_value.present?
value = parent_value
break
end
end
end
value
end
end
def display_seed_availability(member, crop) def display_seed_availability(member, crop)
@seed_availability_cache ||= {} seeds = member.seeds.where(crop:)
cache_key = [ total_quantity = seeds.where.not(quantity: nil).sum(:quantity)
member.persisted? ? member.id : member.object_id,
crop.persisted? ? crop.id : crop.object_id
]
return @seed_availability_cache[cache_key] if @seed_availability_cache.key?(cache_key)
@seed_availability_cache[cache_key] = begin return "You don't have any seeds of this crop." if seeds.none?
seeds = member.seeds.where(crop:)
if seeds.none? if total_quantity == 0
"You don't have any seeds of this crop." "You have an unknown quantity of seeds of this crop."
else else
total_quantity = seeds.where.not(quantity: nil).sum(:quantity) "You have #{total_quantity} #{Seed.model_name.human(count: total_quantity)} of this crop."
if total_quantity == 0
"You have an unknown quantity of seeds of this crop."
else
"You have #{total_quantity} #{Seed.model_name.human(count: total_quantity)} of this crop."
end
end
end end
end end
def crop_ebay_seeds_url(crop) def crop_ebay_seeds_url(crop)
"https://www.ebay.com/sch/i.html?_nkw=#{CGI.escape crop.name}" "https://www.ebay.com/sch/i.html?_nkw=#{CGI.escape crop.name}"
end end
def youtube_video_id(url)
return unless url
regex = %r{(?:youtube(?:-nocookie)?\.com/(?:[^/\n\s]+/\S+/|(?:v|e(?:mbed)?)/|\S*?[?&]v=)|youtu\.be/)([a-zA-Z0-9_-]{11})}
match = url.match(regex)
match[1] if match
end
def crop_jsonld_data(crop, full_attributes: true)
Rails.cache.fetch([crop.cache_key_with_version, "jsonld", full_attributes]) do
same_as_urls = [crop.en_wikipedia_url]
crop.scientific_names.each do |scientific_name|
if scientific_name.wikidata_id.present?
same_as_urls << "https://www.wikidata.org/wiki/#{scientific_name.wikidata_id}"
end
end
subject_of_entities = []
images = []
if full_attributes
if crop.en_youtube_url.present?
subject_of_entities << {
'@type': "VideoObject",
url: crop.en_youtube_url
}
end
crop.posts.each do |post|
subject_of_entities << {
'@type': "SocialMediaPosting",
url: post_url(post),
author: {
'@type': 'Person',
name: post.author.login_name
},
datePublished: post.created_at
}
end
crop.photos.each do |photo|
images << photo.fullsize_url
end
end
# TODO: Review plantings, seeds, harvests as a subtype of social media post or event that ended? Or creative work?
# has_many :plantings, dependent: :destroy
# has_many :seeds, dependent: :destroy
# has_many :harvests, dependent: :destroy
{
'@context': "https://schema.org",
'@type': "BioChemEntity",
name: crop.name,
taxonomicRange: crop.scientific_names.map(&:name),
description: crop.description,
sameAs: same_as_urls,
alternateName: crop.alternate_names.map(&:name),
subjectOf: subject_of_entities,
image: images
}.compact
end
end
end end

View File

@@ -7,8 +7,6 @@ module EventHelper
def event_description(event) def event_description(event)
render "#{event.event_type.pluralize}/description", event_model: resolve_model(event) render "#{event.event_type.pluralize}/description", event_model: resolve_model(event)
rescue ActionView::MissingTemplate
"#{event.event_type.humanize.downcase}d"
end end
def resolve_model(event) def resolve_model(event)

View File

@@ -59,10 +59,6 @@ module IconsHelper
image_icon 'delete' image_icon 'delete'
end end
def copy_icon
icon('far', 'copy')
end
def add_photo_icon def add_photo_icon
image_icon 'add-photo' image_icon 'add-photo'
end end

View File

@@ -43,18 +43,6 @@ module PlantingsHelper
(planting.first_harvest_predicted_at - Time.zone.today).to_i (planting.first_harvest_predicted_at - Time.zone.today).to_i
end end
# Returns a list of gardens the planting can be transplanted to
# based on the planting's owner.
def transplantable_gardens_by_owner(planting)
@transplantable_gardens ||= {}
cache_key = planting.id || planting.object_id
@transplantable_gardens[cache_key] ||= begin
garden_ids = planting.owner.gardens.select(:id).to_a + GardenCollaborator.where(member_id: planting.owner.id).select(:garden_id).to_a
Garden.active.where.not(id: planting.garden_id).where(id: garden_ids)
end
end
def days_from_now_to_last_harvest(planting) def days_from_now_to_last_harvest(planting)
return unless planting.planted_at.present? && planting.last_harvest_predicted_at.present? return unless planting.planted_at.present? && planting.last_harvest_predicted_at.present?

View File

@@ -57,19 +57,6 @@ class NotifierMailer < ApplicationMailer
mail(to: @member.email, subject: @subject) if @member.send_planting_reminder mail(to: @member.email, subject: @subject) if @member.send_planting_reminder
end end
def harvest_reminder(member)
@member = member
@plantings = @member.plantings.active.select(&:harvest_in_next_week?)
@sitename = ENV.fetch('GROWSTUFF_SITE_NAME', nil)
@subject = I18n.t('notifier_mailer.harvest_reminder.subject', sitename: @sitename)
# Encrypting
message = { member_id: @member.id, type: :send_harvest_reminder }
@signed_message = verifier.generate(message)
mail(to: @member.email, subject: @subject) if @member.send_harvest_reminder
end
def new_crop_request(member, request) def new_crop_request(member, request)
@member = member @member = member
@request = request @request = request

View File

@@ -76,7 +76,6 @@ class Ability
if member.role? :crop_wrangler if member.role? :crop_wrangler
can :wrangle, Crop can :wrangle, Crop
can :manage, Crop can :manage, Crop
can :manage, CropCompanion
can :manage, ScientificName can :manage, ScientificName
can :manage, AlternateName can :manage, AlternateName
can :openfarm, Crop can :openfarm, Crop
@@ -109,43 +108,16 @@ class Ability
can :create, Planting can :create, Planting
can :update, Planting, garden: { owner_id: member.id }, crop: { approval_status: 'approved' } can :update, Planting, garden: { owner_id: member.id }, crop: { approval_status: 'approved' }
can :destroy, Planting, garden: { owner_id: member.id }, crop: { approval_status: 'approved' } can :destroy, Planting, garden: { owner_id: member.id }, crop: { approval_status: 'approved' }
can :update, Planting do |planting|
planting.garden.garden_collaborators.where(member_id: member.id).any?
end
can :transplant, Planting, garden: { owner_id: member.id }
can :transplant, Planting do |planting|
planting.garden.garden_collaborators.where(member_id: member.id).any?
end
can :destroy, Planting do |planting|
planting.garden.garden_collaborators.where(member_id: member.id).any?
end
can :create, GardenCollaborator, garden: { owner_id: member.id }
can :update, GardenCollaborator, garden: { owner_id: member.id }
can :destroy, GardenCollaborator, garden: { owner_id: member.id }
can :destroy, GardenCollaborator, member_id: member.id
can :create, Activity can :create, Activity
can :update, Activity, owner_id: member.id can :update, Activity, owner_id: member.id
can :destroy, Activity, owner_id: member.id can :destroy, Activity, owner_id: member.id
can :update, Activity do |activity|
activity.garden&.garden_collaborators&.where(member_id: member.id)&.any?
end
can :destroy, Activity do |activity|
activity.garden&.garden_collaborators&.where(member_id: member.id)&.any?
end
can :create, Harvest can :create, Harvest
can :update, Harvest, owner_id: member.id can :update, Harvest, owner_id: member.id
can :destroy, Harvest, owner_id: member.id can :destroy, Harvest, owner_id: member.id
can :update, Harvest, owner_id: member.id, planting: { owner_id: member.id } can :update, Harvest, owner_id: member.id, planting: { owner_id: member.id }
can :destroy, Harvest, owner_id: member.id, planting: { owner_id: member.id } can :destroy, Harvest, owner_id: member.id, planting: { owner_id: member.id }
can :update, Harvest do |harvest|
harvest.planting&.garden&.garden_collaborators&.where(member_id: member.id)&.any?
end
can :destroy, Harvest do |harvest|
harvest.planting&.garden&.garden_collaborators&.where(member_id: member.id)&.any?
end
can :create, Photo can :create, Photo
can :update, Photo, owner_id: member.id can :update, Photo, owner_id: member.id
@@ -165,12 +137,6 @@ class Ability
can :destroy, Follow can :destroy, Follow
cannot :destroy, Follow, followed_id: member.id # can't unfollow yourself cannot :destroy, Follow, followed_id: member.id # can't unfollow yourself
# blocking/unblocking permissions
can :create, Block
cannot :create, Block, blocked_id: member.id # can't block yourself
can :destroy, Block, blocker_id: member.id # can only unblock your own blocks
cannot :create, GardenType cannot :create, GardenType
cannot :update, GardenType cannot :update, GardenType
cannot :destroy, GardenType cannot :destroy, GardenType

View File

@@ -4,7 +4,7 @@ class Activity < ApplicationRecord
extend FriendlyId extend FriendlyId
include Ownable include Ownable
include Finishable include Finishable
include Likeable include SearchActivities
belongs_to :garden, optional: true belongs_to :garden, optional: true
belongs_to :planting, optional: true belongs_to :planting, optional: true
@@ -29,33 +29,4 @@ class Activity < ApplicationRecord
def to_s def to_s
name name
end end
def garden_name
garden&.name
end
def garden_slug
garden&.slug
end
def planting_name
planting&.crop&.name
end
def planting_slug
planting&.crop&.slug
end
scope :active, -> { where(finished: [false, nil]) }
def self.homepage_records(limit)
# Get the latest activity for each owner, then return the latest 'limit' of those
Activity.where(id: Activity.unscoped.select("DISTINCT ON (owner_id) id").order("owner_id, created_at DESC"))
.order(created_at: :desc)
.limit(limit)
end
def self.reindex(refresh: false); end
def reindex(refresh: false); end
end end

View File

@@ -5,7 +5,6 @@ class AlternateName < ApplicationRecord
belongs_to :creator, class_name: 'Member', inverse_of: :created_alternate_names belongs_to :creator, class_name: 'Member', inverse_of: :created_alternate_names
validates :name, presence: true validates :name, presence: true
validates :crop, presence: true validates :crop, presence: true
validates :language, presence: true
after_commit :reindex after_commit :reindex

View File

@@ -1,8 +0,0 @@
# frozen_string_literal: true
class AustralianFoodClassificationData < ApplicationRecord
belongs_to :crop,
foreign_key: :public_food_key,
primary_key: :public_food_key,
inverse_of: :australian_food_classification_data
end

View File

@@ -1,18 +0,0 @@
# frozen_string_literal: true
class Block < ApplicationRecord
belongs_to :blocker, class_name: "Member"
belongs_to :blocked, class_name: "Member"
validates :blocker_id, uniqueness: { scope: :blocked_id }
after_create :destroy_follow_relationship
private
def destroy_follow_relationship
# Destroy the follow relationship in both directions
Follow.where(follower: blocker, followed: blocked).destroy_all
Follow.where(follower: blocked, followed: blocker).destroy_all
end
end

View File

@@ -2,38 +2,26 @@
class Comment < ApplicationRecord class Comment < ApplicationRecord
belongs_to :author, class_name: 'Member', inverse_of: :comments belongs_to :author, class_name: 'Member', inverse_of: :comments
belongs_to :commentable, polymorphic: true, counter_cache: true belongs_to :post, counter_cache: true
# validates :body, presence: true
validate :author_is_not_blocked
scope :post_order, -> { order(created_at: :asc) } # for display on post page scope :post_order, -> { order(created_at: :asc) } # for display on post page
after_create do after_create do
recipient = commentable.author.id recipient = post.author.id
sender = author.id sender = author.id
# don't send notifications to yourself # don't send notifications to yourself
if recipient != sender if recipient != sender
Notification.create( Notification.create(
recipient_id: recipient, recipient_id: recipient,
sender_id: sender, sender_id: sender,
subject: "#{author} commented on #{commentable.subject}", subject: "#{author} commented on #{post.subject}",
body:, body:,
notifiable: commentable post_id: post.id
) )
end end
end end
def to_s def to_s
"#{author.login_name} commented on #{commentable.subject}" "#{author.login_name} commented on #{post.subject}"
end
private
def author_is_not_blocked
return unless author
return unless commentable.author.already_blocking?(author)
errors.add(:base, "You cannot comment on a post of a member who has blocked you.")
end end
end end

View File

@@ -8,12 +8,7 @@ module Finishable
scope :current, -> { where.not(finished: true) } scope :current, -> { where.not(finished: true) }
def active def active
# Plantings can fail. At the moment, activities and seeds cannot. !finished
if respond_to?(:failed)
!finished && !failed
else
!finished
end
end end
end end
end end

View File

@@ -40,15 +40,8 @@ module MemberFlickr
# Fetches a collection of photos from Flickr # Fetches a collection of photos from Flickr
# Returns a [[page of photos], total] pair. # Returns a [[page of photos], total] pair.
# Total is needed for pagination. # Total is needed for pagination.
def flickr_photos(page_num = 1, set = nil, tags = nil) def flickr_photos(page_num = 1, set = nil)
result = if tags.present? result = if set
flickr.photos.search(
user_id: 'me',
tags: tags,
page: page_num,
per_page: 30
)
elsif set.present?
flickr.photosets.getPhotos( flickr.photosets.getPhotos(
photoset_id: set, photoset_id: set,
page: page_num, page: page_num,

View File

@@ -4,10 +4,22 @@ module OpenFarmData
extend ActiveSupport::Concern extend ActiveSupport::Concern
included do included do
def update_openfarm_data!
OpenfarmService.new.update_crop(self)
end
def of_photo def of_photo
fetch_attr('main_image_path') fetch_attr('main_image_path')
end end
def height
fetch_attr('height')
end
def spread
fetch_attr('spread')
end
def svg_icon def svg_icon
icon = fetch_attr('svg_icon') icon = fetch_attr('svg_icon')
return icon if icon.present? return icon if icon.present?
@@ -19,18 +31,42 @@ module OpenFarmData
fetch_attr('tags_array') fetch_attr('tags_array')
end end
def description
fetch_attr('description')
end
def row_spacing
fetch_attr('row_spacing')
end
def common_names def common_names
fetch_attr('common_names') fetch_attr('common_names')
end end
def guides_count
fetch_attr('guides_count')
end
def binomial_name def binomial_name
fetch_attr('binomial_name') fetch_attr('binomial_name')
end end
def sowing_method
fetch_attr('sowing_method')
end
def main_image_path def main_image_path
fetch_attr('main_image_path') fetch_attr('main_image_path')
end end
def sun_requirements
fetch_attr('sun_requirements')
end
def growing_degree_days
fetch_attr('growing_degree_days')
end
def processing_pictures def processing_pictures
fetch_attr('processing_pictures') fetch_attr('processing_pictures')
end end
@@ -39,6 +75,6 @@ module OpenFarmData
def fetch_attr(key) def fetch_attr(key)
return if openfarm_data.blank? return if openfarm_data.blank?
openfarm_data.dig('attributes', key) openfarm_data.fetch('attributes', {}).fetch(key, nil)
end end
end end

View File

@@ -6,31 +6,23 @@ module PredictHarvest
included do included do
# dates # dates
def first_harvest_date def first_harvest_date
return @first_harvest_date if defined?(@first_harvest_date) harvests_with_dates.minimum(:harvested_at)
@first_harvest_date = harvests_with_dates.minimum(:harvested_at)
end end
def last_harvest_date def last_harvest_date
return @last_harvest_date if defined?(@last_harvest_date) harvests_with_dates.maximum(:harvested_at)
@last_harvest_date = harvests_with_dates.maximum(:harvested_at)
end end
def first_harvest_predicted_at def first_harvest_predicted_at
return @first_harvest_predicted_at if defined?(@first_harvest_predicted_at) return unless crop.median_days_to_first_harvest.present? && planted_at.present?
@first_harvest_predicted_at = if crop.median_days_to_first_harvest.present? && planted_at.present? planted_at + crop.median_days_to_first_harvest.days
planted_at + crop.median_days_to_first_harvest.days
end
end end
def last_harvest_predicted_at def last_harvest_predicted_at
return @last_harvest_predicted_at if defined?(@last_harvest_predicted_at) return unless crop.median_days_to_last_harvest.present? && planted_at.present?
@last_harvest_predicted_at = if crop.median_days_to_last_harvest.present? && planted_at.present? planted_at + crop.median_days_to_last_harvest.days
planted_at + crop.median_days_to_last_harvest.days
end
end end
# actions # actions
@@ -46,7 +38,7 @@ module PredictHarvest
# status # status
def harvest_time? def harvest_time?
return false if crop.perennial || finished || failed return false if crop.perennial || finished
# We have harvests but haven't finished # We have harvests but haven't finished
harvests.size.positive? || harvests.size.positive? ||
@@ -60,16 +52,10 @@ module PredictHarvest
def before_harvest_time? def before_harvest_time?
first_harvest_predicted_at.present? && first_harvest_predicted_at.present? &&
harvests.empty? && harvests.empty? &&
first_harvest_predicted_at.present? &&
first_harvest_predicted_at > Time.zone.today first_harvest_predicted_at > Time.zone.today
end end
def harvest_in_next_week?
first_harvest_predicted_at.present? &&
harvests.empty? &&
first_harvest_predicted_at >= Time.zone.today &&
first_harvest_predicted_at <= Time.zone.today + 7.days
end
def harvest_months def harvest_months
Rails.cache.fetch("#{cache_key_with_version}/harvest_months", expires_in: 5.minutes) do Rails.cache.fetch("#{cache_key_with_version}/harvest_months", expires_in: 5.minutes) do
neighbours_for_harvest_predictions.where.not(harvested_at: nil) neighbours_for_harvest_predictions.where.not(harvested_at: nil)
@@ -79,18 +65,16 @@ module PredictHarvest
end end
def neighbours_for_harvest_predictions def neighbours_for_harvest_predictions
@neighbours_for_harvest_predictions ||= begin # use this planting's harvest if any
# use this planting's harvest if any return harvests if harvests.size.positive?
if harvests.size.positive?
harvests # otherwise use nearby plantings
# otherwise use nearby plantings if location
elsif location return Harvest.where(planting: nearby_same_crop.has_harvests)
Harvest.where(planting: nearby_same_crop.has_harvests) .where.not(planting_id: nil)
.where.not(planting_id: nil)
else
Harvest.none
end
end end
Harvest.none
end end
private private

View File

@@ -8,63 +8,51 @@ module PredictPlanting
before_save :calculate_lifespan before_save :calculate_lifespan
def calculate_lifespan def calculate_lifespan
self.lifespan = (planted_at.present? && finished_at.present? && !failed? ? finished_at - planted_at : nil) self.lifespan = (planted_at.present? && finished_at.present? ? finished_at - planted_at : nil)
end end
# dates # dates
def finish_predicted_at def finish_predicted_at
return @finish_predicted_at if defined?(@finish_predicted_at) if planted_at.blank?
nil
@finish_predicted_at = if planted_at.blank? || failed? elsif crop.median_lifespan.present?
nil planted_at + crop.median_lifespan.days
elsif crop.median_lifespan.present? elsif crop.parent.present? && crop.parent.median_lifespan.present?
planted_at + crop.median_lifespan.days planted_at + crop.parent.median_lifespan.days
elsif crop.parent.present? && crop.parent.median_lifespan.present? end
planted_at + crop.parent.median_lifespan.days
end
end end
# days # days
def expected_lifespan def expected_lifespan
return @expected_lifespan if defined?(@expected_lifespan) if actual_lifespan.present?
actual_lifespan
@expected_lifespan = if actual_lifespan.present? elsif crop.median_lifespan.present?
actual_lifespan crop.median_lifespan
elsif crop.median_lifespan.present? elsif crop.parent.present? && crop.parent.median_lifespan.present?
crop.median_lifespan crop.parent.median_lifespan
elsif crop.parent.present? && crop.parent.median_lifespan.present? end
crop.parent.median_lifespan
end
end end
def actual_lifespan def actual_lifespan
return @actual_lifespan if defined?(@actual_lifespan) return unless planted_at.present? && finished_at.present?
@actual_lifespan = if planted_at.present? && finished_at.present? && !failed? (finished_at - planted_at).to_i
(finished_at - planted_at).to_i
end
end end
def age_in_days def age_in_days
return @age_in_days if defined?(@age_in_days) return if planted_at.blank?
@age_in_days = if planted_at.blank? || failed? known_last_day ||= finished_at || Time.zone.today
nil (known_last_day - planted_at).to_i
else
known_last_day = finished_at || Time.zone.today
known_last_day = Time.zone.today if known_last_day > Time.zone.today
(known_last_day - planted_at).to_i
end
end end
def percentage_grown def percentage_grown
Rails.cache.fetch("#{cache_key_with_version}/percentage_grown", expires_in: 8.hours) do Rails.cache.fetch("#{cache_key_with_version}/percentage_grown", expires_in: 8.hours) do
if finished? if finished?
100 100
elsif !planted? || failed? elsif !planted?
0 0
elsif crop.perennial || (finish_predicted_at.nil? && finished_at.nil?) # This covers future dated finished_at that hasn't occurrred yet. elsif crop.perennial || finish_predicted_at.nil?
nil nil
else else
calculate_percentage_grown calculate_percentage_grown
@@ -83,7 +71,7 @@ module PredictPlanting
end end
def late? def late?
crop.annual? && !finished && !failed && crop.annual? && !finished &&
planted_at.present? && planted_at.present? &&
finish_predicted_at.present? && finish_predicted_at.present? &&
finish_predicted_at <= Time.zone.today finish_predicted_at <= Time.zone.today
@@ -103,9 +91,9 @@ module PredictPlanting
private private
def calculate_percentage_grown def calculate_percentage_grown
return 0 if age_in_days.to_i < 0 return 0 if age_in_days < 0
percent = (age_in_days.to_f / expected_lifespan.to_f) * 100 percent = (age_in_days / expected_lifespan.to_f) * 100
(percent > 100 ? 100 : percent) (percent > 100 ? 100 : percent)
end end
end end

View File

@@ -0,0 +1,62 @@
# frozen_string_literal: true
module SearchActivities
extend ActiveSupport::Concern
included do
searchkick merge_mappings: true,
settings: { number_of_shards: 1, number_of_replicas: 0 },
mappings: {
properties: {
active: { type: :boolean },
created_at: { type: :integer }
}
}
def search_data
{
slug:,
active:,
finished: finished?,
name:,
due_date:,
category:,
garden_id:,
garden_name: garden&.name,
planting_id:,
planting_name: planting&.crop&.name,
description:,
# owner
owner_id:,
owner_login_name:,
owner_slug:,
# timestamps
created_at: created_at.to_i,
updated_at: updated_at.to_i
}
end
def self.homepage_records(limit)
records = []
owners = []
1..limit.times do
where = {
# photos_count: { gt: 0 },
owner_id: { not: owners }
}
one_record = search('*',
limit: 1,
where:,
boost_by: [:created_at],
load: false).first
return records if one_record.nil?
owners << one_record.owner_id
records << one_record
end
records
end
end
end

View File

@@ -53,9 +53,7 @@ module SearchHarvests
owners = [] owners = []
1..limit.times do 1..limit.times do
where = { where = {
# Disabled for now so that more relevant harvests are photos_count: { gt: 0 },
# surfaced; even if we're falling back to crop photos.
# photos_count: { gt: 0 },
owner_id: { not: owners } owner_id: { not: owners }
} }
one_record = search('*', one_record = search('*',

View File

@@ -30,7 +30,6 @@ module SearchPlantings
quantity:, quantity:,
sunniness:, sunniness:,
garden_id:, garden_id:,
garden_slug: garden&.garden_slug,
garden_name: garden&.name, garden_name: garden&.name,
description:, description:,
@@ -66,9 +65,7 @@ module SearchPlantings
owners = [] owners = []
1..limit.times do 1..limit.times do
where = { where = {
# Disabled for now so that more relevant plantings are photos_count: { gt: 0 },
# surfaced; even if we're falling back to crop photos.
# photos_count: { gt: 0 },
owner_id: { not: owners } owner_id: { not: owners }
} }
one_record = search('*', one_record = search('*',

View File

@@ -59,8 +59,7 @@ module SearchSeeds
search('*', limit:, search('*', limit:,
where: { where: {
finished: false, finished: false,
tradable: true, tradable: true
_or: [{ plant_before: nil }, { plant_before: { lt: Date.today } }]
}, },
boost_by: [:created_at], boost_by: [:created_at],
load: false) load: false)

Some files were not shown because too many files have changed in this diff Show More