├── .codeclimate.yml ├── .devcontainer ├── .env ├── Dockerfile ├── create-db-user.sql ├── devcontainer.json └── docker-compose.yml ├── .editorconfig ├── .esignore ├── .eslintrc.json ├── .github ├── dependabot.yml └── workflows │ ├── ci-features-admin.yml │ ├── ci-features-comments.yml │ ├── ci-features-conversations.yml │ ├── ci-features-crops.yml │ ├── ci-features-gardens.yml │ ├── ci-features-harvests.yml │ ├── ci-features-home.yml │ ├── ci-features-members.yml │ ├── ci-features-plantings.yml │ ├── ci-features-seeds.yml │ ├── ci-features-timeline.yml │ ├── ci-features.yml │ └── ci.yml ├── .gitignore ├── .haml-lint.yml ├── .overcommit.yml ├── .rspec ├── .rubocop.yml ├── .rubocop_todo.yml ├── .ruby-gemset ├── .ruby-version ├── .scss-lint.yml ├── .travis.yml ├── .yamllint ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── CONTRIBUTORS.md ├── Gemfile ├── Gemfile.lock ├── Guardfile ├── LICENSE.txt ├── Procfile ├── README.md ├── Rakefile ├── TECH.md ├── app.json ├── app ├── assets │ ├── config │ │ └── manifest.js │ ├── images │ │ ├── blog_32.png │ │ ├── email_32.png │ │ ├── facebook-login-splash.png │ │ ├── facebook-thumbnail.png │ │ ├── facebook_32.png │ │ ├── favicon.ico │ │ ├── flickr_32.png │ │ ├── growstuff-apple-touch-icon-precomposed.png │ │ ├── growstuff-brand.png │ │ ├── icons │ │ │ ├── COPYRIGHT │ │ │ ├── activity-add.svg │ │ │ ├── add-photo.svg │ │ │ ├── ant.svg │ │ │ ├── bee.svg │ │ │ ├── bug.svg │ │ │ ├── butterfly.svg │ │ │ ├── cat.svg │ │ │ ├── delete.svg │ │ │ ├── earth-worm.svg │ │ │ ├── edit.svg │ │ │ ├── finish.svg │ │ │ ├── finished.svg │ │ │ ├── gardener.svg │ │ │ ├── gardens.svg │ │ │ ├── grass.svg │ │ │ ├── growing.svg │ │ │ ├── harvest-add.svg │ │ │ ├── harvest.svg │ │ │ ├── hose.svg │ │ │ ├── insect.svg │ │ │ ├── ladybird.svg │ │ │ ├── notification.svg │ │ │ ├── photo.svg │ │ │ ├── plant_parts │ │ │ │ ├── bark.svg │ │ │ │ ├── bulb.svg │ │ │ │ ├── flower.svg │ │ │ │ ├── fruit.svg │ │ │ │ ├── leaf.svg │ │ │ │ ├── other.svg │ │ │ │ ├── pod.svg │ │ │ │ ├── root.svg │ │ │ │ ├── seed.svg │ │ │ │ ├── stem.svg │ │ │ │ ├── tuber.svg │ │ │ │ └── whole plant.svg │ │ │ ├── planting-add.svg │ │ │ ├── planting-hand.svg │ │ │ ├── planting-sun.svg │ │ │ ├── planting.svg │ │ │ ├── post.svg │ │ │ ├── rabbit.svg │ │ │ ├── seed-add.svg │ │ │ ├── seeds.svg │ │ │ ├── slug-eating.svg │ │ │ ├── slug.svg │ │ │ ├── snail.svg │ │ │ ├── spiderweb.svg │ │ │ ├── sprinkler.svg │ │ │ ├── sprout-add.svg │ │ │ ├── sprout.svg │ │ │ ├── stones.svg │ │ │ ├── timeline.svg │ │ │ ├── trade.svg │ │ │ ├── watering-can.svg │ │ │ └── wheelbarrow.svg │ │ ├── location-not-set.en.png │ │ ├── open_service.png │ │ ├── pear.png │ │ ├── placeholder.xcf │ │ ├── placeholder_600.png │ │ ├── spade-marker.svg │ │ ├── sunniness_not_specified.png │ │ ├── sunniness_semi-shade.png │ │ ├── sunniness_shade.png │ │ ├── sunniness_sun.png │ │ └── twitter_32.png │ ├── javascripts │ │ ├── append_date.js.coffee │ │ ├── application.js │ │ ├── auto_suggest.js.coffee │ │ ├── charts.js │ │ ├── comfy │ │ │ └── admin │ │ │ │ └── cms │ │ │ │ └── custom.js.coffee │ │ ├── cropmap.js.erb │ │ ├── crops.js.coffee │ │ ├── datepicker.js │ │ ├── editable.js │ │ ├── finish_planting.js.coffee │ │ ├── finish_seed.js.coffee │ │ ├── highcharts.js │ │ ├── likes.js │ │ ├── members.js.erb │ │ ├── places.js.erb │ │ ├── scientific_name_auto_suggest.js.coffee │ │ ├── tab_navigation.js │ │ └── tooltips.js │ └── stylesheets │ │ ├── _crops.scss │ │ ├── _harvests.scss │ │ ├── _homepage.scss │ │ ├── _likes.scss │ │ ├── _maps.scss │ │ ├── _members.scss │ │ ├── _notifications.scss │ │ ├── _photos.scss │ │ ├── _plantings.scss │ │ ├── _posts.scss │ │ ├── _predictions.scss │ │ ├── _seeds.scss │ │ ├── _variables.scss │ │ ├── application.scss │ │ ├── leaflet_overrides.scss │ │ ├── mobile.scss │ │ └── overrides.scss ├── controllers │ ├── activities_controller.rb │ ├── admin │ │ ├── members_controller.rb │ │ └── roles_controller.rb │ ├── admin_controller.rb │ ├── alternate_names_controller.rb │ ├── api │ │ └── v1 │ │ │ ├── base_controller.rb │ │ │ ├── crops_controller.rb │ │ │ ├── gardens_controller.rb │ │ │ ├── harvests_controller.rb │ │ │ ├── members_controller.rb │ │ │ ├── photos_controller.rb │ │ │ ├── plantings_controller.rb │ │ │ └── seeds_controller.rb │ ├── application_controller.rb │ ├── authentications_controller.rb │ ├── charts │ │ ├── crops_controller.rb │ │ └── gardens_controller.rb │ ├── comments_controller.rb │ ├── conversations_controller.rb │ ├── crops_controller.rb │ ├── data_controller.rb │ ├── follows_controller.rb │ ├── forums_controller.rb │ ├── garden_collaborators_controller.rb │ ├── garden_types_controller.rb │ ├── gardens_controller.rb │ ├── harvests_controller.rb │ ├── home_controller.rb │ ├── likes_controller.rb │ ├── members_controller.rb │ ├── messages_controller.rb │ ├── omniauth_callbacks_controller.rb │ ├── pages_controller.rb │ ├── passwords_controller.rb │ ├── photo_associations_controller.rb │ ├── photos_controller.rb │ ├── places_controller.rb │ ├── plant_parts_controller.rb │ ├── plantings_controller.rb │ ├── posts_controller.rb │ ├── registrations_controller.rb │ ├── robots_controller.rb │ ├── scientific_names_controller.rb │ ├── seeds_controller.rb │ ├── sessions_controller.rb │ └── timeline_controller.rb ├── helpers │ ├── application_helper.rb │ ├── auto_suggest_helper.rb │ ├── buttons_helper.rb │ ├── crops_helper.rb │ ├── editable_form_helper.rb │ ├── event_helper.rb │ ├── gardens_helper.rb │ ├── harvests_helper.rb │ ├── icons_helper.rb │ ├── photos_helper.rb │ ├── plantings_helper.rb │ ├── posts_helper.rb │ └── seeds_helper.rb ├── jobs │ └── application_job.rb ├── mailers │ ├── .gitkeep │ ├── application_mailer.rb │ └── notifier_mailer.rb ├── models │ ├── .gitkeep │ ├── ability.rb │ ├── activity.rb │ ├── alternate_name.rb │ ├── application_record.rb │ ├── authentication.rb │ ├── comment.rb │ ├── concerns │ │ ├── finishable.rb │ │ ├── gbif_data.rb │ │ ├── likeable.rb │ │ ├── member_flickr.rb │ │ ├── member_newsletter.rb │ │ ├── open_farm_data.rb │ │ ├── ownable.rb │ │ ├── photo_capable.rb │ │ ├── predict_harvest.rb │ │ ├── predict_planting.rb │ │ ├── search_activities.rb │ │ ├── search_crops.rb │ │ ├── search_harvests.rb │ │ ├── search_photos.rb │ │ ├── search_plantings.rb │ │ └── search_seeds.rb │ ├── crop.rb │ ├── crop_companion.rb │ ├── crop_post.rb │ ├── csv_importer.rb │ ├── follow.rb │ ├── forum.rb │ ├── garden.rb │ ├── garden_collaborator.rb │ ├── garden_type.rb │ ├── harvest.rb │ ├── like.rb │ ├── member.rb │ ├── notification.rb │ ├── photo.rb │ ├── photo_association.rb │ ├── plant_part.rb │ ├── planting.rb │ ├── post.rb │ ├── role.rb │ ├── scientific_name.rb │ └── seed.rb ├── resources │ ├── api │ │ └── v1 │ │ │ ├── crop_resource.rb │ │ │ ├── garden_resource.rb │ │ │ ├── harvest_resource.rb │ │ │ ├── member_resource.rb │ │ │ ├── photo_resource.rb │ │ │ ├── planting_resource.rb │ │ │ └── seed_resource.rb │ └── base_resource.rb ├── services │ ├── crop_search_service.rb │ ├── gbif_service.rb │ ├── openfarm_service.rb │ └── timeline_service.rb ├── validators │ └── approved_validator.rb └── views │ ├── activities │ ├── _actions.haml │ ├── _card.html.haml │ ├── _description.haml │ ├── _form.html.haml │ ├── _owner.haml │ ├── edit.html.haml │ ├── index.csv.shaper │ ├── index.html.haml │ ├── index.ics.erb │ ├── index.rss.haml │ ├── new.html.haml │ └── show.html.haml │ ├── admin │ ├── index.html.haml │ ├── members │ │ ├── _form.html.haml │ │ ├── edit.html.haml │ │ └── index.html.haml │ ├── newsletter.html.haml │ └── roles │ │ ├── _form.html.haml │ │ ├── edit.html.haml │ │ ├── index.html.haml │ │ └── new.html.haml │ ├── alternate_names │ ├── _form.html.haml │ ├── edit.html.haml │ ├── index.html.haml │ ├── new.html.haml │ └── show.html.haml │ ├── comments │ ├── _description.haml │ ├── _form.html.haml │ ├── _single.html.haml │ ├── edit.html.haml │ ├── index.rss.haml │ └── new.html.haml │ ├── conversations │ ├── index.haml │ └── show.html.haml │ ├── crops │ ├── _actions.html.haml │ ├── _alternate_names.html.haml │ ├── _approval_status_message.html.haml │ ├── _crop.html.haml │ ├── _find_seeds.html.haml │ ├── _form.html.haml │ ├── _grown_for.html.haml │ ├── _harvests.html.haml │ ├── _hierarchy.html.haml │ ├── _image_with_popover.html.haml │ ├── _info.haml │ ├── _photos.html.haml │ ├── _planting_advice.html.haml │ ├── _plantings.html.haml │ ├── _popover.html.haml │ ├── _posts.html.haml │ ├── _predictions.html.haml │ ├── _scientific_names.html.haml │ ├── _search_bar.haml │ ├── _thumbnail.html.haml │ ├── _tiny.html.haml │ ├── _varieties.html.haml │ ├── _wrangle.html.haml │ ├── edit.html.haml │ ├── hierarchy.html.haml │ ├── index.csv.shaper │ ├── index.html.haml │ ├── index.rss.haml │ ├── new.html.haml │ ├── requested.haml │ ├── search.html.haml │ ├── show.html.haml │ └── wrangle.html.haml │ ├── devise │ ├── confirmations │ │ └── new.html.haml │ ├── mailer │ │ ├── confirmation_instructions.html.haml │ │ ├── reset_password_instructions.html.haml │ │ └── unlock_instructions.html.haml │ ├── passwords │ │ ├── edit.html.haml │ │ └── new.html.haml │ ├── registrations │ │ ├── _delete.html.haml │ │ ├── _edit_apps.html.haml │ │ ├── _edit_email.html.haml │ │ ├── _edit_password.html.haml │ │ ├── _edit_profile.html.haml │ │ ├── _newsletter_blurb.html.haml │ │ ├── edit.html.haml │ │ └── new.html.haml │ ├── sessions │ │ └── new.html.haml │ ├── shared │ │ ├── _error_messages.html.haml │ │ └── _links.haml │ └── unlocks │ │ └── new.html.haml │ ├── errors │ ├── 404.html │ ├── 422.html │ └── 500.html │ ├── follows │ ├── followers.html.haml │ └── index.html.haml │ ├── forums │ ├── _form.html.haml │ ├── edit.html.haml │ ├── index.html.haml │ ├── new.html.haml │ └── show.html.haml │ ├── garden_collaborators │ ├── _form.html.haml │ ├── edit.html.haml │ ├── index.html.haml │ ├── new.html.haml │ └── show.html.haml │ ├── garden_types │ ├── _actions.html.haml │ ├── _form.html.haml │ ├── _thumbnail.html.haml │ ├── edit.html.haml │ ├── index.html.haml │ ├── new.html.haml │ └── show.html.haml │ ├── gardens │ ├── _actions.html.haml │ ├── _card.html.haml │ ├── _form.html.haml │ ├── _garden.html.haml │ ├── _overview.html.haml │ ├── _photo.html.haml │ ├── _previously.haml │ ├── edit.html.haml │ ├── index.html.haml │ ├── new.html.haml │ └── show.html.haml │ ├── harvests │ ├── _actions.html.haml │ ├── _card.html.haml │ ├── _description.haml │ ├── _form.html.haml │ ├── _harvest.haml │ ├── _image_with_popover.haml │ ├── _modal.html.haml │ ├── _owner.html.haml │ ├── _planting.haml │ ├── _popover.html.haml │ ├── _thumbnail.html.haml │ ├── edit.html.haml │ ├── index.csv.shaper │ ├── index.html.haml │ ├── index.rss.haml │ ├── new.html.haml │ └── show.html.haml │ ├── home │ ├── _activities.html.haml │ ├── _blurb.html.haml │ ├── _crops.html.haml │ ├── _discuss.html.haml │ ├── _harvests.html.haml │ ├── _members.html.haml │ ├── _plantings.html.haml │ ├── _seeds.html.haml │ ├── _stats.html.haml │ └── index.html.haml │ ├── layouts │ ├── _fact_card.haml │ ├── _footer.html.haml │ ├── _head.html.haml │ ├── _header.html.haml │ ├── _menu.haml │ ├── _nav.haml │ ├── application.html.haml │ ├── mailer.html.erb │ ├── mailer.text.erb │ └── modal.html.haml │ ├── likes │ ├── _count.haml │ └── _likes.html.haml │ ├── mailboxer │ ├── message_mailer │ │ ├── new_message_email.html.erb │ │ ├── new_message_email.text.erb │ │ ├── reply_message_email.html.erb │ │ └── reply_message_email.text.erb │ └── notification_mailer │ │ ├── new_notification_email.html.erb │ │ └── new_notification_email.text.erb │ ├── members │ ├── _avatar.html.haml │ ├── _bio.html.haml │ ├── _contact.html.haml │ ├── _follow_buttons.haml │ ├── _gardens.html.haml │ ├── _harvests.html.haml │ ├── _location.html.haml │ ├── _map.html.haml │ ├── _member.haml │ ├── _stats.html.haml │ ├── _thumbnail.html.haml │ ├── _tiny.haml │ ├── finish_signup.haml │ ├── index.html.haml │ ├── nearby.html.haml │ ├── show.html.haml │ ├── show.rss.haml │ └── unsubscribe.html.haml │ ├── messages │ ├── _form.haml │ └── new.html.haml │ ├── notifier_mailer │ ├── _planting.haml │ ├── _signature.html.haml │ ├── crop_request_approved.html.haml │ ├── crop_request_rejected.html.haml │ ├── new_crop_request.html.haml │ ├── notify.html.haml │ └── planting_reminder.html.haml │ ├── photos │ ├── _actions.html.haml │ ├── _association_delete_button.haml │ ├── _associations.html.haml │ ├── _card.html.haml │ ├── _description.haml │ ├── _gallery.haml │ ├── _hero.html.haml │ ├── _likes.html.haml │ ├── _photo.haml │ ├── _thumbnail.html.haml │ ├── _tiny.html.haml │ ├── edit.html.haml │ ├── index.html.haml │ ├── new.html.haml │ └── show.html.haml │ ├── places │ ├── _map_attribution.html.haml │ ├── _search_form.html.haml │ ├── index.html.haml │ └── show.html.haml │ ├── plant_parts │ ├── _form.html.haml │ ├── edit.html.haml │ ├── index.html.haml │ ├── new.html.haml │ └── show.html.haml │ ├── plantings │ ├── _actions.html.haml │ ├── _badges.html.haml │ ├── _card.html.haml │ ├── _descendants.html.haml │ ├── _description.haml │ ├── _facts.haml │ ├── _form.html.haml │ ├── _harvests.html.haml │ ├── _image_with_popover.html.haml │ ├── _modal.html.haml │ ├── _owner.haml │ ├── _photos.haml │ ├── _planting.haml │ ├── _popover.html.haml │ ├── _progress.html.haml │ ├── _progress_list.haml │ ├── _quick_actions.haml │ ├── _thumbnail.html.haml │ ├── _timeline.html.haml │ ├── _timeline_icon.haml │ ├── _tiny.html.haml │ ├── edit.html.haml │ ├── index.csv.shaper │ ├── index.html.haml │ ├── index.ics.erb │ ├── index.rss.haml │ ├── new.html.haml │ └── show.html.haml │ ├── posts │ ├── _actions.html.haml │ ├── _comments.html.haml │ ├── _description.haml │ ├── _form.html.haml │ ├── _preview.haml │ ├── _single.html.haml │ ├── _summary.html.haml │ ├── edit.html.haml │ ├── index.html.haml │ ├── index.rss.haml │ ├── new.html.haml │ ├── show.html.haml │ └── show.rss.haml │ ├── scientific_names │ ├── _form.html.haml │ ├── edit.html.haml │ ├── index.html.haml │ ├── new.html.haml │ └── show.html.haml │ ├── seeds │ ├── _actions.html.haml │ ├── _card.html.haml │ ├── _days_until_maturity.html.haml │ ├── _descendants.html.haml │ ├── _description.haml │ ├── _facts.html.haml │ ├── _form.html.haml │ ├── _modal.html.haml │ ├── _owner.html.haml │ ├── _seed.haml │ ├── _thumbnail.html.haml │ ├── edit.html.haml │ ├── index.csv.shaper │ ├── index.html.haml │ ├── index.rss.haml │ ├── new.html.haml │ └── show.html.haml │ ├── shared │ ├── _flash_messages.html.haml │ ├── _glyphicon.html.haml │ ├── _markdown_help.html.haml │ ├── _signin_signup.html.haml │ ├── buttons │ │ ├── _delete.haml │ │ └── _edit.haml │ └── editable │ │ ├── _date.html.haml │ │ └── _form.html.haml │ ├── support │ └── index.html.haml │ └── timeline │ ├── _photos.html.haml │ └── index.html.haml ├── bin ├── bundle ├── rails ├── rake ├── setup ├── update └── yarn ├── config.rb ├── config.ru ├── config ├── application.rb ├── boot.rb ├── cable.yml ├── compass.rb ├── database.yml ├── database.yml.example ├── elasticsearch.yml ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── factory_bot.rb ├── i18n-tasks.yml ├── initializers │ ├── application_controller_renderer.rb │ ├── assets.rb │ ├── backtrace_silencers.rb │ ├── comfortable_mexican_sofa.rb │ ├── content_security_policy.rb │ ├── cookies_serializer.rb │ ├── devise.rb │ ├── escaped_markdown.rb │ ├── filter_parameter_logging.rb │ ├── friendly_id.rb │ ├── geocoder.rb │ ├── growstuff_markdown.rb │ ├── inflections.rb │ ├── jsonapi_resources.rb │ ├── leaflet.rb │ ├── mailboxer.rb │ ├── mime_types.rb │ ├── new_framework_defaults_5_1.rb │ ├── new_framework_defaults_5_2.rb │ ├── new_framework_defaults_6_0.rb │ ├── omniauth.rb │ ├── rswag_api.rb │ ├── rswag_ui.rb │ ├── session_store.rb │ ├── sidekiq.rb │ ├── swagger.rb │ ├── time_formats.rb │ └── wrap_parameters.rb ├── locales │ ├── README.md │ ├── devise.en.yml │ ├── en.bootstrap.yml │ ├── en.yml │ └── ja.yml ├── newrelic.yml ├── puma.rb ├── robots.staging.txt ├── robots.txt ├── routes.rb ├── secrets.yml ├── setup_load_paths.rb ├── sidekiq.yml ├── spring.rb ├── storage.yml └── unicorn.rb ├── db ├── migrate │ ├── 20120903092956_devise_create_users.rb │ ├── 20120903112806_add_username_to_users.rb │ ├── 20121001212604_create_crops.rb │ ├── 20121003190731_require_system_name_for_crops.rb │ ├── 20121027035231_add_slug_to_crops.rb │ ├── 20121105032913_create_gardens.rb │ ├── 20121106101718_add_slug_to_users.rb │ ├── 20121107012827_create_scientific_names.rb │ ├── 20121108105440_create_updates.rb │ ├── 20121109130033_add_creation_index_to_updates.rb │ ├── 20121203034745_add_tos_agreement_to_users.rb │ ├── 20121214224227_add_slug_to_updates.rb │ ├── 20121219022554_create_plantings.rb │ ├── 20130113045802_rename_updates_to_posts.rb │ ├── 20130113060852_rename_users_to_members.rb │ ├── 20130113081521_rename_post_member_to_author.rb │ ├── 20130113095802_rename_garden_member_to_owner.rb │ ├── 20130118031942_add_description_to_gardens.rb │ ├── 20130118043431_add_slug_to_plantings.rb │ ├── 20130206033956_create_comments.rb │ ├── 20130206051328_add_show_email_to_member.rb │ ├── 20130208034248_require_fields_for_comments.rb │ ├── 20130212001748_add_geo_to_members.rb │ ├── 20130212123628_create_notifications.rb │ ├── 20130213014511_create_forums.rb │ ├── 20130213015708_add_forum_to_posts.rb │ ├── 20130214024117_create_roles.rb │ ├── 20130214034838_add_members_roles_table.rb │ ├── 20130215131921_rename_notification_fields.rb │ ├── 20130220044605_add_slug_to_forums.rb │ ├── 20130220044642_add_slug_to_roles.rb │ ├── 20130222060730_default_read_to_false.rb │ ├── 20130326092227_change_planted_at_to_date.rb │ ├── 20130327120024_add_send_email_to_member.rb │ ├── 20130329045744_add_sunniness_to_planting.rb │ ├── 20130404174459_create_authentications.rb │ ├── 20130409103549_make_post_subject_non_null.rb │ ├── 20130409162140_add_name_to_authentications.rb │ ├── 20130507105357_create_products.rb │ ├── 20130507110411_create_orders.rb │ ├── 20130507113915_add_orders_products_table.rb │ ├── 20130508050711_add_completed_to_order.rb │ ├── 20130508104506_create_photos.rb │ ├── 20130509123711_add_metadata_to_photos.rb │ ├── 20130514124515_add_parent_to_crop.rb │ ├── 20130515033842_create_order_items.rb │ ├── 20130515054017_change_order_member_id_to_integer.rb │ ├── 20130515122301_change_prices_to_integers.rb │ ├── 20130517015920_create_account_details.rb │ ├── 20130517051922_create_account_types.rb │ ├── 20130517234458_require_account_type_name.rb │ ├── 20130518000339_add_columns_to_product.rb │ ├── 20130518002942_rename_account_detail_to_account.rb │ ├── 20130529032813_add_express_token_to_orders.rb │ ├── 20130531110729_add_photos_plantings_table.rb │ ├── 20130601011725_change_flickr_photo_id_to_string.rb │ ├── 20130606230333_change_product_description_to_text.rb │ ├── 20130606233733_add_recommended_price_to_product.rb │ ├── 20130705104238_add_planted_from_to_planting.rb │ ├── 20130715110134_create_seeds.rb │ ├── 20130718005600_change_use_by_to_plant_before_on_seed.rb │ ├── 20130718011247_add_trading_to_seeds.rb │ ├── 20130722050836_remove_tradable_from_seeds.rb │ ├── 20130723103128_set_default_tradable_to_on_seed.rb │ ├── 20130723110702_add_slug_to_seed.rb │ ├── 20130809012511_add_bio_to_members.rb │ ├── 20130819004549_add_planting_count_to_crop.rb │ ├── 20130821011352_add_creator_to_crops.rb │ ├── 20130821073736_add_creator_to_scientific_name.rb │ ├── 20130826012139_add_owner_to_planting.rb │ ├── 20130826023159_add_plantings_count_to_member.rb │ ├── 20130827105823_add_newsletter_to_member.rb │ ├── 20130913015118_add_referral_code_to_order.rb │ ├── 20130917053547_create_harvests.rb │ ├── 20130917060257_change_harvest_notes_to_description.rb │ ├── 20130917071545_change_harvest_units_to_unit.rb │ ├── 20130917075803_add_slug_to_harvests.rb │ ├── 20130925050304_add_weight_to_harvests.rb │ ├── 20131018101204_rename_system_name_to_name.rb │ ├── 20131025104228_add_fields_to_gardens.rb │ ├── 20131029053113_add_plant_part_to_harvests.rb │ ├── 20131030230908_create_plant_parts.rb │ ├── 20131030231202_change_plant_part_to_plant_part_id.rb │ ├── 20131031000655_add_slug_to_plant_part.rb │ ├── 20140718075753_default_plantings_count_to_zero.rb │ ├── 20140829230600_add_finished_to_planting.rb │ ├── 20140905001730_add_harvests_photos_table.rb │ ├── 20140928044231_add_crops_posts_table.rb │ ├── 20140928085713_add_send_planting_reminder_to_member.rb │ ├── 20141002022459_create_index_harvest_photos.rb │ ├── 20141018111015_create_alternate_names.rb │ ├── 20141111130849_create_follows.rb │ ├── 20141119130555_change_follows_member_id_to_follower_id.rb │ ├── 20150124110540_add_properties_to_seeds.rb │ ├── 20150127043022_add_gardens_photos_table.rb │ ├── 20150129034206_add_si_weight_to_harvest.rb │ ├── 20150130224814_add_requester_to_crops.rb │ ├── 20150201052245_create_cms.rb │ ├── 20150201053200_add_approval_status_to_crops.rb │ ├── 20150201062506_add_reason_for_rejection_to_crops.rb │ ├── 20150201064502_add_request_notes_to_crops.rb │ ├── 20150203080226_create_likes.rb │ ├── 20150209105410_add_rejection_notes_to_crops.rb │ ├── 20150625224805_add_days_before_maturity_to_plantings.rb │ ├── 20150824145414_add_member_preferred_image.rb │ ├── 20161129021533_rename_scientific_name.rb │ ├── 20161201154922_add_photos_seeds_table.rb │ ├── 20170104035248_add_planting_ref_to_harvests.rb │ ├── 20170413221549_counter_caches.rb │ ├── 20170520060252_add_deleted_to_members.rb │ ├── 20171022032108_all_the_predictions.rb │ ├── 20171105011017_set_prediction_data.rb │ ├── 20171129041341_create_photographings.rb │ ├── 20180118112809_add_datetaken_to_photos.rb │ ├── 20180205000612_remove_shop.rb │ ├── 20180213005731_seed_usage.rb │ ├── 20180401220637_add_member_count_caches.rb │ ├── 20190130090437_add_crop_to_photographings.rb │ ├── 20190317023129_finished_boolean.rb │ ├── 20190326063855_create_garden_types.rb │ ├── 20190326224347_add_harvests_count.rb │ ├── 20190712003735_add_like_counter_caches.rb │ ├── 20190712234859_rename_photographings.rb │ ├── 20190720000555_create_mailboxer.mailboxer_engine.rb │ ├── 20190720000556_add_conversation_optout.mailboxer_engine.rb │ ├── 20190720000557_add_missing_indices.mailboxer_engine.rb │ ├── 20190720000558_add_delivery_tracking_info_to_mailboxer_receipts.mailboxer_engine.rb │ ├── 20190720000625_notifications_to_mailboxer.rb │ ├── 20190721042146_paranoia_to_discard.rb │ ├── 20190902004225_add_openfarm_data_to_crops.rb │ ├── 20190910022329_add_photo_source.rb │ ├── 20190915065209_create_crop_companions.rb │ ├── 20190918033319_unique_urls.rb │ ├── 20190921211652_crop_posts.rb │ ├── 20191029024101_add_saved_at_to_seeds.rb │ ├── 20191119020643_upgrade_cms.rb │ ├── 20191119030244_cms_tags.rb │ ├── 20191226024813_crop_harvest_counter_cache.rb │ ├── 20191226024957_crop_photo_counter_cache.rb │ ├── 20191226025124_plant_part_harvest_counter_cache.rb │ ├── 20191226025225_post_comment_counter_cache.rb │ ├── 20191226051019_elastic_indexing.rb │ ├── 20200801084007_add_foreign_key_constraint_to_active_storage_attachments_for_blob_id.active_storage.rb │ ├── 20200801210054_missing_uniqueness.rb │ ├── 20230313015323_create_active_storage_tables.active_storage.rb │ ├── 20240114045751_add_gbif.rb │ ├── 20240218035144_add_activities.rb │ ├── 20240218053122_add_slug_to_activity.rb │ ├── 20240714024918_like_everything.rb │ └── 20240929041435_create_garden_collaborators.rb ├── schema.rb ├── seeds.rb └── seeds │ ├── README.md │ ├── alternate_names_201410.csv │ ├── crops-00.csv │ ├── crops-10-peppers.csv │ ├── crops-11-tomatoes.csv │ ├── crops-12-mint.csv │ ├── crops-13-brassicas.csv │ ├── crops-14-london-workingbee.csv │ ├── crops-15-squashes.csv │ └── suburbs.csv ├── env-example ├── lib ├── actions │ └── oauth_signup_action.rb ├── assets │ └── .gitkeep ├── geocodable.rb ├── haml │ └── filters │ │ ├── escaped_markdown.rb │ │ └── growstuff_markdown.rb └── tasks │ ├── .gitkeep │ ├── gardens.rake │ ├── gbif.rake │ ├── growstuff.rake │ ├── hooks.rake │ ├── i18n.rake │ ├── openfarm.rake │ ├── search.rake │ └── testing.rake ├── log └── .gitkeep ├── package.json ├── public ├── 404.html ├── 422.html ├── 500.html └── favicon.ico ├── script ├── check_contributors_md.rb ├── check_elasticsearch.sh ├── check_static.rb ├── deploy-tasks.sh ├── heroku_maintenance.rb ├── install_elasticsearch.sh ├── install_linters.sh ├── install_phantomjs.sh ├── percy.sh └── rails ├── spec ├── cassettes │ └── GbifService │ │ ├── _fetch │ │ └── fetches_a_given_key.yml │ │ ├── _suggest │ │ └── matches.yml │ │ └── _update_crop │ │ ├── gets_photos.yml │ │ ├── resolves_common_names.yml │ │ └── resolves_scientific_names.yml ├── controllers │ ├── admin │ │ └── roles_controller_spec.rb │ ├── admin_controller_spec.rb │ ├── api │ │ └── v1 │ │ │ └── plantings_controller_spec.rb │ ├── authentications_controller_spec.rb │ ├── charts │ │ ├── crops_controller_spec.rb │ │ └── gardens_controller_spec.rb │ ├── comments_controller_spec.rb │ ├── crops_controller_spec.rb │ ├── forums_controller_spec.rb │ ├── garden_types_controller_spec.rb │ ├── gardens_controller_spec.rb │ ├── harvests_controller_spec.rb │ ├── home_controller_spec.rb │ ├── likes_controller_spec.rb │ ├── member_controller_spec.rb │ ├── photo_associations_controller_spec.rb │ ├── photos_controller_spec.rb │ ├── places_controller_spec.rb │ ├── plant_parts_controller_spec.rb │ ├── plantings_controller_spec.rb │ ├── posts_controller_spec.rb │ ├── registrations_controller_spec.rb │ ├── robots_controller_spec.rb │ ├── scientific_names_controller_spec.rb │ └── seeds_controller_spec.rb ├── custom_matchers.rb ├── factories │ ├── activity.rb │ ├── alternate_names.rb │ ├── authentications.rb │ ├── comments.rb │ ├── crop.rb │ ├── crop_companions.rb │ ├── follows.rb │ ├── forums.rb │ ├── garden.rb │ ├── garden_collaborators.rb │ ├── garden_types.rb │ ├── harvests.rb │ ├── like.rb │ ├── member.rb │ ├── notifications.rb │ ├── photos.rb │ ├── plant_parts.rb │ ├── planting.rb │ ├── post.rb │ ├── roles.rb │ ├── scientific_name.rb │ └── seeds.rb ├── features │ ├── admin │ │ ├── admin_spec.rb │ │ ├── forums_spec.rb │ │ ├── newsletter_spec.rb │ │ ├── plant_parts_spec.rb │ │ └── roles_spec.rb │ ├── cms_spec.rb │ ├── comments │ │ └── commenting_a_comment_spec.rb │ ├── conversations │ │ ├── index_spec.rb │ │ └── show_spec.rb │ ├── crops │ │ ├── alternate_name_spec.rb │ │ ├── browse_crops_spec.rb │ │ ├── creating_a_crop_spec.rb │ │ ├── crop_detail_page_spec.rb │ │ ├── crop_photos_spec.rb │ │ ├── crop_search_spec.rb │ │ ├── crop_wranglers_spec.rb │ │ ├── crop_wrangling_button_spec.rb │ │ ├── delete_crop_spec.rb │ │ ├── inflections_spec.rb │ │ ├── request_new_crop_spec.rb │ │ ├── requested_crops_spec.rb │ │ ├── scientific_name_spec.rb │ │ └── show_spec.rb │ ├── footer_spec.rb │ ├── gardens │ │ ├── actions_spec.rb │ │ ├── adding_gardens_spec.rb │ │ ├── gardens_spec.rb │ │ └── index_spec.rb │ ├── harvests │ │ ├── browse_harvests_spec.rb │ │ └── harvesting_a_crop_spec.rb │ ├── home │ │ └── home_spec.rb │ ├── likeable_spec.rb │ ├── locale_spec.rb │ ├── members │ │ ├── ban_spec.rb │ │ ├── deletion_spec.rb │ │ ├── following_spec.rb │ │ ├── list_spec.rb │ │ └── profile_spec.rb │ ├── percy │ │ └── percy_spec.rb │ ├── photos │ │ ├── new_photo_spec.rb │ │ └── show_photo_spec.rb │ ├── places │ │ └── searching_a_place_spec.rb │ ├── planting_reminder_spec.rb │ ├── plantings │ │ ├── planting_a_crop_spec.rb │ │ ├── prediction_spec.rb │ │ └── show_spec.rb │ ├── posts │ │ └── posting_a_post_spec.rb │ ├── rss │ │ ├── comments_spec.rb │ │ ├── crops_spec.rb │ │ ├── members_spec.rb │ │ ├── plantings_spec.rb │ │ ├── posts_spec.rb │ │ └── seeds_spec.rb │ ├── seeds │ │ ├── adding_seeds_spec.rb │ │ ├── misc_seeds_spec.rb │ │ └── seed_photos_spec.rb │ ├── shared_examples │ │ ├── append_date.rb │ │ └── crop_suggest.rb │ ├── signin_spec.rb │ ├── signout_spec.rb │ ├── signup_spec.rb │ ├── timeline │ │ └── index_spec.rb │ └── unsubscribing_spec.rb ├── helpers │ ├── application_helper_spec.rb │ ├── buttons_helper_spec.rb │ ├── crops_helper_spec.rb │ ├── event_helper_spec.rb │ ├── gardens_helper_spec.rb │ ├── harvests_helper_spec.rb │ ├── photos_helper_spec.rb │ ├── plantings_helper_spec.rb │ └── seeds_helper_spec.rb ├── javascripts │ ├── helpers │ │ └── .gitkeep │ └── support │ │ └── spec_helper.js ├── lib │ ├── actions │ │ └── oauth_signup_action_spec.rb │ └── haml │ │ └── filters │ │ ├── escaped_markdown_spec.rb │ │ └── growstuff_markdown_spec.rb ├── models │ ├── ability_spec.rb │ ├── alternate_name_spec.rb │ ├── authentication_spec.rb │ ├── comment_spec.rb │ ├── crop_companion_spec.rb │ ├── crop_spec.rb │ ├── follow_spec.rb │ ├── forum_spec.rb │ ├── garden_spec.rb │ ├── garden_type_spec.rb │ ├── harvest_spec.rb │ ├── like_spec.rb │ ├── member_spec.rb │ ├── notification_spec.rb │ ├── photo_spec.rb │ ├── plant_part_spec.rb │ ├── planting_spec.rb │ ├── post_spec.rb │ ├── role_spec.rb │ ├── scientific_name_spec.rb │ └── seed_spec.rb ├── rails_helper.rb ├── requests │ ├── api │ │ └── v1 │ │ │ ├── crop_request_spec.rb │ │ │ ├── gardens_request_spec.rb │ │ │ ├── harvests_request_spec.rb │ │ │ ├── members_request_spec.rb │ │ │ ├── photos_request_spec.rb │ │ │ ├── plantings_request_spec.rb │ │ │ └── seeds_request_spec.rb │ ├── authentications_spec.rb │ ├── conversations_spec.rb │ ├── forums_spec.rb │ ├── garden_types_spec.rb │ ├── gardens_spec.rb │ ├── harvests_spec.rb │ ├── photos_spec.rb │ ├── plant_parts_spec.rb │ ├── plantings_spec.rb │ ├── post_spec.rb │ ├── scientific_names_spec.rb │ └── seeds_spec.rb ├── routing │ ├── admin │ │ └── roles_controller_routing_spec.rb │ ├── admin_controller_routing_spec.rb │ ├── authentications_controller_routing_spec.rb │ ├── comments_controller_routing_spec.rb │ ├── crops_controller_routing_spec.rb │ ├── follows_controller_routing_spec.rb │ ├── forums_controller_routing_spec.rb │ ├── garden_types_controller_routing_spec.rb │ ├── gardens_controller_routing_spec.rb │ ├── harvests_controller_routing_spec.rb │ ├── members_controller_routing_spec.rb │ ├── photos_controller_routing_spec.rb │ ├── plant_parts_controller_routing_spec.rb │ ├── plantings_controller_routing_spec.rb │ ├── posts_controller_updates_routing_spec.rb │ ├── scientific_names_controller_routing_spec.rb │ └── seeds_controller_routing_spec.rb ├── services │ ├── crop_search_service_spec.rb │ ├── gbif_service_spec.rb │ └── timeline_service_spec.rb ├── spec_helper.rb ├── support │ ├── controller_macros.rb │ ├── database_cleaner.rb │ ├── devise.rb │ ├── feature_helpers.rb │ └── is_likeable.rb ├── swagger_helper.rb └── views │ ├── admin │ └── index_spec.rb │ ├── comments │ ├── edit.html.haml_spec.rb │ ├── index.rss.haml_spec.rb │ └── new.html.haml_spec.rb │ ├── crops │ ├── _grown_for.html.haml_spec.rb │ ├── _popover.html.haml_spec.rb │ ├── edit.html.haml_spec.rb │ ├── hierarchy.html.haml_spec.rb │ ├── index.html.haml_spec.rb │ ├── index.rss.haml_spec.rb │ ├── new.html.haml_spec.rb │ ├── show.html.haml_spec.rb │ └── wrangle.html.haml_spec.rb │ ├── devise │ ├── confirmations │ │ └── new_spec.rb │ ├── mailer │ │ ├── confirmation_instructions_spec.rb │ │ ├── reset_password_instructions_spec.rb │ │ └── unlock_instructions_spec.rb │ ├── registrations │ │ ├── edit_spec.rb │ │ └── new_spec.rb │ ├── sessions │ │ └── new_spec.rb │ ├── shared │ │ └── _links_spec.rb │ └── unlocks │ │ └── new_spec.rb │ ├── forums │ ├── edit.html.haml_spec.rb │ ├── index.html.haml_spec.rb │ ├── new.html.haml_spec.rb │ └── show.html.haml_spec.rb │ ├── garden_types │ ├── edit.html.haml_spec.rb │ ├── new.html.haml_spec.rb │ └── show.html.haml_spec.rb │ ├── gardens │ ├── edit.html.haml_spec.rb │ ├── new.html.haml_spec.rb │ └── show.html.haml_spec.rb │ ├── harvests │ ├── edit.html.haml_spec.rb │ ├── index.html.haml_spec.rb │ ├── index.rss.haml_spec.rb │ ├── new.html.haml_spec.rb │ └── show.html.haml_spec.rb │ ├── home │ ├── _blurb.html.haml_spec.rb │ ├── _members.html.haml_spec.rb │ ├── _seeds.html.haml_spec.rb │ ├── _stats.html.haml_spec.rb │ └── index_spec.rb │ ├── layouts │ ├── _head_spec.rb │ ├── _header_spec.rb │ └── application_spec.rb │ ├── members │ ├── _location.html.haml_spec.rb │ ├── index.html.haml_spec.rb │ └── show.rss.haml_spec.rb │ ├── photos │ ├── edit.html.haml_spec.rb │ ├── index.html.haml_spec.rb │ ├── new.html.haml_spec.rb │ └── show.html.haml_spec.rb │ ├── places │ ├── _map_attribution.html.haml_spec.rb │ ├── index.html.haml_spec.rb │ └── show.html.haml_spec.rb │ ├── plantings │ ├── _form.html.haml_spec.rb │ ├── edit.html.haml_spec.rb │ ├── index.html.haml_spec.rb │ ├── index.rss.haml_spec.rb │ ├── new.html.haml_spec.rb │ └── show.html.haml_spec.rb │ ├── posts │ ├── _single.html.haml_spec.rb │ ├── edit.html.haml_spec.rb │ ├── index.html.haml_spec.rb │ ├── index.rss.haml_spec.rb │ ├── new.html.haml_spec.rb │ ├── show.html.haml_spec.rb │ └── show.rss.haml_spec.rb │ └── seeds │ ├── edit.html.haml_spec.rb │ ├── index.rss.haml_spec.rb │ ├── new.html.haml_spec.rb │ └── show.html.haml_spec.rb ├── swagger └── v1 │ └── swagger.json └── yarn.lock /.devcontainer/.env: -------------------------------------------------------------------------------- 1 | # Ruby version 2 | VARIANT=3.3.4 3 | -------------------------------------------------------------------------------- /.devcontainer/create-db-user.sql: -------------------------------------------------------------------------------- 1 | CREATE USER vscode CREATEDB; 2 | CREATE DATABASE vscode WITH OWNER vscode; 3 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | indent_style = space 13 | indent_size = 2 14 | -------------------------------------------------------------------------------- /.esignore: -------------------------------------------------------------------------------- 1 | app/assets/javascripts/bootstrap-accessibility.min.js 2 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "google", 3 | "env": { 4 | "browser": true, 5 | "node": true 6 | }, 7 | "rules": { 8 | "no-var": "off", 9 | "max-len": ["error", { "code": 120, "tabWidth": 4 }] 10 | } 11 | } -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: bundler 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "07:00" 8 | open-pull-requests-limit: 20 9 | versioning-strategy: lockfile-only 10 | - package-ecosystem: github-actions 11 | directory: "/" 12 | schedule: 13 | interval: daily 14 | time: "07:00" 15 | open-pull-requests-limit: 10 16 | 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .byebug_history 2 | .bundle 3 | .env 4 | 5 | # Folders to ignore 6 | /log 7 | /doc 8 | /tmp 9 | /vendor 10 | /coverage 11 | /public 12 | /node_modules 13 | 14 | # Dev database (if they use sqlite) 15 | /db/*.sqlite3 16 | 17 | # Editor and file system droppings 18 | .pt 19 | .*.sw* 20 | *~ 21 | *.DS_Store 22 | .idea/** 23 | 24 | # Dev config files 25 | config/application.yml 26 | config/database.yml 27 | 28 | # Files that are created on Travis 29 | cc-test-reporter 30 | elasticsearch-*.deb 31 | elasticsearch-*.deb.sha512 32 | 33 | -------------------------------------------------------------------------------- /.haml-lint.yml: -------------------------------------------------------------------------------- 1 | linters: 2 | LineLength: 3 | max: 120 4 | InstanceVariables: 5 | enabled: false 6 | IdNames: 7 | enabled: false 8 | ConsecutiveComments: 9 | enabled: false 10 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --require spec_helper 3 | -------------------------------------------------------------------------------- /.ruby-gemset: -------------------------------------------------------------------------------- 1 | growstuffdev 2 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 3.3.7 2 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | extends: relaxed 2 | 3 | rules: 4 | # 80 chars should be enough, but don't fail if a line is longer 5 | line-length: 6 | max: 150 7 | level: warning 8 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: bundle exec puma -C config/puma.rb -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | # frozen_string_literal: true 3 | 4 | # Add your own tasks in files placed in lib/tasks ending in .rake, 5 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 6 | 7 | require 'rake/dsl_definition' 8 | require File.expand_path('config/application', __dir__) 9 | 10 | Rails.application.load_tasks 11 | -------------------------------------------------------------------------------- /app/assets/config/manifest.js: -------------------------------------------------------------------------------- 1 | // = link_tree ../images 2 | // = link_directory ../javascripts .js 3 | // = link_directory ../stylesheets .css 4 | -------------------------------------------------------------------------------- /app/assets/images/blog_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/app/assets/images/blog_32.png -------------------------------------------------------------------------------- /app/assets/images/email_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/app/assets/images/email_32.png -------------------------------------------------------------------------------- /app/assets/images/facebook-login-splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/app/assets/images/facebook-login-splash.png -------------------------------------------------------------------------------- /app/assets/images/facebook-thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/app/assets/images/facebook-thumbnail.png -------------------------------------------------------------------------------- /app/assets/images/facebook_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/app/assets/images/facebook_32.png -------------------------------------------------------------------------------- /app/assets/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/app/assets/images/favicon.ico -------------------------------------------------------------------------------- /app/assets/images/flickr_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/app/assets/images/flickr_32.png -------------------------------------------------------------------------------- /app/assets/images/growstuff-apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/app/assets/images/growstuff-apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /app/assets/images/growstuff-brand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/app/assets/images/growstuff-brand.png -------------------------------------------------------------------------------- /app/assets/images/icons/COPYRIGHT: -------------------------------------------------------------------------------- 1 | Icons in this folder attributable to Icons8.com. Used with permission. 2 | -------------------------------------------------------------------------------- /app/assets/images/icons/delete.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/assets/images/icons/edit.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/assets/images/icons/finish.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/assets/images/icons/post.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/assets/images/icons/stones.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/assets/images/location-not-set.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/app/assets/images/location-not-set.en.png -------------------------------------------------------------------------------- /app/assets/images/open_service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/app/assets/images/open_service.png -------------------------------------------------------------------------------- /app/assets/images/pear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/app/assets/images/pear.png -------------------------------------------------------------------------------- /app/assets/images/placeholder.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/app/assets/images/placeholder.xcf -------------------------------------------------------------------------------- /app/assets/images/placeholder_600.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/app/assets/images/placeholder_600.png -------------------------------------------------------------------------------- /app/assets/images/sunniness_not_specified.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/app/assets/images/sunniness_not_specified.png -------------------------------------------------------------------------------- /app/assets/images/sunniness_semi-shade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/app/assets/images/sunniness_semi-shade.png -------------------------------------------------------------------------------- /app/assets/images/sunniness_shade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/app/assets/images/sunniness_shade.png -------------------------------------------------------------------------------- /app/assets/images/sunniness_sun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/app/assets/images/sunniness_sun.png -------------------------------------------------------------------------------- /app/assets/images/twitter_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/app/assets/images/twitter_32.png -------------------------------------------------------------------------------- /app/assets/javascripts/charts.js: -------------------------------------------------------------------------------- 1 | // = require Chart.bundle 2 | // = require chartkick 3 | -------------------------------------------------------------------------------- /app/assets/javascripts/comfy/admin/cms/custom.js.coffee: -------------------------------------------------------------------------------- 1 | # Custom JS for the admin area -------------------------------------------------------------------------------- /app/assets/javascripts/datepicker.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | $('.add-datepicker').datepicker({'format': 'yyyy-mm-dd'}); 3 | }); 4 | -------------------------------------------------------------------------------- /app/assets/javascripts/editable.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | $('.editable').click(function() { 3 | $(this.dataset.form).show(); 4 | $(this.dataset.display).hide(); 5 | }); 6 | }); 7 | -------------------------------------------------------------------------------- /app/assets/javascripts/finish_planting.js.coffee: -------------------------------------------------------------------------------- 1 | # Clears the finished at date field when 2 | # a planting is marked unfinished, and 3 | # repopulates the field with a cached value 4 | # marking unfinished is undone. 5 | 6 | jQuery -> 7 | previousValue = '' 8 | $('#planting_finished').on('click', -> 9 | finished = $('#planting_finished_at') 10 | if @checked 11 | if previousValue.length 12 | date = previousValue 13 | finished.val(date) 14 | else 15 | finished.trigger('focus') 16 | else 17 | previousValue = finished.val() 18 | finished.val('') 19 | ) 20 | -------------------------------------------------------------------------------- /app/assets/javascripts/finish_seed.js.coffee: -------------------------------------------------------------------------------- 1 | # Clears the finished at date field when 2 | # a seed is marked unfinished, and 3 | # repopulates the field with a cached value 4 | # marking unfinished is undone. 5 | 6 | jQuery -> 7 | previousValue = '' 8 | $('#seed_finished').on('click', -> 9 | finished = $('#seed_finished_at') 10 | if @checked 11 | if previousValue.length 12 | date = previousValue 13 | finished.val(date) 14 | else 15 | finished.trigger('focus') 16 | else 17 | previousValue = finished.val() 18 | finished.val('') 19 | ) 20 | -------------------------------------------------------------------------------- /app/assets/javascripts/tooltips.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/app/assets/javascripts/tooltips.js -------------------------------------------------------------------------------- /app/assets/stylesheets/_homepage.scss: -------------------------------------------------------------------------------- 1 | // stats shown on homepage. eg. "999 members..." 2 | .stats { 3 | font-weight: bold; 4 | } 5 | 6 | .crops, 7 | .seeds, 8 | .members { 9 | .index-cards { 10 | justify-content: center; 11 | } 12 | } 13 | 14 | .homepage--list-item { 15 | height: 100px; 16 | } 17 | -------------------------------------------------------------------------------- /app/assets/stylesheets/_likes.scss: -------------------------------------------------------------------------------- 1 | .liked { 2 | color: $red; 3 | } 4 | 5 | .like-btn { 6 | color: $brown; 7 | } 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/_maps.scss: -------------------------------------------------------------------------------- 1 | .map { 2 | height: 500px; 3 | z-index: 2; 4 | } 5 | 6 | .member-map { 7 | height: 250px; 8 | z-index: 2; 9 | } 10 | -------------------------------------------------------------------------------- /app/assets/stylesheets/_notifications.scss: -------------------------------------------------------------------------------- 1 | .message { 2 | width: 100%; 3 | } 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/_posts.scss: -------------------------------------------------------------------------------- 1 | .post-actions { 2 | margin-bottom: 1rem; 3 | } 4 | 5 | .post-content { 6 | img { 7 | max-width: 100%; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /app/assets/stylesheets/_predictions.scss: -------------------------------------------------------------------------------- 1 | .predictions { 2 | .predictions-card { 3 | background: $white; 4 | border-radius: 5%; 5 | border: 1px solid lighten($green, 20%); 6 | margin: 1em; 7 | max-width: 250px; 8 | text-align: center; 9 | 10 | strong { 11 | text-align: center; 12 | font-size: 3em; 13 | } 14 | 15 | span { 16 | display: block; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/assets/stylesheets/_seeds.scss: -------------------------------------------------------------------------------- 1 | .seed-card { 2 | .text { 3 | opacity: 0.95; 4 | margin: 0; 5 | padding: 0; 6 | position: absolute; 7 | text-align: center; 8 | top: 1em; 9 | width: 100%; 10 | 11 | h4 { 12 | color: $white; 13 | background-color: $green; 14 | padding: 0; 15 | margin: 0; 16 | a { 17 | color: $white; 18 | } 19 | a:hover { 20 | color: $black; 21 | } 22 | } 23 | 24 | h5 { 25 | color: $black; 26 | background-color: $beige; 27 | } 28 | color: $black; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/assets/stylesheets/leaflet_overrides.scss: -------------------------------------------------------------------------------- 1 | .leaflet-popup-content-wrapper, 2 | .leaflet-popup-tip { 3 | border: 0; 4 | } 5 | 6 | .thumbnail { 7 | background: $white; 8 | border: solid 1px $white; 9 | 10 | .crop-thumbnail .cropinfo { 11 | padding-top: 14px; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/controllers/admin_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AdminController < ApplicationController 4 | respond_to :html 5 | def index 6 | authorize! :manage, :all 7 | end 8 | 9 | def newsletter 10 | authorize! :manage, :all 11 | @members = Member.confirmed.wants_newsletter.all.paginate(page: params[:page], per_page: 100) 12 | respond_with @members 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /app/controllers/api/v1/base_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Api 4 | module V1 5 | class BaseController < JSONAPI::ResourceController 6 | abstract 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/controllers/api/v1/crops_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Api 4 | module V1 5 | class CropsController < BaseController 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/controllers/api/v1/gardens_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Api 4 | module V1 5 | class GardensController < BaseController 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/controllers/api/v1/harvests_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Api 4 | module V1 5 | class HarvestsController < BaseController 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/controllers/api/v1/members_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Api 4 | module V1 5 | class MembersController < BaseController 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/controllers/api/v1/photos_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Api 4 | module V1 5 | class PhotosController < BaseController 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/controllers/api/v1/plantings_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Api 4 | module V1 5 | class PlantingsController < BaseController 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/controllers/api/v1/seeds_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Api 4 | module V1 5 | class SeedsController < BaseController 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/controllers/data_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class DataController < ApplicationController 4 | abstract 5 | before_action :authenticate_member!, except: %i(index show) 6 | load_and_authorize_resource id_param: :slug 7 | 8 | after_action :expire_homepage, only: %i(create update destroy) 9 | 10 | respond_to :html, :json 11 | respond_to :csv, :rss, only: [:index] 12 | responders :flash 13 | end 14 | -------------------------------------------------------------------------------- /app/controllers/home_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class HomeController < ApplicationController 4 | skip_authorize_resource 5 | respond_to :html 6 | 7 | def index 8 | # we were previously generating a lot of instance variables like 9 | # @members_count and @interesting_crops in here, but now we call 10 | # the relevant class methods directly in the view, so that fragment 11 | # caching will be effective. 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /app/controllers/pages_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class PagesController < ApplicationController 4 | def letsencrypt 5 | # use your code here, not mine 6 | render text: "y9KNck8wqkoQLnlr2RgA2TVwWtyYb4PeY_hzGNx0Tfs.dlIPqFhMDCLyQEccczY3roHZ1UWu6UqVeyb9mkRxheU" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/controllers/passwords_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class PasswordsController < Devise::PasswordsController 4 | protected 5 | 6 | def after_resetting_password_path_for(_resource) 7 | root_path 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/controllers/robots_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RobotsController < ApplicationController 4 | DEFAULT_FILENAME = 'config/robots.txt' 5 | 6 | def robots 7 | filename = "config/robots.#{subdomain}.txt" if subdomain && subdomain != 'www' 8 | file_to_render = File.exist?(filename.to_s) ? filename : DEFAULT_FILENAME 9 | render file: file_to_render, layout: false, content_type: 'text/plain' 10 | end 11 | 12 | private 13 | 14 | def subdomain 15 | request.subdomain.presence 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/controllers/sessions_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class SessionsController < Devise::SessionsController 4 | respond_to :html, :json 5 | 6 | def create 7 | super do |_resource| 8 | flash[:alert] = "There are crops waiting to be wrangled." if Crop.pending_approval.present? && current_member.role?(:crop_wrangler) 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/controllers/timeline_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class TimelineController < ApplicationController 4 | def index 5 | if current_member 6 | @timeline = TimelineService.followed_query(current_member).paginate(page: params[:page]) 7 | @members = current_member.followed 8 | else 9 | @timeline = TimelineService.query.paginate(page: params[:page]) 10 | @members = Member.interesting.limit 10 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /app/helpers/editable_form_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module EditableFormHelper 4 | def editable(field_type, model, field, display_field:, collection: []) 5 | render 'shared/editable/form', field_type:, 6 | model:, field:, display_field:, collection: 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/helpers/event_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module EventHelper 4 | def in_weeks(days) 5 | (days / 7.0).round 6 | end 7 | 8 | def event_description(event) 9 | render "#{event.event_type.pluralize}/description", event_model: resolve_model(event) 10 | end 11 | 12 | def resolve_model(event) 13 | event.event_type.classify.constantize.find(event.id) 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /app/helpers/posts_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module PostsHelper 4 | def post_stripped_tags(post, length: 300) 5 | truncate(strip_tags(markdownify(post.body)), length:) 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/helpers/seeds_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SeedsHelper 4 | def display_seed_quantity(seed) 5 | if seed.quantity.nil? 6 | 'seeds' 7 | else 8 | pluralize(seed.quantity, 'seed') 9 | end 10 | end 11 | 12 | def display_seed_description(seed) 13 | if seed.description.present? 14 | return truncate(seed.description, length: 130, separator: ' ', omission: '... ') do 15 | link_to "Read more", seed_path(seed) 16 | end 17 | end 18 | 19 | '' 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ApplicationJob < ActiveJob::Base 4 | end 5 | -------------------------------------------------------------------------------- /app/mailers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/app/mailers/.gitkeep -------------------------------------------------------------------------------- /app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ApplicationMailer < ActionMailer::Base 4 | default from: 'from@example.com' 5 | layout 'mailer' 6 | end 7 | -------------------------------------------------------------------------------- /app/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/app/models/.gitkeep -------------------------------------------------------------------------------- /app/models/alternate_name.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AlternateName < ApplicationRecord 4 | belongs_to :crop 5 | belongs_to :creator, class_name: 'Member', inverse_of: :created_alternate_names 6 | validates :name, presence: true 7 | validates :crop, presence: true 8 | 9 | after_commit :reindex 10 | 11 | delegate :reindex, to: :crop 12 | end 13 | -------------------------------------------------------------------------------- /app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ApplicationRecord < ActiveRecord::Base 4 | self.abstract_class = true 5 | self.per_page = 36 6 | end 7 | -------------------------------------------------------------------------------- /app/models/authentication.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Authentication < ApplicationRecord 4 | belongs_to :member 5 | end 6 | -------------------------------------------------------------------------------- /app/models/concerns/finishable.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Finishable 4 | extend ActiveSupport::Concern 5 | 6 | included do 7 | scope :finished, -> { where(finished: true) } 8 | scope :current, -> { where.not(finished: true) } 9 | 10 | def active 11 | !finished 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /app/models/concerns/gbif_data.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module GbifData 4 | extend ActiveSupport::Concern 5 | 6 | included do 7 | def update_gbif_data! 8 | GbifService.new.update_crop(self) 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/models/concerns/likeable.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Likeable 4 | extend ActiveSupport::Concern 5 | 6 | included do 7 | has_many :likes, as: :likeable, inverse_of: :likeable, dependent: :delete_all 8 | has_many :members, through: :likes 9 | end 10 | 11 | def liked_by?(member) 12 | liked_by_members_names.include?(member.login_name) 13 | end 14 | 15 | def liked_by_members_names 16 | Member.where(id: likes.pluck(:member_id)).pluck(:login_name) 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /app/models/concerns/ownable.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Ownable 4 | extend ActiveSupport::Concern 5 | 6 | included do 7 | belongs_to :owner, class_name: 'Member', counter_cache: true 8 | 9 | default_scope { joins(:owner).merge(Member.kept) } # Ensures the owner still exists 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/models/crop_companion.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CropCompanion < ApplicationRecord 4 | belongs_to :crop_a, class_name: :Crop 5 | belongs_to :crop_b, class_name: :Crop 6 | end 7 | -------------------------------------------------------------------------------- /app/models/crop_post.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CropPost < ApplicationRecord 4 | belongs_to :crop 5 | belongs_to :post 6 | end 7 | -------------------------------------------------------------------------------- /app/models/forum.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Forum < ApplicationRecord 4 | extend FriendlyId 5 | include Ownable 6 | validates :name, presence: true 7 | validates :description, presence: true 8 | friendly_id :name, use: %i(slugged finders) 9 | 10 | has_many :posts, dependent: :destroy 11 | 12 | def to_s 13 | name 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /app/models/garden_collaborator.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class GardenCollaborator < ApplicationRecord 4 | belongs_to :member 5 | belongs_to :garden 6 | 7 | validates :member_id, uniqueness: { scope: :garden } 8 | validate :not_garden_owner 9 | 10 | def not_garden_owner 11 | return unless member 12 | return unless garden 13 | 14 | errors.add(:member_id, "cannot be the garden owner") if garden.owner == member 15 | end 16 | 17 | def member_slug 18 | @member&.slug 19 | end 20 | 21 | def member_slug=(_slug) 22 | member_slug 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /app/models/garden_type.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class GardenType < ApplicationRecord 4 | extend FriendlyId 5 | friendly_id :name, use: %i(slugged finders) 6 | 7 | has_many :gardens, dependent: :nullify 8 | 9 | validates :name, presence: true, uniqueness: true 10 | validates :slug, presence: true, uniqueness: true 11 | 12 | def garden_type_slug 13 | name.gsub!(/[^A-Za-z]/, '') 14 | end 15 | 16 | def subtitler(garden_type) 17 | num = garden_type.gardens.uniq.count 18 | s = num > 1 || num.zero? ? "s are" : " is" 19 | "#{num} garden#{s} using this garden type" 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /app/models/like.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Like < ApplicationRecord 4 | belongs_to :member 5 | belongs_to :likeable, polymorphic: true, counter_cache: true, touch: true 6 | validates :member, :likeable, presence: true 7 | validates :member, uniqueness: { scope: :likeable } 8 | end 9 | -------------------------------------------------------------------------------- /app/models/plant_part.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class PlantPart < ApplicationRecord 4 | extend FriendlyId 5 | friendly_id :name, use: %i(slugged finders) 6 | 7 | has_many :harvests, dependent: :destroy 8 | has_many :crops, -> { joins_members.distinct }, through: :harvests 9 | 10 | validates :name, presence: true, uniqueness: true 11 | 12 | scope :joins_members, -> { joins("INNER JOIN members ON members.id = harvests.owner_id") } 13 | 14 | def to_s 15 | name 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/models/role.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class Role < ApplicationRecord 4 | extend FriendlyId 5 | friendly_id :name, use: %i(slugged finders) 6 | validates :name, uniqueness: true, presence: true 7 | 8 | has_and_belongs_to_many :members 9 | 10 | class << self 11 | %i(crop_wranglers admins).each do |method| 12 | define_method method do 13 | slug = method.to_s.singularize.dasherize 14 | Role.where(slug:).try(:first).try(:members) 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /app/models/scientific_name.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ScientificName < ApplicationRecord 4 | belongs_to :crop 5 | belongs_to :creator, class_name: 'Member', inverse_of: :created_scientific_names 6 | validates :name, presence: true 7 | validates :crop, presence: true 8 | after_commit :reindex 9 | delegate :reindex, to: :crop 10 | 11 | def to_s 12 | name 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /app/resources/api/v1/garden_resource.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Api 4 | module V1 5 | class GardenResource < BaseResource 6 | immutable 7 | 8 | has_one :owner, class_name: 'Member' 9 | has_many :plantings 10 | has_many :photos 11 | 12 | attribute :name 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /app/resources/api/v1/harvest_resource.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Api 4 | module V1 5 | class HarvestResource < BaseResource 6 | immutable 7 | 8 | has_one :crop 9 | has_one :planting 10 | has_one :owner, class_name: 'Member' 11 | has_many :photos 12 | 13 | attribute :harvested_at 14 | attribute :description 15 | attribute :unit 16 | attribute :weight_quantity 17 | attribute :weight_unit 18 | attribute :si_weight 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /app/resources/api/v1/member_resource.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Api 4 | module V1 5 | class MemberResource < BaseResource 6 | immutable 7 | 8 | has_many :gardens, foreign_key: 'owner_id' 9 | has_many :plantings, foreign_key: 'owner_id' 10 | has_many :harvests, foreign_key: 'owner_id' 11 | has_many :seeds, foreign_key: 'owner_id' 12 | 13 | has_many :photos 14 | 15 | attribute :login_name 16 | attribute :slug 17 | 18 | filters :login_name, :slug 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /app/resources/api/v1/photo_resource.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Api 4 | module V1 5 | class PhotoResource < BaseResource 6 | immutable 7 | 8 | has_one :owner, class_name: 'Member' 9 | has_many :plantings 10 | has_many :gardens 11 | has_many :harvests 12 | 13 | attribute :thumbnail_url 14 | attribute :fullsize_url 15 | attribute :license_name 16 | attribute :link_url 17 | attribute :title 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /app/resources/api/v1/seed_resource.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Api 4 | module V1 5 | class SeedResource < BaseResource 6 | immutable 7 | 8 | has_one :owner, class_name: 'Member' 9 | has_one :crop 10 | 11 | attribute :description 12 | attribute :quantity 13 | attribute :plant_before 14 | attribute :tradable_to 15 | attribute :days_until_maturity_min 16 | attribute :days_until_maturity_max 17 | attribute :organic 18 | attribute :gmo 19 | attribute :heirloom 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /app/resources/base_resource.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class BaseResource < JSONAPI::Resource 4 | immutable 5 | abstract 6 | end 7 | -------------------------------------------------------------------------------- /app/validators/approved_validator.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ApprovedValidator < ActiveModel::EachValidator 4 | def validate_each(record, attribute, _value) 5 | record.errors.add(attribute, options[:message] || 'must be approved') unless record.crop.try(:approved?) 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /app/views/activities/_description.haml: -------------------------------------------------------------------------------- 1 | #{link_to event_model.category, event_model} - #{event_model.name} 2 | 3 | - if event_model.planting 4 | %span on #{link_to event_model.planting, event_model.planting} 5 | 6 | - if event_model.garden 7 | %span in #{link_to event_model.garden, event_model.garden} 8 | -------------------------------------------------------------------------------- /app/views/activities/edit.html.haml: -------------------------------------------------------------------------------- 1 | = content_for :title, "Editing activity" 2 | 3 | = render 'form' 4 | -------------------------------------------------------------------------------- /app/views/activities/new.html.haml: -------------------------------------------------------------------------------- 1 | = content_for :title, t('activities.plan_something') 2 | 3 | = render 'form' 4 | -------------------------------------------------------------------------------- /app/views/admin/members/_form.html.haml: -------------------------------------------------------------------------------- 1 | %section.card.form-card 2 | = bootstrap_form_for [:admin, @member] do |f| 3 | - if @member.errors.any? 4 | #error_explanation 5 | %h2 6 | = pluralize(@member.errors.size, "error") 7 | prohibited this role from being saved: 8 | %ul 9 | - @member.errors.full_messages.each do |msg| 10 | %li= msg 11 | .card-body 12 | = f.collection_check_boxes(:role_ids, Role.all, :id, :name) 13 | .card-footer 14 | = f.submit 'Save', class: 'btn btn-success' 15 | -------------------------------------------------------------------------------- /app/views/admin/members/edit.html.haml: -------------------------------------------------------------------------------- 1 | .row 2 | .col= render 'members/member', member: @member 3 | .col= render 'form' 4 | -------------------------------------------------------------------------------- /app/views/admin/newsletter.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, 'Newsletter subscribers' 2 | 3 | %p 4 | - @members.each do |m| 5 | = m.email 6 | %br/ 7 | = will_paginate @members 8 | -------------------------------------------------------------------------------- /app/views/admin/roles/_form.html.haml: -------------------------------------------------------------------------------- 1 | .form-page 2 | %section.card.form-card 3 | = bootstrap_form_for [:admin, @role] do |f| 4 | - if @role.errors.any? 5 | #error_explanation 6 | %h2 7 | = pluralize(@role.errors.size, "error") 8 | prohibited this role from being saved: 9 | %ul 10 | - @role.errors.full_messages.each do |msg| 11 | %li= msg 12 | .card-body 13 | = f.text_field :name 14 | = f.text_area :description 15 | .card-footer 16 | = f.submit 'Save', class: 'btn btn-success' 17 | -------------------------------------------------------------------------------- /app/views/admin/roles/edit.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "Editing role" 2 | - content_for :breadcrumbs do 3 | %li.breadcrumb-item= link_to 'Admin', admin_path 4 | %li.breadcrumb-item= link_to 'Roles', admin_roles_path 5 | %li.breadcrumb-item.active= link_to 'Edit', edit_admin_role_path(@role) 6 | = render 'form' 7 | 8 | = link_to 'Back', admin_roles_path 9 | -------------------------------------------------------------------------------- /app/views/admin/roles/new.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "New role" 2 | 3 | 4 | - content_for :breadcrumbs do 5 | %li.breadcrumb-item= link_to 'Admin', admin_path 6 | %li.breadcrumb-item= link_to 'Roles', admin_roles_path 7 | %li.breadcrumb-item.active= link_to 'New', new_admin_role_path 8 | 9 | = render 'form' 10 | 11 | = link_to 'Back', admin_roles_path 12 | -------------------------------------------------------------------------------- /app/views/alternate_names/edit.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "Edit alternate name" 2 | 3 | %p 4 | Added by 5 | = link_to @alternate_name.creator, @alternate_name.creator 6 | = distance_of_time_in_words(@alternate_name.created_at, Time.zone.now) 7 | ago. 8 | 9 | = render 'form' 10 | -------------------------------------------------------------------------------- /app/views/alternate_names/new.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "New alternate name" 2 | 3 | = render 'form' 4 | -------------------------------------------------------------------------------- /app/views/comments/_description.haml: -------------------------------------------------------------------------------- 1 | #{link_to 'commented', event_model} on #{link_to event_model.post, event_model.post} 2 | -------------------------------------------------------------------------------- /app/views/comments/edit.html.haml: -------------------------------------------------------------------------------- 1 | = content_for :title, "Editing comment" 2 | 3 | %p 4 | Editing comment on 5 | = link_to @comment.post.subject, @comment.post 6 | 7 | = render 'form' 8 | -------------------------------------------------------------------------------- /app/views/comments/new.html.haml: -------------------------------------------------------------------------------- 1 | = content_for :title, "New comment" 2 | 3 | %section.blog-post 4 | .card.post{ id: "post-#{@post.id}" } 5 | .card-header 6 | %h2.display-3= @post.subject 7 | .card-body= render "posts/single", post: @post || @comment.post, subject: true 8 | 9 | = render partial: "posts/comments", locals: { post: @post || @comment.post } 10 | 11 | = render 'form' 12 | -------------------------------------------------------------------------------- /app/views/crops/_actions.html.haml: -------------------------------------------------------------------------------- 1 | - if crop.approved? && signed_in? 2 | 3 | .btn-group{"aria-label" => "Crop Actions", role: "group"} 4 | = render 'plantings/modal', planting: Planting.new(crop: crop, owner: current_member) 5 | = render 'harvests/modal', harvest: Harvest.new(crop: @crop, owner: current_member) 6 | = render 'seeds/modal', seed: Seed.new(crop: @crop, owner: current_member) 7 | -------------------------------------------------------------------------------- /app/views/crops/_approval_status_message.html.haml: -------------------------------------------------------------------------------- 1 | - if crop.pending? 2 | .alert.alert-danger 3 | %b This crop is currently pending approval. 4 | %p This crop was requested by #{crop.requester} #{time_ago_in_words(crop.created_at)} ago. 5 | - unless crop.request_notes.blank? 6 | %p 7 | Request notes: #{crop.request_notes} 8 | 9 | - if crop.rejected? 10 | .alert.alert-danger 11 | %b This crop was rejected for the following reason: #{crop.rejection_explanation} 12 | -------------------------------------------------------------------------------- /app/views/crops/_grown_for.html.haml: -------------------------------------------------------------------------------- 1 | - if crop.harvests.any? 2 | %p 3 | %strong Grown for: 4 | - crop.popular_plant_parts.each do |plant_part, frequency| 5 | - id, name = plant_part 6 | = link_to name, plant_part_path(id: id) 7 | (#{frequency}) 8 | -------------------------------------------------------------------------------- /app/views/crops/_hierarchy.html.haml: -------------------------------------------------------------------------------- 1 | %ul 2 | - @count ||= 0 3 | - unless defined? max 4 | - max = 0 # list all without "show all" toggle button 5 | - display_crops.each do |c| 6 | %li.crop-hierarchy{ class: (max != 0 && @count >= max) || !c.approved? ? ['hide', 'toggle'] : [] } 7 | = render 'crops/tiny', crop: c 8 | - if c.perennial 9 | = perennial_icon 10 | - @count += 1 11 | - if c.varieties.present? 12 | - c.varieties.order(:name).each do |v| 13 | = render partial: 'hierarchy', locals: { display_crops: [v], max: max } 14 | -------------------------------------------------------------------------------- /app/views/crops/_image_with_popover.html.haml: -------------------------------------------------------------------------------- 1 | - cache crop do 2 | = link_to image_tag(crop_image_path(crop), 3 | alt: "Image of #{crop.name}", class: 'image-responsive crop-image'), 4 | crop.name, 5 | rel: "popover", 6 | 'data-bs-toggle': 'popover', 7 | 'data-bs-trigger': 'hover', 8 | 'data-bs-title': crop.name, 9 | 'data-bs-content': render(partial: 'crops/popover', locals: { crop: crop }), 10 | 'data-bs-html': true 11 | -------------------------------------------------------------------------------- /app/views/crops/_photos.html.haml: -------------------------------------------------------------------------------- 1 | %h2 #{photo_icon} Photos 2 | - [Crop, Planting, Harvest, Seed].each do |model_name| 3 | - if crop.photos.by_model(model_name).any? 4 | %h3 #{@crop.name.capitalize} #{t("activerecord.models.#{model_name.to_s.downcase}.other")} 5 | = render 'photos/gallery', photos: crop.photos.by_model(model_name).includes(:owner).order(likes_count: :desc).limit(5) 6 | - if crop.photos.count.positive? 7 | = link_to 'more photos »', crop_photos_path(@crop), class: 'btn' 8 | -------------------------------------------------------------------------------- /app/views/crops/_planting_advice.html.haml: -------------------------------------------------------------------------------- 1 | - if crop.guides_count.present? && crop.guides_count.positive? 2 | %p 3 | There are 4 | = link_to "https://openfarm.cc/en/crops/#{CGI.escape @crop.name.gsub(' ', '-').downcase}" do 5 | #{crop.guides_count} growing guides on Open Farm 6 | 7 | -------------------------------------------------------------------------------- /app/views/crops/_popover.html.haml: -------------------------------------------------------------------------------- 1 | %p 2 | %small 3 | - unless crop.scientific_names.empty? 4 | %i 5 | = crop.scientific_names.first.name 6 | %br/ 7 | Planted 8 | = pluralize(crop.plantings.size, "time") 9 | -------------------------------------------------------------------------------- /app/views/crops/_search_bar.haml: -------------------------------------------------------------------------------- 1 | = form_tag search_crops_path, method: :get, class: 'form-inline', id: 'navbar-search' do 2 | .input-group 3 | %input.form-control{name: 'term', "aria-label" => "Search crops", placeholder: "Search crops", type: "search", id: 'term' }/ 4 | %button.btn.btn-default.text-white{type: "submit"} 5 | = icon 'fas', 'search' 6 | .sr-only Search 7 | -------------------------------------------------------------------------------- /app/views/crops/_thumbnail.html.haml: -------------------------------------------------------------------------------- 1 | - cache crop do 2 | .card.crop-thumbnail 3 | = link_to crop_path(slug: crop.slug) do 4 | = image_tag(crop.thumbnail_url.presence || placeholder_image, 5 | alt: "Image of #{crop.name}", 6 | class: 'img img-card') 7 | 8 | 9 | .text 10 | %h3.crop-name= link_to crop.name, crop_path(slug: crop.slug) 11 | - if crop.scientific_names.any? 12 | %div.crop-sci-name 13 | = crop.scientific_names.first 14 | -------------------------------------------------------------------------------- /app/views/crops/_tiny.html.haml: -------------------------------------------------------------------------------- 1 | - if crop.approved? || can?(:wrangle, Crop) 2 | = link_to crop do 3 | %span.chip.crop-chip 4 | = crop_icon(crop) 5 | = crop.name 6 | - unless crop.approved? 7 | %badge.badge-warning= crop.approval_status 8 | -------------------------------------------------------------------------------- /app/views/crops/_varieties.html.haml: -------------------------------------------------------------------------------- 1 | - if crop.varieties.size.positive? 2 | - crop.varieties.includes(:varieties).order(:name).each do |v| 3 | = render 'crops/thumbnail', crop: v 4 | = render 'crops/varieties', crop: v 5 | -------------------------------------------------------------------------------- /app/views/crops/hierarchy.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "Crop Hierarchy" 2 | 3 | %p 4 | This page shows the hierarchical tree of all crops in our 5 | = succeed "." do 6 | = link_to "crops database", crops_path 7 | 8 | - cache cache_key_for(Crop) do 9 | = render partial: "hierarchy", locals: { display_crops: @crops } 10 | -------------------------------------------------------------------------------- /app/views/crops/index.rss.haml: -------------------------------------------------------------------------------- 1 | 2 | %rss{ version: 2.0 } 3 | %channel 4 | %title Recently added crops (#{ENV['GROWSTUFF_SITE_NAME']}) 5 | %link= crops_url 6 | - @crops.each do |crop| 7 | %item 8 | %title= crop.name 9 | %pubdate= crop.created_at.to_fs(:rfc822) 10 | %link= crop_url(crop) 11 | %guid= crop_url(crop) 12 | -------------------------------------------------------------------------------- /app/views/crops/requested.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, t('crops.requested.title') 2 | - content_for :subtitle, t('crops.requested.subtitle', crops_size: @crops.size) 3 | 4 | %p Crops you have requested 5 | 6 | .pagination 7 | = will_paginate @requested 8 | 9 | .index-cards 10 | - @requested.each do |crop| 11 | = render partial: "thumbnail", locals: { crop: crop } 12 | 13 | .pagination 14 | = will_paginate @requested 15 | -------------------------------------------------------------------------------- /app/views/devise/registrations/_newsletter_blurb.html.haml: -------------------------------------------------------------------------------- 1 | The #{ENV['GROWSTUFF_SITE_NAME']} newsletter is sent out 2 | every few weeks. Check out our 3 | = link_to 'past newsletters', 'http://blog.growstuff.org/category/newsletter/' 4 | if you want to see the sort of thing we'll send you. Of course, we'll never spam you 5 | or sell your email address, and you can unsubscribe any time. 6 | -------------------------------------------------------------------------------- /app/views/devise/shared/_error_messages.html.haml: -------------------------------------------------------------------------------- 1 | - if resource.errors.any? 2 | #error_explanation 3 | %h2 4 | = I18n.t("errors.messages.not_saved", | 5 | count: resource.errors.count, | 6 | resource: resource.class.model_name.human.downcase) | 7 | %ul 8 | - resource.errors.full_messages.each do |message| 9 | %li= message 10 | -------------------------------------------------------------------------------- /app/views/devise/unlocks/new.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "" 2 | .form-page 3 | .card.form-card 4 | = form_for(resource, as: resource_name, 5 | url: unlock_path(resource_name), 6 | html: { method: :post, 7 | class: 'form-horizontal', 8 | role: 'form' }) do |f| 9 | 10 | %h2 Resend unlock instructions 11 | = render 'devise/shared/error_messages', resource: resource 12 | = f.email_field :email, class: 'form-control', placeholder: 'Email' 13 | = f.submit "Resend unlock instructions", class: 'btn btn-block my-4 btn-primary' 14 | 15 | = render "devise/shared/links" 16 | -------------------------------------------------------------------------------- /app/views/follows/followers.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "#{@member.login_name}'s followers" 2 | 3 | = page_entries_info @followers 4 | = will_paginate @followers 5 | 6 | .index-cards 7 | - @followers.each do |f| 8 | .thumbnail= render partial: "members/thumbnail", locals: { member: f } 9 | 10 | = page_entries_info @followers 11 | = will_paginate @followers 12 | -------------------------------------------------------------------------------- /app/views/follows/index.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "#{@member.login_name}'s follows" 2 | 3 | %h1.page-title #{@member.login_name}'s follows 4 | 5 | = page_entries_info @follows 6 | = will_paginate @follows 7 | 8 | .index-cards= render @follows 9 | 10 | = page_entries_info @follows 11 | = will_paginate @follows 12 | -------------------------------------------------------------------------------- /app/views/forums/edit.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "Editing forum" 2 | 3 | = render 'form' 4 | -------------------------------------------------------------------------------- /app/views/forums/index.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, t('.title') 2 | 3 | - if can? :create, Forum 4 | %p 5 | = link_to "New forum", new_forum_path, class: 'btn btn-default' 6 | 7 | - @forums.each do |forum| 8 | %h2= forum 9 | %p 10 | = localize_plural(forum.posts, Post) 11 | | 12 | = link_to "Visit forum", forum 13 | | 14 | = link_to "Post", new_post_path(forum_id: forum.id) 15 | = render partial: "posts/summary", locals: { posts: forum.posts, howmany: 4 } 16 | 17 | -------------------------------------------------------------------------------- /app/views/forums/new.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "New Forum" 2 | 3 | = render 'form' 4 | -------------------------------------------------------------------------------- /app/views/garden_collaborators/edit.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "Edit garden collaborator" 2 | 3 | = render 'form' -------------------------------------------------------------------------------- /app/views/garden_collaborators/new.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "New garden collaborator" 2 | 3 | = render 'form' 4 | -------------------------------------------------------------------------------- /app/views/garden_collaborators/show.html.haml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/app/views/garden_collaborators/show.html.haml -------------------------------------------------------------------------------- /app/views/garden_types/_actions.html.haml: -------------------------------------------------------------------------------- 1 | .btn-group.garden_type-actions 2 | = render 'shared/buttons/edit', path: edit_garden_type_path(garden_type) 3 | .text-right 4 | = render 'shared/buttons/delete', path: garden_type_path(garden_type) 5 | -------------------------------------------------------------------------------- /app/views/garden_types/_thumbnail.html.haml: -------------------------------------------------------------------------------- 1 | - cache cache_key_for(GardenType, garden_type.id) do 2 | .thumbnail 3 | .garden_type-thumbnail 4 | - if garden_type 5 | .garden_typeinfo 6 | .garden_typename 7 | = link_to garden_type.name, garden_type 8 | -------------------------------------------------------------------------------- /app/views/garden_types/edit.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "Edit GardenType" 2 | 3 | - if can? :update, @garden_type 4 | = render 'form' 5 | -------------------------------------------------------------------------------- /app/views/garden_types/index.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, 'GardenTypes' 2 | 3 | %p 4 | #{ENV['GROWSTUFF_SITE_NAME']} tracks who's growing what, where. 5 | View any garden_type page to see which of our members have used it. 6 | 7 | .index-cards 8 | - @garden_types.each do |garden_type| 9 | = render partial: "thumbnail", locals: { garden_type: garden_type } 10 | 11 | - if can? :create, GardenType 12 | %div 13 | = link_to 'New GardenType', new_garden_type_path, class: 'btn btn-primary' 14 | 15 | .pagination 16 | = will_paginate @garden_types 17 | -------------------------------------------------------------------------------- /app/views/garden_types/new.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "New GardenType" 2 | 3 | - if can? :create, @garden_type 4 | = render 'form' 5 | -------------------------------------------------------------------------------- /app/views/garden_types/show.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, @garden_type.name.capitalize 2 | - content_for :subtitle, @garden_type.subtitler(@garden_type) 3 | 4 | - if can?(:create, @garden_type) && can?(:edit, @garden_type) && can?(:destroy, @garden_type) 5 | - content_for :buttonbar do 6 | = render 'garden_types/actions', garden_type: @garden_type 7 | 8 | - if @garden_type.gardens.uniq.empty? 9 | %p There are no gardens to display. 10 | - else 11 | - @garden_type.gardens.uniq.each do |garden| 12 | = render 'gardens/overview', garden: garden 13 | -------------------------------------------------------------------------------- /app/views/gardens/_garden.html.haml: -------------------------------------------------------------------------------- 1 | .card 2 | = link_to garden do 3 | = image_tag garden_image_path(garden), class: 'img-card', alt: "Image of #{garden.name}" 4 | .card-body.text-center 5 | %h4.card-title= garden.name -------------------------------------------------------------------------------- /app/views/gardens/_photo.html.haml: -------------------------------------------------------------------------------- 1 | = link_to image_tag(garden_image_path(garden), 2 | alt: "Image of #{garden.name}", class: 'img-responsive'), 3 | garden_path(garden) 4 | -------------------------------------------------------------------------------- /app/views/gardens/edit.html.haml: -------------------------------------------------------------------------------- 1 | = content_for :title, "Edit garden" 2 | 3 | = render "form" 4 | -------------------------------------------------------------------------------- /app/views/gardens/new.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "New garden" 2 | 3 | = render 'form' 4 | -------------------------------------------------------------------------------- /app/views/harvests/_actions.html.haml: -------------------------------------------------------------------------------- 1 | - if can?(:edit, harvest) 2 | %span.dropdown.harvest-actions 3 | %a#harvest-actions-button.btn.btn-info.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-bs-toggle" => "dropdown", type: "button", href: '#'} Actions 4 | .dropdown-menu.dropdown-menu-xs{"aria-labelledby" => "harvest-actions-button"} 5 | = harvest_edit_button(harvest, classes: 'dropdown-item') 6 | = add_photo_button(harvest, classes: 'dropdown-item') 7 | .dropdown-divider 8 | = delete_button(harvest, classes: 'dropdown-item text-danger') 9 | -------------------------------------------------------------------------------- /app/views/harvests/_card.html.haml: -------------------------------------------------------------------------------- 1 | - cache harvest do 2 | .card 3 | = link_to harvest_path(slug: harvest.slug) do 4 | = image_tag harvest.thumbnail_url ? harvest.thumbnail_url : placeholder_image, alt: harvest.crop_name, class: 'img-card' 5 | .card-body 6 | %h5 7 | %strong= link_to harvest.crop_name, harvest_path(slug: harvest.slug) 8 | %span.badge.badge-pill= harvest.plant_part_name 9 | .card-footer 10 | .float-right 11 | %span.chip.member-chip 12 | = link_to member_path(slug: harvest.owner_slug) do 13 | = harvest.owner_login_name 14 | -------------------------------------------------------------------------------- /app/views/harvests/_description.haml: -------------------------------------------------------------------------------- 1 | harvested #{link_to event_model, event_model} 2 | -------------------------------------------------------------------------------- /app/views/harvests/_harvest.haml: -------------------------------------------------------------------------------- 1 | - if local_assigns[:full] 2 | = render 'harvests/card', harvest: harvest 3 | - else 4 | = render 'harvests/thumbnail', harvest: harvest -------------------------------------------------------------------------------- /app/views/harvests/_image_with_popover.haml: -------------------------------------------------------------------------------- 1 | = link_to image_tag(harvest_image_path(harvest), 2 | alt: harvest.to_s, 3 | class: 'image-responsive crop-image'), 4 | harvest, 5 | rel: "popover", 6 | 'data-bs-toggle': 'popover', 7 | 'data-bs-trigger': 'hover', 8 | 'data-bs-title': harvest.to_s, 9 | 'data-bs-content': render('harvests/popover', harvest: harvest), 10 | 'data-bs-html': true 11 | -------------------------------------------------------------------------------- /app/views/harvests/_planting.haml: -------------------------------------------------------------------------------- 1 | - if @harvest.planting.nil? && @matching_plantings && @matching_plantings.any? && @harvest.owner == current_member 2 | .alert.alert-info{role: "alert"} 3 | = bootstrap_form_for(@harvest) do |f| 4 | Is this from one of these plantings? 5 | - @matching_plantings.each do |planting| 6 | = f.radio_button :planting_id, planting.id, label: planting 7 | = f.submit "save", class: 'btn btn-sm' 8 | -------------------------------------------------------------------------------- /app/views/harvests/_popover.html.haml: -------------------------------------------------------------------------------- 1 | %p 2 | %small 3 | = harvest.harvested_at 4 | -------------------------------------------------------------------------------- /app/views/harvests/_thumbnail.html.haml: -------------------------------------------------------------------------------- 1 | - cache harvest do 2 | .card.harvest-thumbnail 3 | = link_to harvest_path(slug: harvest.slug) do 4 | = image_tag(harvest.thumbnail_url ? harvest.thumbnail_url : placeholder_image, 5 | alt: harvest.crop_name, 6 | class: 'img img-card') 7 | 8 | .card-body 9 | %h3.harvest-crop.card-title 10 | = link_to harvest.crop_name, harvest_path(slug: harvest.slug) 11 | harvest 12 | %h4.harvest-plant-part 13 | = harvest.plant_part_name 14 | %small.text-muted= harvest.harvested_at 15 | -------------------------------------------------------------------------------- /app/views/harvests/edit.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "Editing harvest" 2 | 3 | = render 'form' 4 | 5 | = link_to 'Show', @harvest 6 | \| 7 | = link_to 'Back', harvests_path 8 | -------------------------------------------------------------------------------- /app/views/harvests/new.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, t('harvests.harvest_something') 2 | 3 | = render 'form' 4 | -------------------------------------------------------------------------------- /app/views/home/_activities.html.haml: -------------------------------------------------------------------------------- 1 | %h2= t('.recent_activities') 2 | - Activity.homepage_records(6).each do |activity| 3 | - cache activity do 4 | = link_to activity_path(slug: activity.slug), class: 'list-group-item list-group-item-action flex-column align-items-start' do 5 | .d-flex.w-100.justify-content-between.homepage--list-item 6 | %div 7 | %h4= activity.name 8 | %span.badge.badge-success= activity.category 9 | %small.text-muted 10 | by #{activity.owner_login_name} -------------------------------------------------------------------------------- /app/views/home/_blurb.html.haml: -------------------------------------------------------------------------------- 1 | .row.homepage-blurb 2 | .col-md-8.info 3 | %h1 Growstuff - An open gardening platform 4 | %p= t('.intro', site_name: ENV['GROWSTUFF_SITE_NAME']) 5 | = render 'stats' 6 | .col-md-4 7 | .signup 8 | %p= t('.perks') 9 | %p= link_to(t('.sign_up'), new_member_registration_path, class: 'btn btn-primary btn-block') 10 | %p= t('.already_html', sign_in: link_to(t('.sign_in_linktext'), new_member_session_path, class: 'btn btn-primary')) 11 | -------------------------------------------------------------------------------- /app/views/home/_crops.html.haml: -------------------------------------------------------------------------------- 1 | - cache cache_key_for(Crop, 'homepage'), expires_in: 1.day do 2 | .index-cards 3 | - CropSearchService.random_with_photos(20).each do |c| 4 | = render 'crops/thumbnail', crop: c 5 | -------------------------------------------------------------------------------- /app/views/home/_discuss.html.haml: -------------------------------------------------------------------------------- 1 | 2 | %h2.font-weight-bold.mb-4.pb-2 Recent posts 3 | .row 4 | - Post.includes(:author, :crop_posts, :crops).order(created_at: :desc).limit(6).each do |post| 5 | .col-lg-4.col-md-12.mb-4 6 | = render 'posts/preview', post: post 7 | 8 | %p.text-right 9 | = link_to "#{t('.view_all')} »", posts_path, class: 'btn btn-block' 10 | -------------------------------------------------------------------------------- /app/views/home/_members.html.haml: -------------------------------------------------------------------------------- 1 | - cache cache_key_for(Member) do 2 | .hidden-xs 3 | - members = Member.interesting.limit(6) 4 | - if members.present? 5 | %h2.text-center= t('.title') 6 | .index-cards 7 | = render partial: 'members/member', collection: members 8 | %p.text-right 9 | = link_to "#{t('.view_all')} »", members_path, class: 'btn btn-block' 10 | -------------------------------------------------------------------------------- /app/views/home/_seeds.html.haml: -------------------------------------------------------------------------------- 1 | - cache cache_key_for(Seed) do 2 | %h2.text-center= t('home.seeds.title') 3 | .row 4 | - Seed.homepage_records(9).each do |s| 5 | .col-6.col-md-4= render 'seeds/card', seed: s 6 | -------------------------------------------------------------------------------- /app/views/home/_stats.html.haml: -------------------------------------------------------------------------------- 1 | - cache("homepage_stats") do 2 | %p.stats 3 | = t('.message_html', 4 | member: link_to(t('.member_linktext', count: Member.confirmed.size.to_i), members_path), 5 | number_crops: link_to(t('.number_crops_linktext', count: Crop.count.to_i), crops_path), 6 | number_plantings: link_to(t('.number_plantings_linktext', count: Planting.count.to_i), plantings_path), 7 | number_gardens: link_to(t('.number_gardens_linktext', count: Garden.count.to_i), gardens_path)) 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/views/layouts/_fact_card.haml: -------------------------------------------------------------------------------- 1 | .card.fact-card 2 | .card-body.text-center 3 | %h3= title 4 | %strong= value 5 | - if description.present? 6 | %span= description -------------------------------------------------------------------------------- /app/views/layouts/_footer.html.haml: -------------------------------------------------------------------------------- 1 | - cache 'footer', expires: 1.week do 2 | .container-fluid.text-center.text-md-left 3 | .row 4 | .col-md-4#footer1 5 | != cms_snippet_content(:footer1) 6 | .col-md-4#footer2 7 | != cms_snippet_content(:footer2) 8 | .col-md-4#footer3 9 | .badge.badge-success= link_to 'API', '/api-docs' 10 | != cms_snippet_content(:footer3) 11 | %div{ style: "float: right;" } 12 | = link_to "https://opendefinition.org/ossd/" do 13 | = image_tag 'open_service.png', alt: "Open Service" 14 | -------------------------------------------------------------------------------- /app/views/layouts/mailer.text.erb: -------------------------------------------------------------------------------- 1 | <%= yield %> 2 | -------------------------------------------------------------------------------- /app/views/layouts/modal.html.haml: -------------------------------------------------------------------------------- 1 | #mainModal.modal{"aria-hidden" => "true", "aria-labelledby" => "mainModalLabel", role: "dialog", tabindex: "-1"} 2 | .modal-dialog 3 | .modal-content 4 | .modal-header 5 | %button.close{"data-bs-dismiss" => "modal", type: "button"} 6 | %span{"aria-hidden" => "true"} × 7 | %span.sr-only Close 8 | %h4#mainModalLabel.modal-title 9 | = yield :title if content_for? :title 10 | \  11 | = yield 12 | -------------------------------------------------------------------------------- /app/views/likes/_count.haml: -------------------------------------------------------------------------------- 1 | %span.badge.like-badge{class: liked ? 'liked' : ''} 2 | = like_icon 3 |   4 | %span.like-count{title: t('buttons.total_likes')}= likeable.likes_count 5 | -------------------------------------------------------------------------------- /app/views/mailboxer/message_mailer/new_message_email.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

You have a new message: <%= @subject %>

8 |

9 | You have received a new message: 10 |

11 |
12 |

13 | <%= raw @message.body %> 14 |

15 |
16 |

17 | Visit <%= link_to root_url, root_url %> and go to your inbox for more info. 18 |

19 | 20 | 21 | -------------------------------------------------------------------------------- /app/views/mailboxer/message_mailer/new_message_email.text.erb: -------------------------------------------------------------------------------- 1 | You have a new message: <%= @subject %> 2 | =============================================== 3 | 4 | You have received a new message: 5 | 6 | ----------------------------------------------- 7 | <%= @message.body.html_safe? ? @message.body : strip_tags(@message.body) %> 8 | ----------------------------------------------- 9 | 10 | Visit <%= root_url %> and go to your inbox for more info. 11 | -------------------------------------------------------------------------------- /app/views/mailboxer/message_mailer/reply_message_email.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

You have a new reply: <%= @subject %>

8 |

9 | You have received a new reply: 10 |

11 |
12 |

13 | <%= raw @message.body %> 14 |

15 |
16 |

17 | Visit <%= link_to root_url, root_url %> and go to your inbox for more info. 18 |

19 | 20 | 21 | -------------------------------------------------------------------------------- /app/views/mailboxer/message_mailer/reply_message_email.text.erb: -------------------------------------------------------------------------------- 1 | You have a new reply: <%= @subject %> 2 | =============================================== 3 | 4 | You have received a new reply: 5 | 6 | ----------------------------------------------- 7 | <%= @message.body.html_safe? ? @message.body : strip_tags(@message.body) %> 8 | ----------------------------------------------- 9 | 10 | Visit <%= root_url %> and go to your inbox for more info. 11 | -------------------------------------------------------------------------------- /app/views/mailboxer/notification_mailer/new_notification_email.text.erb: -------------------------------------------------------------------------------- 1 | You have a new notification: <%= @notification.subject.html_safe? ? @notification.subject : strip_tags(@notification.subject) %> 2 | =============================================== 3 | 4 | You have received a new notification: 5 | 6 | ----------------------------------------------- 7 | <%= @notification.body.html_safe? ? @notification.body : strip_tags(@notification.body) %> 8 | ----------------------------------------------- 9 | 10 | Visit <%= root_url %> and go to your notifications for more info. 11 | -------------------------------------------------------------------------------- /app/views/members/_avatar.html.haml: -------------------------------------------------------------------------------- 1 | = link_to image_tag(avatar_uri(member, 150), alt: "Avatar of #{member}", class: 'avatar img img-fluid'), member_path(member) 2 | -------------------------------------------------------------------------------- /app/views/members/_bio.html.haml: -------------------------------------------------------------------------------- 1 | %h2 All about #{member.login_name} 2 | %p 3 | %small 4 | %a{href: "#content"} 5 | Skip to main content 6 | - if member.bio.blank? 7 | - if can? :edit, member 8 | = link_to "Add a bio to complete your profile.", edit_member_registration_path 9 | - else 10 | #{member.login_name} hasn't written a bio yet. 11 | - else 12 | :markdown 13 | #{ strip_tags markdownify(member.bio) } 14 | -------------------------------------------------------------------------------- /app/views/members/_contact.html.haml: -------------------------------------------------------------------------------- 1 | - if twitter_auth || flickr_auth || member.show_email 2 | %h4 Contact 3 | 4 | - if twitter_auth 5 | %p 6 | = image_tag "twitter_32.png", size: "32x32", alt: 'Twitter logo' 7 | = link_to twitter_auth.name, "https://twitter.com/#{twitter_auth.name}" 8 | 9 | - if flickr_auth 10 | %p 11 | = image_tag "flickr_32.png", size: "32x32", alt: 'Flickr logo' 12 | = link_to flickr_auth.name, "https://flickr.com/photos/#{flickr_auth.uid}" 13 | 14 | - if member.show_email 15 | %p 16 | Email: 17 | = mail_to member.email 18 | -------------------------------------------------------------------------------- /app/views/members/_follow_buttons.haml: -------------------------------------------------------------------------------- 1 | - if current_member && current_member != member # must be logged in, can't follow yourself 2 | - follow = current_member.get_follow(member) 3 | - if !follow && can?(:create, Follow) # not already following 4 | = link_to 'Follow', follows_path(followed: member), method: :post, class: 'btn btn-block btn-success' 5 | - if follow && can?(:destroy, follow) # already following 6 | = link_to 'Unfollow', follow_path(follow), method: :delete, class: 'btn btn-block' -------------------------------------------------------------------------------- /app/views/members/_gardens.html.haml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/app/views/members/_gardens.html.haml -------------------------------------------------------------------------------- /app/views/members/_harvests.html.haml: -------------------------------------------------------------------------------- 1 | .card-row-short 2 | - harvests.each do |harvest| 3 | .card 4 | = render partial: "harvests/card", locals: { harvest: harvest } 5 | - if !harvests.any? 6 | #{member.login_name} hasn't harvested anything yet. 7 | -------------------------------------------------------------------------------- /app/views/members/_location.html.haml: -------------------------------------------------------------------------------- 1 | - if member.location.present? 2 | = link_to place_path(member.location) do 3 | %span.badge.badge-location{ title: member.location } 4 | = icon 'fas', 'map-marker' 5 | = truncate(member.location, length: 15, separator: ' ', omission: '... ') 6 | - else 7 | %span.badge.badge-location 8 | unknown location -------------------------------------------------------------------------------- /app/views/members/_map.html.haml: -------------------------------------------------------------------------------- 1 | - if member.latitude && member.longitude 2 | #membermap.member-map 3 | %p.text-right 4 | See other members, plantings, seeds and more near 5 | = link_to member.location, place_path(member.location, anchor: "members") 6 | - else 7 | .location-not-set 8 | .sr-only Location not known 9 | .sr-only We can't show you what's nearby 10 | -------------------------------------------------------------------------------- /app/views/members/_tiny.haml: -------------------------------------------------------------------------------- 1 | %span.chip.member-chip 2 | - if member.discarded? 3 | = icon 'fas', 'user-times' 4 | = member 5 | - else 6 | = link_to member do 7 | = image_tag(avatar_uri(member, 100), alt: member.login_name, height: 50, width: 50) 8 | = member 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/views/members/show.rss.haml: -------------------------------------------------------------------------------- 1 | 2 | %rss{ version: 2.0 } 3 | %channel 4 | %title #{@member.login_name}'s recent posts (#{ENV['GROWSTUFF_SITE_NAME']}) 5 | %link= member_url(@member) 6 | - @member.posts.each do |post| 7 | %item 8 | %title #{post.subject} by #{post.author.login_name} 9 | %pubdate= post.created_at.to_fs(:rfc822) 10 | %link= post_url(post) 11 | %guid= post_url(post) 12 | %description 13 | :escaped_markdown 14 | #{ strip_tags markdownify(post.body) } 15 | -------------------------------------------------------------------------------- /app/views/members/unsubscribe.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "Unsubscribe #{@member}" 2 | %h1 Unsubscribe #{@member} 3 | %p 4 | If you wish to unsubscribe from other Growstuff emails, you may do so via 5 | = link_to "your settings page", edit_member_registration_url 6 | -------------------------------------------------------------------------------- /app/views/messages/new.html.haml: -------------------------------------------------------------------------------- 1 | = content_for :title, "Send a message to #{@recipient}" 2 | - content_for :breadcrumbs do 3 | %li.breadcrumb-item= link_to 'Messages', conversations_path 4 | 5 | = render 'form' 6 | 7 | -------------------------------------------------------------------------------- /app/views/notifier_mailer/_planting.haml: -------------------------------------------------------------------------------- 1 | = link_to planting_url(planting) do 2 | = planting.crop 3 | -------------------------------------------------------------------------------- /app/views/notifier_mailer/_signature.html.haml: -------------------------------------------------------------------------------- 1 | %p 2 | The #{ENV['GROWSTUFF_SITE_NAME']} team. 3 | %br/ 4 | = link_to root_url, root_url 5 | -------------------------------------------------------------------------------- /app/views/notifier_mailer/crop_request_approved.html.haml: -------------------------------------------------------------------------------- 1 | %p Hello #{@member.login_name}, 2 | 3 | %p 4 | Your request for the new crop: #{link_to @crop.name, crop_url(@crop)} has 5 | been approved! Thank you for helping us make our listing ever more complete! 6 | 7 | %ul 8 | %li 9 | = link_to "Plant #{@crop.name}", new_planting_url(crop_id: @crop.id) 10 | %li 11 | = link_to "Harvest #{@crop.name}", new_harvest_url(crop_id: @crop.id) 12 | %li 13 | = link_to "Stash seeds for #{@crop.name}", new_seed_url(crop_id: @crop.id) 14 | 15 | = render partial: 'signature' 16 | 17 | -------------------------------------------------------------------------------- /app/views/notifier_mailer/crop_request_rejected.html.haml: -------------------------------------------------------------------------------- 1 | %p 2 | Hello #{@member.login_name}, 3 | %p 4 | We're sorry, but your request for the new crop: 5 | = link_to @crop.name, crop_url(@crop) 6 | has been rejected for the following reason: 7 | = @crop.rejection_explanation 8 | 9 | = render partial: 'signature' 10 | -------------------------------------------------------------------------------- /app/views/notifier_mailer/new_crop_request.html.haml: -------------------------------------------------------------------------------- 1 | %p 2 | Hello 3 | = @member.login_name 4 | , 5 | 6 | %p 7 | = @request.requester.login_name 8 | has requested a new crop on 9 | = ENV['GROWSTUFF_SITE_NAME'] 10 | 11 | %ul 12 | %li Name: #{@request.name} 13 | %li Wikipedia URL: #{@request.en_wikipedia_url.present? ? @request.en_wikipedia_url : 'not specified'} 14 | %li Notes: #{@request.request_notes} 15 | 16 | %p 17 | As a crop wrangler, you can 18 | = link_to "approve or reject this request", edit_crop_url(@request) 19 | \. 20 | 21 | %p 22 | Thanks for your help! 23 | 24 | = render partial: 'signature' 25 | -------------------------------------------------------------------------------- /app/views/photos/_actions.html.haml: -------------------------------------------------------------------------------- 1 | - if can?(:edit, @photo) && can?(:destroy, @photo) 2 | .dropdown.float-right.photo-actions 3 | %a#photo-actions-button.btn.dropdown-toggle{"aria-expanded" => "false", "aria-haspopup" => "true", "data-bs-toggle" => "dropdown", type: "button", href: '#'} Actions 4 | .dropdown-menu.dropdown-menu-xs{"aria-labelledby" => "photo-actions-button"} 5 | = edit_button(edit_photo_path(@photo), classes: 'dropdown-item') 6 | .dropdown-divider 7 | = delete_button(@photo, classes: 'dropdown-item text-danger') 8 | -------------------------------------------------------------------------------- /app/views/photos/_association_delete_button.haml: -------------------------------------------------------------------------------- 1 | - if can? :edit, photo 2 | = link_to photo_association_path(photo_id: photo.id, type: type, id: thing.id), 3 | data: { confirm: "Removing photo from this #{type}. Are you sure?" }, 4 | method: 'delete', class: 'text-warning btn-sm' do 5 | = delete_association_icon 6 | 7 | -------------------------------------------------------------------------------- /app/views/photos/_description.haml: -------------------------------------------------------------------------------- 1 | took a photo #{link_to event_model.title, event_model} 2 | -------------------------------------------------------------------------------- /app/views/photos/_gallery.haml: -------------------------------------------------------------------------------- 1 | .index-cards 2 | - photos.each do |photo| 3 | = render 'photos/card', photo: photo 4 | 5 | -------------------------------------------------------------------------------- /app/views/photos/_hero.html.haml: -------------------------------------------------------------------------------- 1 | .photo.hero.jumbotron 2 | .row 3 | .col-6 4 | = image_tag(photo.thumbnail_url, alt: photo.title, class: 'img img-responsive hero-photo') 5 | .col-6 6 | %h3= link_to photo.title, photo 7 | - if photo.date_taken 8 | Taken on #{I18n.l photo.date_taken} 9 | -------------------------------------------------------------------------------- /app/views/photos/_photo.haml: -------------------------------------------------------------------------------- 1 | .photo 2 | = image_tag(photo.fullsize_url, alt: photo.title, class: 'img img-responsive') 3 | .text 4 | %p 5 | = link_to photo.title, photo 6 | %br/ 7 | %small 8 | %i 9 | by 10 | = link_to photo.owner, photo.owner -------------------------------------------------------------------------------- /app/views/photos/_thumbnail.html.haml: -------------------------------------------------------------------------------- 1 | .thumbnail 2 | .photo-thumbnail{id: "photo-#{photo.id}"} 3 | = link_to image_tag(photo.thumbnail_url, alt: photo.title, class: 'img img-responsive rounded'), photo 4 | .text.ellipsis 5 | %p 6 | = link_to photo.title, photo 7 | %br/ 8 | %small 9 | %i 10 | by 11 | = link_to photo.owner, photo.owner 12 | -------------------------------------------------------------------------------- /app/views/photos/_tiny.html.haml: -------------------------------------------------------------------------------- 1 | - if photo.present? 2 | .photo 3 | = image_tag(photo.thumbnail_url, alt: photo.title, class: 'img img-tiny') 4 | -------------------------------------------------------------------------------- /app/views/photos/index.html.haml: -------------------------------------------------------------------------------- 1 | %h1 2 | - if @crop 3 | Photos of #{@crop.name} 4 | - elsif @planting.present? 5 | Photos of #{@planting} 6 | - else 7 | Most recent photos added to #{ENV['GROWSTUFF_SITE_NAME']}. 8 | 9 | - content_for :breadcrumbs do 10 | %li.breadcrumb-item= link_to 'Photos', photos_path 11 | 12 | = will_paginate @photos 13 | 14 | .index-cards 15 | - @photos.each do |p| 16 | = render 'photos/card', photo: p 17 | 18 | = page_entries_info @photos 19 | = will_paginate @photos 20 | -------------------------------------------------------------------------------- /app/views/places/_map_attribution.html.haml: -------------------------------------------------------------------------------- 1 | Map data © 2 | = link_to "OpenStreetMap", "https://openstreetmap.org" 3 | contributors under 4 | = link_to "ODbL", "https://www.openstreetmap.org/copyright" 5 | -------------------------------------------------------------------------------- /app/views/places/_search_form.html.haml: -------------------------------------------------------------------------------- 1 | %form.form-inline{ action: search_places_path, method: :get, role: 'form' } 2 | .form-group 3 | = label_tag :new_place, "Change location:", class: 'sr-only' 4 | = text_field_tag :new_place, '', class: 'form-control', placeholder: "Search for city, suburb or state..." 5 | = submit_tag "Search", class: 'btn btn-primary', id: "search_button" 6 | %br/ 7 | -------------------------------------------------------------------------------- /app/views/places/index.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, t(".title", site_name: ENV['GROWSTUFF_SITE_NAME']) 2 | 3 | %h2=t(".title", site_name: ENV['GROWSTUFF_SITE_NAME']) 4 | 5 | = render partial: 'search_form' 6 | #placesmap.map 7 | -------------------------------------------------------------------------------- /app/views/plant_parts/_form.html.haml: -------------------------------------------------------------------------------- 1 | = form_for @plant_part do |f| 2 | - if @plant_part.errors.any? 3 | #error_explanation 4 | %h2 5 | = pluralize(@plant_part.errors.size, "error") 6 | prohibited this plant_part from being saved: 7 | %ul 8 | - @plant_part.errors.full_messages.each do |msg| 9 | %li= msg 10 | 11 | .field 12 | = f.label :name 13 | = f.text_field :name 14 | .actions 15 | = f.submit 'Save' 16 | -------------------------------------------------------------------------------- /app/views/plant_parts/edit.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "Editing plant part" 2 | 3 | = render 'form' 4 | 5 | = link_to 'Show', @plant_part 6 | \| 7 | = link_to 'Back', plant_parts_path 8 | -------------------------------------------------------------------------------- /app/views/plant_parts/new.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "New plant part" 2 | 3 | = render 'form' 4 | 5 | = link_to 'Back', plant_parts_path 6 | -------------------------------------------------------------------------------- /app/views/plantings/_description.haml: -------------------------------------------------------------------------------- 1 | planted #{link_to event_model.crop, event_model} 2 | -------------------------------------------------------------------------------- /app/views/plantings/_harvests.html.haml: -------------------------------------------------------------------------------- 1 | %h2 Harvests 2 | 3 | - if can? :edit, planting 4 | = render 'harvests/modal', harvest: Harvest.new(crop: planting.crop, planting: planting) 5 | - if planting.harvests.empty? 6 | %p No harvests recorded 7 | - if !planting.finished? && can?(:edit, planting) && can?(:create, Harvest) 8 | %p Record your harvests here to improve crop predictions, and you'll be able to compare with your garden next season. 9 | - else 10 | .index-cards 11 | - planting.harvests.each do |harvest| 12 | = render 'harvests/thumbnail', harvest: harvest 13 | -------------------------------------------------------------------------------- /app/views/plantings/_image_with_popover.html.haml: -------------------------------------------------------------------------------- 1 | - cache planting do 2 | = link_to image_tag(planting_image_path(planting), 3 | alt: planting.to_s, 4 | class: 'image-responsive'), 5 | planting, 6 | rel: "popover", 7 | 'data-bs-toggle': 'popover', 8 | 'data-bs-trigger': 'hover', 9 | 'data-bs-title': planting.crop.name, 10 | 'data-bs-content': render('plantings/popover', planting: planting), 11 | 'data-bs-html': true 12 | -------------------------------------------------------------------------------- /app/views/plantings/_photos.haml: -------------------------------------------------------------------------------- 1 | %h2 Photos 2 | - if planting.photos.size.positive? 3 | = render 'photos/gallery', photos: photos 4 | - if can?(:edit, planting) && can?(:create, Photo) 5 | %p.text-right= add_photo_button(planting) 6 | %p.text-right 7 | = link_to planting_photos_path(planting), class: 'btn' do 8 | = photo_icon 9 | more photos 10 | - else 11 | %p No photos. 12 | - if can?(:edit, planting) && can?(:create, Photo) 13 | %p Add a photo to visually track growth of this planting, to Flickr, iNaturalist or Pl@ntNet 14 | = add_photo_button(planting) 15 | -------------------------------------------------------------------------------- /app/views/plantings/_planting.haml: -------------------------------------------------------------------------------- 1 | - if local_assigns[:full] 2 | - cache planting do 3 | = render 'plantings/card', planting: planting 4 | - else 5 | - cache planting do 6 | = render 'plantings/thumbnail', planting: planting -------------------------------------------------------------------------------- /app/views/plantings/_popover.html.haml: -------------------------------------------------------------------------------- 1 | - if planting.quantity.present? 2 | %p 3 | %small 4 | Quantity: 5 | = planting.quantity 6 | 7 | - if planting.planted_at.present? 8 | %p 9 | %small 10 | Planted: 11 | = planting.planted_at.to_s 12 | -------------------------------------------------------------------------------- /app/views/plantings/_thumbnail.html.haml: -------------------------------------------------------------------------------- 1 | .card.planting.thumbnail 2 | .planting-thumbnail-image 3 | = link_to image_tag(planting_image_path(planting), 4 | alt: planting.crop, class: 'img-card'), 5 | planting 6 | .card-body 7 | %h4 8 | = crop_icon(planting.crop) 9 | = link_to planting.crop, planting 10 | planting 11 | - if planting.finished_at.present? 12 | %h6.card-subtitle.text-muted=planting.finished_at 13 | -------------------------------------------------------------------------------- /app/views/plantings/_timeline_icon.haml: -------------------------------------------------------------------------------- 1 | - if @planting.first_harvest_date.present? 2 | - # this planting has harvests 3 | - if date_this_week >= @planting.first_harvest_date 4 | = crop_icon(@planting.crop) 5 | - else 6 | = growing_icon 7 | - elsif @planting.first_harvest_predicted_at.present? 8 | - # no harvests yet, so use predicted harvest 9 | - if date_this_week < @planting.first_harvest_predicted_at 10 | = growing_icon 11 | - elsif date_this_week > @planting.first_harvest_predicted_at 12 | = crop_icon(@planting.crop) 13 | - else 14 | = week_number -------------------------------------------------------------------------------- /app/views/plantings/_tiny.html.haml: -------------------------------------------------------------------------------- 1 | = link_to planting do 2 | .chip.crop-chip 3 | = crop_icon(planting.crop) 4 | = planting.crop.name 5 | -------------------------------------------------------------------------------- /app/views/plantings/edit.html.haml: -------------------------------------------------------------------------------- 1 | = content_for :title, "Editing planting" 2 | 3 | = render 'form' 4 | -------------------------------------------------------------------------------- /app/views/plantings/new.html.haml: -------------------------------------------------------------------------------- 1 | = content_for :title, t('plantings.plant_something') 2 | 3 | = render 'form' 4 | -------------------------------------------------------------------------------- /app/views/posts/_comments.html.haml: -------------------------------------------------------------------------------- 1 | %a{ name: "comments" } 2 | - if post.comments 3 | %hr/ 4 | %h2 5 | = comment_icon 6 | = localize_plural(post.comments, Comment) 7 | - post.comments.post_order.each do |comment| 8 | = render "comments/single", comment: comment 9 | 10 | - else 11 | %h2 There are no comments yet 12 | 13 | -------------------------------------------------------------------------------- /app/views/posts/_description.haml: -------------------------------------------------------------------------------- 1 | wrote a post about #{link_to event_model, event_model} -------------------------------------------------------------------------------- /app/views/posts/_single.html.haml: -------------------------------------------------------------------------------- 1 | %p 2 | Posted by 3 | - if @post.author 4 | = link_to @post.author.login_name, member_path(@post.author) 5 | - else 6 | Member Deleted 7 | - if @post.forum 8 | in 9 | = link_to @post.forum, @post.forum 10 | on 11 | = @post.created_at.to_fs(:default) 12 | - if @post.updated_at > @post.created_at 13 | and edited at 14 | = @post.updated_at.to_fs(:default) 15 | 16 | = link_to "Permalink", post 17 | 18 | :markdown 19 | #{ strip_tags markdownify(@post.body) } 20 | -------------------------------------------------------------------------------- /app/views/posts/edit.html.haml: -------------------------------------------------------------------------------- 1 | = content_for :title, "Edit post" 2 | 3 | = render 'form' 4 | 5 | -------------------------------------------------------------------------------- /app/views/posts/index.rss.haml: -------------------------------------------------------------------------------- 1 | 2 | %rss{ version: 2.0 } 3 | %channel 4 | %title 5 | Recent posts from #{@author ? @author : 'all members'} (#{ENV['GROWSTUFF_SITE_NAME']}) 6 | %link= posts_url 7 | - @posts.each do |post| 8 | %item 9 | %title #{post.subject} by #{post.author.login_name} 10 | %description 11 | :escaped_markdown 12 | #{ strip_tags markdownify(post.body) } 13 | %pubdate= post.created_at.to_fs(:rfc822) 14 | %link= post_url(post) 15 | %guid= post_url(post) 16 | -------------------------------------------------------------------------------- /app/views/posts/new.html.haml: -------------------------------------------------------------------------------- 1 | = content_for :title, @forum ? "Post in #{@forum.name}" : t('posts.write_blog_post') 2 | 3 | = render 'form' 4 | -------------------------------------------------------------------------------- /app/views/scientific_names/edit.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "Edit scientific name" 2 | 3 | %p 4 | Added by 5 | = link_to @scientific_name.creator, @scientific_name.creator 6 | = distance_of_time_in_words(@scientific_name.created_at, Time.zone.now) 7 | ago. 8 | 9 | = render 'form' 10 | -------------------------------------------------------------------------------- /app/views/scientific_names/new.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "New scientific name" 2 | 3 | = render 'form' 4 | -------------------------------------------------------------------------------- /app/views/seeds/_days_until_maturity.html.haml: -------------------------------------------------------------------------------- 1 | - if seed.days_until_maturity_min.blank? 2 | - if seed.days_until_maturity_max.blank? 3 | unknown 4 | - else 5 | = seed.days_until_maturity_max.to_s 6 | - elsif seed.days_until_maturity_max.blank? 7 | = seed.days_until_maturity_min.to_s 8 | - else 9 | != "#{seed.days_until_maturity_min}–#{seed.days_until_maturity_max}" 10 | -------------------------------------------------------------------------------- /app/views/seeds/_descendants.html.haml: -------------------------------------------------------------------------------- 1 | - if @seed.child_plantings.any? 2 | %h2 Plants grown from these seeds 3 | .index-cards 4 | - seed.child_plantings.each do |planting| 5 | = render 'plantings/thumbnail', planting: planting 6 | -------------------------------------------------------------------------------- /app/views/seeds/_description.haml: -------------------------------------------------------------------------------- 1 | saved #{link_to event_model.crop, event_model} seeds -------------------------------------------------------------------------------- /app/views/seeds/_owner.html.haml: -------------------------------------------------------------------------------- 1 | .card 2 | .card-body 3 | .row 4 | .col-md-8 5 | %h4 6 | Saved by 7 | = link_to @seed.owner, @seed.owner 8 | = link_to "view all #{@seed.owner}'s seeds", member_seeds_path(@seed.owner) 9 | 10 | .col-md-4= render "members/avatar", member: @seed.owner 11 | .row 12 | .col-12 13 | - if @seed.owner.location 14 | %p 15 | %small 16 | View other seeds, members and more near 17 | = link_to @seed.owner.location, place_path(@seed.owner.location, anchor: "seeds") -------------------------------------------------------------------------------- /app/views/seeds/_seed.haml: -------------------------------------------------------------------------------- 1 | - if local_assigns[:full] 2 | - cache seed do 3 | = render 'seeds/card', seed: seed 4 | - else 5 | - cache seed do 6 | = render 'seeds/thumbnail', seed: seed 7 | -------------------------------------------------------------------------------- /app/views/seeds/_thumbnail.html.haml: -------------------------------------------------------------------------------- 1 | .thumbnail 2 | .seed-thumbnail 3 | = link_to image_tag(seed_image_path(seed), 4 | alt: seed.crop.name, class: 'img'), 5 | seed_path(seed) 6 | .seedinfo 7 | .seed-name 8 | = link_to seed.crop, seed_path(seed) 9 | - if seed.saved_at.present? 10 | %span= I18n.l(seed.saved_at.to_date) 11 | -------------------------------------------------------------------------------- /app/views/seeds/edit.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, "Editing seeds" 2 | 3 | = render 'form' 4 | -------------------------------------------------------------------------------- /app/views/seeds/new.html.haml: -------------------------------------------------------------------------------- 1 | - content_for :title, t('seeds.save_seeds') 2 | 3 | = render 'form' 4 | -------------------------------------------------------------------------------- /app/views/shared/_flash_messages.html.haml: -------------------------------------------------------------------------------- 1 | - flash.each do |type, content| 2 | %div{ class: build_alert_classes(type), role: "alert" } 3 | %button.close{ type: "button", "data-bs-dismiss" => "alert" } 4 | %span{ "aria-hidden" => true } × 5 | %span.sr-only Close 6 | = content 7 | -------------------------------------------------------------------------------- /app/views/shared/_glyphicon.html.haml: -------------------------------------------------------------------------------- 1 | %span.glyphicon{class: "glyphicon-#{icon}", title: t(title) } 2 | =t(title) -------------------------------------------------------------------------------- /app/views/shared/_markdown_help.html.haml: -------------------------------------------------------------------------------- 1 | You can use 2 | = link_to 'Markdown', 'https://daringfireball.net/projects/markdown/syntax/' 3 | to format your text. 4 | %br/ 5 | For instance, *italic*, **bold**, or a link [like this](http://to.some.site.com/). 6 | %br/ 7 | Quick crop links: [sweet potato](crop). 8 | %br/ 9 | Quick member links: @Username or [Username](member). 10 | -------------------------------------------------------------------------------- /app/views/shared/_signin_signup.html.haml: -------------------------------------------------------------------------------- 1 | = link_to 'Sign in', new_member_session_path, class: 'text-success' 2 | or 3 | = link_to 'sign up', new_member_registration_path, class: 'text-info' 4 | to 5 | = succeed "." do 6 | = to 7 | -------------------------------------------------------------------------------- /app/views/shared/buttons/_delete.haml: -------------------------------------------------------------------------------- 1 | = link_to path, method: :delete, 2 | data: { confirm: t(:are_you_sure?) }, class: 'btn btn-default btn-xs' do 3 | = render 'shared/glyphicon', icon: 'trash', title: 'buttons.delete' 4 | =t('buttons.delete') 5 | -------------------------------------------------------------------------------- /app/views/shared/buttons/_edit.haml: -------------------------------------------------------------------------------- 1 | = link_to path, class: 'btn btn-default' do 2 | = render 'shared/glyphicon', icon: 'pencil', title: 'buttons.edit' 3 | =t('buttons.edit') 4 | -------------------------------------------------------------------------------- /app/views/shared/editable/_date.html.haml: -------------------------------------------------------------------------------- 1 | - if can? :edit, model 2 | %small.edit-link 3 | %a.editable-date#description{"data-field" => "#date--#{model.id}-#{field.to_s}", 4 | "data-display": display_field, href: "#"} 5 | = edit_icon 6 | .hide{id: "date--#{model.id}-#{field.to_s}"} 7 | = bootstrap_form_for(model) do |f| 8 | = f.date_field field, 9 | value: model.send(field) ? model.send(field).to_fs(:ymd) : '', label: 'When?' 10 | = f.submit :save 11 | -------------------------------------------------------------------------------- /app/views/support/index.html.haml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/app/views/support/index.html.haml -------------------------------------------------------------------------------- /bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 5 | load Gem.bin_path('bundler', 'bundle') 6 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | APP_PATH = File.expand_path('../config/application', __dir__) 5 | require_relative '../config/boot' 6 | require 'rails/commands' 7 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | require_relative '../config/boot' 5 | require 'rake' 6 | Rake.application.run 7 | -------------------------------------------------------------------------------- /bin/yarn: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | APP_ROOT = File.expand_path('..', __dir__) 5 | Dir.chdir(APP_ROOT) do 6 | exec "yarnpkg", *ARGV 7 | rescue Errno::ENOENT 8 | warn "Yarn executable was not detected in the system." 9 | warn "Download Yarn at https://yarnpkg.com/en/docs/install" 10 | exit 1 11 | end 12 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This file is used by Rack-based servers to start the application. 4 | 5 | require File.expand_path('config/environment', __dir__) 6 | run Rails.application 7 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 4 | 5 | require 'bundler/setup' # Set up gems listed in the Gemfile. 6 | # require 'bootsnap/setup' # Speed up boot time by caching expensive operations. 7 | -------------------------------------------------------------------------------- /config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: async 3 | 4 | test: 5 | adapter: async 6 | 7 | production: 8 | adapter: redis 9 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> 10 | channel_prefix: growstuff_production 11 | -------------------------------------------------------------------------------- /config/compass.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Require any additional compass plugins here. 4 | project_type = :rails 5 | -------------------------------------------------------------------------------- /config/elasticsearch.yml: -------------------------------------------------------------------------------- 1 | development: &default 2 | host: 'http://es01:9200' 3 | log: true 4 | test: 5 | host: 'http://es01:9200' 6 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Load the Rails application. 4 | require_relative 'application' 5 | 6 | # Initialize the Rails application. 7 | Rails.application.initialize! 8 | -------------------------------------------------------------------------------- /config/factory_bot.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | ActionDispatch::Callbacks.after do 4 | # Reload the factories 5 | return unless Rails.env.local? 6 | 7 | if FactoryBot.factories.present? # first init will load factories, this should only run on subsequent reloads 8 | FactoryBot.factories.clear 9 | FactoryBot.find_definitions 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Be sure to restart your server when you modify this file. 4 | 5 | # ActiveSupport::Reloader.to_prepare do 6 | # ApplicationController.renderer.defaults.merge!( 7 | # http_host: 'example.org', 8 | # https: false 9 | # ) 10 | # end 11 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Be sure to restart your server when you modify this file. 4 | 5 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 6 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 7 | 8 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 9 | # Rails.backtrace_cleaner.remove_silencers! 10 | -------------------------------------------------------------------------------- /config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Be sure to restart your server when you modify this file. 4 | 5 | # Specify a serializer for the signed and encrypted cookie jars. 6 | # Valid options are :json, :marshal, and :hybrid. 7 | Rails.application.config.action_dispatch.cookies_serializer = :json 8 | -------------------------------------------------------------------------------- /config/initializers/escaped_markdown.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'haml/filters/escaped_markdown' 4 | -------------------------------------------------------------------------------- /config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Be sure to restart your server when you modify this file. 4 | 5 | # Configure sensitive parameters which will be filtered from the log file. 6 | Rails.application.config.filter_parameters += [:password] 7 | -------------------------------------------------------------------------------- /config/initializers/geocoder.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'geocodable' 4 | 5 | Geocoder.configure( 6 | units: :km, 7 | timeout: 10, 8 | http_headers: { 9 | "User-Agent" => 10 | "#{Rails.application.config.user_agent} #{Rails.application.config.user_agent_email}", 11 | "From" => Rails.application.config.user_agent_email 12 | } 13 | ) 14 | # This configuration takes precedence over environment/test.rb 15 | # Reported as https://github.com/alexreisner/geocoder/issues/509 16 | Geocoder.configure(lookup: :nominatim) if Geocoder.config.lookup != :test 17 | -------------------------------------------------------------------------------- /config/initializers/growstuff_markdown.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'haml/filters/growstuff_markdown' 4 | -------------------------------------------------------------------------------- /config/initializers/jsonapi_resources.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | JSONAPI.configure do |config| 4 | # built in paginators are :none, :offset, :paged 5 | config.default_paginator = :offset 6 | config.default_page_size = 10 7 | config.maximum_page_size = 100 8 | end 9 | -------------------------------------------------------------------------------- /config/initializers/leaflet.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Leaflet.tile_layer = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png' 4 | Leaflet.attribution = '© OpenStreetMap contributors, CC-BY-SA' 5 | Leaflet.max_zoom = 18 6 | -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Be sure to restart your server when you modify this file. 4 | 5 | # Add new mime types for use in respond_to blocks: 6 | # Mime::Type.register "text/richtext", :rtf 7 | Mime::Type.register "text/calendar", :ics 8 | -------------------------------------------------------------------------------- /config/initializers/omniauth.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Rails.application.config.middleware.use OmniAuth::Builder do 4 | provider :twitter, ENV.fetch('GROWSTUFF_TWITTER_KEY', nil), ENV.fetch('GROWSTUFF_TWITTER_SECRET', nil) 5 | provider :flickr, ENV.fetch('GROWSTUFF_FLICKR_KEY', nil), ENV.fetch('GROWSTUFF_FLICKR_SECRET', nil), scope: 'read' 6 | end 7 | -------------------------------------------------------------------------------- /config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Be sure to restart your server when you modify this file. 4 | 5 | Rails.application.config.session_store :cookie_store, key: '_growstuff_session' 6 | 7 | # Use the database for sessions instead of the cookie-based default, 8 | # which shouldn't be used to store highly confidential information 9 | # (create the session table with "rails generate session_migration") 10 | # Rails.application.config.session_store :active_record_store 11 | -------------------------------------------------------------------------------- /config/initializers/sidekiq.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # config/initializers/sidekiq.rb 4 | 5 | Sidekiq.configure_server do |config| 6 | config.redis = { url: 'redis://localhost:6379/0', namespace: "app3_sidekiq_#{Rails.env}" } 7 | end 8 | 9 | Sidekiq.configure_client do |config| 10 | config.redis = { url: 'redis://localhost:6379/0', namespace: "app3_sidekiq_#{Rails.env}" } 11 | end 12 | -------------------------------------------------------------------------------- /config/initializers/swagger.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Jsonapi::Swagger.config do |config| 4 | config.use_rswag = false 5 | config.version = '2.0' 6 | config.info = { title: 'API V1', version: 'V1' } 7 | config.file_path = 'v1/swagger.json' 8 | end 9 | -------------------------------------------------------------------------------- /config/initializers/time_formats.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Time::DATE_FORMATS[:default] = '%B %d, %Y at %H:%M' 4 | Date::DATE_FORMATS[:default] = "%B %d, %Y" 5 | 6 | Time::DATE_FORMATS[:date] = "%B %d, %Y" 7 | Date::DATE_FORMATS[:date] = "%B %d, %Y" 8 | 9 | Date::DATE_FORMATS[:ymd] = "%Y-%m-%d" 10 | 11 | Time::DATE_FORMATS[:datetime] = '%B %d, %Y at %H:%M' 12 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Be sure to restart your server when you modify this file. 4 | 5 | # This file contains settings for ActionController::ParamsWrapper which 6 | # is enabled by default. 7 | 8 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 9 | ActiveSupport.on_load(:action_controller) do 10 | wrap_parameters format: [:json] 11 | end 12 | 13 | # To enable root element in JSON for ActiveRecord objects. 14 | ActiveSupport.on_load(:active_record) do 15 | self.include_root_in_json = false 16 | end 17 | -------------------------------------------------------------------------------- /config/locales/en.bootstrap.yml: -------------------------------------------------------------------------------- 1 | # Sample localization file for English. Add more files in this directory for other locales. 2 | # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. 3 | 4 | en: 5 | helpers: 6 | actions: "Actions" 7 | links: 8 | back: "Back" 9 | cancel: "Cancel" 10 | confirm: "Are you sure?" 11 | destroy: "Delete" 12 | new: "New" 13 | titles: 14 | edit: "Edit" 15 | save: "Save" 16 | new: "New" 17 | delete: "Delete" 18 | -------------------------------------------------------------------------------- /config/locales/ja.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ja: 3 | home: 4 | blurb: 5 | intro: "%{site_name}はガーデナーのコミュニティです。" 6 | -------------------------------------------------------------------------------- /config/robots.staging.txt: -------------------------------------------------------------------------------- 1 | User-Agent: * 2 | Disallow: / 3 | -------------------------------------------------------------------------------- /config/robots.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/config/robots.txt -------------------------------------------------------------------------------- /config/setup_load_paths.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | if ENV['MY_RUBY_HOME']&.include?('rvm') 4 | begin 5 | require 'rvm' 6 | RVM.use_from_path! File.dirname(__FILE__, 2) 7 | rescue LoadError 8 | # RVM is unavailable at this point. 9 | raise "RVM ruby lib is currently unavailable." 10 | end 11 | end 12 | 13 | # Select the correct item for which you use below. 14 | # If you're not using bundler, remove it completely. 15 | 16 | # If we're using a Bundler 1.0 beta 17 | ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', File.dirname(__FILE__)) 18 | require 'bundler/setup' 19 | -------------------------------------------------------------------------------- /config/sidekiq.yml: -------------------------------------------------------------------------------- 1 | --- 2 | :concurrency: 1 3 | :queues: 4 | - default 5 | - mailers 6 | -------------------------------------------------------------------------------- /config/spring.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | %w( 4 | .ruby-version 5 | .rbenv-vars 6 | tmp/restart.txt 7 | tmp/caching-dev.txt 8 | ).each { |path| Spring.watch(path) } 9 | -------------------------------------------------------------------------------- /db/migrate/20120903112806_add_username_to_users.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddUsernameToUsers < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :users, :username, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20121001212604_create_crops.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateCrops < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :crops do |t| 6 | t.string :system_name 7 | t.string :en_wikipedia_url 8 | t.timestamps null: true 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20121003190731_require_system_name_for_crops.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RequireSystemNameForCrops < ActiveRecord::Migration[4.2] 4 | def up 5 | change_table :crops do |t| 6 | t.index :system_name 7 | t.change :system_name, :string, null: false 8 | end 9 | end 10 | 11 | def down 12 | change_table :crops do |t| 13 | t.change :system_name, :string, null: true 14 | t.remove_index :system_name 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /db/migrate/20121027035231_add_slug_to_crops.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddSlugToCrops < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :crops, :slug, :string 6 | add_index :crops, :slug, unique: true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20121105032913_create_gardens.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateGardens < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :gardens do |t| 6 | t.string :name, null: false 7 | t.integer :user_id 8 | t.string :slug, null: false 9 | 10 | t.timestamps null: true 11 | end 12 | 13 | add_index :gardens, :user_id 14 | add_index :gardens, :slug, unique: true 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /db/migrate/20121106101718_add_slug_to_users.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddSlugToUsers < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :users, :slug, :string 6 | add_index :users, :slug, unique: true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20121107012827_create_scientific_names.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateScientificNames < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :scientific_names do |t| 6 | t.string :scientific_name, null: false 7 | t.integer :crop_id, null: false 8 | 9 | t.timestamps null: true 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20121108105440_create_updates.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateUpdates < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :updates do |t| 6 | t.integer :user_id, null: false 7 | t.string :subject, null: false 8 | t.text :body, null: false 9 | 10 | t.timestamps null: true 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20121109130033_add_creation_index_to_updates.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddCreationIndexToUpdates < ActiveRecord::Migration[4.2] 4 | def change 5 | add_index :updates, %i(created_at user_id) 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20121203034745_add_tos_agreement_to_users.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddTosAgreementToUsers < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :users, :tos_agreement, :boolean 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20121214224227_add_slug_to_updates.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddSlugToUpdates < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :updates, :slug, :string 6 | add_index :updates, :slug, unique: true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20121219022554_create_plantings.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreatePlantings < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :plantings do |t| 6 | t.integer :garden_id, null: false 7 | t.integer :crop_id, null: false 8 | t.datetime :planted_at 9 | t.integer :quantity 10 | t.text :description 11 | 12 | t.timestamps null: true 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20130113045802_rename_updates_to_posts.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameUpdatesToPosts < ActiveRecord::Migration[4.2] 4 | def change 5 | rename_table :updates, :posts 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130113060852_rename_users_to_members.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameUsersToMembers < ActiveRecord::Migration[4.2] 4 | def change 5 | rename_table :users, :members 6 | rename_column :members, :username, :login_name 7 | rename_column :gardens, :user_id, :member_id 8 | rename_column :posts, :user_id, :member_id 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20130113081521_rename_post_member_to_author.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenamePostMemberToAuthor < ActiveRecord::Migration[4.2] 4 | def change 5 | rename_column :posts, :member_id, :author_id 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130113095802_rename_garden_member_to_owner.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameGardenMemberToOwner < ActiveRecord::Migration[4.2] 4 | def change 5 | rename_column :gardens, :member_id, :owner_id 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130118031942_add_description_to_gardens.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddDescriptionToGardens < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :gardens, :description, :text 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130118043431_add_slug_to_plantings.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddSlugToPlantings < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :plantings, :slug, :string 6 | add_index :plantings, :slug, unique: true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20130206033956_create_comments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateComments < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :comments do |t| 6 | t.integer :post_id 7 | t.integer :author_id 8 | t.text :body 9 | 10 | t.timestamps null: true 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20130206051328_add_show_email_to_member.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddShowEmailToMember < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :members, :show_email, :boolean 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130208034248_require_fields_for_comments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RequireFieldsForComments < ActiveRecord::Migration[4.2] 4 | def up 5 | change_table :comments do |t| 6 | t.change :post_id, :integer, null: false 7 | t.change :author_id, :integer, null: false 8 | t.change :body, :text, null: false 9 | end 10 | end 11 | 12 | def down 13 | change_table :comments do |t| 14 | t.change :post_id, :integer, null: true 15 | t.change :author_id, :integer, null: true 16 | t.change :body, :text, null: true 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /db/migrate/20130212001748_add_geo_to_members.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddGeoToMembers < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :members, :location, :string 6 | add_column :members, :latitude, :float 7 | add_column :members, :longitude, :float 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20130212123628_create_notifications.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateNotifications < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :notifications do |t| 6 | t.integer :from_id 7 | t.integer :to_id, null: false 8 | t.string :subject 9 | t.text :body 10 | t.boolean :read 11 | t.integer :post_id 12 | 13 | t.timestamps null: true 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /db/migrate/20130213014511_create_forums.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateForums < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :forums do |t| 6 | t.string :name, null: false 7 | t.text :description, null: false 8 | t.integer :owner_id, null: false 9 | 10 | t.timestamps null: true 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20130213015708_add_forum_to_posts.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddForumToPosts < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :posts, :forum_id, :integer 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130214024117_create_roles.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateRoles < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :roles do |t| 6 | t.string :name, null: false 7 | t.text :description 8 | 9 | t.timestamps null: true 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20130214034838_add_members_roles_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddMembersRolesTable < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :members_roles, id: false do |t| 6 | t.integer :member_id 7 | t.integer :role_id 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20130215131921_rename_notification_fields.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameNotificationFields < ActiveRecord::Migration[4.2] 4 | def change 5 | change_table :notifications do |t| 6 | t.rename :to_id, :recipient_id 7 | t.rename :from_id, :sender_id 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20130220044605_add_slug_to_forums.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddSlugToForums < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :forums, :slug, :string 6 | add_index :forums, :slug, unique: true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20130220044642_add_slug_to_roles.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddSlugToRoles < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :roles, :slug, :string 6 | add_index :roles, :slug, unique: true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20130222060730_default_read_to_false.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class DefaultReadToFalse < ActiveRecord::Migration[4.2] 4 | def up 5 | change_table :notifications do |t| 6 | t.change :read, :boolean, default: false 7 | end 8 | end 9 | 10 | def down 11 | change_table :notifications do |t| 12 | t.change :read, :boolean, default: nil 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20130326092227_change_planted_at_to_date.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ChangePlantedAtToDate < ActiveRecord::Migration[4.2] 4 | def change 5 | change_column :plantings, :planted_at, :date 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130327120024_add_send_email_to_member.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddSendEmailToMember < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :members, :send_notification_email, :boolean, default: true 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130329045744_add_sunniness_to_planting.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddSunninessToPlanting < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :plantings, :sunniness, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130404174459_create_authentications.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateAuthentications < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :authentications do |t| 6 | t.integer :member_id, null: false 7 | t.string :provider, null: false 8 | t.string :uid 9 | t.string :token 10 | t.string :secret 11 | t.timestamps null: true 12 | end 13 | add_index :authentications, :member_id 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20130409103549_make_post_subject_non_null.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class MakePostSubjectNonNull < ActiveRecord::Migration[4.2] 4 | change_column :posts, :subject, :string, null: false 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130409162140_add_name_to_authentications.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddNameToAuthentications < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :authentications, :name, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130507105357_create_products.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateProducts < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :products do |t| 6 | t.string :name, null: false 7 | t.string :description, null: false 8 | t.decimal :min_price, null: false 9 | 10 | t.timestamps null: true 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20130507110411_create_orders.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateOrders < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :orders do |t| 6 | t.string :member_id, null: false 7 | 8 | t.timestamps null: true 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20130507113915_add_orders_products_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddOrdersProductsTable < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :orders_products, id: false do |t| 6 | t.integer :order_id 7 | t.integer :product_id 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20130508050711_add_completed_to_order.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddCompletedToOrder < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :orders, :completed_at, :datetime 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130508104506_create_photos.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreatePhotos < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :photos do |t| 6 | t.integer :owner_id, null: false 7 | t.integer :flickr_photo_id, null: false 8 | t.string :thumbnail_url, null: false 9 | t.string :fullsize_url, null: false 10 | 11 | t.timestamps null: true 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20130514124515_add_parent_to_crop.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddParentToCrop < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :crops, :parent_id, :integer 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130515033842_create_order_items.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateOrderItems < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :order_items do |t| 6 | t.integer :order_id 7 | t.integer :product_id 8 | t.decimal :price 9 | t.integer :quantity 10 | 11 | t.timestamps null: true 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20130515054017_change_order_member_id_to_integer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ChangeOrderMemberIdToInteger < ActiveRecord::Migration[4.2] 4 | def up 5 | remove_column :orders, :member_id 6 | add_column :orders, :member_id, :integer 7 | end 8 | 9 | def down 10 | remove_column :orders, :member_id 11 | add_column :orders, :member_id, :string 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20130515122301_change_prices_to_integers.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ChangePricesToIntegers < ActiveRecord::Migration[4.2] 4 | def up 5 | change_column :order_items, :price, :integer 6 | change_column :products, :min_price, :integer 7 | end 8 | 9 | def down 10 | change_column :order_items, :price, :decimal 11 | change_column :products, :min_price, :decimal 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20130517015920_create_account_details.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateAccountDetails < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :account_details do |t| 6 | t.integer :member_id, null: false 7 | t.integer :account_type_id 8 | t.datetime :paid_until 9 | 10 | t.timestamps null: true 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20130517051922_create_account_types.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateAccountTypes < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :account_types do |t| 6 | t.string :name 7 | t.boolean :is_paid 8 | t.boolean :is_permanent_paid 9 | 10 | t.timestamps null: true 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20130517234458_require_account_type_name.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RequireAccountTypeName < ActiveRecord::Migration[4.2] 4 | def up 5 | change_column :account_types, :name, :string, null: false 6 | end 7 | 8 | def down 9 | change_column :account_types, :name, :string, null: true 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20130518000339_add_columns_to_product.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddColumnsToProduct < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :products, :account_type_id, :integer 6 | add_column :products, :paid_months, :integer 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20130518002942_rename_account_detail_to_account.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameAccountDetailToAccount < ActiveRecord::Migration[4.2] 4 | def change 5 | rename_table :account_details, :accounts 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130529032813_add_express_token_to_orders.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddExpressTokenToOrders < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :orders, :paypal_express_token, :string 6 | add_column :orders, :paypal_express_payer_id, :string 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20130531110729_add_photos_plantings_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddPhotosPlantingsTable < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :photos_plantings, id: false do |t| 6 | t.integer :photo_id 7 | t.integer :planting_id 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20130601011725_change_flickr_photo_id_to_string.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ChangeFlickrPhotoIdToString < ActiveRecord::Migration[4.2] 4 | def up 5 | remove_column :photos, :flickr_photo_id 6 | add_column :photos, :flickr_photo_id, :string 7 | end 8 | 9 | def down 10 | # Postgres doesn't allow you to cast strings to integers 11 | # Hence there's no way of rolling back this migration without losing 12 | # information. 13 | remove_column :photos, :flickr_photo_id 14 | change_column :photos, :flickr_photo_id, :integer 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /db/migrate/20130606230333_change_product_description_to_text.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ChangeProductDescriptionToText < ActiveRecord::Migration[4.2] 4 | def up 5 | change_column :products, :description, :text 6 | end 7 | 8 | def down 9 | change_column :products, :description, :string 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20130606233733_add_recommended_price_to_product.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddRecommendedPriceToProduct < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :products, :recommended_price, :integer 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130705104238_add_planted_from_to_planting.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddPlantedFromToPlanting < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :plantings, :planted_from, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130715110134_create_seeds.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateSeeds < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :seeds do |t| 6 | t.integer :owner_id, null: false 7 | t.integer :crop_id, null: false 8 | t.text :description 9 | t.integer :quantity 10 | t.date :use_by 11 | 12 | t.timestamps null: true 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20130718005600_change_use_by_to_plant_before_on_seed.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ChangeUseByToPlantBeforeOnSeed < ActiveRecord::Migration[4.2] 4 | def change 5 | rename_column :seeds, :use_by, :plant_before 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130718011247_add_trading_to_seeds.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddTradingToSeeds < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :seeds, :tradable, :boolean 6 | add_column :seeds, :tradable_to, :string 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20130722050836_remove_tradable_from_seeds.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RemoveTradableFromSeeds < ActiveRecord::Migration[4.2] 4 | def up 5 | remove_column :seeds, :tradable 6 | end 7 | 8 | def down 9 | add_column :seeds, :tradable, :boolean 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20130723103128_set_default_tradable_to_on_seed.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class SetDefaultTradableToOnSeed < ActiveRecord::Migration[4.2] 4 | def up 5 | change_column_default(:seeds, :tradable_to, 'nowhere') 6 | end 7 | 8 | def down 9 | change_column_default(:seeds, :tradable_to, nil) 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20130723110702_add_slug_to_seed.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddSlugToSeed < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :seeds, :slug, :string 6 | add_index :seeds, :slug, unique: true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20130809012511_add_bio_to_members.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddBioToMembers < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :members, :bio, :text 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130819004549_add_planting_count_to_crop.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddPlantingCountToCrop < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :crops, :plantings_count, :integer 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130821011352_add_creator_to_crops.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddCreatorToCrops < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :crops, :creator_id, :integer 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130821073736_add_creator_to_scientific_name.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddCreatorToScientificName < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :scientific_names, :creator_id, :integer 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130826012139_add_owner_to_planting.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddOwnerToPlanting < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :plantings, :owner_id, :integer 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130826023159_add_plantings_count_to_member.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddPlantingsCountToMember < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :members, :plantings_count, :integer 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130827105823_add_newsletter_to_member.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddNewsletterToMember < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :members, :newsletter, :boolean 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130913015118_add_referral_code_to_order.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddReferralCodeToOrder < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :orders, :referral_code, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130917053547_create_harvests.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateHarvests < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :harvests do |t| 6 | t.integer :crop_id, null: false 7 | t.integer :owner_id, null: false 8 | t.date :harvested_at 9 | t.decimal :quantity 10 | t.string :units 11 | t.text :notes 12 | 13 | t.timestamps null: true 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /db/migrate/20130917060257_change_harvest_notes_to_description.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ChangeHarvestNotesToDescription < ActiveRecord::Migration[4.2] 4 | def change 5 | rename_column :harvests, :notes, :description 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130917071545_change_harvest_units_to_unit.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ChangeHarvestUnitsToUnit < ActiveRecord::Migration[4.2] 4 | def change 5 | rename_column :harvests, :units, :unit 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130917075803_add_slug_to_harvests.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddSlugToHarvests < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :harvests, :slug, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20130925050304_add_weight_to_harvests.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddWeightToHarvests < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :harvests, :weight_quantity, :decimal 6 | add_column :harvests, :weight_unit, :string 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20131018101204_rename_system_name_to_name.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameSystemNameToName < ActiveRecord::Migration[4.2] 4 | def up 5 | # Rails is smart enough to alter the column being indexed, but not the name 6 | # of the index, and there's no rename_index command. 7 | remove_index :crops, :system_name 8 | rename_column :crops, :system_name, :name 9 | add_index :crops, :name 10 | end 11 | 12 | def down 13 | remove_index :crops, :name 14 | rename_column :crops, :name, :system_name 15 | add_index :crops, :system_name 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /db/migrate/20131025104228_add_fields_to_gardens.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddFieldsToGardens < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :gardens, :active, :boolean, default: true 6 | add_column :gardens, :location, :string 7 | add_column :gardens, :latitude, :float 8 | add_column :gardens, :longitude, :float 9 | add_column :gardens, :area, :decimal 10 | add_column :gardens, :area_unit, :string 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20131029053113_add_plant_part_to_harvests.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddPlantPartToHarvests < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :harvests, :plant_part, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20131030230908_create_plant_parts.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreatePlantParts < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :plant_parts do |t| 6 | t.string :name 7 | 8 | t.timestamps null: true 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20131030231202_change_plant_part_to_plant_part_id.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ChangePlantPartToPlantPartId < ActiveRecord::Migration[4.2] 4 | def up 5 | remove_column :harvests, :plant_part 6 | add_column :harvests, :plant_part_id, :integer 7 | end 8 | 9 | def down 10 | remove_column :harvests, :plant_part_id 11 | add_column :harvests, :plant_part, :string 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20131031000655_add_slug_to_plant_part.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddSlugToPlantPart < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :plant_parts, :slug, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20140718075753_default_plantings_count_to_zero.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class DefaultPlantingsCountToZero < ActiveRecord::Migration[4.2] 4 | def up 5 | change_column :crops, :plantings_count, :integer, default: 0 6 | end 7 | 8 | def down 9 | change_column :crops, :plantings_count, :integer, default: nil 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20140829230600_add_finished_to_planting.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddFinishedToPlanting < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :plantings, :finished, :boolean, default: false 6 | add_column :plantings, :finished_at, :date 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20140905001730_add_harvests_photos_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddHarvestsPhotosTable < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :harvests_photos, id: false do |t| 6 | t.integer :photo_id 7 | t.integer :harvest_id 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20140928044231_add_crops_posts_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddCropsPostsTable < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :crops_posts, id: false do |t| 6 | t.integer :crop_id 7 | t.integer :post_id 8 | end 9 | add_index :crops_posts, %i(crop_id post_id) 10 | add_index :crops_posts, :crop_id 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20140928085713_add_send_planting_reminder_to_member.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddSendPlantingReminderToMember < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :members, :send_planting_reminder, :boolean, default: true 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20141002022459_create_index_harvest_photos.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateIndexHarvestPhotos < ActiveRecord::Migration[4.2] 4 | def change 5 | add_index(:harvests_photos, %i(harvest_id photo_id)) 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20141018111015_create_alternate_names.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateAlternateNames < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :alternate_names do |t| 6 | t.string :name, null: false 7 | t.integer :crop_id, null: false 8 | t.integer :creator_id, null: false 9 | 10 | t.timestamps null: true 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20141111130849_create_follows.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateFollows < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :follows do |t| 6 | t.integer :member_id 7 | t.integer :followed_id 8 | 9 | t.timestamps null: true 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20141119130555_change_follows_member_id_to_follower_id.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ChangeFollowsMemberIdToFollowerId < ActiveRecord::Migration[4.2] 4 | def change 5 | rename_column :follows, :member_id, :follower_id 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20150124110540_add_properties_to_seeds.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddPropertiesToSeeds < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :seeds, :days_until_maturity_min, :integer 6 | add_column :seeds, :days_until_maturity_max, :integer 7 | add_column :seeds, :organic, :text, default: 'unknown' 8 | add_column :seeds, :gmo, :text, default: 'unknown' 9 | add_column :seeds, :heirloom, :text, default: 'unknown' 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20150127043022_add_gardens_photos_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddGardensPhotosTable < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :gardens_photos, id: false do |t| 6 | t.integer :photo_id 7 | t.integer :garden_id 8 | end 9 | add_index(:gardens_photos, %i(garden_id photo_id)) 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20150129034206_add_si_weight_to_harvest.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddSiWeightToHarvest < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :harvests, :si_weight, :float 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20150130224814_add_requester_to_crops.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddRequesterToCrops < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :crops, :requester_id, :integer 6 | add_index :crops, :requester_id 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20150201053200_add_approval_status_to_crops.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddApprovalStatusToCrops < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :crops, :approval_status, :string, default: "approved" 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20150201062506_add_reason_for_rejection_to_crops.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddReasonForRejectionToCrops < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :crops, :reason_for_rejection, :text 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20150201064502_add_request_notes_to_crops.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddRequestNotesToCrops < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :crops, :request_notes, :text 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20150203080226_create_likes.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateLikes < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :likes do |t| 6 | t.references :member, index: true 7 | t.references :likeable, polymorphic: true, index: true 8 | t.string :categories, array: true 9 | 10 | t.timestamps 11 | end 12 | 13 | add_index :likes, :likeable_id 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20150209105410_add_rejection_notes_to_crops.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddRejectionNotesToCrops < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :crops, :rejection_notes, :text 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20150625224805_add_days_before_maturity_to_plantings.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddDaysBeforeMaturityToPlantings < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :plantings, :days_before_maturity, :integer 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20150824145414_add_member_preferred_image.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddMemberPreferredImage < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :members, :preferred_avatar_uri, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20161129021533_rename_scientific_name.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenameScientificName < ActiveRecord::Migration[4.2] 4 | def self.up 5 | rename_column :scientific_names, :scientific_name, :name 6 | end 7 | 8 | def self.down 9 | rename_column :scientific_names, :name, :scientific_name 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20161201154922_add_photos_seeds_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddPhotosSeedsTable < ActiveRecord::Migration[4.2] 4 | def change 5 | create_table :photos_seeds, id: false do |t| 6 | t.integer :photo_id 7 | t.integer :seed_id 8 | end 9 | add_index(:photos_seeds, %i(seed_id photo_id)) 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20170104035248_add_planting_ref_to_harvests.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddPlantingRefToHarvests < ActiveRecord::Migration[4.2] 4 | def change 5 | add_reference :harvests, :planting, index: true, foreign_key: true 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20170520060252_add_deleted_to_members.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddDeletedToMembers < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :members, :deleted_at, :datetime 6 | add_index :members, :deleted_at 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20171105011017_set_prediction_data.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class SetPredictionData < ActiveRecord::Migration[4.2] 4 | def up 5 | say "Updating all plantings time to first harvest" 6 | Planting.unscoped.all.each(&:update_harvest_days!) 7 | say "Updating crop median time to first harvest, and lifespan" 8 | Crop.all.each do |crop| 9 | crop.update_lifespan_medians 10 | crop.update_harvest_medians 11 | end 12 | end 13 | 14 | def down; end 15 | end 16 | -------------------------------------------------------------------------------- /db/migrate/20180118112809_add_datetaken_to_photos.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddDatetakenToPhotos < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :photos, :date_taken, :datetime 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20180205000612_remove_shop.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RemoveShop < ActiveRecord::Migration[4.2] 4 | def up 5 | drop_table :order_items 6 | drop_table :orders 7 | drop_table :products 8 | drop_table :account_types 9 | drop_table :accounts 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20180401220637_add_member_count_caches.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddMemberCountCaches < ActiveRecord::Migration[4.2] 4 | def change 5 | add_column :members, :photos_count, :integer 6 | add_column :members, :forums_count, :integer 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20190130090437_add_crop_to_photographings.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddCropToPhotographings < ActiveRecord::Migration[5.2] 4 | def change 5 | add_column(:photographings, :crop_id, :integer) 6 | add_foreign_key(:photographings, :crops) 7 | 8 | Photographing.where(crop_id: nil).each do |p| 9 | p.set_crop && p.save! 10 | end 11 | end 12 | 13 | class Photographing < ApplicationRecord 14 | belongs_to :photo, inverse_of: :photo_associations 15 | belongs_to :photographable, polymorphic: true 16 | belongs_to :crop, optional: true 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /db/migrate/20190317023129_finished_boolean.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class FinishedBoolean < ActiveRecord::Migration[5.2] 4 | def change 5 | Planting.unscoped.where('finished_at < now()').update_all(finished: true) 6 | Planting.unscoped.where(finished: nil).update_all(finished: false) 7 | change_column_null :plantings, :finished, false 8 | change_column_default :plantings, :finished, from: nil, to: false 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20190326224347_add_harvests_count.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddHarvestsCount < ActiveRecord::Migration[5.2] 4 | def change 5 | add_column :plantings, :harvests_count, :integer, default: 0 6 | Planting.reset_column_information 7 | Planting.unscoped.pluck(:id).each do |planting_id| 8 | Planting.reset_counters(planting_id, :harvests) 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20190712234859_rename_photographings.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class RenamePhotographings < ActiveRecord::Migration[5.2] 4 | def change 5 | rename_table :photographings, :photo_associations 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20190720000558_add_delivery_tracking_info_to_mailboxer_receipts.mailboxer_engine.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # This migration comes from mailboxer_engine (originally 20151103080417) 4 | class AddDeliveryTrackingInfoToMailboxerReceipts < ActiveRecord::Migration[4.2] 5 | def change 6 | add_column :mailboxer_receipts, :is_delivered, :boolean, default: false 7 | add_column :mailboxer_receipts, :delivery_method, :string 8 | add_column :mailboxer_receipts, :message_id, :string 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20190721042146_paranoia_to_discard.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ParanoiaToDiscard < ActiveRecord::Migration[5.2] 4 | def change 5 | rename_column :members, :deleted_at, :discarded_at 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20190902004225_add_openfarm_data_to_crops.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddOpenfarmDataToCrops < ActiveRecord::Migration[5.2] 4 | def change 5 | add_column :crops, :openfarm_data, :jsonb 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20190910022329_add_photo_source.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddPhotoSource < ActiveRecord::Migration[5.2] 4 | def change 5 | add_column :photos, :source, :string 6 | rename_column :photos, :flickr_photo_id, :source_id 7 | Photo.update_all(source: 'flickr') # rubocop:disable Rails/SkipsModelValidations 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20190915065209_create_crop_companions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CreateCropCompanions < ActiveRecord::Migration[5.2] 4 | def change 5 | create_table :crop_companions do |t| 6 | t.integer "crop_a_id", null: false 7 | t.integer "crop_b_id", null: false 8 | t.timestamps null: false 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20190918033319_unique_urls.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class UniqueUrls < ActiveRecord::Migration[5.2] 4 | def change 5 | add_index :photos, :fullsize_url, unique: true 6 | add_index :photos, :thumbnail_url, unique: true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20190921211652_crop_posts.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class CropPosts < ActiveRecord::Migration[5.2] 4 | def change 5 | rename_table :crops_posts, :crop_posts 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20191029024101_add_saved_at_to_seeds.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddSavedAtToSeeds < ActiveRecord::Migration[5.2] 4 | def change 5 | add_column :seeds, :saved_at, :date 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20191226051019_elastic_indexing.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class ElasticIndexing < ActiveRecord::Migration[5.2] 4 | def up 5 | say 'indexing crops' 6 | Crop.reindex 7 | say 'indexing plantings' 8 | Planting.reindex 9 | say 'indexing seeds' 10 | Seed.reindex 11 | say 'indexing harvests' 12 | Harvest.reindex 13 | say 'indexing photos' 14 | Photo.reindex 15 | end 16 | 17 | def down; end 18 | end 19 | -------------------------------------------------------------------------------- /db/migrate/20200801084007_add_foreign_key_constraint_to_active_storage_attachments_for_blob_id.active_storage.rb: -------------------------------------------------------------------------------- 1 | # This migration comes from active_storage (originally 20180723000244) 2 | class AddForeignKeyConstraintToActiveStorageAttachmentsForBlobId < ActiveRecord::Migration[6.0] 3 | def up 4 | return if foreign_key_exists?(:active_storage_attachments, column: :blob_id) 5 | 6 | add_foreign_key :active_storage_attachments, :active_storage_blobs, column: :blob_id if table_exists?(:active_storage_blobs) 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20200801210054_missing_uniqueness.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class MissingUniqueness < ActiveRecord::Migration[6.0] 4 | def change 5 | add_index(:garden_types, [:name], unique: true) 6 | add_index(:garden_types, [:slug], unique: true) 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20240114045751_add_gbif.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddGbif < ActiveRecord::Migration[7.0] 4 | def change 5 | add_column :scientific_names, :gbif_key, :int 6 | add_column :scientific_names, :gbif_rank, :string 7 | add_column :scientific_names, :gbif_status, :string 8 | add_column :scientific_names, :wikidata_id, :string 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20240218035144_add_activities.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddActivities < ActiveRecord::Migration[7.1] 4 | def change 5 | create_table :activities do |t| 6 | t.string :category 7 | t.string :name 8 | t.string :description 9 | t.date :due_date 10 | t.boolean :finished 11 | t.references :owner 12 | t.references :garden 13 | t.references :planting 14 | t.timestamps 15 | end 16 | 17 | add_column :members, :activities_count, :integer 18 | 19 | Activity.reindex 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /db/migrate/20240218053122_add_slug_to_activity.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class AddSlugToActivity < ActiveRecord::Migration[7.1] 4 | def change 5 | add_column :activities, :slug, :string 6 | add_index :activities, :slug, unique: true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20240714024918_like_everything.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class LikeEverything < ActiveRecord::Migration[7.1] 4 | def change 5 | change_table :activities do |t| 6 | t.integer :likes_count, default: 0 7 | end 8 | 9 | change_table :plantings do |t| 10 | t.integer :likes_count, default: 0 11 | end 12 | 13 | change_table :harvests do |t| 14 | t.integer :likes_count, default: 0 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /db/migrate/20240929041435_create_garden_collaborators.rb: -------------------------------------------------------------------------------- 1 | class CreateGardenCollaborators < ActiveRecord::Migration[7.2] 2 | def change 3 | create_table :garden_collaborators do |t| 4 | t.references :member 5 | t.references :garden 6 | t.timestamps 7 | t.index [:member_id, :garden_id], unique: true 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/seeds/README.md: -------------------------------------------------------------------------------- 1 | The format for these crop seed files is CSV with the following fields: 2 | 3 | Crop name 4 | Scientific name 5 | English Wikipedia URL 6 | Parent crop name 7 | -------------------------------------------------------------------------------- /lib/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/lib/assets/.gitkeep -------------------------------------------------------------------------------- /lib/geocodable.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Geocodable 4 | def self.included(base) 5 | base.extend(self) 6 | end 7 | 8 | private 9 | 10 | def empty_unwanted_geocodes 11 | return if location.present? 12 | 13 | self.latitude = nil 14 | self.longitude = nil 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/haml/filters/escaped_markdown.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'bluecloth' 4 | require 'haml/filters/growstuff_markdown' 5 | 6 | class Haml::Filters 7 | class EscapedMarkdown < Haml::Filters::Markdown 8 | def compile(node) 9 | [:escape, true, super] 10 | end 11 | end 12 | 13 | # Register it as the handler for the :escaped_markdown HAML command. 14 | # The automatic system gives us :escapedmarkdown, which is ugly. 15 | Haml::Filters.registered[:escaped_markdown] ||= EscapedMarkdown 16 | end 17 | -------------------------------------------------------------------------------- /lib/tasks/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/lib/tasks/.gitkeep -------------------------------------------------------------------------------- /lib/tasks/gardens.rake: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | namespace :gardens do 4 | desc "Mark old gardens inactive" 5 | task archive: :environment do 6 | Planting.archive! 7 | Garden.archive! 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/tasks/gbif.rake: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | namespace :gbif do 4 | desc "Retrieve crop info from GBIF" 5 | 6 | task import: :environment do 7 | Rails.logger = Logger.new(STDOUT) 8 | GbifService.new.import! 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/tasks/hooks.rake: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | desc "Install git hooks" 4 | task :hooks do 5 | FileUtils.symlink '../../script/pre-commit.sh', '.git/hooks/pre-commit', 6 | force: true 7 | end 8 | -------------------------------------------------------------------------------- /lib/tasks/i18n.rake: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | namespace :i18n do 4 | desc "sort all i18n locale keys" 5 | task :normalize do 6 | `i18n-tasks normalize` 7 | end 8 | 9 | desc "translate haml strings into i18 en locale using haml-i18n-extractor" 10 | task :extractor, [:haml_path] do |_t, args| 11 | require 'haml-i18n-extractor' 12 | haml_path = args[:haml_path] 13 | begin 14 | translate = Haml::I18n::Extractor.new(haml_path) 15 | translate.run 16 | rescue Haml::I18n::Extractor::InvalidSyntax 17 | puts "There was an error with #{haml_path}" 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/tasks/openfarm.rake: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | namespace :openfarm do 4 | desc "Retrieve crop info from open farm" 5 | # usage: rake growstuff:admin_user name=skud 6 | 7 | task import: :environment do 8 | Rails.logger = Logger.new(STDOUT) 9 | OpenfarmService.new.import! 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /lib/tasks/search.rake: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | namespace :search do 4 | desc 'reindex' 5 | task reindex: :environment do 6 | Crop.reindex 7 | Planting.reindex 8 | Harvest.reindex 9 | Seed.reindex 10 | Activity.reindex 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /log/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/log/.gitkeep -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/public/favicon.ico -------------------------------------------------------------------------------- /script/check_static.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | checks = [ 5 | # 'overcommit -r', 6 | 'bundle exec script/check_contributors_md.rb' 7 | ] 8 | 9 | return_values = checks.collect { |t| system(t) } 10 | failures = return_values.count(&:!) 11 | abort "#{failures} static check(s) failed" unless failures.zero? 12 | -------------------------------------------------------------------------------- /script/install_linters.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "${STATIC_CHECKS}" = "true" ]; then 4 | set -euv 5 | yarn install; 6 | 7 | gem install --update overcommit haml-lint bundler-audit --no-document; 8 | 9 | # pip install --upgrade pip; 10 | pip install yamllint --user; 11 | 12 | overcommit --install; 13 | overcommit --sign; 14 | overcommit --sign pre-commit; 15 | 16 | bundle-audit update; 17 | fi 18 | -------------------------------------------------------------------------------- /script/install_phantomjs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -v 3 | 4 | if [ "$(phantomjs --version)" != '2.1.1' ]; then 5 | PHANTOM_URL="https://assets.membergetmember.co/software/phantomjs-2.1.1-linux-x86_64.tar.bz2" 6 | rm -rf "$PWD/travis_phantomjs" 7 | mkdir -p "$PWD/travis_phantomjs" 8 | cd "$PWD/travis_phantomjs" || exit 1 9 | wget "$PHANTOM_URL" 10 | tar -vjxf phantomjs-2.1.1-linux-x86_64.tar.bz2 11 | fi 12 | 13 | which phantomjs 14 | phantomjs --version 15 | -------------------------------------------------------------------------------- /script/percy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euv 3 | bundle exec rails assets:precompile 4 | npx percy exec -- bundle exec rspec spec/features/percy/ 5 | -------------------------------------------------------------------------------- /script/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # This command will automatically be run when you run "rails" 5 | # with Rails 3 gems installed from the root of your application. 6 | 7 | APP_PATH = File.expand_path('../config/application', __dir__) 8 | require File.expand_path('../config/boot', __dir__) 9 | require 'rails/commands' 10 | -------------------------------------------------------------------------------- /spec/controllers/authentications_controller_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe AuthenticationsController do 6 | before do 7 | @member = FactoryBot.create(:member) 8 | sign_in @member 9 | controller.stub(:current_member) { @member } 10 | @auth = FactoryBot.create(:authentication, member: @member) 11 | request.env['omniauth.auth'] = { 12 | 'provider' => 'foo', 13 | 'uid' => 'bar', 14 | 'info' => { 'nickname' => 'blah' }, 15 | 'credentials' => { 'token' => 'blah', 'secret' => 'blah' } 16 | } 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/controllers/forums_controller_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe ForumsController do 6 | login_member(:admin_member) 7 | 8 | def valid_attributes 9 | { 10 | "name" => "MyString", 11 | "description" => "Something", 12 | "owner_id" => 1 13 | } 14 | end 15 | 16 | def valid_session 17 | {} 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/controllers/home_controller_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe HomeController do 6 | describe "GET index" do 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/controllers/plant_parts_controller_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe PlantPartsController do 6 | end 7 | -------------------------------------------------------------------------------- /spec/controllers/scientific_names_controller_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe ScientificNamesController do 6 | login_member(:crop_wrangling_member) 7 | 8 | let!(:crop) { FactoryBot.create(:tomato) } 9 | 10 | def valid_attributes 11 | { name: 'Solanum lycopersicum', crop_id: crop.id } 12 | end 13 | 14 | describe "GET new" do 15 | it "assigns crop if specified" do 16 | get :new, params: { crop_id: crop.id } 17 | assigns(:crop).should be_an_instance_of Crop 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /spec/custom_matchers.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rspec/expectations' 4 | 5 | RSpec::Matchers.define :have_optional do |expected| 6 | match do |actual| 7 | actual.has_selector? "#{expected} + span", text: '(Optional)' 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/factories/alternate_names.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Read about factories at https://github.com/thoughtbot/factory_bot 4 | 5 | FactoryBot.define do 6 | factory :alternate_name do 7 | name { "alternate name" } 8 | crop 9 | creator 10 | 11 | factory :alternate_eggplant do 12 | association :crop, factory: :eggplant 13 | name { "aubergine" } 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/factories/authentications.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Read about factories at https://github.com/thoughtbot/factory_bot 4 | 5 | FactoryBot.define do 6 | factory :authentication do 7 | member 8 | provider { 'twitter' } 9 | uid { 'foo' } 10 | secret { 'bar' } 11 | name { 'baz' } 12 | 13 | factory :flickr_authentication do 14 | provider { 'flickr' } 15 | uid { 'blah@blah' } 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/factories/comments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :comment do 5 | post 6 | author 7 | sequence(:body) { |n| "OMG LOL #{n}" } 8 | # because our commenters are more polite than YouTube's 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /spec/factories/crop_companions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :crop_companion do 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /spec/factories/follows.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :follow do 5 | follower 6 | followed 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/factories/forums.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Read about factories at https://github.com/thoughtbot/factory_bot 4 | 5 | FactoryBot.define do 6 | factory :forum do 7 | name { "Permaculture" } 8 | description { "*Everything* about permaculture!" } 9 | owner 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/factories/garden_collaborators.rb: -------------------------------------------------------------------------------- 1 | FactoryBot.define do 2 | factory :garden_collaborator do 3 | garden 4 | member 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /spec/factories/garden_types.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :garden_type do 5 | name { "homemade swamp" } 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /spec/factories/like.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :like do 5 | member 6 | association :likeable, factory: "post" 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/factories/notifications.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Read about factories at https://github.com/thoughtbot/factory_bot 4 | 5 | FactoryBot.define do 6 | factory :notification, aliases: [:message] do 7 | sender { FactoryBot.create(:member) } 8 | recipient { FactoryBot.create(:member) } 9 | subject { "MyString" } 10 | 11 | body { "MyText" } 12 | read { false } 13 | post 14 | 15 | factory :no_email_notification do 16 | recipient { FactoryBot.create(:no_email_notifications_member) } 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/factories/plant_parts.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Read about factories at https://github.com/thoughtbot/factory_bot 4 | 5 | FactoryBot.define do 6 | factory :plant_part do 7 | name { "#{Faker::Games::Pokemon.name} #{Faker::Number.number(digits: 10)}" } 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/factories/post.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :post do 5 | subject { Faker::Book.title } 6 | 7 | body { Faker::Lorem.paragraphs.join("\n") } 8 | author 9 | created_at { Time.zone.now } 10 | 11 | # Markdown is allowed in posts 12 | factory :markdown_post do 13 | body { "This is some **strong** text." } 14 | end 15 | 16 | # HTML isn't allowed in posts 17 | factory :html_post do 18 | body { 'EVIL' } 19 | end 20 | 21 | factory :forum_post do 22 | forum 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/factories/roles.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Read about factories at https://github.com/thoughtbot/factory_bot 4 | 5 | FactoryBot.define do 6 | factory :role do 7 | name { "Moderator" } 8 | description { "These people moderate the forums" } 9 | initialize_with { Role.find_or_create_by(name:) } 10 | 11 | factory :admin do 12 | name { "admin" } 13 | end 14 | 15 | factory :crop_wrangler do 16 | name { "Crop Wrangler" } 17 | description { "they wrangle crops" } 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /spec/factories/scientific_name.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | FactoryBot.define do 4 | factory :scientific_name do 5 | association :crop 6 | name { "Beanus Magicus" } 7 | creator 8 | 9 | factory :zea_mays do 10 | association :crop, factory: :maize 11 | name { "Zea mays" } 12 | end 13 | 14 | factory :solanum_lycopersicum do 15 | association :crop, factory: :tomato 16 | name { "Solanum lycopersicum" } 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/features/admin/admin_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe "forums", :js do 6 | context 'signed in admin' do 7 | include_context 'signed in admin' 8 | it "navigating to forum admin with js" do 9 | visit admin_path 10 | page.percy_snapshot(page, name: 'Admin page') 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/features/crops/requested_crops_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe "Requesting Crops" do 6 | let!(:requested_crop) { create(:crop, requester: member, approval_status: 'pending', name: 'puha for dinner') } 7 | 8 | context 'signed in' do 9 | include_context 'signed in member' 10 | before { visit requested_crops_path } 11 | 12 | it "creating a crop with multiple scientific and alternate name", :js do 13 | expect(page).to have_content "puha for dinner" 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/features/footer_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe "footer", :js do 6 | before { visit root_path } 7 | 8 | it "footer is on home page" do 9 | expect(page).to have_css 'footer' 10 | end 11 | 12 | it 'has the Open Service link and graphic' do 13 | expect(page).to have_selector 'a[href="https://opendefinition.org/ossd/"]' 14 | end 15 | 16 | # NB: not testing specific content in the footer since I'm going to put them 17 | # in the CMS and they'll be variable. 18 | end 19 | -------------------------------------------------------------------------------- /spec/features/rss/comments_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe 'Comments RSS feed' do 6 | it 'The index feed exists' do 7 | visit comments_path(format: 'rss') 8 | # expect(page.status_code).to equal 200 9 | end 10 | 11 | it 'The index title is what we expect' do 12 | visit comments_path(format: 'rss') 13 | expect(page).to have_content "Recent comments on all posts (#{ENV.fetch('GROWSTUFF_SITE_NAME', nil)})" 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/features/rss/crops_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe 'Crops RSS feed' do 6 | it 'The index feed exists' do 7 | Crop.reindex 8 | visit crops_path(format: 'rss') 9 | # expect(page.status_code).to equal 200 10 | end 11 | 12 | it 'The index title is what we expect' do 13 | Crop.reindex 14 | visit crops_path(format: 'rss') 15 | expect(page).to have_content "Recently added crops (#{ENV.fetch('GROWSTUFF_SITE_NAME', nil)})" 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/features/rss/members_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe 'Members RSS feed' do 6 | let(:member) { create(:member) } 7 | 8 | before { visit member_path(member, format: 'rss') } 9 | 10 | it 'The show action title is what we expect' do 11 | expect(page).to have_content "#{member.login_name}'s recent posts (#{ENV.fetch('GROWSTUFF_SITE_NAME', nil)})" 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/features/rss/plantings_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe 'Plantings RSS feed' do 6 | it 'The index feed exists' do 7 | visit plantings_path(format: 'rss') 8 | # expect(page.status_code).to equal 200 9 | end 10 | 11 | it 'The index title is what we expect' do 12 | Planting.reindex 13 | visit plantings_path(format: 'rss') 14 | expect(page).to have_content "Recent plantings from " \ 15 | "#{@owner || 'all members'} (#{ENV.fetch('GROWSTUFF_SITE_NAME', nil)})" 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/features/rss/posts_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe 'Posts RSS feed' do 6 | it 'The index feed exists' do 7 | visit posts_path(format: 'rss') 8 | # expect(page.status_code).to equal 200 9 | end 10 | 11 | it 'The index title is what we expect' do 12 | visit posts_path(format: 'rss') 13 | expect(page).to have_content "Recent posts from " \ 14 | "#{@author || 'all members'} (#{ENV.fetch('GROWSTUFF_SITE_NAME', nil)})" 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/features/rss/seeds_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe 'Seeds RSS feed' do 6 | it 'The index feed exists' do 7 | visit seeds_path(format: 'rss') 8 | # expect(page.status_code).to equal 200 9 | end 10 | 11 | it 'The index title is what we expect' do 12 | visit seeds_path(format: 'rss') 13 | expect(page).to have_content "Recent seeds from " \ 14 | "#{@owner || 'all members'} (#{ENV.fetch('GROWSTUFF_SITE_NAME', nil)})" 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/javascripts/helpers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Growstuff/growstuff/3bfa1af67b556f6bb568647ba25a660240c58463/spec/javascripts/helpers/.gitkeep -------------------------------------------------------------------------------- /spec/javascripts/support/spec_helper.js: -------------------------------------------------------------------------------- 1 | beforeEach(function() { 2 | $(window).off(); 3 | $(document).off(); 4 | $('body').off(); 5 | $('#jasmine_content').replaceWith($('
')); 6 | }); 7 | -------------------------------------------------------------------------------- /spec/models/authentication_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe Authentication do 6 | it 'creates an authentication' do 7 | @auth = FactoryBot.create(:authentication) 8 | @auth.should be_an_instance_of described_class 9 | @auth.member.should be_an_instance_of Member 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/models/crop_companion_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | RSpec.describe CropCompanion, type: :model do 6 | it 'has a crop' do 7 | cc = described_class.new 8 | cc.crop_a = FactoryBot.create :tomato 9 | cc.crop_b = FactoryBot.create :maize 10 | cc.save! 11 | 12 | expect(cc.crop_a.name).to eq 'tomato' 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/requests/authentications_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe "Authentications" do 6 | describe "GET /authentications" do 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/requests/forums_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe "Forums" do 6 | describe "GET /forums" do 7 | it "works! (now write some real specs)" do 8 | # Run the generator again with the --webrat flag if you want to use webrat methods/matchers 9 | get forums_path 10 | response.status.should be(200) 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/requests/garden_types_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | RSpec.describe "GardenTypes", type: :request do 6 | describe "GET /garden_types" do 7 | it "works! (now write some real specs)" do 8 | get garden_types_path 9 | expect(response).to have_http_status(:ok) 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/requests/gardens_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe "Gardens" do 6 | describe "GET /gardens" do 7 | it "works! (now write some real specs)" do 8 | # Run the generator again with the --webrat flag if you want to use webrat methods/matchers 9 | get gardens_path 10 | response.status.should be(200) 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/requests/harvests_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe "Harvests" do 6 | describe "GET /harvests" do 7 | it "works! (now write some real specs)" do 8 | get harvests_path 9 | expect(response.status).to be 200 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/requests/photos_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe "Photos" do 6 | describe "GET /photos" do 7 | it "works! (now write some real specs)" do 8 | # Run the generator again with the --webrat flag if you want to use webrat methods/matchers 9 | get photos_path 10 | response.status.should be(200) 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/requests/plant_parts_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe "PlantParts" do 6 | describe "GET /plant_parts" do 7 | it "works! (now write some real specs)" do 8 | # Run the generator again with the --webrat flag if you want to use webrat methods/matchers 9 | get plant_parts_path 10 | response.status.should be(200) 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/requests/post_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe "Posts" do 6 | describe "GET /posts" do 7 | it "works! (now write some real specs)" do 8 | get posts_path 9 | response.status.should be(200) 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/requests/scientific_names_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe "ScientificNames" do 6 | describe "GET /scientific_names" do 7 | it "works! (now write some real specs)" do 8 | # Run the generator again with the --webrat flag if you want to use webrat methods/matchers 9 | get scientific_names_path 10 | response.status.should be(200) 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/requests/seeds_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe "Seeds" do 6 | describe "GET /seeds" do 7 | it "works! (now write some real specs)" do 8 | # Run the generator again with the --webrat flag if you want to use webrat methods/matchers 9 | get seeds_path 10 | response.status.should be(200) 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/routing/admin_controller_routing_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "rails_helper" 4 | 5 | describe AdminController do 6 | describe "routing" do 7 | it { expect(get("/admin/")).to route_to("admin#index") } 8 | it { expect(get("/admin/members")).to route_to("admin/members#index") } 9 | it { expect(get("/admin/newsletter")).to route_to("admin#newsletter") } 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/routing/authentications_controller_routing_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "rails_helper" 4 | 5 | describe AuthenticationsController do 6 | describe "routing" do 7 | it "routes to #create" do 8 | post("/authentications").should route_to("authentications#create") 9 | end 10 | 11 | it "routes to #destroy" do 12 | delete("/authentications/1").should route_to("authentications#destroy", id: "1") 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/routing/follows_controller_routing_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "spec_helper" 4 | 5 | describe FollowsController do 6 | describe "routing" do 7 | it "routes to #create" do 8 | post("/follows").should route_to("follows#create") 9 | end 10 | 11 | it "routes to #destroy" do 12 | delete("/follows/1").should route_to("follows#destroy", id: "1") 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/support/controller_macros.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Taken unashamedly from https://github.com/plataformatec/devise/wiki/How-To%3a-Controllers-and-Views-tests-with-Rails-3-%28and-rspec%29 4 | module ControllerMacros 5 | def login_member(member_factory = :member) 6 | let(:member) { FactoryBot.create(member_factory || :member) } 7 | before do 8 | @request.env["devise.mapping"] = Devise.mappings[:member] 9 | sign_in member 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/support/devise.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RSpec.configure do |config| 4 | config.include Devise::Test::ControllerHelpers, type: :controller 5 | config.include Devise::Test::ControllerHelpers, type: :view 6 | config.include Devise::Test::IntegrationHelpers, type: :feature 7 | end 8 | -------------------------------------------------------------------------------- /spec/views/admin/index_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe 'admin/index.html.haml', type: "view" do 6 | before do 7 | @member = FactoryBot.create(:admin_member) 8 | sign_in @member 9 | controller.stub(:current_user) { @member } 10 | render 11 | end 12 | 13 | it "includes links to manage various things" do 14 | assert_select "a", href: admin_roles_path 15 | assert_select "a", href: forums_path 16 | end 17 | 18 | it "has a link to newsletter subscribers" do 19 | expect(rendered).to have_content "Newsletter subscribers" 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /spec/views/comments/edit.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe "comments/edit" do 6 | before do 7 | controller.stub(:current_user) { nil } 8 | assign(:comment, FactoryBot.create(:comment)) 9 | end 10 | 11 | it "renders the edit comment form" do 12 | render 13 | 14 | # Run the generator again with the --webrat flag if you want to use webrat matchers 15 | assert_select "form", action: comments_path(@comment), method: "post" do 16 | assert_select "textarea#comment_body", name: "comment[body]" 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/views/crops/edit.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe "crops/edit" do 6 | before do 7 | controller.stub(:current_user) do 8 | FactoryBot.create(:crop_wrangling_member) 9 | end 10 | @crop = FactoryBot.create(:maize) 11 | 3.times do 12 | @crop.scientific_names.build 13 | end 14 | assign(:crop, @crop) 15 | render 16 | end 17 | 18 | it "shows the creator" do 19 | expect(rendered).to have_content "Added by #{@crop.creator} less than a minute ago." 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /spec/views/crops/hierarchy.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe "crops/hierarchy" do 6 | before do 7 | controller.stub(:current_user) { nil } 8 | @tomato = FactoryBot.create(:tomato) 9 | @roma = FactoryBot.create(:crop, name: 'Roma tomato', parent: @tomato) 10 | assign(:crops, [@tomato, @roma]) 11 | render 12 | end 13 | 14 | it "shows crop hierarchy" do 15 | assert_select "ul>li>ul>li", text: @roma.name 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/views/devise/confirmations/new_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | describe 'devise/confirmations/new.html.haml', type: "view" do 4 | before do 5 | @view.stub(:resource).and_return(Member.new) 6 | @view.stub(:resource_name).and_return("member") 7 | @view.stub(:resource_class).and_return(Member) 8 | @view.stub(:devise_mapping).and_return(Devise.mappings[:member]) 9 | render 10 | end 11 | 12 | it 'contains a login field' do 13 | rendered.should have_content "Enter either your login name or your email address" 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/views/devise/mailer/confirmation_instructions_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe 'devise/mailer/confirmation_instructions.html.haml', type: "view" do 6 | context "logged in" do 7 | before do 8 | @resource = FactoryBot.create(:member) 9 | render 10 | end 11 | 12 | it 'has a confirmation link' do 13 | rendered.should have_content 'Confirm my account' 14 | end 15 | 16 | it 'has a link to the homepage' do 17 | rendered.should have_content root_url 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /spec/views/devise/mailer/unlock_instructions_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | describe 'devise/mailer/unlock_instructions.html.haml', type: "view" do 5 | context "logged in" do 6 | before do 7 | @resource = FactoryBot.create(:member) 8 | render 9 | end 10 | 11 | it "explains what's happened" do 12 | rendered.should have_content "account has been locked" 13 | end 14 | 15 | it "has an unlock link" do 16 | rendered.should have_content "Unlock my account" 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/views/forums/new.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe "forums/new" do 6 | before do 7 | @forum = assign(:forum, FactoryBot.create(:forum)) 8 | render 9 | end 10 | 11 | it "renders new forum form" do 12 | assert_select "form", action: forums_path, method: "post" do 13 | assert_select "input#forum_name", name: "forum[name]" 14 | assert_select "textarea#forum_description", name: "forum[description]" 15 | assert_select "select#forum_owner_id", name: "forum[owner_id]" 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/views/garden_types/edit.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe "garden_types/edit" do 6 | before do 7 | @owner = FactoryBot.create(:admin_member) 8 | sign_in @owner 9 | controller.stub(:current_user) { @owner } 10 | @garden_type = assign(:garden_type, FactoryBot.create(:garden_type)) 11 | render 12 | end 13 | 14 | it "renders the edit garden_type form" do 15 | assert_select "form", action: garden_types_path, method: "post" do 16 | assert_select "input#garden_type_name", name: "garden_type[name]" 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/views/garden_types/new.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe "garden_types/new" do 6 | before do 7 | @owner = FactoryBot.create(:admin_member) 8 | sign_in @owner 9 | controller.stub(:current_user) { @owner } 10 | @garden_type = assign(:garden_type, FactoryBot.create(:garden_type)) 11 | render 12 | end 13 | 14 | it "renders new garden_type form" do 15 | assert_select "form", action: garden_types_path, method: "post" do 16 | assert_select "input#garden_type_name", name: "garden_type[name]" 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/views/garden_types/show.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe "garden_types/show" do 6 | subject { render } 7 | 8 | let!(:garden_type) { FactoryBot.create(:garden_type, name: "Hot Sauce") } 9 | 10 | before do 11 | controller.stub(:current_user) { nil } 12 | assign(:garden_type, garden_type) 13 | render 14 | end 15 | 16 | describe "renders a garden_type with no gardens" do 17 | it { is_expected.to have_content "There are no gardens to display." } 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/views/home/_stats.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe 'home/_stats.html.haml', type: "view" do 6 | it 'has activity stats' do 7 | render 8 | rendered.should have_content "So far, 0 members have planted 0 crops" 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /spec/views/layouts/application_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe 'layouts/application.html.haml', type: "view" do 6 | before do 7 | controller.stub(:current_user) { nil } 8 | end 9 | 10 | it 'includes the analytics code' do 11 | Rails.application.config.analytics_code = '' 12 | render 13 | assert_select "script", text: 'console.log("foo!");' 14 | rendered.should_not have_content 'script' 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/views/photos/edit.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe "photos/edit" do 6 | before do 7 | @photo = assign(:photo, stub_model(Photo, 8 | owner_id: 1, 9 | flickr_photo_id: 1, 10 | thumbnail_url: "MyString", 11 | fullsize_url: "MyString")) 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/views/places/_map_attribution.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe "places/_map_attribution.html.haml", type: :view do 6 | before do 7 | render 8 | end 9 | 10 | it "links to OpenStreetMap" do 11 | assert_select "a", href: "http://openstreetmap.org", 12 | text: "OpenStreetMap" 13 | end 14 | 15 | it "links to the ODbL" do 16 | assert_select "a", href: "http://www.openstreetmap.org/copyright", 17 | text: "ODbL" 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/views/places/index.html.haml_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'rails_helper' 4 | 5 | describe "places/index" do 6 | before do 7 | render 8 | end 9 | 10 | it "shows a map" do 11 | assert_select "div#placesmap" 12 | end 13 | end 14 | --------------------------------------------------------------------------------