Compare commits

..

67 Commits

Author SHA1 Message Date
Brenda Wallace
76db8177d0 Only build the dev and mainline branches 2020-08-17 11:24:57 +12:00
Brenda Wallace
6735fa7535 REduce parallel jobs on travis to 3 2020-08-17 11:23:11 +12:00
Brenda Wallace
e92600a07e Run bin/setup on travis 2020-08-17 10:53:07 +12:00
Brenda Wallace
dba9a7b2b5 Read variables from .env when checking for elastic 2020-08-17 10:45:33 +12:00
Brenda Wallace
8c69652f4e Updating setup to read database.yaml and .env, and check for elastic 2020-08-17 10:44:55 +12:00
Brenda Wallace
70e9c029d7 Set up database config for parallel tests 2020-08-17 10:29:18 +12:00
Brenda Wallace
08c1a4e80d fix travis parallel config 2020-08-16 20:30:49 +12:00
Brenda Wallace
1ed8befb64 Merge branch 'upgrade/rails-6' into feature/parallel-tests 2020-08-16 20:29:37 +12:00
Brenda Wallace
0ba32ab15e Configure contributor check for github actions 2020-08-16 20:27:55 +12:00
Brenda Wallace
42ce0d2b9b Configure contributor check for github actions 2020-08-16 20:27:17 +12:00
Brenda Wallace
8eb101138d Setting user name and email in github actions 2020-08-16 16:41:16 +12:00
Brenda
d2aa8d2e9b gem updates 2020-08-16 16:36:33 +12:00
Brenda Wallace
7450dc43e2 Install bundler depencdencies 2020-08-16 16:33:00 +12:00
Brenda Wallace
0ec892171c Merge branch 'upgrade/rails-6' into feature/parallel-tests 2020-08-16 16:32:21 +12:00
Brenda Wallace
74c7b79eaa check out repo 2020-08-16 16:32:03 +12:00
Brenda Wallace
a8daccc621 Run tests in parallell 2020-08-16 15:52:27 +12:00
Brenda Wallace
9490960063 removing last mention of cloudmade
this company used to produce the leaflet widget, but that staff member moved elsewhere in like 2012 and took the code with them and made it open source. the credit is no longer needed
2020-08-16 15:40:01 +12:00
Brenda Wallace
e7980631d6 Help view spec find the correct template 2020-08-16 15:33:53 +12:00
Brenda Wallace
9d78dd603c only run static checks on github 2020-08-15 15:06:33 +12:00
Brenda Wallace
224e17352f Adding ru files to codeclimate 2020-08-15 15:05:02 +12:00
Brenda Wallace
9f1671cbc5 Explaning why brakeman is off 2020-08-15 15:04:41 +12:00
Brenda Wallace
503b54da1f Removing dependabot config 2020-08-15 15:03:31 +12:00
Brenda Wallace
8aa7fdda2d Renaming notifier to new rails 6 style 2020-08-15 15:02:23 +12:00
Brenda Wallace
ba86a480bb Removed cloudmade test 2020-08-15 15:00:04 +12:00
Brenda Wallace
45780ac3f0 Comment out a migration that needs an old gem to work 2020-08-15 13:32:11 +12:00
Brenda Wallace
e4942a6646 Upgrade to activemedian 0.2.0 2020-08-15 13:26:49 +12:00
Brenda Wallace
f77ab839ff Run github actions on push, pull request 2020-08-15 10:52:59 +12:00
Brenda Wallace
b63c9ca7eb Removed extra steps on travis 2020-08-15 10:51:45 +12:00
Brenda Wallace
d68acafd41 seperate steps on travis 2020-08-15 10:49:35 +12:00
Brenda Wallace
80e2487b1b Remove extra env variable 2020-08-15 10:43:33 +12:00
Brenda Wallace
26a3d6968c Update name from Notifier to NotifierMailer 2020-08-15 10:17:31 +12:00
Brenda Wallace
84717a7937 Prepare database in travis run 2020-08-15 10:15:47 +12:00
Brenda Wallace
3c4ecef985 Removed contributor check from travis 2020-08-15 10:14:41 +12:00
Brenda Wallace
a59db8c090 Adding contributor check to github actions 2020-08-15 09:48:42 +12:00
Brenda Wallace
757394ddd9 Updating content type in tests to include charset 2020-08-15 09:32:35 +12:00
Brenda Wallace
037dd8c548 Ensuring the postgresql media functions exist 2020-08-15 09:29:45 +12:00
Brenda Wallace
30fff768f2 Merge remote-tracking branch 'upstream/dev' into upgrade/rails-6 2020-08-15 09:27:48 +12:00
Brenda Wallace
a23b8f34f8 Adding github actions 2020-08-04 16:19:03 +12:00
Brenda Wallace
e6a01473fd ensure the activemedian methods are in the test db 2020-08-03 14:24:06 +12:00
Brenda Wallace
7b42d86921 Merge branch 'upgrade/rails-6' of github.com:Br3nda/growstuff into upgrade/rails-6 2020-08-02 14:46:00 +12:00
Brenda Wallace
a66187fe41 fixed ambiguous negative 2020-08-02 14:45:55 +12:00
Brenda Wallace
1e897ac671 Use member.kpt in auth 2020-08-02 14:45:45 +12:00
Brenda Wallace
989750ac47 Merge branch 'dev' into upgrade/rails-6 2020-08-02 14:24:13 +12:00
Brenda Wallace
61363305b5 Prefer ary[n..] over ary[n..-1]. 2020-08-02 13:57:20 +12:00
Brenda Wallace
4a8f76e21a removed redundant escaping 2020-08-02 13:56:16 +12:00
Brenda Wallace
2bddc15cb0 run travis-ci as test 2020-08-02 13:54:01 +12:00
Brenda Wallace
2cf449800c Add active median in test runner on travis-ci 2020-08-02 13:53:22 +12:00
Brenda Wallace
30d1fd67ab Rename Notifer to NotifierMailer 2020-08-02 13:46:01 +12:00
Brenda Wallace
aa2648784f Rubocop indentation fixes 2020-08-02 09:24:54 +12:00
Brenda Wallace
282e76b599 Apply suggestions from code review 2020-08-02 09:22:13 +12:00
Brenda Wallace
31dc367298 Disabling brakeman on codeclimate because it doesn't understand rails 6 2020-08-02 09:18:28 +12:00
Brenda Wallace
ca3265841c Apply suggestions from code review 2020-08-02 09:16:46 +12:00
Brenda
99ae2da126 Splitting up complex method in photos controller 2020-08-02 09:12:33 +12:00
Brenda
df2aacd7ff Added missing unique constraint to garden_types 2020-08-02 09:03:47 +12:00
Brenda Wallace
d629e0d976 Rubocop target is rails 6.0 2020-08-02 08:56:13 +12:00
Brenda Wallace
bf9e3328eb Removing link to cloudmade
because they no longer exist and the domain is used by something else now
2020-08-02 08:50:39 +12:00
Brenda Wallace
40989aeefe Removing deprecated commented out parts of application.rb 2020-08-02 08:50:20 +12:00
Brenda
a11db6767b rewrote order by to not be raw sql 2020-08-02 08:43:17 +12:00
Brenda
fc72f0072c removed redundant assignment 2020-08-02 08:34:02 +12:00
Brenda Wallace
0e02ee749f Align end 2020-08-02 08:32:57 +12:00
Brenda
94e6576b36 foreign key declarations not needed anymore 2020-08-02 08:30:24 +12:00
Brenda Wallace
1bfd3851e8 Enable the new rubocop cops 2020-08-02 08:23:52 +12:00
Brenda Wallace
d590a4337d Merge branch 'feature/dotenv' into upgrade/rails-6 2020-08-02 08:21:11 +12:00
Brenda
d0455c25ab Rubocop fixes after rails 6 upgrades 2020-08-02 08:19:29 +12:00
Brenda Wallace
7c55ce628a New robocops 2020-08-02 08:18:44 +12:00
Brenda Wallace
95bc0a927c Upgrade to rails 6 2020-08-02 08:12:38 +12:00
Brenda Wallace
8eb8275493 Upgrade rails gem to 6 2020-08-01 20:33:51 +12:00
599 changed files with 8063 additions and 19993 deletions

39
.codeclimate.yml Normal file
View File

@@ -0,0 +1,39 @@
engines:
rubocop:
enabled: true
channel: "rubocop-0-88"
scss-lint:
enabled: true
shellcheck:
enabled: true
eslint:
enabled: true
coffeelint:
enabled: true
brakeman:
enabled: false # codeclimate's brakeman is stuck in rails 5 rules
bundler-audit:
enabled: true
duplication:
enabled: true
config:
languages:
- ruby
- javascript
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,2 +0,0 @@
# Ruby version
VARIANT=3.3.4

View File

@@ -1,33 +0,0 @@
FROM mcr.microsoft.com/devcontainers/ruby:1-3.3-bullseye
# Install Rails
RUN gem install rails:7.0.8
# Default value to allow debug server to serve content over GitHub Codespace's port forwarding service
# The value is a comma-separated list of allowed domains
ENV RAILS_DEVELOPMENT_HOSTS=".githubpreview.dev,.preview.app.github.dev,.app.github.dev"
#RUN bundle
#RUN bundle exec rake db:create
#RUN bundle exec rake db:migrate
# [Optional] Uncomment this section to install additional OS packages.
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install --no-install-recommends bash-completion
# Chrome for testing packages. https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md#chrome-doesnt-launch-on-linux
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install --no-install-recommends ca-certificates fonts-liberation libasound2 libatk-bridge2.0-0 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgbm1 libgcc1 libglib2.0-0 libgtk-3-0 libnspr4 libnss3 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 lsb-release wget xdg-utils
# [Optional] Uncomment this line to install additional gems.
# RUN gem install <your-gem-names-here>
# [Optional] Uncomment this line to install global node packages.
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1
# We run as the vscode user.
# Make sure this is writable as https://github.com/rubygems/rubygems/issues/6272 was removed
RUN su root -c "mkdir -p /usr/local/rvm/gems/default/cache/bundler/"
RUN su root -c "mkdir -p /usr/local/rvm/gems/default/bundler/gems/"
RUN su root -c "chown -R vscode:rvm /usr/local/rvm/gems/"
RUN su root -c "chmod -R 0755 /usr/local/rvm/gems/"

View File

@@ -1,2 +0,0 @@
CREATE USER vscode CREATEDB;
CREATE DATABASE vscode WITH OWNER vscode;

View File

@@ -1,38 +0,0 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/ruby-rails-postgres
{
"name": "Growstuff",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
// Features to add to the dev container. More info: https://containers.dev/features.
// Need something to get javascript working
"features": {
"ghcr.io/devcontainers/features/node:1": {}
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// This can be used to network with other containers or the host.
"forwardPorts": [3000, 5432, 9200, 8081],
// Use 'postCreateCommand' to run commands after the container is created.
// these don't actually work as postCreateCommands, you need to run them manually
// for some unknown reason, Github codespaces use rbenv and rvm simultaneously
// and you need both to be correct for it to work
"postCreateCommand": "nice -n 19 bundle install && nice -n 19 bundle exec rake db:create && nice -n 19 bundle exec rake db:migrate && nice -n19 bundle exec rake db:seed",
// Configure tool-specific properties.
"customizations": {
"vscode": {
"extensions": [
"karunamurti.haml",
"redhat.vscode-yaml",
"CraigMaslowski.erb"
]
}
}
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}

View File

@@ -1,83 +0,0 @@
version: '3'
services:
app:
build:
context: ..
dockerfile: .devcontainer/Dockerfile
depends_on:
db:
condition: service_healthy
elasticsearch:
condition: service_healthy
environment:
ELASTICSEARCH_URL: http://elasticsearch:9200/
APP_DOMAIN_NAME: localhost:3000
APP_PROTOCOL: http
DEVISE_SECRET_KEY: secret
GROWSTUFF_EMAIL: "noreply@test.growstuff.org"
GROWSTUFF_FLICKR_KEY: secretkey
GROWSTUFF_FLICKR_SECRET: secretsecret
GROWSTUFF_SITE_NAME: "Growstuff (local)"
RAILS_SECRET_TOKEN: supersecret
volumes:
- ../..:/workspaces:cached
# Overrides default command so things don't shut down after the process ends.
command: sleep infinity
db:
image: postgres:17
restart: unless-stopped
volumes:
- postgres-data:/var/lib/postgresql/data
- ./create-db-user.sql:/docker-entrypoint-initdb.d/create-db-user.sql
environment:
POSTGRES_USER: postgres
POSTGRES_DB: growstuff_dev
POSTGRES_PASSWORD: postgres
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready"]
interval: 10s
timeout: 5s
retries: 5
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.4.0
container_name: elasticsearch
restart: unless-stopped
environment:
- xpack.security.enabled=false
- discovery.type=single-node
ulimits:
memlock:
soft: -1
hard: -1
nofile:
soft: 65536
hard: 65536
cap_add:
- IPC_LOCK
healthcheck:
test:
[
"CMD-SHELL",
"curl http://localhost:9200 | grep tagline",
]
interval: 10s
timeout: 10s
retries: 120
volumes:
- esdata01:/usr/share/elasticsearch/data
ports:
- 9200:9200
- 9300:9300
volumes:
postgres-data:
certs:
driver: local
esdata01:
driver: local

View File

@@ -1,16 +0,0 @@
version: 2
updates:
- package-ecosystem: bundler
directory: "/"
schedule:
interval: daily
time: "07:00"
open-pull-requests-limit: 20
versioning-strategy: lockfile-only
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: daily
time: "07:00"
open-pull-requests-limit: 10

View File

@@ -1,123 +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@v4
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
- name: Cache Playwright Chromium browser
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-browsers-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
- name: Install Playwright Chromium browser (with deps)
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: yarn run playwright install --with-deps chromium
- name: Install Playwright Chromium browser deps
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: yarn run playwright install-deps chromium
- name: Install NodeJS
uses: actions/setup-node@v6
with:
node-version: '12'
- 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@v5
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,124 +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@v4
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
- name: Cache Playwright Chromium browser
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-browsers-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
- name: Install Playwright Chromium browser (with deps)
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: yarn run playwright install --with-deps chromium
- name: Install Playwright Chromium browser deps
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: yarn run playwright install-deps chromium
- name: Install NodeJS
uses: actions/setup-node@v6
with:
node-version: '12'
- 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@v5
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,124 +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@v4
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
- name: Cache Playwright Chromium browser
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-browsers-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
- name: Install Playwright Chromium browser (with deps)
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: yarn run playwright install --with-deps chromium
- name: Install Playwright Chromium browser deps
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: yarn run playwright install-deps chromium
- name: Install NodeJS
uses: actions/setup-node@v6
with:
node-version: '12'
- 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@v5
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,124 +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@v4
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
- name: Cache Playwright Chromium browser
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-browsers-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
- name: Install Playwright Chromium browser (with deps)
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: yarn run playwright install --with-deps chromium
- name: Install Playwright Chromium browser deps
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: yarn run playwright install-deps chromium
- name: Install NodeJS
uses: actions/setup-node@v6
with:
node-version: '12'
- 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@v5
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,124 +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@v4
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
- name: Cache Playwright Chromium browser
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-browsers-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
- name: Install Playwright Chromium browser (with deps)
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: yarn run playwright install --with-deps chromium
- name: Install Playwright Chromium browser deps
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: yarn run playwright install-deps chromium
- name: Install NodeJS
uses: actions/setup-node@v6
with:
node-version: '12'
- 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@v5
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,124 +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@v4
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
- name: Cache Playwright Chromium browser
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-browsers-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
- name: Install Playwright Chromium browser (with deps)
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: yarn run playwright install --with-deps chromium
- name: Install Playwright Chromium browser deps
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: yarn run playwright install-deps chromium
- name: Install NodeJS
uses: actions/setup-node@v6
with:
node-version: '12'
- 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@v5
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,124 +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@v4
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
- name: Cache Playwright Chromium browser
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-browsers-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
- name: Install Playwright Chromium browser (with deps)
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: yarn run playwright install --with-deps chromium
- name: Install Playwright Chromium browser deps
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: yarn run playwright install-deps chromium
- name: Install NodeJS
uses: actions/setup-node@v6
with:
node-version: '12'
- 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@v5
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,124 +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@v4
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
- name: Cache Playwright Chromium browser
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-browsers-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
- name: Install Playwright Chromium browser (with deps)
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: yarn run playwright install --with-deps chromium
- name: Install Playwright Chromium browser deps
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: yarn run playwright install-deps chromium
- name: Install NodeJS
uses: actions/setup-node@v6
with:
node-version: '12'
- 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@v5
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,124 +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@v4
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
- name: Cache Playwright Chromium browser
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-browsers-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
- name: Install Playwright Chromium browser (with deps)
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: yarn run playwright install --with-deps chromium
- name: Install Playwright Chromium browser deps
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: yarn run playwright install-deps chromium
- name: Install NodeJS
uses: actions/setup-node@v6
with:
node-version: '12'
- 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@v5
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,124 +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@v4
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
- name: Cache Playwright Chromium browser
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-browsers-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
- name: Install Playwright Chromium browser (with deps)
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: yarn run playwright install --with-deps chromium
- name: Install Playwright Chromium browser deps
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: yarn run playwright install-deps chromium
- name: Install NodeJS
uses: actions/setup-node@v6
with:
node-version: '12'
- 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@v5
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,125 +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@v4
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: '12'
- 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 required OS packages
run: |
sudo apt-get -y install libpq-dev
- name: Cache Playwright Chromium browser
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-browsers-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
- name: Install Playwright Chromium browser (with deps)
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: yarn run playwright install --with-deps chromium
- name: Install Playwright Chromium browser deps
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: yarn run playwright install-deps chromium
- 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@v5
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,125 +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@v4
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: '12'
- 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 required OS packages
run: |
sudo apt-get -y install libpq-dev
- name: Cache Playwright Chromium browser
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-browsers-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
- name: Install Playwright Chromium browser (with deps)
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: yarn run playwright install --with-deps chromium
- name: Install Playwright Chromium browser deps
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: yarn run playwright install-deps chromium
- 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@v5
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,125 +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@v4
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: '12'
- 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 required OS packages
run: |
sudo apt-get -y install libpq-dev
- name: Cache Playwright Chromium browser
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-browsers-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
- name: Install Playwright Chromium browser (with deps)
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: yarn run playwright install --with-deps chromium
- name: Install Playwright Chromium browser deps
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: yarn run playwright install-deps chromium
- 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@v5
with:
name: screenshots
path: tmp/screenshots

View File

@@ -1,134 +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@v4
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: '12'
- 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 required OS packages
run: |
sudo apt-get -y install libpq-dev
- name: Cache Playwright Chromium browser
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-browsers-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
- name: Install Playwright Chromium browser (with deps)
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: yarn run playwright install --with-deps chromium
- name: Install Playwright Chromium browser deps
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: yarn run playwright install-deps chromium
- 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@v5
with:
name: screenshots
path: tmp/screenshots

View File

@@ -6,141 +6,10 @@ jobs:
contributors: contributors:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v1
- 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:
bundler-cache: true
- name: Install gem bundle
run: |
gem install bundler
bundle install
- name: Check contributors - name: Check contributors
run: | run: |
bundle exec script/check_contributors_md.rb ./script/check_contributors_md.rb
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@v4
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: '12'
- 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 required OS packages
run: |
sudo apt-get -y install libpq-dev
- name: Cache Playwright Chromium browser
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-browsers-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
- name: Install Playwright Chromium browser (with deps)
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: yarn run playwright install --with-deps chromium
- name: Install Playwright Chromium browser deps
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: yarn run playwright install-deps chromium
- name: Prepare database for testing
run: bundle exec rails db:prepare
- name: Run rspec (lib)
run: bundle exec rspec spec/lib/ -fd --fail-fast
- name: Run rspec (services)
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,17 +1,10 @@
inherit_from: .rubocop_todo.yml inherit_from: .rubocop_todo.yml
plugins: require: rubocop-rails
- rubocop-factory_bot
- rubocop-capybara
- rubocop-rails
- rubocop-rspec
- rubocop-rspec_rails
- rubocop-rake
AllCops: AllCops:
NewCops: enable
Exclude: Exclude:
- 'db/schema.rb' - 'db/schema.rb'
- 'vendor/**/*' - 'vendor/**/*'
TargetRailsVersion: 7.1 TargetRailsVersion: 6.0
Rails: Rails:
Enabled: true Enabled: true
@@ -22,11 +15,6 @@ Naming/FileName:
- 'Gemfile' - 'Gemfile'
- 'Gemfile.lock' - 'Gemfile.lock'
RSpec/DescribeClass:
Exclude:
- 'spec/views/**/*.rb'
- 'spec/features/**/*.rb'
Layout/MultilineMethodCallIndentation: Layout/MultilineMethodCallIndentation:
EnforcedStyle: indented EnforcedStyle: indented
@@ -72,3 +60,75 @@ Rails/SkipsModelValidations:
Exclude: Exclude:
- 'db/migrate/20190317023129_finished_boolean.rb' - 'db/migrate/20190317023129_finished_boolean.rb'
- 'db/seeds.rb' - 'db/seeds.rb'
Layout/EmptyLinesAroundAttributeAccessor:
Enabled: true
Layout/SpaceAroundMethodCallOperator:
Enabled: true
Lint/DeprecatedOpenSSLConstant:
Enabled: true
Lint/DuplicateElsifCondition:
Enabled: true
Lint/MixedRegexpCaptureTypes:
Enabled: true
Lint/RaiseException:
Enabled: true
Lint/StructNewOverride:
Enabled: true
Style/AccessorGrouping:
Enabled: true
Style/ArrayCoercion:
Enabled: true
Style/BisectedAttrAccessor:
Enabled: false
Style/CaseLikeIf:
Enabled: true
Style/ExponentialNotation:
Enabled: true
Style/HashAsLastArrayItem:
Enabled: true
Style/HashEachMethods:
Enabled: true
Style/HashLikeCase:
Enabled: true
Style/HashTransformKeys:
Enabled: true
Style/HashTransformValues:
Enabled: true
Style/RedundantAssignment:
Enabled: true
Style/RedundantFetchBlock:
Enabled: true
Style/RedundantFileExtensionInRequire:
Enabled: true
Style/RedundantRegexpCharacterClass:
Enabled: true
Style/RedundantRegexpEscape:
Enabled: true
Style/SlicingWithRange:
Enabled: true
Rails/ActiveRecordCallbacksOrder:
Enabled: true
Rails/FindById:
Enabled: true
Rails/Inquiry:
Enabled: true
Rails/MailerName:
Enabled: true
Rails/MatchRoute:
Enabled: true
Rails/NegateInclude:
Enabled: true
Rails/Pluck:
Enabled: true
Rails/PluckInWhere:
Enabled: true
Rails/RenderInline:
Enabled: true
Rails/RenderPlainText:
Enabled: true
Rails/ShortI18n:
Enabled: true
Rails/WhereExists:
Enabled: true

View File

@@ -1,452 +1,50 @@
# This configuration was generated by # This configuration was generated by
# `rubocop --auto-gen-config` # `rubocop --auto-gen-config --no-offense-counts`
# on 2024-07-13 05:47:38 UTC using RuboCop version 1.65.0. # on 2019-12-16 21:01:58 +1300 using RuboCop version 0.77.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: 231 Lint/AmbiguousOperator:
# Configuration parameters: EnforcedStyle.
# SupportedStyles: link_or_button, strict
Capybara/ClickLinkOrButtonStyle:
Enabled: false
# Offense count: 39
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: DefaultSelector.
Capybara/RSpec/HaveSelector:
Exclude:
- 'spec/features/conversations/index_spec.rb'
- 'spec/features/footer_spec.rb'
- 'spec/features/gardens/adding_gardens_spec.rb'
- 'spec/features/harvests/harvesting_a_crop_spec.rb'
- 'spec/features/members/list_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
Capybara/SpecificMatcher:
Exclude:
- 'spec/features/footer_spec.rb'
- 'spec/features/gardens/adding_gardens_spec.rb'
- 'spec/features/harvests/harvesting_a_crop_spec.rb'
- 'spec/features/plantings/planting_a_crop_spec.rb'
- 'spec/features/seeds/adding_seeds_spec.rb'
# Offense count: 1
Capybara/VisibilityMatcher:
Exclude:
- 'spec/features/shared_examples/crop_suggest.rb'
# Offense count: 6
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: EnforcedStyle, NonImplicitAssociationMethodNames.
# SupportedStyles: explicit, implicit
FactoryBot/AssociationStyle:
Exclude:
- 'spec/factories/alternate_names.rb'
- 'spec/factories/crop.rb'
- 'spec/factories/like.rb'
- 'spec/factories/scientific_name.rb'
# Offense count: 3
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: AutoCorrect, Include, EnforcedStyle, ExplicitOnly.
# Include: **/*_spec.rb, **/spec/**/*, **/test/**/*, **/features/support/factories/**/*.rb
# SupportedStyles: create_list, n_times
FactoryBot/CreateList:
Exclude:
- 'spec/views/comments/index.rss.haml_spec.rb'
- 'spec/views/photos/index.html.haml_spec.rb'
- 'spec/views/posts/index.html.haml_spec.rb'
# Offense count: 4
# Configuration parameters: Include, MaxAmount.
# Include: **/*_spec.rb, **/spec/**/*, **/test/**/*, **/features/support/factories/**/*.rb
FactoryBot/ExcessiveCreateList:
Exclude:
- 'spec/controllers/posts_controller_spec.rb'
- 'spec/features/crops/show_spec.rb'
- 'spec/features/percy/percy_spec.rb'
# Offense count: 1127
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: Include.
# Include: **/*_spec.rb, **/spec/**/*, **/test/**/*, **/features/support/factories/**/*.rb
FactoryBot/SyntaxMethods:
Enabled: false
# Offense count: 2
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: Max, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns.
# URISchemes: http, https
Layout/LineLength:
Exclude:
- 'app/helpers/crops_helper.rb'
- 'db/seeds.rb'
# Offense count: 3
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: RequireParenthesesForMethodChains.
Lint/AmbiguousRange:
Exclude:
- 'app/models/concerns/search_activities.rb'
- 'app/models/concerns/search_harvests.rb'
- 'app/models/concerns/search_plantings.rb'
# Offense count: 2
# Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches.
Lint/DuplicateBranch:
Exclude:
- 'app/models/harvest.rb'
- 'lib/actions/oauth_signup_action.rb'
# Offense count: 8
# Configuration parameters: AllowComments, AllowEmptyLambdas.
Lint/EmptyBlock:
Exclude:
- '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
# This cop supports safe autocorrection (--autocorrect).
Lint/RedundantCopDisableDirective:
Exclude:
- 'db/migrate/20230313015323_create_active_storage_tables.active_storage.rb'
# Offense count: 2
# This cop supports unsafe autocorrection (--autocorrect-all).
Lint/RedundantDirGlobSort:
Exclude:
- 'spec/rails_helper.rb'
# Offense count: 1
# Configuration parameters: AllowComments, AllowNil.
Lint/SuppressedException:
Exclude:
- 'lib/tasks/testing.rake'
# Offense count: 7
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: AutoCorrect.
Lint/UselessAssignment:
Exclude:
- 'config.rb'
- 'config/compass.rb'
# Offense count: 52
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
Metrics/AbcSize:
Max: 151
# Offense count: 14
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode.
# AllowedMethods: refine
Metrics/BlockLength:
Max: 115
# Offense count: 7
# Configuration parameters: CountComments, CountAsOne.
Metrics/ClassLength:
Max: 188
# Offense count: 6
# Configuration parameters: AllowedMethods, AllowedPatterns.
Metrics/CyclomaticComplexity:
Max: 32
# Offense count: 71
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
Metrics/MethodLength:
Max: 127
# Offense count: 2
# Configuration parameters: CountComments, CountAsOne.
Metrics/ModuleLength:
Max: 125
# Offense count: 5
# Configuration parameters: AllowedMethods, AllowedPatterns.
Metrics/PerceivedComplexity:
Max: 32
# Offense count: 3
RSpec/AnyInstance:
Exclude:
- 'spec/controllers/harvests_controller_spec.rb'
- 'spec/controllers/photos_controller_spec.rb'
# Offense count: 292
# Configuration parameters: Prefixes, AllowedPatterns.
# Prefixes: when, with, without
RSpec/ContextWording:
Enabled: false
# Offense count: 36
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: SkipBlocks, EnforcedStyle, OnlyStaticConstants.
# SupportedStyles: described_class, explicit
RSpec/DescribedClass:
Exclude:
- 'spec/models/like_spec.rb'
- 'spec/models/member_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
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: AllowConsecutiveOneLiners.
RSpec/EmptyLineAfterExample:
Exclude:
- 'spec/models/ability_spec.rb'
# Offense count: 140
# Configuration parameters: CountAsOne.
RSpec/ExampleLength:
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
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: EnforcedStyle.
# SupportedStyles: implicit, each, example
RSpec/HookArgument:
Exclude:
- 'spec/requests/api/v1/plantings_request_spec.rb'
# Offense count: 2
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: AutoCorrect.
RSpec/HooksBeforeExamples:
Exclude:
- 'spec/features/crops/creating_a_crop_spec.rb'
# Offense count: 37
# Configuration parameters: Max, AllowedIdentifiers, AllowedPatterns.
RSpec/IndexedLet:
Exclude:
- '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: 720
# Configuration parameters: AssignmentOnly.
RSpec/InstanceVariable:
Enabled: false
# Offense count: 40
RSpec/LetSetup:
Enabled: false
# Offense count: 1
# This cop supports safe autocorrection (--autocorrect).
RSpec/MatchArray:
Exclude:
- 'spec/models/post_spec.rb'
# Offense count: 2
RSpec/MessageChain:
Exclude:
- 'spec/models/member_spec.rb'
# Offense count: 23
# Configuration parameters: .
# SupportedStyles: have_received, receive
RSpec/MessageSpies:
EnforcedStyle: receive
# Offense count: 1
RSpec/MultipleDescribes:
Exclude:
- 'spec/features/crops/crop_wranglers_spec.rb'
# Offense count: 152
RSpec/MultipleExpectations:
Max: 19
# Offense count: 138
# Configuration parameters: AllowSubject.
RSpec/MultipleMemoizedHelpers:
Max: 20
# Offense count: 133
# Configuration parameters: EnforcedStyle, IgnoreSharedExamples.
# SupportedStyles: always, named_only
RSpec/NamedSubject:
Enabled: false
# Offense count: 111
# Configuration parameters: AllowedGroups.
RSpec/NestedGroups:
Max: 6
# Offense count: 403
# Configuration parameters: AllowedPatterns.
# AllowedPatterns: ^expect_, ^assert_
RSpec/NoExpectationExample:
Enabled: false
# Offense count: 3
RSpec/PendingWithoutReason:
Exclude:
- 'spec/features/seeds/misc_seeds_spec.rb'
- 'spec/features/unsubscribing_spec.rb'
# Offense count: 2
RSpec/RepeatedDescription:
Exclude:
- 'spec/models/like_spec.rb'
# Offense count: 6
RSpec/RepeatedExample:
Exclude:
- 'spec/controllers/photos_controller_spec.rb'
- 'spec/features/members/following_spec.rb'
- 'spec/models/like_spec.rb'
# Offense count: 4
RSpec/RepeatedExampleGroupBody:
Exclude: Exclude:
- 'spec/controllers/crops_controller_spec.rb' - 'spec/controllers/crops_controller_spec.rb'
# Offense count: 6
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: AutoCorrect.
RSpec/ScatteredSetup:
Exclude:
- 'spec/features/percy/percy_spec.rb'
- 'spec/features/plantings/prediction_spec.rb'
# Offense count: 1
# Configuration parameters: Include, CustomTransform, IgnoreMethods, IgnoreMetadata.
# Include: **/*_spec.rb
RSpec/SpecFilePathFormat:
Exclude:
- 'spec/controllers/member_controller_spec.rb'
# Offense count: 3
RSpec/StubbedMock:
Exclude:
- 'spec/controllers/garden_types_controller_spec.rb'
- 'spec/controllers/gardens_controller_spec.rb'
- 'spec/models/member_spec.rb'
# Offense count: 1
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: constant, string # SupportedStyles: lowercase, uppercase
RSpec/VerifiedDoubleReference: Naming/HeredocDelimiterCase:
Exclude: Exclude:
- 'spec/models/member_spec.rb' - 'config/environments/production.rb'
# Offense count: 3
# Configuration parameters: IgnoreNameless, IgnoreSymbolicNames.
RSpec/VerifiedDoubles:
Exclude:
- 'spec/controllers/garden_types_controller_spec.rb'
- 'spec/controllers/gardens_controller_spec.rb'
- 'spec/views/devise/shared/_links_spec.rb'
# 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).
# Configuration parameters: Inferences.
RSpecRails/InferredSpecType:
Enabled: false
# Offense count: 28
# Configuration parameters: Database, Include.
# SupportedDatabases: mysql, postgresql
# Include: db/**/*.rb
Rails/BulkChangeTable:
Enabled: false
# Offense count: 4
# Configuration parameters: Include. # Configuration parameters: Include.
# Include: db/**/*.rb # Include: db/migrate/*.rb
Rails/CreateTableWithTimestamps: Rails/CreateTableWithTimestamps:
Exclude: Exclude:
- 'db/migrate/20130214034838_add_members_roles_table.rb'
- 'db/migrate/20130507113915_add_orders_products_table.rb'
- 'db/migrate/20130531110729_add_photos_plantings_table.rb'
- 'db/migrate/20140905001730_add_harvests_photos_table.rb'
- 'db/migrate/20140928044231_add_crops_posts_table.rb'
- 'db/migrate/20150127043022_add_gardens_photos_table.rb'
- 'db/migrate/20150201052245_create_cms.rb' - 'db/migrate/20150201052245_create_cms.rb'
- 'db/migrate/20161201154922_add_photos_seeds_table.rb'
- 'db/migrate/20171022032108_all_the_predictions.rb' - 'db/migrate/20171022032108_all_the_predictions.rb'
# Offense count: 1 # Configuration parameters: EnforcedStyle.
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: EnforcedStyle, AllowToTime.
# SupportedStyles: strict, flexible # SupportedStyles: strict, flexible
Rails/Date: Rails/Date:
Exclude: Exclude:
- 'app/mailers/notifier_mailer.rb' - 'app/mailers/notifier.rb'
# Offense count: 11 # Configuration parameters: EnforcedStyle.
# This cop supports unsafe autocorrection (--autocorrect-all). # SupportedStyles: slashes, arguments
# Configuration parameters: AllowedMethods, AllowedPatterns. Rails/FilePath:
# AllowedMethods: order, limit, select, lock
Rails/FindEach:
Exclude: Exclude:
- 'app/controllers/conversations_controller.rb' - 'app/controllers/crops_controller.rb'
- 'db/migrate/20171105011017_set_prediction_data.rb' - 'config/application.rb'
- 'db/migrate/20171129041341_create_photographings.rb' - 'config/environments/development.rb'
- 'db/migrate/20190130090437_add_crop_to_photographings.rb' - 'db/seeds.rb'
- 'db/migrate/20191119030244_cms_tags.rb'
# Offense count: 2
# Configuration parameters: Include. # Configuration parameters: Include.
# Include: app/models/**/*.rb # Include: app/models/**/*.rb
Rails/HasAndBelongsToMany: Rails/HasAndBelongsToMany:
@@ -454,46 +52,23 @@ Rails/HasAndBelongsToMany:
- 'app/models/member.rb' - 'app/models/member.rb'
- 'app/models/role.rb' - 'app/models/role.rb'
# Offense count: 5
# Configuration parameters: Include. # Configuration parameters: Include.
# Include: app/models/**/*.rb # Include: app/models/**/*.rb
Rails/HasManyOrHasOneDependent: Rails/HasManyOrHasOneDependent:
Exclude: Exclude:
- 'app/models/member.rb' - 'app/models/member.rb'
# Offense count: 1
# Configuration parameters: Include. # Configuration parameters: Include.
# Include: spec/**/*.rb, test/**/*.rb # Include: app/models/**/*.rb
Rails/I18nLocaleAssignment: Rails/InverseOf:
Exclude: Exclude:
- 'spec/features/locale_spec.rb' - 'app/models/concerns/ownable.rb'
# Offense count: 33
Rails/I18nLocaleTexts:
Enabled: false
# Offense count: 3
# Configuration parameters: Include.
# Include: app/controllers/**/*.rb, app/mailers/**/*.rb
Rails/LexicallyScopedActionFilter:
Exclude:
- 'app/controllers/data_controller.rb'
- 'app/controllers/registrations_controller.rb'
# Offense count: 2
Rails/OutputSafety: Rails/OutputSafety:
Exclude: Exclude:
- 'app/helpers/auto_suggest_helper.rb' - 'app/helpers/auto_suggest_helper.rb'
- 'app/helpers/gardens_helper.rb' - 'app/helpers/gardens_helper.rb'
# Offense count: 1
# This cop supports safe autocorrection (--autocorrect).
Rails/PluralizationGrammar:
Exclude:
- 'spec/requests/plantings_spec.rb'
# Offense count: 4
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: Include. # Configuration parameters: Include.
# Include: **/Rakefile, **/*.rake # Include: **/Rakefile, **/*.rake
Rails/RakeEnvironment: Rails/RakeEnvironment:
@@ -502,102 +77,27 @@ Rails/RakeEnvironment:
- 'lib/tasks/i18n.rake' - 'lib/tasks/i18n.rake'
- 'lib/tasks/testing.rake' - 'lib/tasks/testing.rake'
# Offense count: 9
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: AllowedReceivers.
# AllowedReceivers: ActionMailer::Preview, ActiveSupport::TimeZone
Rails/RedundantActiveRecordAllMethod:
Exclude:
- 'app/controllers/admin/roles_controller.rb'
- 'app/controllers/alternate_names_controller.rb'
- 'app/controllers/forums_controller.rb'
- 'app/controllers/plant_parts_controller.rb'
- 'app/controllers/scientific_names_controller.rb'
- 'app/services/openfarm_service.rb'
- 'spec/features/percy/percy_spec.rb'
- 'spec/models/harvest_spec.rb'
# Offense count: 5
# This cop supports unsafe autocorrection (--autocorrect-all).
Rails/RedundantPresenceValidationOnBelongsTo:
Exclude:
- 'app/models/alternate_name.rb'
- 'app/models/like.rb'
- 'app/models/planting.rb'
- 'app/models/scientific_name.rb'
# Offense count: 15
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: Include. # Configuration parameters: Include.
# Include: spec/controllers/**/*.rb, spec/requests/**/*.rb, test/controllers/**/*.rb, test/integration/**/*.rb # Include: db/migrate/*.rb
Rails/ResponseParsedBody:
Exclude:
- 'spec/controllers/api/v1/plantings_controller_spec.rb'
- 'spec/controllers/likes_controller_spec.rb'
- 'spec/requests/api/v1/crop_request_spec.rb'
- 'spec/requests/api/v1/gardens_request_spec.rb'
- 'spec/requests/api/v1/harvests_request_spec.rb'
- 'spec/requests/api/v1/members_request_spec.rb'
- 'spec/requests/api/v1/photos_request_spec.rb'
- 'spec/requests/api/v1/plantings_request_spec.rb'
- 'spec/requests/api/v1/seeds_request_spec.rb'
# 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/20191119020643_upgrade_cms.rb' - 'db/migrate/20191119020643_upgrade_cms.rb'
# Offense count: 2 # Configuration parameters: Blacklist, Whitelist.
# This cop supports unsafe autocorrection (--autocorrect-all). # Blacklist: decrement!, decrement_counter, increment!, increment_counter, toggle!, touch, update_all, update_attribute, update_column, update_columns, update_counters
Rails/RootPathnameMethods: Rails/SkipsModelValidations:
Exclude: Exclude:
- 'app/controllers/crops_controller.rb' - 'db/migrate/20190317023129_finished_boolean.rb'
- 'app/helpers/icons_helper.rb' - 'db/seeds.rb'
- 'db/migrate/20190910022329_add_photo_source.rb'
# Offense count: 21 # Configuration parameters: AllowedChars.
# Configuration parameters: Include. Style/AsciiComments:
# Include: db/**/*.rb
Rails/ThreeStateBooleanColumn:
Enabled: false
# Offense count: 6
# Configuration parameters: Include.
# Include: app/models/**/*.rb
Rails/UniqueValidationWithoutIndex:
Exclude: Exclude:
- 'app/models/follow.rb' - 'config/initializers/comfortable_mexican_sofa.rb'
- 'app/models/garden.rb'
- 'app/models/like.rb'
- 'app/models/member.rb'
- 'app/models/plant_part.rb'
- 'app/models/role.rb'
# Offense count: 3 # Cop supports --auto-correct.
# This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: AutoCorrect, EnforcedStyle.
Rails/WhereEquals:
Exclude:
- 'app/models/crop.rb'
- 'app/models/harvest.rb'
- 'app/models/planting.rb'
# Offense count: 2
# This cop supports unsafe autocorrection (--autocorrect-all).
Rails/WhereRange:
Exclude:
- 'app/models/concerns/predict_planting.rb'
- 'app/models/garden.rb'
# Offense count: 1
Rake/MethodDefinitionInTask:
Exclude:
- 'lib/tasks/growstuff.rake'
# Offense count: 3
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: EnforcedStyle.
# SupportedStyles: nested, compact # SupportedStyles: nested, compact
Style/ClassAndModuleChildren: Style/ClassAndModuleChildren:
Exclude: Exclude:
@@ -605,121 +105,23 @@ Style/ClassAndModuleChildren:
- '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: 6
# This cop supports unsafe autocorrection (--autocorrect-all).
Style/CommentedKeyword: Style/CommentedKeyword:
Exclude: Exclude:
- 'db/migrate/20191119030244_cms_tags.rb'
- 'spec/models/crop_spec.rb' - 'spec/models/crop_spec.rb'
- 'spec/models/photo_spec.rb' - 'spec/models/photo_spec.rb'
- 'spec/models/planting_spec.rb' - 'spec/models/planting_spec.rb'
# Offense count: 3
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: EnforcedStyle.
# SupportedStyles: always, always_true, never
Style/FrozenStringLiteralComment:
Exclude:
- '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'
# Offense count: 3
# This cop supports unsafe autocorrection (--autocorrect-all).
Style/GlobalStdStream:
Exclude:
- 'config/environments/production.rb'
- 'lib/tasks/gbif.rake'
- 'lib/tasks/openfarm.rake'
# Offense count: 1
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: AllowedMethods.
# AllowedMethods: nonzero?
Style/IfWithBooleanLiteralBranches:
Exclude:
- 'app/controllers/gardens_controller.rb'
# Offense count: 1
# This cop supports unsafe autocorrection (--autocorrect-all).
Style/MinMaxComparison:
Exclude:
- 'app/models/concerns/predict_planting.rb'
# Offense count: 2
Style/MixinUsage: Style/MixinUsage:
Exclude: Exclude:
- 'bin/setup'
- 'bin/update' - 'bin/update'
- 'spec/rails_helper.rb' - 'spec/rails_helper.rb'
# Offense count: 1 # Cop supports --auto-correct.
# This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: AutoCorrect, EnforcedStyle, IgnoredMethods.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: literals, strict
Style/MutableConstant:
Exclude:
- 'app/models/activity.rb'
# Offense count: 5
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: EnforcedStyle, AllowedMethods, AllowedPatterns.
# SupportedStyles: predicate, comparison # SupportedStyles: predicate, comparison
Style/NumericPredicate: Style/NumericPredicate:
Exclude: Exclude:
- 'app/helpers/crops_helper.rb' - 'spec/**/*'
- 'app/helpers/harvests_helper.rb' - 'app/helpers/harvests_helper.rb'
- 'app/helpers/plantings_helper.rb' - 'app/helpers/plantings_helper.rb'
- 'app/models/concerns/predict_planting.rb'
# Offense count: 6
Style/OpenStructUse:
Exclude:
- 'spec/helpers/event_helper_spec.rb'
# Offense count: 2
# Configuration parameters: AllowedMethods.
# AllowedMethods: respond_to_missing?
Style/OptionalBooleanParameter:
Exclude:
- 'app/models/concerns/member_newsletter.rb'
# Offense count: 1
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: Methods.
Style/RedundantArgument:
Exclude:
- 'app/helpers/application_helper.rb'
# Offense count: 4
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: SafeForConstants.
Style/RedundantFetchBlock:
Exclude:
- 'config/puma.rb'
# Offense count: 2
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: AllowModifier.
Style/SoleNestedConditional:
Exclude:
- 'app/controllers/application_controller.rb'
- 'app/controllers/messages_controller.rb'
# Offense count: 24
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: Mode.
Style/StringConcatenation:
Exclude:
- 'app/controllers/messages_controller.rb'
- 'app/helpers/buttons_helper.rb'
- 'config/initializers/rswag_api.rb'
- 'spec/helpers/gardens_helper_spec.rb'
- 'spec/helpers/seeds_helper_spec.rb'
# Offense count: 1
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: AllowMethodsWithArguments, AllowedMethods, AllowedPatterns, AllowComments.
# AllowedMethods: define_method, mail, respond_to
Style/SymbolProc:
Exclude:
- 'app/controllers/crops_controller.rb'

View File

@@ -1 +1 @@
3.3.8 2.6.5

View File

@@ -1,18 +1,52 @@
sudo: required sudo: required
language: ruby language: ruby
dist: bionic dist: bionic
services:
- postgresql
- xvfb
branches: branches:
only: only:
- mainline - mainline
- dev - dev
cache: cache:
bundler: true bundler: true
yarn: true
directories: directories:
- tmp/cache/assets/test/sprockets - tmp/cache/assets/test/sprockets
addons:
postgresql: "9.4" # Matches production
code_climate:
repo_token:
secure: "PfhLGBKRgNqhKuYCJsK+VPhdAzcgWFGeeOyxC/eS8gtlvIISVdgyZE+r30uIei0DFI6zEiN62eW4d+xtT4j7/e2ZcAcx7U52mza/SnQNuu3nCGQDJB8VOvV5NbnwXfi8vfr4e889Mt7k3ocd2c4gqB4UtRqrzhygj7HN+B/GfEk="
env: env:
matrix:
- "TEST_GROUP=1"
- "TEST_GROUP=2"
- "TEST_GROUP=3"
global: global:
- secure: "Z5TpM2jEX4UCvNePnk/LwltQX48U2u9BRc+Iypr1x9QW2o228QJhPIOH39a8RMUrepGnkQIq9q3ZRUn98RfrJz1yThtlNFL3NmzdQ57gKgjGwfpa0e4Dwj/ZJqV2D84tDGjvdVYLP7zzaYZxQcwk/cgNpzKf/jq97HLNP7CYuf4=" - secure: "Z5TpM2jEX4UCvNePnk/LwltQX48U2u9BRc+Iypr1x9QW2o228QJhPIOH39a8RMUrepGnkQIq9q3ZRUn98RfrJz1yThtlNFL3NmzdQ57gKgjGwfpa0e4Dwj/ZJqV2D84tDGjvdVYLP7zzaYZxQcwk/cgNpzKf/jq97HLNP7CYuf4="
- ELASTIC_SEARCH_VERSION="7.5.1-amd64"
- COVERAGE=true
- GROWSTUFF_EMAIL="noreply@test.growstuff.org"g
- GROWSTUFF_SITE_NAME="Growstuff (travis)"
- RAILS_SECRET_TOKEN='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx']
- RAILS_ENV=test
before_install:
- sudo apt clean
- sudo apt update
- sudo apt install dpkg
- ./script/install_elasticsearch.sh
- sudo apt install google-chrome-stable
- ./bin/setup
script:
# - bundle exec rails db:create db:migrate
# - bundle exec rails assets:precompile
# - bundle exec rails search:reindex
# - bundle exec rspec spec -fd
- bundle exec parallel_test spec/ -n 3 --only-group $TEST_GROUP --group-by filesize --type rspec
after_script:
- >
gem install codeclimate-test-reporter
codeclimate-test-reporter
before_deploy: before_deploy:
- bundle exec script/heroku_maintenance.rb on - bundle exec script/heroku_maintenance.rb on
deploy: deploy:
@@ -25,6 +59,7 @@ deploy:
dev: growstuff-staging dev: growstuff-staging
mainline: growstuff-prod mainline: growstuff-prod
run: run:
- "rake db:migrate"
- "script/deploy-tasks.sh" - "script/deploy-tasks.sh"
- restart - restart
after_deploy: after_deploy:

View File

@@ -1,129 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
info@growstuff.org. Any issues with a particular moderator can be reported to
any one of the other moderators.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

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)
@@ -91,15 +91,9 @@ submit the change with your pull request.
- Taylor William / [bestest-mensch](https://github.com/bestest-mensch) - Taylor William / [bestest-mensch](https://github.com/bestest-mensch)
- André Aubin / [lambda2](https://github.com/lambda2) - André Aubin / [lambda2](https://github.com/lambda2)
- Martina Simicic / [simicic](https://github.com/simicic) - Martina Simicic / [simicic](https://github.com/simicic)
- Rowan Crawford / [wombleton](https://github.com/wombleton)
- Ítalo Pires / [italopires](https://github.com/italopires)
- Bennett Zink / [bennett-zink](https://github.com/bennett-zink)
- Dominick Thornton / [domthor](https://github.com/domthor)
## Bots ## Bots
### Security and Dependency Updates ### Security and Dependency Updates
- `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-preview[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)

82
Gemfile
View File

@@ -2,20 +2,19 @@
source 'https://rubygems.org' source 'https://rubygems.org'
# Match ruby version in .ruby-version ruby '2.6.5'
ruby File.read('.ruby-version')
gem 'rails', '~> 7.2.0' gem 'rails', '6.0.3.2'
# 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', '>=1.1.5'
gem 'coffee-rails' gem 'coffee-rails'
gem 'haml' gem 'haml'
gem 'sassc-rails' gem 'sass-rails'
# API data # API data
gem 'jsonapi-resources' gem 'jsonapi-resources'
@@ -24,7 +23,7 @@ gem 'rswag-api'
gem 'rswag-ui' gem 'rswag-ui'
# CSS framework # CSS framework
gem "bootstrap", ">= 5.0.0" gem "bootstrap", ">= 4.3.1"
gem 'material-sass', '4.1.1' gem 'material-sass', '4.1.1'
# Icons used by bootstrap/material-sass # Icons used by bootstrap/material-sass
@@ -33,32 +32,33 @@ gem 'material_icons'
# icons # icons
gem 'font-awesome-sass' gem 'font-awesome-sass'
gem 'terser' gem 'uglifier' # JavaScript compressor
gem 'oj' # Speeds up json gem 'oj' # Speeds up json
# planting and harvest predictions # planting and harvest predictions
# based on median values for the crop # based on median values for the crop
gem 'active_median' gem 'active_median', '0.2.0'
gem 'active_record_union' gem 'active_record_union'
gem 'flickraw' gem 'flickraw'
gem 'jquery-rails' gem 'jquery-rails'
gem 'jquery-ui-rails', github: 'jquery-ui-rails/jquery-ui-rails', tag: 'v7.0.0' # See https://github.com/jquery-ui-rails/jquery-ui-rails/issues/146 gem 'jquery-ui-rails'
gem 'js-routes' # provides access to Rails routes in Javascript
gem 'cancancan' # for checking member privileges gem 'cancancan' # for checking member privileges
gem 'csv_shaper' # CSV export gem 'csv_shaper' # CSV export
gem 'gibbon', '~>1.2.0' # for Mailchimp newsletter subscriptions gem 'gibbon', '~>1.2.0' # for Mailchimp newsletter subscriptions
# Maps # Maps
gem 'leaflet-rails', '>= 1.9.2' gem 'leaflet-rails'
gem 'rails-assets-leaflet.markercluster', source: 'https://rails-assets.org' gem 'rails-assets-leaflet.markercluster', source: 'https://rails-assets.org'
gem 'pg' gem 'pg', '< 1.0.0' # Upstream bug, see https://github.com/Growstuff/growstuff/pull/1539
gem 'ruby-units' # for unit conversion gem 'ruby-units' # for unit conversion
gem 'unicorn' # http server gem 'unicorn' # http server
gem "comfortable_mexican_sofa", git: "https://github.com/restarone/comfortable-mexican-sofa.git" gem "comfortable_mexican_sofa", "~> 2.0.0"
gem 'active_utils' gem 'active_utils'
gem 'sidekiq' gem 'sidekiq'
@@ -68,7 +68,7 @@ gem 'bluecloth'
# Pagination # Pagination
gem 'will_paginate' gem 'will_paginate'
gem 'will_paginate-bootstrap-style' gem 'will_paginate-bootstrap4'
# user signup/login/etc # user signup/login/etc
gem 'devise' gem 'devise'
@@ -89,17 +89,19 @@ gem 'geocoder'
gem 'bootstrap-datepicker-rails' 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.2.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-facebook'
gem 'omniauth-flickr', '>= 0.0.15' gem 'omniauth-flickr', '>= 0.0.15'
gem 'omniauth-twitter'
# Pretty charts # Pretty charts
gem "chartkick" gem "chartkick"
# clever elastic search # clever elastic search
gem 'elasticsearch', '~> 7.0.0' gem 'elasticsearch', '< 7.0.0'
gem 'searchkick' gem 'searchkick'
gem "hashie", ">= 3.5.3" gem "hashie", ">= 3.5.3"
@@ -110,37 +112,23 @@ gem 'rake', '>= 10.0.0'
gem "responders" gem "responders"
# allows soft delete. Used for members. # allows soft delete. Used for members.
gem 'discard', '>= 1.2' gem 'discard', '~> 1.2'
gem 'xmlrpc' # fixes rake error - can be removed if not needed later gem 'xmlrpc' # fixes rake error - can be removed if not needed later
gem 'puma' gem 'puma'
gem 'loofah', '>= 2.19.1' gem 'loofah', '>= 2.2.1'
gem 'rack-protection', '>= 2.0.1' gem 'rack-protection', '>= 2.0.1'
# Member to member messaging system # Member to member messaging system
gem 'mailboxer', '>= 0.15.1' gem 'mailboxer'
gem 'faraday' gem 'faraday'
gem 'faraday_middleware'
gem 'rack-cors' gem 'rack-cors'
gem 'icalendar'
# for signups as requested by email service
gem 'recaptcha'
# External APIs for data
gem "gbifrb"
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'
@@ -166,23 +154,20 @@ group :development, :test do
gem 'factory_bot_rails' # for creating test data gem 'factory_bot_rails' # for creating test data
gem 'faker' gem 'faker'
gem 'haml-rails' # HTML templating language gem 'haml-rails' # HTML templating language
gem 'pry'
gem 'query_diet' gem 'query_diet'
gem 'parallel_tests'
gem 'rspec-activemodel-mocks' gem 'rspec-activemodel-mocks'
gem 'rspec-rails' # unit testing framework gem 'rspec-rails' # unit testing framework
gem 'rswag-specs' gem 'rswag-specs'
gem 'rubocop-capybara'
gem 'rubocop-factory_bot'
gem 'rubocop-rails' gem 'rubocop-rails'
gem 'rubocop-rake'
gem 'rubocop-rspec' gem 'rubocop-rspec'
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 'coveralls', require: false # coverage analysis
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
@@ -190,23 +175,14 @@ group :development, :test do
end end
group :test do group :test do
gem 'axe-core-capybara' gem 'codeclimate-test-reporter', require: false
gem 'axe-core-rspec' gem 'percy-capybara', '~> 4.0.0'
gem "percy-capybara", "~> 5.0.0"
gem 'rails-controller-testing' gem 'rails-controller-testing'
gem "rspec-rebound" gem 'selenium-webdriver'
gem 'capybara-playwright-driver'
gem 'timecop' gem 'timecop'
gem 'vcr' gem 'webdrivers'
end end
group :travis do group :travis do
gem 'platform-api' gem 'platform-api'
end end
gem "i18n_data", "~> 1.1"
gem "paper_trail", "~> 17.0"
gem 'sitemap_generator'
gem 'aws-sdk-s3', '~> 1', '>= 1.114.0'

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,8 @@
# 🌱 Growstuff # 🌱 Growstuff
![Build status](https://github.com/Growstuff/growstuff/workflows/CI/badge.svg) [![Build Status](https://travis-ci.org/Growstuff/growstuff.svg?branch=dev)](https://travis-ci.org/Growstuff/growstuff)
[![Coverage Status](https://coveralls.io/repos/github/Growstuff/growstuff/badge.svg?branch=dev)](https://coveralls.io/github/Growstuff/growstuff?branch=dev)
[![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.
@@ -14,18 +16,12 @@ Growstuff was founded in 2012 and has been built by dozens of
[contributors](CONTRIBUTORS.md). We are an inclusive, welcoming project, and [contributors](CONTRIBUTORS.md). We are an inclusive, welcoming project, and
encourage participation from people of all backgrounds and skill levels. encourage participation from people of all backgrounds and skill levels.
## 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.
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)
* [Wiki](https://github.com/Growstuff/growstuff/wiki) (general documentation, 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. Help by migrating from the [old wiki](https://web.archive.org/web/*/wiki.growstuff.org))
## For coders ## For coders
@@ -34,12 +30,9 @@ frontend features. We welcome contributions -- see
[CONTRIBUTING](CONTRIBUTING.md) for details. [CONTRIBUTING](CONTRIBUTING.md) for details.
* 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).
* We encourage [pair programming](http://wiki.growstuff.org/index.php/Pairing), especially for newer developers.
* 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 +60,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

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<!-- MIT Licenced, https://www.svgrepo.com/svg/336823/plan -->
<svg width="800px" height="800px" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="48" height="48" fill="white" fill-opacity="0.01"/>
<path d="M5 19H43V41C43 42.1046 42.1046 43 41 43H7C5.89543 43 5 42.1046 5 41V19Z" fill="#2F88FF" stroke="#000000" stroke-width="4" stroke-linejoin="round"/>
<path d="M5 10C5 8.89543 5.89543 8 7 8H41C42.1046 8 43 8.89543 43 10V19H5V10Z" stroke="#000000" stroke-width="4" stroke-linejoin="round"/>
<path d="M16 31L22 37L34 25" stroke="white" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M16 5V13" stroke="#000000" stroke-width="4" stroke-linecap="round"/>
<path d="M32 5V13" stroke="#000000" stroke-width="4" stroke-linecap="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 916 B

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

@@ -12,23 +12,13 @@
// //
// = require leaflet // = require leaflet
// = require leaflet.markercluster // = require leaflet.markercluster
// = require js-routes
// = require popper // = require popper
// = require jquery // = require jquery
// = require jquery_ujs // = require jquery_ujs
// = require jquery-ui/widgets/autocomplete // = require jquery-ui/widgets/autocomplete
// = require bootstrap-sprockets // = require bootstrap-sprockets
// = require bootstrap-datepicker // = require bootstrap-datepicker
// = require bootstrap
// = require material // = require material
// = require_tree . // = require_tree .
document.addEventListener('DOMContentLoaded', function(event) {
var popoverTrigger = Array.prototype.slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'));
popoverTrigger.map(function(popoverTrigger2) {
return new bootstrap.Popover(popoverTrigger2);
});
var tooltipTrigger = Array.prototype.slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
tooltipTrigger.map(function(tooltipTrigger2) {
return new bootstrap.Tooltip(tooltipTrigger2);
});
});

View File

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
jQuery ->
$("a[rel=popover]").popover()
$(".tooltip").tooltip()
$("a[rel=tooltip]").tooltip()

View File

@@ -1,6 +1,10 @@
function showCropMap(cropmap) { function showCropMap(cropmap) {
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { var mapbox_map_id = "<%= Rails.env == 'test' ? 0 : Rails.application.config.mapbox_map_id %>";
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors', var mapbox_access_token = "<%= Rails.env == 'test' ? 0 : Rails.application.config.mapbox_access_token %>";
var mapbox_base_url = "https://a.tiles.mapbox.com/v4/" + mapbox_map_id + "/{z}/{x}/{y}.png?access_token=" + mapbox_access_token;
L.tileLayer(mapbox_base_url, {
attribution: 'Map data &copy; <a href="https://openstreetmap.org">OpenStreetMap</a> contributors under <a href="https://www.openstreetmap.org/copyright">ODbL</a> | Map imagery &copy; <a href="https://mapbox.com">Mapbox</a>',
maxZoom: 18 maxZoom: 18
}).addTo(cropmap); }).addTo(cropmap);
var markers = new L.MarkerClusterGroup({showCoverageOnHover: false, maxClusterRadius: 20 }); var markers = new L.MarkerClusterGroup({showCoverageOnHover: false, maxClusterRadius: 20 });

View File

@@ -5,7 +5,7 @@ jQuery ->
$(".remove-altname-row").css("display", "inline-block") $(".remove-altname-row").css("display", "inline-block")
-$ -> -$ ->
sci_template = "<div id='sci_template[INDEX]' class='template col-md-12'><div class='col-md-2'><label>Scientific name INDEX:</label></div><div class='col-md-8'><input name='sci_name[INDEX]' class='scientific-name-auto-suggest form-control' id='sci_name[INDEX]' data-source-url='/scientific_names/gbif_suggest')'></input><span class='help-block'>Scientific name of crop</span><input type='text' id='sci_gbif_key[INDEX]' class=''></div><div class='col-md-2'></div></div>" sci_template = "<div id='sci_template[INDEX]' class='template col-md-12'><div class='col-md-2'><label>Scientific name INDEX:</label></div><div class='col-md-8'><input name='sci_name[INDEX]' class='form-control', id='sci_name[INDEX]')'></input><span class='help-block'>Scientific name of crop.</span></div><div class='col-md-2'></div></div>"
sci_index = $('#scientific_names .template').length + 1 sci_index = $('#scientific_names .template').length + 1
@@ -21,7 +21,7 @@ jQuery ->
element = document.getElementById(tmp) element = document.getElementById(tmp)
element.remove() element.remove()
alt_template = "<div id='alt_template[INDEX]' class='template col-md-12'><div class='col-md-2'><label>Alternate name INDEX:</label></div><div class='col-md-8'><input name='alt_name[INDEX]' class='form-control' id='alt_name[INDEX]')'></input><span class='help-block'>Alternate name of crop.</span></div><div class='col-md-2'></div></div>" alt_template = "<div id='alt_template[INDEX]' class='template col-md-12'><div class='col-md-2'><label>Alternate name INDEX:</label></div><div class='col-md-8'><input name='alt_name[INDEX]' class='form-control', id='alt_name[INDEX]')'></input><span class='help-block'>Alternate name of crop.</span></div><div class='col-md-2'></div></div>"
alt_index = $('#alternate_names .template').length + 1 alt_index = $('#alternate_names .template').length + 1

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,4 +1,10 @@
if (document.getElementById("membermap") !== null) { if (document.getElementById("membermap") !== null) {
var mapbox_map_id = "<%= Rails.env == 'test' ? 0 : Rails.application.config.mapbox_map_id %>";
var mapbox_access_token = "<%= Rails.env == 'test' ? 0 : Rails.application.config.mapbox_access_token %>";
var mapbox_base_url = "https://a.tiles.mapbox.com/v4/" + mapbox_map_id + "/{z}/{x}/{y}.png?access_token=" + mapbox_access_token;
L.Icon.Default.imagePath = '/assets'
L.Icon.Default.imagePath = '/assets'; L.Icon.Default.imagePath = '/assets';
var default_marker_icon = L.icon({ var default_marker_icon = L.icon({
@@ -12,8 +18,8 @@ if (document.getElementById("membermap") !== null) {
if (member.latitude && member.longitude) { if (member.latitude && member.longitude) {
var membermap = L.map('membermap').setView([member.latitude, member.longitude], 4); var membermap = L.map('membermap').setView([member.latitude, member.longitude], 4);
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { L.tileLayer(mapbox_base_url, {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors', attribution: 'Map data &copy; <a href="https://openstreetmap.org">OpenStreetMap</a> contributors under <a href="https://www.openstreetmap.org/copyright">ODbL</a> | Map imagery &copy; <a href="https://mapbox.com">Mapbox</a>',
maxZoom: 18 maxZoom: 18
}).addTo(membermap); }).addTo(membermap);
var marker = new L.Marker(new L.LatLng(member.latitude, member.longitude), var marker = new L.Marker(new L.LatLng(member.latitude, member.longitude),

View File

@@ -0,0 +1 @@
$('.dropdown-toggle').dropdown();

View File

@@ -1,5 +1,8 @@
if (document.getElementById("placesmap") !== null) { if (document.getElementById("placesmap") !== null) {
var places_base_path = "/places"; var places_base_path = "/places";
var mapbox_map_id = "<%= Rails.env == 'test' ? 0 : Rails.application.config.mapbox_map_id %>";
var mapbox_access_token = "<%= Rails.env == 'test' ? 0 : Rails.application.config.mapbox_access_token %>";
var mapbox_base_url = "https://a.tiles.mapbox.com/v4/" + mapbox_map_id + "/{z}/{x}/{y}.png?access_token=" + mapbox_access_token;
var nominatim_base_url = 'https://nominatim.openstreetmap.org/search/'; var nominatim_base_url = 'https://nominatim.openstreetmap.org/search/';
var nominatim_user_agent_email = "<%= Rails.env == 'test' ? 0 : Rails.application.config.user_agent_email %>"; var nominatim_user_agent_email = "<%= Rails.env == 'test' ? 0 : Rails.application.config.user_agent_email %>";
@@ -28,8 +31,8 @@ if (document.getElementById("placesmap") !== null) {
} }
function showMap(placesmap) { function showMap(placesmap) {
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { L.tileLayer(mapbox_base_url, {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors', attribution: 'Map data &copy; <a href="https://openstreetmap.org">OpenStreetMap</a> contributors under <a href="https://www.openstreetmap.org/copyright">ODbL</a> | Map imagery &copy; <a href="https://mapbox.com">Mapbox</a>',
maxZoom: 18 maxZoom: 18
}).addTo(placesmap); }).addTo(placesmap);
@@ -58,7 +61,6 @@ function showMap(placesmap) {
}); });
function fetchCropsForMap(url) { function fetchCropsForMap(url) {
var n = 0;
$.getJSON(url, function(crop_data) { $.getJSON(url, function(crop_data) {
$.each(crop_data['data'], function(i, p) { $.each(crop_data['data'], function(i, p) {
if (p.attributes.latitude && p.attributes.longitude) { if (p.attributes.latitude && p.attributes.longitude) {
@@ -79,8 +81,7 @@ function showMap(placesmap) {
markers.addLayer(marker); markers.addLayer(marker);
} }
}); });
// We fetch pages of 10 at a time. Stop after 200 crops; so we are showing only 'active' plantings. if (crop_data['links']['next']) {
if (crop_data['links']['next'] && n++ < 20) {
fetchCropsForMap(crop_data['links']['next']) fetchCropsForMap(crop_data['links']['next'])
} }
return crop_data; return crop_data;

View File

@@ -1,31 +0,0 @@
# TODO: This assumes one autocomplete per page.
# Needs to be a function so that when we append one of these, it gets uniquely associated with the hidden controls.
jQuery ->
if el = $( '.scientific-name-auto-suggest' )
id = $( '.scientific-name-auto-suggest-id' )
el.autocomplete
minLength: 3,
source: el.attr( 'data-source-url' ),
focus: ( event, ui ) ->
el.val( ui.item.canonicalName )
id.val( ui.item.nameKey )
false
select: ( event, ui ) ->
el.val( ui.item.canonicalName )
id.val( ui.item.nameKey )
false
response: ( event, ui ) ->
id.val( "" )
for item in ui.content
if item.name == el.val()
id.val( item.nameKey )
if el.data( 'uiAutocomplete' )
el.data( 'uiAutocomplete' )._renderItem = ( ul, item ) ->
$( '<li class="list-group-item"></li>' )
.data( 'item.autocomplete', item )
.append( "<a>#{item.canonicalName} (#{item.scientificName}) - #{item.rank}</a>" )
.appendTo( ul )

View File

@@ -1,22 +0,0 @@
$(document).ready(function() {
var url = location.href.replace(/\/$/, '');
if (location.hash) {
var hash = url.split('#');
var triggerEl = document.querySelector('#myTab a[href="#' + hash[1] + '"]');
var tab = new bootstrap.Tab(triggerEl);
tab.show();
url = location.href.replace(/\/#/, '#');
history.replaceState(null, null, url);
setTimeout(function() {
$(window).scrollTop(0);
}, 20);
}
$('a[data-bs-toggle="tab"]').on('click', function() {
var newUrl;
var hash = $(this).attr('href');
newUrl = url.split('#')[0] + hash;
history.replaceState(null, null, newUrl);
});
});

View File

@@ -0,0 +1,3 @@
$(function() {
$('[data-toggle="tooltip"]').tooltip();
});

View File

@@ -1,19 +1,13 @@
.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;
color: $white; color: $white;
margin: 0; margin: 0;
opacity: 0.8; opacity: .8;
position: absolute; position: absolute;
text-align: center; text-align: center;
width: 100%; width: 100%;
@@ -25,10 +19,10 @@
padding-bottom: 0; padding-bottom: 0;
} }
.crop-sci-name { h5.crop-sci-name {
background-color: $beige; background-color: $beige;
color: $black; color: $black;
font-size: 0.7em; font-size: .7em;
margin-top: 0; margin-top: 0;
padding-top: 0; padding-top: 0;
} }
@@ -51,7 +45,7 @@
.planting { .planting {
.crop-card { .crop-card {
height: 100%; height: 100%;
margin: 0.1em; margin: .1em;
min-height: 300px; min-height: 300px;
} }
@@ -91,7 +85,7 @@
@include media-breakpoint-down(xs) { @include media-breakpoint-down(xs) {
.index-cards { .index-cards {
.crop-thumbnail { .crop-thumbnail {
margin: 0.2em; margin: .2em;
width: 30%; width: 30%;
} }
} }

View File

@@ -2,7 +2,7 @@
.text { .text {
color: $white; color: $white;
margin: 0; margin: 0;
opacity: 0.8; opacity: .8;
position: absolute; position: absolute;
text-align: center; text-align: center;
top: 30%; top: 30%;
@@ -12,7 +12,7 @@
h3, h3,
h4, h4,
h5 { h5 {
margin: 0; margin: 0
} }
h3 { h3 {

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

@@ -2,7 +2,7 @@
border-radius: 12px; border-radius: 12px;
height: 200px; height: 200px;
margin: 1em; margin: 1em;
padding: 0.25em; padding: .25em;
div { div {
display: inline-block; display: inline-block;
@@ -11,11 +11,12 @@
} }
} }
.member-thumbnail div ~ div { .member-thumbnail div~div {
padding-left: 1em; padding-left: 1em;
width: 15em; width: 15em;
} }
.member-chip { .member-chip {
background-color: lighten($green, 30%); background-color: lighten($green, 30%);
@@ -33,22 +34,16 @@
} }
} }
.card { .location-not-set {
.badge-location { background-image: image-url('location-not-set.en.png');
background-color: darken($blue, 10%); background-position: center;
border-radius: 5%; background-repeat: no-repeat;
color: $white; height: 250px;
width: 100%;
}
.fa-map-marker { .badge-location {
padding-right: 0.5em; background-color: darken($blue, 10%);
} border-radius: 5%;
} color: $white;
}
.badge {
text-overflow: ellipsis;
white-space: normal;
align-items: end;
max-height: 1rlh;
-webkit-line-clamp: 1;
}
}

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

@@ -1,6 +1,6 @@
.seed-card { .seed-card {
.text { .text {
opacity: 0.95; opacity: 0.8;
margin: 0; margin: 0;
padding: 0; padding: 0;
position: absolute; position: absolute;

View File

@@ -1,10 +1,10 @@
//$screen-md-min: 1028px //$screen-md-min: 1028px
// Base colours // Base colours
$beige: #f4f2ef; $beige: #f3f1ee;
$brown: #413f3b; $brown: #413f3b;
$green: #57803c; $green: #5f8e43;
$blue: #2f4365; $blue: #2f4365;
$red: #ff4d43; $red: #ff4d43;
$orange: #ffa500; $orange: #ffa500;
@@ -15,36 +15,30 @@ $body-bg: $beige;
$text-color: $brown; $text-color: $brown;
$link-color: $green; $link-color: $green;
$default-font: "Raleway", "Fira Sans", Helvetica, Arial, sans-serif; $default-font: 'Raleway',
"Fira Sans",
Helvetica,
Arial,
sans-serif;
$primary: ( $primary: (color: $green,
color: $green,
dark: darken($green, 20%), dark: darken($green, 20%),
light: lighten($green, 20%), light: lighten($green, 20%));
); $secondary: (color: $blue,
$secondary: (
color: $blue,
dark: darken($blue, 20%), dark: darken($blue, 20%),
light: lighten($blue, 20%), light: lighten($blue, 20%));
); $success: (color: $green,
$success: (
color: $green,
dark: darken($green, 20%), dark: darken($green, 20%),
light: lighten($green, 20%), light: lighten($green, 20%));
); $danger: (color: $red,
$danger: (
color: $red,
dark: darken($red, 20%), dark: darken($red, 20%),
light: lighten($red, 20%), light: lighten($red, 20%));
); $dark: (color: $brown,
$dark: (
color: $brown,
dark: darken($brown, 20%), dark: darken($brown, 20%),
light: lighten($brown, 20%), light: lighten($brown, 20%));
);
$grid-breakpoints: (
// Extra small screen / phone $grid-breakpoints: ( // Extra small screen / phone
xs: 0, xs: 0,
// Small screen / phone // Small screen / phone
sm: 576px, sm: 576px,
@@ -53,8 +47,7 @@ $grid-breakpoints: (
// Large screen / desktop // Large screen / desktop
lg: 1200px, lg: 1200px,
// Extra large screen / wide desktop // Extra large screen / wide desktop
xl: 1800px xl: 1800px);
);
// Nav bar // Nav bar
$navbar-default-bg: $brown; $navbar-default-bg: $brown;

View File

@@ -1,36 +1,33 @@
// Import original variables so they can be used in overrides // Import original variables so they can be used in overrides
@import "variables"; @import 'variables';
@import "material"; @import 'material';
@import 'jquery-ui/autocomplete';
@import 'bootstrap-datepicker';
@import 'leaflet';
@import 'leaflet.markercluster';
@import "jquery-ui/autocomplete";
@import "bootstrap-datepicker";
@import "leaflet";
@import "leaflet.markercluster";
// Font Awesome // Font Awesome
@import "font-awesome-sprockets"; @import 'font-awesome-sprockets';
@import "font-awesome"; @import 'font-awesome';
@import "material_icons"; @import 'material_icons';
@import "rails_bootstrap_forms"; @import 'rails_bootstrap_forms';
@import "overrides"; @import 'overrides';
@import "mobile"; @import 'mobile';
@import "crops"; @import 'crops';
@import "harvests"; @import 'harvests';
@import "likes"; @import 'likes';
@import "members"; @import 'members';
@import "notifications"; @import 'notifications';
@import "plantings"; @import 'plantings';
@import "photos"; @import 'photos';
@import "posts"; @import 'posts';
@import "seeds"; @import 'seeds';
@import "predictions"; @import 'predictions';
@import "homepage"; @import 'homepage';
@import "maps"; @import 'maps';
@view-transition {
navigation: auto;
}

View File

@@ -1,6 +1,7 @@
// Overrides applying only to mobile view. This must be at the end of the overrides file. // Overrides applying only to mobile view. This must be at the end of the overrides file.
// Extra small devices (portrait phones, less than 576px) // Extra small devices (portrait phones, less than 576px)
@include media-breakpoint-down(md) { @include media-breakpoint-down(md) {
.container { .container {
margin: 2px; margin: 2px;
padding: 0; padding: 0;
@@ -10,33 +11,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;
@@ -56,10 +33,11 @@
} }
.site-name:after { .site-name:after {
content: ""; content: '';
display: inline-block; display: inline-block;
width: 100%; width: 100%;
} }
} }
h1 { h1 {
@@ -78,12 +56,6 @@
margin-bottom: 0; margin-bottom: 0;
} }
.card-footer {
.d-flex {
flex-direction: column;
}
}
.sidebar { .sidebar {
border-left: 0; border-left: 0;
margin-left: 0; margin-left: 0;
@@ -94,13 +66,14 @@
height: 300px; height: 300px;
} }
section .btn { section .btn {
width: 100%; width: 100%;
} }
.index-cards { .index-cards {
.card { .card {
margin: 0.2em; margin: .2em;
width: 48%; width: 48%;
// Shrink title to fit more on page // Shrink title to fit more on page
@@ -114,6 +87,7 @@
object-fit: cover; object-fit: cover;
width: 100%; width: 100%;
} }
} }
} }
} }

View File

@@ -8,19 +8,15 @@ 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;
font-size: 3em; font-size: 3em;
margin: 0.3em; margin: .3em;
} }
img { img {
height: 100%; height: 60px;
} }
} }
@@ -50,6 +46,7 @@ body {
font-size: 5em; font-size: 5em;
} }
.ellipsis { .ellipsis {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
@@ -85,8 +82,9 @@ h3 {
font-size: 120%; font-size: 120%;
} }
section { section {
margin: 0.5em 0 0; margin: .5em 0 0;
padding: 0 0 1em; padding: 0 0 1em;
h2 { h2 {
@@ -94,7 +92,7 @@ section {
box-shadow: 1px 1px 1px 1px darken($beige, 20%); box-shadow: 1px 1px 1px 1px darken($beige, 20%);
color: $white; color: $white;
font-weight: normal; font-weight: normal;
padding: 0.2em; padding: .2em;
a { a {
color: $white; color: $white;
@@ -102,18 +100,7 @@ section {
} }
.card { .card {
background: $white;
box-shadow: 1px 3px 3px 1px darken($beige, 20%); box-shadow: 1px 3px 3px 1px darken($beige, 20%);
cursor: pointer;
transition:
0.1s transform cubic-bezier(0.155, 1.105, 0.295, 1.12),
0.1s box-shadow,
0.1s -webkit-transform cubic-bezier(0.155, 1.105, 0.295, 1.12);
}
.card:hover {
box-shadow:
1px 3px 3px 1px darken($beige, 30%);
} }
} }
@@ -130,10 +117,8 @@ section {
.card { .card {
background: $white; background: $white;
border-radius: 5%; border-radius: 5%;
margin: 0.5em 0.5em 0.5em 0; margin: .5em .5em .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%;
@@ -152,6 +137,10 @@ section {
color: $brown; color: $brown;
} }
} }
.card:hover {
background-color: $beige;
}
} }
.img-cover, .img-cover,
@@ -243,6 +232,7 @@ ul.associations {
// footer // footer
footer { footer {
#footer1, #footer1,
#footer2, #footer2,
#footer3 { #footer3 {
@@ -358,9 +348,7 @@ ul.thumbnail-buttons {
text-align: center; text-align: center;
} }
} }
.text-muted {
color: $blue;
}
.jumbotron { .jumbotron {
background-color: $beige; background-color: $beige;
margin-bottom: 1em; margin-bottom: 1em;
@@ -373,21 +361,16 @@ ul.thumbnail-buttons {
// signup widget on homepage // signup widget on homepage
.signup { .signup {
background-color: darken($green, 20%); background-color: lighten($green, 40%);
border: 1px solid darken($green, 20%); border: 1px solid lighten($green, 20%);
color: $white;
border-radius: 6px; border-radius: 6px;
line-height: 200%; line-height: 200%;
padding: 15px; padding: 15px;
text-align: center; text-align: center;
.btn-info {
background-color: $blue;
}
} }
.info { .info {
padding: 0.5em; padding: .5em;
text-align: center; text-align: center;
} }
} }
@@ -403,7 +386,7 @@ ul.thumbnail-buttons {
display: inline-block; display: inline-block;
height: 30px; height: 30px;
line-height: 30px; line-height: 30px;
margin: 0.2em; margin: .2em;
padding: 0 25px; padding: 0 25px;
a { a {
@@ -428,14 +411,14 @@ ul.thumbnail-buttons {
.progress-fade::before { .progress-fade::before {
background: $beige; background: $beige;
bottom: 0; bottom: 0;
content: ""; content: '';
display: block; display: block;
left: 0; left: 0;
opacity: 0.7; opacity: .7;
position: absolute; position: absolute;
right: 0; right: 0;
top: 0; top: 0;
transition: background 0.3s linear; transition: background .3s linear;
} }
.progress-fade:hover::before { .progress-fade:hover::before {

View File

@@ -1,119 +0,0 @@
# frozen_string_literal: true
class ActivitiesController < DataController
def index
@show_all = params[:all] == '1'
where = {}
where['active'] = true unless @show_all
if params[:member_slug]
@owner = Member.find_by(slug: params[:member_slug])
where['owner_id'] = @owner.id unless @owner.nil?
end
@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"
respond_with(@activities)
end
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
end
def new
@activity = Activity.new(
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]
@activity.garden = Garden.find_by(
owner: current_member,
id: params[:garden_id]
)
end
if params[:planting_id]
@activity.planting = Planting.find_by(
owner: current_member,
id: params[:planting_id]
)
end
respond_with @activity
end
def edit
# the following are needed to display the form but aren't used
@gardens = @activity.owner.gardens.active.order_by_name
@plantings = @activity.owner.plantings.active
end
def create
@activity = Activity.new(activity_params)
@activity.owner = current_member
@activity.due_date ||= Date.today
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
end
def update
@activity.update(activity_params)
respond_with @activity
end
def destroy
@activity.destroy
respond_with @activity, location: @activity.garden
end
private
def activity_params
params.require(:activity).permit(
:name, :description, :category, :finished,
:garden_id, :planting_id, :due_date,
:repeat_times, :repeat_weeks
)
end
def specifics
return if @owner.blank?
"#{@owner.to_param}-"
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: 'Companion was successfully 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: 'Companion was successfully destroyed.'
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

@@ -13,6 +13,12 @@ module Admin
@members = @members.order(:login_name).paginate(page: params[:page]) @members = @members.order(:login_name).paginate(page: params[:page])
end end
def destroy
@member = Member.find_by!(slug: params[:slug])
@member.discard
redirect_to admin_members_path
end
def edit def edit
@member = Member.find_by!(slug: params[:slug]) @member = Member.find_by!(slug: params[:slug])
end end
@@ -24,12 +30,6 @@ module Admin
respond_with @member, location: admin_members_path respond_with @member, location: admin_members_path
end end
def destroy
@member = Member.find_by!(slug: params[:slug])
@member.discard
redirect_to admin_members_path
end
private private
def search_term def search_term

View File

@@ -8,7 +8,7 @@ module Admin
responders :flash responders :flash
def index def index
@roles = Role.all.order(:name).paginate(page: params[:page]) @roles = Role.all.order(:name)
respond_with @roles respond_with @roles
end end
@@ -33,7 +33,7 @@ module Admin
def destroy def destroy
@role.destroy @role.destroy
respond_with @role, location: admin_roles_path, notice: "Role was successfully deleted" respond_with @role, location: admin_roles_path
end end
private private

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: "Reverted to version from #{@version.created_at.strftime('%B %d, %Y')}"
else
redirect_to admin_crops_path, alert: "Could not revert to version from #{@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

@@ -8,7 +8,7 @@ class AdminController < ApplicationController
def newsletter def newsletter
authorize! :manage, :all authorize! :manage, :all
@members = Member.confirmed.wants_newsletter.all.paginate(page: params[:page], per_page: 100) @members = Member.confirmed.wants_newsletter.all
respond_with @members respond_with @members
end end
end end

View File

@@ -9,7 +9,7 @@ class AlternateNamesController < ApplicationController
# GET /alternate_names # GET /alternate_names
# GET /alternate_names.json # GET /alternate_names.json
def index def index
@alternate_names = AlternateName.all.order(:name).paginate(page: params[:page], per_page: 100) @alternate_names = AlternateName.all.order(:name)
respond_with(@alternate_names) respond_with(@alternate_names)
end end
@@ -57,6 +57,6 @@ class AlternateNamesController < ApplicationController
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

@@ -2,8 +2,6 @@
class ApplicationController < ActionController::Base class ApplicationController < ActionController::Base
protect_from_forgery protect_from_forgery
# Working from codespaces, we want to turn off validation
skip_before_action :verify_authenticity_token if Rails.env.development? && ENV['CODESPACE_NAME']
include ApplicationHelper include ApplicationHelper
@@ -78,7 +76,6 @@ 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, :show_email, :newsletter, :send_notification_email, :send_planting_reminder,
# update password # update password

View File

@@ -14,14 +14,14 @@ class AuthenticationsController < ApplicationController
@authentication = current_member.authentications @authentication = current_member.authentications
.create_with( .create_with(
name:, name: name,
token: auth['credentials']['token'], token: auth['credentials']['token'],
secret: auth['credentials']['secret'] secret: auth['credentials']['secret']
) )
.find_or_create_by( .find_or_create_by(
provider: auth['provider'], provider: auth['provider'],
uid: auth['uid'], uid: auth['uid'],
name: name: name
) )
flash[:notice] = "Authentication successful." flash[:notice] = "Authentication successful."

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

@@ -71,7 +71,7 @@ class ConversationsController < ApplicationController
@conversation = Mailboxer::Conversation.find_by(id: params[:id]) @conversation = Mailboxer::Conversation.find_by(id: params[:id])
return unless @conversation.nil? || !@conversation.is_participant?(current_member) return unless @conversation.nil? || !@conversation.is_participant?(current_member)
redirect_to conversations_path(box:) redirect_to conversations_path(box: box)
nil nil
end end
end end

View File

@@ -10,6 +10,7 @@ class CropsController < ApplicationController
responders :flash responders :flash
def index def index
@sort = params[:sort]
@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],
@@ -39,9 +40,9 @@ class CropsController < ApplicationController
respond_with @crops respond_with @crops
end end
def gbif def openfarm
@crop = Crop.find(params[:crop_slug]) @crop = Crop.find(params[:crop_slug])
@crop.update_gbif_data! @crop.update_openfarm_data!
respond_with @crop, location: @crop respond_with @crop, location: @crop
end end
@@ -56,28 +57,21 @@ class CropsController < ApplicationController
@crops = CropSearchService.search(@term, @crops = CropSearchService.search(@term,
page: params[:page], page: params[:page],
per_page: Crop.per_page, per_page: Crop.per_page,
current_member:) current_member: current_member)
respond_with @crops
respond_to do |format|
format.html do
render
end
format.json do
render json: @crops.to_a
end
end
end end
def show def show
@crop = Crop.includes(
:scientific_names, :alternate_names, :parent, :varieties
).find_by!(slug: params[:slug])
respond_to do |format| respond_to do |format|
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'))
send_data(icon_data, type: "image/svg+xml", disposition: "inline") send_data(icon_data, type: "image/svg+xml", disposition: "inline")
end end
format.json do format.json do
@@ -95,6 +89,7 @@ class CropsController < ApplicationController
end end
def edit def edit
@crop = Crop.find_by!(slug: params[:slug])
@crop.alternate_names.build if @crop.alternate_names.blank? @crop.alternate_names.build if @crop.alternate_names.blank?
@crop.scientific_names.build if @crop.scientific_names.blank? @crop.scientific_names.build if @crop.scientific_names.blank?
end end
@@ -109,31 +104,27 @@ class CropsController < ApplicationController
@crop.approval_status = "pending" @crop.approval_status = "pending"
end end
if Crop.transaction { @crop.save && save_crop_names } notify_wranglers if Crop.transaction { @crop.save && save_crop_names }
notify_wranglers
else
@crop.alternate_names.build
@crop.scientific_names.build
end
respond_with @crop respond_with @crop
end end
def update def update
@crop = Crop.find_by!(slug: params[:slug])
if can?(:wrangle, @crop) if can?(:wrangle, @crop)
@crop.approval_status = 'rejected' if params.fetch("reject", false) @crop.approval_status = 'rejected' if params.fetch("reject", false)
@crop.approval_status = 'approved' if params.fetch("approve", false) @crop.approval_status = 'approved' if params.fetch("approve", false)
end end
@crop.creator = current_member if @crop.approval_status == "pending" @crop.creator = current_member if @crop.approval_status == "pending"
if @crop.update(crop_params) if @crop.update(crop_params)
recreate_names('alt_name', 'alternate') recreate_names('alt_name', 'alternate')
recreate_names('sci_name', 'scientific') recreate_names('sci_name', 'scientific')
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_gbif_data! @crop.update_openfarm_data!
end end
else else
@crop.approval_status = @crop.approval_status_was @crop.approval_status = @crop.approval_status_was
@@ -149,34 +140,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.left_joins(:alternate_names).where(alternate_names: { id: nil }).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,8 +152,12 @@ 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" } }) params[:alt_name]&.values&.each do |value|
ScientificName.create!(names_params(:sci_name).map { |n| { name: n, creator_id: current_member.id, crop_id: @crop.id } }) create_name!('alternate', value) unless value.empty?
end
params[:sci_name]&.values&.each do |value|
create_name!('scientific', value) unless value.empty?
end
end end
def notify_wranglers def notify_wranglers
@@ -204,49 +171,49 @@ 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 do |_i, 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, :en_wikipedia_url,
:parent_id, :perennial, :name,
:request_notes, :reason_for_rejection, :parent_id,
:perennial,
:request_notes,
:reason_for_rejection,
:rejection_notes, :rejection_notes,
:description, scientific_names_attributes: %i(scientific_name
:public_food_key, _destroy
:row_spacing, :spread, :height, id)
:sowing_method, :sun_requirements, :growing_degree_days,
scientific_names_attributes: %i(scientific_name _destroy id)
) )
end end
def names_params(name_type)
params.require(name_type).values&.reject { |n| n.empty? }
end
def filename def filename
"Growstuff-Crops-#{Time.zone.now.to_fs(:number)}.csv" "Growstuff-Crops-#{Time.zone.now.to_s(:number)}.csv"
end end
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

@@ -5,10 +5,6 @@ class FollowsController < ApplicationController
load_and_authorize_resource load_and_authorize_resource
skip_load_resource only: :create skip_load_resource only: :create
def index
@follows = @member.followed.paginate(page: params[:page])
end
def create def create
@follow = current_member.follows.build(followed: Member.find(params[:followed])) @follow = current_member.follows.build(followed: Member.find(params[:followed]))
@@ -29,6 +25,10 @@ class FollowsController < ApplicationController
redirect_to @unfollowed redirect_to @unfollowed
end end
def index
@follows = @member.followed.paginate(page: params[:page])
end
def followers def followers
@followers = @member.followers.paginate(page: params[:page]) @followers = @member.followers.paginate(page: params[:page])
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

@@ -4,23 +4,18 @@ class GardensController < DataController
def index def index
@owner = Member.find_by(slug: params[:member_slug]) @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)
@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 +34,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

View File

@@ -20,7 +20,7 @@ class HarvestsController < DataController
where['planting_id'] = @planting.id where['planting_id'] = @planting.id
end end
@harvests = Harvest.search('*', where:, @harvests = Harvest.search('*', where: where,
limit: 100, limit: 100,
page: params[:page], page: params[:page],
load: false, load: false,
@@ -92,7 +92,7 @@ class HarvestsController < DataController
elsif @crop elsif @crop
"#{@crop.to_param}-" "#{@crop.to_param}-"
end end
"Growstuff-#{specifics}Harvests-#{Time.zone.now.to_fs(:number)}.csv" "Growstuff-#{specifics}Harvests-#{Time.zone.now.to_s(:number)}.csv"
end end
def update_crop_medians def update_crop_medians

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

@@ -39,7 +39,7 @@ class LikesController < ApplicationController
{ {
id: like.likeable.id, id: like.likeable.id,
like_count: like.likeable.likes.count, like_count: like.likeable.likes.count,
liked_by_member:, liked_by_member: liked_by_member,
description: ActionController::Base.helpers.pluralize(like.likeable.likes.count, "like") description: ActionController::Base.helpers.pluralize(like.likeable.likes.count, "like")
} }
end end
@@ -50,7 +50,7 @@ class LikesController < ApplicationController
format.json do format.json do
render(json: render_json( render(json: render_json(
like, like,
liked_by_member: liked_by_member: liked_by_member
), status: status_code) ), status: status_code)
end end
end end
@@ -58,7 +58,7 @@ class LikesController < ApplicationController
def failed(like, message) def failed(like, message)
respond_to do |format| respond_to do |format|
format.json { render(json: { error: message }, status: :forbidden) } format.json { render(json: { 'error': message }, status: :forbidden) }
format.html do format.html do
flash[:error] = message flash[:error] = message
if like&.likeable if like&.likeable

View File

@@ -16,7 +16,9 @@ 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')
@facebook_auth = @member.auth('facebook')
@posts = @member.posts @posts = @member.posts
@activity = TimelineService.member_query(@member).limit(30) @activity = TimelineService.member_query(@member).limit(30)
@@ -60,7 +62,7 @@ class MembersController < ApplicationController
end end
def unsubscribe def unsubscribe
verifier = ActiveSupport::MessageVerifier.new(ENV.fetch('RAILS_SECRET_TOKEN', nil)) verifier = ActiveSupport::MessageVerifier.new(ENV['RAILS_SECRET_TOKEN'])
decrypted_message = verifier.verify(params[:message]) decrypted_message = verifier.verify(params[:message])
@member = Member.find(decrypted_message[:member_id]) @member = Member.find(decrypted_message[:member_id])

View File

@@ -21,7 +21,7 @@ class MessagesController < ApplicationController
return if params[:recipient_id].blank? return if params[:recipient_id].blank?
@recipient = Member.find_by(id: params[:recipient_id]) @recipient = Member.find_by(id: params[:recipient_id])
nil if @recipient.nil? return if @recipient.nil?
end end
def create def create

View File

@@ -9,6 +9,10 @@ require './lib/actions/oauth_signup_action'
# Heavily overlaps with Authentications controller # Heavily overlaps with Authentications controller
# #
class OmniauthCallbacksController < Devise::OmniauthCallbacksController class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
create
end
def failure def failure
flash[:alert] = "Authentication failed." flash[:alert] = "Authentication failed."
redirect_to request.env['omniauth.origin'] || "/" redirect_to request.env['omniauth.origin'] || "/"
@@ -28,7 +32,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(facebook 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
@@ -41,7 +45,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def after_sign_in_path_for(resource) def after_sign_in_path_for(resource)
if resource.tos_agreement if resource.tos_agreement
super super resource
else else
finish_signup_path(resource) finish_signup_path(resource)
end end

View File

@@ -8,6 +8,11 @@ class PhotosController < ApplicationController
respond_to :html, :json respond_to :html, :json
responders :flash responders :flash
def show
@crops = Crop.distinct.joins(:photo_associations).where(photo_associations: { photo: @photo })
respond_with(@photo)
end
def index def index
@photos = Photo.search( @photos = Photo.search(
load: false, load: false,
@@ -19,12 +24,6 @@ class PhotosController < ApplicationController
respond_with(@photos) respond_with(@photos)
end end
def show
@crops = Crop.distinct.joins(:photo_associations).where(photo_associations: { photo: @photo })
@comment = Comment.new(commentable: @photo)
respond_with(@photo)
end
def new def new
@photo = Photo.new @photo = Photo.new
@item = item_to_link_to @item = item_to_link_to
@@ -64,7 +63,7 @@ class PhotosController < ApplicationController
def photo_params def photo_params
params.require(:photo).permit(:source_id, :source, :title, :license_name, params.require(:photo).permit(:source_id, :source, :title, :license_name,
:license_url, :thumbnail_url, :fullsize_url, :link_url, :date_taken) :license_url, :thumbnail_url, :fullsize_url, :link_url)
end end
# Item with photos attached # Item with photos attached
@@ -93,15 +92,8 @@ class PhotosController < ApplicationController
def retrieve_from_flickr def retrieve_from_flickr
@flickr_auth = current_member.auth('flickr') @flickr_auth = current_member.auth('flickr')
return if @flickr_auth.nil?
unless current_member.flickr_auth_valid?
current_member.remove_stale_flickr_auth
@please_reconnect_flickr = true
return
end
@current_set = params[:set] @current_set = params[:set]
return unless @flickr_auth
page = params[:page] || 1 page = params[:page] || 1

View File

@@ -6,7 +6,7 @@ class PlantPartsController < ApplicationController
responders :flash responders :flash
def index def index
@plant_parts = PlantPart.all.order(:name).paginate(page: params[:page], per_page: 100) @plant_parts = PlantPart.all.order(:name)
respond_with(@plant_parts) respond_with(@plant_parts)
end end

View File

@@ -3,7 +3,6 @@
class PlantingsController < DataController class PlantingsController < DataController
after_action :update_crop_medians, only: %i(create update destroy) after_action :update_crop_medians, only: %i(create update destroy)
after_action :update_planting_medians, only: :update after_action :update_planting_medians, only: :update
respond_to :ics, only: [:index] # TODO: This can be shifted up when all relevant controllers respond to ical
def index def index
@show_all = params[:all] == '1' @show_all = params[:all] == '1'
@@ -13,31 +12,30 @@ class PlantingsController < DataController
if params[:member_slug] 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 unless @owner.nil? where['owner_id'] = @owner.id
end end
if params[:crop_slug] if params[:crop_slug]
@crop = Crop.find_by(slug: params[:crop_slug]) @crop = Crop.find_by(slug: params[:crop_slug])
where['crop_id'] = @crop.id unless @crop.nil? where['crop_id'] = @crop.id
end end
@plantings = Planting.search( @plantings = Planting.search(
where:, where: where,
page: params[:page], page: params[:page],
limit: 30, limit: 30,
boost_by: [:created_at], boost_by: [:created_at],
load: false load: false
) )
@filename = "Growstuff-#{specifics}Plantings-#{Time.zone.now.to_fs(:number)}.csv" @filename = "Growstuff-#{specifics}Plantings-#{Time.zone.now.to_s(:number)}.csv"
respond_with(@plantings) respond_with(@plantings)
end end
def show def show
@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)
@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 +44,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 +90,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: 'Planting was successfully transplanted.'
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: "There was an error transplanting the planting: #{new_planting.errors.full_messages.to_sentence}"
end
end
private private
def update_crop_medians def update_crop_medians
@@ -140,7 +106,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

View File

@@ -3,10 +3,10 @@
class RegistrationsController < Devise::RegistrationsController class RegistrationsController < Devise::RegistrationsController
respond_to :json respond_to :json
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')
@facebook_auth = current_member.auth('facebook')
render "edit" render "edit"
end end
@@ -38,12 +38,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
@@ -53,25 +47,6 @@ class RegistrationsController < Devise::RegistrationsController
render "edit" render "edit"
end end
end end
private
def sign_up_params
params.require(:member).permit(:login_name, :email, :tos_agreement, :newsletter, :password, :password_confirmation)
end
def check_captcha
return if verify_recaptcha # verify_recaptcha(action: 'signup') for v3
self.resource = resource_class.new sign_up_params
resource.validate # Look for any other validation errors besides reCAPTCHA
set_minimum_password_length
respond_with_navigational(resource) do
flash.discard(:recaptcha_error) # We need to discard flash to avoid showing it on the next page reload
render :new
end
end
end end
# check if we need the current password to update fields # check if we need the current password to update fields

View File

@@ -1,15 +1,15 @@
# frozen_string_literal: true # frozen_string_literal: true
class ScientificNamesController < ApplicationController class ScientificNamesController < ApplicationController
before_action :authenticate_member!, except: %i(index show gbif_suggest) before_action :authenticate_member!, except: %i(index show)
load_and_authorize_resource except: [:gbif_suggest] load_and_authorize_resource
respond_to :html, :json respond_to :html, :json
responders :flash responders :flash
# GET /scientific_names # GET /scientific_names
# GET /scientific_names.json # GET /scientific_names.json
def index def index
@scientific_names = ScientificName.all.order(:name).paginate(page: params[:page], per_page: 100) @scientific_names = ScientificName.all.order(:name)
respond_with(@scientific_names) respond_with(@scientific_names)
end end
@@ -35,7 +35,7 @@ class ScientificNamesController < ApplicationController
def create def create
@scientific_name = ScientificName.new(scientific_name_params) @scientific_name = ScientificName.new(scientific_name_params)
@scientific_name.creator = current_member @scientific_name.creator = current_member
gbif_sync!(@scientific_name)
@scientific_name.save @scientific_name.save
respond_with(@scientific_name.crop) respond_with(@scientific_name.crop)
end end
@@ -43,9 +43,7 @@ class ScientificNamesController < ApplicationController
# PUT /scientific_names/1 # PUT /scientific_names/1
# PUT /scientific_names/1.json # PUT /scientific_names/1.json
def update def update
@scientific_name.assign_attributes(scientific_name_params) @scientific_name.update(scientific_name_params)
gbif_sync!(@scientific_name)
@scientific_name.save
respond_with(@scientific_name.crop) respond_with(@scientific_name.crop)
end end
@@ -58,26 +56,9 @@ class ScientificNamesController < ApplicationController
respond_with(@crop) respond_with(@crop)
end end
def gbif_suggest
render json: gbif_service.suggest(params[:term])
end
private private
def gbif_sync!(model)
return unless model.gbif_key
result = gbif_service.fetch(model.gbif_key)
model.gbif_rank = result["rank"]
model.gbif_status = result["status"]
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)
end
def gbif_service
GbifService.new
end end
end end

View File

@@ -19,14 +19,12 @@ 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
@filename = csv_filename @filename = csv_filename
@seeds = Seed.search( @seeds = Seed.search(
where:, where: where,
page: params[:page], page: params[:page],
limit: 30, limit: 30,
boost_by: [:created_at], boost_by: [:created_at],
@@ -37,13 +35,12 @@ class SeedsController < DataController
end end
def show def show
@photos = @seed.photos.includes(:owner).order(created_at: :desc, id: :desc).paginate(page: params[:page], per_page: 30) @photos = @seed.photos.includes(:owner).order(created_at: :desc).paginate(page: params[:page])
respond_with(@seed) respond_with(@seed)
end end
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,8 +54,6 @@ 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] = "Successfully added #{@seed.crop} seed to your stash." if @seed.save flash[:notice] = "Successfully added #{@seed.crop} seed to your stash." if @seed.save
@@ -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
) )
@@ -94,9 +89,9 @@ class SeedsController < DataController
def csv_filename def csv_filename
if @owner if @owner
"Growstuff-#{@owner.to_param}-Seeds-#{Time.zone.now.to_fs(:number)}.csv" "Growstuff-#{@owner.to_param}-Seeds-#{Time.zone.now.to_s(:number)}.csv"
else else
"Growstuff-Seeds-#{Time.zone.now.to_fs(:number)}.csv" "Growstuff-Seeds-#{Time.zone.now.to_s(:number)}.csv"
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,44 +21,17 @@ 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
max_updated_at = klass.maximum(:updated_at).try(:utc).try(:to_fs, :number) max_updated_at = klass.maximum(:updated_at).try(:utc).try(:to_s, :number)
"#{klass.name.downcase.pluralize}/#{identifier}-#{count}-#{max_updated_at}" "#{klass.name.downcase.pluralize}/#{identifier}-#{count}-#{max_updated_at}"
end end
# A helper to replace the complex template compilation mess def required_field_help_text
# of HAML, Tilt, and dynamic compilation with interpolated ruby. asterisk = tag.span('*', class: ['red'])
def markdownify(text) text = tag.em('denotes a required field')
translator = Haml::Filters::GrowstuffMarkdown.new tag.div(asterisk + ' '.html_safe + text, class: ['margin-bottom'])
translator.expand_members!(translator.expand_crops!(text.to_s))
end end
# #
@@ -77,12 +49,13 @@ 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
end end
Gravatar.new(member.email).image_url(size:, Gravatar.new(member.email).image_url(size: size,
default: :identicon, default: :identicon,
ssl: true) ssl: true)
end end
@@ -97,11 +70,11 @@ module ApplicationHelper
all = show_all ? '' : 1 all = show_all ? '' : 1
if owner.present? if owner.present?
public_send("member_#{type}_path", owner, all:) public_send("member_#{type}_path", owner, all: all)
elsif crop.present? elsif crop.present?
public_send("crop_#{type}_path", crop, all:) public_send("crop_#{type}_path", crop, all: all)
else else
public_send("#{type}_path", all:) public_send("#{type}_path", all: all)
end end
end end
@@ -120,22 +93,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
@@ -19,30 +18,6 @@ module ButtonsHelper
end end
end end
def garden_plan_something_button(garden, classes: "btn btn-default")
return unless can? :edit, garden
link_to new_activity_path(garden_id: garden.id), class: classes do
activity_icon + ' ' + t('buttons.new_activity')
end
end
def plan_something_button
return unless can? :create, Activity
link_to new_activity_path, class: "btn btn-default" do
activity_icon + ' ' + t('buttons.new_activity')
end
end
def planting_plan_something_button(planting, classes: "btn btn-default")
return unless can? :edit, planting
link_to new_activity_path(planting_id: planting.id), class: classes do
activity_icon + ' ' + t('buttons.new_activity')
end
end
def garden_mark_active_button(garden, classes: 'btn') def garden_mark_active_button(garden, classes: 'btn')
link_to t('buttons.mark_as_active'), link_to t('buttons.mark_as_active'),
garden_path(garden, garden: { active: 1 }), garden_path(garden, garden: { active: 1 }),
@@ -53,7 +28,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)
@@ -69,49 +44,23 @@ module ButtonsHelper
end end
def seed_edit_button(seed, classes: "btn btn-raised btn-info") def seed_edit_button(seed, classes: "btn btn-raised btn-info")
edit_button(edit_seed_path(seed), classes:) edit_button(edit_seed_path(seed), classes: classes)
end end
def harvest_edit_button(harvest, classes: "btn btn-raised btn-info") def harvest_edit_button(harvest, classes: "btn btn-raised btn-info")
edit_button(edit_harvest_path(harvest), classes:) edit_button(edit_harvest_path(harvest), classes: classes)
end end
def garden_edit_button(garden, classes: "btn btn-raised btn-info") def garden_edit_button(garden, classes: "btn btn-raised btn-info")
edit_button(edit_garden_path(garden), classes:) edit_button(edit_garden_path(garden), classes: classes)
end end
def planting_edit_button(planting, classes: "btn btn-raised btn-info") def planting_edit_button(planting, classes: "btn btn-raised btn-info")
edit_button(edit_planting_path(planting), classes:) edit_button(edit_planting_path(planting), classes: classes)
end
def activity_edit_button(activity, classes: "btn btn-raised btn-info")
edit_button(edit_activity_path(slug: activity.slug), 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
def activity_finish_button(activity, classes: 'btn btn-default btn-secondary')
return unless can?(:edit, activity) || activity.finished
link_to activity_path(slug: activity.slug, activity: { finished: 1 }),
method: :put, class: "#{classes} append-date" do
finished_icon + ' ' + t('buttons.mark_as_finished')
end
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 +68,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 +85,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,92 +1,20 @@
# frozen_string_literal: true # frozen_string_literal: true
module CropsHelper module CropsHelper
def crop_or_parent(crop, attribute)
default = crop.send(attribute)
return default if default.present?
parent = crop
while parent = parent.parent
return parent.send(attribute) if parent&.send(attribute).present?
end
# For scopes, arrays, etc return the empty value
default
end
def display_seed_availability(member, crop) def display_seed_availability(member, crop)
seeds = member.seeds.where(crop:) seeds = member.seeds.where(crop: crop)
total_quantity = seeds.where.not(quantity: nil).sum(:quantity) total_quantity = seeds.where.not(quantity: nil).sum(:quantity)
return "You don't have any seeds of this crop." if seeds.none? return "You don't have any seeds of this crop." if seeds.none?
if total_quantity == 0 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." "You have #{total_quantity} #{Seed.model_name.human(count: total_quantity)} of this crop."
else
"You have an unknown quantity of seeds of this crop."
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://rover.ebay.com/rover/1/705-53470-19255-0/1?icep_ff3=9&pub=5575213277&toolid=10001&campid=5337940151&customid=&icep_uq=#{CGI.escape crop.name}&icep_sellerId=&icep_ex_kw=&icep_sortBy=12&icep_catId=181003&icep_minPrice=&icep_maxPrice=&ipn=psmain&icep_vectorid=229515&kwid=902099&mtid=824&kw=lg"
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)
same_as_urls = [crop.en_wikipedia_url]
crop.scientific_names.each do |scientific_name|
same_as_urls << "https://www.wikidata.org/wiki/#{scientific_name.wikidata_id}" if scientific_name.wikidata_id.present?
end
subject_of_entities = []
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
images = []
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

@@ -2,7 +2,7 @@
module EditableFormHelper module EditableFormHelper
def editable(field_type, model, field, display_field:, collection: []) def editable(field_type, model, field, display_field:, collection: [])
render 'shared/editable/form', field_type:, render 'shared/editable/form', field_type: field_type,
model:, field:, display_field:, collection: model: model, field: field, display_field: display_field, collection: collection
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

@@ -11,12 +11,10 @@ module GardensHelper
end end
end end
# TODO: Not used?
def display_garden_name(garden) def display_garden_name(garden)
truncate(garden.name, length: 50, separator: ' ', omission: '... ') truncate(garden.name, length: 50, separator: ' ', omission: '... ')
end end
# TODO: Only used by specs?
def display_garden_plantings(plantings) def display_garden_plantings(plantings)
if plantings.blank? if plantings.blank?
"None" "None"

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
@@ -75,10 +71,6 @@ module IconsHelper
icon('fas', 'seedling') icon('fas', 'seedling')
end end
def activity_icon
icon('fas', 'fa-truck-pickup')
end
def post_icon def post_icon
image_icon 'post' image_icon 'post'
end end
@@ -101,7 +93,7 @@ module IconsHelper
def plant_part_icon(name) def plant_part_icon(name)
if File.exist? Rails.root.join('app', 'assets', 'images', 'icons', 'plant_parts', "#{name}.svg") if File.exist? Rails.root.join('app', 'assets', 'images', 'icons', 'plant_parts', "#{name}.svg")
image_tag "icons/plant_parts/#{name}.svg", class: 'img img-icon', 'aria-hidden' => "true", alt: name image_tag "icons/plant_parts/#{name}.svg", class: 'img img-icon', 'aria-hidden' => "true"
else else
planting_icon planting_icon
end end
@@ -109,7 +101,7 @@ module IconsHelper
def crop_icon(crop) def crop_icon(crop)
if crop.svg_icon.present? if crop.svg_icon.present?
image_tag(crop_path(crop, format: 'svg'), class: 'crop-icon', alt: crop) image_tag(crop_path(crop, format: 'svg'), class: 'crop-icon')
elsif crop.parent.present? elsif crop.parent.present?
crop_icon(crop.parent) crop_icon(crop.parent)
else else
@@ -131,6 +123,6 @@ module IconsHelper
end end
def image_icon(icon) def image_icon(icon)
image_tag "icons/#{icon}.svg", class: 'img img-icon', 'aria-hidden' => "true", alt: icon image_tag "icons/#{icon}.svg", class: 'img img-icon', 'aria-hidden' => "true"
end end
end end

View File

@@ -43,14 +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)
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
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

@@ -1,7 +1,12 @@
# frozen_string_literal: true # frozen_string_literal: true
module PostsHelper module PostsHelper
def display_post_truncated(post, length: 300)
truncate(strip_tags(post.body), length: length,
separator: ' ', omission: '... ') { link_to "Read more", post_path(post) }
end
def post_stripped_tags(post, length: 300) def post_stripped_tags(post, length: 300)
truncate(strip_tags(markdownify(post.body)), length:) truncate(strip_tags(post.body), length: length)
end end
end end

View File

@@ -2,15 +2,15 @@
class NotifierMailer < ApplicationMailer class NotifierMailer < ApplicationMailer
# include NotificationsHelper # include NotificationsHelper
default from: "Growstuff <#{ENV.fetch('GROWSTUFF_EMAIL', nil)}>" default from: "Growstuff <#{ENV['GROWSTUFF_EMAIL']}>"
def verifier def verifier
unless ENV['RAILS_SECRET_TOKEN'] unless ENV['RAILS_SECRET_TOKEN']
raise "RAILS_SECRET_TOKEN environment variable" \ raise "RAILS_SECRET_TOKEN environment variable"\
"not set - have you created config/application.yml?" "not set - have you created config/application.yml?"
end end
ActiveSupport::MessageVerifier.new(ENV.fetch('RAILS_SECRET_TOKEN', nil)) ActiveSupport::MessageVerifier.new(ENV['RAILS_SECRET_TOKEN'])
end end
def notify(notification) def notify(notification)
@@ -27,7 +27,7 @@ class NotifierMailer < ApplicationMailer
def planting_reminder(member) def planting_reminder(member)
@member = member @member = member
@sitename = ENV.fetch('GROWSTUFF_SITE_NAME', nil) @sitename = ENV['GROWSTUFF_SITE_NAME']
@late = [] @late = []
@super_late = [] @super_late = []

View File

@@ -70,17 +70,15 @@ class Ability
can :create, Notification do |n| can :create, Notification do |n|
n.recipient_id != member.id n.recipient_id != member.id
end end
# NOTE: we don't support update for notifications # note we don't support update for notifications
# only crop wranglers can create/edit/destroy crops # only crop wranglers can create/edit/destroy crops
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
can :gbif, Crop
end end
# any member can create a crop provisionally # any member can create a crop provisionally
@@ -109,42 +107,12 @@ 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 :create, Activity
can :update, 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
@@ -180,10 +148,5 @@ class Ability
can :destroy, PlantPart do |pp| can :destroy, PlantPart do |pp|
pp.harvests.empty? pp.harvests.empty?
end end
# Admins can't delete themselves
cannot :destroy, Member
can :destroy, Member do |other_member|
other_member&.id != member.id
end
end end
end end

View File

@@ -1,49 +0,0 @@
# frozen_string_literal: true
class Activity < ApplicationRecord
extend FriendlyId
include Ownable
include Finishable
include SearchActivities
include Likeable
belongs_to :garden, optional: true
belongs_to :planting, optional: true
friendly_id :activity_slug, use: %i(slugged finders)
CATEGORIES = ["General", "Weeding", "Soil Cultivation", "Fertilizing", "Pruning", "Topical Application/Treating", "Watering"]
validates :name, presence: true
validates :category, inclusion: { in: CATEGORIES }, presence: true
validates :owner, presence: true
validates :slug, uniqueness: true
delegate :location, :latitude, :longitude, to: :owner
delegate :login_name, :slug, :location, to: :owner, prefix: true
def activity_slug
"#{owner.login_name}-#{name}-#{id}".downcase.tr(' ', '-')
end
def to_s
name
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
end

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