├── .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 ? " " : "

ToSBack stored this version on #{@policy.versions.first.created_at.to_date.to_formatted_s(:long)}

".html_safe 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /app/views/layouts/_bsheader.html.erb: -------------------------------------------------------------------------------- 1 | 3 | 21 | -------------------------------------------------------------------------------- /app/views/layouts/_footer.html.erb: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /app/views/layouts/_header.html.erb: -------------------------------------------------------------------------------- 1 | 23 | 24 | -------------------------------------------------------------------------------- /app/views/layouts/_sidebar.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

3 | Organizations 4 |

5 |

(ToS;DR Reviews)

6 |
7 | 93 |
94 |
95 | -------------------------------------------------------------------------------- /app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <%= csrf_meta_tags %> 5 | TOSBack | The Terms-Of-Service Tracker 6 | <%= stylesheet_link_tag "application", :media => "all" %> 7 | <%= javascript_include_tag "application" %> 8 | 9 | 10 | 11 |
12 | 13 | <%= render 'layouts/header' %> 14 | 15 |
16 | 17 | <% if flash.any? %> 18 |
19 | <% flash.each do |key, value| %> 20 |
<%= value %>
21 | <% end %> 22 |
23 | <% end %> 24 | 25 |
26 |

TOSBack.org is Under Construction

27 |

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 |
43 | 44 | 51 | 52 |
53 | 54 | <%= yield %> 55 | 56 |
57 |
58 | 59 | <%= render 'layouts/footer' %> 60 | 61 |
62 | 63 | 64 | -------------------------------------------------------------------------------- /app/views/layouts/bsapplication.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <%= csrf_meta_tags %> 5 | TOSBack | The Terms-Of-Service Tracker <%= yield(:title) if content_for?(:title) %> 6 | <%= stylesheet_link_tag "application", :media => "all" %> 7 | <%= javascript_include_tag "application" %> 8 | <%= csrf_meta_tags %> 9 | 10 | 11 | <%= render 'layouts/header' %> 12 | 13 | <% if flash.any? %> 14 |
15 | <% flash.each do |key, value| %> 16 |
<%= value %>
17 | <% end %> 18 |
19 | <% end %> 20 | 21 |
22 | <%= yield %> 23 |
24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/views/layouts/mailer.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/views/layouts/mailer.text.erb: -------------------------------------------------------------------------------- 1 | <%= yield %> 2 | -------------------------------------------------------------------------------- /app/views/notifications/index.html.erb: -------------------------------------------------------------------------------- 1 |
2 | TOSBack keeps an eye on website policies.
3 | Every time one of them changes, you'll see an update here. 4 |
5 | <% @notifications.each do |n| %> 6 |
7 | <%= image_tag n.image_from_sitename, size:"32x32" %> 8 |
9 |

<%= n.site.capitalize %>

10 |
11 | TOSBack recorded a new version of the <%= n.name %>
12 | <%= link_to "View the changes on Github", n.diff_url %> 13 |
14 |
15 | <%= n.created_at.to_date.to_formatted_s(:long) %> 16 |
17 |
18 |
19 |
20 | <% end %> 21 | <%= will_paginate @notifications %> 22 | -------------------------------------------------------------------------------- /app/views/policies/index.html.erb: -------------------------------------------------------------------------------- 1 |

Policies

2 | <%= render 'shared/list_each_as_link', list_object: @policies, ul_class: "policies" %> 3 | 4 | <%= will_paginate @policies %> -------------------------------------------------------------------------------- /app/views/policies/show.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :sidebar do %> 2 |
3 |

4 | Belongs to: 5 |

6 |
7 | <%= render 'shared/list_each_as_link', list_object: @sites, ul_class: "sites" %> 8 |
9 | <%= will_paginate @sites, param_name: 'site_page' %> 10 | 11 |
12 |

View version from:

13 | 16 |

<%= link_to "View all versions...", policy_versions_path(@policy) %>

17 |
18 |
19 | <% end %> 20 | 21 | <%= content_tag :div, id: 'version_info', data: {current_version: @policy.versions.first.id} do %> 22 |

<%= @policy_presenter.name %>

23 | <%= @policy_presenter.default_date %> 24 | <% end %> 25 | 26 |
27 | <%= @policy_presenter.default_version_text %> 28 |
29 | -------------------------------------------------------------------------------- /app/views/sessions/new.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Sign in

4 | <%= form_tag signin_path do %> 5 | <%= label_tag :email %> 6 | <%= text_field_tag :email, params[:email], id: "login_email" %> 7 | 8 | <%= label_tag :password %> 9 | <%= password_field_tag :password, nil, id: "login_password" %> 10 | 11 | <%= submit_tag "Sign in", class: "btn btn-large" %> 12 | <% end %> 13 | 14 | ...or <%= link_to "sign up!", signup_path %> 15 |
16 |
-------------------------------------------------------------------------------- /app/views/shared/_errors.html.erb: -------------------------------------------------------------------------------- 1 | <% # Use for form errors! e.g., render 'shared/errors', error_object: @user %> 2 | <% if error_object.errors.any? %> 3 |
4 |
5 | The form contains <%= pluralize(error_object.errors.count, "error") %>. 6 | 11 |
12 |
13 | <% end %> -------------------------------------------------------------------------------- /app/views/shared/_list_each_as_link.html.erb: -------------------------------------------------------------------------------- 1 | <% # render 'shared/list_each_as_link', list_object: @whatevz, ul_class: "whatevz" %> 2 | -------------------------------------------------------------------------------- /app/views/sites/index.html.erb: -------------------------------------------------------------------------------- 1 |

Sites ToSBack is tracking:

2 | <%= render 'shared/list_each_as_link', list_object: @sites, ul_class: "sites" %> 3 | 4 | <%= will_paginate @sites %> 5 | -------------------------------------------------------------------------------- /app/views/sites/show.html.erb: -------------------------------------------------------------------------------- 1 |

Policies for <%= @site.name.capitalize %>:

2 | 3 | <% if @site.policies.any? %> 4 | 9 | <% end %> 10 | -------------------------------------------------------------------------------- /app/views/users/_user_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= f.label :name %> 2 | <%= f.text_field :name %> 3 | 4 | <%= f.label :email %> 5 | <%= f.text_field :email %> 6 | 7 | <%= f.label :password %> 8 | <%= f.password_field :password %> 9 | 10 | <%= f.label :password_confirmation, "Confirm Password" %> 11 | <%= f.password_field :password_confirmation %> -------------------------------------------------------------------------------- /app/views/users/edit.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

Edit your account:

3 | <%= render 'shared/errors', error_object: @user %> 4 | <%= form_for(@user) do |f| %> 5 | <%= render 'user_form', f: f %> 6 | <%= f.submit "Save changes", class: "btn btn-large" %> 7 | <% end %> 8 |
-------------------------------------------------------------------------------- /app/views/users/new.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

Sign up!

3 | <%= render 'shared/errors', error_object: @user %> 4 | <%= form_for(@user) do |f| %> 5 | <%= render 'user_form', f: f %> 6 | <%= f.submit "Create account", class: "btn btn-large" %> 7 | <% end %> 8 |
-------------------------------------------------------------------------------- /app/views/users/show.html.erb: -------------------------------------------------------------------------------- 1 |

Subscriptions for <%= @user.name %>:

-------------------------------------------------------------------------------- /app/views/versions/_version.html.erb: -------------------------------------------------------------------------------- 1 |
  • 2 | <%= link_to version.created_at.to_date.to_formatted_s(:long), policy_version_path(@policy, version.id), class: "version_link", id: "version_link_"+version.id.to_s %> 3 | <% if version.diff_url %> 4 | <%= link_to "(diff)", version.diff_url, class: "version_link", id: "version_diff_link_"+version.id.to_s %> 5 | <% end %> 6 |
  • 7 | -------------------------------------------------------------------------------- /app/views/versions/index.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :sidebar do %> 2 |
    3 |
    4 |

    View version from:

    5 | 9 |

    <%= link_to "Back to current policy...", policy_path(@policy) %>

    10 |
    11 |
    12 | <% end %> 13 | 14 |

    Here's the list of versions that we have archived for <%= @policy.name %>!

    15 |

    Choose a version to see the archived copy and compare what's been changed!

    16 | 17 | 20 | 21 | <%= will_paginate @versions %> 22 | -------------------------------------------------------------------------------- /app/views/versions/show.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :sidebar do %> 2 |
    3 |
    4 |

    View version from:

    5 | 8 |

    <%= link_to "View all versions...", policy_versions_path(@policy) %>

    9 |

    <%= link_to "Back to current policy...", policy_path(@policy) %>

    10 |
    11 |
    12 | <% end %> 13 | 14 | <%= content_tag :div, id: 'version_info', data: {current_version: @version.id} do %> 15 |

    <%= @policy.name %>

    16 |

    ToSBack stored this version on <%= @version.created_at.to_date.to_formatted_s(:long) %>

    17 | <% end %> 18 | 19 |
    20 | 21 |
    22 | <%= @version.text.html_safe %> 23 |
    24 | -------------------------------------------------------------------------------- /app/views/versions/show.js.erb: -------------------------------------------------------------------------------- 1 | $("#policy_text").html("<%= j @version.text.html_safe %>"); 2 | $("#policy_date").html("<%= j @version.created_at.to_date.to_formatted_s(:long) %>"); 3 | -------------------------------------------------------------------------------- /app/views/versions/show.json.erb: -------------------------------------------------------------------------------- 1 | <%= response = { 2 | created_at: @version.created_at.to_date.to_formatted_s(:long), 3 | text: @version.text.html_safe, 4 | id: @version.id 5 | } 6 | response.to_json.html_safe %> 7 | -------------------------------------------------------------------------------- /bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path('../spring', __FILE__) 4 | rescue LoadError => e 5 | raise unless e.message.include?('spring') 6 | end 7 | APP_PATH = File.expand_path('../config/application', __dir__) 8 | require_relative '../config/boot' 9 | require 'rails/commands' 10 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path('../spring', __FILE__) 4 | rescue LoadError => e 5 | raise unless e.message.include?('spring') 6 | end 7 | require_relative '../config/boot' 8 | require 'rake' 9 | Rake.application.run 10 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | require 'fileutils' 4 | include FileUtils 5 | 6 | # path to your application root. 7 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) 8 | 9 | def system!(*args) 10 | system(*args) || abort("\n== Command #{args} failed ==") 11 | end 12 | 13 | chdir APP_ROOT do 14 | # This script is a starting point to setup your application. 15 | # Add necessary setup steps to this file. 16 | 17 | puts '== Installing dependencies ==' 18 | system! 'gem install bundler --conservative' 19 | system('bundle check') || system!('bundle install') 20 | 21 | # Install JavaScript dependencies if using Yarn 22 | # system('bin/yarn') 23 | 24 | 25 | # puts "\n== Copying sample files ==" 26 | # unless File.exist?('config/database.yml') 27 | # cp 'config/database.yml.sample', 'config/database.yml' 28 | # end 29 | 30 | puts "\n== Preparing database ==" 31 | system! 'bin/rails db:setup' 32 | 33 | puts "\n== Removing old logs and tempfiles ==" 34 | system! 'bin/rails log:clear tmp:clear' 35 | 36 | puts "\n== Restarting application server ==" 37 | system! 'bin/rails restart' 38 | end 39 | -------------------------------------------------------------------------------- /bin/spring: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # This file loads spring without using Bundler, in order to be fast. 4 | # It gets overwritten when you run the `spring binstub` command. 5 | 6 | unless defined?(Spring) 7 | require 'rubygems' 8 | require 'bundler' 9 | 10 | lockfile = Bundler::LockfileParser.new(Bundler.default_lockfile.read) 11 | spring = lockfile.specs.detect { |spec| spec.name == "spring" } 12 | if spring 13 | Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path 14 | gem 'spring', spring.version 15 | require 'spring/binstub' 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /bin/update: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | require 'fileutils' 4 | include FileUtils 5 | 6 | # path to your application root. 7 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) 8 | 9 | def system!(*args) 10 | system(*args) || abort("\n== Command #{args} failed ==") 11 | end 12 | 13 | chdir APP_ROOT do 14 | # This script is a way to update your development environment automatically. 15 | # Add necessary update steps to this file. 16 | 17 | puts '== Installing dependencies ==' 18 | system! 'gem install bundler --conservative' 19 | system('bundle check') || system!('bundle install') 20 | 21 | puts "\n== Updating database ==" 22 | system! 'bin/rails db:migrate' 23 | 24 | puts "\n== Removing old logs and tempfiles ==" 25 | system! 'bin/rails log:clear tmp:clear' 26 | 27 | puts "\n== Restarting application server ==" 28 | system! 'bin/rails restart' 29 | end 30 | -------------------------------------------------------------------------------- /bin/yarn: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | VENDOR_PATH = File.expand_path('..', __dir__) 3 | Dir.chdir(VENDOR_PATH) do 4 | begin 5 | exec "yarnpkg #{ARGV.join(" ")}" 6 | rescue Errno::ENOENT 7 | $stderr.puts "Yarn executable was not detected in the system." 8 | $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" 9 | exit 1 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require_relative 'config/environment' 4 | 5 | run Rails.application 6 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative 'boot' 2 | 3 | #require 'rails/all' 4 | require "rails" 5 | # Pick the frameworks you want: 6 | require "active_model/railtie" 7 | require "active_job/railtie" 8 | require "active_record/railtie" 9 | require "action_controller/railtie" 10 | require "action_mailer/railtie" 11 | require "action_view/railtie" 12 | require "sprockets/railtie" 13 | #require "rails/test_unit/railtie" 14 | 15 | # Require the gems listed in Gemfile, including any gems 16 | # you've limited to :test, :development, or :production. 17 | Bundler.require(*Rails.groups) 18 | 19 | module Tb3 20 | class Application < Rails::Application 21 | # Initialize configuration defaults for originally generated Rails version. 22 | config.load_defaults 5.1 23 | 24 | #config.read_encrypted_secrets = true 25 | # Settings in config/environments/* take precedence over those specified here. 26 | # Application configuration should go into files in config/initializers 27 | # -- all .rb files in that directory are automatically loaded. 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 2 | 3 | require 'bundler/setup' # Set up gems listed in the Gemfile. 4 | -------------------------------------------------------------------------------- /config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: async 3 | 4 | test: 5 | adapter: async 6 | 7 | production: 8 | adapter: redis 9 | url: redis://localhost:6379/1 10 | channel_prefix: tb3_production 11 | -------------------------------------------------------------------------------- /config/database.yml.example: -------------------------------------------------------------------------------- 1 | # MySQL. Versions 4.1 and 5.0 are recommended. 2 | # 3 | # Install the MySQL driver: 4 | # gem install mysql2 5 | # 6 | # And be sure to use new-style password hashing: 7 | # http://dev.mysql.com/doc/refman/5.0/en/old-client.html 8 | development: 9 | adapter: mysql2 10 | encoding: utf8 11 | reconnect: false 12 | database: tosback_dev 13 | pool: 5 14 | username: 15 | password: 16 | hostname: localhost 17 | 18 | # Warning: The database defined as "test" will be erased and 19 | # re-generated from your development database when you run "rake". 20 | # Do not set this db to the same as development or production. 21 | test: 22 | adapter: mysql2 23 | encoding: utf8 24 | reconnect: false 25 | database: tosback_test 26 | pool: 5 27 | username: 28 | password: 29 | hostname: localhost 30 | 31 | production: 32 | adapter: mysql2 33 | encoding: utf8 34 | reconnect: false 35 | database: tosback 36 | pool: 5 37 | username: 38 | password: 39 | hostname: localhost 40 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative 'application' 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Do not eager load code on boot. 10 | config.eager_load = false 11 | 12 | # Show full error reports. 13 | config.consider_all_requests_local = true 14 | 15 | # Enable/disable caching. By default caching is disabled. 16 | if Rails.root.join('tmp/caching-dev.txt').exist? 17 | config.action_controller.perform_caching = true 18 | 19 | config.cache_store = :memory_store 20 | config.public_file_server.headers = { 21 | 'Cache-Control' => "public, max-age=#{2.days.seconds.to_i}" 22 | } 23 | else 24 | config.action_controller.perform_caching = false 25 | 26 | config.cache_store = :null_store 27 | end 28 | 29 | # Don't care if the mailer can't send. 30 | config.action_mailer.raise_delivery_errors = false 31 | 32 | config.action_mailer.perform_caching = false 33 | 34 | # Print deprecation notices to the Rails logger. 35 | config.active_support.deprecation = :log 36 | 37 | # Raise an error on page load if there are pending migrations. 38 | config.active_record.migration_error = :page_load 39 | 40 | # Debug mode disables concatenation and preprocessing of assets. 41 | # This option may cause significant delays in view rendering with a large 42 | # number of complex assets. 43 | config.assets.debug = true 44 | 45 | # Suppress logger output for asset requests. 46 | config.assets.quiet = true 47 | 48 | # Raises error for missing translations 49 | # config.action_view.raise_on_missing_translations = true 50 | 51 | # Use an evented file watcher to asynchronously detect changes in source code, 52 | # routes, locales, etc. This feature depends on the listen gem. 53 | config.file_watcher = ActiveSupport::EventedFileUpdateChecker 54 | end 55 | -------------------------------------------------------------------------------- /config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # Code is not reloaded between requests. 5 | config.cache_classes = true 6 | 7 | # Eager load code on boot. This eager loads most of Rails and 8 | # your application in memory, allowing both threaded web servers 9 | # and those relying on copy on write to perform better. 10 | # Rake tasks automatically ignore this option for performance. 11 | config.eager_load = true 12 | 13 | # Full error reports are disabled and caching is turned on. 14 | config.consider_all_requests_local = false 15 | config.action_controller.perform_caching = true 16 | 17 | # Attempt to read encrypted secrets from `config/secrets.yml.enc`. 18 | # Requires an encryption key in `ENV["RAILS_MASTER_KEY"]` or 19 | # `config/secrets.yml.key`. 20 | config.read_encrypted_secrets = true 21 | 22 | # Disable serving static files from the `/public` folder by default since 23 | # Apache or NGINX already handles this. 24 | config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? 25 | 26 | # Compress JavaScripts and CSS. 27 | config.assets.js_compressor = :uglifier 28 | # config.assets.css_compressor = :sass 29 | 30 | # Do not fallback to assets pipeline if a precompiled asset is missed. 31 | config.assets.compile = true 32 | 33 | # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb 34 | 35 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 36 | # config.action_controller.asset_host = 'http://assets.example.com' 37 | 38 | # Specifies the header that your server uses for sending files. 39 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache 40 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX 41 | 42 | # Mount Action Cable outside main process or domain 43 | # config.action_cable.mount_path = nil 44 | # config.action_cable.url = 'wss://example.com/cable' 45 | # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] 46 | 47 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 48 | # config.force_ssl = true 49 | 50 | # Use the lowest log level to ensure availability of diagnostic information 51 | # when problems arise. 52 | config.log_level = :debug 53 | 54 | # Prepend all log lines with the following tags. 55 | config.log_tags = [ :request_id ] 56 | 57 | # Use a different cache store in production. 58 | # config.cache_store = :mem_cache_store 59 | 60 | # Use a real queuing backend for Active Job (and separate queues per environment) 61 | # config.active_job.queue_adapter = :resque 62 | # config.active_job.queue_name_prefix = "tb3_#{Rails.env}" 63 | config.action_mailer.perform_caching = false 64 | 65 | # Ignore bad email addresses and do not raise email delivery errors. 66 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 67 | # config.action_mailer.raise_delivery_errors = false 68 | 69 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 70 | # the I18n.default_locale when a translation cannot be found). 71 | config.i18n.fallbacks = true 72 | 73 | # Send deprecation notices to registered listeners. 74 | config.active_support.deprecation = :notify 75 | 76 | # Use default logging formatter so that PID and timestamp are not suppressed. 77 | config.log_formatter = ::Logger::Formatter.new 78 | 79 | # Use a different logger for distributed setups. 80 | # require 'syslog/logger' 81 | # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') 82 | 83 | if ENV["RAILS_LOG_TO_STDOUT"].present? 84 | logger = ActiveSupport::Logger.new(STDOUT) 85 | logger.formatter = config.log_formatter 86 | config.logger = ActiveSupport::TaggedLogging.new(logger) 87 | end 88 | 89 | # Do not dump schema after migrations. 90 | config.active_record.dump_schema_after_migration = false 91 | end 92 | -------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Do not eager load code on boot. This avoids loading your whole application 11 | # just for the purpose of running a single test. If you are using a tool that 12 | # preloads Rails for running tests, you may have to set it to true. 13 | config.eager_load = false 14 | 15 | # Configure public file server for tests with Cache-Control for performance. 16 | config.public_file_server.enabled = true 17 | config.public_file_server.headers = { 18 | 'Cache-Control' => "public, max-age=#{1.hour.seconds.to_i}" 19 | } 20 | 21 | # Show full error reports and disable caching. 22 | config.consider_all_requests_local = true 23 | config.action_controller.perform_caching = false 24 | 25 | # Raise exceptions instead of rendering exception templates. 26 | config.action_dispatch.show_exceptions = false 27 | 28 | # Disable request forgery protection in test environment. 29 | config.action_controller.allow_forgery_protection = false 30 | config.action_mailer.perform_caching = false 31 | 32 | # Tell Action Mailer not to deliver emails to the real world. 33 | # The :test delivery method accumulates sent emails in the 34 | # ActionMailer::Base.deliveries array. 35 | config.action_mailer.delivery_method = :test 36 | 37 | # Print deprecation notices to the stderr. 38 | config.active_support.deprecation = :stderr 39 | 40 | # Raises error for missing translations 41 | # config.action_view.raise_on_missing_translations = true 42 | end 43 | -------------------------------------------------------------------------------- /config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # ActiveSupport::Reloader.to_prepare do 4 | # ApplicationController.renderer.defaults.merge!( 5 | # http_host: 'example.org', 6 | # https: false 7 | # ) 8 | # end 9 | -------------------------------------------------------------------------------- /config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = '1.0' 5 | 6 | # Add additional assets to the asset load path. 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | # Add Yarn node_modules folder to the asset load path. 9 | Rails.application.config.assets.paths << Rails.root.join('node_modules') 10 | 11 | # Precompile additional assets. 12 | # application.js, application.css, and all non-JS/CSS in the app/assets 13 | # folder are already added. 14 | # Rails.application.config.assets.precompile += %w( admin.js admin.css ) 15 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Specify a serializer for the signed and encrypted cookie jars. 4 | # Valid options are :json, :marshal, and :hybrid. 5 | Rails.application.config.action_dispatch.cookies_serializer = :json 6 | -------------------------------------------------------------------------------- /config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /config/initializers/new_framework_defaults_5_1.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | # 3 | # This file contains migration options to ease your Rails 5.1 upgrade. 4 | # 5 | # Once upgraded flip defaults one by one to migrate to the new default. 6 | # 7 | # Read the Guide for Upgrading Ruby on Rails for more info on each option. 8 | 9 | # Make `form_with` generate non-remote forms. 10 | Rails.application.config.action_view.form_with_generates_remote_forms = false 11 | 12 | # Unknown asset fallback will return the path passed in when the given 13 | # asset is not present in the asset pipeline. 14 | # Rails.application.config.assets.unknown_asset_fallback = false 15 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # The following keys must be escaped otherwise they will not be retrieved by 20 | # the default I18n backend: 21 | # 22 | # true, false, on, off, yes, no 23 | # 24 | # Instead, surround them with single quotes. 25 | # 26 | # en: 27 | # 'true': 'foo' 28 | # 29 | # To learn more, please read the Rails Internationalization guide 30 | # available at http://guides.rubyonrails.org/i18n.html. 31 | 32 | en: 33 | hello: "Hello world" 34 | -------------------------------------------------------------------------------- /config/puma.rb: -------------------------------------------------------------------------------- 1 | # Puma can serve each request in a thread from an internal thread pool. 2 | # The `threads` method setting takes two numbers: a minimum and maximum. 3 | # Any libraries that use thread pools should be configured to match 4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum 5 | # and maximum; this matches the default thread size of Active Record. 6 | # 7 | threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } 8 | threads threads_count, threads_count 9 | 10 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000. 11 | # 12 | port ENV.fetch("PORT") { 3000 } 13 | 14 | # Specifies the `environment` that Puma will run in. 15 | # 16 | environment ENV.fetch("RAILS_ENV") { "development" } 17 | 18 | # Specifies the number of `workers` to boot in clustered mode. 19 | # Workers are forked webserver processes. If using threads and workers together 20 | # the concurrency of the application would be max `threads` * `workers`. 21 | # Workers do not work on JRuby or Windows (both of which do not support 22 | # processes). 23 | # 24 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 } 25 | 26 | # Use the `preload_app!` method when specifying a `workers` number. 27 | # This directive tells Puma to first boot the application and load code 28 | # before forking the application. This takes advantage of Copy On Write 29 | # process behavior so workers use less memory. If you use this option 30 | # you need to make sure to reconnect any threads in the `on_worker_boot` 31 | # block. 32 | # 33 | # preload_app! 34 | 35 | # If you are preloading your application and using Active Record, it's 36 | # recommended that you close any connections to the database before workers 37 | # are forked to prevent connection leakage. 38 | # 39 | # before_fork do 40 | # ActiveRecord::Base.connection_pool.disconnect! if defined?(ActiveRecord) 41 | # end 42 | 43 | # The code in the `on_worker_boot` will be called if you are using 44 | # clustered mode by specifying a number of `workers`. After each worker 45 | # process is booted, this block will be run. If you are using the `preload_app!` 46 | # option, you will want to use this block to reconnect to any threads 47 | # or connections that may have been created at application boot, as Ruby 48 | # cannot share connections between processes. 49 | # 50 | # on_worker_boot do 51 | # ActiveRecord::Base.establish_connection if defined?(ActiveRecord) 52 | # end 53 | # 54 | 55 | # Allow puma to be restarted by `rails restart` command. 56 | plugin :tmp_restart 57 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | 3 | root to: "notifications#index" 4 | 5 | ### Uncomment below as we add functionality/data ### 6 | 7 | #root to: 'policies#index' 8 | 9 | #resources :policies, only: [:index, :show] do 10 | #resources :versions, only: [:index, :show] 11 | #end 12 | #resources :sites, only: [:index, :show] 13 | #resources :users, only: [:edit, :update, :show] 14 | 15 | #comment these in as we add tests: 16 | #get '/signup', to: 'users#new', as: 'signup' 17 | #post '/signup', to: 'users#create', as: 'users' 18 | #get '/signin', to: 'sessions#new', as: 'signin' 19 | #post '/signin', to: 'sessions#create' 20 | #match '/signout', to: 'sessions#destroy', via: :delete, as: 'signout' 21 | 22 | ### Uncomment above ^ ### 23 | 24 | # The priority is based upon order of creation: 25 | # first created -> highest priority. 26 | 27 | # Sample of regular route: 28 | # match 'products/:id' => 'catalog#view' 29 | # Keep in mind you can assign values other than :controller and :action 30 | 31 | # Sample of named route: 32 | # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase 33 | # This route can be invoked with purchase_url(:id => product.id) 34 | 35 | # Sample resource route (maps HTTP verbs to controller actions automatically): 36 | # resources :products 37 | 38 | # Sample resource route with options: 39 | # resources :products do 40 | # member do 41 | # get 'short' 42 | # post 'toggle' 43 | # end 44 | # 45 | # collection do 46 | # get 'sold' 47 | # end 48 | # end 49 | 50 | # Sample resource route with sub-resources: 51 | # resources :products do 52 | # resources :comments, :sales 53 | # resource :seller 54 | # end 55 | 56 | # Sample resource route with more complex sub-resources 57 | # resources :products do 58 | # resources :comments 59 | # resources :sales do 60 | # get 'recent', :on => :collection 61 | # end 62 | # end 63 | 64 | # Sample resource route within a namespace: 65 | # namespace :admin do 66 | # # Directs /admin/products/* to Admin::ProductsController 67 | # # (app/controllers/admin/products_controller.rb) 68 | # resources :products 69 | # end 70 | 71 | # You can have the root of your site routed with "root" 72 | # just remember to delete public/index.html. 73 | # root :to => 'welcome#index' 74 | 75 | # See how all your routes lay out with "rake routes" 76 | 77 | # This is a legacy wild controller route that's not recommended for RESTful applications. 78 | # Note: This route will make all actions in every controller accessible via GET requests. 79 | # match ':controller(/:action(/:id))(.:format)' 80 | end 81 | -------------------------------------------------------------------------------- /config/secrets.yml: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key is used for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | 6 | # Make sure the secret is at least 30 characters and all random, 7 | # no regular words or you'll be exposed to dictionary attacks. 8 | # You can use `rails secret` to generate a secure secret key. 9 | 10 | # Make sure the secrets in this file are kept private 11 | # if you're sharing your code publicly. 12 | 13 | # Shared secrets are available across all environments. 14 | 15 | # shared: 16 | # api_key: a1B2c3D4e5F6 17 | 18 | # Environmental secrets are only available for that specific environment. 19 | 20 | development: 21 | secret_key_base: ef1cd57c29560eae2956c173b47f67be2740ab5d68aa20cf5d774ca50ea98e15ffa3c131830b00ad7127c19fec809a7c9ece086091b3eb69b56deb231d4a500e 22 | 23 | test: 24 | secret_key_base: 355ca0dc504336f05ad01415a1f573dd028a4899a997c2a5e24ce056b9d0069a01ac401bbd5a8c14b546ceac6ff53f1904f1e3fc6c92a6d6aca6431a98d234bd 25 | 26 | # Do not keep production secrets in the unencrypted secrets file. 27 | # Instead, either read values from the environment. 28 | # Or, use `bin/rails secrets:setup` to configure encrypted secrets 29 | # and move the `production:` environment over there. 30 | 31 | production: 32 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> 33 | -------------------------------------------------------------------------------- /config/spring.rb: -------------------------------------------------------------------------------- 1 | %w( 2 | .ruby-version 3 | .rbenv-vars 4 | tmp/restart.txt 5 | tmp/caching-dev.txt 6 | ).each { |path| Spring.watch(path) } 7 | -------------------------------------------------------------------------------- /db/migrate/20130106195349_create_sites.rb: -------------------------------------------------------------------------------- 1 | class CreateSites < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :sites do |t| 4 | t.string :name 5 | 6 | t.timestamps 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20130107182823_create_policies.rb: -------------------------------------------------------------------------------- 1 | class CreatePolicies < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :policies do |t| 4 | t.string :name 5 | t.string :url 6 | t.string :xpath 7 | t.string :lang 8 | t.text :crawl 9 | t.integer :site_id 10 | 11 | t.timestamps 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20130107212843_remove_site_id_from_policy.rb: -------------------------------------------------------------------------------- 1 | class RemoveSiteIdFromPolicy < ActiveRecord::Migration[5.1] 2 | def up 3 | remove_column :policies, :site_id 4 | end 5 | 6 | def down 7 | add_column :policies, :site_id, :integer 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20130110080148_create_commitments.rb: -------------------------------------------------------------------------------- 1 | class CreateCommitments < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :commitments do |t| 4 | t.integer :policy_id 5 | t.integer :site_id 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20130117190926_create_versions.rb: -------------------------------------------------------------------------------- 1 | class CreateVersions < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :versions do |t| 4 | t.integer :policy_id 5 | t.text :previous_crawl 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20130122214855_create_crawls.rb: -------------------------------------------------------------------------------- 1 | class CreateCrawls < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :crawls do |t| 4 | t.integer :policy_id 5 | t.text :crawl 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20130122221303_rename_crawl_in_policy.rb: -------------------------------------------------------------------------------- 1 | class RenameCrawlInPolicy < ActiveRecord::Migration[5.1] 2 | def change 3 | rename_column :policies, :crawl, :detail 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130122222453_rename_crawl_in_crawls.rb: -------------------------------------------------------------------------------- 1 | class RenameCrawlInCrawls < ActiveRecord::Migration[5.1] 2 | def change 3 | rename_column :crawls, :crawl, :scrape 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130130183836_add_needs_revision_to_policies.rb: -------------------------------------------------------------------------------- 1 | class AddNeedsRevisionToPolicies < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :policies, :needs_revision, :boolean 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130205164614_create_users.rb: -------------------------------------------------------------------------------- 1 | class CreateUsers < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :users do |t| 4 | t.string :name 5 | t.string :email 6 | t.boolean :admin 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20130205173331_create_subscriptions.rb: -------------------------------------------------------------------------------- 1 | class CreateSubscriptions < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :subscriptions do |t| 4 | t.integer :policy_id 5 | t.integer :user_id 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20130206150453_add_password_digest_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddPasswordDigestToUsers < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :users, :password_digest, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130206154837_add_index_to_users_email.rb: -------------------------------------------------------------------------------- 1 | class AddIndexToUsersEmail < ActiveRecord::Migration[5.1] 2 | def change 3 | add_index :users, :email, unique: true 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130602151232_change_table_crawls.rb: -------------------------------------------------------------------------------- 1 | class ChangeTableCrawls < ActiveRecord::Migration[5.1] 2 | def up 3 | change_table :crawls do |t| 4 | t.rename :scrape, :full_page 5 | end 6 | end 7 | 8 | def down 9 | change_table :crawls do |t| 10 | t.rename :full_page, :scrape 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20130602152236_add_policy_to_crawls.rb: -------------------------------------------------------------------------------- 1 | class AddPolicyToCrawls < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :crawls, :policy, :text 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130602153011_add_full_page_to_versions.rb: -------------------------------------------------------------------------------- 1 | class AddFullPageToVersions < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :versions, :full_page, :text 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20130602153432_rename_column_in_versions.rb: -------------------------------------------------------------------------------- 1 | class RenameColumnInVersions < ActiveRecord::Migration[5.1] 2 | def up 3 | rename_column :versions, :previous_crawl, :previous_policy 4 | end 5 | 6 | def down 7 | rename_column :versions, :previous_policy, :previous_crawl 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20130602163220_rename_column_in_crawls.rb: -------------------------------------------------------------------------------- 1 | class RenameColumnInCrawls < ActiveRecord::Migration[5.1] 2 | def up 3 | rename_column :crawls, :policy, :crawled_policy 4 | end 5 | 6 | def down 7 | rename_column :crawls, :crawled_policy, :policy 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20130718160617_create_notifications.rb: -------------------------------------------------------------------------------- 1 | class CreateNotifications < ActiveRecord::Migration[5.1] 2 | def change 3 | create_table :notifications do |t| 4 | t.string :site 5 | t.string :name 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20130724121055_add_diff_url_to_notifications.rb: -------------------------------------------------------------------------------- 1 | class AddDiffUrlToNotifications < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :notifications, :diff_url, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20141207153633_remove_xpath_and_detail_from_policies.rb: -------------------------------------------------------------------------------- 1 | class RemoveXpathAndDetailFromPolicies < ActiveRecord::Migration[4.2] 2 | def up 3 | remove_column :policies, :xpath 4 | remove_column :policies, :detail 5 | end 6 | 7 | def down 8 | add_column :policies, :detail, :text 9 | add_column :policies, :xpath, :string 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20141207153710_add_xpath_and_text_to_versions.rb: -------------------------------------------------------------------------------- 1 | class AddXpathAndTextToVersions < ActiveRecord::Migration[4.2] 2 | def change 3 | add_column :versions, :xpath, :string 4 | rename_column :versions, :previous_policy, :text 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20180227222001_remove_xpath_from_versions.rb: -------------------------------------------------------------------------------- 1 | class RemoveXpathFromVersions < ActiveRecord::Migration[5.1] 2 | def change 3 | remove_column :versions, :xpath, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20180227222214_add_xpath_to_policies.rb: -------------------------------------------------------------------------------- 1 | class AddXpathToPolicies < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :policies, :xpath, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20180227222404_add_former_site_to_versions.rb: -------------------------------------------------------------------------------- 1 | class AddFormerSiteToVersions < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :versions, :former_site, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20180228193354_add_obsolete_to_policies.rb: -------------------------------------------------------------------------------- 1 | class AddObsoleteToPolicies < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :policies, :obsolete, :boolean 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20180228214750_add_diff_url_to_versions.rb: -------------------------------------------------------------------------------- 1 | class AddDiffUrlToVersions < ActiveRecord::Migration[5.1] 2 | def change 3 | add_column :versions, :diff_url, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/schema.rb: -------------------------------------------------------------------------------- 1 | # This file is auto-generated from the current state of the database. Instead 2 | # of editing this file, please use the migrations feature of Active Record to 3 | # incrementally modify your database, and then regenerate this schema definition. 4 | # 5 | # Note that this schema.rb definition is the authoritative source for your 6 | # database schema. If you need to create the application database on another 7 | # system, you should be using db:schema:load, not running all the migrations 8 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 9 | # you'll amass, the slower it'll run and the greater likelihood for issues). 10 | # 11 | # It's strongly recommended that you check this file into your version control system. 12 | 13 | ActiveRecord::Schema.define(version: 20180228214750) do 14 | 15 | create_table "commitments", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4" do |t| 16 | t.integer "policy_id" 17 | t.integer "site_id" 18 | t.datetime "created_at", null: false 19 | t.datetime "updated_at", null: false 20 | end 21 | 22 | create_table "crawls", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4" do |t| 23 | t.integer "policy_id" 24 | t.text "full_page" 25 | t.datetime "created_at", null: false 26 | t.datetime "updated_at", null: false 27 | t.text "crawled_policy" 28 | end 29 | 30 | create_table "notifications", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4" do |t| 31 | t.string "site" 32 | t.string "name" 33 | t.datetime "created_at", null: false 34 | t.datetime "updated_at", null: false 35 | t.string "diff_url" 36 | end 37 | 38 | create_table "policies", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4" do |t| 39 | t.string "name" 40 | t.string "url" 41 | t.string "lang" 42 | t.datetime "created_at", null: false 43 | t.datetime "updated_at", null: false 44 | t.boolean "needs_revision" 45 | t.string "xpath" 46 | t.boolean "obsolete" 47 | end 48 | 49 | create_table "sites", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4" do |t| 50 | t.string "name" 51 | t.datetime "created_at", null: false 52 | t.datetime "updated_at", null: false 53 | end 54 | 55 | create_table "subscriptions", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4" do |t| 56 | t.integer "policy_id" 57 | t.integer "user_id" 58 | t.datetime "created_at", null: false 59 | t.datetime "updated_at", null: false 60 | end 61 | 62 | create_table "users", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4" do |t| 63 | t.string "name" 64 | t.string "email" 65 | t.boolean "admin" 66 | t.datetime "created_at", null: false 67 | t.datetime "updated_at", null: false 68 | t.string "password_digest" 69 | t.index ["email"], name: "index_users_on_email", unique: true 70 | end 71 | 72 | create_table "versions", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4" do |t| 73 | t.integer "policy_id" 74 | t.text "text" 75 | t.datetime "created_at", null: false 76 | t.datetime "updated_at", null: false 77 | t.text "full_page" 78 | t.string "former_site" 79 | t.string "diff_url" 80 | end 81 | 82 | end 83 | -------------------------------------------------------------------------------- /db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rails db:seed command (or created alongside the database with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }]) 7 | # Character.create(name: 'Luke', movie: movies.first) 8 | -------------------------------------------------------------------------------- /lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/lib/assets/.keep -------------------------------------------------------------------------------- /lib/tasks/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/lib/tasks/.keep -------------------------------------------------------------------------------- /lib/tasks/import_versions.rake: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | namespace :versions do 3 | desc "Import reviewed policy versions from tb2 repo" 4 | task :import_versions => :environment do 5 | #path will be the path to the tb2 repo passed into the command when running the task 6 | path = ENV['path'] 7 | raise ArgumentError.new "\n\nMust include path like so:\nrails versions:import_versions path=../tosback2/\n\n" if path == nil 8 | 9 | io = IO.popen("cd #{path}; git log --format='%H %cd' --after=30/06/2013 --grep='changes for reviewed docs'") 10 | commit_string = io.read 11 | io.close 12 | 13 | commits = [] 14 | commit_string.each_line do |commit| 15 | commit_ary = commit.strip.split(/\s/,2) 16 | commits << {sha: commit_ary[0], date: DateTime.parse(commit_ary[1])} 17 | end 18 | 19 | commits.each do |commit| 20 | io = IO.popen("cd #{path}; git diff-tree -r --name-only --no-commit-id #{commit[:sha]}") 21 | files = io.read.split(/\n/) 22 | io.close 23 | 24 | files.map! do |file| 25 | #each file will be something like "crawl_reviewed/disqus.com/Privacy Policy.txt" 26 | ary = file.split(/\//) 27 | {path: file, site: ary[1], policy: ary[2]} 28 | end 29 | 30 | # site = Site.where(name: file[:site].downcase).first 31 | files.each do |file| 32 | file[:policy] = "Terms of Service.txt" if file[:policy] == "Terms Of Service.txt" 33 | #fixes issue with some of google's other service's old versions not importing 34 | #file[:policy] = "Microsoft Services Agreement.txt" if file[:policy] == "Terms of Service.txt" && file[:site].downcase == "msn.com" 35 | # another cheap fix, but we're just working from one dataset so I'll allow it. 36 | # ^no longer needed? But I just added this... o_O 37 | 38 | #Some sites have changed companies or names... 39 | former_site = nil 40 | 41 | #Going to need this for the import debugging: 42 | #puts file[:site] 43 | #puts file[:policy] 44 | 45 | #Workarounds for a few inconsistencies... 46 | if file[:site] == 'comcast.com' || file[:site] == 'comcast.net' 47 | former_site = file[:site] 48 | file[:site] = 'xfinity.com' 49 | elsif file[:site] == 'delicious.com' 50 | former_site = file[:site] 51 | file[:site] = 'del.icio.us' 52 | elsif file[:site] == 'faranow.com' 53 | former_site = file[:site] 54 | file[:site] = 'packagetrackr.com' 55 | elsif file[:site] == 'rapidshare.com' 56 | next 57 | end 58 | 59 | policy = Site.where(name: file[:site].downcase).first.policies.where(name: file[:policy].sub(".txt","")).first 60 | 61 | if policy.nil? 62 | policy = Policy.new(name: file[:policy].sub(".txt",""), obsolete: true) 63 | end 64 | 65 | version = policy.versions.where(created_at: commit[:date].beginning_of_day..commit[:date].end_of_day).first 66 | 67 | if version.nil? 68 | old_policy = IO.popen("cd #{path}; git show #{commit[:sha]}:'#{file[:path]}'").read 69 | version = policy.versions.new(text: old_policy) 70 | version.created_at = commit[:date] 71 | version.former_site = former_site 72 | version.diff_url = "https://github.com/tosdr/tosback2/commit/#{commit[:sha]}?diff=split" 73 | version.save 74 | end 75 | 76 | end 77 | end 78 | 79 | end # import_versions 80 | end 81 | 82 | -------------------------------------------------------------------------------- /lib/tasks/manage_xml.rake: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | namespace :xml do 3 | desc "Import the XML rules to sites and policies" 4 | task :import_xml => :environment do 5 | path = ENV['path'] 6 | # Point path to tosback2 folder ( e.g. rake xml:import_xml path=../../tosdr/tosback2/ ) 7 | raise ArgumentError.new "\n\nMust include path like so:\nrails xml:import_xml path=../tosback2/\n\n" if path == nil 8 | 9 | io = IO.popen("cd #{path}; git log --format='%H %s' --after=#{3.days.ago.strftime('%d/%m/%Y')}") 10 | commit_string = io.read 11 | io.close 12 | 13 | reviewed_hash = nil 14 | commit_string.each_line do |commit| 15 | break if reviewed_hash 16 | 17 | commit_ary = commit.strip.split(/\s/,2) 18 | reviewed_hash = commit_ary[0] if commit_ary[1] == 'changes for reviewed docs' 19 | end 20 | 21 | Dir.foreach(path+"rules/") do |xml_file| # loop for each xml file/rule 22 | next if xml_file == "." || xml_file == ".." 23 | 24 | filecontent = File.open(path + "rules/" + xml_file) 25 | ngxml = Nokogiri::XML(filecontent) 26 | filecontent.close 27 | 28 | # check to see if site exists 29 | site = Site.where(name: ngxml.xpath("//sitename[1]/@name").to_s.downcase).first 30 | # create site if it doesn't 31 | if site.nil? 32 | site = Site.create(name:ngxml.xpath("//sitename[1]/@name").to_s.downcase) 33 | end 34 | 35 | ngxml.xpath("//sitename/docname").each do |doc| 36 | doc_hash = {} 37 | doc_hash[:name] = doc.at_xpath("./@name").to_s 38 | doc_hash[:url] = doc.at_xpath("./url/@name").to_s 39 | doc_hash[:xpath] = (doc.at_xpath("./url/@xpath").to_s == "") ? nil : doc.at_xpath("./url/@xpath").to_s 40 | doc_hash[:nr] = ((doc.at_xpath("./url/@reviewed").to_s == "") || (doc.at_xpath("./url/@reviewed").to_s == "false")) ? true : false 41 | doc_hash[:lang] = (doc.at_xpath("./url/@lang").to_s == "") ? nil : doc.at_xpath("./url/@lang").to_s 42 | doc_hash[:txt_file] = (doc_hash[:nr] == false) ? "crawl_reviewed/#{site.name}/#{doc_hash[:name]}.txt" : "crawl/#{site.name}/#{doc_hash[:name]}.txt" 43 | 44 | p = Policy.where(url:doc_hash[:url], name: doc_hash[:name]).first 45 | if p.nil? 46 | p = Policy.create do |plcy| 47 | plcy.name = doc_hash[:name] 48 | plcy.url = doc_hash[:url] 49 | plcy.xpath = doc_hash[:xpath] 50 | plcy.needs_revision = doc_hash[:nr] 51 | plcy.lang = doc_hash[:lang] 52 | #TODO see if chomp is necessary for making the diffs work right once the 53 | # new crawler is finished 54 | File.open(path+doc_hash[:txt_file]) do |crawl| 55 | plcy.versions.new(text: crawl.read.chomp) do |ver| 56 | ver.diff_url = "https://github.com/tosdr/tosback2/commit/#{reviewed_hash}?diff=split" unless plcy.needs_revision 57 | end 58 | end 59 | end 60 | end # if p.nil? 61 | 62 | #sets date on version to the correct commit date from git 63 | unless p.needs_revision == true 64 | date_of_crawl = IO.popen("cd #{path}; git log -1 --format='%cd' '#{doc_hash[:txt_file]}'").read 65 | version = p.versions.first 66 | version.created_at = DateTime.parse(date_of_crawl) 67 | version.save 68 | p.created_at = DateTime.parse(date_of_crawl) 69 | p.save 70 | end 71 | 72 | unless p.sites.include?(site) 73 | p.sites << site 74 | end # unless policy has site already 75 | end # each doc 76 | end # each xml file 77 | end # import_xml 78 | 79 | desc "Export the sites and policies in the db to XML" 80 | task :export_xml => :environment do 81 | # Point path to tosback2 folder ( e.g. rake xml:export_xml path=../../tosdr/tosback2/ ) 82 | path = ENV['path'] + "rules/" 83 | raise ArgumentError.new "\n\nMust include path like so:\nrails xml:export_xml path=../tosback2/\n\n" if path == nil 84 | 85 | Dir.mkdir(path) unless File.exists?(path) 86 | 87 | Site.all.each do |site| 88 | rule_file = File.open(path + site.name + ".xml","w") # new file or overwrite old file 89 | rule_file.print "\n" 90 | 91 | site.policies.each do |policy| 92 | rule_file.print " \n" 93 | rule_file.print " \n" 98 | rule_file.print " \n \n \n" 99 | end 100 | 101 | rule_file.print "\n" 102 | rule_file.close 103 | end #policy.all.each 104 | end # export_xml 105 | end 106 | -------------------------------------------------------------------------------- /log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/log/.keep -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tb3", 3 | "private": true, 4 | "dependencies": {} 5 | } 6 | -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
    60 |
    61 |

    The page you were looking for doesn't exist.

    62 |

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

    63 |
    64 |

    If you are the application owner check the logs for more information.

    65 |
    66 | 67 | 68 | -------------------------------------------------------------------------------- /public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
    60 |
    61 |

    The change you wanted was rejected.

    62 |

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

    63 |
    64 |

    If you are the application owner check the logs for more information.

    65 |
    66 | 67 | 68 | -------------------------------------------------------------------------------- /public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
    60 |
    61 |

    We're sorry, but something went wrong.

    62 |
    63 |

    If you are the application owner check the logs for more information.

    64 |
    65 | 66 | 67 | -------------------------------------------------------------------------------- /public/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/public/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/public/favicon.ico -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | [1]: https://www.eff.org/deeplinks/2013/01/campus-party-hackathon-making-rule-contribution-tosback "Contributing Rules to ToSBack" 2 | [4]: https://github.com/tosdr/ToSBack3/wiki/Help-Us-Develop-the-New-ToSBack "Help us develop ToSBack!" 3 | [5]: http://gun.io/blog/how-to-github-fork-branch-and-pull-request/ "How to branch and submit a pull request" 4 | [setup]: https://github.com/tosdr/ToSBack3/wiki/Setting-Up-the-Development-Environment "Setting Up the ToSBack Development Environment" 5 | 6 | ### What is ToSBack? 7 | 8 | Terms-Of-Service and other website policies form the foundation of your relationship with social networking sites, online businesses, and other Internet communities. But most people become aware of these terms only when there's a problem. TOSBack was created to help you monitor the policies for the websites you use everyday, and show how they change over time. 9 | 10 | ### How you can help! 11 | 12 | * Check out the wiki page on [setting up][setup] the development environment. 13 | * If you aren't a developer, you can always help us [add policies][1]. 14 | * Check the issues page or this [wiki article][4] to find a task you want to work on! 15 | * Here is a [good guide][5] for creating an issue in the tracker, forking, branching, and submitting a pull request! 16 | -------------------------------------------------------------------------------- /spec/factories/commitments.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 | # Read about factories at https://github.com/thoughtbot/factory_girl 13 | 14 | FactoryBot.define do 15 | factory :commitment, :class => 'Commitment' do 16 | policy 17 | site 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/factories/crawls.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 | # Read about factories at https://github.com/thoughtbot/factory_girl 14 | 15 | FactoryBot.define do 16 | factory :crawl do 17 | crawled_policy { "

    Privacy Policy

    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&&100c);v++){for(var n=-v+r;n<=v-t;n+=2){var l=g+n,m;m=n==-v||n!=v&&j[l-1]d)t+=2;else if(s>e)r+=2;else if(q&&(l=g+k-n,0<=l&&l= 8 | u)return this.diff_bisectSplit_(a,b,m,s,c)}}for(n=-v+p;n<=v-w;n+=2){l=g+n;u=n==-v||n!=v&&i[l-1]d)w+=2;else if(m>e)p+=2;else if(!q&&(l=g+k-n,0<=l&&(l=u)))return this.diff_bisectSplit_(a,b,m,s,c)}}return[[-1,a],[1,b]]}; 9 | diff_match_patch.prototype.diff_bisectSplit_=function(a,b,c,d,e){var f=a.substring(0,c),g=b.substring(0,d);a=a.substring(c);b=b.substring(d);f=this.diff_main(f,g,!1,e);e=this.diff_main(a,b,!1,e);return f.concat(e)}; 10 | diff_match_patch.prototype.diff_linesToChars_=function(a,b){function c(a){for(var b="",c=0,f=-1,g=d.length;fd?a=a.substring(c-d):c=a.length?[h,j,n,l,g]:null}if(0>=this.Diff_Timeout)return null; 15 | var d=a.length>b.length?a:b,e=a.length>b.length?b:a;if(4>d.length||2*e.lengthd[4].length?g:d:d:g;var j;a.length>b.length?(g=h[0],d=h[1],e=h[2],j=h[3]):(e=h[0],j=h[1],g=h[2],d=h[3]);h=h[4];return[g,d,e,j,h]}; 16 | diff_match_patch.prototype.diff_cleanupSemantic=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=0,h=0,j=0,i=0;f=e){if(d>=b.length/2||d>=c.length/2)a.splice(f,0,[0,c.substring(0,d)]),a[f-1][1]=b.substring(0,b.length-d),a[f+1][1]=c.substring(d),f++}else if(e>=b.length/2||e>=c.length/2)a.splice(f,0,[0,b.substring(0,e)]),a[f-1][0]=1,a[f-1][1]=c.substring(0,c.length-e),a[f+1][0]=-1,a[f+1][1]=b.substring(e),f++;f++}f++}}; 18 | diff_match_patch.prototype.diff_cleanupSemanticLossless=function(a){function b(a,b){if(!a||!b)return 6;var c=a.charAt(a.length-1),d=b.charAt(0),e=c.match(diff_match_patch.nonAlphaNumericRegex_),f=d.match(diff_match_patch.nonAlphaNumericRegex_),g=e&&c.match(diff_match_patch.whitespaceRegex_),h=f&&d.match(diff_match_patch.whitespaceRegex_),c=g&&c.match(diff_match_patch.linebreakRegex_),d=h&&d.match(diff_match_patch.linebreakRegex_),i=c&&a.match(diff_match_patch.blanklineEndRegex_),j=d&&b.match(diff_match_patch.blanklineStartRegex_); 19 | return i||j?5:c||d?4:e&&!g&&h?3:g||h?2:e||f?1:0}for(var c=1;c=i&&(i=k,g=d,h=e,j=f)}a[c-1][1]!=g&&(g?a[c-1][1]=g:(a.splice(c-1,1),c--),a[c][1]= 20 | h,j?a[c+1][1]=j:(a.splice(c+1,1),c--))}c++}};diff_match_patch.nonAlphaNumericRegex_=/[^a-zA-Z0-9]/;diff_match_patch.whitespaceRegex_=/\s/;diff_match_patch.linebreakRegex_=/[\r\n]/;diff_match_patch.blanklineEndRegex_=/\n\r?\n$/;diff_match_patch.blanklineStartRegex_=/^\r?\n\r?\n/; 21 | diff_match_patch.prototype.diff_cleanupEfficiency=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=!1,h=!1,j=!1,i=!1;fb)break;e=c;f=d}return a.length!=g&&-1===a[g][0]?f:f+(b-e)}; 25 | diff_match_patch.prototype.diff_prettyHtml=function(a){for(var b=[],c=/&/g,d=//g,f=/\n/g,g=0;g");switch(h){case 1:b[g]=''+j+"";break;case -1:b[g]=''+j+"";break;case 0:b[g]=""+j+""}}return b.join("")}; 26 | diff_match_patch.prototype.diff_text1=function(a){for(var b=[],c=0;cthis.Match_MaxBits)throw Error("Pattern too long for this browser.");var e=this.match_alphabet_(b),f=this,g=this.Match_Threshold,h=a.indexOf(b,c);-1!=h&&(g=Math.min(d(0,h),g),h=a.lastIndexOf(b,c+b.length),-1!=h&&(g=Math.min(d(0,h),g)));for(var j=1<=i;p--){var w=e[a.charAt(p-1)];k[p]=0===t?(k[p+1]<<1|1)&w:(k[p+1]<<1|1)&w|((r[p+1]|r[p])<<1|1)|r[p+1];if(k[p]&j&&(w=d(t,p-1),w<=g))if(g=w,h=p-1,h>c)i=Math.max(1,2*c-h);else break}if(d(t+1,c)>g)break;r=k}return h}; 32 | diff_match_patch.prototype.match_alphabet_=function(a){for(var b={},c=0;c=2*this.Patch_Margin&& 37 | e&&(this.patch_addContext_(a,h),c.push(a),a=new diff_match_patch.patch_obj,e=0,h=d,f=g)}1!==i&&(f+=k.length);-1!==i&&(g+=k.length)}e&&(this.patch_addContext_(a,h),c.push(a));return c};diff_match_patch.prototype.patch_deepCopy=function(a){for(var b=[],c=0;cthis.Match_MaxBits){if(j=this.match_main(b,h.substring(0,this.Match_MaxBits),g),-1!=j&&(i=this.match_main(b,h.substring(h.length-this.Match_MaxBits),g+h.length-this.Match_MaxBits),-1==i||j>=i))j=-1}else j=this.match_main(b,h,g); 39 | if(-1==j)e[f]=!1,d-=a[f].length2-a[f].length1;else if(e[f]=!0,d=j-g,g=-1==i?b.substring(j,j+h.length):b.substring(j,i+this.Match_MaxBits),h==g)b=b.substring(0,j)+this.diff_text2(a[f].diffs)+b.substring(j+h.length);else if(g=this.diff_main(h,g,!1),h.length>this.Match_MaxBits&&this.diff_levenshtein(g)/h.length>this.Patch_DeleteThreshold)e[f]=!1;else{this.diff_cleanupSemanticLossless(g);for(var h=0,k,i=0;ie[0][1].length){var f=b-e[0][1].length;e[0][1]=c.substring(e[0][1].length)+e[0][1];d.start1-=f;d.start2-=f;d.length1+=f;d.length2+=f}d=a[a.length-1];e=d.diffs;0==e.length||0!=e[e.length-1][0]?(e.push([0, 42 | c]),d.length1+=b,d.length2+=b):b>e[e.length-1][1].length&&(f=b-e[e.length-1][1].length,e[e.length-1][1]+=c.substring(0,f),d.length1+=f,d.length2+=f);return c}; 43 | diff_match_patch.prototype.patch_splitMax=function(a){for(var b=this.Match_MaxBits,c=0;c2*b?(h.length1+=i.length,e+=i.length,j=!1,h.diffs.push([g,i]),d.diffs.shift()):(i=i.substring(0,b-h.length1-this.Patch_Margin),h.length1+=i.length,e+=i.length,0===g?(h.length2+=i.length,f+=i.length):j=!1,h.diffs.push([g,i]),i==d.diffs[0][1]?d.diffs.shift():d.diffs[0][1]=d.diffs[0][1].substring(i.length))}g=this.diff_text2(h.diffs);g=g.substring(g.length-this.Patch_Margin);i=this.diff_text1(d.diffs).substring(0,this.Patch_Margin);""!==i&& 45 | (h.length1+=i.length,h.length2+=i.length,0!==h.diffs.length&&0===h.diffs[h.diffs.length-1][0]?h.diffs[h.diffs.length-1][1]+=i:h.diffs.push([0,i]));j||a.splice(++c,0,h)}}};diff_match_patch.prototype.patch_toText=function(a){for(var b=[],c=0;c/g; 6 | var pattern_para = /\n/g; 7 | for (var x = 0; x < diffs.length; x++) { 8 | var op = diffs[x][0]; // Operation (insert, delete, equal) 9 | var data = diffs[x][1]; // Text of change. 10 | var text = data; 11 | //var text = data.replace(pattern_amp, '&').replace(pattern_lt, '<') 12 | //.replace(pattern_gt, '>').replace(pattern_para, '¶
    '); 13 | switch (op) { 14 | case DIFF_INSERT: 15 | html[x] = '' + text + ''; 16 | break; 17 | case DIFF_DELETE: 18 | html[x] = '' + text + ''; 19 | break; 20 | case DIFF_EQUAL: 21 | html[x] = '' + text + ''; 22 | break; 23 | } 24 | } 25 | return html.join(''); 26 | }; 27 | 28 | $(function(){ 29 | TosbackDiffHandler.init(); 30 | 31 | $(".version_link").bind('ajax:success', function(evt, status, data, xhr){ 32 | 33 | if (evt.target.dataset.diffLink == "true") { 34 | //console.log("difffffffffff"); 35 | window.TosbackDiffHandler.showDiff(status); 36 | } else { 37 | window.TosbackDiffHandler.showPolicy(status); 38 | }; 39 | 40 | //console.log(status.text); 41 | }); 42 | }); 43 | 44 | var TosbackDiffHandler = { 45 | init: function(){ 46 | // TODO need access to version loaded from server initally 47 | this.currentVersion = {}; 48 | this.currentVersion.id = $("#version_info").data().currentVersion; 49 | this.currentVersion.text = $("#policy_text").html().trim(); 50 | this.dmp = new diff_match_patch(); 51 | //console.log("init"); 52 | this.updateFormatting(this.currentVersion.id); 53 | }, 54 | showDiff: function(diff_version){ 55 | //console.log("showDiff"); 56 | this.diff = this.dmp.diff_main(this.currentVersion.text, diff_version.text); 57 | this.dmp.diff_cleanupSemantic(this.diff); 58 | 59 | $("#policy_diff").html(this.dmp.diff_tosbackHtml(this.diff)); 60 | $("#date_text").html("Diff with " + diff_version.created_at ); 61 | $("#policy_text").hide(); 62 | $("#policy_diff").show(); 63 | 64 | this.updateFormatting(diff_version.id); 65 | }, 66 | showPolicy: function(policy){ 67 | if (policy != undefined) { 68 | this.currentVersion = policy; 69 | $("#policy_text").html(this.currentVersion.text); 70 | $("#date_text").html("ToSBack stored this version on " + this.currentVersion.created_at ); 71 | } 72 | 73 | $("#policy_diff").hide(); 74 | $("#policy_text").show(); 75 | this.updateFormatting(this.currentVersion.id); 76 | }, 77 | updateFormatting: function(version_id){ 78 | $(".version_link").show(); 79 | $("#version_diff_link_" + version_id).hide(); 80 | $("#version_diff_link_" + this.currentVersion.id).hide(); 81 | } 82 | }; 83 | -------------------------------------------------------------------------------- /vendor/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tosdr/ToSBack3/7e0970f17b5542308828af1ef0af7487def61b39/vendor/.keep --------------------------------------------------------------------------------