├── .gitattributes ├── .gitignore ├── .rspec ├── .ruby-version ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── Rakefile ├── app ├── assets │ ├── config │ │ └── manifest.js │ ├── images │ │ ├── .keep │ │ ├── collab.png │ │ ├── eff_logo.png │ │ ├── eff_project.png │ │ ├── eff_sm.png │ │ ├── eff_tosdr_project.png │ │ ├── footer.png │ │ ├── logo.png │ │ ├── logo │ │ │ ├── 500px.png │ │ │ ├── allrecipes.png │ │ │ ├── amazon.png │ │ │ ├── android.png │ │ │ ├── app-net.png │ │ │ ├── apple-icloud.png │ │ │ ├── apple.png │ │ │ ├── att.png │ │ │ ├── bearshare.png │ │ │ ├── bit.png │ │ │ ├── blizzard.png │ │ │ ├── blogger.png │ │ │ ├── blogspot.png │ │ │ ├── cloudant.png │ │ │ ├── comcast.png │ │ │ ├── couchsurfing.png │ │ │ ├── default.png │ │ │ ├── delicious.png │ │ │ ├── disqus.png │ │ │ ├── dropbox.png │ │ │ ├── duckduckgo.png │ │ │ ├── ebuddy.png │ │ │ ├── envato.png │ │ │ ├── evernote.png │ │ │ ├── facebook.png │ │ │ ├── faranow.png │ │ │ ├── finance.yahoo.png │ │ │ ├── flattr.png │ │ │ ├── flickr.png │ │ │ ├── foursquare.png │ │ │ ├── freeforums.png │ │ │ ├── github.png │ │ │ ├── gmail.png │ │ │ ├── google.png │ │ │ ├── grammarly.png │ │ │ ├── gravatar.png │ │ │ ├── habbo.png │ │ │ ├── hypster.png │ │ │ ├── identi-ca.png │ │ │ ├── ifttt.png │ │ │ ├── informe.png │ │ │ ├── instagram.png │ │ │ ├── lastpass.png │ │ │ ├── linkedin.png │ │ │ ├── live.png │ │ │ ├── loopt.png │ │ │ ├── microsoft.png │ │ │ ├── microsoftstore.png │ │ │ ├── minecraft.png │ │ │ ├── msn.png │ │ │ ├── myspace.png │ │ │ ├── nabble.png │ │ │ ├── netflix.png │ │ │ ├── newsblur.png │ │ │ ├── olx.png │ │ │ ├── owncube.png │ │ │ ├── phpbb.png │ │ │ ├── plus.google.png │ │ │ ├── rapidshare.png │ │ │ ├── reddit.png │ │ │ ├── runescape.png │ │ │ ├── seenthis.png │ │ │ ├── skype.png │ │ │ ├── sonic.png │ │ │ ├── soundcloud.png │ │ │ ├── spideroak.png │ │ │ ├── spotify.png │ │ │ ├── steampowered.png │ │ │ ├── tumblr.png │ │ │ ├── twitpic.png │ │ │ ├── twitter.png │ │ │ ├── vbulletin.png │ │ │ ├── verizon.png │ │ │ ├── videobb.png │ │ │ ├── whatsapp.png │ │ │ ├── wikimediafoundation.png │ │ │ ├── wikipedia.png │ │ │ ├── wordfeud.png │ │ │ ├── wordpress.png │ │ │ ├── xfire.png │ │ │ ├── xing.png │ │ │ ├── yahoo.png │ │ │ ├── youtube.png │ │ │ └── zoosk.png │ │ ├── rails.png │ │ ├── tagline.png │ │ ├── tosdr-logo-32-w.png │ │ └── tosdr_logo.png │ ├── javascripts │ │ └── application.js │ └── stylesheets │ │ ├── application.scss │ │ ├── crawls.css.scss │ │ ├── notifications.scss │ │ ├── policies.scss │ │ ├── sessions.css.scss │ │ ├── sites.css.scss │ │ ├── users.css.scss │ │ └── versions.css.scss ├── controllers │ ├── application_controller.rb │ ├── concerns │ │ └── .keep │ ├── crawls_controller.rb │ ├── notifications_controller.rb │ ├── policies_controller.rb │ ├── sessions_controller.rb │ ├── sites_controller.rb │ ├── users_controller.rb │ └── versions_controller.rb ├── helpers │ ├── application_helper.rb │ └── sessions_helper.rb ├── jobs │ └── application_job.rb ├── mailers │ └── application_mailer.rb ├── models │ ├── application_record.rb │ ├── commitment.rb │ ├── concerns │ │ └── .keep │ ├── crawl.rb │ ├── notification.rb │ ├── policy.rb │ ├── site.rb │ ├── subscription.rb │ ├── user.rb │ └── version.rb ├── presenters │ └── policy_presenter.rb └── views │ ├── layouts │ ├── _bsheader.html.erb │ ├── _footer.html.erb │ ├── _header.html.erb │ ├── _sidebar.html.erb │ ├── application.html.erb │ ├── bsapplication.html.erb │ ├── mailer.html.erb │ └── mailer.text.erb │ ├── notifications │ └── index.html.erb │ ├── policies │ ├── index.html.erb │ └── show.html.erb │ ├── sessions │ └── new.html.erb │ ├── shared │ ├── _errors.html.erb │ └── _list_each_as_link.html.erb │ ├── sites │ ├── index.html.erb │ └── show.html.erb │ ├── users │ ├── _user_form.html.erb │ ├── edit.html.erb │ ├── new.html.erb │ └── show.html.erb │ └── versions │ ├── _version.html.erb │ ├── index.html.erb │ ├── show.html.erb │ ├── show.js.erb │ └── show.json.erb ├── bin ├── bundle ├── rails ├── rake ├── setup ├── spring ├── update └── yarn ├── config.ru ├── config ├── application.rb ├── boot.rb ├── cable.yml ├── database.yml.example ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── initializers │ ├── application_controller_renderer.rb │ ├── assets.rb │ ├── backtrace_silencers.rb │ ├── cookies_serializer.rb │ ├── filter_parameter_logging.rb │ ├── inflections.rb │ ├── mime_types.rb │ ├── new_framework_defaults_5_1.rb │ └── wrap_parameters.rb ├── locales │ └── en.yml ├── puma.rb ├── routes.rb ├── secrets.yml └── spring.rb ├── db ├── migrate │ ├── 20130106195349_create_sites.rb │ ├── 20130107182823_create_policies.rb │ ├── 20130107212843_remove_site_id_from_policy.rb │ ├── 20130110080148_create_commitments.rb │ ├── 20130117190926_create_versions.rb │ ├── 20130122214855_create_crawls.rb │ ├── 20130122221303_rename_crawl_in_policy.rb │ ├── 20130122222453_rename_crawl_in_crawls.rb │ ├── 20130130183836_add_needs_revision_to_policies.rb │ ├── 20130205164614_create_users.rb │ ├── 20130205173331_create_subscriptions.rb │ ├── 20130206150453_add_password_digest_to_users.rb │ ├── 20130206154837_add_index_to_users_email.rb │ ├── 20130602151232_change_table_crawls.rb │ ├── 20130602152236_add_policy_to_crawls.rb │ ├── 20130602153011_add_full_page_to_versions.rb │ ├── 20130602153432_rename_column_in_versions.rb │ ├── 20130602163220_rename_column_in_crawls.rb │ ├── 20130718160617_create_notifications.rb │ ├── 20130724121055_add_diff_url_to_notifications.rb │ ├── 20141207153633_remove_xpath_and_detail_from_policies.rb │ ├── 20141207153710_add_xpath_and_text_to_versions.rb │ ├── 20180227222001_remove_xpath_from_versions.rb │ ├── 20180227222214_add_xpath_to_policies.rb │ ├── 20180227222404_add_former_site_to_versions.rb │ ├── 20180228193354_add_obsolete_to_policies.rb │ └── 20180228214750_add_diff_url_to_versions.rb ├── schema.rb └── seeds.rb ├── lib ├── assets │ └── .keep └── tasks │ ├── .keep │ ├── import_versions.rake │ └── manage_xml.rake ├── log └── .keep ├── package.json ├── public ├── 404.html ├── 422.html ├── 500.html ├── apple-touch-icon-precomposed.png ├── apple-touch-icon.png ├── favicon.ico └── robots.txt ├── readme.md ├── spec ├── factories │ ├── commitments.rb │ ├── crawls.rb │ ├── notifications.rb │ ├── policies.rb │ ├── sites.rb │ ├── subscriptions.rb │ ├── users.rb │ └── versions.rb ├── features │ ├── authorization_spec.rb │ ├── crawl_controller_spec.rb │ ├── policies_controller_spec.rb │ ├── sessions_controller_spec.rb │ ├── site_controller_spec.rb │ ├── users_controller_spec.rb │ └── versions_controller_spec.rb ├── models │ ├── commitment_spec.rb │ ├── crawl_spec.rb │ ├── notification_spec.rb │ ├── policy_spec.rb │ ├── site_spec.rb │ ├── subscription_spec.rb │ ├── user_spec.rb │ └── version_spec.rb ├── rails_helper.rb ├── spec_helper.rb └── support │ ├── partials_shared.rb │ └── utilities.rb ├── tmp └── .keep ├── unused ├── custom.css.scss ├── diff_match_patch.js └── versions.js └── vendor └── .keep /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behaviour, in case users don't have core.autocrlf set. 2 | * text=auto 3 | *.rb text 4 | *.erb text 5 | *.css text 6 | *.scss text 7 | *.html text 8 | *.htm text 9 | *.coffee text 10 | *.js text 11 | *.less text 12 | *.builder text 13 | *.xml text 14 | 15 | # Denote all files that are truly binary and should not be modified. 16 | *.png binary 17 | *.jpg binary 18 | *.ico binary 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile '~/.gitignore_global' 6 | 7 | # Ignore bundler config. 8 | /.bundle 9 | /config/database.yml 10 | 11 | # Ignore the default SQLite database. 12 | /db/*.sqlite3 13 | /db/*.sqlite3-journal 14 | 15 | # Ignore all logfiles and tempfiles. 16 | /log/* 17 | /tmp/* 18 | !/log/.keep 19 | !/tmp/.keep 20 | 21 | /node_modules 22 | /yarn-error.log 23 | 24 | .byebug_history 25 | 26 | # Ignore encrypted secrets key file. 27 | config/secrets.yml.key 28 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --require rails_helper 2 | --color 3 | -f documentation 4 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.7.2 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | git_source(:github) do |repo_name| 4 | repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") 5 | "https://github.com/#{repo_name}.git" 6 | end 7 | 8 | 9 | # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' 10 | gem 'rails', '~> 5.1.6' 11 | # Use sqlite3 as the database for Active Record 12 | gem 'sqlite3' 13 | # Use Puma as the app server 14 | gem 'puma', '~> 3.7' 15 | # Use SCSS for stylesheets 16 | gem 'sass-rails', '~> 5.0' 17 | # Use Uglifier as compressor for JavaScript assets 18 | gem 'uglifier', '>= 1.3.0' 19 | # See https://github.com/rails/execjs#readme for more supported runtimes 20 | # gem 'therubyracer', platforms: :ruby 21 | gem 'will_paginate' 22 | 23 | # Use CoffeeScript for .coffee assets and views 24 | gem 'coffee-rails', '~> 4.2' 25 | # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks 26 | gem 'turbolinks', '~> 5' 27 | # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder 28 | gem 'jbuilder', '~> 2.5' 29 | # Use Redis adapter to run Action Cable in production 30 | # gem 'redis', '~> 3.0' 31 | # Use ActiveModel has_secure_password 32 | gem 'bcrypt', '~> 3.1.7' 33 | 34 | # Use Capistrano for deployment 35 | # gem 'capistrano-rails', group: :development 36 | group :production do 37 | gem 'mysql2', '~> 0.4.10' 38 | end 39 | 40 | group :development, :test do 41 | # Call 'byebug' anywhere in the code to stop execution and get a debugger console 42 | gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] 43 | gem 'rspec-rails', '~> 3.7' 44 | gem "factory_bot_rails" 45 | 46 | # Adds support for Capybara system testing and selenium driver 47 | gem 'capybara', '~> 2.13' 48 | gem 'selenium-webdriver' 49 | end 50 | 51 | group :development do 52 | gem 'annotate' 53 | # Access an IRB console on exception pages or by using <%= console %> anywhere in the code. 54 | gem 'web-console', '>= 3.3.0' 55 | gem 'listen', '>= 3.0.5', '< 3.2' 56 | # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring 57 | gem 'spring' 58 | gem 'spring-watcher-listen', '~> 2.0.0' 59 | end 60 | 61 | # Windows does not include zoneinfo files, so bundle the tzinfo-data gem 62 | gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] 63 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actioncable (5.1.7) 5 | actionpack (= 5.1.7) 6 | nio4r (~> 2.0) 7 | websocket-driver (~> 0.6.1) 8 | actionmailer (5.1.7) 9 | actionpack (= 5.1.7) 10 | actionview (= 5.1.7) 11 | activejob (= 5.1.7) 12 | mail (~> 2.5, >= 2.5.4) 13 | rails-dom-testing (~> 2.0) 14 | actionpack (5.1.7) 15 | actionview (= 5.1.7) 16 | activesupport (= 5.1.7) 17 | rack (~> 2.0) 18 | rack-test (>= 0.6.3) 19 | rails-dom-testing (~> 2.0) 20 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 21 | actionview (5.1.7) 22 | activesupport (= 5.1.7) 23 | builder (~> 3.1) 24 | erubi (~> 1.4) 25 | rails-dom-testing (~> 2.0) 26 | rails-html-sanitizer (~> 1.0, >= 1.0.3) 27 | activejob (5.1.7) 28 | activesupport (= 5.1.7) 29 | globalid (>= 0.3.6) 30 | activemodel (5.1.7) 31 | activesupport (= 5.1.7) 32 | activerecord (5.1.7) 33 | activemodel (= 5.1.7) 34 | activesupport (= 5.1.7) 35 | arel (~> 8.0) 36 | activesupport (5.1.7) 37 | concurrent-ruby (~> 1.0, >= 1.0.2) 38 | i18n (>= 0.7, < 2) 39 | minitest (~> 5.1) 40 | tzinfo (~> 1.1) 41 | addressable (2.7.0) 42 | public_suffix (>= 2.0.2, < 5.0) 43 | annotate (3.1.1) 44 | activerecord (>= 3.2, < 7.0) 45 | rake (>= 10.4, < 14.0) 46 | arel (8.0.0) 47 | bcrypt (3.1.16) 48 | bindex (0.8.1) 49 | builder (3.2.4) 50 | byebug (11.1.3) 51 | capybara (2.18.0) 52 | addressable 53 | mini_mime (>= 0.1.3) 54 | nokogiri (>= 1.3.3) 55 | rack (>= 1.0.0) 56 | rack-test (>= 0.5.4) 57 | xpath (>= 2.0, < 4.0) 58 | childprocess (3.0.0) 59 | coffee-rails (4.2.2) 60 | coffee-script (>= 2.2.0) 61 | railties (>= 4.0.0) 62 | coffee-script (2.4.1) 63 | coffee-script-source 64 | execjs 65 | coffee-script-source (1.12.2) 66 | concurrent-ruby (1.1.8) 67 | crass (1.0.6) 68 | diff-lcs (1.4.4) 69 | erubi (1.10.0) 70 | execjs (2.7.0) 71 | factory_bot (6.1.0) 72 | activesupport (>= 5.0.0) 73 | factory_bot_rails (6.1.0) 74 | factory_bot (~> 6.1.0) 75 | railties (>= 5.0.0) 76 | ffi (1.15.0) 77 | globalid (0.4.2) 78 | activesupport (>= 4.2.0) 79 | i18n (1.8.9) 80 | concurrent-ruby (~> 1.0) 81 | jbuilder (2.11.2) 82 | activesupport (>= 5.0.0) 83 | listen (3.1.5) 84 | rb-fsevent (~> 0.9, >= 0.9.4) 85 | rb-inotify (~> 0.9, >= 0.9.7) 86 | ruby_dep (~> 1.2) 87 | loofah (2.9.0) 88 | crass (~> 1.0.2) 89 | nokogiri (>= 1.5.9) 90 | mail (2.7.1) 91 | mini_mime (>= 0.1.1) 92 | method_source (1.0.0) 93 | mini_mime (1.0.2) 94 | mini_portile2 (2.5.0) 95 | minitest (5.14.4) 96 | mysql2 (0.4.10) 97 | nio4r (2.5.7) 98 | nokogiri (1.11.2) 99 | mini_portile2 (~> 2.5.0) 100 | racc (~> 1.4) 101 | nokogiri (1.11.2-x86_64-linux) 102 | racc (~> 1.4) 103 | public_suffix (4.0.6) 104 | puma (3.12.6) 105 | racc (1.5.2) 106 | rack (2.2.3) 107 | rack-test (1.1.0) 108 | rack (>= 1.0, < 3) 109 | rails (5.1.7) 110 | actioncable (= 5.1.7) 111 | actionmailer (= 5.1.7) 112 | actionpack (= 5.1.7) 113 | actionview (= 5.1.7) 114 | activejob (= 5.1.7) 115 | activemodel (= 5.1.7) 116 | activerecord (= 5.1.7) 117 | activesupport (= 5.1.7) 118 | bundler (>= 1.3.0) 119 | railties (= 5.1.7) 120 | sprockets-rails (>= 2.0.0) 121 | rails-dom-testing (2.0.3) 122 | activesupport (>= 4.2.0) 123 | nokogiri (>= 1.6) 124 | rails-html-sanitizer (1.3.0) 125 | loofah (~> 2.3) 126 | railties (5.1.7) 127 | actionpack (= 5.1.7) 128 | activesupport (= 5.1.7) 129 | method_source 130 | rake (>= 0.8.7) 131 | thor (>= 0.18.1, < 2.0) 132 | rake (13.0.3) 133 | rb-fsevent (0.10.4) 134 | rb-inotify (0.10.1) 135 | ffi (~> 1.0) 136 | rspec-core (3.9.3) 137 | rspec-support (~> 3.9.3) 138 | rspec-expectations (3.9.4) 139 | diff-lcs (>= 1.2.0, < 2.0) 140 | rspec-support (~> 3.9.0) 141 | rspec-mocks (3.9.1) 142 | diff-lcs (>= 1.2.0, < 2.0) 143 | rspec-support (~> 3.9.0) 144 | rspec-rails (3.9.1) 145 | actionpack (>= 3.0) 146 | activesupport (>= 3.0) 147 | railties (>= 3.0) 148 | rspec-core (~> 3.9.0) 149 | rspec-expectations (~> 3.9.0) 150 | rspec-mocks (~> 3.9.0) 151 | rspec-support (~> 3.9.0) 152 | rspec-support (3.9.4) 153 | ruby_dep (1.5.0) 154 | rubyzip (2.3.0) 155 | sass (3.7.4) 156 | sass-listen (~> 4.0.0) 157 | sass-listen (4.0.0) 158 | rb-fsevent (~> 0.9, >= 0.9.4) 159 | rb-inotify (~> 0.9, >= 0.9.7) 160 | sass-rails (5.0.7) 161 | railties (>= 4.0.0, < 6) 162 | sass (~> 3.1) 163 | sprockets (>= 2.8, < 4.0) 164 | sprockets-rails (>= 2.0, < 4.0) 165 | tilt (>= 1.1, < 3) 166 | selenium-webdriver (3.142.7) 167 | childprocess (>= 0.5, < 4.0) 168 | rubyzip (>= 1.2.2) 169 | spring (2.1.1) 170 | spring-watcher-listen (2.0.1) 171 | listen (>= 2.7, < 4.0) 172 | spring (>= 1.2, < 3.0) 173 | sprockets (3.7.2) 174 | concurrent-ruby (~> 1.0) 175 | rack (> 1, < 3) 176 | sprockets-rails (3.2.2) 177 | actionpack (>= 4.0) 178 | activesupport (>= 4.0) 179 | sprockets (>= 3.0.0) 180 | sqlite3 (1.4.2) 181 | thor (1.1.0) 182 | thread_safe (0.3.6) 183 | tilt (2.0.10) 184 | turbolinks (5.2.1) 185 | turbolinks-source (~> 5.2) 186 | turbolinks-source (5.2.0) 187 | tzinfo (1.2.9) 188 | thread_safe (~> 0.1) 189 | uglifier (4.2.0) 190 | execjs (>= 0.3.0, < 3) 191 | web-console (3.7.0) 192 | actionview (>= 5.0) 193 | activemodel (>= 5.0) 194 | bindex (>= 0.4.0) 195 | railties (>= 5.0) 196 | websocket-driver (0.6.5) 197 | websocket-extensions (>= 0.1.0) 198 | websocket-extensions (0.1.5) 199 | will_paginate (3.3.0) 200 | xpath (3.2.0) 201 | nokogiri (~> 1.8) 202 | 203 | PLATFORMS 204 | ruby 205 | x86_64-linux 206 | 207 | DEPENDENCIES 208 | annotate 209 | bcrypt (~> 3.1.7) 210 | byebug 211 | capybara (~> 2.13) 212 | coffee-rails (~> 4.2) 213 | factory_bot_rails 214 | jbuilder (~> 2.5) 215 | listen (>= 3.0.5, < 3.2) 216 | mysql2 (~> 0.4.10) 217 | puma (~> 3.7) 218 | rails (~> 5.1.6) 219 | rspec-rails (~> 3.7) 220 | sass-rails (~> 5.0) 221 | selenium-webdriver 222 | spring 223 | spring-watcher-listen (~> 2.0.0) 224 | sqlite3 225 | turbolinks (~> 5) 226 | tzinfo-data 227 | uglifier (>= 1.3.0) 228 | web-console (>= 3.3.0) 229 | will_paginate 230 | 231 | BUNDLED WITH 232 | 2.2.15 233 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require_relative 'config/application' 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /app/assets/config/manifest.js: -------------------------------------------------------------------------------- 1 | //= link_tree ../images 2 | //= link_directory ../javascripts .js 3 | //= link_directory ../stylesheets .css 4 | -------------------------------------------------------------------------------- /app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/.keep -------------------------------------------------------------------------------- /app/assets/images/collab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/collab.png -------------------------------------------------------------------------------- /app/assets/images/eff_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/eff_logo.png -------------------------------------------------------------------------------- /app/assets/images/eff_project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/eff_project.png -------------------------------------------------------------------------------- /app/assets/images/eff_sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/eff_sm.png -------------------------------------------------------------------------------- /app/assets/images/eff_tosdr_project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/eff_tosdr_project.png -------------------------------------------------------------------------------- /app/assets/images/footer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/footer.png -------------------------------------------------------------------------------- /app/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo.png -------------------------------------------------------------------------------- /app/assets/images/logo/500px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/500px.png -------------------------------------------------------------------------------- /app/assets/images/logo/allrecipes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/allrecipes.png -------------------------------------------------------------------------------- /app/assets/images/logo/amazon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/amazon.png -------------------------------------------------------------------------------- /app/assets/images/logo/android.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/android.png -------------------------------------------------------------------------------- /app/assets/images/logo/app-net.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/app-net.png -------------------------------------------------------------------------------- /app/assets/images/logo/apple-icloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/apple-icloud.png -------------------------------------------------------------------------------- /app/assets/images/logo/apple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/apple.png -------------------------------------------------------------------------------- /app/assets/images/logo/att.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/att.png -------------------------------------------------------------------------------- /app/assets/images/logo/bearshare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/bearshare.png -------------------------------------------------------------------------------- /app/assets/images/logo/bit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/bit.png -------------------------------------------------------------------------------- /app/assets/images/logo/blizzard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/blizzard.png -------------------------------------------------------------------------------- /app/assets/images/logo/blogger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/blogger.png -------------------------------------------------------------------------------- /app/assets/images/logo/blogspot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/blogspot.png -------------------------------------------------------------------------------- /app/assets/images/logo/cloudant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/cloudant.png -------------------------------------------------------------------------------- /app/assets/images/logo/comcast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/comcast.png -------------------------------------------------------------------------------- /app/assets/images/logo/couchsurfing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/couchsurfing.png -------------------------------------------------------------------------------- /app/assets/images/logo/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/default.png -------------------------------------------------------------------------------- /app/assets/images/logo/delicious.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/delicious.png -------------------------------------------------------------------------------- /app/assets/images/logo/disqus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/disqus.png -------------------------------------------------------------------------------- /app/assets/images/logo/dropbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/dropbox.png -------------------------------------------------------------------------------- /app/assets/images/logo/duckduckgo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/duckduckgo.png -------------------------------------------------------------------------------- /app/assets/images/logo/ebuddy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/ebuddy.png -------------------------------------------------------------------------------- /app/assets/images/logo/envato.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/envato.png -------------------------------------------------------------------------------- /app/assets/images/logo/evernote.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/evernote.png -------------------------------------------------------------------------------- /app/assets/images/logo/facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/facebook.png -------------------------------------------------------------------------------- /app/assets/images/logo/faranow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/faranow.png -------------------------------------------------------------------------------- /app/assets/images/logo/finance.yahoo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/finance.yahoo.png -------------------------------------------------------------------------------- /app/assets/images/logo/flattr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/flattr.png -------------------------------------------------------------------------------- /app/assets/images/logo/flickr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/flickr.png -------------------------------------------------------------------------------- /app/assets/images/logo/foursquare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/foursquare.png -------------------------------------------------------------------------------- /app/assets/images/logo/freeforums.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/freeforums.png -------------------------------------------------------------------------------- /app/assets/images/logo/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/github.png -------------------------------------------------------------------------------- /app/assets/images/logo/gmail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/gmail.png -------------------------------------------------------------------------------- /app/assets/images/logo/google.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/google.png -------------------------------------------------------------------------------- /app/assets/images/logo/grammarly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/grammarly.png -------------------------------------------------------------------------------- /app/assets/images/logo/gravatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/gravatar.png -------------------------------------------------------------------------------- /app/assets/images/logo/habbo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/habbo.png -------------------------------------------------------------------------------- /app/assets/images/logo/hypster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/hypster.png -------------------------------------------------------------------------------- /app/assets/images/logo/identi-ca.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/identi-ca.png -------------------------------------------------------------------------------- /app/assets/images/logo/ifttt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/ifttt.png -------------------------------------------------------------------------------- /app/assets/images/logo/informe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/informe.png -------------------------------------------------------------------------------- /app/assets/images/logo/instagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/instagram.png -------------------------------------------------------------------------------- /app/assets/images/logo/lastpass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/lastpass.png -------------------------------------------------------------------------------- /app/assets/images/logo/linkedin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/linkedin.png -------------------------------------------------------------------------------- /app/assets/images/logo/live.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/live.png -------------------------------------------------------------------------------- /app/assets/images/logo/loopt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/loopt.png -------------------------------------------------------------------------------- /app/assets/images/logo/microsoft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/microsoft.png -------------------------------------------------------------------------------- /app/assets/images/logo/microsoftstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/microsoftstore.png -------------------------------------------------------------------------------- /app/assets/images/logo/minecraft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/minecraft.png -------------------------------------------------------------------------------- /app/assets/images/logo/msn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/msn.png -------------------------------------------------------------------------------- /app/assets/images/logo/myspace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/myspace.png -------------------------------------------------------------------------------- /app/assets/images/logo/nabble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/nabble.png -------------------------------------------------------------------------------- /app/assets/images/logo/netflix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/netflix.png -------------------------------------------------------------------------------- /app/assets/images/logo/newsblur.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/newsblur.png -------------------------------------------------------------------------------- /app/assets/images/logo/olx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/olx.png -------------------------------------------------------------------------------- /app/assets/images/logo/owncube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/owncube.png -------------------------------------------------------------------------------- /app/assets/images/logo/phpbb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/phpbb.png -------------------------------------------------------------------------------- /app/assets/images/logo/plus.google.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/plus.google.png -------------------------------------------------------------------------------- /app/assets/images/logo/rapidshare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/rapidshare.png -------------------------------------------------------------------------------- /app/assets/images/logo/reddit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/reddit.png -------------------------------------------------------------------------------- /app/assets/images/logo/runescape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/runescape.png -------------------------------------------------------------------------------- /app/assets/images/logo/seenthis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/seenthis.png -------------------------------------------------------------------------------- /app/assets/images/logo/skype.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/skype.png -------------------------------------------------------------------------------- /app/assets/images/logo/sonic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/sonic.png -------------------------------------------------------------------------------- /app/assets/images/logo/soundcloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/soundcloud.png -------------------------------------------------------------------------------- /app/assets/images/logo/spideroak.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/spideroak.png -------------------------------------------------------------------------------- /app/assets/images/logo/spotify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/spotify.png -------------------------------------------------------------------------------- /app/assets/images/logo/steampowered.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/steampowered.png -------------------------------------------------------------------------------- /app/assets/images/logo/tumblr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/tumblr.png -------------------------------------------------------------------------------- /app/assets/images/logo/twitpic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/twitpic.png -------------------------------------------------------------------------------- /app/assets/images/logo/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/twitter.png -------------------------------------------------------------------------------- /app/assets/images/logo/vbulletin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/vbulletin.png -------------------------------------------------------------------------------- /app/assets/images/logo/verizon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/verizon.png -------------------------------------------------------------------------------- /app/assets/images/logo/videobb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/videobb.png -------------------------------------------------------------------------------- /app/assets/images/logo/whatsapp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/whatsapp.png -------------------------------------------------------------------------------- /app/assets/images/logo/wikimediafoundation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/wikimediafoundation.png -------------------------------------------------------------------------------- /app/assets/images/logo/wikipedia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/wikipedia.png -------------------------------------------------------------------------------- /app/assets/images/logo/wordfeud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/wordfeud.png -------------------------------------------------------------------------------- /app/assets/images/logo/wordpress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/wordpress.png -------------------------------------------------------------------------------- /app/assets/images/logo/xfire.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/xfire.png -------------------------------------------------------------------------------- /app/assets/images/logo/xing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/xing.png -------------------------------------------------------------------------------- /app/assets/images/logo/yahoo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/yahoo.png -------------------------------------------------------------------------------- /app/assets/images/logo/youtube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/youtube.png -------------------------------------------------------------------------------- /app/assets/images/logo/zoosk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/logo/zoosk.png -------------------------------------------------------------------------------- /app/assets/images/rails.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/rails.png -------------------------------------------------------------------------------- /app/assets/images/tagline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/tagline.png -------------------------------------------------------------------------------- /app/assets/images/tosdr-logo-32-w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/tosdr-logo-32-w.png -------------------------------------------------------------------------------- /app/assets/images/tosdr_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/assets/images/tosdr_logo.png -------------------------------------------------------------------------------- /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, or any plugin's 5 | // vendor/assets/javascripts directory 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 | // compiled file. JavaScript code in this file should be added after the last require_* statement. 9 | // 10 | // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details 11 | // about supported directives. 12 | // 13 | //= require rails-ujs 14 | //= require turbolinks 15 | //= require_tree . 16 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.scss: -------------------------------------------------------------------------------- 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 | * You can change require_directory back to require_tree when we're done with the temp notifications page 12 | */ 13 | 14 | /*Global Vars*/ 15 | $box-shadow-color: #ccc; 16 | $link-color: #f00; 17 | 18 | .alert-box { 19 | text-align: center; 20 | border: 1px dotted #f00; 21 | /*background: #9cf;*/ 22 | padding: 8px; 23 | } 24 | 25 | @import 'notifications'; 26 | @import 'policies'; 27 | -------------------------------------------------------------------------------- /app/assets/stylesheets/crawls.css.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the Crawl controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/notifications.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the notifications controller here. 2 | // You can use Sass (SCSS) here: http://sass-lang.com/ 3 | body { 4 | margin: 0; 5 | padding: 0; 6 | 7 | font-family: helvetica, sans-serif; 8 | font-size: 16px; 9 | } 10 | 11 | .clear { 12 | clear: both; 13 | } 14 | 15 | a { 16 | text-decoration: none; 17 | color: $link-color; 18 | } 19 | 20 | a:hover { 21 | text-decoration: underline; 22 | } 23 | 24 | h1 { 25 | font-size: 18px; 26 | } 27 | 28 | h2 { 29 | font-size: 16px; 30 | } 31 | 32 | h3 { 33 | font-size: 14px; 34 | } 35 | 36 | h4 { 37 | font-size: 12px; 38 | } 39 | 40 | h1,h2,h3,h4,h5 { 41 | padding: 0; 42 | margin: 0; 43 | } 44 | 45 | img { 46 | border: 0; 47 | } 48 | 49 | #page { 50 | } 51 | 52 | #header { 53 | margin: 0; 54 | 55 | height: 100px; 56 | width: 100%; 57 | 58 | background: #039; 59 | border-bottom: 8px solid #09f; 60 | color: #fff; 61 | } 62 | 63 | #innerheader { 64 | margin: 0 auto; 65 | 66 | position: relative; 67 | height: 100px; 68 | width: 765px; 69 | } 70 | 71 | #header h1#logo { 72 | padding: 0; 73 | margin: 0; 74 | 75 | position: absolute; 76 | bottom: 20px; 77 | left: 0; 78 | 79 | height: 53px; 80 | width: 180px; 81 | 82 | background-image: image-url('logo.png'); 83 | text-indent: -5000px; 84 | } 85 | 86 | #header #tagline { 87 | left: 200px; /* align left-border with #content left-border */ 88 | position: absolute; 89 | bottom: 16px; 90 | 91 | height: 34px; 92 | width: 296px; 93 | 94 | background-image: image-url('tagline.png'); 95 | text-indent: -5000px; 96 | } 97 | 98 | #header #user { 99 | position: absolute; 100 | right: 0; 101 | top: 0; 102 | font-size: 12px; 103 | } 104 | 105 | #header #projectof { 106 | position: absolute; 107 | right: 0; 108 | bottom: 16px; 109 | font-size: 12px; 110 | 111 | } 112 | 113 | #eff_logo { 114 | width:53px; 115 | height:35px; 116 | background-image: image-url('eff_logo.png'); 117 | text-indent: -5000px; 118 | float:left; 119 | margin-left:12px; 120 | margin-top:4px; 121 | } 122 | 123 | #tosdr_logo { 124 | width:32px; 125 | height:32px; 126 | background-image: image-url('tosdr_logo.png'); 127 | text-indent: -5000px; 128 | float:left; 129 | margin-left:12px; 130 | margin-top:4px; 131 | } 132 | 133 | #header #user a { 134 | color: #fff; 135 | } 136 | 137 | #crumbs { 138 | width: 765px; 139 | margin: 8px auto 0 auto; 140 | font-size: 12px; 141 | } 142 | 143 | #crumbs a { 144 | color: #000; 145 | text-decoration: underline; 146 | } 147 | 148 | #explanation { 149 | padding-bottom: 2em; 150 | font-size: 20px; 151 | line-height: 28px; 152 | } 153 | 154 | #mission { 155 | width: 749px; /* (765px desired visual width) minus (16px horiz padding) */ 156 | margin: 8px auto; 157 | } 158 | 159 | #mission a { 160 | color: #039; 161 | } 162 | 163 | #mission img { 164 | float: left; 165 | width: 164px; /* center over sidebar blocks, mirror 8px padding */ 166 | margin-right: 24px; /* line up the #missiontext left-border with the #content left-border */ 167 | background: #fff; 168 | } 169 | 170 | #mission #missiontext { 171 | float: left; 172 | font-size: 14px; 173 | } 174 | 175 | #mission #missiontext h2 { 176 | font-size: 18px; 177 | color: #039; 178 | } 179 | 180 | #mission #missiontext #missionsub { 181 | font-size: 11px; 182 | overflow: hidden; 183 | width: 550px; 184 | height: 1em; 185 | } 186 | 187 | #body { 188 | width: 765px; 189 | margin: 16px auto; 190 | } 191 | 192 | .block { 193 | background: #9cf; 194 | padding: 8px; 195 | font-size: 12px; 196 | } 197 | 198 | .block h3 { 199 | color: #039; 200 | font-size: 14px; 201 | } 202 | 203 | .block h4 { 204 | font-size: 11px; 205 | } 206 | 207 | .block a { 208 | color: #000; 209 | } 210 | .block ul { 211 | list-style: none; 212 | padding: 0; 213 | } 214 | .block ul li{ 215 | margin-bottom: .5em; 216 | } 217 | 218 | #sidebar { 219 | width: 180px; 220 | float: left; 221 | margin-right: 20px; 222 | } 223 | 224 | #sidebar .block { 225 | width: 164px; /* (180px desired visual width) minus (16px horiz padding) */ 226 | margin-bottom: 20px; 227 | } 228 | 229 | #content { 230 | padding: 8px 0px 0px 0px; 231 | float: left; 232 | margin-bottom: 36px; 233 | } 234 | 235 | #content.narrow { 236 | width: 565px; 237 | } 238 | 239 | #content.wide { 240 | width: 765px; 241 | } 242 | 243 | .timeline, 244 | .org, 245 | .policy { 246 | font-size: 14px; 247 | clear: left; 248 | margin-bottom: 24px; 249 | } 250 | 251 | .timeline img { 252 | float: left; 253 | margin-right: 12px; 254 | } 255 | 256 | .org img, 257 | .policy img { 258 | float: left; 259 | margin-right: 12px; 260 | } 261 | 262 | .timeline .info { 263 | float: left; 264 | width: 480px; 265 | } 266 | 267 | .org .info { 268 | float: left; 269 | color: #333; 270 | } 271 | 272 | .policy.first .url a { 273 | color: #000; 274 | } 275 | 276 | .policy .info { 277 | float: left; 278 | width: 530px; 279 | } 280 | 281 | .org .info h3 a, 282 | .policy .info h3 a { 283 | color: $link-color; 284 | font-weight: bold; 285 | } 286 | 287 | .timeline .info .when, 288 | .policy .info .links, 289 | .policy .info .source { 290 | color: #666; 291 | font-size: 11px; 292 | } 293 | 294 | #footer { 295 | margin: 0; 296 | 297 | width: 100%; 298 | height: 50px; 299 | 300 | background: #039; 301 | color: #fff; 302 | 303 | clear: left; 304 | } 305 | 306 | #innerfooter { 307 | width: 765px; 308 | height: 50px; 309 | margin: 0 auto; 310 | position: relative; 311 | } 312 | 313 | #footer h5{ 314 | position: absolute; 315 | top: 6px; 316 | left: 50px; 317 | 318 | width: 306px; 319 | height: 30px; 320 | background-image: image-url('footer.png'); 321 | 322 | text-indent: -5000px; 323 | } 324 | 325 | #footer #tosdr_footer { 326 | position: absolute; 327 | top: 8px; 328 | left: 400px; 329 | 330 | width: 190px; 331 | height: 32px; 332 | background-image: image-url('tosdr-logo-32-w.png'); 333 | 334 | text-indent: -5000px; 335 | } 336 | 337 | /* ABOUT page */ 338 | 339 | #about h2 { 340 | font-size: 20px; 341 | } 342 | 343 | #about h3 { 344 | padding-top: 1em; 345 | } 346 | 347 | #about p { 348 | font-size: 14px; 349 | } 350 | 351 | /* DEBUGGERY */ 352 | 353 | #debug { 354 | 355 | } 356 | 357 | #debug .query { 358 | margin: 1em; 359 | } 360 | 361 | /* REPORT page */ 362 | 363 | #report table a { 364 | color: #000; 365 | } 366 | 367 | #report table tr.error { 368 | background: #faa; 369 | } 370 | 371 | /* MISC */ 372 | 373 | #error { 374 | background: #faa; 375 | padding: 8px; 376 | width: 549px; 377 | margin: 0 auto 16px auto; 378 | } 379 | -------------------------------------------------------------------------------- /app/assets/stylesheets/policies.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the Policies controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | 5 | #version_info { 6 | margin-bottom: 20px; 7 | h1 { 8 | font-size: 18px; 9 | } 10 | } 11 | 12 | #policy_text { 13 | border: 1px solid $box-shadow-color; 14 | box-shadow: 3px 3px $box-shadow-color; 15 | padding: 5px; 16 | margin-right: 5px; 17 | } 18 | -------------------------------------------------------------------------------- /app/assets/stylesheets/sessions.css.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the Sessions controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/sites.css.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the Sites controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/users.css.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the Users controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/versions.css.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the Versions controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | protect_from_forgery with: :exception 3 | end 4 | -------------------------------------------------------------------------------- /app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /app/controllers/crawls_controller.rb: -------------------------------------------------------------------------------- 1 | class CrawlsController < ApplicationController 2 | def show 3 | @crawl = Crawl.find(params[:id]) 4 | end 5 | end -------------------------------------------------------------------------------- /app/controllers/notifications_controller.rb: -------------------------------------------------------------------------------- 1 | class NotificationsController < ApplicationController 2 | def index 3 | @notifications = Notification.paginate(:page => params[:page],per_page: 10) 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/controllers/policies_controller.rb: -------------------------------------------------------------------------------- 1 | class PoliciesController < ApplicationController 2 | def index 3 | @policies = Policy.paginate(:page => params[:page]) 4 | end 5 | 6 | def show 7 | @policy = Policy.includes(:sites, :versions).find(params[:id]) 8 | @policy_presenter = PolicyPresenter.new(@policy) 9 | @sites = @policy.sites.paginate(page:params[:site_page], per_page: 10) 10 | #@versions = @policy.versions.limit(10) 11 | # @version = params[:diff_id].nil? ? @policy.versions.first : @policy.versions.find(params[:diff_id]) 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /app/controllers/sessions_controller.rb: -------------------------------------------------------------------------------- 1 | class SessionsController < ApplicationController 2 | def new 3 | end 4 | 5 | def create 6 | user = User.find_by_email(params[:email].downcase) 7 | if user && user.authenticate(params[:password]) 8 | helpers.sign_in user 9 | flash[:success] = "Successfully signed in!" 10 | redirect_to user_path(user) 11 | else 12 | flash.now[:error] = "Sorry, the email and password combination was invalid." 13 | render :new 14 | end 15 | end 16 | 17 | def destroy 18 | session[:user_id] = nil 19 | flash[:success] = "You have successfully signed out!" 20 | redirect_to root_path 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /app/controllers/sites_controller.rb: -------------------------------------------------------------------------------- 1 | class SitesController < ApplicationController 2 | def index 3 | @sites = Site.reviewed.paginate(:page => params[:page]) 4 | end 5 | 6 | def show 7 | @site = Site.includes(:policies).find(params[:id]) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/controllers/users_controller.rb: -------------------------------------------------------------------------------- 1 | class UsersController < ApplicationController 2 | before_action :signed_in_user, only: [:edit, :update] 3 | before_action :correct_user, only: [:edit, :update] 4 | 5 | def new 6 | @user = User.new 7 | end 8 | 9 | def create 10 | @user = User.new(params[:user]) 11 | if @user.save 12 | flash[:success] = "Welcome to TOSBack!" 13 | helpers.sign_in @user 14 | redirect_to user_path(@user) 15 | else 16 | render :new 17 | end 18 | end 19 | 20 | def edit 21 | @user = User.find(params[:id]) 22 | end 23 | 24 | def update 25 | @user = User.find(params[:id]) 26 | if @user.update_attributes(params[:user]) 27 | flash[:success] = "Successfully saved!" 28 | redirect_to user_path(@user) 29 | else 30 | render :edit 31 | end 32 | end 33 | 34 | def show 35 | @user = User.find(params[:id]) 36 | end 37 | end 38 | 39 | private 40 | 41 | def signed_in_user 42 | redirect_to signin_path, notice: "Please sign in." unless helpers.signed_in? 43 | end 44 | 45 | def correct_user 46 | redirect_to root_path unless helpers.current_user == User.find(params[:id]) 47 | end 48 | -------------------------------------------------------------------------------- /app/controllers/versions_controller.rb: -------------------------------------------------------------------------------- 1 | class VersionsController < ApplicationController 2 | before_action :get_policy 3 | 4 | def index 5 | @versions = @policy.versions.paginate(page: params[:page]) 6 | end 7 | 8 | def show 9 | @version = @policy.versions.find(params[:id]) 10 | @versions = @policy.versions.limit(10) 11 | 12 | #if params[:diff].nil? 13 | #@content = @version.display_policy.html_safe 14 | #elsif params[:diff] == "current" 15 | #@content = @version.changes_with_current 16 | #elsif params[:diff] == "previous" 17 | #@content = @version.changes_from_previous 18 | #end 19 | 20 | #respond_with(@version, only: [:text, :created_at]) 21 | end 22 | 23 | private 24 | 25 | def get_policy 26 | @policy = Policy.includes(:versions).find(params[:policy_id]) 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/sessions_helper.rb: -------------------------------------------------------------------------------- 1 | module SessionsHelper 2 | 3 | def current_user 4 | @current_user ||= User.find(session[:user_id]) if session[:user_id] 5 | end 6 | 7 | def sign_in(user) 8 | session[:user_id] = user.id 9 | end 10 | 11 | def signed_in? 12 | current_user != nil 13 | end 14 | 15 | end 16 | -------------------------------------------------------------------------------- /app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | class ApplicationJob < ActiveJob::Base 2 | end 3 | -------------------------------------------------------------------------------- /app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | class ApplicationMailer < ActionMailer::Base 2 | default from: 'from@example.com' 3 | layout 'mailer' 4 | end 5 | -------------------------------------------------------------------------------- /app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | self.abstract_class = true 3 | end 4 | -------------------------------------------------------------------------------- /app/models/commitment.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: commitments 4 | # 5 | # id :integer not null, primary key 6 | # policy_id :integer 7 | # site_id :integer 8 | # created_at :datetime not null 9 | # updated_at :datetime not null 10 | # 11 | 12 | class Commitment < ApplicationRecord 13 | belongs_to :site, inverse_of: :commitments 14 | belongs_to :policy, inverse_of: :commitments 15 | #attr_protected :policy_id, :site_id 16 | 17 | #commented out next line due to problems validating new policies 18 | #validates :policy_id, :site_id, presence: true 19 | validates :policy_id, uniqueness: {:scope => :site_id, :message => "This site already has this policy"} 20 | end 21 | -------------------------------------------------------------------------------- /app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/app/models/concerns/.keep -------------------------------------------------------------------------------- /app/models/crawl.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: crawls 4 | # 5 | # id :integer not null, primary key 6 | # policy_id :integer 7 | # full_page :text 8 | # created_at :datetime not null 9 | # updated_at :datetime not null 10 | # crawled_policy :text 11 | # 12 | 13 | class Crawl < ApplicationRecord 14 | belongs_to :policy 15 | 16 | #attr_accessible :crawled_policy, :full_page 17 | 18 | validates :policy_id, presence: true, uniqueness: true 19 | end 20 | -------------------------------------------------------------------------------- /app/models/notification.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: notifications 4 | # 5 | # id :integer not null, primary key 6 | # site :string 7 | # name :string 8 | # created_at :datetime not null 9 | # updated_at :datetime not null 10 | # diff_url :string 11 | # 12 | 13 | class Notification < ApplicationRecord 14 | #attr_accessible :name, :site, :diff_url 15 | 16 | default_scope { order("created_at DESC") } 17 | 18 | validates :name, :site, :diff_url, presence: true 19 | 20 | def image_from_sitename 21 | path = "logo/" + site.gsub(/\.([^.]*)$/,".png") 22 | return ActionController::Base.helpers.asset_digest_path(path).nil? ? 'logo/default.png' : path 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /app/models/policy.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: policies 4 | # 5 | # id :integer not null, primary key 6 | # name :string 7 | # url :string 8 | # lang :string 9 | # created_at :datetime not null 10 | # updated_at :datetime not null 11 | # needs_revision :boolean 12 | # xpath :string 13 | # obsolete :boolean 14 | # 15 | 16 | class Policy < ApplicationRecord 17 | has_many :commitments, inverse_of: :policy 18 | has_many :sites, through: :commitments 19 | has_many :subscriptions 20 | has_many :users, through: :subscriptions 21 | has_many :versions, inverse_of: :policy 22 | has_one :crawl 23 | 24 | validates :name, :url, presence: true 25 | validates :xpath, uniqueness: { scope: :url } 26 | 27 | def self.reviewed 28 | where(needs_revision: false) 29 | end 30 | 31 | #TODO null object pattern instead of string to make behavior consistent 32 | #TODO delete unused method? 33 | def current_version 34 | versions.first || "Sorry, there don't seem to be any versions of this policy stored!" 35 | end 36 | 37 | #after_create do |p| 38 | #p.update_current_version 39 | #end 40 | 41 | #before_update do |p| 42 | #p.update_current_version if p.needs_new_version? 43 | #end 44 | 45 | protected 46 | 47 | #def update_current_version 48 | #unless versions.empty? 49 | #old_version = versions.first # because of default scope order of versions 50 | #old_version.update_attributes(previous_policy: detail_was) 51 | #end 52 | 53 | #versions.create(previous_policy: "Current Version") 54 | #end 55 | 56 | #def needs_new_version? 57 | #detail_changed? 58 | #end 59 | end 60 | -------------------------------------------------------------------------------- /app/models/site.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: sites 4 | # 5 | # id :integer not null, primary key 6 | # name :string 7 | # created_at :datetime not null 8 | # updated_at :datetime not null 9 | # 10 | 11 | class Site < ApplicationRecord 12 | has_many :commitments, inverse_of: :site 13 | has_many :policies, through: :commitments 14 | #attr_accessible :name 15 | 16 | validates :name, presence: true, uniqueness: {case_sensitive: false} 17 | 18 | def self.reviewed 19 | joins(:policies).merge(Policy.reviewed).distinct 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /app/models/subscription.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: subscriptions 4 | # 5 | # id :integer not null, primary key 6 | # policy_id :integer 7 | # user_id :integer 8 | # created_at :datetime not null 9 | # updated_at :datetime not null 10 | # 11 | 12 | class Subscription < ApplicationRecord 13 | belongs_to :policy 14 | belongs_to :user 15 | 16 | validates :policy_id, :user_id, presence: true 17 | validates :policy_id, uniqueness: { :scope => :user_id, :message => "Already subscribed to this policy" } 18 | 19 | #attr_protected :policy_id, :user_id 20 | end 21 | -------------------------------------------------------------------------------- /app/models/user.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: users 4 | # 5 | # id :integer not null, primary key 6 | # name :string 7 | # email :string 8 | # admin :boolean 9 | # created_at :datetime not null 10 | # updated_at :datetime not null 11 | # password_digest :string 12 | # 13 | 14 | class User < ApplicationRecord 15 | has_many :subscriptions 16 | has_many :policies, through: :subscriptions 17 | 18 | has_secure_password 19 | 20 | #attr_accessible :email, :name, :password, :password_confirmation 21 | 22 | #VALID_EMAIL_REGEX = /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i 23 | VALID_EMAIL_REGEX = /\A([\w+\-].?)+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i 24 | 25 | validates :name, :email, presence: true, length: {maximum: 50} 26 | validates :email, presence: true, format: {with: VALID_EMAIL_REGEX}, uniqueness: {case_sensitive: false} 27 | validates :password, presence: true, length: {minimum: 8} 28 | 29 | before_save { |user| user.email = email.downcase } 30 | 31 | end 32 | -------------------------------------------------------------------------------- /app/models/version.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: versions 4 | # 5 | # id :integer not null, primary key 6 | # policy_id :integer 7 | # text :text 8 | # created_at :datetime not null 9 | # updated_at :datetime not null 10 | # full_page :text 11 | # former_site :string 12 | # diff_url :string 13 | # 14 | 15 | class Version < ApplicationRecord 16 | belongs_to :policy, inverse_of: :versions 17 | 18 | default_scope { order("versions.created_at DESC") } 19 | 20 | #attr_accessible :previous_policy, :full_page 21 | 22 | validates :policy, :text, presence: true 23 | 24 | protected 25 | 26 | #TODO both methods not needed? 27 | def previous_version 28 | policy.versions.where("created_at < ?", created_at).first #returns nil when no previous versions 29 | end 30 | 31 | def current_version? 32 | self == policy.versions.first 33 | end 34 | 35 | end 36 | -------------------------------------------------------------------------------- /app/presenters/policy_presenter.rb: -------------------------------------------------------------------------------- 1 | class PolicyPresenter 2 | 3 | def initialize(policy) 4 | @policy = policy 5 | @versions_empty = @policy.versions.empty? 6 | end 7 | 8 | def name 9 | @policy.name 10 | end 11 | 12 | def versions 13 | @policy.versions.limit(10) 14 | end 15 | 16 | def default_version_text 17 | @versions_empty ? "Sorry, there are no versions of this policy stored yet!" : @policy.versions.first.text.html_safe 18 | end 19 | 20 | def default_date 21 | @versions_empty ? " " : "
28 | TOSBack began as a collaboration between the EFF, 29 | the Internet Society, 30 | and ToS;DR, and is now maintained by 31 | ToS;DR in friendly collaboration with the 32 | French Ambassador for digital affairs. 33 | Every day, we check the Terms and Policies 34 | of many online services to see if any of them have changed. 35 | The project is currently in beta as we are working on some improvements to ensure greater 36 | reliability and coverage. For now, please double check any results with the website 37 | operator before relying on them for important legal or journalistic purposes. 38 | See https://github.com/tosdr/tosback3 or 39 | these instructions 40 | for our latest data. 41 |
42 |Choose a version to see the archived copy and compare what's been changed!
16 | 17 |You may have mistyped the address or the page may have moved.
63 |If you are the application owner check the logs for more information.
65 |Maybe you tried to change something you didn't have access to.
63 |If you are the application owner check the logs for more information.
65 |If you are the application owner check the logs for more information.
64 |trust.us cares about your privacy
" } 18 | policy 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /spec/factories/notifications.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: notifications 4 | # 5 | # id :integer not null, primary key 6 | # site :string 7 | # name :string 8 | # created_at :datetime not null 9 | # updated_at :datetime not null 10 | # diff_url :string 11 | # 12 | 13 | # Read about factories at https://github.com/thoughtbot/factory_girl 14 | 15 | FactoryBot.define do 16 | factory :notification do 17 | site { "example.com" } 18 | name { "Privacy Policy" } 19 | diff_url { "http://example.com/some_diff_url" } 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /spec/factories/policies.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: policies 4 | # 5 | # id :integer not null, primary key 6 | # name :string 7 | # url :string 8 | # lang :string 9 | # created_at :datetime not null 10 | # updated_at :datetime not null 11 | # needs_revision :boolean 12 | # xpath :string 13 | # obsolete :boolean 14 | # 15 | 16 | # Read about factories at https://github.com/thoughtbot/factory_girl 17 | 18 | FactoryBot.define do 19 | factory :policy do 20 | sequence(:name) { |n| "Privacy Policy #{n}" } 21 | sequence(:url) { |n| "http://www.example#{n}.com/privacy" } 22 | lang { "EN" } 23 | needs_revision { true } 24 | xpath { "//div[@id='content']" } 25 | obsolete { false } 26 | transient do 27 | sites_count { 1 } 28 | versions_count { 0 } 29 | end 30 | 31 | factory :policy_with_sites_and_versions do 32 | transient do 33 | sites_count { 5 } 34 | versions_count { 5 } 35 | end 36 | end #with_sites 37 | 38 | after(:build) do |policy, eval| 39 | eval.sites_count.times { policy.sites << FactoryBot.create(:site) } 40 | eval.versions_count.times do |n| 41 | policy.versions << FactoryBot.create(:version, policy: policy, text: "Policy info!
" * (n + 1), created_at: (n+1).days.ago) 42 | end 43 | end 44 | 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /spec/factories/sites.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: sites 4 | # 5 | # id :integer not null, primary key 6 | # name :string 7 | # created_at :datetime not null 8 | # updated_at :datetime not null 9 | # 10 | 11 | FactoryBot.define do 12 | factory :site do 13 | sequence(:name) {|n| "example#{n}.com"} 14 | 15 | factory :site_with_policies do 16 | # policies_count is declared as an ignored attribute and available in 17 | # attributes on the factory, as well as the callback via the evaluator 18 | transient do 19 | policies_count { 5 } 20 | end 21 | 22 | after(:create) do |site, evaluator| 23 | evaluator.policies_count.times { site.policies << FactoryBot.create(:policy, needs_revision: false)} 24 | end 25 | 26 | # This allows us to do: 27 | # 28 | # FactoryBot.create(:site).policies.length # 0 29 | # FactoryBot.create(:site_with_policies).policies.length # 5 30 | # FactoryBot.create(:site_with_policies, policies_count: 15).policies.length # 15 31 | 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /spec/factories/subscriptions.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: subscriptions 4 | # 5 | # id :integer not null, primary key 6 | # policy_id :integer 7 | # user_id :integer 8 | # created_at :datetime not null 9 | # updated_at :datetime not null 10 | # 11 | 12 | # Read about factories at https://github.com/thoughtbot/factory_girl 13 | 14 | FactoryBot.define do 15 | factory :subscription do 16 | policy_id { 1 } 17 | user_id { 1 } 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/factories/users.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: users 4 | # 5 | # id :integer not null, primary key 6 | # name :string 7 | # email :string 8 | # admin :boolean 9 | # created_at :datetime not null 10 | # updated_at :datetime not null 11 | # password_digest :string 12 | # 13 | 14 | # Read about factories at https://github.com/thoughtbot/factory_girl 15 | 16 | FactoryBot.define do 17 | factory :user do 18 | name { "John Doe" } 19 | sequence(:email) {|n| "john.doe#{n}@ihopethisisafakedomain.com" } 20 | password { "dictionary" } 21 | password_confirmation { "dictionary" } 22 | # admin false 23 | 24 | factory :admin do 25 | admin { true } 26 | end #admin 27 | 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /spec/factories/versions.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: versions 4 | # 5 | # id :integer not null, primary key 6 | # policy_id :integer 7 | # text :text 8 | # created_at :datetime not null 9 | # updated_at :datetime not null 10 | # full_page :text 11 | # former_site :string 12 | # diff_url :string 13 | # 14 | 15 | # Read about factories at https://github.com/thoughtbot/factory_girl 16 | 17 | FactoryBot.define do 18 | factory :version do 19 | policy 20 | sequence(:text) { |n| "Crawl Data #{n}" } 21 | former_site { nil } 22 | diff_url { "https://github.com/tosdr/tosback2/commit/bc68a13b5be09be76cf08d62be874d1ca899fa37?diff=split" } 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /spec/features/authorization_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe "Authorization", disabled: true do 4 | subject { page } 5 | 6 | describe "editing user info" do 7 | before do 8 | @user = FactoryBot.create(:user) 9 | end 10 | 11 | context "when not signed in" do 12 | before { visit edit_user_path(@user) } 13 | 14 | it "redirects to signin_path" do 15 | current_path.should eq(signin_path) 16 | end 17 | 18 | it { should have_selector('div.alert.alert-notice', text: 'sign in') } 19 | end #when not signed in 20 | 21 | context "when signed in" do 22 | before { sign_in @user } 23 | 24 | context "visiting current_user's account settings" do 25 | before do 26 | visit edit_user_path(@user) 27 | end 28 | 29 | it { should have_selector('h2', text: "Edit") } 30 | end 31 | 32 | context "doing something unauthorized" do 33 | before { @otheruser = FactoryBot.create(:user, email: "other@other.com") } 34 | 35 | context "visiting another user's settings" do 36 | before { visit edit_user_path(@otheruser) } 37 | 38 | it "redirects to root" do 39 | current_path.should eq(root_path) 40 | end 41 | end # visiting another user's settings 42 | 43 | context "trying to update the wrong user" do 44 | let(:user_attrs) { FactoryBot.attributes_for(:user, email: "test@test.com").except!(:admin) } # Can't mass-assign protected attributes: admin 45 | xit "doesn't update via 'put' request" do 46 | #unsupported syntax?: 47 | #expect{ put "/users/#{@otheruser.id}", id: @otheruser.id, user: user_attrs }.to_not change{@otheruser.reload.email}.from("other@other.com").to("test@test.com") 48 | 49 | #long version: 50 | put "/users/#{@otheruser.id}", id: @otheruser.id, user: user_attrs 51 | @otheruser.reload 52 | @otheruser.email.should_not eq(user_attrs[:email]) 53 | end 54 | 55 | end #trying to update the wrong user 56 | 57 | end # doing something unauthorized 58 | end # when signed in 59 | end # in UsersController 60 | end 61 | -------------------------------------------------------------------------------- /spec/features/crawl_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe "CrawlController", disabled: true do 4 | before { @crawl = FactoryBot.create(:crawl) } 5 | subject { page } 6 | 7 | context "as an admin" do 8 | before(:each) do 9 | @admin = FactoryBot.create(:admin) 10 | sign_in @admin 11 | end 12 | 13 | describe "visiting crawl #show" do 14 | before { visit crawl_path(@crawl) } 15 | 16 | xit { has_selector?('h2', text: @crawl.policy.name) } 17 | xit { has_selector?('div#crawled_policy', text: @crawl.crawled_policy) } 18 | xit { has_button?('Approve!') } 19 | xit { has_button?('Skip!') } 20 | xit { has_button?('Revise...') } 21 | 22 | end #visiting crawl #show 23 | end #as an admin 24 | 25 | context "as regular user" do 26 | before(:each) do 27 | @user = FactoryBot.create(:user) 28 | sign_in @user 29 | end 30 | 31 | describe "visiting crawl_path" do 32 | before { visit crawl_path(@crawl) } 33 | 34 | xit "redirects to policy path" do 35 | current_path.should eq(policy_path(@crawl.policy)) 36 | end 37 | end #visiting crawl_path 38 | 39 | end #as user 40 | end # CrawlController 41 | -------------------------------------------------------------------------------- /spec/features/policies_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe "PoliciesController", disabled: true do 4 | 5 | subject { page } 6 | 7 | describe "visiting #index", disabled: true do 8 | before(:all) { 31.times { FactoryBot.create(:policy) } } 9 | after(:all) do 10 | Policy.delete_all 11 | Site.delete_all 12 | Commitment.delete_all 13 | end 14 | 15 | before(:each) do 16 | visit policies_path 17 | end 18 | 19 | it "contains first policy" do 20 | page.should have_selector('li', text: Policy.first.name) 21 | end 22 | 23 | it "doesn't contain the 31st policy (pagination)" do 24 | page.should_not have_selector('li', text: Policy.last.name) 25 | end 26 | 27 | it "lists page numbers" do 28 | page.should have_selector('div.pagination') 29 | end 30 | 31 | it "links to policy_path(:id)" do 32 | page.should have_link(Policy.first.name, href: policy_path(Policy.first)) 33 | end 34 | end # policies_path#index 35 | 36 | describe "visiting #show" do 37 | 38 | context "when policy has many sites and versions" do 39 | before do 40 | @policy = FactoryBot.create(:policy_with_sites_and_versions, sites_count: 14, versions_count: 17) 41 | visit policy_path(@policy) 42 | end 43 | # let(:changes) { Nokogiri::HTML(page.source).xpath("//div[@id='policy_changes']/node()").to_s } 44 | 45 | it { should have_selector('h1', text: @policy.name) } 46 | it { should have_selector('h3', text: @policy.versions.first.created_at.to_date.strftime("%B %-d, %Y")) } 47 | 48 | it "paginates site links to the first 10" do 49 | @policy.sites.each_with_index do |site, i| 50 | if i<10 51 | page.should have_link(site.name, href: site_path(site.id)) 52 | page.should have_selector('li', text: site.name) 53 | else 54 | page.should_not have_link(site.name, href: site_path(site.id)) 55 | page.should_not have_selector('li', text: site.name) 56 | end 57 | end 58 | end 59 | 60 | it "paginates version links to the first 10" do 61 | @policy.versions.each_with_index do |version, i| 62 | if i<10 63 | page.should have_link(version.created_at.to_date.strftime("%B %-d, %Y")) 64 | else 65 | page.should_not have_link(version.created_at.to_date.strftime("%B %-d, %Y")) 66 | end 67 | end 68 | end 69 | 70 | it { should have_selector('div.pagination') } 71 | it { should have_selector('div#policy_text') } 72 | 73 | context "clicking a link to a different version" do 74 | before { click_link(@policy.versions[5].created_at.to_date.strftime("%B %-d, %Y")) } 75 | 76 | it { should have_selector('h3', text: @policy.versions[5].created_at.to_date.strftime("%B %-d, %Y")) } 77 | end 78 | end #many 79 | 80 | context "when policy has no versions" do 81 | before do 82 | @policy = FactoryGirl.create(:policy_with_sites_and_versions, sites_count: 1, versions_count: 0) 83 | visit policy_path(@policy) 84 | end 85 | 86 | it { should have_content("Sorry") } 87 | end #no versions 88 | 89 | end #visiting #show 90 | end 91 | -------------------------------------------------------------------------------- /spec/features/sessions_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe "SessionsController", disabled: true do 4 | subject { page } 5 | 6 | describe "visiting signin_path" do 7 | before { visit signin_path } 8 | 9 | it { should have_selector('h2', text: "Sign in") } 10 | it { should have_link('sign up', href: signup_path) } 11 | it { should have_button("Sign in") } 12 | 13 | describe "signing in" do 14 | before (:all) { @user = FactoryBot.create(:user) } 15 | after (:all) { @user.destroy } 16 | 17 | context "when login info is invalid" do 18 | before { click_button "Sign in"} 19 | 20 | it { should have_selector('div.alert.alert-error', text: 'invalid') } 21 | 22 | it "url remains at /signin instead of /sessions" do 23 | current_path.should eq(signin_path) 24 | end 25 | 26 | context "when visiting another page after a login failure" do 27 | before { click_link "sign up"} 28 | 29 | it { should_not have_selector('div.alert.alert-error', text: 'invalid') } 30 | end 31 | 32 | end #invalid login info 33 | 34 | context "when login info is valid" do 35 | before do 36 | sign_in @user 37 | end 38 | 39 | it { should have_selector('div.alert.alert-success', text: 'signed in') } 40 | it { should have_selector('h2', text: @user.name) } 41 | 42 | it_behaves_like "it has signed in header links" do # in partials_spec.rb 43 | let(:user_id) {@user.id} 44 | end 45 | 46 | context "clicking sign out" do 47 | before { click_link "Sign out" } 48 | 49 | it { should have_selector('div.alert.alert-success', text: 'signed out') } 50 | it_behaves_like "it has signed out header links" 51 | end 52 | 53 | end #valid login 54 | end #signing in 55 | 56 | end #visiting signin_path 57 | end 58 | -------------------------------------------------------------------------------- /spec/features/site_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe "Site Controller" do 4 | describe "site_path#index" do 5 | before(:all) do 6 | 32.times { FactoryBot.create(:site_with_policies, policies_count: 1) } 7 | Site.all[10].policies.first.update_attribute(:needs_revision, true) 8 | end 9 | let!(:unreviewed) { Site.all[10] } 10 | after(:all) do 11 | Site.delete_all 12 | Policy.delete_all 13 | Commitment.delete_all 14 | end 15 | 16 | before(:each) do 17 | visit sites_path 18 | end 19 | 20 | it "contains first site" do 21 | expect(page).to have_selector('li', text: Site.first.name) 22 | end 23 | 24 | it "doesn't contain the unreviewed site (scope)" do 25 | expect(page).not_to have_selector('li', text: unreviewed.name) 26 | end 27 | 28 | it "lists page numbers" do 29 | expect(page).to have_selector('div.pagination') 30 | end 31 | 32 | it "links to site_path(:id)" do 33 | expect(page).to have_link(Site.first.name, href: site_path(Site.first)) 34 | end 35 | end #index 36 | 37 | describe "site_path(:id)" do 38 | before(:each) do 39 | visit site_path(site) 40 | end 41 | 42 | context "when site does not have policies" do 43 | let!(:site) { FactoryBot.create(:site) } 44 | 45 | it "contains the site's capitalized title" do 46 | expect(page).to have_selector("h1", text: site.name.capitalize ) 47 | end 48 | 49 | it "displays message in place of policies" 50 | 51 | it "displays a link to add a policy" 52 | 53 | end # doesn't have policies 54 | 55 | context "when the site has policies" do 56 | let!(:site) { FactoryBot.create(:site_with_policies) } 57 | 58 | it "lists the site's policies" do 59 | site.policies.each do |policy| 60 | expect(page).to have_selector("li", text: policy.name) 61 | end 62 | end 63 | 64 | specify "policy names are links to policy pages" do 65 | expect(page).to have_link(site.policies.first.name, href: policy_path(site.policies.first)) 66 | end 67 | 68 | end # has policies 69 | end #show 70 | end 71 | -------------------------------------------------------------------------------- /spec/features/users_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe "UsersController", disabled: true do 4 | subject { page } 5 | 6 | describe "visiting signup_path" do 7 | before { visit signup_path } 8 | 9 | it { should have_field("user_name") } 10 | it { should have_field("user_email") } 11 | it { should have_field("user_password") } 12 | it { should have_field("user_password_confirmation") } 13 | it { should have_button("Create") } 14 | 15 | describe "signing up" do 16 | before do 17 | @user = FactoryBot.build(:user) 18 | fill_in "user_name", with: @user.name 19 | fill_in "user_email", with: @user.email 20 | fill_in "user_password", with: @user.password 21 | end 22 | 23 | context "with valid info" do 24 | before do 25 | fill_in "user_password_confirmation", with: @user.password_confirmation 26 | click_button "Create" 27 | end 28 | 29 | it { should have_selector('div.alert.alert-success', text: 'Welcome') } 30 | 31 | it_behaves_like "it has signed in header links" do 32 | let(:user_id) { User.last.id } 33 | end 34 | end 35 | 36 | context "with invalid user info" do 37 | before do 38 | fill_in "user_password_confirmation", with: @user.password_confirmation.upcase 39 | click_button "Create" 40 | end 41 | 42 | it { should have_selector('div.alert.alert-error', text: 'error') } 43 | end #with invalid info 44 | end #signing up 45 | end #visiting signup_path 46 | 47 | describe "editing account info" do 48 | before (:each) do 49 | @user = FactoryBot.create(:user) 50 | sign_in @user 51 | visit edit_user_path(@user) 52 | end 53 | 54 | context "with valid information" do 55 | let(:new_name) { "New Name" } 56 | let(:new_email) { "new@example.com" } 57 | before do 58 | fill_in "user_name", with: new_name 59 | fill_in "user_email", with: new_email 60 | fill_in "user_password", with: @user.password 61 | fill_in "user_password_confirmation", with: @user.password 62 | click_button "Save" 63 | end 64 | 65 | it { should have_selector('div.alert.alert-success', text: 'saved') } 66 | specify { @user.reload.name.should == new_name } 67 | specify { @user.reload.email.should == new_email } 68 | 69 | end # with valid info 70 | 71 | context "with invalid information" do 72 | before { click_button "Save" } 73 | 74 | it { should have_selector('div.alert.alert-error', text: 'error') } 75 | end #with invalid information 76 | end #editing account 77 | 78 | end 79 | -------------------------------------------------------------------------------- /spec/features/versions_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe "VersionsController", disabled: true do 4 | 5 | subject { page } 6 | 7 | describe "visiting versions#index" do 8 | before(:each) { @policy = FactoryBot.create(:policy_with_sites_and_versions, sites_count: 14, versions_count: 32) } 9 | before { visit policy_versions_path(@policy) } 10 | 11 | it "doesn't contain the 32nd version (pagination)" do 12 | page.should_not have_selector('li', text: @policy.versions.last.created_at.to_date.to_formatted_s(:long).squish ) 13 | #squish out those extra spaces 14 | end 15 | 16 | it { should have_link("Back to current policy...", href: policy_path(@policy)) } 17 | 18 | #TODO shared example for pagination links 19 | it "lists page numbers" do 20 | page.should have_selector('div.pagination') 21 | end 22 | 23 | end 24 | 25 | describe "visiting versions#show" do 26 | 27 | context "when policy has many sites and versions" do 28 | before(:each) { @policy = FactoryBot.create(:policy_with_sites_and_versions, sites_count: 14, versions_count: 32) } 29 | before { @version = @policy.versions[2] } 30 | before { visit policy_version_path(@policy,@version) } 31 | 32 | it { should have_selector('h1', text: @policy.name) } 33 | it { should have_selector('h3', text: @version.created_at.to_date.strftime("%B %-d, %Y")) } 34 | 35 | it { should have_selector('div#previous_text') } 36 | 37 | context "clicking a link to a different version" do 38 | before { click_link(@policy.versions[5].created_at.to_date.strftime("%B %-d, %Y")) } 39 | 40 | it { should have_selector('h3', text: @policy.versions[5].created_at.to_date.strftime("%B %-d, %Y")) } 41 | end 42 | end #many 43 | 44 | end #visiting #show 45 | end 46 | -------------------------------------------------------------------------------- /spec/models/commitment_spec.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: commitments 4 | # 5 | # id :integer not null, primary key 6 | # policy_id :integer 7 | # site_id :integer 8 | # created_at :datetime not null 9 | # updated_at :datetime not null 10 | # 11 | 12 | require 'spec_helper' 13 | 14 | RSpec.describe Commitment do 15 | let(:commitment) { FactoryBot.build(:commitment) } 16 | 17 | it "has a valid factory" do 18 | expect(commitment).to be_valid 19 | end 20 | 21 | it 'responds to site' do 22 | expect(commitment).to respond_to(:site) 23 | end 24 | 25 | it 'responds to policy' do 26 | expect(commitment).to respond_to(:policy) 27 | end 28 | 29 | describe "#validates" do 30 | it "is invalid without site_id" do 31 | commitment.site_id = nil 32 | expect(commitment).not_to be_valid 33 | end 34 | 35 | it "is invalid without policy_id" do 36 | commitment.policy_id = nil 37 | expect(commitment).not_to be_valid 38 | end 39 | 40 | #don't think these are really needed: 41 | context "when row exists in database", disabled: true do 42 | let!(:eg) { FactoryBot.create(:commitment) } 43 | 44 | it "is is invalid if the site and policy ids are both duplicates" do 45 | expect(commitment).not_to be_valid 46 | end 47 | 48 | it "is valid if site id is unique and policy id exists" do 49 | commitment.site_id = 2 50 | expect(commitment).to be_valid 51 | end 52 | 53 | it "is valid if policy id is unique and site id exists" do 54 | commitment.policy_id = 2 55 | expect(commitment).to be_valid 56 | end 57 | end 58 | end #validates 59 | end 60 | -------------------------------------------------------------------------------- /spec/models/crawl_spec.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: crawls 4 | # 5 | # id :integer not null, primary key 6 | # policy_id :integer 7 | # full_page :text 8 | # created_at :datetime not null 9 | # updated_at :datetime not null 10 | # crawled_policy :text 11 | # 12 | 13 | require 'spec_helper' 14 | 15 | RSpec.describe Crawl do 16 | let(:crawl) { FactoryBot.create(:crawl) } 17 | #before(:each) { @crawl = FactoryBot.create(:crawl) } 18 | 19 | it 'responds to policy' do 20 | expect(crawl).to respond_to(:policy) 21 | end 22 | 23 | it "has a valid factory" do 24 | expect(crawl).to be_valid 25 | end 26 | 27 | it "is invalid without a policy_id" do 28 | crawl.policy_id = nil 29 | expect(crawl).not_to be_valid 30 | end 31 | 32 | context "when crawl exists already" do 33 | let(:dup) { FactoryBot.build(:crawl, policy_id: crawl.policy_id) } 34 | #before(:each) { @dup = FactoryBot.build(:crawl, policy_id: @crawl.policy_id) } 35 | 36 | it "is invalid with a duplicate policy_id" do 37 | expect(dup).not_to be_valid 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /spec/models/notification_spec.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: notifications 4 | # 5 | # id :integer not null, primary key 6 | # site :string 7 | # name :string 8 | # created_at :datetime not null 9 | # updated_at :datetime not null 10 | # diff_url :string 11 | # 12 | 13 | require 'spec_helper' 14 | 15 | RSpec.describe Notification, type: :model do 16 | let(:notification) { FactoryBot.build(:notification) } 17 | 18 | it "has a valid factory" do 19 | expect(notification).to be_valid 20 | end 21 | 22 | describe "image_from_sitename" do 23 | it "returns logo when asset exists" do 24 | notification.site = "facebook.com" 25 | expect(notification.image_from_sitename).to eq("logo/facebook.png") 26 | end 27 | 28 | it "returns a default logo when asset is missing" do 29 | notification.site = "madeupsite.com" 30 | expect(notification.image_from_sitename).to eq("logo/default.png") 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /spec/models/policy_spec.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: policies 4 | # 5 | # id :integer not null, primary key 6 | # name :string 7 | # url :string 8 | # lang :string 9 | # created_at :datetime not null 10 | # updated_at :datetime not null 11 | # needs_revision :boolean 12 | # xpath :string 13 | # obsolete :boolean 14 | # 15 | 16 | require 'spec_helper' 17 | 18 | RSpec.describe Policy do 19 | let(:policy) { FactoryBot.create(:policy) } 20 | 21 | it "has a valid factory" do 22 | expect(policy).to be_valid 23 | end 24 | 25 | #before(:each) { @policy = FactoryBot.create(:policy) } 26 | 27 | it 'responds to sites' do 28 | expect(policy).to respond_to(:sites) 29 | end 30 | it 'responds to commitments' do 31 | expect(policy).to respond_to(:commitments) 32 | end 33 | it 'responds to versions' do 34 | expect(policy).to respond_to(:versions) 35 | end 36 | it 'responds to crawl' do 37 | expect(policy).to respond_to(:crawl) 38 | end 39 | it 'responds to subscriptions' do 40 | expect(policy).to respond_to(:subscriptions) 41 | end 42 | it 'responds to users' do 43 | expect(policy).to respond_to(:users) 44 | end 45 | 46 | describe "#validates presence" do 47 | it "is invalid without a name" do 48 | expect(FactoryBot.build(:policy, name: nil)).not_to be_valid 49 | end 50 | it "is invalid without a url" do 51 | expect(FactoryBot.build(:policy, url: nil)).not_to be_valid 52 | end 53 | end # validates 54 | 55 | describe "creating duplicate policy" do 56 | let(:dup) { FactoryBot.build(:policy, url: policy.url, xpath: policy.xpath) } 57 | 58 | it "is invalid if it has duplicate url and xpath" do 59 | expect(dup).not_to be_valid 60 | end 61 | it "is valid if url is duplicate but xpath is different" do 62 | dup.xpath = "//div[@id='xxxxx']" 63 | expect(dup).to be_valid 64 | end 65 | it "is valid if xpath is duplicate but url is different" do 66 | dup.url = "http://ex.com/terms" 67 | expect(dup).to be_valid 68 | end 69 | end # when policy is dup 70 | 71 | #TODO remove when sure we no longer want policy to create versions on update 72 | describe "updating a policy", disabled: true do 73 | before (:all) { @modified = FactoryBot.create(:policy) } 74 | after (:all) {Policy.destroy_all} 75 | 76 | context "when policy name is changed" do 77 | before (:all) { @modified.name = "some new policy name"} 78 | 79 | it "needs_new_version? returns false" do 80 | @modified.send(:needs_new_version?).should eq(false) 81 | end 82 | 83 | it "doesn't add a new version when saved" do 84 | expect{@modified.save}.to_not change{@modified.versions.count}.by(1) 85 | end 86 | end 87 | 88 | context "when policy detail is changed" do 89 | before (:all) { @modified.detail = "new crawl" } 90 | 91 | it "needs_new_version? returns true" do 92 | @modified.send(:needs_new_version?).should eq(true) 93 | end 94 | 95 | context "and policy detail is saved" do 96 | before (:all) do 97 | @old_crawl = @modified.detail_was 98 | @modified.save 99 | end 100 | 101 | it "isn't dirty" do 102 | @modified.changed?.should eq(false) 103 | end 104 | 105 | it "adds a new version" do 106 | @modified.versions.count.should eq(2) 107 | end 108 | 109 | specify "second to last version equals old policy detail" do 110 | @modified.versions[-2].previous_policy.should eq(@old_crawl) 111 | end 112 | 113 | specify "most recent version represents current version" do 114 | @modified.versions.last.previous_policy.should eq("Current Version") 115 | end 116 | 117 | end # policy is saved 118 | end 119 | 120 | end # updating a policy 121 | 122 | describe ".reviewed" do 123 | let!(:policies) { FactoryBot.create_list(:policy, 3) } 124 | it "scopes to policies with needs_revision == nil" do 125 | policies[0].needs_revision = false 126 | policies[0].save 127 | expect(Policy.reviewed.count).to eq(1) 128 | end 129 | end 130 | end 131 | -------------------------------------------------------------------------------- /spec/models/site_spec.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: sites 4 | # 5 | # id :integer not null, primary key 6 | # name :string 7 | # created_at :datetime not null 8 | # updated_at :datetime not null 9 | # 10 | 11 | require 'spec_helper' 12 | 13 | RSpec.describe Site do 14 | let(:site) { FactoryBot.create(:site) } 15 | 16 | it "has a valid factory" do 17 | expect(site).to be_valid 18 | end 19 | 20 | it "is invalid without a url" do 21 | expect(FactoryBot.build(:site, name: nil)).not_to be_valid 22 | end 23 | 24 | it 'responds to policies' do 25 | expect(site).to respond_to(:policies) 26 | end 27 | it 'responds to commitments' do 28 | expect(site).to respond_to(:commitments) 29 | end 30 | 31 | describe "#validates uniqueness" do 32 | let(:dup_site) { FactoryBot.build(:site, name: site.name) } 33 | 34 | it "is invalid without a unique url" do 35 | expect(dup_site).not_to be_valid 36 | end 37 | 38 | it "is invalid if url isn't unique (case insensitive)" do 39 | dup_site.name.upcase! 40 | expect(dup_site).not_to be_valid 41 | end 42 | end #validates uniqueness 43 | 44 | describe ".reviewed" do 45 | let!(:site) { FactoryBot.create(:site_with_policies) } 46 | it "scopes to sites with reviewed policies" do 47 | site.policies[0].needs_revision = true 48 | site.policies[0].save 49 | # Would be 6 before save due to policy factory creating sites too 50 | expect(Site.reviewed.count).to eq(5) 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /spec/models/subscription_spec.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: subscriptions 4 | # 5 | # id :integer not null, primary key 6 | # policy_id :integer 7 | # user_id :integer 8 | # created_at :datetime not null 9 | # updated_at :datetime not null 10 | # 11 | 12 | require 'spec_helper' 13 | 14 | RSpec.describe Subscription, disabled: true do 15 | it "has a valid factory" do 16 | FactoryBot.build(:subscription).should be_valid 17 | end 18 | 19 | it { should respond_to(:policy) } 20 | it { should respond_to(:user) } 21 | 22 | describe "#validates" do 23 | it "is invalid without user_id" do 24 | FactoryBot.build(:subscription, user_id: nil).should_not be_valid 25 | end 26 | 27 | it "is invalid without policy_id" do 28 | FactoryBot.build(:subscription, policy_id: nil).should_not be_valid 29 | end 30 | 31 | context "when row exists in database" do 32 | before (:all) { @existing_subscription = FactoryBot.create(:subscription) } 33 | after (:all) { Subscription.destroy_all } 34 | 35 | it "is is invalid if the user and policy ids are both duplicates" do 36 | FactoryBot.build(:subscription, user_id: @existing_subscription.user_id, policy_id: @existing_subscription.policy_id).should_not be_valid 37 | end 38 | 39 | it "is valid if user_id is unique and policy_id exists" do 40 | FactoryBot.build(:subscription, policy_id: @existing_subscription.policy_id, user_id: 25).should be_valid 41 | end 42 | 43 | it "is valid if policy_id is unique and user_id exists" do 44 | FactoryBot.build(:subscription, user_id: @existing_subscription.user_id, policy_id: 25).should be_valid 45 | end 46 | end 47 | end #validates 48 | 49 | end 50 | -------------------------------------------------------------------------------- /spec/models/user_spec.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: users 4 | # 5 | # id :integer not null, primary key 6 | # name :string 7 | # email :string 8 | # admin :boolean 9 | # created_at :datetime not null 10 | # updated_at :datetime not null 11 | # password_digest :string 12 | # 13 | 14 | require 'spec_helper' 15 | 16 | RSpec.describe User, disabled: true do 17 | it "has a valid factory" do 18 | FactoryBot.build(:user).should be_valid 19 | end 20 | 21 | it { should respond_to(:subscriptions) } 22 | it { should respond_to(:policies) } 23 | it { should respond_to(:password_digest) } 24 | it { should respond_to(:authenticate) } 25 | 26 | describe "#validates" do 27 | it "is invalid without a name" do 28 | FactoryBot.build(:user, name: nil).should_not be_valid 29 | end 30 | 31 | it "is invalid with a name longer than 50 chars" do 32 | FactoryBot.build(:user, name: ("a" * 51)).should_not be_valid 33 | end 34 | 35 | it "is invalid without a email address" do 36 | FactoryBot.build(:user, email: " ").should_not be_valid 37 | end 38 | 39 | it "is invalid without a password" do 40 | FactoryBot.build(:user, password: " ", password_confirmation: " ").should_not be_valid 41 | end 42 | 43 | it "is invalid if the password confirmation doesn't match" do 44 | FactoryBot.build(:user, password_confirmation: " ").should_not be_valid 45 | end 46 | 47 | it "is invalid if the password is too short" do 48 | FactoryBot.build(:user, password: ("e" * 5), password_confirmation: ("e" * 5)).should_not be_valid 49 | end 50 | 51 | specify "malformed email addresses are invalid" do 52 | %w[user@foo,com user_at_foo.org example.user@foo. foo@foo@bar.com foo@bar+baz.com].each do |invalid_email| 53 | FactoryBot.build(:user, email: invalid_email).should_not be_valid 54 | end 55 | end 56 | 57 | specify "proper email addresses are valid" do 58 | %w[user@foo.COM A_US-ER@f.b.org frst.lst@foo.jp a+b@baz.cn].each do |valid_email| 59 | FactoryBot.build(:user, email: valid_email).should be_valid 60 | end 61 | end 62 | 63 | context "when user already exists in database, new user" do 64 | before(:all) { @existing = FactoryBot.create(:user) } 65 | after(:all) { User.destroy_all } 66 | 67 | it "is valid with the same name" do 68 | FactoryBot.build(:user, name: @existing.name).should be_valid 69 | end 70 | 71 | it "is invalid with the same email" do 72 | FactoryBot.build(:user, email: @existing.email).should_not be_valid 73 | end 74 | end 75 | end # validates 76 | 77 | describe "saving a user" do 78 | before { @user = FactoryBot.create(:user, email: "ALLCAPS@CAPSLOCK.COM") } 79 | 80 | specify "email should be downcased before saving" do 81 | @user.email.should eq("allcaps@capslock.com") 82 | end 83 | end 84 | end 85 | -------------------------------------------------------------------------------- /spec/models/version_spec.rb: -------------------------------------------------------------------------------- 1 | # == Schema Information 2 | # 3 | # Table name: versions 4 | # 5 | # id :integer not null, primary key 6 | # policy_id :integer 7 | # text :text 8 | # created_at :datetime not null 9 | # updated_at :datetime not null 10 | # full_page :text 11 | # former_site :string 12 | # diff_url :string 13 | # 14 | 15 | require 'spec_helper' 16 | 17 | RSpec.describe Version do 18 | let(:version) { FactoryBot.build(:version) } 19 | 20 | it "has a valid factory" do 21 | expect(version).to be_valid 22 | end 23 | 24 | it 'responds to policy' do 25 | expect(version).to respond_to(:policy) 26 | end 27 | 28 | describe "#validates presence" do 29 | it "is invalid without a policy_id" do 30 | version.policy_id = nil 31 | expect(version).not_to be_valid 32 | end 33 | 34 | it "is invalid without text" do 35 | version.text = " " 36 | expect(version).not_to be_valid 37 | end 38 | end #validates presence 39 | 40 | describe "default order" do 41 | let!(:older_version) { FactoryBot.create(:version, created_at: 1.day.ago) } 42 | let!(:newer_version) { FactoryBot.create(:version, policy: older_version.policy) } 43 | let!(:oldest_version) { FactoryBot.create(:version, created_at: 3.day.ago, policy: older_version.policy) } 44 | 45 | it "uses created_at to determine newest version" do 46 | expect(Version.first).to eq(newer_version) 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /spec/rails_helper.rb: -------------------------------------------------------------------------------- 1 | # This file is copied to spec/ when you run 'rails generate rspec:install' 2 | require 'spec_helper' 3 | ENV['RAILS_ENV'] ||= 'test' 4 | require File.expand_path('../../config/environment', __FILE__) 5 | # Prevent database truncation if the environment is production 6 | abort("The Rails environment is running in production mode!") if Rails.env.production? 7 | require 'rspec/rails' 8 | # Add additional requires below this line. Rails is not loaded until this point! 9 | 10 | # Requires supporting ruby files with custom matchers and macros, etc, in 11 | # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are 12 | # run as spec files by default. This means that files in spec/support that end 13 | # in _spec.rb will both be required and run as specs, causing the specs to be 14 | # run twice. It is recommended that you do not name files matching this glob to 15 | # end with _spec.rb. You can configure this pattern with the --pattern 16 | # option on the command line or in ~/.rspec, .rspec or `.rspec-local`. 17 | # 18 | # The following line is provided for convenience purposes. It has the downside 19 | # of increasing the boot-up time by auto-requiring all files in the support 20 | # directory. Alternatively, in the individual `*_spec.rb` files, manually 21 | # require only the support files necessary. 22 | # 23 | Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } 24 | 25 | # Checks for pending migrations and applies them before tests are run. 26 | # If you are not using ActiveRecord, you can remove this line. 27 | ActiveRecord::Migration.maintain_test_schema! 28 | 29 | RSpec.configure do |config| 30 | config.filter_run_excluding :disabled => true 31 | # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures 32 | config.fixture_path = "#{::Rails.root}/spec/fixtures" 33 | 34 | # If you're not using ActiveRecord, or you'd prefer not to run each of your 35 | # examples within a transaction, remove the following line or assign false 36 | # instead of true. 37 | config.use_transactional_fixtures = true 38 | 39 | # RSpec Rails can automatically mix in different behaviours to your tests 40 | # based on their file location, for example enabling you to call `get` and 41 | # `post` in specs under `spec/controllers`. 42 | # 43 | # You can disable this behaviour by removing the line below, and instead 44 | # explicitly tag your specs with their type, e.g.: 45 | # 46 | # RSpec.describe UsersController, :type => :controller do 47 | # # ... 48 | # end 49 | # 50 | # The different available types are documented in the features, such as in 51 | # https://relishapp.com/rspec/rspec-rails/docs 52 | config.infer_spec_type_from_file_location! 53 | 54 | # Filter lines from Rails gems in backtraces. 55 | config.filter_rails_from_backtrace! 56 | # arbitrary gems may also be filtered via: 57 | # config.filter_gems_from_backtrace("gem name") 58 | end 59 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # This file was generated by the `rails generate rspec:install` command. Conventionally, all 2 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. 3 | # The generated `.rspec` file contains `--require spec_helper` which will cause 4 | # this file to always be loaded, without a need to explicitly require it in any 5 | # files. 6 | # 7 | # Given that it is always loaded, you are encouraged to keep this file as 8 | # light-weight as possible. Requiring heavyweight dependencies from this file 9 | # will add to the boot time of your test suite on EVERY test run, even for an 10 | # individual file that may not need all of that loaded. Instead, consider making 11 | # a separate helper file that requires the additional dependencies and performs 12 | # the additional setup, and require it from the spec files that actually need 13 | # it. 14 | # 15 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration 16 | RSpec.configure do |config| 17 | # rspec-expectations config goes here. You can use an alternate 18 | # assertion/expectation library such as wrong or the stdlib/minitest 19 | # assertions if you prefer. 20 | config.expect_with :rspec do |expectations| 21 | # This option will default to `true` in RSpec 4. It makes the `description` 22 | # and `failure_message` of custom matchers include text for helper methods 23 | # defined using `chain`, e.g.: 24 | # be_bigger_than(2).and_smaller_than(4).description 25 | # # => "be bigger than 2 and smaller than 4" 26 | # ...rather than: 27 | # # => "be bigger than 2" 28 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true 29 | end 30 | 31 | # rspec-mocks config goes here. You can use an alternate test double 32 | # library (such as bogus or mocha) by changing the `mock_with` option here. 33 | config.mock_with :rspec do |mocks| 34 | # Prevents you from mocking or stubbing a method that does not exist on 35 | # a real object. This is generally recommended, and will default to 36 | # `true` in RSpec 4. 37 | mocks.verify_partial_doubles = true 38 | end 39 | 40 | # This option will default to `:apply_to_host_groups` in RSpec 4 (and will 41 | # have no way to turn it off -- the option exists only for backwards 42 | # compatibility in RSpec 3). It causes shared context metadata to be 43 | # inherited by the metadata hash of host groups and examples, rather than 44 | # triggering implicit auto-inclusion in groups with matching metadata. 45 | config.shared_context_metadata_behavior = :apply_to_host_groups 46 | 47 | # The settings below are suggested to provide a good initial experience 48 | # with RSpec, but feel free to customize to your heart's content. 49 | =begin 50 | # This allows you to limit a spec run to individual examples or groups 51 | # you care about by tagging them with `:focus` metadata. When nothing 52 | # is tagged with `:focus`, all examples get run. RSpec also provides 53 | # aliases for `it`, `describe`, and `context` that include `:focus` 54 | # metadata: `fit`, `fdescribe` and `fcontext`, respectively. 55 | config.filter_run_when_matching :focus 56 | 57 | # Allows RSpec to persist some state between runs in order to support 58 | # the `--only-failures` and `--next-failure` CLI options. We recommend 59 | # you configure your source control system to ignore this file. 60 | config.example_status_persistence_file_path = "spec/examples.txt" 61 | 62 | # Limits the available syntax to the non-monkey patched syntax that is 63 | # recommended. For more details, see: 64 | # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ 65 | # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ 66 | # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode 67 | config.disable_monkey_patching! 68 | 69 | # Many RSpec users commonly either run the entire suite or an individual 70 | # file, and it's useful to allow more verbose output when running an 71 | # individual spec file. 72 | if config.files_to_run.one? 73 | # Use the documentation formatter for detailed output, 74 | # unless a formatter has already been configured 75 | # (e.g. via a command-line flag). 76 | config.default_formatter = "doc" 77 | end 78 | 79 | # Print the 10 slowest examples and example groups at the 80 | # end of the spec run, to help surface which specs are running 81 | # particularly slow. 82 | config.profile_examples = 10 83 | 84 | # Run specs in random order to surface order dependencies. If you find an 85 | # order dependency and want to debug it, you can fix the order by providing 86 | # the seed, which is printed after each run. 87 | # --seed 1234 88 | config.order = :random 89 | 90 | # Seed global randomization in this process using the `--seed` CLI option. 91 | # Setting this allows you to use `--seed` to deterministically reproduce 92 | # test failures related to randomization by passing the same `--seed` value 93 | # as the one that triggered the failure. 94 | Kernel.srand config.seed 95 | =end 96 | end 97 | -------------------------------------------------------------------------------- /spec/support/partials_shared.rb: -------------------------------------------------------------------------------- 1 | RSpec.shared_examples "it has signed in header links" do 2 | it { should have_link('Sign out', href: signout_path) } 3 | it { should have_link('Subscriptions', href: user_path(user_id))} 4 | it { should have_link('Account', href: edit_user_path(user_id))} 5 | it { should_not have_link('Sign in', href: signin_path) } 6 | end 7 | 8 | RSpec.shared_examples "it has signed out header links" do 9 | it { should_not have_link('Sign out', href: signout_path) } 10 | it { should have_link('Sign in', href: signin_path) } 11 | end 12 | -------------------------------------------------------------------------------- /spec/support/utilities.rb: -------------------------------------------------------------------------------- 1 | def sign_in(user) 2 | visit signin_path 3 | fill_in "login_email", with: user.email.upcase 4 | fill_in "login_password", with: user.password 5 | click_button "Sign in" 6 | # using capybara 7 | end 8 | -------------------------------------------------------------------------------- /tmp/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/tmp/.keep -------------------------------------------------------------------------------- /unused/custom.css.scss: -------------------------------------------------------------------------------- 1 | //Was used with the bootstrap-sass gem: 2 | //@import 'bootstrap'; 3 | 4 | html { 5 | overflow-y: scroll; 6 | } 7 | 8 | body { 9 | padding-top: 60px; 10 | } 11 | 12 | section { 13 | overflow: auto; 14 | } 15 | 16 | textarea { 17 | resize: vertical; 18 | } 19 | 20 | .center { 21 | text-align: center; 22 | } 23 | 24 | .center h1 { 25 | margin-bottom: 10px; 26 | } 27 | 28 | .diff { 29 | background:#fff; 30 | overflow:auto; 31 | list-style:none; 32 | margin:0; 33 | padding:0; 34 | display:inline; 35 | width:100%; 36 | text-decoration:none; 37 | } 38 | 39 | ins.diff {background:#dfd; color:#080} 40 | del.diff {background:#fee; color:#b00} 41 | 42 | .diff :hover{background:#ffc} 43 | .diff strong{font-weight:normal;background:#fcc;} 44 | .diff strong{font-weight:normal;background:#9f9;} 45 | 46 | /*Diff styles*/ 47 | /* from diffy - with (very) minor edits */ 48 | /*.diff{overflow:auto;}*/ 49 | /*.diff ul{background:#fff;overflow:auto;[>font-size:13px;<]list-style:none;margin:0;padding:0;display:table;width:100%;}*/ 50 | /*.diff del, .diff ins{display:block;text-decoration:none;}*/ 51 | /*.diff li{padding:0; display:table-row;margin: 0;height:1em;}*/ 52 | /*.diff li.ins{background:#dfd; color:#080}*/ 53 | /*.diff li.del{background:#fee; color:#b00}*/ 54 | /*.diff li:hover{background:#ffc}*/ 55 | /*[> try 'whitespace:pre;' if you don't want lines to wrap <]*/ 56 | /*.diff del, .diff ins, .diff span{white-space:pre-wrap;}*/ 57 | /*.diff del strong{font-weight:normal;background:#fcc;}*/ 58 | /*.diff ins strong{font-weight:normal;background:#9f9;}*/ 59 | /*.diff li.diff-comment { display: none; }*/ 60 | /*.diff li.diff-block-info { background: none repeat scroll 0 0 gray; }*/ 61 | 62 | /*del.differ {*/ 63 | /*background-color: #f87a8a;*/ 64 | /*}*/ 65 | 66 | /*ins.differ {*/ 67 | /*background-color: #abfab5;*/ 68 | /*}*/ 69 | -------------------------------------------------------------------------------- /unused/diff_match_patch.js: -------------------------------------------------------------------------------- 1 | (function(){function diff_match_patch(){this.Diff_Timeout=1;this.Diff_EditCost=4;this.Match_Threshold=0.5;this.Match_Distance=1E3;this.Patch_DeleteThreshold=0.5;this.Patch_Margin=4;this.Match_MaxBits=32} 2 | diff_match_patch.prototype.diff_main=function(a,b,c,d){"undefined"==typeof d&&(d=0>=this.Diff_Timeout?Number.MAX_VALUE:(new Date).getTime()+1E3*this.Diff_Timeout);if(null==a||null==b)throw Error("Null input. (diff_main)");if(a==b)return a?[[0,a]]:[];"undefined"==typeof c&&(c=!0);var e=c,f=this.diff_commonPrefix(a,b);c=a.substring(0,f);a=a.substring(f);b=b.substring(f);var f=this.diff_commonSuffix(a,b),g=a.substring(a.length-f);a=a.substring(0,a.length-f);b=b.substring(0,b.length-f);a=this.diff_compute_(a, 3 | b,e,d);c&&a.unshift([0,c]);g&&a.push([0,g]);this.diff_cleanupMerge(a);return a}; 4 | diff_match_patch.prototype.diff_compute_=function(a,b,c,d){if(!a)return[[1,b]];if(!b)return[[-1,a]];var e=a.length>b.length?a:b,f=a.length>b.length?b:a,g=e.indexOf(f);return-1!=g?(c=[[1,e.substring(0,g)],[0,f],[1,e.substring(g+f.length)]],a.length>b.length&&(c[0][0]=c[2][0]=-1),c):1==f.length?[[-1,a],[1,b]]:(e=this.diff_halfMatch_(a,b))?(f=e[0],a=e[1],g=e[2],b=e[3],e=e[4],f=this.diff_main(f,g,c,d),c=this.diff_main(a,b,c,d),f.concat([[0,e]],c)):c&&100