├── .gitignore ├── .tool-versions ├── .travis.yml ├── Appraisals ├── Gemfile ├── Gemfile.lock ├── MIT-LICENSE ├── README.md ├── Rakefile ├── app ├── assets │ ├── images │ │ └── pointless_feedback │ │ │ └── .gitkeep │ ├── javascripts │ │ └── pointless_feedback │ │ │ └── application.js │ └── stylesheets │ │ └── pointless_feedback │ │ └── application.css ├── controllers │ └── pointless_feedback │ │ └── messages_controller.rb ├── helpers │ └── pointless_feedback │ │ └── application_helper.rb ├── mailers │ └── pointless_feedback │ │ └── feedback_mailer.rb ├── models │ └── pointless_feedback │ │ └── message.rb └── views │ ├── layouts │ └── pointless_feedback │ │ └── application.html.erb │ └── pointless_feedback │ ├── feedback_mailer │ └── feedback.html.erb │ └── messages │ └── new.html.erb ├── config ├── locales │ └── en.yml └── routes.rb ├── db └── migrate │ ├── 20130501182659_create_pointless_feedback_messages.rb │ └── 20220518205500_add_url_to_pointless_feedback_messages.rb ├── gemfiles ├── rails_40.gemfile ├── rails_40.gemfile.lock ├── rails_41.gemfile ├── rails_41.gemfile.lock ├── rails_42.gemfile └── rails_42.gemfile.lock ├── lib ├── generators │ ├── pointless_feedback │ │ ├── install_generator.rb │ │ └── views_generator.rb │ └── templates │ │ └── pointless_feedback.rb ├── pointless_feedback.rb ├── pointless_feedback │ ├── captcha.rb │ ├── controllers │ │ └── helpers.rb │ ├── engine.rb │ └── version.rb └── tasks │ └── pointless_feedback_tasks.rake ├── pointless_feedback.gemspec ├── script └── rails └── test ├── dummy ├── README.rdoc ├── Rakefile ├── app │ ├── assets │ │ ├── javascripts │ │ │ └── application.js │ │ └── stylesheets │ │ │ └── application.css │ ├── controllers │ │ ├── application_controller.rb │ │ └── home_controller.rb │ ├── helpers │ │ └── application_helper.rb │ ├── mailers │ │ └── .gitkeep │ ├── models │ │ └── .gitkeep │ └── views │ │ ├── home │ │ └── index.html.erb │ │ └── layouts │ │ └── application.html.erb ├── config.ru ├── config │ ├── application.rb │ ├── boot.rb │ ├── database.yml │ ├── environment.rb │ ├── environments │ │ ├── development.rb │ │ ├── production.rb │ │ └── test.rb │ ├── initializers │ │ ├── backtrace_silencers.rb │ │ ├── filter_parameter_logging.rb │ │ ├── inflections.rb │ │ ├── mime_types.rb │ │ ├── secret_token.rb │ │ ├── session_store.rb │ │ └── wrap_parameters.rb │ ├── locales │ │ └── en.yml │ └── routes.rb ├── db │ └── schema.rb ├── lib │ └── assets │ │ └── .gitkeep ├── log │ └── .gitkeep ├── public │ ├── 404.html │ ├── 422.html │ ├── 500.html │ └── favicon.ico └── script │ └── rails ├── factories └── messages.rb ├── functional └── pointless_feedback │ ├── feedback_mailer_test.rb │ └── messages_controller_test.rb ├── generators ├── install_generator_test.rb └── views_generator_test.rb ├── integration └── pointless_feedback │ ├── feedback_submission_test.rb │ └── main_app_root_url_test.rb ├── pointless_feedback_test.rb ├── test_helper.rb └── unit ├── helpers └── pointless_feedback │ └── application_helper_test.rb └── pointless_feedback ├── captcha_test.rb └── message_test.rb /.gitignore: -------------------------------------------------------------------------------- 1 | .ruby-version 2 | .bundle/ 3 | log/*.log 4 | pkg/ 5 | test/dummy/db/*.sqlite3 6 | test/dummy/log/*.log 7 | test/dummy/tmp/ 8 | test/dummy/.sass-cache 9 | test/tmp 10 | -------------------------------------------------------------------------------- /.tool-versions: -------------------------------------------------------------------------------- 1 | ruby 2.3.0 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.0.0 4 | - 2.1.0 5 | - 2.2.0 6 | 7 | gemfile: 8 | - gemfiles/rails_40.gemfile 9 | - gemfiles/rails_41.gemfile 10 | - gemfiles/rails_42.gemfile 11 | 12 | before_script: 13 | - bundle exec rake db:migrate 14 | - bundle exec rake app:db:test:prepare 15 | 16 | script: bundle exec rake 17 | -------------------------------------------------------------------------------- /Appraisals: -------------------------------------------------------------------------------- 1 | appraise "rails-40" do 2 | gem "rails", "~> 4.0.0" 3 | end 4 | 5 | appraise "rails-41" do 6 | gem "rails", "~> 4.1.0" 7 | end 8 | 9 | appraise "rails-42" do 10 | gem "rails", "~> 4.2.0" 11 | end 12 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | # Declare your gem's dependencies in pointless_feedback.gemspec. 4 | # Bundler will treat runtime dependencies like base dependencies, and 5 | # development dependencies will be added by default to the :development group. 6 | gemspec 7 | 8 | group :test do 9 | gem 'test-unit' 10 | gem 'pry' 11 | gem 'minitest-spec-rails' 12 | gem 'mocha', require: false 13 | end 14 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | pointless_feedback (4.1.5) 5 | airrecord (~> 1.0) 6 | jquery-rails (>= 4.0) 7 | rails (>= 4.0) 8 | typhoeus (~> 0.7, >= 0.7.3) 9 | 10 | GEM 11 | remote: http://rubygems.org/ 12 | specs: 13 | actionmailer (4.2.2) 14 | actionpack (= 4.2.2) 15 | actionview (= 4.2.2) 16 | activejob (= 4.2.2) 17 | mail (~> 2.5, >= 2.5.4) 18 | rails-dom-testing (~> 1.0, >= 1.0.5) 19 | actionpack (4.2.2) 20 | actionview (= 4.2.2) 21 | activesupport (= 4.2.2) 22 | rack (~> 1.6) 23 | rack-test (~> 0.6.2) 24 | rails-dom-testing (~> 1.0, >= 1.0.5) 25 | rails-html-sanitizer (~> 1.0, >= 1.0.1) 26 | actionview (4.2.2) 27 | activesupport (= 4.2.2) 28 | builder (~> 3.1) 29 | erubis (~> 2.7.0) 30 | rails-dom-testing (~> 1.0, >= 1.0.5) 31 | rails-html-sanitizer (~> 1.0, >= 1.0.1) 32 | activejob (4.2.2) 33 | activesupport (= 4.2.2) 34 | globalid (>= 0.3.0) 35 | activemodel (4.2.2) 36 | activesupport (= 4.2.2) 37 | builder (~> 3.1) 38 | activerecord (4.2.2) 39 | activemodel (= 4.2.2) 40 | activesupport (= 4.2.2) 41 | arel (~> 6.0) 42 | activesupport (4.2.2) 43 | i18n (~> 0.7) 44 | json (~> 1.7, >= 1.7.7) 45 | minitest (~> 5.1) 46 | thread_safe (~> 0.3, >= 0.3.4) 47 | tzinfo (~> 1.1) 48 | addressable (2.3.8) 49 | airrecord (1.0.8) 50 | faraday (>= 0.10, < 3.0) 51 | net-http-persistent 52 | appraisal (2.0.1) 53 | activesupport (>= 3.2.21) 54 | bundler 55 | rake 56 | thor (>= 0.14.0) 57 | arel (6.0.0) 58 | builder (3.2.2) 59 | capybara (2.4.4) 60 | mime-types (>= 1.16) 61 | nokogiri (>= 1.3.3) 62 | rack (>= 1.0.0) 63 | rack-test (>= 0.5.4) 64 | xpath (~> 2.0) 65 | coderay (1.1.0) 66 | connection_pool (2.2.5) 67 | erubis (2.7.0) 68 | ethon (0.15.0) 69 | ffi (>= 1.15.0) 70 | factory_girl (4.5.0) 71 | activesupport (>= 3.0.0) 72 | factory_girl_rails (4.5.0) 73 | factory_girl (~> 4.5.0) 74 | railties (>= 3.0.0) 75 | faraday (1.0.1) 76 | multipart-post (>= 1.2, < 3) 77 | ffi (1.15.5) 78 | globalid (0.3.5) 79 | activesupport (>= 4.1.0) 80 | i18n (0.7.0) 81 | jquery-rails (4.4.0) 82 | rails-dom-testing (>= 1, < 3) 83 | railties (>= 4.2.0) 84 | thor (>= 0.14, < 2.0) 85 | json (1.8.6) 86 | launchy (2.4.3) 87 | addressable (~> 2.3) 88 | loofah (2.0.2) 89 | nokogiri (>= 1.5.9) 90 | mail (2.6.3) 91 | mime-types (>= 1.16, < 3) 92 | metaclass (0.0.4) 93 | method_source (0.8.2) 94 | mime-types (2.6.1) 95 | mini_portile (0.6.2) 96 | minitest (5.7.0) 97 | minitest-spec-rails (5.2.2) 98 | minitest (~> 5.0) 99 | rails (~> 4.1) 100 | mocha (1.1.0) 101 | metaclass (~> 0.0.1) 102 | multipart-post (2.1.1) 103 | net-http-persistent (4.0.1) 104 | connection_pool (~> 2.2) 105 | nokogiri (1.6.6.2) 106 | mini_portile (~> 0.6.0) 107 | power_assert (0.2.3) 108 | pry (0.10.1) 109 | coderay (~> 1.1.0) 110 | method_source (~> 0.8.1) 111 | slop (~> 3.4) 112 | rack (1.6.4) 113 | rack-test (0.6.3) 114 | rack (>= 1.0) 115 | rails (4.2.2) 116 | actionmailer (= 4.2.2) 117 | actionpack (= 4.2.2) 118 | actionview (= 4.2.2) 119 | activejob (= 4.2.2) 120 | activemodel (= 4.2.2) 121 | activerecord (= 4.2.2) 122 | activesupport (= 4.2.2) 123 | bundler (>= 1.3.0, < 2.0) 124 | railties (= 4.2.2) 125 | sprockets-rails 126 | rails-deprecated_sanitizer (1.0.3) 127 | activesupport (>= 4.2.0.alpha) 128 | rails-dom-testing (1.0.6) 129 | activesupport (>= 4.2.0.beta, < 5.0) 130 | nokogiri (~> 1.6.0) 131 | rails-deprecated_sanitizer (>= 1.0.1) 132 | rails-html-sanitizer (1.0.2) 133 | loofah (~> 2.0) 134 | railties (4.2.2) 135 | actionpack (= 4.2.2) 136 | activesupport (= 4.2.2) 137 | rake (>= 0.8.7) 138 | thor (>= 0.18.1, < 2.0) 139 | rake (10.4.2) 140 | slop (3.6.0) 141 | sprockets (3.2.0) 142 | rack (~> 1.0) 143 | sprockets-rails (2.3.1) 144 | actionpack (>= 3.0) 145 | activesupport (>= 3.0) 146 | sprockets (>= 2.8, < 4.0) 147 | sqlite3 (1.3.10) 148 | test-unit (3.1.2) 149 | power_assert 150 | thor (0.19.1) 151 | thread_safe (0.3.5) 152 | typhoeus (0.8.0) 153 | ethon (>= 0.8.0) 154 | tzinfo (1.2.2) 155 | thread_safe (~> 0.1) 156 | xpath (2.0.0) 157 | nokogiri (~> 1.3) 158 | 159 | PLATFORMS 160 | ruby 161 | 162 | DEPENDENCIES 163 | appraisal (~> 2.0) 164 | capybara (~> 2.4) 165 | factory_girl_rails (~> 4.5) 166 | launchy (~> 2.4) 167 | minitest-spec-rails 168 | mocha 169 | pointless_feedback! 170 | pry 171 | sqlite3 (~> 1.3) 172 | test-unit 173 | 174 | BUNDLED WITH 175 | 1.17.3 176 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2013 Viget 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pointless Feedback 2 | 3 | [![Code Climate](https://codeclimate.com/github/vigetlabs/pointless-feedback.png)](https://codeclimate.com/github/vigetlabs/pointless-feedback) [![Build Status](https://travis-ci.org/vigetlabs/pointless-feedback.svg?branch=master)](https://travis-ci.org/vigetlabs/pointless-feedback) 4 | 5 | A Rails engine that provides a platform for your app to submit user feedback to 6 | a specified service. Messages are stored in your database as a fail-safe when 7 | the specified service is unavailable. Currently, only email, Unfuddle, and 8 | Github Issues are supported. 9 | 10 | *Brought to you by the fine folks at [Viget](http://viget.com) and commissioned 11 | under [Pointless Corp](http://www.pointlesscorp.com/).* 12 | 13 | ## Contents 14 | 15 | 1. [Versions](#versions) 16 | 2. [Installation](#installation) 17 | 3. [Configuration](#configuration) 18 | 4. [Customization](#customization) 19 | 5. [Development](#development) 20 | 6. [Roadmap](#roadmap) 21 | 7. [Contributors](#contributors) 22 | 23 | ## Versions 24 | 25 | For Rails 3.x support, use Pointless Feedback version 1.x. 26 | 27 | For Rails 4.x and greater, use Pointless Feedback version 4.x. 28 | 29 | Additionally, Pointless 4.x will only support Ruby 2.x. 30 | 31 | ## Installation 32 | 33 | To install, simply add the following to your Gemfile: 34 | 35 | ```ruby 36 | gem 'pointless_feedback' 37 | ``` 38 | 39 | After you install Pointless Feedback and add it to your Gemfile, you need to 40 | run the generator and install the engine migrations: 41 | 42 | ``` 43 | bundle exec rails generate pointless_feedback:install 44 | bundle exec rake pointless_feedback:install:migrations 45 | bundle exec rake db:migrate 46 | ``` 47 | 48 | The generator will install an initializer which describes ALL Pointless 49 | Feedback's configuration options and you MUST take a look at it. When you are 50 | done, you are ready to mount the routes in your `config/routes.rb` file. 51 | 52 | ```ruby 53 | mount PointlessFeedback::Engine, :at => '/feedback' 54 | ``` 55 | 56 | Pointless Feedback uses flash messages to let users know if feedback was 57 | successfully sent. Pointless Feedback expects your application to call 58 | `flash[:notice]` as appropriate. 59 | 60 | After submitting feedback, Pointless Feedback will use your application's 61 | default `root_path`. This means that you need to set the root inside your 62 | routes: 63 | 64 | ```ruby 65 | root :to => 'home#index' 66 | ``` 67 | 68 | That's it! Start your Rails server and navigate to `/feedback` to see a basic 69 | feedback form that users can submit. 70 | 71 | ## Configuration 72 | 73 | There are a number of configuration variables you can set in the initializer generated by `rails generate pointless_feedback:install` 74 | 75 | #### Email Configuration 76 | 77 | **email_feedback:** 78 | Defaults to `false`. If set to `true` will send feedback as an email. 79 | 80 | **message_topics:** 81 | Defaults to `['Error on page', 'Other']`. Populates the "Topic" dropdown for feedback submissions. 82 | 83 | **send_from_submitter:** 84 | Defaults to `false`. If set to `true` will use the submitted email address as the from address for feedback emails. 85 | 86 | **to_emails:** 87 | Specifies to what addresses feedback email is sent to. 88 | 89 | **from_email:** 90 | Specifies what address the feedback email is sent from. 91 | 92 | **table_name:** 93 | Defaults to engine's namespace, e.g. `pointless_feedback_messages`. Change to any desired table for `PointlessFeedback::Message` model. 94 | 95 | **invalid_words:** 96 | List of words in the feedback description that would prevent an email from sending. 97 | 98 | **show_url_field:** 99 | Defaults to `false`. If set to `true`, will show an additional URL field in the form. 100 | 101 | **url_label:** 102 | Defaults to `URL`. The label for the URL field that will be shown if `show_url_field` is `true`. 103 | 104 | **google_captcha_site_key & google_captcha_secret_key:** 105 | If you'd like to block out the robots, set up a Google Captcha instance: 106 | 107 | Do so here - http://www.google.com/recaptcha/admin. Be sure to configure it with the reCAPTCHA v2 `"I'm not a robot" Checkbox`. Then copy the site_key and secret_key into these config variables and PointlessFeedback will handle the rest! 108 | 109 | #### Airtable Configuration 110 | 111 | **airtable_api_key:** 112 | Self explanatory, required if you want to export submitted feedback contents into an Airtable database. 113 | 114 | **airtable_app_key:** 115 | Self explanatory 116 | 117 | **airtable_table_name:** 118 | Self explanatory 119 | 120 | ## Customization 121 | 122 | Pointless Feedback provides you with a simple setup that should cover most 123 | cases. However, certain things are customizable to suit your app's needs. 124 | 125 | #### Views 126 | 127 | Since Pointless Feedback is an engine, all its views are packaged inside the 128 | gem. These views will help you get started, but after some time you may want 129 | to change them. If this is the case, you just need to invoke the following 130 | generator, and it will copy all views to your application: 131 | 132 | ``` 133 | bundle exec rails generate pointless_feedback:views 134 | ``` 135 | 136 | After doing so, you will find the views at `app/views/pointless_feedback/` 137 | within your application. 138 | 139 | **Note: Any url helpers used while on the feedback form page will need to prefaced with `main_app`.** 140 | 141 | #### I18n 142 | 143 | Most of the messaging in the Pointless Feedback engine uses I18n and can be 144 | customized within your respective localization file. 145 | 146 | To customize the flash notification upon successful submission, add the 147 | following to your `config/locales/en.yml` file: 148 | 149 | ```yml 150 | pointless_feedback: 151 | messages: 152 | saved: "Thanks for your feedback!" 153 | ``` 154 | 155 | The error messages output defaults to the following: 156 | 157 | ```yml 158 | activerecord: 159 | errors: 160 | header: "Invalid Fields" 161 | message: "Correct the following errors and try again." 162 | ``` 163 | 164 | To customize the subject of the feedback email, add the following to your 165 | `config/locales/en.yml` file as well: 166 | 167 | ```yml 168 | pointless_feedback: 169 | email: 170 | subject: "Pointless Feedback" 171 | ``` 172 | 173 | #### Controllers 174 | 175 | You can overwrite `after_message_create_path` in your `ApplicationController` 176 | to customize your redirect hook. 177 | 178 | ## Development 179 | 180 | 1. Clone the repo: `git clone git://github.com/vigetlabs/pointless-feedback.git` 181 | 2. Install dependencies: `bundle install` 182 | 3. Setup databases: `bundle exec rake db:migrate && rake app:db:test:prepare` 183 | 4. Run the test suite: `bundle exec rake test` 184 | 5. Make your changes in a feature branch 185 | 6. Make sure the test suite passes before submitting a Pull Request 186 | 187 | ## Roadmap 188 | 189 | - [ ] Add service to send to Github 190 | - [ ] Add admin view for messages with comments 191 | 192 | ## Contributors 193 | 194 | * [@zporter](http://github.com/zporter) 195 | * [@efatsi](http://github.com/efatsi) 196 | * [@reagent](http://github.com/reagent) 197 | 198 | This project rocks and uses MIT-LICENSE. 199 | 200 | *** 201 | 202 | 203 | Code At Viget 204 | 205 | 206 | Visit [code.viget.com](http://code.viget.com) to see more projects from [Viget.](https://viget.com) 207 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | begin 3 | require 'bundler/setup' 4 | rescue LoadError 5 | puts 'You must `gem install bundler` and `bundle install` to run rake tasks' 6 | end 7 | begin 8 | require 'rdoc/task' 9 | rescue LoadError 10 | require 'rdoc/rdoc' 11 | require 'rake/rdoctask' 12 | RDoc::Task = Rake::RDocTask 13 | end 14 | 15 | RDoc::Task.new(:rdoc) do |rdoc| 16 | rdoc.rdoc_dir = 'rdoc' 17 | rdoc.title = 'PointlessFeedback' 18 | rdoc.options << '--line-numbers' 19 | rdoc.rdoc_files.include('README.rdoc') 20 | rdoc.rdoc_files.include('lib/**/*.rb') 21 | end 22 | 23 | APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__) 24 | load 'rails/tasks/engine.rake' 25 | 26 | 27 | 28 | Bundler::GemHelper.install_tasks 29 | 30 | require 'rake/testtask' 31 | 32 | Rake::TestTask.new(:test) do |t| 33 | t.libs << 'lib' 34 | t.libs << 'test' 35 | t.pattern = 'test/**/*_test.rb' 36 | t.verbose = false 37 | end 38 | 39 | 40 | task :default => :test 41 | -------------------------------------------------------------------------------- /app/assets/images/pointless_feedback/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vigetlabs/pointless-feedback/9b3363237b316e5fe0511c86624f71c3235f7ded/app/assets/images/pointless_feedback/.gitkeep -------------------------------------------------------------------------------- /app/assets/javascripts/pointless_feedback/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // the compiled file. 9 | // 10 | // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD 11 | // GO AFTER THE REQUIRES BELOW. 12 | // 13 | //= require jquery 14 | //= require jquery_ujs 15 | //= require_tree . 16 | -------------------------------------------------------------------------------- /app/assets/stylesheets/pointless_feedback/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the top of the 9 | * compiled file, but it's generally better to create a new file per style scope. 10 | * 11 | *= require_self 12 | *= require_tree . 13 | */ 14 | -------------------------------------------------------------------------------- /app/controllers/pointless_feedback/messages_controller.rb: -------------------------------------------------------------------------------- 1 | module PointlessFeedback 2 | class MessagesController < PointlessFeedback.parent_controller.constantize 3 | helper PointlessFeedback::ApplicationHelper 4 | 5 | def new 6 | @message = Message.new 7 | end 8 | 9 | def create 10 | @message = Message.new(message_params) 11 | 12 | if pass_captcha? && @message.save 13 | flash[:notice] = I18n.t('pointless_feedback.messages.saved', 14 | :default => 'Thanks for your feedback!') 15 | 16 | redirect_to after_message_create_path 17 | else 18 | flash[:alert] = I18n.t('pointless_feedback.messages.invalid_captcha', 19 | :default => 'Are you a robot? Please check the box at the bottom of the page and try again.') 20 | render :new 21 | end 22 | end 23 | 24 | private 25 | 26 | def message_params 27 | params.require(:message).permit([ 28 | :description, 29 | :email_address, 30 | :name, 31 | :topic, 32 | :contact_info, 33 | :url 34 | ]) 35 | end 36 | 37 | def pass_captcha? 38 | if PointlessFeedback.using_captcha? 39 | PointlessFeedback::Captcha.pass?(params["g-recaptcha-response"]) 40 | else 41 | true 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /app/helpers/pointless_feedback/application_helper.rb: -------------------------------------------------------------------------------- 1 | module PointlessFeedback 2 | module ApplicationHelper 3 | delegate :root_url, :root_path, :to => :main_app 4 | 5 | # Can search for named routes directly in the main app, omitting 6 | # the "main_app." prefix 7 | def method_missing(method, *args, &block) 8 | if main_app_url_helper?(method) 9 | main_app.send(method, *args) 10 | else 11 | super 12 | end 13 | end 14 | 15 | def respond_to_missing?(method, include_all) 16 | main_app_url_helper?(method) || super 17 | end 18 | 19 | 20 | private 21 | 22 | def main_app_url_helper?(method) 23 | /\A\w+(_path|_url)\z/ === method.to_s && main_app.respond_to?(method) 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /app/mailers/pointless_feedback/feedback_mailer.rb: -------------------------------------------------------------------------------- 1 | module PointlessFeedback 2 | class FeedbackMailer < ActionMailer::Base 3 | def feedback(message) 4 | @message = message 5 | 6 | mail(:to => to_emails, :subject => feedback_subject, :from => from_address) 7 | end 8 | 9 | private 10 | 11 | def from_address 12 | if PointlessFeedback.send_from_submitter 13 | @message.email_address 14 | else 15 | PointlessFeedback.from_email 16 | end 17 | end 18 | 19 | def to_emails 20 | Array(PointlessFeedback.to_emails) 21 | end 22 | 23 | def feedback_subject 24 | I18n.t('pointless_feedback.email.subject', :default => 'Feedback') 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /app/models/pointless_feedback/message.rb: -------------------------------------------------------------------------------- 1 | module PointlessFeedback 2 | class Message < ActiveRecord::Base 3 | if PointlessFeedback.table_name.present? 4 | self.table_name = PointlessFeedback.table_name 5 | end 6 | 7 | attr_accessor :contact_info 8 | 9 | validates :name, :email_address, :topic, :description, :presence => true 10 | validates :topic, :inclusion => PointlessFeedback.message_topics 11 | validates :email_address, :format => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i 12 | validate :is_not_spam 13 | 14 | after_save :export_feedback, :unless => :ignore_feedback? 15 | 16 | private 17 | 18 | def export_feedback 19 | if PointlessFeedback.email_feedback 20 | # Support Rails < 4.2 and >= 4.2 delivery options 21 | mailer = FeedbackMailer.feedback(self) 22 | mailer.respond_to?(:deliver_now) ? mailer.deliver_now : mailer.deliver 23 | end 24 | 25 | if PointlessFeedback.airtable_api_key 26 | feedback_table = Airrecord.table( 27 | PointlessFeedback.airtable_api_key, 28 | PointlessFeedback.airtable_app_key, 29 | PointlessFeedback.airtable_table_name 30 | ) 31 | 32 | begin 33 | feedback_table.create( 34 | "Name" => name, 35 | "Email" => email_address, 36 | "Topic" => topic, 37 | "Description" => description, 38 | "Date" => created_at.strftime("%m/%d/%y"), 39 | "URL" => url 40 | ) 41 | rescue => e 42 | # ignore errors in production, last thing you want is a 500 43 | # when someone's trying to complain about your site. 44 | raise(e) if Rails.env.development? 45 | end 46 | end 47 | end 48 | 49 | def ignore_feedback? 50 | honeypot_filled_in? || contains_invalid_words? 51 | end 52 | 53 | def honeypot_filled_in? 54 | contact_info.present? 55 | end 56 | 57 | def contains_invalid_words? 58 | PointlessFeedback.invalid_words.each do |word| 59 | if description.downcase.include? word.downcase 60 | return true 61 | end 62 | end 63 | 64 | false 65 | end 66 | 67 | def is_not_spam 68 | if URI.extract(description || "").count >= 3 69 | errors.add(:description, "can not contain more than 2 http links (often a sign of spam)") 70 | end 71 | end 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /app/views/layouts/pointless_feedback/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | PointlessFeedback 5 | <%= stylesheet_link_tag "pointless_feedback/application", :media => "all" %> 6 | <%= javascript_include_tag "pointless_feedback/application" %> 7 | <%= csrf_meta_tags %> 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/views/pointless_feedback/feedback_mailer/feedback.html.erb: -------------------------------------------------------------------------------- 1 | You've got feedback! 2 | 3 |

Name: <%= @message.name %>

4 |

Email Address: <%= @message.email_address %>

5 |

Topic: <%= @message.topic %>

6 | <% if PointlessFeedback.show_url_field %> 7 |

<%= PointlessFeedback.url_label %>: <%= @message.url %>

8 | <% end %> 9 |

Description: <%= @message.description %>

10 | -------------------------------------------------------------------------------- /app/views/pointless_feedback/messages/new.html.erb: -------------------------------------------------------------------------------- 1 | <% if PointlessFeedback.using_captcha? %> 2 | 3 | 4 | 5 | <% end %> 6 | 7 | <%= form_for @message do |f| %> 8 | <% if @message.errors.any? %> 9 |
10 |

11 | <%= I18n.t('activerecord.errors.header', :default => 'Invalid Fields') %> 12 |

13 | 14 |

15 | <%= I18n.t('activerecord.errors.message', :default => 'Correct the following errors and try again.') %> 16 |

17 | 18 | 23 |
24 | <% end %> 25 | 26 |
27 | About You 28 | 29 |
30 | <%= f.label :name %> 31 | <%= f.text_field :name %> 32 |
33 | 34 |
35 | <%= f.label :email_address %> 36 | <%= f.text_field :email_address %> 37 |
38 |
39 | 40 |
41 | Leave Your Feedback 42 | 43 |
44 | <%= f.label :topic %> 45 | <%= f.select :topic, PointlessFeedback.message_topics, { :prompt => true } %> 46 |
47 | 48 | <% if PointlessFeedback.show_url_field %> 49 |
50 | <%= f.label :url, PointlessFeedback.url_label %> 51 | <%= f.text_field :url %> 52 |
53 | <% end %> 54 | 55 |
56 | <%= f.label :description %> 57 | <%= f.text_area :description %> 58 |
59 | 60 | 61 | 62 |
63 | <%= f.text_field :contact_info %> 64 |
65 | 66 | 67 |
68 | 69 | <% if PointlessFeedback.using_captcha? %> 70 |
71 | <% end %> 72 | 73 | <%= f.submit 'Submit' %> 74 | <% end %> 75 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | PointlessFeedback::Engine.routes.draw do 2 | root :to => 'messages#new' 3 | 4 | resources :messages, :only => [:new, :create] 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130501182659_create_pointless_feedback_messages.rb: -------------------------------------------------------------------------------- 1 | class CreatePointlessFeedbackMessages < ActiveRecord::Migration 2 | def change 3 | create_table :pointless_feedback_messages do |t| 4 | t.string :name 5 | t.string :email_address 6 | t.string :topic 7 | t.text :description 8 | 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20220518205500_add_url_to_pointless_feedback_messages.rb: -------------------------------------------------------------------------------- 1 | class AddUrlToPointlessFeedbackMessages < ActiveRecord::Migration 2 | def change 3 | add_column :pointless_feedback_messages, :url, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /gemfiles/rails_40.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "jquery-rails" 6 | gem "rails", "~> 4.0.0" 7 | 8 | group :test do 9 | gem "test-unit" 10 | gem "pry" 11 | gem "minitest-spec-rails" 12 | gem "mocha", :require => false 13 | end 14 | 15 | gemspec :path => "../" 16 | -------------------------------------------------------------------------------- /gemfiles/rails_40.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: ../ 3 | specs: 4 | pointless_feedback (4.0.0) 5 | rails (~> 4.0) 6 | 7 | GEM 8 | remote: http://rubygems.org/ 9 | specs: 10 | actionmailer (4.0.13) 11 | actionpack (= 4.0.13) 12 | mail (~> 2.5, >= 2.5.4) 13 | actionpack (4.0.13) 14 | activesupport (= 4.0.13) 15 | builder (~> 3.1.0) 16 | erubis (~> 2.7.0) 17 | rack (~> 1.5.2) 18 | rack-test (~> 0.6.2) 19 | activemodel (4.0.13) 20 | activesupport (= 4.0.13) 21 | builder (~> 3.1.0) 22 | activerecord (4.0.13) 23 | activemodel (= 4.0.13) 24 | activerecord-deprecated_finders (~> 1.0.2) 25 | activesupport (= 4.0.13) 26 | arel (~> 4.0.0) 27 | activerecord-deprecated_finders (1.0.4) 28 | activesupport (4.0.13) 29 | i18n (~> 0.6, >= 0.6.9) 30 | minitest (~> 4.2) 31 | multi_json (~> 1.3) 32 | thread_safe (~> 0.1) 33 | tzinfo (~> 0.3.37) 34 | addressable (2.3.8) 35 | appraisal (2.0.1) 36 | activesupport (>= 3.2.21) 37 | bundler 38 | rake 39 | thor (>= 0.14.0) 40 | arel (4.0.2) 41 | builder (3.1.4) 42 | capybara (2.4.4) 43 | mime-types (>= 1.16) 44 | nokogiri (>= 1.3.3) 45 | rack (>= 1.0.0) 46 | rack-test (>= 0.5.4) 47 | xpath (~> 2.0) 48 | coderay (1.1.0) 49 | erubis (2.7.0) 50 | factory_girl (4.5.0) 51 | activesupport (>= 3.0.0) 52 | factory_girl_rails (4.5.0) 53 | factory_girl (~> 4.5.0) 54 | railties (>= 3.0.0) 55 | i18n (0.7.0) 56 | jquery-rails (3.0.4) 57 | railties (>= 3.0, < 5.0) 58 | thor (>= 0.14, < 2.0) 59 | launchy (2.4.3) 60 | addressable (~> 2.3) 61 | mail (2.6.3) 62 | mime-types (>= 1.16, < 3) 63 | metaclass (0.0.4) 64 | method_source (0.8.2) 65 | mime-types (2.6.1) 66 | mini_portile (0.6.2) 67 | minitest (4.7.5) 68 | minitest-spec-rails (4.7.2) 69 | minitest (~> 4.7) 70 | rails (>= 3.0) 71 | mocha (1.1.0) 72 | metaclass (~> 0.0.1) 73 | multi_json (1.11.1) 74 | nokogiri (1.6.6.2) 75 | mini_portile (~> 0.6.0) 76 | power_assert (0.2.2) 77 | pry (0.10.1) 78 | coderay (~> 1.1.0) 79 | method_source (~> 0.8.1) 80 | slop (~> 3.4) 81 | rack (1.5.5) 82 | rack-test (0.6.3) 83 | rack (>= 1.0) 84 | rails (4.0.13) 85 | actionmailer (= 4.0.13) 86 | actionpack (= 4.0.13) 87 | activerecord (= 4.0.13) 88 | activesupport (= 4.0.13) 89 | bundler (>= 1.3.0, < 2.0) 90 | railties (= 4.0.13) 91 | sprockets-rails (~> 2.0) 92 | railties (4.0.13) 93 | actionpack (= 4.0.13) 94 | activesupport (= 4.0.13) 95 | rake (>= 0.8.7) 96 | thor (>= 0.18.1, < 2.0) 97 | rake (10.4.2) 98 | slop (3.6.0) 99 | sprockets (3.2.0) 100 | rack (~> 1.0) 101 | sprockets-rails (2.3.1) 102 | actionpack (>= 3.0) 103 | activesupport (>= 3.0) 104 | sprockets (>= 2.8, < 4.0) 105 | sqlite3 (1.3.10) 106 | test-unit (3.0.8) 107 | power_assert 108 | thor (0.19.1) 109 | thread_safe (0.3.5) 110 | tzinfo (0.3.44) 111 | xpath (2.0.0) 112 | nokogiri (~> 1.3) 113 | 114 | PLATFORMS 115 | ruby 116 | 117 | DEPENDENCIES 118 | appraisal 119 | capybara 120 | factory_girl_rails 121 | jquery-rails 122 | launchy 123 | minitest-spec-rails 124 | mocha 125 | pointless_feedback! 126 | pry 127 | rails (~> 4.0.0) 128 | sqlite3 129 | test-unit 130 | -------------------------------------------------------------------------------- /gemfiles/rails_41.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "jquery-rails" 6 | gem "rails", "~> 4.1.0" 7 | 8 | group :test do 9 | gem "test-unit" 10 | gem "pry" 11 | gem "minitest-spec-rails" 12 | gem "mocha", :require => false 13 | end 14 | 15 | gemspec :path => "../" 16 | -------------------------------------------------------------------------------- /gemfiles/rails_41.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: ../ 3 | specs: 4 | pointless_feedback (4.0.0) 5 | rails (~> 4.0) 6 | 7 | GEM 8 | remote: http://rubygems.org/ 9 | specs: 10 | actionmailer (4.1.11) 11 | actionpack (= 4.1.11) 12 | actionview (= 4.1.11) 13 | mail (~> 2.5, >= 2.5.4) 14 | actionpack (4.1.11) 15 | actionview (= 4.1.11) 16 | activesupport (= 4.1.11) 17 | rack (~> 1.5.2) 18 | rack-test (~> 0.6.2) 19 | actionview (4.1.11) 20 | activesupport (= 4.1.11) 21 | builder (~> 3.1) 22 | erubis (~> 2.7.0) 23 | activemodel (4.1.11) 24 | activesupport (= 4.1.11) 25 | builder (~> 3.1) 26 | activerecord (4.1.11) 27 | activemodel (= 4.1.11) 28 | activesupport (= 4.1.11) 29 | arel (~> 5.0.0) 30 | activesupport (4.1.11) 31 | i18n (~> 0.6, >= 0.6.9) 32 | json (~> 1.7, >= 1.7.7) 33 | minitest (~> 5.1) 34 | thread_safe (~> 0.1) 35 | tzinfo (~> 1.1) 36 | addressable (2.3.8) 37 | appraisal (2.0.1) 38 | activesupport (>= 3.2.21) 39 | bundler 40 | rake 41 | thor (>= 0.14.0) 42 | arel (5.0.1.20140414130214) 43 | builder (3.2.2) 44 | capybara (2.4.4) 45 | mime-types (>= 1.16) 46 | nokogiri (>= 1.3.3) 47 | rack (>= 1.0.0) 48 | rack-test (>= 0.5.4) 49 | xpath (~> 2.0) 50 | coderay (1.1.0) 51 | erubis (2.7.0) 52 | factory_girl (4.5.0) 53 | activesupport (>= 3.0.0) 54 | factory_girl_rails (4.5.0) 55 | factory_girl (~> 4.5.0) 56 | railties (>= 3.0.0) 57 | i18n (0.7.0) 58 | jquery-rails (3.1.3) 59 | railties (>= 3.0, < 5.0) 60 | thor (>= 0.14, < 2.0) 61 | json (1.8.3) 62 | launchy (2.4.3) 63 | addressable (~> 2.3) 64 | mail (2.6.3) 65 | mime-types (>= 1.16, < 3) 66 | metaclass (0.0.4) 67 | method_source (0.8.2) 68 | mime-types (2.6.1) 69 | mini_portile (0.6.2) 70 | minitest (5.7.0) 71 | minitest-spec-rails (5.2.2) 72 | minitest (~> 5.0) 73 | rails (~> 4.1) 74 | mocha (1.1.0) 75 | metaclass (~> 0.0.1) 76 | nokogiri (1.6.6.2) 77 | mini_portile (~> 0.6.0) 78 | power_assert (0.2.3) 79 | pry (0.10.1) 80 | coderay (~> 1.1.0) 81 | method_source (~> 0.8.1) 82 | slop (~> 3.4) 83 | rack (1.5.5) 84 | rack-test (0.6.3) 85 | rack (>= 1.0) 86 | rails (4.1.11) 87 | actionmailer (= 4.1.11) 88 | actionpack (= 4.1.11) 89 | actionview (= 4.1.11) 90 | activemodel (= 4.1.11) 91 | activerecord (= 4.1.11) 92 | activesupport (= 4.1.11) 93 | bundler (>= 1.3.0, < 2.0) 94 | railties (= 4.1.11) 95 | sprockets-rails (~> 2.0) 96 | railties (4.1.11) 97 | actionpack (= 4.1.11) 98 | activesupport (= 4.1.11) 99 | rake (>= 0.8.7) 100 | thor (>= 0.18.1, < 2.0) 101 | rake (10.4.2) 102 | slop (3.6.0) 103 | sprockets (3.2.0) 104 | rack (~> 1.0) 105 | sprockets-rails (2.3.1) 106 | actionpack (>= 3.0) 107 | activesupport (>= 3.0) 108 | sprockets (>= 2.8, < 4.0) 109 | sqlite3 (1.3.10) 110 | test-unit (3.1.2) 111 | power_assert 112 | thor (0.19.1) 113 | thread_safe (0.3.5) 114 | tzinfo (1.2.2) 115 | thread_safe (~> 0.1) 116 | xpath (2.0.0) 117 | nokogiri (~> 1.3) 118 | 119 | PLATFORMS 120 | ruby 121 | 122 | DEPENDENCIES 123 | appraisal 124 | capybara 125 | factory_girl_rails 126 | jquery-rails 127 | launchy 128 | minitest-spec-rails 129 | mocha 130 | pointless_feedback! 131 | pry 132 | rails (~> 4.1.0) 133 | sqlite3 134 | test-unit 135 | -------------------------------------------------------------------------------- /gemfiles/rails_42.gemfile: -------------------------------------------------------------------------------- 1 | # This file was generated by Appraisal 2 | 3 | source "http://rubygems.org" 4 | 5 | gem "jquery-rails" 6 | gem "rails", "~> 4.2.0" 7 | 8 | group :test do 9 | gem "test-unit" 10 | gem "pry" 11 | gem "minitest-spec-rails" 12 | gem "mocha", :require => false 13 | end 14 | 15 | gemspec :path => "../" 16 | -------------------------------------------------------------------------------- /gemfiles/rails_42.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: ../ 3 | specs: 4 | pointless_feedback (4.0.0) 5 | rails (~> 4.0) 6 | 7 | GEM 8 | remote: http://rubygems.org/ 9 | specs: 10 | actionmailer (4.2.2) 11 | actionpack (= 4.2.2) 12 | actionview (= 4.2.2) 13 | activejob (= 4.2.2) 14 | mail (~> 2.5, >= 2.5.4) 15 | rails-dom-testing (~> 1.0, >= 1.0.5) 16 | actionpack (4.2.2) 17 | actionview (= 4.2.2) 18 | activesupport (= 4.2.2) 19 | rack (~> 1.6) 20 | rack-test (~> 0.6.2) 21 | rails-dom-testing (~> 1.0, >= 1.0.5) 22 | rails-html-sanitizer (~> 1.0, >= 1.0.1) 23 | actionview (4.2.2) 24 | activesupport (= 4.2.2) 25 | builder (~> 3.1) 26 | erubis (~> 2.7.0) 27 | rails-dom-testing (~> 1.0, >= 1.0.5) 28 | rails-html-sanitizer (~> 1.0, >= 1.0.1) 29 | activejob (4.2.2) 30 | activesupport (= 4.2.2) 31 | globalid (>= 0.3.0) 32 | activemodel (4.2.2) 33 | activesupport (= 4.2.2) 34 | builder (~> 3.1) 35 | activerecord (4.2.2) 36 | activemodel (= 4.2.2) 37 | activesupport (= 4.2.2) 38 | arel (~> 6.0) 39 | activesupport (4.2.2) 40 | i18n (~> 0.7) 41 | json (~> 1.7, >= 1.7.7) 42 | minitest (~> 5.1) 43 | thread_safe (~> 0.3, >= 0.3.4) 44 | tzinfo (~> 1.1) 45 | addressable (2.3.8) 46 | appraisal (2.0.1) 47 | activesupport (>= 3.2.21) 48 | bundler 49 | rake 50 | thor (>= 0.14.0) 51 | arel (6.0.0) 52 | builder (3.2.2) 53 | capybara (2.4.4) 54 | mime-types (>= 1.16) 55 | nokogiri (>= 1.3.3) 56 | rack (>= 1.0.0) 57 | rack-test (>= 0.5.4) 58 | xpath (~> 2.0) 59 | coderay (1.1.0) 60 | erubis (2.7.0) 61 | factory_girl (4.5.0) 62 | activesupport (>= 3.0.0) 63 | factory_girl_rails (4.5.0) 64 | factory_girl (~> 4.5.0) 65 | railties (>= 3.0.0) 66 | globalid (0.3.5) 67 | activesupport (>= 4.1.0) 68 | i18n (0.7.0) 69 | jquery-rails (4.0.4) 70 | rails-dom-testing (~> 1.0) 71 | railties (>= 4.2.0) 72 | thor (>= 0.14, < 2.0) 73 | json (1.8.3) 74 | launchy (2.4.3) 75 | addressable (~> 2.3) 76 | loofah (2.0.2) 77 | nokogiri (>= 1.5.9) 78 | mail (2.6.3) 79 | mime-types (>= 1.16, < 3) 80 | metaclass (0.0.4) 81 | method_source (0.8.2) 82 | mime-types (2.6.1) 83 | mini_portile (0.6.2) 84 | minitest (5.7.0) 85 | minitest-spec-rails (5.2.2) 86 | minitest (~> 5.0) 87 | rails (~> 4.1) 88 | mocha (1.1.0) 89 | metaclass (~> 0.0.1) 90 | nokogiri (1.6.6.2) 91 | mini_portile (~> 0.6.0) 92 | power_assert (0.2.3) 93 | pry (0.10.1) 94 | coderay (~> 1.1.0) 95 | method_source (~> 0.8.1) 96 | slop (~> 3.4) 97 | rack (1.6.4) 98 | rack-test (0.6.3) 99 | rack (>= 1.0) 100 | rails (4.2.2) 101 | actionmailer (= 4.2.2) 102 | actionpack (= 4.2.2) 103 | actionview (= 4.2.2) 104 | activejob (= 4.2.2) 105 | activemodel (= 4.2.2) 106 | activerecord (= 4.2.2) 107 | activesupport (= 4.2.2) 108 | bundler (>= 1.3.0, < 2.0) 109 | railties (= 4.2.2) 110 | sprockets-rails 111 | rails-deprecated_sanitizer (1.0.3) 112 | activesupport (>= 4.2.0.alpha) 113 | rails-dom-testing (1.0.6) 114 | activesupport (>= 4.2.0.beta, < 5.0) 115 | nokogiri (~> 1.6.0) 116 | rails-deprecated_sanitizer (>= 1.0.1) 117 | rails-html-sanitizer (1.0.2) 118 | loofah (~> 2.0) 119 | railties (4.2.2) 120 | actionpack (= 4.2.2) 121 | activesupport (= 4.2.2) 122 | rake (>= 0.8.7) 123 | thor (>= 0.18.1, < 2.0) 124 | rake (10.4.2) 125 | slop (3.6.0) 126 | sprockets (3.2.0) 127 | rack (~> 1.0) 128 | sprockets-rails (2.3.1) 129 | actionpack (>= 3.0) 130 | activesupport (>= 3.0) 131 | sprockets (>= 2.8, < 4.0) 132 | sqlite3 (1.3.10) 133 | test-unit (3.1.2) 134 | power_assert 135 | thor (0.19.1) 136 | thread_safe (0.3.5) 137 | tzinfo (1.2.2) 138 | thread_safe (~> 0.1) 139 | xpath (2.0.0) 140 | nokogiri (~> 1.3) 141 | 142 | PLATFORMS 143 | ruby 144 | 145 | DEPENDENCIES 146 | appraisal 147 | capybara 148 | factory_girl_rails 149 | jquery-rails 150 | launchy 151 | minitest-spec-rails 152 | mocha 153 | pointless_feedback! 154 | pry 155 | rails (~> 4.2.0) 156 | sqlite3 157 | test-unit 158 | -------------------------------------------------------------------------------- /lib/generators/pointless_feedback/install_generator.rb: -------------------------------------------------------------------------------- 1 | module PointlessFeedback 2 | module Generators 3 | class InstallGenerator < Rails::Generators::Base 4 | source_root File.expand_path("../../templates", __FILE__) 5 | 6 | desc "Creates a PointlessFeedback initializer for your application." 7 | 8 | def copy_initializer 9 | template "pointless_feedback.rb", "config/initializers/pointless_feedback.rb" 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/generators/pointless_feedback/views_generator.rb: -------------------------------------------------------------------------------- 1 | module PointlessFeedback 2 | module Generators 3 | class ViewsGenerator < Rails::Generators::Base 4 | desc "Copies Pointless Feedback views to your application." 5 | source_root File.expand_path("../../../../app/views/pointless_feedback", __FILE__) 6 | 7 | public_task :copy_views 8 | 9 | def copy_views 10 | directory 'messages', 'app/views/pointless_feedback/messages' do |content| 11 | content 12 | end 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/generators/templates/pointless_feedback.rb: -------------------------------------------------------------------------------- 1 | PointlessFeedback.setup do |config| 2 | # ==> Feedback Configuration 3 | # Configure the topics for the user to choose from on the feedback form 4 | # config.message_topics = ['Error on page', 'Feature Request', 'Praise', 'Other'] 5 | 6 | # ==> Email Configuration 7 | # Configure feedback email properties (disabled by default) 8 | # Variables needed for emailing feedback 9 | # config.email_feedback = false 10 | # config.send_from_submitter = false 11 | # config.from_email = 'feedback@pointlesscorp.com' 12 | # config.to_emails = ['first@example.com', 'second@example.com'] 13 | 14 | # ==> Google reCAPTCHA Configuration 15 | # If you'd like to enable Google reCAPTCHA, 16 | # 1. Register your site at: https://www.google.com/recaptcha/admin 17 | # 2. !! Ensure you opt for reCAPTCHA v2. Support for v3 is not here yet. 18 | # 3. Grab the site and secret key and paste them here. 19 | # 20 | # config.google_captcha_site_key = nil 21 | # config.google_captcha_secret_key = nil 22 | 23 | # ==> Airtable Configuration 24 | # If you'd like to export feedback submissions to an Airtable database, 25 | # 1. Create an Airtable database with the following columns: 26 | # - Name 27 | # - Email 28 | # - Topic 29 | # - Description 30 | # 2. Generate an API Key: https://airtable.com/account 31 | # 3. Find your app key and table name: https://airtable.com/api 32 | # 4. Fill in all these configs 33 | # 34 | # config.airtable_api_key = "key--------------" 35 | # config.airtable_app_key = "app--------------" 36 | # config.airtable_table_name = "Feedback Tracker" 37 | end 38 | -------------------------------------------------------------------------------- /lib/pointless_feedback.rb: -------------------------------------------------------------------------------- 1 | require "pointless_feedback/engine" 2 | require "pointless_feedback/captcha" 3 | require "typhoeus" 4 | require "jquery-rails" 5 | require "airrecord" 6 | 7 | module PointlessFeedback 8 | module Controllers 9 | autoload :Helpers, 'pointless_feedback/controllers/helpers' 10 | end 11 | 12 | # The parent controller all PointlessFeedback controllers inherit from. 13 | # Defaults to ApplicationController. This should be set early 14 | # in the initialization process and should be set to a string. 15 | mattr_accessor :parent_controller 16 | @@parent_controller = "ApplicationController" 17 | 18 | # The table name that will be used to store all messages. By default this 19 | # includes the engine's namespace (e.g. `pointless_feedback_messages`), but 20 | # it can be configured to whatever is desired. 21 | mattr_accessor :table_name 22 | 23 | # Custom topics to display on message form 24 | mattr_accessor :message_topics 25 | @@message_topics = ['Error on page', 'Other'] 26 | 27 | # Variables needed for emailing feedback 28 | mattr_accessor :email_feedback 29 | @@email_feedback = false 30 | 31 | mattr_accessor :from_email 32 | @@from_email = 'feedback@pointlesscorp.com' 33 | 34 | mattr_accessor :send_from_submitter 35 | @@send_from_submitter = false 36 | 37 | mattr_accessor :to_emails 38 | @@to_emails = ['first@example.com', 'second@example.com'] 39 | 40 | mattr_accessor :google_captcha_site_key 41 | @@google_captcha_site_key = nil 42 | 43 | mattr_accessor :google_captcha_secret_key 44 | @@google_captcha_secret_key = nil 45 | 46 | mattr_accessor :airtable_api_key 47 | @@airtable_api_key = nil 48 | 49 | mattr_accessor :airtable_app_key 50 | @@airtable_app_key = nil 51 | 52 | mattr_accessor :airtable_table_name 53 | @@airtable_table_name = nil 54 | 55 | mattr_accessor :invalid_words 56 | @@invalid_words = [] 57 | 58 | mattr_accessor :show_url_field 59 | @@show_url_field = false 60 | 61 | mattr_accessor :url_label 62 | @@url_label = "URL" 63 | 64 | # Default way to setup PointlessFeedback. Run rails generate 65 | # pointless_feedback_install to create a fresh initializer with all 66 | # configuration values. 67 | def self.setup 68 | yield self 69 | end 70 | 71 | def self.using_captcha? 72 | @@google_captcha_site_key.present? && @@google_captcha_secret_key.present? 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /lib/pointless_feedback/captcha.rb: -------------------------------------------------------------------------------- 1 | require 'uri' 2 | require 'net/http' 3 | require 'json' 4 | 5 | module PointlessFeedback 6 | class Captcha 7 | def self.pass?(captcha_response) 8 | new(captcha_response).pass? 9 | end 10 | 11 | def initialize(captcha_response) 12 | @captcha_response = captcha_response 13 | end 14 | 15 | def pass? 16 | JSON.parse(response.body)["success"] == true 17 | end 18 | 19 | private 20 | 21 | def response 22 | @response ||= Typhoeus.post(url, body: body) 23 | end 24 | 25 | def url 26 | "https://www.google.com/recaptcha/api/siteverify" 27 | end 28 | 29 | def body 30 | { 31 | secret: PointlessFeedback.google_captcha_secret_key, 32 | response: @captcha_response 33 | } 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /lib/pointless_feedback/controllers/helpers.rb: -------------------------------------------------------------------------------- 1 | module PointlessFeedback 2 | module Controllers 3 | # Those helpers are convenience methods added to ApplicationController. 4 | module Helpers 5 | def after_message_create_path 6 | main_app.try(:root_path) || '/' 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/pointless_feedback/engine.rb: -------------------------------------------------------------------------------- 1 | module PointlessFeedback 2 | class Engine < ::Rails::Engine 3 | isolate_namespace PointlessFeedback 4 | 5 | initializer "pointless_feedback.controller.helpers" do 6 | ActiveSupport.on_load(:action_controller) do 7 | if defined?(PointlessFeedback::Controllers::Helpers) 8 | include PointlessFeedback::Controllers::Helpers 9 | end 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/pointless_feedback/version.rb: -------------------------------------------------------------------------------- 1 | module PointlessFeedback 2 | VERSION = "4.1.5" 3 | end 4 | -------------------------------------------------------------------------------- /lib/tasks/pointless_feedback_tasks.rake: -------------------------------------------------------------------------------- 1 | # desc "Explaining what the task does" 2 | # task :pointless_feedback do 3 | # # Task goes here 4 | # end 5 | -------------------------------------------------------------------------------- /pointless_feedback.gemspec: -------------------------------------------------------------------------------- 1 | $:.push File.expand_path("../lib", __FILE__) 2 | 3 | # Maintain your gem's version: 4 | require "pointless_feedback/version" 5 | 6 | # Describe your gem and declare its dependencies: 7 | Gem::Specification.new do |s| 8 | s.name = "pointless_feedback" 9 | s.version = PointlessFeedback::VERSION 10 | s.authors = ["Zachary Porter"] 11 | s.email = ["developers@viget.com"] 12 | s.homepage = "https://github.com/vigetlabs/pointless-feedback" 13 | s.summary = "Simple Rails Engine to allow users to submit feedback" 14 | s.description = "Drop in feedback engine with customizable fields, and captcha available" 15 | s.license = "MIT" 16 | 17 | s.files = Dir["{app,config,db,lib}/**/*"] + ["MIT-LICENSE", "Rakefile", "README.md"] 18 | s.test_files = Dir["test/**/*"] 19 | 20 | s.add_dependency "rails", ">= 4.0" 21 | s.add_dependency "typhoeus", "~> 0.7", ">= 0.7.3" 22 | s.add_dependency "jquery-rails", ">= 4.0" 23 | s.add_dependency "airrecord", "~> 1.0" 24 | 25 | s.add_development_dependency "sqlite3", "~> 1.3" 26 | s.add_development_dependency "capybara", "~> 2.4" 27 | s.add_development_dependency "factory_girl_rails", "~> 4.5" 28 | s.add_development_dependency "launchy", "~> 2.4" 29 | s.add_development_dependency "appraisal", "~> 2.0" 30 | end 31 | -------------------------------------------------------------------------------- /script/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. 3 | 4 | ENGINE_ROOT = File.expand_path('../..', __FILE__) 5 | ENGINE_PATH = File.expand_path('../../lib/pointless_feedback/engine', __FILE__) 6 | 7 | require 'rails/all' 8 | require 'rails/engine/commands' 9 | -------------------------------------------------------------------------------- /test/dummy/README.rdoc: -------------------------------------------------------------------------------- 1 | == Welcome to Rails 2 | 3 | Rails is a web-application framework that includes everything needed to create 4 | database-backed web applications according to the Model-View-Control pattern. 5 | 6 | This pattern splits the view (also called the presentation) into "dumb" 7 | templates that are primarily responsible for inserting pre-built data in between 8 | HTML tags. The model contains the "smart" domain objects (such as Account, 9 | Product, Person, Post) that holds all the business logic and knows how to 10 | persist themselves to a database. The controller handles the incoming requests 11 | (such as Save New Account, Update Product, Show Post) by manipulating the model 12 | and directing data to the view. 13 | 14 | In Rails, the model is handled by what's called an object-relational mapping 15 | layer entitled Active Record. This layer allows you to present the data from 16 | database rows as objects and embellish these data objects with business logic 17 | methods. You can read more about Active Record in 18 | link:files/vendor/rails/activerecord/README.html. 19 | 20 | The controller and view are handled by the Action Pack, which handles both 21 | layers by its two parts: Action View and Action Controller. These two layers 22 | are bundled in a single package due to their heavy interdependence. This is 23 | unlike the relationship between the Active Record and Action Pack that is much 24 | more separate. Each of these packages can be used independently outside of 25 | Rails. You can read more about Action Pack in 26 | link:files/vendor/rails/actionpack/README.html. 27 | 28 | 29 | == Getting Started 30 | 31 | 1. At the command prompt, create a new Rails application: 32 | rails new myapp (where myapp is the application name) 33 | 34 | 2. Change directory to myapp and start the web server: 35 | cd myapp; rails server (run with --help for options) 36 | 37 | 3. Go to http://localhost:3000/ and you'll see: 38 | "Welcome aboard: You're riding Ruby on Rails!" 39 | 40 | 4. Follow the guidelines to start developing your application. You can find 41 | the following resources handy: 42 | 43 | * The Getting Started Guide: http://guides.rubyonrails.org/getting_started.html 44 | * Ruby on Rails Tutorial Book: http://www.railstutorial.org/ 45 | 46 | 47 | == Debugging Rails 48 | 49 | Sometimes your application goes wrong. Fortunately there are a lot of tools that 50 | will help you debug it and get it back on the rails. 51 | 52 | First area to check is the application log files. Have "tail -f" commands 53 | running on the server.log and development.log. Rails will automatically display 54 | debugging and runtime information to these files. Debugging info will also be 55 | shown in the browser on requests from 127.0.0.1. 56 | 57 | You can also log your own messages directly into the log file from your code 58 | using the Ruby logger class from inside your controllers. Example: 59 | 60 | class WeblogController < ActionController::Base 61 | def destroy 62 | @weblog = Weblog.find(params[:id]) 63 | @weblog.destroy 64 | logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!") 65 | end 66 | end 67 | 68 | The result will be a message in your log file along the lines of: 69 | 70 | Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1! 71 | 72 | More information on how to use the logger is at http://www.ruby-doc.org/core/ 73 | 74 | Also, Ruby documentation can be found at http://www.ruby-lang.org/. There are 75 | several books available online as well: 76 | 77 | * Programming Ruby: http://www.ruby-doc.org/docs/ProgrammingRuby/ (Pickaxe) 78 | * Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide) 79 | 80 | These two books will bring you up to speed on the Ruby language and also on 81 | programming in general. 82 | 83 | 84 | == Debugger 85 | 86 | Debugger support is available through the debugger command when you start your 87 | Mongrel or WEBrick server with --debugger. This means that you can break out of 88 | execution at any point in the code, investigate and change the model, and then, 89 | resume execution! You need to install ruby-debug to run the server in debugging 90 | mode. With gems, use sudo gem install ruby-debug. Example: 91 | 92 | class WeblogController < ActionController::Base 93 | def index 94 | @posts = Post.all 95 | debugger 96 | end 97 | end 98 | 99 | So the controller will accept the action, run the first line, then present you 100 | with a IRB prompt in the server window. Here you can do things like: 101 | 102 | >> @posts.inspect 103 | => "[#nil, "body"=>nil, "id"=>"1"}>, 105 | #"Rails", "body"=>"Only ten..", "id"=>"2"}>]" 107 | >> @posts.first.title = "hello from a debugger" 108 | => "hello from a debugger" 109 | 110 | ...and even better, you can examine how your runtime objects actually work: 111 | 112 | >> f = @posts.first 113 | => #nil, "body"=>nil, "id"=>"1"}> 114 | >> f. 115 | Display all 152 possibilities? (y or n) 116 | 117 | Finally, when you're ready to resume execution, you can enter "cont". 118 | 119 | 120 | == Console 121 | 122 | The console is a Ruby shell, which allows you to interact with your 123 | application's domain model. Here you'll have all parts of the application 124 | configured, just like it is when the application is running. You can inspect 125 | domain models, change values, and save to the database. Starting the script 126 | without arguments will launch it in the development environment. 127 | 128 | To start the console, run rails console from the application 129 | directory. 130 | 131 | Options: 132 | 133 | * Passing the -s, --sandbox argument will rollback any modifications 134 | made to the database. 135 | * Passing an environment name as an argument will load the corresponding 136 | environment. Example: rails console production. 137 | 138 | To reload your controllers and models after launching the console run 139 | reload! 140 | 141 | More information about irb can be found at: 142 | link:http://www.rubycentral.org/pickaxe/irb.html 143 | 144 | 145 | == dbconsole 146 | 147 | You can go to the command line of your database directly through rails 148 | dbconsole. You would be connected to the database with the credentials 149 | defined in database.yml. Starting the script without arguments will connect you 150 | to the development database. Passing an argument will connect you to a different 151 | database, like rails dbconsole production. Currently works for MySQL, 152 | PostgreSQL and SQLite 3. 153 | 154 | == Description of Contents 155 | 156 | The default directory structure of a generated Ruby on Rails application: 157 | 158 | |-- app 159 | | |-- assets 160 | | | |-- images 161 | | | |-- javascripts 162 | | | `-- stylesheets 163 | | |-- controllers 164 | | |-- helpers 165 | | |-- mailers 166 | | |-- models 167 | | `-- views 168 | | `-- layouts 169 | |-- config 170 | | |-- environments 171 | | |-- initializers 172 | | `-- locales 173 | |-- db 174 | |-- doc 175 | |-- lib 176 | | |-- assets 177 | | `-- tasks 178 | |-- log 179 | |-- public 180 | |-- script 181 | |-- test 182 | | |-- fixtures 183 | | |-- functional 184 | | |-- integration 185 | | |-- performance 186 | | `-- unit 187 | |-- tmp 188 | | `-- cache 189 | | `-- assets 190 | `-- vendor 191 | |-- assets 192 | | |-- javascripts 193 | | `-- stylesheets 194 | `-- plugins 195 | 196 | app 197 | Holds all the code that's specific to this particular application. 198 | 199 | app/assets 200 | Contains subdirectories for images, stylesheets, and JavaScript files. 201 | 202 | app/controllers 203 | Holds controllers that should be named like weblogs_controller.rb for 204 | automated URL mapping. All controllers should descend from 205 | ApplicationController which itself descends from ActionController::Base. 206 | 207 | app/models 208 | Holds models that should be named like post.rb. Models descend from 209 | ActiveRecord::Base by default. 210 | 211 | app/views 212 | Holds the template files for the view that should be named like 213 | weblogs/index.html.erb for the WeblogsController#index action. All views use 214 | eRuby syntax by default. 215 | 216 | app/views/layouts 217 | Holds the template files for layouts to be used with views. This models the 218 | common header/footer method of wrapping views. In your views, define a layout 219 | using the layout :default and create a file named default.html.erb. 220 | Inside default.html.erb, call <% yield %> to render the view using this 221 | layout. 222 | 223 | app/helpers 224 | Holds view helpers that should be named like weblogs_helper.rb. These are 225 | generated for you automatically when using generators for controllers. 226 | Helpers can be used to wrap functionality for your views into methods. 227 | 228 | config 229 | Configuration files for the Rails environment, the routing map, the database, 230 | and other dependencies. 231 | 232 | db 233 | Contains the database schema in schema.rb. db/migrate contains all the 234 | sequence of Migrations for your schema. 235 | 236 | doc 237 | This directory is where your application documentation will be stored when 238 | generated using rake doc:app 239 | 240 | lib 241 | Application specific libraries. Basically, any kind of custom code that 242 | doesn't belong under controllers, models, or helpers. This directory is in 243 | the load path. 244 | 245 | public 246 | The directory available for the web server. Also contains the dispatchers and the 247 | default HTML files. This should be set as the DOCUMENT_ROOT of your web 248 | server. 249 | 250 | script 251 | Helper scripts for automation and generation. 252 | 253 | test 254 | Unit and functional tests along with fixtures. When using the rails generate 255 | command, template test files will be generated for you and placed in this 256 | directory. 257 | 258 | vendor 259 | External libraries that the application depends on. Also includes the plugins 260 | subdirectory. If the app has frozen rails, those gems also go here, under 261 | vendor/rails/. This directory is in the load path. 262 | -------------------------------------------------------------------------------- /test/dummy/Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | # Add your own tasks in files placed in lib/tasks ending in .rake, 3 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 4 | 5 | require File.expand_path('../config/application', __FILE__) 6 | 7 | Dummy::Application.load_tasks 8 | -------------------------------------------------------------------------------- /test/dummy/app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // the compiled file. 9 | // 10 | // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD 11 | // GO AFTER THE REQUIRES BELOW. 12 | // 13 | //= require jquery 14 | //= require jquery_ujs 15 | //= require_tree . 16 | -------------------------------------------------------------------------------- /test/dummy/app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the top of the 9 | * compiled file, but it's generally better to create a new file per style scope. 10 | * 11 | *= require_self 12 | *= require_tree . 13 | */ 14 | -------------------------------------------------------------------------------- /test/dummy/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | # Prevent CSRF attacks by raising an exception. 3 | # For APIs, you may want to use :null_session instead. 4 | protect_from_forgery with: :exception 5 | end 6 | -------------------------------------------------------------------------------- /test/dummy/app/controllers/home_controller.rb: -------------------------------------------------------------------------------- 1 | class HomeController < ApplicationController 2 | def index 3 | end 4 | end -------------------------------------------------------------------------------- /test/dummy/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /test/dummy/app/mailers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vigetlabs/pointless-feedback/9b3363237b316e5fe0511c86624f71c3235f7ded/test/dummy/app/mailers/.gitkeep -------------------------------------------------------------------------------- /test/dummy/app/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vigetlabs/pointless-feedback/9b3363237b316e5fe0511c86624f71c3235f7ded/test/dummy/app/models/.gitkeep -------------------------------------------------------------------------------- /test/dummy/app/views/home/index.html.erb: -------------------------------------------------------------------------------- 1 | <%= flash.notice %> 2 | -------------------------------------------------------------------------------- /test/dummy/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dummy 5 | <%= stylesheet_link_tag "application", :media => "all" %> 6 | <%= javascript_include_tag "application" %> 7 | <%= csrf_meta_tags %> 8 | 9 | 10 | 11 | <%= link_to "Homepage", root_url %> 12 | 13 | <%= yield %> 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /test/dummy/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run Dummy::Application 5 | -------------------------------------------------------------------------------- /test/dummy/config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require 'rails/all' 4 | 5 | Bundler.require(*Rails.groups) 6 | require "pointless_feedback" 7 | 8 | module Dummy 9 | class Application < Rails::Application 10 | # Settings in config/environments/* take precedence over those specified here. 11 | # Application configuration should go into files in config/initializers 12 | # -- all .rb files in that directory are automatically loaded. 13 | 14 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 15 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 16 | # config.time_zone = 'Central Time (US & Canada)' 17 | 18 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 19 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 20 | # config.i18n.default_locale = :de 21 | end 22 | end 23 | 24 | -------------------------------------------------------------------------------- /test/dummy/config/boot.rb: -------------------------------------------------------------------------------- 1 | # Set up gems listed in the Gemfile. 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__) 3 | 4 | require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) 5 | $LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__) -------------------------------------------------------------------------------- /test/dummy/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | development: 7 | adapter: sqlite3 8 | database: db/development.sqlite3 9 | pool: 5 10 | timeout: 5000 11 | 12 | # Warning: The database defined as "test" will be erased and 13 | # re-generated from your development database when you run "rake". 14 | # Do not set this db to the same as development or production. 15 | test: 16 | adapter: sqlite3 17 | database: db/test.sqlite3 18 | pool: 5 19 | timeout: 5000 20 | 21 | production: 22 | adapter: sqlite3 23 | database: db/production.sqlite3 24 | pool: 5 25 | timeout: 5000 26 | -------------------------------------------------------------------------------- /test/dummy/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the Rails application. 5 | Dummy::Application.initialize! -------------------------------------------------------------------------------- /test/dummy/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Dummy::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Do not eager load code on boot. 10 | config.eager_load = false 11 | 12 | # Show full error reports and disable caching. 13 | config.consider_all_requests_local = true 14 | config.action_controller.perform_caching = false 15 | 16 | # Don't care if the mailer can't send. 17 | config.action_mailer.raise_delivery_errors = false 18 | 19 | # Print deprecation notices to the Rails logger. 20 | config.active_support.deprecation = :log 21 | 22 | # Raise an error on page load if there are pending migrations 23 | config.active_record.migration_error = :page_load 24 | 25 | # Debug mode disables concatenation and preprocessing of assets. 26 | # This option may cause significant delays in view rendering with a large 27 | # number of complex assets. 28 | config.assets.debug = true 29 | end -------------------------------------------------------------------------------- /test/dummy/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Dummy::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # Code is not reloaded between requests. 5 | config.cache_classes = true 6 | 7 | # Eager load code on boot. This eager loads most of Rails and 8 | # your application in memory, allowing both thread web servers 9 | # and those relying on copy on write to perform better. 10 | # Rake tasks automatically ignore this option for performance. 11 | config.eager_load = true 12 | 13 | # Full error reports are disabled and caching is turned on. 14 | config.consider_all_requests_local = false 15 | config.action_controller.perform_caching = true 16 | 17 | # Enable Rack::Cache to put a simple HTTP cache in front of your application 18 | # Add `rack-cache` to your Gemfile before enabling this. 19 | # For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid. 20 | # config.action_dispatch.rack_cache = true 21 | 22 | # Disable Rails's static asset server (Apache or nginx will already do this). 23 | config.serve_static_files = false 24 | 25 | # Compress JavaScripts and CSS. 26 | config.assets.js_compressor = :uglifier 27 | # config.assets.css_compressor = :sass 28 | 29 | # Do not fallback to assets pipeline if a precompiled asset is missed. 30 | config.assets.compile = false 31 | 32 | # Generate digests for assets URLs. 33 | config.assets.digest = true 34 | 35 | # Version of your assets, change this if you want to expire all your assets. 36 | config.assets.version = '1.0' 37 | 38 | # Specifies the header that your server uses for sending files. 39 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache 40 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 41 | 42 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 43 | # config.force_ssl = true 44 | 45 | # Set to :debug to see everything in the log. 46 | config.log_level = :info 47 | 48 | # Prepend all log lines with the following tags. 49 | # config.log_tags = [ :subdomain, :uuid ] 50 | 51 | # Use a different logger for distributed setups. 52 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 53 | 54 | # Use a different cache store in production. 55 | # config.cache_store = :mem_cache_store 56 | 57 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 58 | # config.action_controller.asset_host = "http://assets.example.com" 59 | 60 | # Precompile additional assets. 61 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. 62 | # config.assets.precompile += %w( search.js ) 63 | 64 | # Ignore bad email addresses and do not raise email delivery errors. 65 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 66 | # config.action_mailer.raise_delivery_errors = false 67 | 68 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 69 | # the I18n.default_locale when a translation can not be found). 70 | config.i18n.fallbacks = true 71 | 72 | # Send deprecation notices to registered listeners. 73 | config.active_support.deprecation = :notify 74 | 75 | # Disable automatic flushing of the log to improve performance. 76 | # config.autoflush_log = false 77 | 78 | # Use default logging formatter so that PID and timestamp are not suppressed. 79 | config.log_formatter = ::Logger::Formatter.new 80 | end 81 | -------------------------------------------------------------------------------- /test/dummy/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Dummy::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Do not eager load code on boot. This avoids loading your whole application 11 | # just for the purpose of running a single test. If you are using a tool that 12 | # preloads Rails for running tests, you may have to set it to true. 13 | config.eager_load = false 14 | 15 | # Configure static asset server for tests with Cache-Control for performance. 16 | config.serve_static_files = true 17 | config.static_cache_control = "public, max-age=3600" 18 | 19 | # Show full error reports and disable caching. 20 | config.consider_all_requests_local = true 21 | config.action_controller.perform_caching = false 22 | 23 | # Raise exceptions instead of rendering exception templates. 24 | config.action_dispatch.show_exceptions = false 25 | 26 | # Disable request forgery protection in test environment. 27 | config.action_controller.allow_forgery_protection = false 28 | 29 | # Tell Action Mailer not to deliver emails to the real world. 30 | # The :test delivery method accumulates sent emails in the 31 | # ActionMailer::Base.deliveries array. 32 | config.action_mailer.delivery_method = :test 33 | 34 | # Print deprecation notices to the stderr. 35 | config.active_support.deprecation = :stderr 36 | 37 | config.active_support.test_order = :sorted 38 | end 39 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end -------------------------------------------------------------------------------- /test/dummy/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | # Mime::Type.register_alias "text/html", :iphone 6 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key is used for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | 6 | # Make sure the secret is at least 30 characters and all random, 7 | # no regular words or you'll be exposed to dictionary attacks. 8 | # You can use `rake secret` to generate a secure secret key. 9 | 10 | # Make sure your secret_key_base is kept private 11 | # if you're sharing your code publicly. 12 | Dummy::Application.config.secret_key_base = '85ca90e845b627a2935036b88eaf5e8fdf3ead8a5b05a8daa96129449b7693b71f177172d376065372e939b7347ff2977a4d7965da3c6cc023fb67c51d0e09fd' 13 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Dummy::Application.config.session_store :cookie_store, key: '_dummy_session' 4 | -------------------------------------------------------------------------------- /test/dummy/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] if respond_to?(:wrap_parameters) 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /test/dummy/config/locales/en.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 | hello: "Hello world" 6 | -------------------------------------------------------------------------------- /test/dummy/config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | mount PointlessFeedback::Engine => "/pointless_feedback" 3 | 4 | root :to => 'home#index' 5 | end 6 | -------------------------------------------------------------------------------- /test/dummy/db/schema.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | # This file is auto-generated from the current state of the database. Instead 3 | # of editing this file, please use the migrations feature of Active Record to 4 | # incrementally modify your database, and then regenerate this schema definition. 5 | # 6 | # Note that this schema.rb definition is the authoritative source for your 7 | # database schema. If you need to create the application database on another 8 | # system, you should be using db:schema:load, not running all the migrations 9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 10 | # you'll amass, the slower it'll run and the greater likelihood for issues). 11 | # 12 | # It's strongly recommended that you check this file into your version control system. 13 | 14 | ActiveRecord::Schema.define(version: 20220518205500) do 15 | 16 | create_table "pointless_feedback_messages", force: :cascade do |t| 17 | t.string "name" 18 | t.string "email_address" 19 | t.string "topic" 20 | t.text "description" 21 | t.datetime "created_at" 22 | t.datetime "updated_at" 23 | t.string "url" 24 | end 25 | 26 | end 27 | -------------------------------------------------------------------------------- /test/dummy/lib/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vigetlabs/pointless-feedback/9b3363237b316e5fe0511c86624f71c3235f7ded/test/dummy/lib/assets/.gitkeep -------------------------------------------------------------------------------- /test/dummy/log/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vigetlabs/pointless-feedback/9b3363237b316e5fe0511c86624f71c3235f7ded/test/dummy/log/.gitkeep -------------------------------------------------------------------------------- /test/dummy/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The page you were looking for doesn't exist.

23 |

You may have mistyped the address or the page may have moved.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /test/dummy/public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

The change you wanted was rejected.

23 |

Maybe you tried to change something you didn't have access to.

24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /test/dummy/public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 17 | 18 | 19 | 20 | 21 |
22 |

We're sorry, but something went wrong.

23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /test/dummy/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vigetlabs/pointless-feedback/9b3363237b316e5fe0511c86624f71c3235f7ded/test/dummy/public/favicon.ico -------------------------------------------------------------------------------- /test/dummy/script/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. 3 | 4 | APP_PATH = File.expand_path('../../config/application', __FILE__) 5 | require File.expand_path('../../config/boot', __FILE__) 6 | require 'rails/commands' 7 | -------------------------------------------------------------------------------- /test/factories/messages.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :message, :class => PointlessFeedback::Message do 3 | name 'A Developer' 4 | email_address 'developer@pointlesscorp.com' 5 | description 'Site is broke' 6 | topic 'Other' 7 | url 'https://www.viget.com/' 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /test/functional/pointless_feedback/feedback_mailer_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | module PointlessFeedback 4 | class FeedbackMailerTest < ActionMailer::TestCase 5 | before do 6 | PointlessFeedback.to_emails = 'to@example.com' 7 | 8 | @message = FactoryGirl.create(:message) 9 | @mail = FeedbackMailer.feedback(@message) 10 | end 11 | 12 | test "feedback email" do 13 | assert_equal "Feedback", @mail.subject 14 | assert_equal ["to@example.com"], @mail.to 15 | assert_equal ["feedback@pointlesscorp.com"], @mail.from 16 | end 17 | 18 | test "feedback email body" do 19 | assert_match "You've got feedback!", @mail.body.encoded 20 | assert_match "Name: #{@message.name}", @mail.body.encoded 21 | assert_match "Email Address: #{@message.email_address}", @mail.body.encoded 22 | assert_match "Topic: #{@message.topic}", @mail.body.encoded 23 | assert_match "Description: #{@message.description}", @mail.body.encoded 24 | end 25 | 26 | test "feedback email body with URL field" do 27 | PointlessFeedback.show_url_field = true 28 | PointlessFeedback.url_label = "Story URL" 29 | 30 | assert_match "You've got feedback!", @mail.body.encoded 31 | assert_match "Name: #{@message.name}", @mail.body.encoded 32 | assert_match "Email Address: #{@message.email_address}", @mail.body.encoded 33 | assert_match "Topic: #{@message.topic}", @mail.body.encoded 34 | assert_match "Description: #{@message.description}", @mail.body.encoded 35 | assert_match "Story URL: #{@message.url}", @mail.body.encoded 36 | end 37 | 38 | test "feedback from email when set" do 39 | PointlessFeedback.from_email = 'from@example.com' 40 | @mail = FeedbackMailer.feedback(@message) 41 | 42 | assert_equal 'from@example.com', @mail.from.first 43 | end 44 | 45 | test "feedback from email when set as the sender" do 46 | PointlessFeedback.send_from_submitter = true 47 | @mail = FeedbackMailer.feedback(@message) 48 | 49 | assert_equal @message.email_address, @mail.from.first 50 | end 51 | 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /test/functional/pointless_feedback/messages_controller_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | module PointlessFeedback 4 | class MessagesControllerTest < ActionController::TestCase 5 | setup do 6 | @routes = Engine.routes 7 | end 8 | 9 | describe "getting new" do 10 | setup { get :new } 11 | 12 | it { assert_response :success } 13 | it { assert_template :new } 14 | it { assigns(:message).must_be_instance_of Message } 15 | end 16 | 17 | describe "posting to create" do 18 | setup do 19 | @valid_params = { 20 | :message => { 21 | :name => 'Some Guy', 22 | :email_address => 'some_guy@web.com', 23 | :topic => 'Other', 24 | :description => 'Yo website bork' 25 | } 26 | } 27 | end 28 | 29 | describe "with invalid params" do 30 | setup do 31 | post :create, @valid_params.merge(:message => { :name => ''}) 32 | end 33 | 34 | it { assert_response :success } 35 | it { assert_template :new } 36 | 37 | it { assigns(:message).must_be :invalid? } 38 | end 39 | 40 | describe "with valid params" do 41 | describe "with default after_message_create_path" do 42 | setup do 43 | post :create, @valid_params 44 | end 45 | 46 | it { assert_response :redirect } 47 | it { assert_redirected_to '/' } 48 | it { flash[:notice].must_equal 'Thanks for your feedback!' } 49 | end 50 | 51 | describe "with overridden after_message_create_path" do 52 | setup do 53 | @controller.instance_eval "def after_message_create_path; '/dashboard'; end" 54 | post :create, @valid_params 55 | end 56 | 57 | it { assert_response :redirect } 58 | it { assert_redirected_to '/dashboard' } 59 | it { flash[:notice].must_equal 'Thanks for your feedback!' } 60 | end 61 | end 62 | end 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /test/generators/install_generator_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | require "rails/generators/test_case" 3 | require "generators/pointless_feedback/install_generator" 4 | 5 | class InstallGeneratorTest < Rails::Generators::TestCase 6 | tests PointlessFeedback::Generators::InstallGenerator 7 | destination File.expand_path("../../tmp", __FILE__) 8 | setup :prepare_destination 9 | 10 | test "Assert all files are properly created" do 11 | run_generator 12 | assert_file "config/initializers/pointless_feedback.rb" 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /test/generators/views_generator_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | require "rails/generators/test_case" 3 | require "generators/pointless_feedback/views_generator" 4 | 5 | class ViewsGeneratorTest < Rails::Generators::TestCase 6 | tests PointlessFeedback::Generators::ViewsGenerator 7 | destination File.expand_path("../../tmp", __FILE__) 8 | setup :prepare_destination 9 | 10 | test "Assert all views are properly created" do 11 | run_generator 12 | assert_file 'app/views/pointless_feedback/messages/new.html.erb' 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /test/integration/pointless_feedback/feedback_submission_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class FeedbackSubmissionTest < ActionDispatch::IntegrationTest 4 | fixtures :all 5 | 6 | describe "submitting feedback" do 7 | before do 8 | visit "/pointless_feedback" 9 | 10 | fill_in_fields 11 | 12 | click_on "Submit" 13 | end 14 | 15 | test "redirects to the root path" do 16 | assert_equal current_path, "/" 17 | end 18 | 19 | test "thanks message is displayed" do 20 | within('body') do 21 | assert_match 'Thanks for your feedback!', text 22 | end 23 | end 24 | end 25 | 26 | describe "submitting feedback with the honeypot field filled in" do 27 | before do 28 | visit "/pointless_feedback" 29 | 30 | fill_in_fields 31 | fill_in "message_contact_info", :with => "I'm a spam bot!" 32 | 33 | click_on "Submit" 34 | end 35 | 36 | test "redirects to the root path" do 37 | assert_equal current_path, "/" 38 | end 39 | 40 | test "thanks message is displayed" do 41 | within('body') do 42 | assert_match 'Thanks for your feedback!', text 43 | end 44 | end 45 | end 46 | 47 | describe "submitting feedback with the invalid word in description" do 48 | before do 49 | PointlessFeedback.invalid_words = ['nymphomania'] 50 | 51 | visit "/pointless_feedback" 52 | 53 | fill_in_fields 54 | fill_in "Description", :with => "I got nymphomania." 55 | 56 | click_on "Submit" 57 | end 58 | 59 | test "redirects to the root path" do 60 | assert_equal current_path, "/" 61 | end 62 | 63 | test "thanks message is displayed" do 64 | within('body') do 65 | assert_match 'Thanks for your feedback!', text 66 | end 67 | end 68 | end 69 | 70 | def fill_in_fields 71 | fill_in "Name", :with => "Eli" 72 | fill_in "Email address", :with => "eli@example.com" 73 | select "Other", :from => "Topic" 74 | fill_in "Description", :with => "This site is awful" 75 | end 76 | 77 | end 78 | -------------------------------------------------------------------------------- /test/integration/pointless_feedback/main_app_root_url_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class MainAppRootUrlTest < ActionDispatch::IntegrationTest 4 | test "root_url link points to main_app.root_url" do 5 | visit "/pointless_feedback" 6 | 7 | assert page.has_link?("Homepage", :href => current_host + "/") 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /test/pointless_feedback_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class PointlessFeedbackTest < ActiveSupport::TestCase 4 | test "truth" do 5 | assert_kind_of Module, PointlessFeedback 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | # Configure Rails Environment 2 | ENV["RAILS_ENV"] = "test" 3 | 4 | require File.expand_path("../dummy/config/environment.rb", __FILE__) 5 | require "rails/test_help" 6 | require "capybara/rails" 7 | require "factory_girl" 8 | require "test/unit" 9 | require "mocha/setup" 10 | 11 | require File.expand_path("../factories/messages.rb", __FILE__) 12 | 13 | Rails.backtrace_cleaner.remove_silencers! 14 | 15 | # Load support files 16 | Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f } 17 | 18 | # Load fixtures from the engine 19 | if ActiveSupport::TestCase.method_defined?(:fixture_path=) 20 | ActiveSupport::TestCase.fixture_path = File.expand_path("../fixtures", __FILE__) 21 | end 22 | 23 | class ActionDispatch::IntegrationTest 24 | # Make the Capybara DSL available in all integration tests 25 | include Capybara::DSL 26 | end 27 | -------------------------------------------------------------------------------- /test/unit/helpers/pointless_feedback/application_helper_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | module PointlessFeedback 4 | class ApplicationHelperTest < ActionDispatch::IntegrationTest 5 | describe "main app's named routes" do 6 | class MainAppApplicationHelperMock 7 | def foo_path 8 | '/foo' 9 | end 10 | 11 | def foo_url 12 | 'http://host/foo' 13 | end 14 | end 15 | 16 | class PointlessFeedbackApplicationHelperMock 17 | include PointlessFeedback::ApplicationHelper 18 | 19 | def main_app 20 | MainAppApplicationHelperMock.new 21 | end 22 | end 23 | 24 | let(:raw_helper) { PointlessFeedbackApplicationHelperMock.new } 25 | 26 | it "outputs named path from the main app" do 27 | raw_helper.foo_path.must_equal '/foo' 28 | end 29 | 30 | it "outputs named url from the main app" do 31 | raw_helper.foo_url.must_equal 'http://host/foo' 32 | end 33 | 34 | it "raises exception with other routes" do 35 | proc{ raw_helper.lolwut_path }.must_raise NoMethodError 36 | end 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /test/unit/pointless_feedback/captcha_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | module PointlessFeedback 4 | class CaptchaTest < ActiveSupport::TestCase 5 | 6 | describe ".pass?" do 7 | setup do 8 | PointlessFeedback.google_captcha_secret_key = "super-secret" 9 | @url = "https://www.google.com/recaptcha/api/siteverify" 10 | @body = { 11 | secret: "super-secret", 12 | response: "fake-response" 13 | } 14 | end 15 | 16 | teardown do 17 | PointlessFeedback.google_captcha_secret_key = nil 18 | @url = nil 19 | @body = nil 20 | end 21 | 22 | subject { PointlessFeedback::Captcha } 23 | 24 | it "returns true if Google response is true" do 25 | success = { "success" => true } 26 | response = stub(body: success.to_json) 27 | 28 | Typhoeus.expects(:post).with(@url, body: @body).returns(response) 29 | 30 | assert subject.pass?("fake-response") 31 | end 32 | 33 | it "returns false if Google response is true" do 34 | failure = { "success" => false } 35 | response = stub(body: failure.to_json) 36 | 37 | Typhoeus.expects(:post).with(@url, body: @body).returns(response) 38 | 39 | refute subject.pass?("fake-response") 40 | end 41 | end 42 | 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /test/unit/pointless_feedback/message_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | module PointlessFeedback 4 | class MessageTest < ActiveSupport::TestCase 5 | subject { PointlessFeedback::Message.new } 6 | 7 | %w(name email_address topic description).each do |field| 8 | it "requires #{field}" do 9 | subject.send("#{field}=", '') 10 | subject.save 11 | 12 | subject.errors[field.to_sym].must_include "can't be blank" 13 | end 14 | end 15 | 16 | describe "validating topics" do 17 | subject { FactoryGirl.build(:message) } 18 | 19 | it "allows valid topic" do 20 | subject.topic = 'Other' 21 | 22 | assert subject.valid? 23 | end 24 | 25 | it "does not allow invalid topic" do 26 | subject.topic = 'lolwut' 27 | 28 | assert subject.invalid? 29 | subject.errors[:topic].must_include "is not included in the list" 30 | end 31 | end 32 | 33 | describe "validating email" do 34 | subject { FactoryGirl.build(:message) } 35 | 36 | it "allows a valid email address" do 37 | subject.email_address = 'test@example.com' 38 | 39 | assert subject.valid? 40 | end 41 | 42 | it "does not allow invalid emails address" do 43 | subject.email_address = 'test@example' 44 | assert subject.invalid? 45 | 46 | subject.email_address = 'test.com' 47 | assert subject.invalid? 48 | 49 | subject.email_address = 'come on' 50 | assert subject.invalid? 51 | end 52 | end 53 | 54 | describe "validating against spam" do 55 | subject { FactoryGirl.build(:message) } 56 | 57 | it "allows descriptions with no links" do 58 | subject.description = "I have no links!" 59 | 60 | assert subject.valid? 61 | end 62 | 63 | it "does not allow descriptions with 3 or more links" do 64 | subject.description = 'CXYz73 kniuzeqqywrg, [url=http://kdvfwnevgkcq.com/]kdvfwnevgkcq[/url], [link=http://fibhlwzwvxjr.com/]fibhlwzwvxjr[/link], http://pebecsefhsmz.com/' 65 | 66 | assert subject.invalid? 67 | end 68 | end 69 | 70 | describe "export_feedback" do 71 | describe "when PointlessFeedback.email_feedback is true" do 72 | before do 73 | PointlessFeedback.email_feedback = true 74 | PointlessFeedback.to_emails = ['test1@example.com', 'test2@example.com'] 75 | end 76 | 77 | subject { FactoryGirl.build(:message) } 78 | 79 | it "sends mail after create" do 80 | mailer = stub(:deliver_now => true) 81 | FeedbackMailer.expects(:feedback).with(subject).returns(mailer) 82 | 83 | subject.save 84 | end 85 | 86 | describe "when the honeypot field is not nil" do 87 | it "does not send mail after create" do 88 | subject.contact_info = "I'm a spam bot!" 89 | FeedbackMailer.expects(:feedback).never 90 | 91 | subject.save 92 | end 93 | end 94 | 95 | describe "when the description contains an invalid word" do 96 | it "does not send mail after create" do 97 | PointlessFeedback.invalid_words = ['nymphomania'] 98 | 99 | subject.description = "I have nymphomania." 100 | FeedbackMailer.expects(:feedback).never 101 | 102 | subject.save 103 | end 104 | end 105 | end 106 | 107 | describe "when PointlessFeedback.email_feedback is false" do 108 | before do 109 | PointlessFeedback.email_feedback = false 110 | end 111 | subject { FactoryGirl.build(:message) } 112 | 113 | it "does not send any mail" do 114 | FeedbackMailer.expects(:feedback).times(0) 115 | 116 | subject.save 117 | end 118 | end 119 | end 120 | end 121 | end 122 | --------------------------------------------------------------------------------