mirror of
https://github.com/Growstuff/growstuff.git
synced 2026-05-25 09:19:15 -04:00
Compare commits
6 Commits
feature/po
...
yarn-updat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08b63b372a | ||
|
|
98c9456065 | ||
|
|
33b0f743a5 | ||
|
|
3b1add686b | ||
|
|
723d62bf41 | ||
|
|
68e4a32cff |
1
.github/dependabot.yml
vendored
1
.github/dependabot.yml
vendored
@@ -13,4 +13,3 @@ updates:
|
||||
interval: daily
|
||||
time: "07:00"
|
||||
open-pull-requests-limit: 10
|
||||
|
||||
|
||||
40
.github/workflows/brakeman-analysis.yml
vendored
Normal file
40
.github/workflows/brakeman-analysis.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
# This workflow integrates Brakeman with GitHub's Code Scanning feature
|
||||
# Brakeman is a static analysis security vulnerability scanner for Ruby on Rails applications
|
||||
|
||||
name: Brakeman Scan
|
||||
|
||||
# This section configures the trigger for the workflow. Feel free to customize depending on your convention
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ dev ]
|
||||
|
||||
jobs:
|
||||
brakeman-scan:
|
||||
name: Brakeman Scan
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Checkout the repository to the GitHub Actions runner
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Customize the ruby version depending on your needs
|
||||
- name: Setup Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
|
||||
- name: Setup Brakeman
|
||||
env:
|
||||
BRAKEMAN_VERSION: '5.1.1' # SARIF support is provided in Brakeman version 4.10+
|
||||
run: |
|
||||
gem install brakeman --version $BRAKEMAN_VERSION
|
||||
|
||||
# Execute Brakeman CLI and generate a SARIF output with the security issues identified during the analysis
|
||||
- name: Scan
|
||||
continue-on-error: true
|
||||
run: |
|
||||
brakeman -f sarif -o output.sarif.json .
|
||||
|
||||
# Upload the SARIF file generated in the previous step
|
||||
- name: Upload SARIF
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: output.sarif.json
|
||||
102
.github/workflows/ci-features-admin.yml
vendored
102
.github/workflows/ci-features-admin.yml
vendored
@@ -1,102 +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@v4
|
||||
|
||||
- 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@v4
|
||||
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
|
||||
102
.github/workflows/ci-features-comments.yml
vendored
102
.github/workflows/ci-features-comments.yml
vendored
@@ -1,102 +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@v4
|
||||
|
||||
- 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@v4
|
||||
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
|
||||
103
.github/workflows/ci-features-conversations.yml
vendored
103
.github/workflows/ci-features-conversations.yml
vendored
@@ -1,103 +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@v4
|
||||
|
||||
- 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@v4
|
||||
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
|
||||
|
||||
102
.github/workflows/ci-features-crops.yml
vendored
102
.github/workflows/ci-features-crops.yml
vendored
@@ -1,102 +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@v4
|
||||
|
||||
- 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@v4
|
||||
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
|
||||
102
.github/workflows/ci-features-gardens.yml
vendored
102
.github/workflows/ci-features-gardens.yml
vendored
@@ -1,102 +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@v4
|
||||
|
||||
- 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@v4
|
||||
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
|
||||
102
.github/workflows/ci-features-harvests.yml
vendored
102
.github/workflows/ci-features-harvests.yml
vendored
@@ -1,102 +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@v4
|
||||
|
||||
- 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@v4
|
||||
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
|
||||
102
.github/workflows/ci-features-home.yml
vendored
102
.github/workflows/ci-features-home.yml
vendored
@@ -1,102 +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@v4
|
||||
|
||||
- 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@v4
|
||||
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
|
||||
102
.github/workflows/ci-features-members.yml
vendored
102
.github/workflows/ci-features-members.yml
vendored
@@ -1,102 +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@v4
|
||||
|
||||
- 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@v4
|
||||
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
|
||||
102
.github/workflows/ci-features-plantings.yml
vendored
102
.github/workflows/ci-features-plantings.yml
vendored
@@ -1,102 +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@v4
|
||||
|
||||
- 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@v4
|
||||
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
|
||||
102
.github/workflows/ci-features-seeds.yml
vendored
102
.github/workflows/ci-features-seeds.yml
vendored
@@ -1,102 +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@v4
|
||||
|
||||
- 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@v4
|
||||
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 (seeds/)
|
||||
run: bundle exec rspec spec/features/seeds/ -fd -t ~@flaky
|
||||
102
.github/workflows/ci-features-timeline.yml
vendored
102
.github/workflows/ci-features-timeline.yml
vendored
@@ -1,102 +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@v4
|
||||
|
||||
- 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@v4
|
||||
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 (timeline/)
|
||||
run: bundle exec rspec spec/features/timeline/ -fd -t ~@flaky
|
||||
125
.github/workflows/ci-features.yml
vendored
125
.github/workflows/ci-features.yml
vendored
@@ -1,125 +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@v4
|
||||
|
||||
- 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@v4
|
||||
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 (*_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 (places/)
|
||||
run: bundle exec rspec spec/features/places/ -fd
|
||||
|
||||
- name: Run rspec (plantings/)
|
||||
run: bundle exec rspec spec/features/plantings/ -fd
|
||||
|
||||
- name: Run rspec (posts/)
|
||||
run: bundle exec rspec spec/features/posts/ -fd
|
||||
|
||||
- name: Run rspec (rss/)
|
||||
run: bundle exec rspec spec/features/rss/ -fd
|
||||
|
||||
- name: Report to code climate
|
||||
run: |
|
||||
gem install codeclimate-test-reporter
|
||||
codeclimate-test-reporter
|
||||
31
.github/workflows/ci.yml
vendored
31
.github/workflows/ci.yml
vendored
@@ -72,6 +72,8 @@ jobs:
|
||||
#
|
||||
# See https://github.com/actions/cache/blob/master/examples.md#node---yarn for details
|
||||
#
|
||||
- name: Enable Corepack
|
||||
run: corepack enable
|
||||
- name: Get yarn cache directory path
|
||||
id: yarn-cache-dir-path
|
||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
@@ -106,28 +108,15 @@ jobs:
|
||||
|
||||
- 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 (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
|
||||
- name: Run rspec (report results to Percy.io and CodeClimate)
|
||||
run: bundle exec rspec spec -fd
|
||||
|
||||
- name: Report to code climate
|
||||
run: |
|
||||
|
||||
@@ -158,7 +158,7 @@ Metrics/BlockLength:
|
||||
# Offense count: 7
|
||||
# Configuration parameters: CountComments, CountAsOne.
|
||||
Metrics/ClassLength:
|
||||
Max: 188
|
||||
Max: 183
|
||||
|
||||
# Offense count: 6
|
||||
# Configuration parameters: AllowedMethods, AllowedPatterns.
|
||||
|
||||
@@ -1 +1 @@
|
||||
3.3.7
|
||||
3.3.4
|
||||
|
||||
BIN
.yarn/install-state.gz
Normal file
BIN
.yarn/install-state.gz
Normal file
Binary file not shown.
925
.yarn/releases/yarn-4.5.0.cjs
vendored
Executable file
925
.yarn/releases/yarn-4.5.0.cjs
vendored
Executable file
File diff suppressed because one or more lines are too long
3
.yarnrc.yml
Normal file
3
.yarnrc.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
nodeLinker: node-modules
|
||||
|
||||
yarnPath: .yarn/releases/yarn-4.5.0.cjs
|
||||
423
Gemfile.lock
423
Gemfile.lock
@@ -33,29 +33,29 @@ GEM
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
actioncable (7.2.2.1)
|
||||
actionpack (= 7.2.2.1)
|
||||
activesupport (= 7.2.2.1)
|
||||
actioncable (7.2.1)
|
||||
actionpack (= 7.2.1)
|
||||
activesupport (= 7.2.1)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (>= 0.6.1)
|
||||
zeitwerk (~> 2.6)
|
||||
actionmailbox (7.2.2.1)
|
||||
actionpack (= 7.2.2.1)
|
||||
activejob (= 7.2.2.1)
|
||||
activerecord (= 7.2.2.1)
|
||||
activestorage (= 7.2.2.1)
|
||||
activesupport (= 7.2.2.1)
|
||||
actionmailbox (7.2.1)
|
||||
actionpack (= 7.2.1)
|
||||
activejob (= 7.2.1)
|
||||
activerecord (= 7.2.1)
|
||||
activestorage (= 7.2.1)
|
||||
activesupport (= 7.2.1)
|
||||
mail (>= 2.8.0)
|
||||
actionmailer (7.2.2.1)
|
||||
actionpack (= 7.2.2.1)
|
||||
actionview (= 7.2.2.1)
|
||||
activejob (= 7.2.2.1)
|
||||
activesupport (= 7.2.2.1)
|
||||
actionmailer (7.2.1)
|
||||
actionpack (= 7.2.1)
|
||||
actionview (= 7.2.1)
|
||||
activejob (= 7.2.1)
|
||||
activesupport (= 7.2.1)
|
||||
mail (>= 2.8.0)
|
||||
rails-dom-testing (~> 2.2)
|
||||
actionpack (7.2.2.1)
|
||||
actionview (= 7.2.2.1)
|
||||
activesupport (= 7.2.2.1)
|
||||
actionpack (7.2.1)
|
||||
actionview (= 7.2.1)
|
||||
activesupport (= 7.2.1)
|
||||
nokogiri (>= 1.8.5)
|
||||
racc
|
||||
rack (>= 2.2.4, < 3.2)
|
||||
@@ -64,15 +64,15 @@ GEM
|
||||
rails-dom-testing (~> 2.2)
|
||||
rails-html-sanitizer (~> 1.6)
|
||||
useragent (~> 0.16)
|
||||
actiontext (7.2.2.1)
|
||||
actionpack (= 7.2.2.1)
|
||||
activerecord (= 7.2.2.1)
|
||||
activestorage (= 7.2.2.1)
|
||||
activesupport (= 7.2.2.1)
|
||||
actiontext (7.2.1)
|
||||
actionpack (= 7.2.1)
|
||||
activerecord (= 7.2.1)
|
||||
activestorage (= 7.2.1)
|
||||
activesupport (= 7.2.1)
|
||||
globalid (>= 0.6.0)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (7.2.2.1)
|
||||
activesupport (= 7.2.2.1)
|
||||
actionview (7.2.1)
|
||||
activesupport (= 7.2.1)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.11)
|
||||
rails-dom-testing (~> 2.2)
|
||||
@@ -80,31 +80,30 @@ GEM
|
||||
active_link_to (1.0.5)
|
||||
actionpack
|
||||
addressable
|
||||
active_median (0.6.0)
|
||||
activesupport (>= 7.1)
|
||||
active_median (0.4.1)
|
||||
activesupport (>= 6.1)
|
||||
active_record_union (1.3.0)
|
||||
activerecord (>= 4.0)
|
||||
active_utils (3.5.0)
|
||||
active_utils (3.4.1)
|
||||
activesupport (>= 4.2)
|
||||
i18n
|
||||
activejob (7.2.2.1)
|
||||
activesupport (= 7.2.2.1)
|
||||
activejob (7.2.1)
|
||||
activesupport (= 7.2.1)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (7.2.2.1)
|
||||
activesupport (= 7.2.2.1)
|
||||
activerecord (7.2.2.1)
|
||||
activemodel (= 7.2.2.1)
|
||||
activesupport (= 7.2.2.1)
|
||||
activemodel (7.2.1)
|
||||
activesupport (= 7.2.1)
|
||||
activerecord (7.2.1)
|
||||
activemodel (= 7.2.1)
|
||||
activesupport (= 7.2.1)
|
||||
timeout (>= 0.4.0)
|
||||
activestorage (7.2.2.1)
|
||||
actionpack (= 7.2.2.1)
|
||||
activejob (= 7.2.2.1)
|
||||
activerecord (= 7.2.2.1)
|
||||
activesupport (= 7.2.2.1)
|
||||
activestorage (7.2.1)
|
||||
actionpack (= 7.2.1)
|
||||
activejob (= 7.2.1)
|
||||
activerecord (= 7.2.1)
|
||||
activesupport (= 7.2.1)
|
||||
marcel (~> 1.0)
|
||||
activesupport (7.2.2.1)
|
||||
activesupport (7.2.1)
|
||||
base64
|
||||
benchmark (>= 0.3)
|
||||
bigdecimal
|
||||
concurrent-ruby (~> 1.0, >= 1.3.1)
|
||||
connection_pool (>= 2.2.5)
|
||||
@@ -116,20 +115,18 @@ GEM
|
||||
tzinfo (~> 2.0, >= 2.0.5)
|
||||
addressable (2.8.7)
|
||||
public_suffix (>= 2.0.2, < 7.0)
|
||||
ast (2.4.3)
|
||||
ast (2.4.2)
|
||||
autoprefixer-rails (10.4.16.0)
|
||||
execjs (~> 2)
|
||||
axe-core-api (4.10.3)
|
||||
axe-core-api (4.10.0)
|
||||
dumb_delegator
|
||||
ostruct
|
||||
virtus
|
||||
axe-core-capybara (4.10.3)
|
||||
axe-core-api (= 4.10.3)
|
||||
axe-core-capybara (4.10.0)
|
||||
axe-core-api (= 4.10.0)
|
||||
dumb_delegator
|
||||
axe-core-rspec (4.10.3)
|
||||
axe-core-api (= 4.10.3)
|
||||
axe-core-rspec (4.10.0)
|
||||
axe-core-api (= 4.10.0)
|
||||
dumb_delegator
|
||||
ostruct
|
||||
virtus
|
||||
axiom-types (0.1.1)
|
||||
descendants_tracker (~> 0.0.4)
|
||||
@@ -137,12 +134,11 @@ GEM
|
||||
thread_safe (~> 0.3, >= 0.3.1)
|
||||
base64 (0.2.0)
|
||||
bcrypt (3.1.20)
|
||||
benchmark (0.4.0)
|
||||
better_errors (2.10.1)
|
||||
erubi (>= 1.0.0)
|
||||
rack (>= 0.9.0)
|
||||
rouge (>= 1.0.0)
|
||||
bigdecimal (3.1.9)
|
||||
bigdecimal (3.1.8)
|
||||
bluecloth (2.2.0)
|
||||
bonsai-elasticsearch-rails (7.0.1)
|
||||
elasticsearch-model (< 8)
|
||||
@@ -156,10 +152,10 @@ GEM
|
||||
actionpack (>= 6.1)
|
||||
activemodel (>= 6.1)
|
||||
builder (3.3.0)
|
||||
bullet (8.0.7)
|
||||
bullet (7.2.0)
|
||||
activesupport (>= 3.0.0)
|
||||
uniform_notifier (~> 1.11)
|
||||
byebug (12.0.0)
|
||||
byebug (11.1.3)
|
||||
cancancan (3.6.1)
|
||||
capybara (3.40.0)
|
||||
addressable
|
||||
@@ -183,7 +179,7 @@ GEM
|
||||
image_processing (~> 1.1)
|
||||
marcel (~> 1.0.0)
|
||||
ssrf_filter (~> 1.0)
|
||||
chartkick (5.1.5)
|
||||
chartkick (5.1.0)
|
||||
childprocess (5.0.0)
|
||||
codeclimate-test-reporter (1.0.9)
|
||||
simplecov (<= 0.13)
|
||||
@@ -199,21 +195,20 @@ GEM
|
||||
coffee-script-source (1.12.2)
|
||||
comfy_bootstrap_form (4.0.9)
|
||||
rails (>= 5.0.0)
|
||||
concurrent-ruby (1.3.5)
|
||||
connection_pool (2.5.3)
|
||||
concurrent-ruby (1.3.4)
|
||||
connection_pool (2.4.1)
|
||||
crass (1.0.6)
|
||||
csv (3.3.1)
|
||||
csv_shaper (1.4.0)
|
||||
csv (3.3.0)
|
||||
csv_shaper (1.3.2)
|
||||
activesupport (>= 3.0.0)
|
||||
csv
|
||||
dalli (3.2.8)
|
||||
database_cleaner (2.1.0)
|
||||
database_cleaner (2.0.2)
|
||||
database_cleaner-active_record (>= 2, < 3)
|
||||
database_cleaner-active_record (2.2.0)
|
||||
activerecord (>= 5.a)
|
||||
database_cleaner-core (~> 2.0.0)
|
||||
database_cleaner-core (2.0.1)
|
||||
date (3.4.1)
|
||||
date (3.3.4)
|
||||
descendants_tracker (0.0.4)
|
||||
thread_safe (~> 0.3, >= 0.3.1)
|
||||
devise (4.9.4)
|
||||
@@ -222,16 +217,16 @@ GEM
|
||||
railties (>= 4.1.0)
|
||||
responders
|
||||
warden (~> 1.2.3)
|
||||
diff-lcs (1.6.1)
|
||||
discard (1.4.0)
|
||||
activerecord (>= 4.2, < 9.0)
|
||||
diff-lcs (1.5.1)
|
||||
discard (1.3.0)
|
||||
activerecord (>= 4.2, < 8)
|
||||
docile (1.1.5)
|
||||
dotenv (3.1.8)
|
||||
dotenv-rails (3.1.8)
|
||||
dotenv (= 3.1.8)
|
||||
dotenv (3.1.4)
|
||||
dotenv-rails (3.1.4)
|
||||
dotenv (= 3.1.4)
|
||||
railties (>= 6.1)
|
||||
drb (2.2.1)
|
||||
dumb_delegator (1.1.0)
|
||||
dumb_delegator (1.0.0)
|
||||
elasticsearch (7.0.0)
|
||||
elasticsearch-api (= 7.0.0)
|
||||
elasticsearch-transport (= 7.0.0)
|
||||
@@ -245,24 +240,23 @@ GEM
|
||||
elasticsearch-transport (7.0.0)
|
||||
faraday
|
||||
multi_json
|
||||
erubi (1.13.1)
|
||||
erubi (1.13.0)
|
||||
erubis (2.7.0)
|
||||
excon (1.2.5)
|
||||
logger
|
||||
execjs (2.10.0)
|
||||
factory_bot (6.5.0)
|
||||
excon (0.110.0)
|
||||
execjs (2.9.1)
|
||||
factory_bot (6.4.6)
|
||||
activesupport (>= 5.0.0)
|
||||
factory_bot_rails (6.4.4)
|
||||
factory_bot (~> 6.5)
|
||||
factory_bot_rails (6.4.3)
|
||||
factory_bot (~> 6.4)
|
||||
railties (>= 5.0.0)
|
||||
faker (3.5.1)
|
||||
faker (3.4.2)
|
||||
i18n (>= 1.8.11, < 2)
|
||||
faraday (2.13.1)
|
||||
faraday-net_http (>= 2.0, < 3.5)
|
||||
faraday (2.12.0)
|
||||
faraday-net_http (>= 2.0, < 3.4)
|
||||
json
|
||||
logger
|
||||
faraday-net_http (3.4.0)
|
||||
net-http (>= 0.5.0)
|
||||
faraday-net_http (3.3.0)
|
||||
net-http
|
||||
ffi (1.16.3)
|
||||
flickraw (0.9.10)
|
||||
font-awesome-sass (5.15.1)
|
||||
@@ -270,7 +264,7 @@ GEM
|
||||
friendly_id (5.5.1)
|
||||
activerecord (>= 4.0.0)
|
||||
gbifrb (0.2.0)
|
||||
geocoder (1.8.5)
|
||||
geocoder (1.8.3)
|
||||
base64 (>= 0.1.0)
|
||||
csv (>= 3.0.0)
|
||||
gibbon (1.2.1)
|
||||
@@ -296,29 +290,27 @@ GEM
|
||||
activesupport (>= 5.1)
|
||||
haml (>= 4.0.6)
|
||||
railties (>= 5.1)
|
||||
haml_lint (0.62.0)
|
||||
haml_lint (0.58.0)
|
||||
haml (>= 5.0)
|
||||
parallel (~> 1.10)
|
||||
rainbow
|
||||
rubocop (>= 1.0)
|
||||
sysexits (~> 1.1)
|
||||
hashie (5.0.0)
|
||||
heroics (0.1.3)
|
||||
base64
|
||||
heroics (0.1.2)
|
||||
erubis (~> 2.0)
|
||||
excon
|
||||
moneta
|
||||
multi_json (>= 1.9.2)
|
||||
webrick
|
||||
highline (3.1.2)
|
||||
reline
|
||||
highline (3.0.1)
|
||||
httparty (0.22.0)
|
||||
csv
|
||||
mini_mime (>= 1.0.0)
|
||||
multi_xml (>= 0.5.2)
|
||||
i18n (1.14.7)
|
||||
i18n (1.14.6)
|
||||
concurrent-ruby (~> 1.0)
|
||||
i18n-tasks (1.0.15)
|
||||
i18n-tasks (1.0.14)
|
||||
activesupport (>= 4.0.2)
|
||||
ast (>= 2.1.0)
|
||||
erubi
|
||||
@@ -327,30 +319,26 @@ GEM
|
||||
parser (>= 3.2.2.1)
|
||||
rails-i18n
|
||||
rainbow (>= 2.2.2, < 4.0)
|
||||
ruby-progressbar (~> 1.8, >= 1.8.1)
|
||||
terminal-table (>= 1.5.1)
|
||||
icalendar (2.11.0)
|
||||
base64
|
||||
icalendar (2.10.3)
|
||||
ice_cube (~> 0.16)
|
||||
logger
|
||||
ostruct
|
||||
ice_cube (0.17.0)
|
||||
ice_nine (0.11.2)
|
||||
image_processing (1.12.2)
|
||||
mini_magick (>= 4.9.5, < 5)
|
||||
ruby-vips (>= 2.0.17, < 3)
|
||||
io-console (0.8.0)
|
||||
irb (1.15.2)
|
||||
pp (>= 0.6.0)
|
||||
io-console (0.7.2)
|
||||
irb (1.14.0)
|
||||
rdoc (>= 4.0.0)
|
||||
reline (>= 0.4.2)
|
||||
jquery-rails (4.6.0)
|
||||
rails-dom-testing (>= 1, < 3)
|
||||
railties (>= 4.2.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
json (2.12.0)
|
||||
json-schema (5.1.0)
|
||||
addressable (~> 2.8)
|
||||
json (2.7.2)
|
||||
json-schema (4.3.1)
|
||||
addressable (>= 2.8)
|
||||
jsonapi-resources (0.10.7)
|
||||
activerecord (>= 4.1)
|
||||
concurrent-ruby
|
||||
@@ -359,7 +347,7 @@ GEM
|
||||
kgio (2.11.4)
|
||||
kramdown (2.4.0)
|
||||
rexml
|
||||
language_server-protocol (3.17.0.5)
|
||||
language_server-protocol (3.17.0.3)
|
||||
launchy (3.0.1)
|
||||
addressable (~> 2.8)
|
||||
childprocess (~> 5.0)
|
||||
@@ -368,12 +356,11 @@ GEM
|
||||
railties (>= 4.2.0)
|
||||
letter_opener (1.10.0)
|
||||
launchy (>= 2.2, < 4)
|
||||
lint_roller (1.1.0)
|
||||
listen (3.9.0)
|
||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||
rb-inotify (~> 0.9, >= 0.9.10)
|
||||
logger (1.7.0)
|
||||
loofah (2.24.1)
|
||||
logger (1.6.1)
|
||||
loofah (2.22.0)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.12.0)
|
||||
mail (2.8.1)
|
||||
@@ -392,22 +379,22 @@ GEM
|
||||
railties (>= 3.2)
|
||||
matrix (0.4.2)
|
||||
memcachier (0.0.2)
|
||||
method_source (1.1.0)
|
||||
method_source (1.0.0)
|
||||
mimemagic (0.4.3)
|
||||
nokogiri (~> 1)
|
||||
rake
|
||||
mini_magick (4.12.0)
|
||||
mini_mime (1.1.5)
|
||||
mini_portile2 (2.8.9)
|
||||
minitest (5.25.5)
|
||||
mini_portile2 (2.8.7)
|
||||
minitest (5.25.1)
|
||||
moneta (1.0.0)
|
||||
msgpack (1.8.0)
|
||||
msgpack (1.7.2)
|
||||
multi_json (1.15.0)
|
||||
multi_xml (0.7.1)
|
||||
bigdecimal (~> 3.1)
|
||||
net-http (0.6.0)
|
||||
net-http (0.4.1)
|
||||
uri
|
||||
net-imap (0.4.20)
|
||||
net-imap (0.4.14)
|
||||
date
|
||||
net-protocol
|
||||
net-pop (0.1.2)
|
||||
@@ -416,14 +403,14 @@ GEM
|
||||
timeout
|
||||
net-smtp (0.5.0)
|
||||
net-protocol
|
||||
nio4r (2.7.4)
|
||||
nokogiri (1.18.8)
|
||||
nio4r (2.7.3)
|
||||
nokogiri (1.16.7)
|
||||
mini_portile2 (~> 2.8.2)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.18.8-x86_64-linux-gnu)
|
||||
nokogiri (1.16.7-x86_64-linux)
|
||||
racc (~> 1.4)
|
||||
oauth (0.5.6)
|
||||
oj (3.16.10)
|
||||
oj (3.16.6)
|
||||
bigdecimal (>= 3.0)
|
||||
ostruct (>= 0.2)
|
||||
omniauth (1.9.2)
|
||||
@@ -439,35 +426,30 @@ GEM
|
||||
omniauth-oauth (~> 1.1)
|
||||
rack
|
||||
orm_adapter (0.5.0)
|
||||
ostruct (0.6.1)
|
||||
parallel (1.27.0)
|
||||
parser (3.3.8.0)
|
||||
ostruct (0.6.0)
|
||||
parallel (1.26.3)
|
||||
parser (3.3.5.0)
|
||||
ast (~> 2.4.1)
|
||||
racc
|
||||
percy-capybara (5.0.0)
|
||||
capybara (>= 3)
|
||||
pg (1.5.9)
|
||||
platform-api (3.8.0)
|
||||
pg (1.5.8)
|
||||
platform-api (3.7.0)
|
||||
heroics (~> 0.1.1)
|
||||
moneta (~> 1.0.0)
|
||||
rate_throttle_client (~> 0.1.0)
|
||||
popper_js (2.11.8)
|
||||
pp (0.6.2)
|
||||
prettyprint
|
||||
prettyprint (0.2.0)
|
||||
prism (1.4.0)
|
||||
pry (0.15.2)
|
||||
pry (0.14.2)
|
||||
coderay (~> 1.1)
|
||||
method_source (~> 1.0)
|
||||
psych (5.2.6)
|
||||
date
|
||||
psych (5.1.2)
|
||||
stringio
|
||||
public_suffix (6.0.1)
|
||||
puma (6.6.0)
|
||||
puma (6.4.3)
|
||||
nio4r (~> 2.0)
|
||||
query_diet (0.7.2)
|
||||
racc (1.8.1)
|
||||
rack (2.2.15)
|
||||
rack (2.2.9)
|
||||
rack-cors (2.0.2)
|
||||
rack (>= 2.0.0)
|
||||
rack-protection (3.2.0)
|
||||
@@ -475,25 +457,25 @@ GEM
|
||||
rack (~> 2.2, >= 2.2.4)
|
||||
rack-session (1.0.2)
|
||||
rack (< 3)
|
||||
rack-test (2.2.0)
|
||||
rack-test (2.1.0)
|
||||
rack (>= 1.3)
|
||||
rackup (1.0.1)
|
||||
rackup (1.0.0)
|
||||
rack (< 3)
|
||||
webrick
|
||||
rails (7.2.2.1)
|
||||
actioncable (= 7.2.2.1)
|
||||
actionmailbox (= 7.2.2.1)
|
||||
actionmailer (= 7.2.2.1)
|
||||
actionpack (= 7.2.2.1)
|
||||
actiontext (= 7.2.2.1)
|
||||
actionview (= 7.2.2.1)
|
||||
activejob (= 7.2.2.1)
|
||||
activemodel (= 7.2.2.1)
|
||||
activerecord (= 7.2.2.1)
|
||||
activestorage (= 7.2.2.1)
|
||||
activesupport (= 7.2.2.1)
|
||||
rails (7.2.1)
|
||||
actioncable (= 7.2.1)
|
||||
actionmailbox (= 7.2.1)
|
||||
actionmailer (= 7.2.1)
|
||||
actionpack (= 7.2.1)
|
||||
actiontext (= 7.2.1)
|
||||
actionview (= 7.2.1)
|
||||
activejob (= 7.2.1)
|
||||
activemodel (= 7.2.1)
|
||||
activerecord (= 7.2.1)
|
||||
activestorage (= 7.2.1)
|
||||
activesupport (= 7.2.1)
|
||||
bundler (>= 1.15.0)
|
||||
railties (= 7.2.2.1)
|
||||
railties (= 7.2.1)
|
||||
rails-controller-testing (1.0.5)
|
||||
actionpack (>= 5.0.1.rc1)
|
||||
actionview (>= 5.0.1.rc1)
|
||||
@@ -502,10 +484,10 @@ GEM
|
||||
activesupport (>= 5.0.0)
|
||||
minitest
|
||||
nokogiri (>= 1.6)
|
||||
rails-html-sanitizer (1.6.2)
|
||||
rails-html-sanitizer (1.6.0)
|
||||
loofah (~> 2.21)
|
||||
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
||||
rails-i18n (7.0.10)
|
||||
nokogiri (~> 1.14)
|
||||
rails-i18n (7.0.9)
|
||||
i18n (>= 0.7, < 2)
|
||||
railties (>= 6.0.0, < 8)
|
||||
rails_12factor (0.0.3)
|
||||
@@ -513,9 +495,9 @@ GEM
|
||||
rails_stdout_logging
|
||||
rails_serve_static_assets (0.0.5)
|
||||
rails_stdout_logging (0.0.5)
|
||||
railties (7.2.2.1)
|
||||
actionpack (= 7.2.2.1)
|
||||
activesupport (= 7.2.2.1)
|
||||
railties (7.2.1)
|
||||
actionpack (= 7.2.1)
|
||||
activesupport (= 7.2.1)
|
||||
irb (~> 1.13)
|
||||
rackup (>= 1.0.0)
|
||||
rake (>= 12.2)
|
||||
@@ -528,100 +510,91 @@ GEM
|
||||
rb-fsevent (0.11.2)
|
||||
rb-inotify (0.10.1)
|
||||
ffi (~> 1.0)
|
||||
rdoc (6.13.1)
|
||||
rdoc (6.7.0)
|
||||
psych (>= 4.0.0)
|
||||
recaptcha (5.19.0)
|
||||
redis-client (0.23.2)
|
||||
recaptcha (5.17.0)
|
||||
redis-client (0.22.2)
|
||||
connection_pool
|
||||
regexp_parser (2.10.0)
|
||||
reline (0.6.1)
|
||||
regexp_parser (2.9.2)
|
||||
reline (0.5.10)
|
||||
io-console (~> 0.5)
|
||||
responders (3.1.1)
|
||||
actionpack (>= 5.2)
|
||||
railties (>= 5.2)
|
||||
rexml (3.4.1)
|
||||
rexml (3.3.7)
|
||||
rouge (4.1.2)
|
||||
rspec (3.13.0)
|
||||
rspec-core (~> 3.13.0)
|
||||
rspec-expectations (~> 3.13.0)
|
||||
rspec-mocks (~> 3.13.0)
|
||||
rspec-activemodel-mocks (1.2.1)
|
||||
rspec-activemodel-mocks (1.2.0)
|
||||
activemodel (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
rspec-mocks (>= 2.99, < 4.0)
|
||||
rspec-core (3.13.3)
|
||||
rspec-core (3.13.1)
|
||||
rspec-support (~> 3.13.0)
|
||||
rspec-expectations (3.13.4)
|
||||
rspec-expectations (3.13.2)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.13.0)
|
||||
rspec-mocks (3.13.4)
|
||||
rspec-mocks (3.13.1)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.13.0)
|
||||
rspec-rails (8.0.0)
|
||||
actionpack (>= 7.2)
|
||||
activesupport (>= 7.2)
|
||||
railties (>= 7.2)
|
||||
rspec-rails (7.0.1)
|
||||
actionpack (>= 7.0)
|
||||
activesupport (>= 7.0)
|
||||
railties (>= 7.0)
|
||||
rspec-core (~> 3.13)
|
||||
rspec-expectations (~> 3.13)
|
||||
rspec-mocks (~> 3.13)
|
||||
rspec-support (~> 3.13)
|
||||
rspec-support (3.13.3)
|
||||
rspectre (0.2.0)
|
||||
parser (>= 3.3.7.1)
|
||||
prism (~> 1.3)
|
||||
rspec (~> 3.10)
|
||||
rswag-api (2.16.0)
|
||||
activesupport (>= 5.2, < 8.1)
|
||||
railties (>= 5.2, < 8.1)
|
||||
rswag-specs (2.16.0)
|
||||
activesupport (>= 5.2, < 8.1)
|
||||
json-schema (>= 2.2, < 6.0)
|
||||
railties (>= 5.2, < 8.1)
|
||||
rspec-support (3.13.1)
|
||||
rspectre (0.1.0)
|
||||
parser (>= 3.2.2.1)
|
||||
rspec (~> 3.9)
|
||||
rswag-api (2.14.0)
|
||||
activesupport (>= 5.2, < 8.0)
|
||||
railties (>= 5.2, < 8.0)
|
||||
rswag-specs (2.14.0)
|
||||
activesupport (>= 5.2, < 8.0)
|
||||
json-schema (>= 2.2, < 5.0)
|
||||
railties (>= 5.2, < 8.0)
|
||||
rspec-core (>= 2.14)
|
||||
rswag-ui (2.16.0)
|
||||
actionpack (>= 5.2, < 8.1)
|
||||
railties (>= 5.2, < 8.1)
|
||||
rubocop (1.75.5)
|
||||
rswag-ui (2.14.0)
|
||||
actionpack (>= 5.2, < 8.0)
|
||||
railties (>= 5.2, < 8.0)
|
||||
rubocop (1.66.1)
|
||||
json (~> 2.3)
|
||||
language_server-protocol (~> 3.17.0.2)
|
||||
lint_roller (~> 1.1.0)
|
||||
language_server-protocol (>= 3.17.0)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 3.3.0.2)
|
||||
rainbow (>= 2.2.2, < 4.0)
|
||||
regexp_parser (>= 2.9.3, < 3.0)
|
||||
rubocop-ast (>= 1.44.0, < 2.0)
|
||||
regexp_parser (>= 2.4, < 3.0)
|
||||
rubocop-ast (>= 1.32.2, < 2.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 2.4.0, < 4.0)
|
||||
rubocop-ast (1.44.1)
|
||||
parser (>= 3.3.7.2)
|
||||
prism (~> 1.4)
|
||||
rubocop-capybara (2.22.1)
|
||||
lint_roller (~> 1.1)
|
||||
rubocop (~> 1.72, >= 1.72.1)
|
||||
rubocop-factory_bot (2.27.1)
|
||||
lint_roller (~> 1.1)
|
||||
rubocop (~> 1.72, >= 1.72.1)
|
||||
rubocop-rails (2.32.0)
|
||||
unicode-display_width (>= 2.4.0, < 3.0)
|
||||
rubocop-ast (1.32.3)
|
||||
parser (>= 3.3.1.0)
|
||||
rubocop-capybara (2.21.0)
|
||||
rubocop (~> 1.41)
|
||||
rubocop-factory_bot (2.26.1)
|
||||
rubocop (~> 1.61)
|
||||
rubocop-rails (2.26.2)
|
||||
activesupport (>= 4.2.0)
|
||||
lint_roller (~> 1.1)
|
||||
rack (>= 1.1)
|
||||
rubocop (>= 1.75.0, < 2.0)
|
||||
rubocop-ast (>= 1.44.0, < 2.0)
|
||||
rubocop-rake (0.7.1)
|
||||
lint_roller (~> 1.1)
|
||||
rubocop (>= 1.72.1)
|
||||
rubocop-rspec (3.6.0)
|
||||
lint_roller (~> 1.1)
|
||||
rubocop (~> 1.72, >= 1.72.1)
|
||||
rubocop-rspec_rails (2.31.0)
|
||||
lint_roller (~> 1.1)
|
||||
rubocop (~> 1.72, >= 1.72.1)
|
||||
rubocop-rspec (~> 3.5)
|
||||
rubocop (>= 1.52.0, < 2.0)
|
||||
rubocop-ast (>= 1.31.1, < 2.0)
|
||||
rubocop-rake (0.6.0)
|
||||
rubocop (~> 1.0)
|
||||
rubocop-rspec (3.0.5)
|
||||
rubocop (~> 1.61)
|
||||
rubocop-rspec_rails (2.30.0)
|
||||
rubocop (~> 1.61)
|
||||
rubocop-rspec (~> 3, >= 3.0.1)
|
||||
ruby-progressbar (1.13.0)
|
||||
ruby-units (4.1.0)
|
||||
ruby-vips (2.2.1)
|
||||
ffi (~> 1.12)
|
||||
rubyzip (2.4.1)
|
||||
rubyzip (2.3.2)
|
||||
sass (3.7.4)
|
||||
sass-listen (~> 4.0.0)
|
||||
sass-listen (4.0.0)
|
||||
@@ -635,20 +608,20 @@ GEM
|
||||
sprockets (> 3.0)
|
||||
sprockets-rails
|
||||
tilt
|
||||
scout_apm (5.6.4)
|
||||
scout_apm (5.4.0)
|
||||
parser
|
||||
searchkick (5.3.1)
|
||||
activemodel (>= 6.1)
|
||||
hashie
|
||||
securerandom (0.4.1)
|
||||
selenium-webdriver (4.32.0)
|
||||
securerandom (0.3.1)
|
||||
selenium-webdriver (4.25.0)
|
||||
base64 (~> 0.2)
|
||||
logger (~> 1.4)
|
||||
rexml (~> 3.2, >= 3.2.5)
|
||||
rubyzip (>= 1.2.2, < 3.0)
|
||||
websocket (~> 1.0)
|
||||
sidekiq (7.3.9)
|
||||
base64
|
||||
sidekiq (7.3.2)
|
||||
concurrent-ruby (< 2)
|
||||
connection_pool (>= 2.3.0)
|
||||
logger
|
||||
rack (>= 2.2.4)
|
||||
@@ -667,30 +640,28 @@ GEM
|
||||
activesupport (>= 5.2)
|
||||
sprockets (>= 3.0.0)
|
||||
ssrf_filter (1.1.2)
|
||||
stringio (3.1.7)
|
||||
stringio (3.1.1)
|
||||
sysexits (1.2.0)
|
||||
temple (0.10.3)
|
||||
terminal-table (4.0.0)
|
||||
unicode-display_width (>= 1.1.1, < 4)
|
||||
terser (1.2.5)
|
||||
terminal-table (3.0.2)
|
||||
unicode-display_width (>= 1.1.1, < 3)
|
||||
terser (1.2.3)
|
||||
execjs (>= 0.3.0, < 3)
|
||||
thor (1.3.2)
|
||||
thread_safe (0.3.6)
|
||||
tilt (2.6.0)
|
||||
tilt (2.4.0)
|
||||
timecop (0.9.10)
|
||||
timeout (0.4.3)
|
||||
timeout (0.4.1)
|
||||
trollop (1.16.2)
|
||||
tzinfo (2.0.6)
|
||||
concurrent-ruby (~> 1.0)
|
||||
unicode-display_width (3.1.4)
|
||||
unicode-emoji (~> 4.0, >= 4.0.4)
|
||||
unicode-emoji (4.0.4)
|
||||
unicode-display_width (2.6.0)
|
||||
unicorn (6.1.0)
|
||||
kgio (~> 2.6)
|
||||
raindrops (~> 0.7)
|
||||
uniform_notifier (1.17.0)
|
||||
uri (1.0.3)
|
||||
useragent (0.16.11)
|
||||
uniform_notifier (1.16.0)
|
||||
uri (0.13.1)
|
||||
useragent (0.16.10)
|
||||
validate_url (1.0.15)
|
||||
activemodel (>= 3.0.0)
|
||||
public_suffix
|
||||
@@ -706,7 +677,7 @@ GEM
|
||||
nokogiri (>= 1.2.0)
|
||||
rack (>= 1.0)
|
||||
rack-test (>= 0.5.3)
|
||||
webrick (1.9.1)
|
||||
webrick (1.8.2)
|
||||
websocket (1.2.11)
|
||||
websocket-driver (0.7.6)
|
||||
websocket-extensions (>= 0.1.0)
|
||||
@@ -718,7 +689,7 @@ GEM
|
||||
webrick
|
||||
xpath (3.2.0)
|
||||
nokogiri (~> 1.8)
|
||||
zeitwerk (2.7.2)
|
||||
zeitwerk (2.6.18)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
@@ -834,7 +805,7 @@ DEPENDENCIES
|
||||
xmlrpc
|
||||
|
||||
RUBY VERSION
|
||||
ruby 3.3.7p123
|
||||
ruby 3.3.4p94
|
||||
|
||||
BUNDLED WITH
|
||||
2.4.22
|
||||
|
||||
@@ -47,13 +47,4 @@
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
max-height: 2em;
|
||||
-webkit-line-clamp: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin-bottom: 0.5em;
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,16 +24,12 @@ class ActivitiesController < DataController
|
||||
end
|
||||
|
||||
def show
|
||||
# @activity is loaded by load_and_authorize_resource.
|
||||
# We need to ensure comments are eager-loaded.
|
||||
@activity = Activity.includes(comments: :author).find(params[:id])
|
||||
respond_with @activity
|
||||
end
|
||||
|
||||
def new
|
||||
@activity = Activity.new(
|
||||
owner: current_member,
|
||||
due_date: Date.today
|
||||
owner: current_member
|
||||
)
|
||||
if params[:garden_id]
|
||||
@activity.garden = Garden.find_by(
|
||||
|
||||
@@ -13,66 +13,43 @@ class CommentsController < ApplicationController
|
||||
end
|
||||
|
||||
def new
|
||||
@commentable = find_commentable
|
||||
if @commentable
|
||||
@comment = @commentable.comments.new
|
||||
@comments = @commentable.comments.post_order # Assuming post_order is generic enough or will be adapted
|
||||
respond_with(@comment) # Changed from @comments to @comment, or @commentable
|
||||
@comment = Comment.new
|
||||
@post = Post.find_by(id: params[:post_id])
|
||||
|
||||
if @post
|
||||
@comments = @post.comments
|
||||
respond_with(@comments)
|
||||
else
|
||||
redirect_to(request.referer || root_url,
|
||||
alert: "Cannot add a comment to a non-existent or unspecified item.")
|
||||
alert: "Can't post a comment on a non-existent post")
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
# @comment is loaded by load_and_authorize_resource
|
||||
@comments = @comment.commentable.comments.post_order # Assuming post_order is generic
|
||||
@comments = @comment.post.comments
|
||||
end
|
||||
|
||||
def create
|
||||
@commentable = find_commentable
|
||||
if @commentable
|
||||
@comment = @commentable.comments.new(comment_params)
|
||||
@comment.author = current_member
|
||||
@comment.save
|
||||
respond_with @comment, location: @comment.commentable # Redirect to the commentable parent
|
||||
else
|
||||
redirect_to(request.referer || root_url,
|
||||
alert: "Cannot create comment for a non-existent or unspecified item.")
|
||||
end
|
||||
@comment = Comment.new(comment_params)
|
||||
@comment.author = current_member
|
||||
@comment.save
|
||||
respond_with @comment, location: @comment.post
|
||||
end
|
||||
|
||||
def update
|
||||
# @comment is loaded by load_and_authorize_resource
|
||||
@comment.update(comment_params) # body is permitted by comment_params
|
||||
respond_with @comment, location: @comment.commentable # Redirect to the commentable parent
|
||||
@comment.update(body: comment_params['body'])
|
||||
respond_with @comment, location: @comment.post
|
||||
end
|
||||
|
||||
def destroy
|
||||
# @comment is loaded by load_and_authorize_resource
|
||||
@commentable = @comment.commentable # Store before destroying
|
||||
@post = @comment.post
|
||||
@comment.destroy
|
||||
respond_with @comment, location: @commentable # Redirect to the commentable parent
|
||||
respond_with(@post)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_commentable
|
||||
params.each do |name, value|
|
||||
if name =~ /(.+)_id$/
|
||||
model_name = $1.classify
|
||||
# Ensure model_name is one of the expected commentable types
|
||||
# to prevent arbitrary model lookups.
|
||||
allowed_commentables = %w[Post Photo Planting Harvest Activity]
|
||||
if allowed_commentables.include?(model_name)
|
||||
return model_name.constantize.find_by(id: value)
|
||||
end
|
||||
end
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
def comment_params
|
||||
params.require(:comment).permit(:body) # Removed post_id
|
||||
params.require(:comment).permit(:body, :post_id)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -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
|
||||
@@ -8,10 +8,7 @@ class GardensController < DataController
|
||||
|
||||
@gardens = @gardens.includes(:owner)
|
||||
@gardens = @gardens.active unless @show_all
|
||||
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(owner: @owner) if @owner.present?
|
||||
@gardens = @gardens.where.not(members: { confirmed_at: nil })
|
||||
.order(:name).paginate(page: params[:page])
|
||||
respond_with(@gardens)
|
||||
|
||||
@@ -32,9 +32,6 @@ class HarvestsController < DataController
|
||||
end
|
||||
|
||||
def show
|
||||
# @harvest is loaded by load_and_authorize_resource.
|
||||
# We need to ensure comments are eager-loaded.
|
||||
@harvest = Harvest.includes(comments: :author).find(params[:id])
|
||||
@matching_plantings = matching_plantings if @harvest.owner == current_member
|
||||
@photos = @harvest.photos.order(created_at: :desc).paginate(page: params[:page])
|
||||
respond_with(@harvest)
|
||||
|
||||
@@ -20,9 +20,6 @@ class PhotosController < ApplicationController
|
||||
end
|
||||
|
||||
def show
|
||||
# @photo is loaded by load_and_authorize_resource.
|
||||
# We need to ensure comments are eager-loaded.
|
||||
@photo = Photo.includes(comments: :author).find(params[:id])
|
||||
@crops = Crop.distinct.joins(:photo_associations).where(photo_associations: { photo: @photo })
|
||||
respond_with(@photo)
|
||||
end
|
||||
|
||||
@@ -34,9 +34,6 @@ class PlantingsController < DataController
|
||||
end
|
||||
|
||||
def show
|
||||
# @planting is loaded by load_and_authorize_resource.
|
||||
# We need to ensure comments are eager-loaded.
|
||||
@planting = Planting.includes(comments: :author).find(params[:id])
|
||||
@photos = @planting.photos.includes(:owner).order(date_taken: :desc)
|
||||
@harvests = Harvest.search(where: { planting_id: @planting.id })
|
||||
@current_activities = @planting.activities.current.includes(:owner).order(created_at: :desc)
|
||||
|
||||
@@ -28,6 +28,12 @@ module ApplicationHelper
|
||||
"#{klass.name.downcase.pluralize}/#{identifier}-#{count}-#{max_updated_at}"
|
||||
end
|
||||
|
||||
def required_field_help_text
|
||||
asterisk = tag.span('*', class: ['red'])
|
||||
text = tag.em('denotes a required field')
|
||||
tag.div(asterisk + ' '.html_safe + text, class: ['margin-bottom'])
|
||||
end
|
||||
|
||||
# A helper to replace the complex template compilation mess
|
||||
# of HAML, Tilt, and dynamic compilation with interpolated ruby.
|
||||
def markdownify(text)
|
||||
|
||||
@@ -13,7 +13,7 @@ module AutoSuggestHelper
|
||||
resource = resource.class.name.downcase
|
||||
source_path = Rails.application.routes.url_helpers.send("search_#{source}s_path", format: :json)
|
||||
%(
|
||||
<input id="#{source}" class="auto-suggest #{options[:class]}" #{options[:required] ? 'required="required"' : ''}
|
||||
<input id="#{source}" class="auto-suggest #{options[:class]}"
|
||||
type="text" value="#{default}" data-source-url="#{source_path}",
|
||||
placeholder="e.g. lettuce">
|
||||
<noscript class="text-warning">
|
||||
|
||||
@@ -98,19 +98,7 @@ class Ability
|
||||
can :destroy, Like, member_id: member.id
|
||||
can :create, Comment
|
||||
can :update, Comment, author_id: member.id
|
||||
can :destroy, Comment do |comment|
|
||||
is_author = comment.author_id == member.id
|
||||
is_commentable_owner = false
|
||||
if comment.commentable.present?
|
||||
if comment.commentable.respond_to?(:owner_id) && comment.commentable.owner_id == member.id
|
||||
is_commentable_owner = true
|
||||
# Posts use author_id for their "owner"
|
||||
elsif comment.commentable.respond_to?(:author_id) && comment.commentable.author_id == member.id
|
||||
is_commentable_owner = true
|
||||
end
|
||||
end
|
||||
is_author || is_commentable_owner
|
||||
end
|
||||
can :destroy, Comment, author_id: member.id
|
||||
|
||||
# same deal for gardens and plantings
|
||||
can :create, Garden
|
||||
@@ -120,38 +108,16 @@ class Ability
|
||||
can :create, Planting
|
||||
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 :update, 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 :update, 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 :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 :update, Photo, owner_id: member.id
|
||||
|
||||
@@ -2,31 +2,26 @@
|
||||
|
||||
class Comment < ApplicationRecord
|
||||
belongs_to :author, class_name: 'Member', inverse_of: :comments
|
||||
belongs_to :commentable, polymorphic: true, counter_cache: true
|
||||
belongs_to :post, counter_cache: true
|
||||
|
||||
scope :post_order, -> { order(created_at: :asc) } # for display on post page
|
||||
|
||||
after_create do
|
||||
recipient = if commentable.respond_to?(:author)
|
||||
commentable.author.id
|
||||
elsif commentable.respond_to?(:owner)
|
||||
commentable.owner.id
|
||||
end
|
||||
recipient = post.author.id
|
||||
sender = author.id
|
||||
# don't send notifications to yourself
|
||||
if recipient && recipient != sender
|
||||
if recipient != sender
|
||||
Notification.create(
|
||||
recipient_id: recipient,
|
||||
sender_id: sender,
|
||||
subject: "#{author} commented on your #{commentable.class.name.downcase}",
|
||||
subject: "#{author} commented on #{post.subject}",
|
||||
body:,
|
||||
commentable_id: commentable.id,
|
||||
commentable_type: commentable.class.name
|
||||
post_id: post.id
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def to_s
|
||||
"#{author.login_name} commented on #{commentable.class.name.downcase} ##{commentable.id}"
|
||||
"#{author.login_name} commented on #{post.subject}"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -30,7 +30,6 @@ module SearchPlantings
|
||||
quantity:,
|
||||
sunniness:,
|
||||
garden_id:,
|
||||
garden_slug: garden&.garden_slug,
|
||||
garden_name: garden&.name,
|
||||
description:,
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ class Garden < ApplicationRecord
|
||||
has_many :plantings, dependent: :destroy
|
||||
has_many :crops, through: :plantings
|
||||
has_many :activities, dependent: :destroy
|
||||
has_many :garden_collaborators, dependent: :destroy
|
||||
|
||||
belongs_to :garden_type, optional: true
|
||||
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class GardenCollaborator < ApplicationRecord
|
||||
belongs_to :member
|
||||
belongs_to :garden
|
||||
|
||||
validates :member_id, uniqueness: { scope: :garden }
|
||||
validate :not_garden_owner
|
||||
|
||||
def not_garden_owner
|
||||
return unless member
|
||||
return unless garden
|
||||
|
||||
errors.add(:member_id, "cannot be the garden owner") if garden.owner == member
|
||||
end
|
||||
|
||||
def member_slug
|
||||
@member&.slug
|
||||
end
|
||||
|
||||
def member_slug=(_slug)
|
||||
member_slug
|
||||
end
|
||||
end
|
||||
@@ -153,10 +153,7 @@ class Harvest < ApplicationRecord
|
||||
def owner_must_match_planting
|
||||
return if planting.blank? # only check if we are linked to a planting
|
||||
|
||||
return if owner == planting.owner || planting.garden.garden_collaborators.where(member_id: owner).any?
|
||||
|
||||
errors.add(:owner,
|
||||
"of harvest must be the same as planting, or a collaborator on that garden")
|
||||
errors.add(:owner, "of harvest must be the same as planting") unless owner == planting.owner
|
||||
end
|
||||
|
||||
def harvest_must_be_after_planting
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
class Notification < ApplicationRecord
|
||||
belongs_to :sender, class_name: 'Member', inverse_of: :sent_notifications
|
||||
belongs_to :recipient, class_name: 'Member', inverse_of: :notifications
|
||||
belongs_to :commentable, polymorphic: true, optional: true
|
||||
belongs_to :post, optional: true
|
||||
|
||||
validates :subject, length: { maximum: 255 }
|
||||
|
||||
|
||||
@@ -61,7 +61,6 @@ class Planting < ApplicationRecord
|
||||
to: :crop, prefix: true
|
||||
delegate :login_name, :slug, :location, to: :owner, prefix: true
|
||||
delegate :slug, to: :planting, prefix: true
|
||||
delegate :slug, :name, to: :garden, prefix: true
|
||||
|
||||
delegate :annual?, :perennial?, :svg_icon, to: :crop
|
||||
delegate :location, :longitude, :latitude, to: :garden
|
||||
@@ -128,9 +127,6 @@ class Planting < ApplicationRecord
|
||||
end
|
||||
|
||||
def owner_must_match_garden_owner
|
||||
return if owner == garden.owner || garden.garden_collaborators.where(member_id: owner).any?
|
||||
|
||||
errors.add(:owner,
|
||||
"must be the same as garden, or a collaborator on that garden")
|
||||
errors.add(:owner, "must be the same as garden") unless owner == garden.owner
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
%strong=yield :title
|
||||
= bootstrap_form_for(@activity) do |f|
|
||||
.card-body
|
||||
= required_field_help_text
|
||||
- if @activity.errors.any?
|
||||
#error_explanation
|
||||
%h2
|
||||
@@ -39,9 +40,9 @@
|
||||
= link_to "Add a planting.", new_planting_path
|
||||
|
||||
.col-md-4
|
||||
= f.date_field :due_date,
|
||||
= f.text_field :due_date,
|
||||
value: @activity.due_date ? @activity.due_date.to_fs(:ymd) : '',
|
||||
label: 'When?'
|
||||
class: 'add-datepicker', label: 'When?'
|
||||
|
||||
%hr
|
||||
|
||||
|
||||
@@ -44,8 +44,5 @@
|
||||
%a{name: 'plantings'}
|
||||
= render 'plantings/card', planting: @activity.planting
|
||||
|
||||
%section.comments.mt-4
|
||||
= render 'comments/comments', commentable: @activity
|
||||
|
||||
|
||||
.col-md-4.col-xs-12
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
.comments-section.mt-4
|
||||
%h4.mb-3 Comments
|
||||
- if commentable.comments.any?
|
||||
.list-group
|
||||
- commentable.comments.post_order.each do |comment|
|
||||
.list-group-item.p-0.mb-2.border-0
|
||||
= render 'comments/comment', comment: comment
|
||||
- else
|
||||
%p No comments yet.
|
||||
|
||||
- if can? :create, Comment # Assuming a general ability to create comments
|
||||
.mt-3
|
||||
= link_to "Add Comment", new_polymorphic_path([commentable, Comment.new]), class: 'btn btn-primary'
|
||||
|
||||
%hr/
|
||||
-# This section is for rendering the new/edit form directly on the page if needed,
|
||||
-# but the primary "Add Comment" link above goes to the comments/new page.
|
||||
-# If @new_comment is passed, it means we want to show the form.
|
||||
- if defined?(@new_comment) && @new_comment && can?(:create, Comment) # Check @new_comment specifically
|
||||
%h5.mt-3 Leave a comment
|
||||
= render 'comments/form', commentable: commentable, comment: @new_comment
|
||||
@@ -3,14 +3,14 @@
|
||||
- if content_for? :title
|
||||
%h1.h2-responsive.text-center
|
||||
%strong=yield :title
|
||||
= form_for(commentable ? [commentable, comment] : comment, html: { class: "form-horizontal" }) do |f|
|
||||
- if comment.errors.any?
|
||||
= form_for(@comment, html: { class: "form-horizontal" }) do |f|
|
||||
- if @comment.errors.any?
|
||||
#error_explanation
|
||||
%h2
|
||||
= pluralize(comment.errors.size, "error")
|
||||
= pluralize(@comment.errors.size, "error")
|
||||
prohibited this comment from being saved:
|
||||
%ul
|
||||
- comment.errors.full_messages.each do |msg|
|
||||
- @comment.errors.full_messages.each do |msg|
|
||||
%li= msg
|
||||
|
||||
.md-form
|
||||
@@ -21,3 +21,6 @@
|
||||
= render partial: "shared/markdown_help"
|
||||
.actions.text-right
|
||||
= f.submit 'Post comment', class: 'btn btn-primary'
|
||||
- if defined?(@post)
|
||||
.field
|
||||
= f.hidden_field :post_id, value: @post.id
|
||||
|
||||
@@ -1,2 +1,7 @@
|
||||
%h2 Edit Comment
|
||||
= render 'comments/form', commentable: @comment.commentable, comment: @comment
|
||||
= content_for :title, "Editing comment"
|
||||
|
||||
%p
|
||||
Editing comment on
|
||||
= link_to @comment.post.subject, @comment.post
|
||||
|
||||
= render 'form'
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
%h2
|
||||
Add comment to
|
||||
= @commentable.class.name.downcase
|
||||
= content_for :title, "New comment"
|
||||
|
||||
= render 'comments/form', commentable: @commentable, comment: @comment
|
||||
%section.blog-post
|
||||
.card.post{ id: "post-#{@post.id}" }
|
||||
.card-header
|
||||
%h2.display-3= @post.subject
|
||||
.card-body= render "posts/single", post: @post || @comment.post, subject: true
|
||||
|
||||
= render partial: "posts/comments", locals: { post: @post || @comment.post }
|
||||
|
||||
= render 'form'
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
.card.col-md-8.col-lg-7.mx-auto.float-none.white.z-depth-1.py-2.px-2
|
||||
= bootstrap_form_for(@garden_collaborator.new_record? ? [@garden, @garden_collaborator] : garden_garden_collaborator_path(@garden, @garden_collaborator)) do |f|
|
||||
.card-body
|
||||
- if @garden_collaborator.errors.any?
|
||||
#error_explanation.alert.alert-warning{:role => "alert"}
|
||||
%h4.alert-heading
|
||||
= pluralize(@garden_collaborator.errors.size, "error")
|
||||
prohibited this garden collaborator from being saved
|
||||
%ul
|
||||
- @garden_collaborator.errors.full_messages.each do |msg|
|
||||
%li= msg
|
||||
|
||||
.alert.alert-info
|
||||
Ask your friend, family member or community garden member for their growstuff username to add them as a collaborator on your garden.
|
||||
= f.text_field :member_slug, maxlength: 255, required: true
|
||||
.row
|
||||
.card-footer
|
||||
.text-right= f.submit 'Save Collaboator'
|
||||
@@ -1,3 +0,0 @@
|
||||
- content_for :title, "Edit garden collaborator"
|
||||
|
||||
= render 'form'
|
||||
@@ -1,72 +0,0 @@
|
||||
- content_for :title, "#{@garden} collaborators"
|
||||
|
||||
%h1= "#{@garden} collaborators"
|
||||
|
||||
- content_for :breadcrumbs do
|
||||
%li.breadcrumb-item= link_to 'Gardens', gardens_path
|
||||
%li.breadcrumb-item.active= link_to @garden, gardens_path(@garden)
|
||||
|
||||
.row
|
||||
.col-md-2
|
||||
- if current_member.present?
|
||||
.flex-column.nav-pills.layout-nav{"role" => "tablist", "aria-orientation"=>"vertical"}
|
||||
- if can?(:create, GardenCollaborator.new(garden: @garden))
|
||||
= link_to url_for([@garden, GardenCollaborator.new(garden: @garden), action: :new]), class: 'btn' do
|
||||
Add a #{GardenCollaborator.new(garden: @garden).model_name.human}
|
||||
- else
|
||||
= render 'shared/signin_signup', to: "record your #{model.to_s.pluralize.downcase}"
|
||||
|
||||
%hr/
|
||||
%p.text-center
|
||||
#{ENV['GROWSTUFF_SITE_NAME']} helps you track what you're
|
||||
harvesting from your home garden and see how productive it is.
|
||||
|
||||
|
||||
.col-md-10
|
||||
- if @garden_collaborators.empty?
|
||||
%p There are no collaborators to display.
|
||||
- if can?(:create, GardenCollaborator) && @owner == current_member
|
||||
= link_to 'Add a garden collaborator', new_garden_garden_collaborator_path, class: 'btn btn-primary'
|
||||
|
||||
- else
|
||||
%section
|
||||
%h2= page_entries_info @garden_collaborators
|
||||
= will_paginate @garden_collaborators
|
||||
|
||||
- @garden_collaborators.each do |garden_collaborator|
|
||||
- member = garden_collaborator.member
|
||||
- cache member do
|
||||
.card
|
||||
.card-body
|
||||
- if can?(:destroy, garden_collaborator)
|
||||
%div{"style": "float: right"}
|
||||
= link_to garden_garden_collaborator_path(@garden, garden_collaborator), method: :delete, class: "btn btn-danger" do
|
||||
Remove access
|
||||
|
||||
%h4.login-name= link_to member, member
|
||||
%div
|
||||
= render "members/avatar", member: member
|
||||
%div
|
||||
= link_to "view all #{member}'s gardens", member_gardens_path(member)
|
||||
%p
|
||||
%small
|
||||
Joined
|
||||
= distance_of_time_in_words(member.created_at, Time.zone.now)
|
||||
ago.
|
||||
- if member.location.present?
|
||||
= link_to member.location, place_path(member.location)
|
||||
.card-footer
|
||||
%ul.nav.nav-justified.small
|
||||
%li.nav-item.border-right
|
||||
= link_to member_plantings_path(member) do
|
||||
= localize_plural(member.plantings.active, Planting)
|
||||
%li.nav-item.border-right
|
||||
= link_to member_harvests_path(member) do
|
||||
= localize_plural(member.harvests, Harvest)
|
||||
%li.nav-item
|
||||
= link_to member_seeds_path(member) do
|
||||
= localize_plural(member.seeds.active, Seed)
|
||||
|
||||
.row
|
||||
.col-12= page_entries_info @garden_collaborators
|
||||
.col-12= will_paginate @garden_collaborators
|
||||
@@ -1,3 +0,0 @@
|
||||
- content_for :title, "New garden collaborator"
|
||||
|
||||
= render 'form'
|
||||
@@ -5,6 +5,7 @@
|
||||
%h1.h2-responsive.text-center
|
||||
%strong=yield :title
|
||||
.card-body
|
||||
= required_field_help_text
|
||||
- if @garden.errors.any?
|
||||
#error_explanation.alert.alert-warning{:role => "alert"}
|
||||
%h4.alert-heading
|
||||
@@ -15,7 +16,7 @@
|
||||
%li= msg
|
||||
|
||||
= f.text_field :name, maxlength: 255, required: true
|
||||
= f.text_area :description, rows: 6, placeholder: "Tell us about this garden - where is it located? What does it look like? Do you have a link to a photo? Do you have irrigation? What are your plans?"
|
||||
= f.text_area :description, rows: 6
|
||||
= f.text_field :location,
|
||||
value: @garden.location || current_member.location,
|
||||
class: 'form-control', maxlength: 255
|
||||
@@ -26,7 +27,7 @@
|
||||
- else
|
||||
= link_to "Change your location.", edit_member_registration_path
|
||||
.row
|
||||
.col-md-5.col-12= f.number_field :area, class: 'input-small', step: "any", min: 0
|
||||
.col-md-5.col-12= f.number_field :area, class: 'input-small', step: "any"
|
||||
.col-md-7.col-12= f.select(:area_unit, Garden::AREA_UNITS_VALUES, { include_blank: false })
|
||||
.col-12= f.select(:garden_type_id, GardenType.all.order(:name).pluck(:name, :id),
|
||||
selected: @garden.garden_type_id, include_blank: true)
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
%p
|
||||
:markdown
|
||||
#{strip_tags markdownify(@garden.description)}
|
||||
- unless @garden.description.present?
|
||||
- unless @garden.description
|
||||
.row-fluid
|
||||
%p No description available yet.
|
||||
|
||||
@@ -39,13 +39,8 @@
|
||||
%p
|
||||
Why not
|
||||
= link_to 'tell us more.', edit_garden_path(@garden)
|
||||
- else
|
||||
- if can? :edit, @garden
|
||||
%p
|
||||
Did you want to
|
||||
= link_to 'update this description.', edit_garden_path(@garden)
|
||||
|
||||
- if @garden.plantings.active.any?
|
||||
- if @garden.plantings.where.not(planted_at: nil).any?
|
||||
%section.card
|
||||
%h2 Garden progress
|
||||
.card-body
|
||||
@@ -60,14 +55,6 @@
|
||||
- else
|
||||
.col-md-12
|
||||
%p Nothing is currently planted here.
|
||||
- if can?(:edit, @garden)
|
||||
.col-md-12
|
||||
= garden_plant_something_button(@garden)
|
||||
|
||||
- if can?(:destroy, @garden)
|
||||
.dropdown-divider
|
||||
= delete_button(@garden, classes: 'dropdown-item text-danger',
|
||||
message: 'All plantings associated with this garden will also be deleted. Are you sure?')
|
||||
|
||||
%section
|
||||
%h2 Current activities in garden
|
||||
@@ -78,9 +65,6 @@
|
||||
- else
|
||||
.col-md-12
|
||||
%p Nothing is currently planned here.
|
||||
- if can?(:edit, @garden)
|
||||
.col-md-12
|
||||
= garden_plan_something_button(@garden)
|
||||
|
||||
- if @suggested_companions.any?
|
||||
%section.companions
|
||||
@@ -99,17 +83,6 @@
|
||||
%p
|
||||
%strong Owner:
|
||||
= link_to @garden.owner, @garden.owner
|
||||
%p
|
||||
%strong Collaborators:
|
||||
- if can?(:create, GardenCollaborator.new(garden: @garden))
|
||||
= link_to "Manage", garden_garden_collaborators_path(@garden)
|
||||
- if @garden.garden_collaborators.any?
|
||||
%ul
|
||||
- @garden.garden_collaborators.each do |collabator|
|
||||
%li= link_to collabator.member, collabator.member
|
||||
- else
|
||||
None
|
||||
|
||||
- if @garden.location.present?
|
||||
%p
|
||||
%strong Location:
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
= harvest_icon
|
||||
%strong=yield :title
|
||||
.card-body
|
||||
= required_field_help_text
|
||||
- if @harvest.errors.any?
|
||||
#error_explanation
|
||||
%h2 #{pluralize(@harvest.errors.size, "error")} prohibited this harvest from being saved:"
|
||||
@@ -30,7 +31,8 @@
|
||||
= link_to "Request new crops.", new_crop_path
|
||||
|
||||
.col-md-4
|
||||
= f.date_field :harvested_at, value: @harvest.harvested_at ? @harvest.harvested_at.to_fs(:ymd) : '', label: 'When?'
|
||||
= f.text_field :harvested_at, value: @harvest.harvested_at ? @harvest.harvested_at.to_fs(:ymd) : '',
|
||||
class: 'add-datepicker', label: 'When?'
|
||||
.col-12
|
||||
= f.form_group :plant_part_id, label: { text: "Harvested Plant Part" } do
|
||||
.row
|
||||
@@ -42,7 +44,7 @@
|
||||
-# http://blog.isotoma.com/2012/03/html5-input-typenumber-and-decimalsfloats-in-chrome/
|
||||
.row
|
||||
.col-md-4
|
||||
= f.number_field :quantity, class: 'input-small form-control', step: 'any', label: 'How many?', min: 1
|
||||
= f.number_field :quantity, class: 'input-small form-control', step: 'any', label: 'How many?'
|
||||
.col-md-8
|
||||
= f.select(:unit, Harvest::UNITS_VALUES, { include_blank: false }, class: 'input-medium form-control')
|
||||
.row
|
||||
|
||||
@@ -66,8 +66,5 @@
|
||||
Havested from
|
||||
= link_to @harvest.planting, @harvest.planting
|
||||
|
||||
%section.comments.mt-4
|
||||
= render 'comments/comments', commentable: @harvest
|
||||
|
||||
.col-md-4.col-xs-12
|
||||
= render @harvest.crop
|
||||
|
||||
@@ -46,8 +46,4 @@
|
||||
- else
|
||||
= @photo.license_name
|
||||
|
||||
= render "associations", photo: @photo
|
||||
|
||||
.row
|
||||
.col-md-9
|
||||
= render 'comments/comments', commentable: @photo
|
||||
= render "associations", photo: @photo
|
||||
@@ -31,10 +31,7 @@
|
||||
.text-center= render 'plantings/badges', planting: planting
|
||||
= render 'plantings/progress', planting: planting
|
||||
.card-footer
|
||||
%small
|
||||
Planted by
|
||||
= link_to member_path(slug: planting.owner_slug), class: "owner-link" do
|
||||
= planting.owner_login_name
|
||||
in
|
||||
= link_to garden_path(slug: planting.garden_slug), class: "garden-link" do
|
||||
= planting.garden_name
|
||||
.float-right
|
||||
%span.chip.member-chip
|
||||
= link_to member_path(slug: planting.owner_slug) do
|
||||
= planting.owner_login_name
|
||||
@@ -6,6 +6,7 @@
|
||||
%strong=yield :title
|
||||
= bootstrap_form_for(@planting) do |f|
|
||||
.card-body
|
||||
= required_field_help_text
|
||||
- if @planting.errors.any?
|
||||
#error_explanation
|
||||
%h2
|
||||
@@ -44,7 +45,7 @@
|
||||
.col-md-4
|
||||
= f.select(:sunniness, Planting::SUNNINESS_VALUES, { include_blank: '', label: 'Sun or shade?' } )
|
||||
.col-md-4
|
||||
= f.number_field :quantity, label: 'How many?', min: 1
|
||||
= f.number_field :quantity, label: 'How many?'
|
||||
= f.text_area :description, rows: 6, label: 'Tell us more about it'
|
||||
|
||||
.row
|
||||
|
||||
@@ -79,9 +79,6 @@
|
||||
.col-md-12
|
||||
%p Nothing is currently planned here.
|
||||
|
||||
%section.comments.mt-4
|
||||
= render 'comments/comments', commentable: @planting
|
||||
|
||||
|
||||
.col-md-4.col-xs-12
|
||||
= render @planting.crop
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
= render "shared/signin_signup",
|
||||
to: "or to start using #{ENV['GROWSTUFF_SITE_NAME']} to track what you're planting and harvesting"
|
||||
|
||||
- content_for :buttonbar do
|
||||
- if @post.comments.count > 10 && can?(:create, Comment)
|
||||
= link_to 'Comment', new_comment_path(post_id: @post.id), class: 'btn'
|
||||
|
||||
- content_for :breadcrumbs do
|
||||
%li.breadcrumb-item= link_to @post.author, @post.author
|
||||
%li.breadcrumb-item= link_to 'posts', member_posts_path(member_slug: @post.author.slug)
|
||||
@@ -43,10 +47,13 @@
|
||||
.card-footer
|
||||
= render 'likes/likes', object: @post
|
||||
.float-right
|
||||
-# Link removed as it's now part of the _comments partial
|
||||
- if can? :create, Comment
|
||||
= link_to new_comment_path(post_id: @post.id), class: 'btn' do
|
||||
= icon 'fas', 'comment'
|
||||
Comment
|
||||
|
||||
%section.comments
|
||||
= render 'comments/comments', commentable: @post
|
||||
= render "comments", post: @post
|
||||
|
||||
.col-md-4.col-12
|
||||
= render @post.author
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
%ul
|
||||
- @seed.errors.full_messages.each do |msg|
|
||||
%li= msg
|
||||
= required_field_help_text
|
||||
|
||||
.form-group.required
|
||||
= f.label :crop, 'Crop'
|
||||
@@ -22,7 +23,7 @@
|
||||
= f.hidden_field :parent_planting_id, value: @planting.id
|
||||
- else
|
||||
|
||||
= auto_suggest @seed, :crop, class: 'form-control', default: @crop, required: true
|
||||
= auto_suggest @seed, :crop, class: 'form-control', default: @crop
|
||||
%span.help-inline
|
||||
Can't find what you're looking for?
|
||||
= link_to "Request new crops.", new_crop_path
|
||||
@@ -31,7 +32,7 @@
|
||||
= f.text_field :saved_at,
|
||||
value: @seed.saved_at ? @seed.saved_at.to_fs(:ymd) : '',
|
||||
class: 'add-datepicker', label: 'When were the seeds harvested/saved?'
|
||||
.col-12.col-md-4= f.number_field :quantity, label: 'Quantity', min: 1
|
||||
.col-12.col-md-4= f.number_field :quantity, label: 'Quantity'
|
||||
.col-12.col-md-4
|
||||
= f.text_field :plant_before, class: 'add-datepicker',
|
||||
value: @seed.plant_before ? @seed.plant_before.to_fs(:ymd) : ''
|
||||
@@ -45,21 +46,21 @@
|
||||
%span.help-inline= t('.finish_helper')
|
||||
|
||||
.row
|
||||
.col-md-6= f.number_field :days_until_maturity_min, label_as_placeholder: true, label: 'min', prepend: 'Days until maturity', min: 1
|
||||
.col-md-6= f.number_field :days_until_maturity_max, label_as_placeholder: true, label: 'max', prepend: 'to', append: "days", min: 1
|
||||
.col-md-6= f.number_field :days_until_maturity_min, label_as_placeholder: true, label: 'min', prepend: 'Days until maturity'
|
||||
.col-md-6= f.number_field :days_until_maturity_max, label_as_placeholder: true, label: 'max', prepend: 'to', append: "days"
|
||||
|
||||
.row
|
||||
.col-md-4
|
||||
= f.select(:organic, Seed::ORGANIC_VALUES, {label: 'Organic?', wrapper: { class: 'required'}, required: true}, default: 'unknown')
|
||||
= f.select(:organic, Seed::ORGANIC_VALUES, {label: 'Organic?', wrapper: { class: 'required'}}, default: 'unknown', required: true)
|
||||
.col-md-4
|
||||
= f.select(:gmo, Seed::GMO_VALUES, {label: 'GMO?', wrapper: { class: 'required'}, required: true}, default: 'unknown')
|
||||
= f.select(:gmo, Seed::GMO_VALUES, {label: 'GMO?', wrapper: { class: 'required'}}, default: 'unknown', required: true)
|
||||
.col-md-4
|
||||
= f.select(:heirloom, Seed::HEIRLOOM_VALUES, {label: 'Heirloom?', wrapper: { class: 'required'}, required: true}, default: 'unknown')
|
||||
= f.select(:heirloom, Seed::HEIRLOOM_VALUES, {label: 'Heirloom?', wrapper: { class: 'required'}}, default: 'unknown', required: true)
|
||||
= f.text_area :description, rows: 6
|
||||
|
||||
%hr/
|
||||
= t('.trade_help', site_name: ENV['GROWSTUFF_SITE_NAME'])
|
||||
= f.select(:tradable_to, Seed::TRADABLE_TO_VALUES, {label: 'Will trade', wrapper: { class: 'required'}, required: true})
|
||||
= f.select(:tradable_to, Seed::TRADABLE_TO_VALUES, {label: 'Will trade', wrapper: { class: 'required'}})
|
||||
%span.help_inline
|
||||
- if current_member.location.blank?
|
||||
Don't forget to
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
= edit_icon
|
||||
.hide{id: "date--#{model.id}-#{field.to_s}"}
|
||||
= bootstrap_form_for(model) do |f|
|
||||
= f.date_field field,
|
||||
value: model.send(field) ? model.send(field).to_fs(:ymd) : '', label: 'When?'
|
||||
= f.text_field field,
|
||||
value: model.send(field) ? model.send(field).to_fs(:ymd) : '',
|
||||
class: 'add-datepicker', label: 'When?'
|
||||
= f.submit :save
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
- elsif field_type == :select
|
||||
= f.select field, collection
|
||||
- elsif field_type == :date
|
||||
= f.date_field field,
|
||||
value: model.send(field) ? model.send(field).to_fs(:ymd) : '', label: 'When?'
|
||||
= f.text_field field,
|
||||
value: model.send(field) ? model.send(field).to_fs(:ymd) : '',
|
||||
class: 'add-datepicker', label: 'When?'
|
||||
= f.submit :save
|
||||
|
||||
@@ -28,17 +28,11 @@ Rails.application.routes.draw do
|
||||
resources :photos, only: :index
|
||||
end
|
||||
|
||||
concern :commentable do
|
||||
resources :comments, only: [:new, :create, :edit, :update, :destroy], shallow: true
|
||||
end
|
||||
|
||||
resources :gardens, concerns: :has_photos, param: :slug do
|
||||
get 'timeline' => 'charts/gardens#timeline', constraints: { format: 'json' }
|
||||
|
||||
resources :garden_collaborators
|
||||
end
|
||||
|
||||
resources :plantings, concerns: [:has_photos, :commentable], param: :slug do
|
||||
resources :plantings, concerns: :has_photos, param: :slug do
|
||||
resources :harvests
|
||||
resources :seeds
|
||||
collection do
|
||||
@@ -51,11 +45,11 @@ Rails.application.routes.draw do
|
||||
get 'crop/:crop' => 'seeds#index', as: 'seeds_by_crop', on: :collection
|
||||
end
|
||||
|
||||
resources :harvests, concerns: [:has_photos, :commentable], param: :slug do
|
||||
resources :harvests, concerns: :has_photos, param: :slug do
|
||||
get 'crop/:crop' => 'harvests#index', as: 'harvests_by_crop', on: :collection
|
||||
end
|
||||
|
||||
resources :posts, concerns: :commentable do
|
||||
resources :posts do
|
||||
get 'author/:author' => 'posts#index', as: 'by_author', on: :collection
|
||||
end
|
||||
|
||||
@@ -66,7 +60,7 @@ Rails.application.routes.draw do
|
||||
end
|
||||
resources :alternate_names
|
||||
resources :plant_parts
|
||||
resources :photos, concerns: :commentable
|
||||
resources :photos
|
||||
|
||||
resources :photo_associations, only: :destroy
|
||||
|
||||
@@ -116,7 +110,7 @@ Rails.application.routes.draw do
|
||||
end
|
||||
|
||||
resources :messages
|
||||
resources :activities, concerns: :commentable, param: :slug
|
||||
resources :activities, param: :slug
|
||||
resources :conversations do
|
||||
collection do
|
||||
delete 'destroy_multiple'
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
class AddCommentableToComments < ActiveRecord::Migration[6.0]
|
||||
def up
|
||||
add_column :comments, :commentable_id, :integer
|
||||
add_column :comments, :commentable_type, :string
|
||||
add_index :comments, [:commentable_type, :commentable_id]
|
||||
|
||||
# Data migration
|
||||
execute <<-SQL
|
||||
UPDATE comments
|
||||
SET commentable_id = post_id,
|
||||
commentable_type = 'Post'
|
||||
WHERE post_id IS NOT NULL;
|
||||
SQL
|
||||
|
||||
remove_column :comments, :post_id
|
||||
end
|
||||
|
||||
def down
|
||||
add_column :comments, :post_id, :integer
|
||||
|
||||
# Data migration back
|
||||
execute <<-SQL
|
||||
UPDATE comments
|
||||
SET post_id = commentable_id
|
||||
WHERE commentable_type = 'Post';
|
||||
SQL
|
||||
|
||||
remove_index :comments, [:commentable_type, :commentable_id]
|
||||
remove_column :comments, :commentable_type
|
||||
remove_column :comments, :commentable_id
|
||||
end
|
||||
end
|
||||
@@ -1,10 +0,0 @@
|
||||
class CreateGardenCollaborators < ActiveRecord::Migration[7.2]
|
||||
def change
|
||||
create_table :garden_collaborators do |t|
|
||||
t.references :member
|
||||
t.references :garden
|
||||
t.timestamps
|
||||
t.index [:member_id, :garden_id], unique: true
|
||||
end
|
||||
end
|
||||
end
|
||||
63
db/schema.rb
63
db/schema.rb
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[7.2].define(version: 2024_09_29_041435) do
|
||||
ActiveRecord::Schema[7.1].define(version: 2024_07_14_024918) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
||||
@@ -54,6 +54,13 @@ ActiveRecord::Schema[7.2].define(version: 2024_09_29_041435) do
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.string "slug"
|
||||
t.integer "cached_votes_total", default: 0
|
||||
t.integer "cached_votes_score", default: 0
|
||||
t.integer "cached_votes_up", default: 0
|
||||
t.integer "cached_votes_down", default: 0
|
||||
t.integer "cached_weighted_score", default: 0
|
||||
t.integer "cached_weighted_total", default: 0
|
||||
t.float "cached_weighted_average", default: 0.0
|
||||
t.integer "likes_count", default: 0
|
||||
t.index ["garden_id"], name: "index_activities_on_garden_id"
|
||||
t.index ["owner_id"], name: "index_activities_on_owner_id"
|
||||
@@ -207,6 +214,13 @@ ActiveRecord::Schema[7.2].define(version: 2024_09_29_041435) do
|
||||
t.text "body", null: false
|
||||
t.datetime "created_at", precision: nil
|
||||
t.datetime "updated_at", precision: nil
|
||||
t.integer "cached_votes_total", default: 0
|
||||
t.integer "cached_votes_score", default: 0
|
||||
t.integer "cached_votes_up", default: 0
|
||||
t.integer "cached_votes_down", default: 0
|
||||
t.integer "cached_weighted_score", default: 0
|
||||
t.integer "cached_weighted_total", default: 0
|
||||
t.float "cached_weighted_average", default: 0.0
|
||||
end
|
||||
|
||||
create_table "crop_companions", force: :cascade do |t|
|
||||
@@ -266,16 +280,6 @@ ActiveRecord::Schema[7.2].define(version: 2024_09_29_041435) do
|
||||
t.index ["slug"], name: "index_forums_on_slug", unique: true
|
||||
end
|
||||
|
||||
create_table "garden_collaborators", force: :cascade do |t|
|
||||
t.bigint "member_id"
|
||||
t.bigint "garden_id"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["garden_id"], name: "index_garden_collaborators_on_garden_id"
|
||||
t.index ["member_id", "garden_id"], name: "index_garden_collaborators_on_member_id_and_garden_id", unique: true
|
||||
t.index ["member_id"], name: "index_garden_collaborators_on_member_id"
|
||||
end
|
||||
|
||||
create_table "garden_types", force: :cascade do |t|
|
||||
t.text "name", null: false
|
||||
t.text "slug", null: false
|
||||
@@ -500,6 +504,13 @@ ActiveRecord::Schema[7.2].define(version: 2024_09_29_041435) do
|
||||
t.datetime "date_taken", precision: nil
|
||||
t.integer "likes_count", default: 0
|
||||
t.string "source"
|
||||
t.integer "cached_votes_total", default: 0
|
||||
t.integer "cached_votes_score", default: 0
|
||||
t.integer "cached_votes_up", default: 0
|
||||
t.integer "cached_votes_down", default: 0
|
||||
t.integer "cached_weighted_score", default: 0
|
||||
t.integer "cached_weighted_total", default: 0
|
||||
t.float "cached_weighted_average", default: 0.0
|
||||
t.index ["fullsize_url"], name: "index_photos_on_fullsize_url", unique: true
|
||||
t.index ["thumbnail_url"], name: "index_photos_on_thumbnail_url", unique: true
|
||||
end
|
||||
@@ -542,6 +553,13 @@ ActiveRecord::Schema[7.2].define(version: 2024_09_29_041435) do
|
||||
t.integer "days_to_last_harvest"
|
||||
t.integer "parent_seed_id"
|
||||
t.integer "harvests_count", default: 0
|
||||
t.integer "cached_votes_total", default: 0
|
||||
t.integer "cached_votes_score", default: 0
|
||||
t.integer "cached_votes_up", default: 0
|
||||
t.integer "cached_votes_down", default: 0
|
||||
t.integer "cached_weighted_score", default: 0
|
||||
t.integer "cached_weighted_total", default: 0
|
||||
t.float "cached_weighted_average", default: 0.0
|
||||
t.integer "likes_count", default: 0
|
||||
t.index ["slug"], name: "index_plantings_on_slug", unique: true
|
||||
end
|
||||
@@ -556,6 +574,13 @@ ActiveRecord::Schema[7.2].define(version: 2024_09_29_041435) do
|
||||
t.integer "forum_id"
|
||||
t.integer "likes_count", default: 0
|
||||
t.integer "comments_count", default: 0
|
||||
t.integer "cached_votes_total", default: 0
|
||||
t.integer "cached_votes_score", default: 0
|
||||
t.integer "cached_votes_up", default: 0
|
||||
t.integer "cached_votes_down", default: 0
|
||||
t.integer "cached_weighted_score", default: 0
|
||||
t.integer "cached_weighted_total", default: 0
|
||||
t.float "cached_weighted_average", default: 0.0
|
||||
t.index ["created_at", "author_id"], name: "index_posts_on_created_at_and_author_id"
|
||||
t.index ["slug"], name: "index_posts_on_slug", unique: true
|
||||
end
|
||||
@@ -603,6 +628,22 @@ ActiveRecord::Schema[7.2].define(version: 2024_09_29_041435) do
|
||||
t.index ["slug"], name: "index_seeds_on_slug", unique: true
|
||||
end
|
||||
|
||||
create_table "votes", force: :cascade do |t|
|
||||
t.string "votable_type"
|
||||
t.bigint "votable_id"
|
||||
t.string "voter_type"
|
||||
t.bigint "voter_id"
|
||||
t.boolean "vote_flag"
|
||||
t.string "vote_scope"
|
||||
t.integer "vote_weight"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["votable_id", "votable_type", "vote_scope"], name: "index_votes_on_votable_id_and_votable_type_and_vote_scope"
|
||||
t.index ["votable_type", "votable_id"], name: "index_votes_on_votable"
|
||||
t.index ["voter_id", "voter_type", "vote_scope"], name: "index_votes_on_voter_id_and_voter_type_and_vote_scope"
|
||||
t.index ["voter_type", "voter_id"], name: "index_votes_on_voter"
|
||||
end
|
||||
|
||||
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
|
||||
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
|
||||
add_foreign_key "harvests", "plantings"
|
||||
|
||||
@@ -27,5 +27,6 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/growstuff/growstuff/issues"
|
||||
},
|
||||
"homepage": "https://github.com/growstuff/growstuff#readme"
|
||||
"homepage": "https://github.com/growstuff/growstuff#readme",
|
||||
"packageManager": "yarn@4.5.0"
|
||||
}
|
||||
|
||||
@@ -31,316 +31,95 @@ describe CommentsController do
|
||||
end
|
||||
end
|
||||
|
||||
# Shared examples for commentable controllers
|
||||
RSpec.shared_examples "a commentable controller" do |commentable_factory_name, commentable_param_key|
|
||||
let(:commentable_owner) { FactoryBot.create(:member) }
|
||||
let(:comment_author) { FactoryBot.create(:member) }
|
||||
let(:admin_user) { FactoryBot.create(:member, :admin) }
|
||||
let!(:commentable) do
|
||||
if [:post].include?(commentable_factory_name)
|
||||
FactoryBot.create(commentable_factory_name, author: commentable_owner)
|
||||
else
|
||||
FactoryBot.create(commentable_factory_name, owner: commentable_owner)
|
||||
describe "GET new" do
|
||||
let(:post) { FactoryBot.create(:post) }
|
||||
|
||||
describe "with valid params" do
|
||||
before { get :new, params: { post_id: post.id } }
|
||||
|
||||
let(:old_comment) { FactoryBot.create(:comment, post:) }
|
||||
|
||||
it "picks up post from params" do
|
||||
expect(assigns(:post)).to eq(post)
|
||||
end
|
||||
|
||||
it "assigns the old comments as @comments" do
|
||||
expect(assigns(:comments)).to eq [old_comment]
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET #new" do
|
||||
context "when not logged in" do
|
||||
before { sign_out member }
|
||||
it "redirects to login" do
|
||||
get :new, params: { commentable_param_key => commentable.id }
|
||||
expect(response).to redirect_to(new_member_session_path)
|
||||
end
|
||||
end
|
||||
it "dies if no post specified" do
|
||||
get :new
|
||||
expect(response).not_to be_successful
|
||||
end
|
||||
end
|
||||
|
||||
context "when logged in" do
|
||||
before { sign_in comment_author }
|
||||
it "assigns @commentable and new @comment" do
|
||||
get :new, params: { commentable_param_key => commentable.id }
|
||||
expect(assigns(:commentable)).to eq(commentable)
|
||||
expect(assigns(:comment)).to be_a_new(Comment)
|
||||
expect(response).to render_template(:new)
|
||||
end
|
||||
describe "GET edit" do
|
||||
let(:post) { FactoryBot.create(:post) }
|
||||
|
||||
it "redirects if commentable not found" do
|
||||
get :new, params: { commentable_param_key => -1 }
|
||||
expect(response).to redirect_to(request.referer || root_url)
|
||||
expect(flash[:alert]).to match(/Cannot add a comment to a non-existent or unspecified item/)
|
||||
end
|
||||
before { get :edit, params: { id: comment.to_param } }
|
||||
|
||||
describe "my comment" do
|
||||
let!(:comment) { FactoryBot.create(:comment, author: member, post:) }
|
||||
let!(:old_comment) { FactoryBot.create(:comment, post:, created_at: Time.zone.yesterday) }
|
||||
|
||||
it "assigns previous comments as @comments" do
|
||||
expect(assigns(:comments)).to eq([comment, old_comment])
|
||||
end
|
||||
end
|
||||
|
||||
describe "POST #create" do
|
||||
let(:valid_comment_params) { { body: "This is a great comment." } }
|
||||
let(:invalid_comment_params) { { body: "" } }
|
||||
describe "not my comment" do
|
||||
let(:comment) { FactoryBot.create(:comment, post:) }
|
||||
|
||||
context "when not logged in" do
|
||||
before { sign_out member }
|
||||
it "redirects to login" do
|
||||
post :create, params: { commentable_param_key => commentable.id, comment: valid_comment_params }
|
||||
expect(response).to redirect_to(new_member_session_path)
|
||||
end
|
||||
end
|
||||
it { expect(response).not_to be_successful }
|
||||
end
|
||||
end
|
||||
|
||||
context "when logged in" do
|
||||
before { sign_in comment_author }
|
||||
describe "PUT update" do
|
||||
before { put :update, params: { id: comment.to_param, comment: valid_attributes } }
|
||||
|
||||
context "with valid params" do
|
||||
it "creates a new Comment" do
|
||||
expect {
|
||||
post :create, params: { commentable_param_key => commentable.id, comment: valid_comment_params }
|
||||
}.to change(Comment, :count).by(1)
|
||||
end
|
||||
describe "my comment" do
|
||||
let(:comment) { FactoryBot.create(:comment, author: member) }
|
||||
|
||||
it "assigns the comment's author to current_member" do
|
||||
post :create, params: { commentable_param_key => commentable.id, comment: valid_comment_params }
|
||||
expect(Comment.last.author).to eq(comment_author)
|
||||
end
|
||||
|
||||
it "redirects to the commentable's show page" do
|
||||
post :create, params: { commentable_param_key => commentable.id, comment: valid_comment_params }
|
||||
expect(response).to redirect_to(commentable)
|
||||
end
|
||||
end
|
||||
|
||||
context "with invalid params" do
|
||||
it "does not create a comment" do
|
||||
expect {
|
||||
post :create, params: { commentable_param_key => commentable.id, comment: invalid_comment_params }
|
||||
}.not_to change(Comment, :count)
|
||||
end
|
||||
|
||||
it "re-renders the 'new' template (or commentable show with errors)" do
|
||||
# The controller currently redirects if commentable is not found in create,
|
||||
# but for invalid comment params, it should re-render or show errors.
|
||||
# The current controller's create action saves and then responds.
|
||||
# If save fails, it typically re-renders the form via respond_with.
|
||||
# For this test, we'll assume it re-renders 'new' if save fails.
|
||||
# A more precise test would check the response if @comment.save fails.
|
||||
# For now, we'll check that it doesn't redirect to the commentable if save fails.
|
||||
post :create, params: { commentable_param_key => commentable.id, comment: invalid_comment_params }
|
||||
# Depending on how `respond_with` handles failure for new comment on commentable,
|
||||
# it might render the commentable's show page or the comments/new template.
|
||||
# The key is that it shouldn't be a successful redirect to the commentable.
|
||||
# And @comment.errors should be present.
|
||||
expect(assigns(:comment).errors).not_to be_empty
|
||||
# Check for re-render of new or specific error handling view
|
||||
# For now, checking that it's not a successful redirect if save fails.
|
||||
# This might need adjustment based on actual controller error flow.
|
||||
# A common pattern is to render the 'new' template again or the parent's show page.
|
||||
# The `respond_with @comment, location: @comment.commentable` will try to redirect if valid.
|
||||
# If invalid, it should re-render the action that led to the form.
|
||||
# For `create` failing, it's often the `new` view or the parent resource's view.
|
||||
# The controller has `respond_with @comment, location: @comment.commentable`.
|
||||
# If `@comment` is not persisted, `respond_with` might render the `new` template by convention,
|
||||
# or the template of the action (`create.js.erb` or `create.html.erb` if they exist).
|
||||
# Given the setup, it's likely to re-render 'new' or the controller action's default.
|
||||
# Let's assume for now the form is on the `new` page.
|
||||
# This is a weak assertion. A better one would be to check for `render_template(:new)`
|
||||
# if the controller is set up to do that on failure.
|
||||
# However, `respond_with` is tricky. It might also render the `commentable` show page with errors.
|
||||
# The `new` action in controller renders `respond_with(@comment)`.
|
||||
# The `create` action has `respond_with @comment, location: @comment.commentable`.
|
||||
# If `@comment.save` fails, `respond_with` will typically render the `new` template by default
|
||||
# if `create.html.haml` doesn't exist, or it might try to render `commentable` show page
|
||||
# with errors displayed by the form partial.
|
||||
# Given the form is rendered via `comments/new`, let's assume it re-renders new.
|
||||
# This part of the test may need refinement based on actual error rendering flow.
|
||||
# A simple check: ensure it doesn't redirect to the commentable.
|
||||
expect(response).not_to redirect_to(commentable_path(commentable))
|
||||
# And that @commentable is still assigned for the form.
|
||||
expect(assigns(:commentable)).to eq(commentable)
|
||||
end
|
||||
end
|
||||
|
||||
it "redirects if commentable not found" do
|
||||
post :create, params: { commentable_param_key => -1, comment: valid_comment_params }
|
||||
expect(response).to redirect_to(request.referer || root_url)
|
||||
expect(flash[:alert]).to match(/Cannot create comment for a non-existent or unspecified item/)
|
||||
end
|
||||
it "redirects to the comment's post" do
|
||||
expect(response).to redirect_to(comment.post)
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET #edit" do
|
||||
let!(:comment) { FactoryBot.create(:comment, commentable: commentable, author: comment_author) }
|
||||
describe "not my comment" do
|
||||
let(:comment) { FactoryBot.create(:comment) }
|
||||
|
||||
context "when not logged in" do
|
||||
before { sign_out member }
|
||||
it "redirects to login" do
|
||||
get :edit, params: { id: comment.id }
|
||||
expect(response).to redirect_to(new_member_session_path)
|
||||
end
|
||||
end
|
||||
|
||||
context "as comment author" do
|
||||
before { sign_in comment_author }
|
||||
it "assigns @comment and renders edit" do
|
||||
get :edit, params: { id: comment.id }
|
||||
expect(assigns(:comment)).to eq(comment)
|
||||
expect(response).to render_template(:edit)
|
||||
end
|
||||
end
|
||||
|
||||
context "as admin" do
|
||||
before { sign_in admin_user }
|
||||
it "assigns @comment and renders edit" do
|
||||
get :edit, params: { id: comment.id }
|
||||
expect(assigns(:comment)).to eq(comment)
|
||||
expect(response).to render_template(:edit)
|
||||
end
|
||||
end
|
||||
|
||||
context "as unauthorized user" do
|
||||
let(:other_user) { FactoryBot.create(:member) }
|
||||
before { sign_in other_user }
|
||||
it "redirects or shows error" do
|
||||
get :edit, params: { id: comment.id }
|
||||
expect(response).to redirect_to(root_url) # Or some other unauthorized path
|
||||
expect(flash[:alert]).to match(/You are not authorized to access this page./)
|
||||
end
|
||||
end
|
||||
it { expect(response).not_to be_successful }
|
||||
end
|
||||
|
||||
describe "PUT #update" do
|
||||
let!(:comment) { FactoryBot.create(:comment, commentable: commentable, author: comment_author, body: "Original body") }
|
||||
let(:updated_body) { "Updated comment body." }
|
||||
describe "attempting to change post_id" do
|
||||
let(:post) { FactoryBot.create(:post, subject: 'our post') }
|
||||
let(:other_post) { FactoryBot.create(:post, subject: 'the other post') }
|
||||
let(:valid_attributes) { { post_id: other_post.id, body: "kōrero" } }
|
||||
let(:comment) { FactoryBot.create(:comment, author: member, post:) }
|
||||
|
||||
context "when not logged in" do
|
||||
before { sign_out member }
|
||||
it "redirects to login" do
|
||||
put :update, params: { id: comment.id, comment: { body: updated_body } }
|
||||
expect(response).to redirect_to(new_member_session_path)
|
||||
end
|
||||
end
|
||||
|
||||
context "as comment author" do
|
||||
before { sign_in comment_author }
|
||||
context "with valid params" do
|
||||
it "updates the comment" do
|
||||
put :update, params: { id: comment.id, comment: { body: updated_body } }
|
||||
comment.reload
|
||||
expect(comment.body).to eq(updated_body)
|
||||
end
|
||||
it "redirects to commentable show page" do
|
||||
put :update, params: { id: comment.id, comment: { body: updated_body } }
|
||||
expect(response).to redirect_to(commentable_path(commentable))
|
||||
end
|
||||
end
|
||||
context "with invalid params (empty body)" do
|
||||
it "does not update the comment and re-renders edit" do
|
||||
put :update, params: { id: comment.id, comment: { body: "" } }
|
||||
comment.reload
|
||||
expect(comment.body).to eq("Original body") # Should not change
|
||||
expect(response).to render_template(:edit)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "as admin" do
|
||||
before { sign_in admin_user }
|
||||
it "updates the comment" do
|
||||
put :update, params: { id: comment.id, comment: { body: updated_body } }
|
||||
comment.reload
|
||||
expect(comment.body).to eq(updated_body)
|
||||
expect(response).to redirect_to(commentable_path(commentable))
|
||||
end
|
||||
end
|
||||
|
||||
context "as unauthorized user" do
|
||||
let(:other_user) { FactoryBot.create(:member) }
|
||||
before { sign_in other_user }
|
||||
it "redirects or shows error" do
|
||||
put :update, params: { id: comment.id, comment: { body: updated_body } }
|
||||
expect(response).to redirect_to(root_url)
|
||||
expect(flash[:alert]).to match(/You are not authorized to access this page./)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "DELETE #destroy" do
|
||||
let!(:comment_to_delete) { FactoryBot.create(:comment, commentable: commentable, author: comment_author) }
|
||||
|
||||
context "when not logged in" do
|
||||
before { sign_out member }
|
||||
it "redirects to login" do
|
||||
delete :destroy, params: { id: comment_to_delete.id }
|
||||
expect(response).to redirect_to(new_member_session_path)
|
||||
end
|
||||
end
|
||||
|
||||
context "as comment author" do
|
||||
before { sign_in comment_author }
|
||||
it "deletes the comment" do
|
||||
expect {
|
||||
delete :destroy, params: { id: comment_to_delete.id }
|
||||
}.to change(Comment, :count).by(-1)
|
||||
end
|
||||
it "redirects to commentable show page" do
|
||||
delete :destroy, params: { id: comment_to_delete.id }
|
||||
expect(response).to redirect_to(commentable_path(commentable))
|
||||
end
|
||||
end
|
||||
|
||||
context "as commentable owner" do
|
||||
before { sign_in commentable_owner }
|
||||
it "deletes the comment" do
|
||||
# Ensure comment_author is not the same as commentable_owner for this test case
|
||||
expect(comment_to_delete.author).not_to eq(commentable_owner)
|
||||
expect {
|
||||
delete :destroy, params: { id: comment_to_delete.id }
|
||||
}.to change(Comment, :count).by(-1)
|
||||
end
|
||||
it "redirects to commentable show page" do
|
||||
delete :destroy, params: { id: comment_to_delete.id }
|
||||
expect(response).to redirect_to(commentable_path(commentable))
|
||||
end
|
||||
end
|
||||
|
||||
context "as admin" do
|
||||
before { sign_in admin_user }
|
||||
it "deletes the comment" do
|
||||
expect {
|
||||
delete :destroy, params: { id: comment_to_delete.id }
|
||||
}.to change(Comment, :count).by(-1)
|
||||
end
|
||||
it "redirects to commentable show page" do
|
||||
delete :destroy, params: { id: comment_to_delete.id }
|
||||
expect(response).to redirect_to(commentable_path(commentable))
|
||||
end
|
||||
end
|
||||
|
||||
context "as unauthorized user" do
|
||||
let(:other_user) { FactoryBot.create(:member) }
|
||||
before { sign_in other_user }
|
||||
it "does not delete the comment and redirects or shows error" do
|
||||
expect {
|
||||
delete :destroy, params: { id: comment_to_delete.id }
|
||||
}.not_to change(Comment, :count)
|
||||
expect(response).to redirect_to(root_url)
|
||||
expect(flash[:alert]).to match(/You are not authorized to access this page./)
|
||||
end
|
||||
it "does not change post_id" do
|
||||
comment.reload
|
||||
expect(comment.post_id).to eq(post.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Apply shared examples for each commentable type
|
||||
context "for Post" do
|
||||
it_behaves_like "a commentable controller", :post, :post_id
|
||||
end
|
||||
describe "DELETE destroy" do
|
||||
before { delete :destroy, params: { id: comment.to_param } }
|
||||
|
||||
context "for Photo" do
|
||||
it_behaves_like "a commentable controller", :photo, :photo_id
|
||||
end
|
||||
describe "my comment" do
|
||||
let(:comment) { FactoryBot.create(:comment, author: member) }
|
||||
|
||||
context "for Planting" do
|
||||
it_behaves_like "a commentable controller", :planting, :planting_id
|
||||
end
|
||||
it "redirects to the post the comment was on" do
|
||||
expect(response).to redirect_to(comment.post)
|
||||
end
|
||||
end
|
||||
|
||||
context "for Harvest" do
|
||||
it_behaves_like "a commentable controller", :harvest, :harvest_id
|
||||
end
|
||||
describe "not my comment" do
|
||||
let(:comment) { FactoryBot.create(:comment) }
|
||||
|
||||
context "for Activity" do
|
||||
it_behaves_like "a commentable controller", :activity, :activity_id
|
||||
it { expect(response).not_to be_successful }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :activity do
|
||||
association :owner, factory: :member
|
||||
sequence(:name) { |n| "Test Activity #{n}" }
|
||||
description { "This is a test activity." }
|
||||
category { "General" } # Example category
|
||||
due_date { Time.zone.today + 1.week }
|
||||
|
||||
# Optional associations, uncomment and adjust if Activity model has these
|
||||
# association :garden, factory: :garden
|
||||
# association :planting, factory: :planting
|
||||
|
||||
trait :finished do
|
||||
finished { true }
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,30 +2,9 @@
|
||||
|
||||
FactoryBot.define do
|
||||
factory :comment do
|
||||
association :author, factory: :member # Explicitly use :member factory for author
|
||||
post
|
||||
author
|
||||
sequence(:body) { |n| "OMG LOL #{n}" }
|
||||
|
||||
# Default to associating with a post if no specific commentable is provided
|
||||
association :commentable, factory: :post
|
||||
|
||||
trait :for_post do
|
||||
association :commentable, factory: :post
|
||||
end
|
||||
|
||||
trait :for_photo do
|
||||
association :commentable, factory: :photo
|
||||
end
|
||||
|
||||
trait :for_planting do
|
||||
association :commentable, factory: :planting
|
||||
end
|
||||
|
||||
trait :for_harvest do
|
||||
association :commentable, factory: :harvest
|
||||
end
|
||||
|
||||
trait :for_activity do
|
||||
association :commentable, factory: :activity
|
||||
end
|
||||
# because our commenters are more polite than YouTube's
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
FactoryBot.define do
|
||||
factory :garden_collaborator do
|
||||
garden
|
||||
member
|
||||
end
|
||||
end
|
||||
@@ -1,17 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :member do
|
||||
sequence(:login_name) { |n| "member#{n}" }
|
||||
sequence(:email) { |n| "member#{n}@example.com" }
|
||||
password { "password123" }
|
||||
password_confirmation { "password123" }
|
||||
confirmed_at { Time.zone.now } # Assuming Devise confirmable is used
|
||||
|
||||
trait :admin do
|
||||
after(:create) { |member| member.add_role(:admin) }
|
||||
end
|
||||
|
||||
# Add other traits if needed, e.g., for specific member states or roles
|
||||
end
|
||||
end
|
||||
@@ -1,38 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :planting do
|
||||
association :owner, factory: :member
|
||||
association :crop
|
||||
association :garden
|
||||
planted_at { Time.zone.today - 1.month }
|
||||
description { "My awesome planting." }
|
||||
quantity { 1 } # Example attribute
|
||||
|
||||
# Add traits if needed
|
||||
trait :finished do
|
||||
finished { true }
|
||||
finished_at { Time.zone.today - 1.day }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Assuming Crop and Garden factories are needed and might not exist
|
||||
# Minimal Crop factory
|
||||
FactoryBot.define do
|
||||
factory :crop do
|
||||
sequence(:name) { |n| "Test Crop #{n}" }
|
||||
# Add other necessary attributes for Crop
|
||||
# e.g., approval_status if relevant for comments
|
||||
approval_status { 'approved' } # Default to approved for simplicity
|
||||
end
|
||||
end
|
||||
|
||||
# Minimal Garden factory
|
||||
FactoryBot.define do
|
||||
factory :garden do
|
||||
association :owner, factory: :member
|
||||
sequence(:name) { |n| "Test Garden #{n}" }
|
||||
# Add other necessary attributes for Garden
|
||||
end
|
||||
end
|
||||
@@ -1,37 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :post do
|
||||
association :author, factory: :member
|
||||
association :forum # Assuming posts belong to a forum
|
||||
sequence(:subject) { |n| "Test Post Subject #{n}" }
|
||||
sequence(:body) { |n| "This is the body of test post #{n}." }
|
||||
|
||||
# Add traits if needed, e.g., for posts with photos, crops, etc.
|
||||
trait :with_photos do
|
||||
transient do
|
||||
photos_count { 1 }
|
||||
end
|
||||
after(:create) do |post, evaluator|
|
||||
create_list(:photo, evaluator.photos_count, owner: post.author, post_id: post.id) # Assuming Photo has post_id or similar
|
||||
end
|
||||
end
|
||||
|
||||
trait :with_crops do
|
||||
transient do
|
||||
crops_count { 1 }
|
||||
end
|
||||
after(:create) do |post, evaluator|
|
||||
create_list(:crop, evaluator.crops_count, posts: [post]) # Assuming a has_and_belongs_to_many or has_many :through
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Assuming a Forum model exists and has a factory
|
||||
FactoryBot.define do
|
||||
factory :forum do
|
||||
sequence(:name) { |n| "Test Forum #{n}" }
|
||||
# Add other attributes for Forum as needed
|
||||
end
|
||||
end
|
||||
@@ -1,156 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.feature "Commenting on Activities", type: :feature, js: true do
|
||||
let(:activity_owner) { FactoryBot.create(:member, login_name: "ActivityOwner") }
|
||||
let(:commenter) { FactoryBot.create(:member, login_name: "Commenter") }
|
||||
let(:other_member) { FactoryBot.create(:member, login_name: "OtherMember") }
|
||||
let(:admin) { FactoryBot.create(:member, :admin, login_name: "AdminUser") }
|
||||
|
||||
let!(:activity) { FactoryBot.create(:activity, owner: activity_owner, name: "Gardening Day") }
|
||||
|
||||
|
||||
def login_as(user)
|
||||
visit new_member_session_path
|
||||
fill_in "Login Name or Email", with: user.login_name
|
||||
fill_in "Password", with: user.password
|
||||
click_button "Log in"
|
||||
expect(page).to have_content("Signed in successfully")
|
||||
end
|
||||
|
||||
describe "User comments on an Activity" do
|
||||
before do
|
||||
login_as(commenter)
|
||||
visit activity_path(activity)
|
||||
end
|
||||
|
||||
it "allows a user to create a comment" do
|
||||
expect(page).to have_content("Comments")
|
||||
click_link "Add Comment"
|
||||
|
||||
expect(page).to have_current_path(new_activity_comment_path(activity))
|
||||
expect(page).to have_content("Add comment to activity")
|
||||
|
||||
fill_in "comment_body", with: "Sounds like a fun activity!"
|
||||
click_button "Post comment"
|
||||
|
||||
expect(page).to have_current_path(activity_path(activity))
|
||||
expect(page).to have_content("Sounds like a fun activity!")
|
||||
expect(page).to have_content(commenter.login_name)
|
||||
end
|
||||
end
|
||||
|
||||
describe "Editing comments on an Activity" do
|
||||
let!(:comment_to_edit) { FactoryBot.create(:comment, commentable: activity, author: commenter, body: "Initial activity comment") }
|
||||
|
||||
context "as comment author" do
|
||||
before do
|
||||
login_as(commenter)
|
||||
visit activity_path(activity)
|
||||
find('.comment-body', text: "Initial activity comment").ancestor('.comment').find_button('Actions').click
|
||||
click_link "Edit"
|
||||
end
|
||||
|
||||
it "allows the author to edit their comment" do
|
||||
expect(page).to have_current_path(edit_comment_path(comment_to_edit))
|
||||
fill_in "comment_body", with: "Updated activity comment."
|
||||
click_button "Post comment"
|
||||
|
||||
expect(page).to have_current_path(activity_path(activity))
|
||||
expect(page).to have_content("Updated activity comment.")
|
||||
expect(page).not_to have_content("Initial activity comment")
|
||||
end
|
||||
end
|
||||
|
||||
context "as admin" do
|
||||
before do
|
||||
login_as(admin)
|
||||
visit activity_path(activity)
|
||||
find('.comment-body', text: "Initial activity comment").ancestor('.comment').find_button('Actions').click
|
||||
click_link "Edit"
|
||||
end
|
||||
|
||||
it "allows admin to edit any comment" do
|
||||
fill_in "comment_body", with: "Admin edited this activity comment."
|
||||
click_button "Post comment"
|
||||
expect(page).to have_content("Admin edited this activity comment.")
|
||||
end
|
||||
end
|
||||
|
||||
context "as unauthorized user" do
|
||||
before do
|
||||
login_as(other_member)
|
||||
visit activity_path(activity)
|
||||
end
|
||||
|
||||
it "does not show edit link for other's comment" do
|
||||
comment_element = find('.comment-body', text: "Initial activity comment").ancestor('.comment')
|
||||
expect(comment_element).not_to have_link("Edit")
|
||||
expect(comment_element).not_to have_button("Actions")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "Deleting comments on an Activity" do
|
||||
let!(:comment_to_delete) { FactoryBot.create(:comment, commentable: activity, author: commenter, body: "Delete this activity comment") }
|
||||
|
||||
context "as comment author" do
|
||||
before do
|
||||
login_as(commenter)
|
||||
visit activity_path(activity)
|
||||
find('.comment-body', text: "Delete this activity comment").ancestor('.comment').find_button('Actions').click
|
||||
accept_alert { click_link "Delete" }
|
||||
end
|
||||
|
||||
it "allows the author to delete their comment" do
|
||||
expect(page).not_to have_content("Delete this activity comment")
|
||||
expect(page).to have_content("Comment was successfully destroyed.")
|
||||
end
|
||||
end
|
||||
|
||||
context "as activity owner" do
|
||||
before do
|
||||
login_as(activity_owner)
|
||||
visit activity_path(activity)
|
||||
find('.comment-body', text: "Delete this activity comment").ancestor('.comment').find_button('Actions').click
|
||||
accept_alert { click_link "Delete" }
|
||||
end
|
||||
|
||||
it "allows the activity owner to delete any comment on their activity" do
|
||||
expect(page).not_to have_content("Delete this activity comment")
|
||||
expect(page).to have_content("Comment was successfully destroyed.")
|
||||
end
|
||||
end
|
||||
|
||||
context "as admin" do
|
||||
before do
|
||||
login_as(admin)
|
||||
visit activity_path(activity)
|
||||
find('.comment-body', text: "Delete this activity comment").ancestor('.comment').find_button('Actions').click
|
||||
accept_alert { click_link "Delete" }
|
||||
end
|
||||
|
||||
it "allows admin to delete any comment" do
|
||||
expect(page).not_to have_content("Delete this activity comment")
|
||||
expect(page).to have_content("Comment was successfully destroyed.")
|
||||
end
|
||||
end
|
||||
|
||||
context "as unauthorized user" do
|
||||
let!(:another_comment) { FactoryBot.create(:comment, commentable: activity, author: activity_owner, body: "Activity owner's comment") }
|
||||
before do
|
||||
login_as(other_member)
|
||||
visit activity_path(activity)
|
||||
end
|
||||
|
||||
it "does not show delete link for other's comment" do
|
||||
comment_element = find('.comment-body', text: "Activity owner's comment").ancestor('.comment')
|
||||
expect(comment_element).not_to have_link("Delete")
|
||||
|
||||
comment_element_2 = find('.comment-body', text: "Delete this activity comment").ancestor('.comment')
|
||||
expect(comment_element_2).not_to have_link("Delete")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
38
spec/features/comments/commenting_a_comment_spec.rb
Normal file
38
spec/features/comments/commenting_a_comment_spec.rb
Normal file
@@ -0,0 +1,38 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe 'Commenting on a post' do
|
||||
include_context 'signed in member'
|
||||
let(:member) { create(:member) }
|
||||
let(:post) { create(:post, author: member) }
|
||||
|
||||
before { visit new_comment_path post_id: post.id }
|
||||
|
||||
include_examples 'is accessible'
|
||||
|
||||
it "creating a comment" do
|
||||
fill_in "comment_body", with: "This is a sample test for comment"
|
||||
click_button "Post comment"
|
||||
expect(page).to have_content "comment was successfully created."
|
||||
expect(page).to have_content "Posted by"
|
||||
page.percy_snapshot(page, name: 'Posting a comment')
|
||||
end
|
||||
|
||||
context "editing a comment" do
|
||||
let(:existing_comment) { create(:comment, post:, author: member) }
|
||||
|
||||
before do
|
||||
visit edit_comment_path existing_comment
|
||||
end
|
||||
|
||||
include_examples 'is accessible'
|
||||
|
||||
it "saving edit" do
|
||||
fill_in "comment_body", with: "Testing edit for comment"
|
||||
click_button "Post comment"
|
||||
expect(page).to have_content "comment was successfully updated."
|
||||
expect(page).to have_content "edited at"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -10,6 +10,10 @@ describe "Gardens", :js do
|
||||
|
||||
include_examples 'is accessible'
|
||||
|
||||
it "has the required fields help text" do
|
||||
expect(page).to have_content "* denotes a required field"
|
||||
end
|
||||
|
||||
it "displays required and optional fields properly" do
|
||||
expect(page).to have_selector ".required", text: "Name"
|
||||
expect(page).to have_selector 'textarea#garden_description'
|
||||
@@ -23,5 +27,14 @@ describe "Gardens", :js do
|
||||
expect(page).to have_content "Garden was successfully created"
|
||||
expect(page).to have_content "New garden"
|
||||
end
|
||||
|
||||
it "Refuse to create new garden with negative area" do
|
||||
visit new_garden_path
|
||||
fill_in "Name", with: "Negative Garden"
|
||||
fill_in "Area", with: -5
|
||||
click_button "Save"
|
||||
expect(page).to have_no_content "Garden was successfully created"
|
||||
expect(page).to have_content "Area must be greater than or equal to 0"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -52,6 +52,15 @@ describe "Planting a crop", :js do
|
||||
expect(page).to have_content "New garden"
|
||||
end
|
||||
|
||||
it "Refuse to create new garden with negative area" do
|
||||
visit new_garden_path
|
||||
fill_in "Name", with: "Negative Garden"
|
||||
fill_in "Area", with: -5
|
||||
click_button "Save"
|
||||
expect(page).to have_no_content "Garden was successfully created"
|
||||
expect(page).to have_content "Area must be greater than or equal to 0"
|
||||
end
|
||||
|
||||
context "Clicking edit from the index page" do
|
||||
before do
|
||||
visit gardens_path
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.feature "Commenting on Harvests", type: :feature, js: true do
|
||||
let(:harvest_owner) { FactoryBot.create(:member, login_name: "HarvestOwner") }
|
||||
let(:commenter) { FactoryBot.create(:member, login_name: "Commenter") }
|
||||
let(:other_member) { FactoryBot.create(:member, login_name: "OtherMember") }
|
||||
let(:admin) { FactoryBot.create(:member, :admin, login_name: "AdminUser") }
|
||||
|
||||
# Ensure crop, planting, and garden are created for the harvest
|
||||
let(:crop) { FactoryBot.create(:crop) }
|
||||
let(:garden) { FactoryBot.create(:garden, owner: harvest_owner) } # Harvest owner also owns garden for simplicity
|
||||
let(:planting) { FactoryBot.create(:planting, owner: harvest_owner, crop: crop, garden: garden) }
|
||||
let!(:harvest) { FactoryBot.create(:harvest, owner: harvest_owner, planting: planting, description: "My test harvest") }
|
||||
|
||||
|
||||
def login_as(user)
|
||||
visit new_member_session_path
|
||||
fill_in "Login Name or Email", with: user.login_name
|
||||
fill_in "Password", with: user.password
|
||||
click_button "Log in"
|
||||
expect(page).to have_content("Signed in successfully")
|
||||
end
|
||||
|
||||
describe "User comments on a Harvest" do
|
||||
before do
|
||||
login_as(commenter)
|
||||
visit harvest_path(harvest)
|
||||
end
|
||||
|
||||
it "allows a user to create a comment" do
|
||||
expect(page).to have_content("Comments")
|
||||
click_link "Add Comment"
|
||||
|
||||
expect(page).to have_current_path(new_harvest_comment_path(harvest))
|
||||
expect(page).to have_content("Add comment to harvest")
|
||||
|
||||
fill_in "comment_body", with: "This harvest looks bountiful!"
|
||||
click_button "Post comment"
|
||||
|
||||
expect(page).to have_current_path(harvest_path(harvest))
|
||||
expect(page).to have_content("This harvest looks bountiful!")
|
||||
expect(page).to have_content(commenter.login_name)
|
||||
end
|
||||
end
|
||||
|
||||
describe "Editing comments on a Harvest" do
|
||||
let!(:comment_to_edit) { FactoryBot.create(:comment, commentable: harvest, author: commenter, body: "Initial harvest comment") }
|
||||
|
||||
context "as comment author" do
|
||||
before do
|
||||
login_as(commenter)
|
||||
visit harvest_path(harvest)
|
||||
find('.comment-body', text: "Initial harvest comment").ancestor('.comment').find_button('Actions').click
|
||||
click_link "Edit"
|
||||
end
|
||||
|
||||
it "allows the author to edit their comment" do
|
||||
expect(page).to have_current_path(edit_comment_path(comment_to_edit))
|
||||
fill_in "comment_body", with: "Updated harvest comment."
|
||||
click_button "Post comment"
|
||||
|
||||
expect(page).to have_current_path(harvest_path(harvest))
|
||||
expect(page).to have_content("Updated harvest comment.")
|
||||
expect(page).not_to have_content("Initial harvest comment")
|
||||
end
|
||||
end
|
||||
|
||||
context "as admin" do
|
||||
before do
|
||||
login_as(admin)
|
||||
visit harvest_path(harvest)
|
||||
find('.comment-body', text: "Initial harvest comment").ancestor('.comment').find_button('Actions').click
|
||||
click_link "Edit"
|
||||
end
|
||||
|
||||
it "allows admin to edit any comment" do
|
||||
fill_in "comment_body", with: "Admin edited this harvest comment."
|
||||
click_button "Post comment"
|
||||
expect(page).to have_content("Admin edited this harvest comment.")
|
||||
end
|
||||
end
|
||||
|
||||
context "as unauthorized user" do
|
||||
before do
|
||||
login_as(other_member)
|
||||
visit harvest_path(harvest)
|
||||
end
|
||||
|
||||
it "does not show edit link for other's comment" do
|
||||
comment_element = find('.comment-body', text: "Initial harvest comment").ancestor('.comment')
|
||||
expect(comment_element).not_to have_link("Edit")
|
||||
expect(comment_element).not_to have_button("Actions")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "Deleting comments on a Harvest" do
|
||||
let!(:comment_to_delete) { FactoryBot.create(:comment, commentable: harvest, author: commenter, body: "Delete this harvest comment") }
|
||||
|
||||
context "as comment author" do
|
||||
before do
|
||||
login_as(commenter)
|
||||
visit harvest_path(harvest)
|
||||
find('.comment-body', text: "Delete this harvest comment").ancestor('.comment').find_button('Actions').click
|
||||
accept_alert { click_link "Delete" }
|
||||
end
|
||||
|
||||
it "allows the author to delete their comment" do
|
||||
expect(page).not_to have_content("Delete this harvest comment")
|
||||
expect(page).to have_content("Comment was successfully destroyed.")
|
||||
end
|
||||
end
|
||||
|
||||
context "as harvest owner" do
|
||||
before do
|
||||
login_as(harvest_owner)
|
||||
visit harvest_path(harvest)
|
||||
find('.comment-body', text: "Delete this harvest comment").ancestor('.comment').find_button('Actions').click
|
||||
accept_alert { click_link "Delete" }
|
||||
end
|
||||
|
||||
it "allows the harvest owner to delete any comment on their harvest" do
|
||||
expect(page).not_to have_content("Delete this harvest comment")
|
||||
expect(page).to have_content("Comment was successfully destroyed.")
|
||||
end
|
||||
end
|
||||
|
||||
context "as admin" do
|
||||
before do
|
||||
login_as(admin)
|
||||
visit harvest_path(harvest)
|
||||
find('.comment-body', text: "Delete this harvest comment").ancestor('.comment').find_button('Actions').click
|
||||
accept_alert { click_link "Delete" }
|
||||
end
|
||||
|
||||
it "allows admin to delete any comment" do
|
||||
expect(page).not_to have_content("Delete this harvest comment")
|
||||
expect(page).to have_content("Comment was successfully destroyed.")
|
||||
end
|
||||
end
|
||||
|
||||
context "as unauthorized user" do
|
||||
let!(:another_comment) { FactoryBot.create(:comment, commentable: harvest, author: harvest_owner, body: "Harvest owner's comment") }
|
||||
before do
|
||||
login_as(other_member)
|
||||
visit harvest_path(harvest)
|
||||
end
|
||||
|
||||
it "does not show delete link for other's comment" do
|
||||
comment_element = find('.comment-body', text: "Harvest owner's comment").ancestor('.comment')
|
||||
expect(comment_element).not_to have_link("Delete")
|
||||
|
||||
comment_element_2 = find('.comment-body', text: "Delete this harvest comment").ancestor('.comment')
|
||||
expect(comment_element_2).not_to have_link("Delete")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -13,6 +13,10 @@ describe "Harvesting a crop", :js, :search do
|
||||
|
||||
it_behaves_like "crop suggest", "harvest", "crop"
|
||||
|
||||
it "has the required fields help text" do
|
||||
expect(page).to have_content "* denotes a required field"
|
||||
end
|
||||
|
||||
describe "displays required and optional fields properly" do
|
||||
it { expect(page).to have_selector ".required", text: "What did you harvest?" }
|
||||
it { expect(page).to have_selector 'input#harvest_quantity' }
|
||||
@@ -26,7 +30,7 @@ describe "Harvesting a crop", :js, :search do
|
||||
|
||||
within "form#new_harvest" do
|
||||
choose plant_part.name
|
||||
fill_in "When?", with: Time.new(2014, 06, 15)
|
||||
fill_in "When?", with: "2014-06-15"
|
||||
fill_in "How many?", with: 42
|
||||
fill_in "Weighing (in total)", with: 42
|
||||
fill_in "Notes", with: "It's killer."
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe "member deletion", flaky: true do
|
||||
describe "member deletion" do
|
||||
context "with activity and followers" do
|
||||
let(:member) { FactoryBot.create(:member) }
|
||||
let(:other_member) { FactoryBot.create(:member) }
|
||||
@@ -14,9 +14,14 @@ describe "member deletion", flaky: true do
|
||||
let!(:secondgarden) { FactoryBot.create(:garden, owner: member) }
|
||||
|
||||
before do
|
||||
member.follows.create!(followed: other_member)
|
||||
other_member.follows.create!(followed: member)
|
||||
|
||||
login_as(member)
|
||||
visit member_path(other_member)
|
||||
click_link 'Follow'
|
||||
logout
|
||||
login_as(other_member)
|
||||
visit member_path(member)
|
||||
click_link 'Follow'
|
||||
logout
|
||||
login_as(member)
|
||||
FactoryBot.create(:comment, author: member, post: othermemberpost)
|
||||
FactoryBot.create(:comment, author: other_member, post: memberpost, body: "Fun comment-y thing")
|
||||
@@ -55,21 +60,8 @@ describe "member deletion", flaky: true do
|
||||
click_link 'Delete Account'
|
||||
fill_in "current_pw_for_delete", with: "password1", match: :prefer_exact
|
||||
click_button "Delete"
|
||||
|
||||
# Assert we're signed out
|
||||
expect(page).to have_current_path(new_member_session_path)
|
||||
|
||||
# And soft deleted
|
||||
member.reload
|
||||
expect(member.discarded?).to be true
|
||||
|
||||
# Frustratingly, this cannot be discarded? and also meet
|
||||
# `@member = Member.confirmed.kept.find_by!(slug: params[:slug])`
|
||||
#
|
||||
# Yet, we see the below assert fail in CI.
|
||||
#
|
||||
# visit member_path(member)
|
||||
# expect(page).to have_text "The page you were looking for doesn't exist."
|
||||
visit member_path(member)
|
||||
expect(page).to have_text "The page you were looking for doesn't exist."
|
||||
end
|
||||
|
||||
describe 'percy spec' do
|
||||
|
||||
@@ -63,21 +63,8 @@ describe "follows", :js do
|
||||
end
|
||||
|
||||
it "removes members from following and followers lists after unfollow" do
|
||||
expect(member.already_following?(other_member)).to be false
|
||||
|
||||
click_link 'Follow'
|
||||
expect(page).to have_current_path(member_path(other_member))
|
||||
expect(page).to have_content "Followed #{other_member.login_name}"
|
||||
|
||||
member.reload
|
||||
expect(member.already_following?(other_member)).to be true
|
||||
|
||||
click_link 'Unfollow'
|
||||
expect(page).to have_current_path(member_path(other_member))
|
||||
expect(page).to have_content "Unfollowed #{other_member.login_name}"
|
||||
member.reload
|
||||
expect(member.already_following?(other_member)).to be false
|
||||
|
||||
visit member_follows_path(member)
|
||||
expect(page).to have_no_content other_member.login_name
|
||||
visit member_followers_path(other_member)
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.feature "Commenting on Photos", type: :feature, js: true do
|
||||
let(:photo_owner) { FactoryBot.create(:member, login_name: "PhotoOwner") }
|
||||
let(:commenter) { FactoryBot.create(:member, login_name: "Commenter") }
|
||||
let(:other_member) { FactoryBot.create(:member, login_name: "OtherMember") }
|
||||
let(:admin) { FactoryBot.create(:member, :admin, login_name: "AdminUser") }
|
||||
|
||||
let!(:photo) { FactoryBot.create(:photo, owner: photo_owner, title: "Beautiful Sunset") }
|
||||
|
||||
def login_as(user)
|
||||
visit new_member_session_path
|
||||
fill_in "Login Name or Email", with: user.login_name
|
||||
fill_in "Password", with: user.password
|
||||
click_button "Log in"
|
||||
expect(page).to have_content("Signed in successfully")
|
||||
end
|
||||
|
||||
describe "User comments on a Photo" do
|
||||
before do
|
||||
login_as(commenter)
|
||||
visit photo_path(photo)
|
||||
end
|
||||
|
||||
it "allows a user to create a comment" do
|
||||
expect(page).to have_content("Comments")
|
||||
click_link "Add Comment" # From the _comments partial
|
||||
|
||||
expect(page).to have_current_path(new_photo_comment_path(photo))
|
||||
expect(page).to have_content("Add comment to photo")
|
||||
|
||||
fill_in "comment_body", with: "What a stunning photo!"
|
||||
click_button "Post comment"
|
||||
|
||||
expect(page).to have_current_path(photo_path(photo))
|
||||
expect(page).to have_content("What a stunning photo!")
|
||||
expect(page).to have_content(commenter.login_name)
|
||||
end
|
||||
end
|
||||
|
||||
describe "Editing comments on a Photo" do
|
||||
let!(:comment_to_edit) { FactoryBot.create(:comment, commentable: photo, author: commenter, body: "Initial comment body") }
|
||||
|
||||
context "as comment author" do
|
||||
before do
|
||||
login_as(commenter)
|
||||
visit photo_path(photo)
|
||||
# Find the comment section and then the edit button within it.
|
||||
# This assumes the comment body is unique enough or we can find by specific data-testid attributes if added.
|
||||
find('.comment-body', text: "Initial comment body").ancestor('.comment').find_button('Actions').click
|
||||
click_link "Edit"
|
||||
end
|
||||
|
||||
it "allows the author to edit their comment" do
|
||||
expect(page).to have_current_path(edit_comment_path(comment_to_edit))
|
||||
fill_in "comment_body", with: "Updated comment body here."
|
||||
click_button "Post comment"
|
||||
|
||||
expect(page).to have_current_path(photo_path(photo))
|
||||
expect(page).to have_content("Updated comment body here.")
|
||||
expect(page).not_to have_content("Initial comment body")
|
||||
end
|
||||
end
|
||||
|
||||
context "as admin" do
|
||||
before do
|
||||
login_as(admin)
|
||||
visit photo_path(photo)
|
||||
find('.comment-body', text: "Initial comment body").ancestor('.comment').find_button('Actions').click
|
||||
click_link "Edit"
|
||||
end
|
||||
|
||||
it "allows admin to edit any comment" do
|
||||
fill_in "comment_body", with: "Admin edited this comment."
|
||||
click_button "Post comment"
|
||||
expect(page).to have_content("Admin edited this comment.")
|
||||
end
|
||||
end
|
||||
|
||||
context "as unauthorized user" do
|
||||
before do
|
||||
login_as(other_member)
|
||||
visit photo_path(photo)
|
||||
end
|
||||
|
||||
it "does not show edit link for other's comment" do
|
||||
# Check within the specific comment's scope
|
||||
comment_element = find('.comment-body', text: "Initial comment body").ancestor('.comment')
|
||||
expect(comment_element).not_to have_link("Edit")
|
||||
expect(comment_element).not_to have_button("Actions") # Or check that Actions doesn't show Edit
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "Deleting comments on a Photo" do
|
||||
let!(:comment_to_delete) { FactoryBot.create(:comment, commentable: photo, author: commenter, body: "This will be deleted") }
|
||||
|
||||
context "as comment author" do
|
||||
before do
|
||||
login_as(commenter)
|
||||
visit photo_path(photo)
|
||||
find('.comment-body', text: "This will be deleted").ancestor('.comment').find_button('Actions').click
|
||||
accept_alert { click_link "Delete" }
|
||||
end
|
||||
|
||||
it "allows the author to delete their comment" do
|
||||
expect(page).not_to have_content("This will be deleted")
|
||||
expect(page).to have_content("Comment was successfully destroyed.") # Assuming flash message
|
||||
end
|
||||
end
|
||||
|
||||
context "as photo owner" do
|
||||
before do
|
||||
login_as(photo_owner)
|
||||
visit photo_path(photo)
|
||||
find('.comment-body', text: "This will be deleted").ancestor('.comment').find_button('Actions').click
|
||||
accept_alert { click_link "Delete" }
|
||||
end
|
||||
|
||||
it "allows the photo owner to delete any comment on their photo" do
|
||||
expect(page).not_to have_content("This will be deleted")
|
||||
expect(page).to have_content("Comment was successfully destroyed.")
|
||||
end
|
||||
end
|
||||
|
||||
context "as admin" do
|
||||
before do
|
||||
login_as(admin)
|
||||
visit photo_path(photo)
|
||||
find('.comment-body', text: "This will be deleted").ancestor('.comment').find_button('Actions').click
|
||||
accept_alert { click_link "Delete" }
|
||||
end
|
||||
|
||||
it "allows admin to delete any comment" do
|
||||
expect(page).not_to have_content("This will be deleted")
|
||||
expect(page).to have_content("Comment was successfully destroyed.")
|
||||
end
|
||||
end
|
||||
|
||||
context "as unauthorized user" do
|
||||
let!(:another_comment) { FactoryBot.create(:comment, commentable: photo, author: photo_owner, body: "Photo owner's comment") }
|
||||
before do
|
||||
login_as(other_member) # other_member is not admin, not photo_owner, not author of `another_comment`
|
||||
visit photo_path(photo)
|
||||
end
|
||||
|
||||
it "does not show delete link for other's comment" do
|
||||
comment_element = find('.comment-body', text: "Photo owner's comment").ancestor('.comment')
|
||||
expect(comment_element).not_to have_link("Delete")
|
||||
# Also check the original comment_to_delete by commenter
|
||||
comment_element_2 = find('.comment-body', text: "This will be deleted").ancestor('.comment')
|
||||
expect(comment_element_2).not_to have_link("Delete")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,158 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.feature "Commenting on Plantings", type: :feature, js: true do
|
||||
let(:planting_owner) { FactoryBot.create(:member, login_name: "PlantingOwner") }
|
||||
let(:commenter) { FactoryBot.create(:member, login_name: "Commenter") }
|
||||
let(:other_member) { FactoryBot.create(:member, login_name: "OtherMember") }
|
||||
let(:admin) { FactoryBot.create(:member, :admin, login_name: "AdminUser") }
|
||||
|
||||
# Ensure crop and garden are created for the planting
|
||||
let(:crop) { FactoryBot.create(:crop) }
|
||||
let(:garden) { FactoryBot.create(:garden, owner: planting_owner) }
|
||||
let!(:planting) { FactoryBot.create(:planting, owner: planting_owner, crop: crop, garden: garden, description: "My test planting") }
|
||||
|
||||
def login_as(user)
|
||||
visit new_member_session_path
|
||||
fill_in "Login Name or Email", with: user.login_name
|
||||
fill_in "Password", with: user.password
|
||||
click_button "Log in"
|
||||
expect(page).to have_content("Signed in successfully")
|
||||
end
|
||||
|
||||
describe "User comments on a Planting" do
|
||||
before do
|
||||
login_as(commenter)
|
||||
visit planting_path(planting)
|
||||
end
|
||||
|
||||
it "allows a user to create a comment" do
|
||||
expect(page).to have_content("Comments")
|
||||
click_link "Add Comment"
|
||||
|
||||
expect(page).to have_current_path(new_planting_comment_path(planting))
|
||||
expect(page).to have_content("Add comment to planting")
|
||||
|
||||
fill_in "comment_body", with: "This planting looks great!"
|
||||
click_button "Post comment"
|
||||
|
||||
expect(page).to have_current_path(planting_path(planting))
|
||||
expect(page).to have_content("This planting looks great!")
|
||||
expect(page).to have_content(commenter.login_name)
|
||||
end
|
||||
end
|
||||
|
||||
describe "Editing comments on a Planting" do
|
||||
let!(:comment_to_edit) { FactoryBot.create(:comment, commentable: planting, author: commenter, body: "Initial planting comment") }
|
||||
|
||||
context "as comment author" do
|
||||
before do
|
||||
login_as(commenter)
|
||||
visit planting_path(planting)
|
||||
find('.comment-body', text: "Initial planting comment").ancestor('.comment').find_button('Actions').click
|
||||
click_link "Edit"
|
||||
end
|
||||
|
||||
it "allows the author to edit their comment" do
|
||||
expect(page).to have_current_path(edit_comment_path(comment_to_edit))
|
||||
fill_in "comment_body", with: "Updated planting comment."
|
||||
click_button "Post comment"
|
||||
|
||||
expect(page).to have_current_path(planting_path(planting))
|
||||
expect(page).to have_content("Updated planting comment.")
|
||||
expect(page).not_to have_content("Initial planting comment")
|
||||
end
|
||||
end
|
||||
|
||||
context "as admin" do
|
||||
before do
|
||||
login_as(admin)
|
||||
visit planting_path(planting)
|
||||
find('.comment-body', text: "Initial planting comment").ancestor('.comment').find_button('Actions').click
|
||||
click_link "Edit"
|
||||
end
|
||||
|
||||
it "allows admin to edit any comment" do
|
||||
fill_in "comment_body", with: "Admin edited this planting comment."
|
||||
click_button "Post comment"
|
||||
expect(page).to have_content("Admin edited this planting comment.")
|
||||
end
|
||||
end
|
||||
|
||||
context "as unauthorized user" do
|
||||
before do
|
||||
login_as(other_member)
|
||||
visit planting_path(planting)
|
||||
end
|
||||
|
||||
it "does not show edit link for other's comment" do
|
||||
comment_element = find('.comment-body', text: "Initial planting comment").ancestor('.comment')
|
||||
expect(comment_element).not_to have_link("Edit")
|
||||
expect(comment_element).not_to have_button("Actions")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "Deleting comments on a Planting" do
|
||||
let!(:comment_to_delete) { FactoryBot.create(:comment, commentable: planting, author: commenter, body: "Delete this planting comment") }
|
||||
|
||||
context "as comment author" do
|
||||
before do
|
||||
login_as(commenter)
|
||||
visit planting_path(planting)
|
||||
find('.comment-body', text: "Delete this planting comment").ancestor('.comment').find_button('Actions').click
|
||||
accept_alert { click_link "Delete" }
|
||||
end
|
||||
|
||||
it "allows the author to delete their comment" do
|
||||
expect(page).not_to have_content("Delete this planting comment")
|
||||
expect(page).to have_content("Comment was successfully destroyed.")
|
||||
end
|
||||
end
|
||||
|
||||
context "as planting owner" do
|
||||
before do
|
||||
login_as(planting_owner)
|
||||
visit planting_path(planting)
|
||||
find('.comment-body', text: "Delete this planting comment").ancestor('.comment').find_button('Actions').click
|
||||
accept_alert { click_link "Delete" }
|
||||
end
|
||||
|
||||
it "allows the planting owner to delete any comment on their planting" do
|
||||
expect(page).not_to have_content("Delete this planting comment")
|
||||
expect(page).to have_content("Comment was successfully destroyed.")
|
||||
end
|
||||
end
|
||||
|
||||
context "as admin" do
|
||||
before do
|
||||
login_as(admin)
|
||||
visit planting_path(planting)
|
||||
find('.comment-body', text: "Delete this planting comment").ancestor('.comment').find_button('Actions').click
|
||||
accept_alert { click_link "Delete" }
|
||||
end
|
||||
|
||||
it "allows admin to delete any comment" do
|
||||
expect(page).not_to have_content("Delete this planting comment")
|
||||
expect(page).to have_content("Comment was successfully destroyed.")
|
||||
end
|
||||
end
|
||||
|
||||
context "as unauthorized user" do
|
||||
let!(:another_comment) { FactoryBot.create(:comment, commentable: planting, author: planting_owner, body: "Planting owner's comment") }
|
||||
before do
|
||||
login_as(other_member)
|
||||
visit planting_path(planting)
|
||||
end
|
||||
|
||||
it "does not show delete link for other's comment" do
|
||||
comment_element = find('.comment-body', text: "Planting owner's comment").ancestor('.comment')
|
||||
expect(comment_element).not_to have_link("Delete")
|
||||
|
||||
comment_element_2 = find('.comment-body', text: "Delete this planting comment").ancestor('.comment')
|
||||
expect(comment_element_2).not_to have_link("Delete")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -18,6 +18,10 @@ describe "Planting a crop", :js, :search do
|
||||
|
||||
it_behaves_like "crop suggest", "planting"
|
||||
|
||||
it "has the required fields help text" do
|
||||
expect(page).to have_content "* denotes a required field"
|
||||
end
|
||||
|
||||
describe "displays required and optional fields properly" do
|
||||
it { expect(page).to have_selector ".required", text: "What did you plant?" }
|
||||
it { expect(page).to have_selector ".required", text: "Where did you plant it?" }
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.feature "Commenting on Posts", type: :feature, js: true do
|
||||
# Use existing 'signed in member' shared context if it provides Capybara login helper
|
||||
# Otherwise, define one locally or ensure one is available.
|
||||
# For consistency with other new specs, defining a local login_as helper.
|
||||
let(:post_author) { FactoryBot.create(:member, login_name: "PostAuthor") }
|
||||
let(:commenter) { FactoryBot.create(:member, login_name: "Commenter") }
|
||||
let(:other_member) { FactoryBot.create(:member, login_name: "OtherMember") }
|
||||
let(:admin) { FactoryBot.create(:member, :admin, login_name: "AdminUser") }
|
||||
|
||||
# Ensure a forum is created for the post if your Post factory/model requires it
|
||||
let!(:forum) { FactoryBot.create(:forum) }
|
||||
let!(:post) { FactoryBot.create(:post, author: post_author, forum: forum, subject: "My Test Post") }
|
||||
|
||||
def login_as(user)
|
||||
visit new_member_session_path
|
||||
fill_in "Login Name or Email", with: user.login_name
|
||||
fill_in "Password", with: user.password
|
||||
click_button "Log in"
|
||||
expect(page).to have_content("Signed in successfully")
|
||||
end
|
||||
|
||||
# Include shared examples for accessibility if they exist and are relevant
|
||||
# For now, focusing on the commenting CRUD operations.
|
||||
# The original spec had: include_examples 'is accessible'
|
||||
# If this shared example exists and is desired, it can be added to relevant `before` blocks.
|
||||
|
||||
describe "User comments on a Post" do
|
||||
before do
|
||||
login_as(commenter)
|
||||
visit post_path(post)
|
||||
end
|
||||
|
||||
it "allows a user to create a comment" do
|
||||
expect(page).to have_content("Comments") # From the _comments partial
|
||||
# The "Add Comment" link is now within the _comments partial
|
||||
# If the _comments partial is set up to show the form directly or link to new, this will work.
|
||||
# Assuming it has a link:
|
||||
click_link "Add Comment"
|
||||
|
||||
expect(page).to have_current_path(new_post_comment_path(post))
|
||||
expect(page).to have_content("Add comment to post")
|
||||
|
||||
fill_in "comment_body", with: "This is a great post!"
|
||||
click_button "Post comment"
|
||||
|
||||
expect(page).to have_current_path(post_path(post)) # Should redirect back to the post
|
||||
expect(page).to have_content("This is a great post!")
|
||||
expect(page).to have_content(commenter.login_name)
|
||||
# Check for flash message if your controller sets one, e.g.:
|
||||
# expect(page).to have_content("Comment was successfully created.")
|
||||
end
|
||||
end
|
||||
|
||||
describe "Editing comments on a Post" do
|
||||
let!(:comment_to_edit) { FactoryBot.create(:comment, commentable: post, author: commenter, body: "Initial post comment") }
|
||||
|
||||
context "as comment author" do
|
||||
before do
|
||||
login_as(commenter)
|
||||
visit post_path(post)
|
||||
find('.comment-body', text: "Initial post comment").ancestor('.comment').find_button('Actions').click
|
||||
click_link "Edit"
|
||||
end
|
||||
|
||||
it "allows the author to edit their comment" do
|
||||
expect(page).to have_current_path(edit_comment_path(comment_to_edit))
|
||||
fill_in "comment_body", with: "Updated post comment."
|
||||
click_button "Post comment"
|
||||
|
||||
expect(page).to have_current_path(post_path(post))
|
||||
expect(page).to have_content("Updated post comment.")
|
||||
expect(page).not_to have_content("Initial post comment")
|
||||
# Check for flash message if your controller sets one, e.g.:
|
||||
# expect(page).to have_content("Comment was successfully updated.")
|
||||
end
|
||||
end
|
||||
|
||||
context "as admin" do
|
||||
before do
|
||||
login_as(admin)
|
||||
visit post_path(post)
|
||||
find('.comment-body', text: "Initial post comment").ancestor('.comment').find_button('Actions').click
|
||||
click_link "Edit"
|
||||
end
|
||||
|
||||
it "allows admin to edit any comment" do
|
||||
fill_in "comment_body", with: "Admin edited this post comment."
|
||||
click_button "Post comment"
|
||||
expect(page).to have_content("Admin edited this post comment.")
|
||||
end
|
||||
end
|
||||
|
||||
context "as unauthorized user" do
|
||||
before do
|
||||
login_as(other_member)
|
||||
visit post_path(post)
|
||||
end
|
||||
|
||||
it "does not show edit link for other's comment" do
|
||||
comment_element = find('.comment-body', text: "Initial post comment").ancestor('.comment')
|
||||
expect(comment_element).not_to have_link("Edit")
|
||||
expect(comment_element).not_to have_button("Actions")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "Deleting comments on a Post" do
|
||||
let!(:comment_to_delete) { FactoryBot.create(:comment, commentable: post, author: commenter, body: "Delete this post comment") }
|
||||
|
||||
context "as comment author" do
|
||||
before do
|
||||
login_as(commenter)
|
||||
visit post_path(post)
|
||||
find('.comment-body', text: "Delete this post comment").ancestor('.comment').find_button('Actions').click
|
||||
accept_alert { click_link "Delete" }
|
||||
end
|
||||
|
||||
it "allows the author to delete their comment" do
|
||||
expect(page).not_to have_content("Delete this post comment")
|
||||
expect(page).to have_content("Comment was successfully destroyed.") # Assuming flash message
|
||||
end
|
||||
end
|
||||
|
||||
context "as post author (owner of commentable)" do
|
||||
before do
|
||||
# Ensure commenter is not the post_author for this specific test
|
||||
expect(commenter).not_to eq(post_author)
|
||||
login_as(post_author)
|
||||
visit post_path(post)
|
||||
find('.comment-body', text: "Delete this post comment").ancestor('.comment').find_button('Actions').click
|
||||
accept_alert { click_link "Delete" }
|
||||
end
|
||||
|
||||
it "allows the post author to delete any comment on their post" do
|
||||
expect(page).not_to have_content("Delete this post comment")
|
||||
expect(page).to have_content("Comment was successfully destroyed.")
|
||||
end
|
||||
end
|
||||
|
||||
context "as admin" do
|
||||
before do
|
||||
login_as(admin)
|
||||
visit post_path(post)
|
||||
find('.comment-body', text: "Delete this post comment").ancestor('.comment').find_button('Actions').click
|
||||
accept_alert { click_link "Delete" }
|
||||
end
|
||||
|
||||
it "allows admin to delete any comment" do
|
||||
expect(page).not_to have_content("Delete this post comment")
|
||||
expect(page).to have_content("Comment was successfully destroyed.")
|
||||
end
|
||||
end
|
||||
|
||||
context "as unauthorized user" do
|
||||
# Create a comment by the post_author to test against
|
||||
let!(:another_comment) { FactoryBot.create(:comment, commentable: post, author: post_author, body: "Post author's comment") }
|
||||
before do
|
||||
login_as(other_member) # other_member is not admin, not post_author, not author of `another_comment`
|
||||
visit post_path(post)
|
||||
end
|
||||
|
||||
it "does not show delete link for other's comment" do
|
||||
comment_element = find('.comment-body', text: "Post author's comment").ancestor('.comment')
|
||||
expect(comment_element).not_to have_link("Delete")
|
||||
|
||||
# Also check the original comment_to_delete by commenter
|
||||
comment_element_2 = find('.comment-body', text: "Delete this post comment").ancestor('.comment')
|
||||
expect(comment_element_2).not_to have_link("Delete")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -12,6 +12,10 @@ describe "Seeds", :js, :search do
|
||||
|
||||
it_behaves_like "crop suggest", "seed", "crop"
|
||||
|
||||
it "has the required fields help text" do
|
||||
expect(page).to have_content "* denotes a required field"
|
||||
end
|
||||
|
||||
describe "displays required and optional fields properly" do
|
||||
# NOTE: The required behaviour is pushed down to the control itself, not the form-group as of rails 7.1.
|
||||
# Modern browsers enforce the required behaviour better than us doing it ourselves.
|
||||
|
||||
@@ -10,6 +10,13 @@ describe ApplicationHelper do
|
||||
parse_date('may 12th 2012').should eq Date.new(2012, 5, 12)
|
||||
end
|
||||
|
||||
it "shows required field marker help text with proper formatting" do
|
||||
output = required_field_help_text
|
||||
expect(output).to have_selector '.margin-bottom'
|
||||
expect(output).to have_selector '.red', text: '*'
|
||||
expect(output).to have_selector 'em', text: 'denotes a required field'
|
||||
end
|
||||
|
||||
describe '#avatar_uri' do
|
||||
context 'with a normal user' do
|
||||
before do
|
||||
|
||||
@@ -3,152 +3,53 @@
|
||||
require 'rails_helper'
|
||||
|
||||
describe Comment do
|
||||
context "associations" do
|
||||
let(:member) { FactoryBot.create(:member) } # Common author
|
||||
context "basic" do
|
||||
let(:comment) { FactoryBot.create(:comment) }
|
||||
|
||||
it "belongs to a commentable (Post)" do
|
||||
post = FactoryBot.create(:post, author: member)
|
||||
comment = FactoryBot.create(:comment, commentable: post, author: member)
|
||||
comment.commentable.should be_an_instance_of Post
|
||||
end
|
||||
|
||||
it "belongs to a commentable (Photo)" do
|
||||
photo = FactoryBot.create(:photo, owner: member)
|
||||
comment = FactoryBot.create(:comment, commentable: photo, author: member)
|
||||
comment.commentable.should be_an_instance_of Photo
|
||||
end
|
||||
|
||||
it "belongs to a commentable (Planting)" do
|
||||
planting = FactoryBot.create(:planting, owner: member)
|
||||
comment = FactoryBot.create(:comment, commentable: planting, author: member)
|
||||
comment.commentable.should be_an_instance_of Planting
|
||||
end
|
||||
|
||||
it "belongs to a commentable (Harvest)" do
|
||||
harvest = FactoryBot.create(:harvest, owner: member)
|
||||
comment = FactoryBot.create(:comment, commentable: harvest, author: member)
|
||||
comment.commentable.should be_an_instance_of Harvest
|
||||
end
|
||||
|
||||
it "belongs to a commentable (Activity)" do
|
||||
activity = FactoryBot.create(:activity, owner: member)
|
||||
comment = FactoryBot.create(:comment, commentable: activity, author: member)
|
||||
comment.commentable.should be_an_instance_of Activity
|
||||
it "belongs to a post" do
|
||||
comment.post.should be_an_instance_of Post
|
||||
end
|
||||
|
||||
it "belongs to an author" do
|
||||
comment = FactoryBot.create(:comment, author: member) # Default commentable is Post
|
||||
comment.author.should be_an_instance_of Member
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.shared_examples "comment notifications" do |commentable_type, commentable_factory_name|
|
||||
let(:commentable_owner) { FactoryBot.create(:member) }
|
||||
let(:comment_author) { FactoryBot.create(:member) }
|
||||
let!(:commentable) do
|
||||
# For :post, the owner is :author. For others, it's :owner.
|
||||
if commentable_factory_name == :post
|
||||
FactoryBot.create(commentable_factory_name, author: commentable_owner)
|
||||
else
|
||||
FactoryBot.create(commentable_factory_name, owner: commentable_owner)
|
||||
end
|
||||
end
|
||||
|
||||
context "notifications" do
|
||||
it "sends a notification when a comment is posted" do
|
||||
expect do
|
||||
FactoryBot.create(:comment, commentable: commentable, author: comment_author)
|
||||
FactoryBot.create(:comment)
|
||||
end.to change(Notification, :count).by(1)
|
||||
end
|
||||
|
||||
it "sets the notification fields correctly" do
|
||||
comment = FactoryBot.create(:comment, commentable: commentable, author: comment_author)
|
||||
notification = Notification.last # More robust than Notification.first
|
||||
notification.sender.should eq comment.author
|
||||
notification.recipient.should eq commentable_owner
|
||||
notification.subject.should include "commented on your #{commentable_type.downcase}"
|
||||
notification.body.should eq comment.body
|
||||
notification.commentable_id.should eq commentable.id
|
||||
notification.commentable_type.should eq commentable_type
|
||||
it "sets the notification fields" do
|
||||
@c = FactoryBot.create(:comment)
|
||||
@n = Notification.first
|
||||
@n.sender.should eq @c.author
|
||||
@n.recipient.should eq @c.post.author
|
||||
@n.subject.should include 'commented on'
|
||||
@n.body.should eq @c.body
|
||||
@n.post.should eq @c.post
|
||||
end
|
||||
|
||||
it "doesn't send notifications to yourself (when comment author is commentable owner)" do
|
||||
it "doesn't send notifications to yourself" do
|
||||
@m = FactoryBot.create(:member)
|
||||
@p = FactoryBot.create(:post, author: @m)
|
||||
expect do
|
||||
FactoryBot.create(:comment, commentable: commentable, author: commentable_owner)
|
||||
FactoryBot.create(:comment, post: @p, author: @m)
|
||||
end.not_to change(Notification, :count)
|
||||
end
|
||||
end
|
||||
|
||||
context "notifications for Post" do
|
||||
include_examples "comment notifications", "Post", :post
|
||||
end
|
||||
|
||||
context "notifications for Photo" do
|
||||
include_examples "comment notifications", "Photo", :photo
|
||||
end
|
||||
|
||||
context "notifications for Planting" do
|
||||
include_examples "comment notifications", "Planting", :planting
|
||||
end
|
||||
|
||||
context "notifications for Harvest" do
|
||||
include_examples "comment notifications", "Harvest", :harvest
|
||||
end
|
||||
|
||||
context "notifications for Activity" do
|
||||
include_examples "comment notifications", "Activity", :activity
|
||||
end
|
||||
|
||||
RSpec.shared_examples "comment to_s method" do |commentable_type, commentable_factory_name|
|
||||
let(:commentable_owner) { FactoryBot.create(:member) }
|
||||
let(:comment_author) { FactoryBot.create(:member, login_name: "CommenterUser") }
|
||||
let!(:commentable) do
|
||||
# For :post, the owner is :author. For others, it's :owner.
|
||||
obj = if commentable_factory_name == :post
|
||||
FactoryBot.create(commentable_factory_name, author: commentable_owner)
|
||||
else
|
||||
FactoryBot.create(commentable_factory_name, owner: commentable_owner)
|
||||
end
|
||||
# Ensure commentable has a consistent ID for the test if possible, or just use its class name
|
||||
obj
|
||||
end
|
||||
let(:comment) { FactoryBot.create(:comment, commentable: commentable, author: comment_author) }
|
||||
|
||||
it "returns a descriptive string" do
|
||||
expected_string = "#{comment_author.login_name} commented on #{commentable_type.downcase} ##{commentable.id}"
|
||||
comment.to_s.should eq expected_string
|
||||
end
|
||||
end
|
||||
|
||||
context "to_s method for Post" do
|
||||
include_examples "comment to_s method", "Post", :post
|
||||
end
|
||||
|
||||
context "to_s method for Photo" do
|
||||
include_examples "comment to_s method", "Photo", :photo
|
||||
end
|
||||
|
||||
context "to_s method for Planting" do
|
||||
include_examples "comment to_s method", "Planting", :planting
|
||||
end
|
||||
|
||||
context "to_s method for Harvest" do
|
||||
include_examples "comment to_s method", "Harvest", :harvest
|
||||
end
|
||||
|
||||
context "to_s method for Activity" do
|
||||
include_examples "comment to_s method", "Activity", :activity
|
||||
end
|
||||
|
||||
context "ordering" do
|
||||
before do
|
||||
@m = FactoryBot.create(:member)
|
||||
# Ensure the commentable for ordering test is a Post, as it was originally
|
||||
@p = FactoryBot.create(:post, author: @m)
|
||||
@c1 = FactoryBot.create(:comment, commentable: @p, author: @m)
|
||||
@c2 = FactoryBot.create(:comment, commentable: @p, author: @m)
|
||||
@c1 = FactoryBot.create(:comment, post: @p, author: @m)
|
||||
@c2 = FactoryBot.create(:comment, post: @p, author: @m)
|
||||
end
|
||||
|
||||
it 'has a scope for ASC order for displaying on commentable page' do # Renamed for clarity
|
||||
it 'has a scope for ASC order for displaying on post page' do
|
||||
described_class.post_order.should eq [@c1, @c2]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,6 +7,9 @@ require 'simplecov'
|
||||
# output coverage locally AND send it to coveralls
|
||||
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([SimpleCov::Formatter::HTMLFormatter])
|
||||
|
||||
# fail if there's a significant test coverage drop
|
||||
SimpleCov.maximum_coverage_drop 1
|
||||
|
||||
require 'spec_helper'
|
||||
require File.expand_path('../config/environment', __dir__)
|
||||
require 'rspec/rails'
|
||||
|
||||
Reference in New Issue
Block a user