├── log
└── .keep
├── app
├── mailers
│ └── .keep
├── assets
│ ├── images
│ │ └── .keep
│ ├── stylesheets
│ │ ├── navigation.scss
│ │ └── application.scss
│ └── javascripts
│ │ └── application.js
├── models
│ ├── concerns
│ │ └── .keep
│ ├── short_label_sequence.rb
│ ├── label_maker.rb
│ ├── settings.rb
│ ├── item.rb
│ ├── packer.rb
│ ├── single_user_mode.rb
│ ├── link.rb
│ └── user.rb
├── controllers
│ ├── concerns
│ │ └── .keep
│ ├── dashboard_controller.rb
│ ├── application_controller.rb
│ ├── labels_controller.rb
│ ├── links_controller.rb
│ └── items_controller.rb
├── helpers
│ ├── application_helper.rb
│ └── labels_helper.rb
└── views
│ ├── dashboard
│ └── show.html.haml
│ ├── links
│ └── new.html.haml
│ ├── layouts
│ ├── application.html.haml
│ └── _navigation.html.haml
│ ├── items
│ ├── index.html.haml
│ └── new.html.haml
│ └── devise
│ └── sessions
│ └── new.html.erb
├── lib
├── assets
│ └── .keep
└── tasks
│ └── .keep
├── public
├── favicon.ico
├── robots.txt
├── 500.html
├── 422.html
└── 404.html
├── vendor
└── assets
│ ├── javascripts
│ └── .keep
│ └── stylesheets
│ └── .keep
├── .rspec
├── .dockerignore
├── deploy
├── ansible
│ ├── roles
│ │ ├── nginx
│ │ │ ├── meta
│ │ │ │ └── main.yml
│ │ │ ├── handlers
│ │ │ │ └── main.yml
│ │ │ ├── tasks
│ │ │ │ └── main.yml
│ │ │ └── templates
│ │ │ │ └── hellolocker.com.j2
│ │ └── docker
│ │ │ └── tasks
│ │ │ └── main.yml
│ └── deploy.yml
└── docker
│ └── nginx
│ ├── rails-env.conf
│ └── hellolocker.com
├── spec
├── support
│ ├── capybara.rb
│ ├── factory_girl.rb
│ ├── i18n.rb
│ ├── devise.rb
│ ├── rspec_utils.rb
│ └── database_cleaner.rb
├── factories
│ ├── items.rb
│ ├── links.rb
│ └── users.rb
├── features
│ ├── links_spec.rb
│ ├── master_user_spec.rb
│ └── items_spec.rb
├── models
│ ├── short_label_sequence_spec.rb
│ ├── item_spec.rb
│ ├── packer_spec.rb
│ ├── label_maker_spec.rb
│ ├── single_user_mode_spec.rb
│ ├── link_spec.rb
│ └── user_spec.rb
├── controllers
│ └── items_controller_spec.rb
├── javascripts
│ └── spec_helper.js
├── rails_helper.rb
├── spec_helper.rb
└── teaspoon_env.rb
├── config
├── locales
│ ├── layouts
│ │ └── en.yml
│ ├── en.yml
│ └── devise.en.yml
├── boot.rb
├── initializers
│ ├── cookies_serializer.rb
│ ├── session_store.rb
│ ├── mime_types.rb
│ ├── filter_parameter_logging.rb
│ ├── backtrace_silencers.rb
│ ├── assets.rb
│ ├── wrap_parameters.rb
│ ├── inflections.rb
│ ├── browserify.rb
│ └── devise.rb
├── environment.rb
├── routes.rb
├── schedule.rb
├── database.yml
├── secrets.yml
├── application.rb
└── environments
│ ├── development.rb
│ ├── test.rb
│ └── production.rb
├── bin
├── bundle
├── rake
├── rails
├── rspec
├── spring
└── setup
├── db
├── migrate
│ ├── 20150820142016_add_url_to_items.rb
│ ├── 20150821095056_add_label_to_links.rb
│ ├── 20150821150455_add_type_to_links.rb
│ ├── 20150821115125_add_item_id_to_links.rb
│ ├── 20151012152103_add_user_id_to_items.rb
│ ├── 20150808113404_add_master_to_users.rb
│ ├── 20150821114943_add_unique_index_to_links_label.rb
│ ├── 20150807125430_create_items.rb
│ ├── 20150821094416_create_links.rb
│ ├── 20150827100929_rename_type_to_label_type_in_links.rb
│ ├── 20150821155220_create_short_link_sequence.rb
│ ├── 20150821152750_create_settings.rb
│ └── 20150731130331_devise_create_users.rb
├── seeds.rb
├── schema.rb
└── structure.sql
├── config.ru
├── Rakefile
├── package.json
├── Dockerfile
├── .rubocop.yml
├── .gitignore
├── README.md
├── Gemfile
├── Guardfile
└── Gemfile.lock
/log/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/mailers/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lib/assets/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lib/tasks/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/assets/images/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/models/concerns/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/controllers/concerns/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/vendor/assets/javascripts/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/.keep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.rspec:
--------------------------------------------------------------------------------
1 | --color
2 | --require spec_helper
3 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | ansible/
2 | tmp/
3 | coverage/
4 | docker/
5 |
--------------------------------------------------------------------------------
/app/helpers/application_helper.rb:
--------------------------------------------------------------------------------
1 | module ApplicationHelper
2 | end
3 |
--------------------------------------------------------------------------------
/app/assets/stylesheets/navigation.scss:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 5rem;
3 | }
4 |
--------------------------------------------------------------------------------
/deploy/ansible/roles/nginx/meta/main.yml:
--------------------------------------------------------------------------------
1 | dependencies:
2 | - role: docker
3 |
--------------------------------------------------------------------------------
/deploy/docker/nginx/rails-env.conf:
--------------------------------------------------------------------------------
1 | env DATABASE_URL;
2 | env SECRET_KEY_BASE;
3 | env MASTER_PASSWORD;
4 |
--------------------------------------------------------------------------------
/spec/support/capybara.rb:
--------------------------------------------------------------------------------
1 | require 'capybara/poltergeist'
2 | Capybara.javascript_driver = :poltergeist
3 |
--------------------------------------------------------------------------------
/spec/support/factory_girl.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |config|
2 | config.include FactoryGirl::Syntax::Methods
3 | end
4 |
--------------------------------------------------------------------------------
/app/views/dashboard/show.html.haml:
--------------------------------------------------------------------------------
1 | .container
2 | .row
3 | %h1
4 | Hi!
5 | %p.lead
6 | Wooooow
7 |
--------------------------------------------------------------------------------
/deploy/ansible/roles/nginx/handlers/main.yml:
--------------------------------------------------------------------------------
1 | - name: restart nginx
2 | sudo: yes
3 | shell: /etc/init.d/nginx reload
4 |
--------------------------------------------------------------------------------
/config/locales/layouts/en.yml:
--------------------------------------------------------------------------------
1 | en:
2 | layouts:
3 | navigation:
4 | sign_in: "Sign in"
5 | sign_out: "Sign out"
6 |
--------------------------------------------------------------------------------
/spec/support/i18n.rb:
--------------------------------------------------------------------------------
1 | RSpec.configure do |config|
2 | config.include AbstractController::Translation, type: :feature
3 | end
4 |
--------------------------------------------------------------------------------
/app/controllers/dashboard_controller.rb:
--------------------------------------------------------------------------------
1 | class DashboardController < ApplicationController
2 |
3 | def show
4 | end
5 |
6 | end
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 |
--------------------------------------------------------------------------------
/config/boot.rb:
--------------------------------------------------------------------------------
1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
2 |
3 | require 'bundler/setup' # Set up gems listed in the Gemfile.
4 |
--------------------------------------------------------------------------------
/db/migrate/20150820142016_add_url_to_items.rb:
--------------------------------------------------------------------------------
1 | class AddUrlToItems < ActiveRecord::Migration
2 | def change
3 | add_column :items, :url, :string
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/config.ru:
--------------------------------------------------------------------------------
1 | # This file is used by Rack-based servers to start the application.
2 |
3 | require ::File.expand_path('../config/environment', __FILE__)
4 | run Rails.application
5 |
--------------------------------------------------------------------------------
/db/migrate/20150821095056_add_label_to_links.rb:
--------------------------------------------------------------------------------
1 | class AddLabelToLinks < ActiveRecord::Migration
2 | def change
3 | add_column :links, :label, :string
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20150821150455_add_type_to_links.rb:
--------------------------------------------------------------------------------
1 | class AddTypeToLinks < ActiveRecord::Migration
2 | def change
3 | add_column :links, :type, :string
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/app/views/links/new.html.haml:
--------------------------------------------------------------------------------
1 | = form_for [@item, @link] do |form|
2 | = form.label :label, "http://hellolocker.com/"
3 | = form.text_field :label
4 | = form.submit "Create"
5 |
--------------------------------------------------------------------------------
/config/initializers/cookies_serializer.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | Rails.application.config.action_dispatch.cookies_serializer = :json
4 |
--------------------------------------------------------------------------------
/db/migrate/20150821115125_add_item_id_to_links.rb:
--------------------------------------------------------------------------------
1 | class AddItemIdToLinks < ActiveRecord::Migration
2 | def change
3 | add_column :links, :item_id, :integer
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20151012152103_add_user_id_to_items.rb:
--------------------------------------------------------------------------------
1 | class AddUserIdToItems < ActiveRecord::Migration
2 | def change
3 | add_column :items, :user_id, :integer
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/config/environment.rb:
--------------------------------------------------------------------------------
1 | # Load the Rails application.
2 | require File.expand_path('../application', __FILE__)
3 |
4 | # Initialize the Rails application.
5 | Rails.application.initialize!
6 |
--------------------------------------------------------------------------------
/config/initializers/session_store.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | Rails.application.config.session_store :cookie_store, key: '_hellolocker_session'
4 |
--------------------------------------------------------------------------------
/db/migrate/20150808113404_add_master_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddMasterToUsers < ActiveRecord::Migration
2 | def change
3 | add_column :users, :master, :boolean, default: false
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/bin/rake:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | begin
3 | load File.expand_path("../spring", __FILE__)
4 | rescue LoadError
5 | end
6 | require_relative '../config/boot'
7 | require 'rake'
8 | Rake.application.run
9 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/db/migrate/20150821114943_add_unique_index_to_links_label.rb:
--------------------------------------------------------------------------------
1 | class AddUniqueIndexToLinksLabel < ActiveRecord::Migration
2 | def change
3 | add_index :links, :label, unique: true
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/db/migrate/20150807125430_create_items.rb:
--------------------------------------------------------------------------------
1 | class CreateItems < ActiveRecord::Migration
2 | def change
3 | create_table :items do |t|
4 |
5 | t.timestamps null: false
6 | end
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/db/migrate/20150821094416_create_links.rb:
--------------------------------------------------------------------------------
1 | class CreateLinks < ActiveRecord::Migration
2 | def change
3 | create_table :links do |t|
4 |
5 | t.timestamps null: false
6 | end
7 | end
8 | end
9 |
--------------------------------------------------------------------------------
/db/migrate/20150827100929_rename_type_to_label_type_in_links.rb:
--------------------------------------------------------------------------------
1 | class RenameTypeToLabelTypeInLinks < ActiveRecord::Migration
2 | def change
3 | rename_column :links, :type, :label_type
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
2 | #
3 | # To ban all spiders from the entire site uncomment the next two lines:
4 | # User-agent: *
5 | # Disallow: /
6 |
--------------------------------------------------------------------------------
/app/helpers/labels_helper.rb:
--------------------------------------------------------------------------------
1 | module LabelsHelper
2 |
3 | def label_path(link)
4 | label_link_path(label: link.label)
5 | end
6 |
7 | def label_url(link)
8 | label_link_url(label: link.label)
9 | end
10 |
11 | end
12 |
--------------------------------------------------------------------------------
/app/models/short_label_sequence.rb:
--------------------------------------------------------------------------------
1 | class ShortLabelSequence
2 |
3 | def self.next
4 | result = ActiveRecord::Base.connection.execute("SELECT nextval('short_link_seq')")
5 |
6 | result[0]["nextval"].to_i
7 | end
8 |
9 | end
10 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | begin
3 | load File.expand_path("../spring", __FILE__)
4 | rescue LoadError
5 | end
6 | APP_PATH = File.expand_path('../../config/application', __FILE__)
7 | require_relative '../config/boot'
8 | require 'rails/commands'
9 |
--------------------------------------------------------------------------------
/app/models/label_maker.rb:
--------------------------------------------------------------------------------
1 | class LabelMaker
2 |
3 | def generate_short_label(index:, salt_count: 0)
4 | salts = salt_count.times.map { Packer.generate_single_segment_salt }
5 | data = [index] + salts
6 |
7 | Packer.pack(data)
8 | end
9 |
10 | end
11 |
--------------------------------------------------------------------------------
/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 File.expand_path('../config/application', __FILE__)
5 |
6 | Rails.application.load_tasks
7 |
--------------------------------------------------------------------------------
/deploy/docker/nginx/hellolocker.com:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80;
3 | server_name hellolocker.com *.hellolocker.com;
4 | root /home/app/public;
5 |
6 | passenger_enabled on;
7 | passenger_user app;
8 |
9 | passenger_ruby /usr/bin/ruby2.2;
10 | }
11 |
--------------------------------------------------------------------------------
/app/controllers/application_controller.rb:
--------------------------------------------------------------------------------
1 | class ApplicationController < ActionController::Base
2 | # Prevent CSRF attacks by raising an exception.
3 | # For APIs, you may want to use :null_session instead.
4 | protect_from_forgery with: :exception
5 |
6 | before_action :authenticate_user!
7 |
8 | end
9 |
--------------------------------------------------------------------------------
/db/migrate/20150821155220_create_short_link_sequence.rb:
--------------------------------------------------------------------------------
1 | class CreateShortLinkSequence < ActiveRecord::Migration
2 | def up
3 | execute <<-SQL
4 | CREATE SEQUENCE short_link_seq;
5 | SQL
6 | end
7 |
8 | def down
9 | execute <<-SQL
10 | DROP SEQUENCE short_link_seq;
11 | SQL
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "hellolocker",
3 | "dependencies" : {
4 | "browserify": "~> 10.2.4",
5 | "browserify-incremental": "^3.0.1",
6 | "babelify": "~> 6.1.3",
7 | "hashids": "~> 1.0.2"
8 | },
9 | "devDependencies": {
10 | "chai": "~> 3.2.0",
11 | "mocha": "~> 2.2.5",
12 | "sinon": "~> 1.16.1"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/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 rake db:seed (or created alongside the db with db:setup).
3 | #
4 | # Examples:
5 | #
6 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
7 | # Mayor.create(name: 'Emanuel', city: cities.first)
8 |
--------------------------------------------------------------------------------
/app/controllers/labels_controller.rb:
--------------------------------------------------------------------------------
1 | class LabelsController < ApplicationController
2 | skip_before_action :authenticate_user!
3 |
4 | def show
5 | redirect_to item.url
6 | end
7 |
8 | private
9 |
10 | def item
11 | link.item
12 | end
13 |
14 | def link
15 | label = params[:label]
16 |
17 | Link.find_by(label: label)
18 | end
19 |
20 | end
21 |
--------------------------------------------------------------------------------
/deploy/ansible/deploy.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Load current git commit
3 | hosts: all
4 | connection: local
5 | tasks:
6 | - shell: "git log --pretty=format:'%h' -n 1"
7 | register: git_log_result
8 | ignore_errors: True
9 |
10 | - set_fact:
11 | git_ref: "{{git_log_result.stdout}}"
12 |
13 | - name: Deploy
14 | hosts: all
15 | roles:
16 | - nginx
--------------------------------------------------------------------------------
/app/models/settings.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: settings
4 | #
5 | # id :integer not null, primary key
6 | # var :string not null
7 | # value :text
8 | # thing_id :integer
9 | # thing_type :string(30)
10 | # created_at :datetime
11 | # updated_at :datetime
12 | #
13 |
14 | class Settings < RailsSettings::CachedSettings
15 | end
16 |
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 | Rails.application.routes.draw do
2 |
3 | if SingleUserMode.enabled?
4 | devise_for :users, skip: :registrations
5 | else
6 | devise_for :users
7 | end
8 |
9 | resource :dashboard, controller: "dashboard"
10 | resources :items do
11 | resources :links
12 | end
13 |
14 | root to: redirect('/dashboard')
15 |
16 | get "/:label" => "labels#show", as: "label_link"
17 |
18 | end
19 |
--------------------------------------------------------------------------------
/spec/factories/items.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: items
4 | #
5 | # id :integer not null, primary key
6 | # created_at :datetime not null
7 | # updated_at :datetime not null
8 | # url :string
9 | # user_id :integer
10 | #
11 |
12 | FactoryGirl.define do
13 |
14 | factory :item do
15 | url "http://example.com"
16 | user
17 | end
18 |
19 | end
20 |
--------------------------------------------------------------------------------
/spec/features/links_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.feature "Links" do
4 |
5 | scenario "redirect to full URL", :js do
6 | full_url = "http://example.com/"
7 | label = "nanana"
8 | short_item = create :item, url: full_url
9 | short_link = create :link, item: short_item, label: label
10 |
11 | visit "/#{label}"
12 |
13 | expect(current_url).to eq(full_url)
14 | end
15 |
16 | end
17 |
--------------------------------------------------------------------------------
/app/models/item.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: items
4 | #
5 | # id :integer not null, primary key
6 | # created_at :datetime not null
7 | # updated_at :datetime not null
8 | # url :string
9 | # user_id :integer
10 | #
11 |
12 | class Item < ActiveRecord::Base
13 | belongs_to :user
14 |
15 | has_many :links
16 |
17 | validates_presence_of :url, :user
18 | end
19 |
--------------------------------------------------------------------------------
/bin/rspec:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | #
3 | # This file was generated by Bundler.
4 | #
5 | # The application 'rspec' is installed as part of a gem, and
6 | # this file is here to facilitate running it.
7 | #
8 |
9 | require 'pathname'
10 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11 | Pathname.new(__FILE__).realpath)
12 |
13 | require 'rubygems'
14 | require 'bundler/setup'
15 |
16 | load Gem.bin_path('rspec-core', 'rspec')
17 |
--------------------------------------------------------------------------------
/deploy/ansible/roles/nginx/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Upload site configuration file
3 | sudo: yes
4 | template:
5 | src: hellolocker.com.j2
6 | dest: /etc/nginx/sites-available/hellolocker.com
7 | notify: restart nginx
8 |
9 | - name: Enable site
10 | sudo: yes
11 | file:
12 | src: /etc/nginx/sites-available/hellolocker.com
13 | dest: /etc/nginx/sites-enabled/hellolocker.com
14 | state: link
15 | notify: restart nginx
16 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/app/views/layouts/application.html.haml:
--------------------------------------------------------------------------------
1 | !!!
2 | %html
3 | %head
4 | %meta(charset="utf-8")
5 | %meta(content="IE=edge" http-equiv="X-UA-Compatible")
6 | %meta(content="width=device-width, initial-scale=1" name="viewport")
7 |
8 | %title Hellolocker
9 |
10 | = stylesheet_link_tag 'application', media: 'all'
11 | = javascript_include_tag 'application'
12 | = csrf_meta_tags
13 |
14 | %body
15 | = render "layouts/navigation"
16 | = yield
17 |
--------------------------------------------------------------------------------
/spec/models/short_label_sequence_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | RSpec.describe ShortLabelSequence do
4 |
5 | describe "#next" do
6 | it "returns a number" do
7 | num = ShortLabelSequence.next
8 |
9 | expect(num).to be_a(Numeric)
10 | end
11 |
12 | it "returns strictly rising numbers" do
13 | num1 = ShortLabelSequence.next
14 | num2 = ShortLabelSequence.next
15 |
16 | expect(num1).to be < num2
17 | end
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM phusion/passenger-ruby22:0.9.15
2 |
3 | # Enable passenger
4 | RUN rm -f /etc/service/nginx/down
5 |
6 | # Setup Rails app
7 | WORKDIR /home/app
8 |
9 | RUN rm /etc/nginx/sites-enabled/default
10 | ADD deploy/docker/nginx/rails-env.conf /etc/nginx/main.d/rails-env.conf
11 | ADD deploy/docker/nginx/hellolocker.com /etc/nginx/sites-enabled/hellolocker.com
12 |
13 |
14 | ADD Gemfile Gemfile.lock ./
15 | RUN bundle
16 |
17 | ADD . /home/app
18 | RUN bundle exec whenever --update-crontab
19 |
--------------------------------------------------------------------------------
/spec/factories/links.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: links
4 | #
5 | # id :integer not null, primary key
6 | # created_at :datetime not null
7 | # updated_at :datetime not null
8 | # label :string
9 | # item_id :integer
10 | # label_type :string
11 | #
12 |
13 | FactoryGirl.define do
14 |
15 | sequence :label do |n|
16 | "label-#{n}"
17 | end
18 |
19 | factory :link do
20 | label
21 | label_type "custom"
22 | end
23 |
24 | end
25 |
--------------------------------------------------------------------------------
/app/views/items/index.html.haml:
--------------------------------------------------------------------------------
1 | .container
2 | - if @items.any?
3 | .row
4 | List of items
5 |
6 | - @items.each do |item|
7 | .row
8 | %h2
9 | = item.url
10 | %ul
11 | - item.links.each do |link|
12 | %li
13 | = link_to label_url(link) do
14 | = label_url(link)
15 |
16 | %li
17 | = link_to new_item_link_path(item) do
18 | Add New
19 | - else
20 | .row
21 | No items available
22 |
--------------------------------------------------------------------------------
/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 | if match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m)
11 | Gem.paths = { "GEM_PATH" => [Bundler.bundle_path.to_s, *Gem.path].uniq }
12 | gem "spring", match[1]
13 | require "spring/binstub"
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/db/migrate/20150821152750_create_settings.rb:
--------------------------------------------------------------------------------
1 | class CreateSettings < ActiveRecord::Migration
2 | def self.up
3 | create_table :settings do |t|
4 | t.string :var, :null => false
5 | t.text :value, :null => true
6 | t.integer :thing_id, :null => true
7 | t.string :thing_type, :limit => 30, :null => true
8 | t.timestamps
9 | end
10 |
11 | add_index :settings, [ :thing_type, :thing_id, :var ], :unique => true
12 | end
13 |
14 | def self.down
15 | drop_table :settings
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/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 |
9 | # Precompile additional assets.
10 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
11 | # Rails.application.config.assets.precompile += %w( search.js )
12 |
--------------------------------------------------------------------------------
/.rubocop.yml:
--------------------------------------------------------------------------------
1 | AllCops:
2 | Include:
3 | - '**/Rakefile'
4 | - '**/config.ru'
5 | Exclude:
6 | - 'db/**/*'
7 | - 'config/**/*'
8 | - 'script/**/*'
9 |
10 | RunRailsCops: true
11 |
12 | # Indent private/protected/public as deep as method definitions
13 | Style/AccessModifierIndentation:
14 | EnforcedStyle: outdent
15 | SupportedStyles:
16 | - outdent
17 | - indent
18 |
19 | Metrics/LineLength:
20 | Enabled: false
21 |
22 | Style/StringLiterals:
23 | Enabled: false
24 |
25 | Style/EmptyLinesAroundBlockBody:
26 | Enabled: false
27 |
--------------------------------------------------------------------------------
/spec/support/devise.rb:
--------------------------------------------------------------------------------
1 | module FeatureSessionHelpers
2 | def create_user_and_login(*options)
3 | user = create :user, *options
4 |
5 | login_as(user)
6 |
7 | user
8 | end
9 |
10 | def single_user_login
11 | login_as(SingleUserMode.master_user)
12 | end
13 | end
14 |
15 | RSpec.configure do |config|
16 | config.include Warden::Test::Helpers
17 | config.include FeatureSessionHelpers, type: :feature
18 | config.include Devise::TestHelpers, type: :controller
19 |
20 | config.before :suite do
21 | Warden.test_mode!
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/config/schedule.rb:
--------------------------------------------------------------------------------
1 | # Use this file to easily define all of your cron jobs.
2 | #
3 | # It's helpful, but not entirely necessary to understand cron before proceeding.
4 | # http://en.wikipedia.org/wiki/Cron
5 |
6 | # Example:
7 | #
8 | # set :output, "/path/to/my/cron_log.log"
9 | #
10 | # every 2.hours do
11 | # command "/usr/bin/some_great_command"
12 | # runner "MyModel.some_method"
13 | # rake "some:great:rake:task"
14 | # end
15 | #
16 | # every 4.days do
17 | # runner "AnotherModel.prune_old_records"
18 | # end
19 |
20 | # Learn more: http://github.com/javan/whenever
21 |
--------------------------------------------------------------------------------
/app/controllers/links_controller.rb:
--------------------------------------------------------------------------------
1 | class LinksController < ApplicationController
2 | before_action :set_item
3 |
4 | def new
5 | @link = @item.links.build_short_link
6 | end
7 |
8 | def create
9 | @link = @item.links.build(link_params)
10 |
11 | if @link.save
12 | redirect_to items_path
13 | else
14 | render :new
15 | end
16 | end
17 |
18 | private
19 |
20 | def set_item
21 | @item = Item.find(params[:item_id])
22 | end
23 |
24 | def link_params
25 | params.require(:link).permit(:label, :short_id, :salt_count)
26 | end
27 |
28 | end
29 |
--------------------------------------------------------------------------------
/app/views/items/new.html.haml:
--------------------------------------------------------------------------------
1 | %h2 Create a new link
2 |
3 | - if @item.errors.any?
4 | %p
5 | Something went wrong:
6 | %ul
7 | - @item.errors.messages.each do |field, errors|
8 | %li
9 | = field
10 | = errors.to_sentence
11 |
12 | %p
13 | = form_for @item do |form|
14 | %p
15 | = form.label :url, "Full URL:"
16 | = form.text_field :url
17 |
18 | %p
19 | = fields_for @link do |link_form|
20 | = link_form.label :label, "http://hellolocker.com/"
21 | = link_form.text_field :label
22 |
23 | = form.submit "Create"
24 |
--------------------------------------------------------------------------------
/config/initializers/wrap_parameters.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # This file contains settings for ActionController::ParamsWrapper which
4 | # is enabled by default.
5 |
6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7 | ActiveSupport.on_load(:action_controller) do
8 | wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
9 | end
10 |
11 | # To enable root element in JSON for ActiveRecord objects.
12 | # ActiveSupport.on_load(:active_record) do
13 | # self.include_root_in_json = true
14 | # end
15 |
--------------------------------------------------------------------------------
/app/models/packer.rb:
--------------------------------------------------------------------------------
1 | class Packer
2 | TWO_CHAR_UPPER_BOUND = 43 # Numbers higher than this require one more character
3 |
4 | class << self
5 | delegate :pack, :unpack, :generate_single_segment_salt, to: :instance
6 | end
7 |
8 | def pack(data)
9 | hashids.encode(data)
10 | end
11 |
12 | def unpack(data)
13 | hashids.decode(data)
14 | end
15 |
16 | def generate_single_segment_salt
17 | Random.rand(TWO_CHAR_UPPER_BOUND + 1)
18 | end
19 |
20 | private
21 |
22 | def self.instance
23 | Packer.new
24 | end
25 |
26 | def hashids
27 | Hashids.new
28 | end
29 |
30 | end
31 |
--------------------------------------------------------------------------------
/.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 |
10 | # Ignore the default SQLite database.
11 | /db/*.sqlite3
12 | /db/*.sqlite3-journal
13 |
14 | # Ignore all logfiles and tempfiles.
15 | /log/*
16 | !/log/.keep
17 | /tmp
18 |
19 | # Ignore coveralls
20 | coverage
21 |
22 | # Ignore npm packages
23 | node_modules
24 |
--------------------------------------------------------------------------------
/spec/features/master_user_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.feature "Master User" do
4 |
5 | scenario "Can sign in" do
6 | visit root_path
7 | click_on t("layouts.navigation.sign_in")
8 |
9 | fill_in "Password", with: Rails.application.secrets.master_password
10 | click_on "Log in"
11 |
12 | expect(page).to have_content(t("layouts.navigation.sign_out"))
13 | end
14 |
15 | scenario "Can sign out" do
16 | single_user_login
17 | visit root_path
18 |
19 | click_link t("layouts.navigation.sign_out")
20 |
21 | expect(page).to have_content(t("layouts.navigation.sign_in"))
22 | end
23 |
24 | end
25 |
--------------------------------------------------------------------------------
/config/database.yml:
--------------------------------------------------------------------------------
1 | postgresql: &postgresql
2 | adapter: postgresql
3 | encoding: unicode
4 | pool: 5
5 |
6 | development:
7 | <<: *postgresql
8 | host: localhost
9 | database: hellolocker-development
10 | username: <%= ENV['USER'] %>
11 | password:
12 |
13 | # Warning: The database defined as "test" will be erased and
14 | # re-generated from your development database when you run "rake".
15 | # Do not set this db to the same as development or production.
16 | test:
17 | <<: *postgresql
18 | host: localhost
19 | database: hellolocker-test
20 | username: <%= ENV['USER'] %>
21 | password:
22 |
23 | production:
24 | url: <%= ENV['DATABASE_URL'] %>
25 |
--------------------------------------------------------------------------------
/app/controllers/items_controller.rb:
--------------------------------------------------------------------------------
1 | class ItemsController < ApplicationController
2 |
3 | def index
4 | @items = current_user.items
5 | end
6 |
7 | def new
8 | @item = current_user.items.new
9 | @link = @item.links.build_short_link
10 | end
11 |
12 | def create
13 | @item = current_user.items.new(item_params)
14 | @link = @item.links.new(link_params)
15 |
16 | if @item.save
17 | redirect_to items_path
18 | else
19 | render :new
20 | end
21 | end
22 |
23 | private
24 |
25 | def item_params
26 | params.require(:item).permit(:url)
27 | end
28 |
29 | def link_params
30 | params.require(:link).permit(:label, :short_id, :salt_count)
31 | end
32 |
33 | end
34 |
--------------------------------------------------------------------------------
/deploy/ansible/roles/nginx/templates/hellolocker.com.j2:
--------------------------------------------------------------------------------
1 | server {
2 | server_name hellolocker.com *.hellolocker.com;
3 |
4 | access_log /var/log/nginx/hellolocker.access.log;
5 | error_log /var/log/nginx/hellolocker.error.log;
6 |
7 | client_max_body_size 0;
8 | chunked_transfer_encoding on;
9 |
10 | location / {
11 | proxy_pass http://{{hellolocker_address}};
12 |
13 | proxy_set_header Host $http_host;
14 | proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP
15 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
16 | proxy_set_header X-Forwarded-Proto $scheme;
17 | proxy_read_timeout 900;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/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/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 | # To learn more, please read the Rails Internationalization guide
20 | # available at http://guides.rubyonrails.org/i18n.html.
21 |
22 | en:
23 | hello: "Hello world"
24 |
--------------------------------------------------------------------------------
/spec/support/rspec_utils.rb:
--------------------------------------------------------------------------------
1 | module RSpecUtils
2 |
3 | def outside_transaction
4 | if RSpec.configuration.use_transactional_fixtures || database_cleaner_strategy == :transaction
5 | raise <<-ERROR.strip_heredoc
6 | Using this method doesn't work very well if DatabaseCleaner or RSpec uses transactional fixtures.
7 | Consider setting the DatabaseCleaner strategy to :truncation.
8 | ERROR
9 | end
10 |
11 | Thread.new do
12 | ActiveRecord::Base.connection_pool.with_connection do
13 | yield
14 | end
15 | end.join
16 | end
17 |
18 | end
19 |
20 | RSpec.configure do |config|
21 | config.include RSpecUtils
22 |
23 | config.before(:each) do |example|
24 | @example = example
25 | end
26 | end
27 |
--------------------------------------------------------------------------------
/spec/models/item_spec.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: items
4 | #
5 | # id :integer not null, primary key
6 | # created_at :datetime not null
7 | # updated_at :datetime not null
8 | # url :string
9 | # user_id :integer
10 | #
11 |
12 | require 'rails_helper'
13 |
14 | RSpec.describe Item do
15 |
16 | it { expect(Item.new.links).not_to be_nil }
17 |
18 | describe "#url" do
19 | it "is invalid without" do
20 | item = build :item, url: nil
21 |
22 | expect(item).to be_invalid
23 | end
24 | end
25 |
26 | describe "#user" do
27 | it "is invalid without" do
28 | item = build :item, user: nil
29 |
30 | expect(item).to be_invalid
31 | end
32 | end
33 |
34 | end
35 |
--------------------------------------------------------------------------------
/spec/models/packer_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | RSpec.describe Packer do
4 |
5 | it "codes and decodes numbers" do
6 | data = [1,2,3]
7 | encoded = Packer.pack(data)
8 | decoded = Packer.unpack(encoded)
9 |
10 | expect(decoded).to eq(data)
11 | end
12 |
13 | context "#generate_single_segment_salt" do
14 | it "generates random salts" do
15 | salt1 = Packer.generate_single_segment_salt
16 | salt2 = Packer.generate_single_segment_salt
17 |
18 | expect(salt1).not_to eq(salt2)
19 | end
20 |
21 | it "generates numbers encodable in two characters" do
22 | salt = Packer.generate_single_segment_salt
23 | packed = Packer.pack(salt)
24 |
25 | expect(packed.length).to be <= 2
26 | end
27 | end
28 |
29 | end
30 |
--------------------------------------------------------------------------------
/app/views/layouts/_navigation.html.haml:
--------------------------------------------------------------------------------
1 | %nav.navbar.navbar-fixed-top.navbar-dark.bg-inverse
2 | = link_to "Hello Locker", root_url, class: "navbar-brand"
3 |
4 | %ul.nav.nav-pills
5 | %li.nav-item.active
6 | = link_to new_item_path, class: "nav-link" do
7 | New Item
8 | %span.sr-only (current)
9 |
10 | %li.nav-item
11 | = link_to "About", "#", class: "nav-link"
12 |
13 | %li.nav-item
14 | = link_to "Contact", "#", class: "nav-link"
15 |
16 | %ul.nav.nav-pills.pull-right
17 | - if signed_in?
18 | %li.nav-item
19 | = link_to t(".sign_out"), destroy_user_session_path, method: "DELETE", class: "nav-link"
20 |
21 | - else
22 | %li.nav-item
23 | = link_to t(".sign_in"), new_user_session_path, class: "nav-link"
24 |
--------------------------------------------------------------------------------
/app/views/devise/sessions/new.html.erb:
--------------------------------------------------------------------------------
1 |
Log in
2 |
3 | <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
4 | <% if !SingleUserMode.enabled? %>
5 |
6 | <%= f.label :email %>
7 | <%= f.email_field :email, autofocus: true %>
8 |
9 | <% end %>
10 |
11 |
12 | <%= f.label :password %>
13 | <%= f.password_field :password, autocomplete: "off" %>
14 |
15 |
16 | <% if devise_mapping.rememberable? -%>
17 |
18 | <%= f.check_box :remember_me %>
19 | <%= f.label :remember_me %>
20 |
21 | <% end -%>
22 |
23 |
24 | <%= f.submit "Log in" %>
25 |
26 | <% end %>
27 |
28 | <%= render "devise/shared/links" %>
29 |
--------------------------------------------------------------------------------
/app/assets/javascripts/application.js:
--------------------------------------------------------------------------------
1 | // This is a manifest file that'll be compiled into application.js, which will include all the files
2 | // listed below.
3 | //
4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5 | // or any plugin's 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.
9 | //
10 | // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11 | // about supported directives.
12 | //
13 | //= require jquery
14 | //= require jquery_ujs
15 | //= require tether
16 | //= require bootstrap-sprockets
17 | //= require react
18 | //= require react_ujs
19 | //= require components
20 |
--------------------------------------------------------------------------------
/app/models/single_user_mode.rb:
--------------------------------------------------------------------------------
1 | class SingleUserMode
2 |
3 | def self.enabled?
4 | true
5 | end
6 |
7 | def self.master_user
8 | User.find_by!(master: true)
9 |
10 | rescue ActiveRecord::RecordNotFound
11 | create_master_user!
12 | retry
13 | end
14 |
15 | def self.create_master_user!
16 | User.transaction do
17 | our_master_user = User.create(master: true)
18 |
19 | ensure_only_one_master_or_rollback!(our_master_user)
20 | end
21 | end
22 |
23 | private
24 |
25 | def self.ensure_only_one_master_or_rollback!(our_master_user)
26 | if User.where(master: true).many?
27 | first_master_user = User.where(master: true).order(created_at: "ASC").first
28 |
29 | if first_master_user != our_master_user
30 | raise ActiveRecord::Rollback, "There can be only one (master user)"
31 | end
32 | end
33 | end
34 |
35 | end
36 |
--------------------------------------------------------------------------------
/spec/controllers/items_controller_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe ItemsController, type: :controller do
4 |
5 | before :each do
6 | @user = create :user
7 |
8 | sign_in(@user)
9 | end
10 |
11 | describe "GET #new" do
12 | it "generates an item and a short link" do
13 | get :new
14 |
15 | expect(assigns(:item)).not_to be_nil
16 | expect(assigns(:link).label).not_to be_blank
17 | end
18 | end
19 |
20 | describe "POST #create" do
21 |
22 | it "creates a new item for this user" do
23 | exercise = -> do
24 | post :create,
25 | link: FactoryGirl.attributes_for(:link),
26 | item: FactoryGirl.attributes_for(:item)
27 | end
28 |
29 | expect(exercise).to change(Link, :count).and change(Item, :count)
30 |
31 | expect(assigns(:item).user).to eq(@user)
32 | end
33 | end
34 |
35 | end
36 |
--------------------------------------------------------------------------------
/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 any plugin's vendor/assets/stylesheets directory 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 bottom of the
9 | * compiled file so the styles you add here take precedence over styles defined in any styles
10 | * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11 | * file per style scope.
12 | *
13 | *= require_tree .
14 | *= require_self
15 | */
16 |
17 | // Custom bootstrap variables must be set or import before bootstrap itself.
18 | @import "bootstrap";
19 | @import "navigation";
20 |
--------------------------------------------------------------------------------
/bin/setup:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | require 'pathname'
3 |
4 | # path to your application root.
5 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
6 |
7 | Dir.chdir APP_ROOT do
8 | # This script is a starting point to setup your application.
9 | # Add necessary setup steps to this file:
10 |
11 | puts "== Installing dependencies =="
12 | system "gem install bundler --conservative"
13 | system "bundle check || bundle install"
14 |
15 | # puts "\n== Copying sample files =="
16 | # unless File.exist?("config/database.yml")
17 | # system "cp config/database.yml.sample config/database.yml"
18 | # end
19 |
20 | puts "\n== Preparing database =="
21 | system "bin/rake db:setup"
22 |
23 | puts "\n== Removing old logs and tempfiles =="
24 | system "rm -f log/*"
25 | system "rm -rf tmp/cache"
26 |
27 | puts "\n== Restarting application server =="
28 | system "touch tmp/restart.txt"
29 | end
30 |
--------------------------------------------------------------------------------
/spec/models/label_maker_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | RSpec.describe LabelMaker do
4 |
5 | context "#generate_short_label" do
6 | it "generates a short label" do
7 | label_maker = LabelMaker.new
8 | label = label_maker.generate_short_label(salt_count: 5, index: 111)
9 |
10 | expect(label).not_to be_nil
11 | end
12 |
13 | it "generates different labels with same salt_count and index" do
14 | label1 = LabelMaker.new.generate_short_label(salt_count: 5, index: 111)
15 | label2 = LabelMaker.new.generate_short_label(salt_count: 5, index: 111)
16 |
17 | expect(label1).not_to eq(label2)
18 | end
19 |
20 | it "generates longer label when higher salt_count" do
21 | label1 = LabelMaker.new.generate_short_label(salt_count: 1, index: 111)
22 | label2 = LabelMaker.new.generate_short_label(salt_count: 10, index: 111)
23 |
24 | expect(label1.length).to be < label2.length
25 | end
26 | end
27 |
28 | end
29 |
--------------------------------------------------------------------------------
/spec/models/single_user_mode_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe SingleUserMode do
4 |
5 | it "is enabled" do
6 | expect(SingleUserMode).to be_enabled
7 | end
8 |
9 | it "has a master user" do
10 | user = SingleUserMode.master_user
11 |
12 | expect(user).not_to be_nil
13 | expect(user).to be_master
14 | end
15 |
16 | it "creates a master user and avoids doubles", :clean_with_truncation do
17 | our_master_user = create(:user)
18 |
19 | expect(SingleUserMode).to receive(:ensure_only_one_master_or_rollback!)
20 | .and_wrap_original do |original, their_master_user|
21 |
22 | outside_transaction do
23 | our_master_user.update_attribute(:master, true)
24 | end
25 |
26 | original.call(their_master_user)
27 | end
28 |
29 | returned_master_user = SingleUserMode.master_user
30 |
31 | expect(User.where(master: true).many?).to be_falsy
32 | expect(returned_master_user).to eq(our_master_user)
33 | end
34 |
35 | end
36 |
--------------------------------------------------------------------------------
/app/models/link.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: links
4 | #
5 | # id :integer not null, primary key
6 | # created_at :datetime not null
7 | # updated_at :datetime not null
8 | # label :string
9 | # item_id :integer
10 | # label_type :string
11 | #
12 |
13 | class Link < ActiveRecord::Base
14 | LABEL_TYPES = %w(short guid custom)
15 |
16 | belongs_to :item
17 |
18 | validates :label, presence: true, uniqueness: true
19 | validates :label_type, inclusion: {in: LABEL_TYPES}
20 |
21 | attr_accessor :short_id, :salt_count
22 |
23 | def url(options = {})
24 | options[:label] = label
25 |
26 | Rails.application.routes.url_helpers.label_link_url(options)
27 | end
28 |
29 | def self.build_short_link
30 | salt_count = 1
31 | short_id = ShortLabelSequence.next
32 | label = LabelMaker.new.generate_short_label(salt_count: salt_count, index: short_id)
33 |
34 | new(label_type: "short", label: label, salt_count: salt_count, short_id: short_id)
35 | end
36 |
37 | end
38 |
--------------------------------------------------------------------------------
/spec/support/database_cleaner.rb:
--------------------------------------------------------------------------------
1 | module DatabaseCleanerUtils
2 |
3 | attr :database_cleaner_strategy
4 |
5 | def set_database_cleaner_strategy(strategy)
6 | DatabaseCleaner.strategy = strategy
7 | @database_cleaner_strategy = strategy
8 | end
9 |
10 | end
11 |
12 | # Thank you Avdi - http://devblog.avdi.org/2012/08/31/configuring-database_cleaner-with-rails-rspec-capybara-and-selenium/
13 | RSpec.configure do |config|
14 |
15 | config.include DatabaseCleanerUtils
16 |
17 | config.before(:suite) do
18 | DatabaseCleaner.clean_with(:truncation)
19 | end
20 |
21 | config.before(:each) do
22 | set_database_cleaner_strategy(:transaction)
23 | end
24 |
25 | config.before(:each, :clean_with_truncation) do
26 | set_database_cleaner_strategy(:truncation)
27 | end
28 |
29 | config.before(:each, :js) do
30 | set_database_cleaner_strategy(:truncation)
31 | end
32 |
33 | config.before(:each) do
34 | DatabaseCleaner.start
35 | end
36 |
37 | config.after(:each) do
38 | DatabaseCleaner.clean
39 | end
40 |
41 | end
42 |
--------------------------------------------------------------------------------
/spec/factories/users.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: users
4 | #
5 | # id :integer not null, primary key
6 | # email :string default(""), not null
7 | # encrypted_password :string default(""), not null
8 | # reset_password_token :string
9 | # reset_password_sent_at :datetime
10 | # remember_created_at :datetime
11 | # sign_in_count :integer default(0), not null
12 | # current_sign_in_at :datetime
13 | # last_sign_in_at :datetime
14 | # current_sign_in_ip :string
15 | # last_sign_in_ip :string
16 | # created_at :datetime
17 | # updated_at :datetime
18 | # master :boolean default(FALSE)
19 | #
20 |
21 | FactoryGirl.define do
22 | sequence :email do |n|
23 | "my-#{n.ordinalize}-favorite-person@example.com"
24 | end
25 |
26 | factory :user do
27 | email
28 | password "password"
29 |
30 | factory :master do
31 | master true
32 | end
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/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 `rake 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 | development:
14 | secret_key_base: 167d4bf50182bc416f9c6f44435df55c94898dad73ef29b930605a0b3ebc2aec96f9df36f2d5002240788addf957d8a5532507343eec71f9097935230019566c
15 | master_password: password
16 |
17 | test:
18 | secret_key_base: 75f0204fc8b8e037eb911a47ff00cc17c35f17dcddec2dc716d8dc7b1ba5787a0699c0c4b7d5295e894cfed607bd4f3510e791484286f74f3b95f68af2677e15
19 | master_password: password
20 |
21 | # Do not keep production secrets in the repository,
22 | # instead read values from the environment.
23 | production:
24 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
25 | master_password: <%= ENV["MASTER_PASSWORD"] %>
26 |
--------------------------------------------------------------------------------
/spec/features/items_spec.rb:
--------------------------------------------------------------------------------
1 | require "rails_helper"
2 |
3 | RSpec.describe "Items" do
4 |
5 | scenario "can be created with a default short label" do
6 | full_url = "http://example.com/"
7 | user = create_user_and_login
8 |
9 | visit new_item_path
10 |
11 | fill_in "item[url]", with: full_url
12 | click_on "Create"
13 |
14 | expect(page).to have_content(full_url)
15 | end
16 |
17 | scenario "can be created with a custom label" do
18 | full_url = "http://example.com/"
19 | label = "nanana"
20 | user = create_user_and_login
21 |
22 | visit new_item_path
23 |
24 | fill_in "item[url]", with: full_url
25 | fill_in "link[label]", with: label
26 | click_on "Create"
27 |
28 | expect(page).to have_content(full_url)
29 | expect(page).to have_content(label)
30 | end
31 |
32 | scenario "can add another link" do
33 | item = create :item
34 | label = "batmananana"
35 | first_link = create :link, item: item
36 |
37 | visit new_item_link_path(item)
38 |
39 | fill_in "link[label]", with: label
40 | click_on "Create"
41 |
42 | expect(item.links.last.label).to eq(label)
43 | end
44 | end
45 |
--------------------------------------------------------------------------------
/db/migrate/20150731130331_devise_create_users.rb:
--------------------------------------------------------------------------------
1 | class DeviseCreateUsers < ActiveRecord::Migration
2 | def change
3 | create_table(:users) do |t|
4 | ## Database authenticatable
5 | t.string :email, null: false, default: ""
6 | t.string :encrypted_password, null: false, default: ""
7 |
8 | ## Recoverable
9 | t.string :reset_password_token
10 | t.datetime :reset_password_sent_at
11 |
12 | ## Rememberable
13 | t.datetime :remember_created_at
14 |
15 | ## Trackable
16 | t.integer :sign_in_count, default: 0, null: false
17 | t.datetime :current_sign_in_at
18 | t.datetime :last_sign_in_at
19 | t.string :current_sign_in_ip
20 | t.string :last_sign_in_ip
21 |
22 | ## Confirmable
23 | # t.string :confirmation_token
24 | # t.datetime :confirmed_at
25 | # t.datetime :confirmation_sent_at
26 | # t.string :unconfirmed_email # Only if using reconfirmable
27 |
28 | ## Lockable
29 | # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
30 | # t.string :unlock_token # Only if unlock strategy is :email or :both
31 | # t.datetime :locked_at
32 |
33 |
34 | t.timestamps
35 | end
36 |
37 | add_index :users, :email, unique: true
38 | add_index :users, :reset_password_token, unique: true
39 | # add_index :users, :confirmation_token, unique: true
40 | # add_index :users, :unlock_token, unique: true
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/config/application.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../boot', __FILE__)
2 |
3 | require 'rails/all'
4 |
5 | # Require the gems listed in Gemfile, including any gems
6 | # you've limited to :test, :development, or :production.
7 | Bundler.require(*Rails.groups)
8 |
9 | module Hellolocker
10 | class Application < Rails::Application
11 | # Settings in config/environments/* take precedence over those specified here.
12 | # Application configuration should go into files in config/initializers
13 | # -- all .rb files in that directory are automatically loaded.
14 |
15 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
16 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
17 | # config.time_zone = 'Central Time (US & Canada)'
18 |
19 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
20 | config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')]
21 | # config.i18n.default_locale = :de
22 |
23 | # Do not swallow errors in after_commit/after_rollback callbacks.
24 | config.active_record.raise_in_transactional_callbacks = true
25 |
26 | # Dump schema as SQL
27 | config.active_record.schema_format = :sql
28 |
29 | # React settings
30 | config.react.server_renderer_options = {
31 | # files: ["react.js", "components.js"], # files to load for prerendering
32 | replay_console: true, # if true, console.* will be replayed client-side
33 | }
34 |
35 | config.react.addons = true
36 | end
37 | end
38 |
--------------------------------------------------------------------------------
/config/initializers/browserify.rb:
--------------------------------------------------------------------------------
1 | # Transform ES6 & JSX files using babel
2 | Rails.application.config.browserify_rails.commandline_options = " -t babelify"
3 |
4 | # Add /spec to paths
5 | Rails.application.config.browserify_rails.paths << /spec\/javascripts\//
6 |
7 | # # Paths, that should be browserified. We browserify everything, that
8 | # # matches (===) one of the paths. So you will most likely put lambdas
9 | # # regexes in here.
10 | # #
11 | # # By default only files in /app and /node_modules are browserified,
12 | # # vendor stuff is normally not made for browserification and may stop
13 | # # working.
14 | # config.browserify_rails.paths << /vendor\/assets\/javascripts\/module\.js/
15 |
16 | # # Environments, in which to generate source maps
17 | # #
18 | # # The default is none
19 | # config.browserify_rails.source_map_environments << "development"
20 |
21 | # # Should the node_modules directory be evaluated for changes on page load
22 | # #
23 | # # The default is `false`
24 | # config.browserify_rails.evaluate_node_modules = true
25 |
26 | # # Force browserify on every found JavaScript asset
27 | # #
28 | # # The default is `false`
29 | # config.browserify_rails.force = true
30 |
31 | # # Command line options used when running browserify
32 | # #
33 | # # can be provided as an array:
34 | # config.browserify_rails.commandline_options = ["-t browserify-shim", "--fast"]
35 |
36 | # # or as a string:
37 | # config.browserify_rails.commandline_options = "-t browserify-shim --fast"
38 |
39 | # # Define NODE_ENV to be used with envify
40 | # #
41 | # # defaults to Rails.env
42 | # config.browserify_rails.node_env = "production"
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 and disable caching.
13 | config.consider_all_requests_local = true
14 | config.action_controller.perform_caching = false
15 |
16 | # Don't care if the mailer can't send.
17 | config.action_mailer.raise_delivery_errors = false
18 |
19 | # Print deprecation notices to the Rails logger.
20 | config.active_support.deprecation = :log
21 |
22 | # Raise an error on page load if there are pending migrations.
23 | config.active_record.migration_error = :page_load
24 |
25 | # Debug mode disables concatenation and preprocessing of assets.
26 | # This option may cause significant delays in view rendering with a large
27 | # number of complex assets.
28 | config.assets.debug = true
29 |
30 | # Asset digests allow you to set far-future HTTP expiration dates on all assets,
31 | # yet still be able to expire them through the digest params.
32 | config.assets.digest = true
33 |
34 | # Adds additional error checking when serving assets at runtime.
35 | # Checks for improperly declared sprockets dependencies.
36 | # Raises helpful error messages.
37 | config.assets.raise_runtime_errors = true
38 |
39 | # Raises error for missing translations
40 | # config.action_view.raise_on_missing_translations = true
41 | end
42 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/spec/models/link_spec.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: links
4 | #
5 | # id :integer not null, primary key
6 | # created_at :datetime not null
7 | # updated_at :datetime not null
8 | # label :string
9 | # item_id :integer
10 | # label_type :string
11 | #
12 |
13 | require 'rails_helper'
14 |
15 | RSpec.describe Link, type: :model do
16 | it "cannot have the same label as another link" do
17 | label = "abc"
18 | create :link, label: label
19 |
20 | link = build :link, label: label
21 |
22 | expect(link).to be_invalid
23 | end
24 |
25 | it "is invalid with an empty label" do
26 | link = build :link, label: nil
27 |
28 | expect(link).to be_invalid
29 | end
30 |
31 | describe "#url" do
32 | it "returns the full URL with label" do
33 | host = "example.com"
34 | Rails.application.routes.default_url_options[:host] = host
35 | label = "boo"
36 |
37 | link = build :link, label: label
38 |
39 | expect(link.url).to eq("http://#{host}/#{label}")
40 | end
41 | end
42 |
43 | describe ".build_short_link" do
44 | it "generates a Link" do
45 | link = Link.build_short_link
46 |
47 | expect(link).not_to be_nil
48 | expect(link).to be_valid
49 | expect(link.label_type).to eq("short")
50 | end
51 | end
52 |
53 | describe "#label_type" do
54 | it "can not be empty" do
55 | link = build :link, label_type: ""
56 |
57 | expect(link).to be_invalid
58 | end
59 |
60 | it "needs to be from the list" do
61 | link = build :link, label_type: "nananana"
62 |
63 | expect(link).to be_invalid
64 | end
65 |
66 | it "can be custom" do
67 | link = build :link, label_type: "custom"
68 |
69 | expect(link).to be_valid
70 | end
71 | end
72 |
73 | end
74 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 static file server for tests with Cache-Control for performance.
16 | config.serve_static_files = true
17 | config.static_cache_control = 'public, max-age=3600'
18 |
19 | # Show full error reports and disable caching.
20 | config.consider_all_requests_local = true
21 | config.action_controller.perform_caching = false
22 |
23 | # Raise exceptions instead of rendering exception templates.
24 | config.action_dispatch.show_exceptions = false
25 |
26 | # Disable request forgery protection in test environment.
27 | config.action_controller.allow_forgery_protection = false
28 |
29 | # Tell Action Mailer not to deliver emails to the real world.
30 | # The :test delivery method accumulates sent emails in the
31 | # ActionMailer::Base.deliveries array.
32 | config.action_mailer.delivery_method = :test
33 |
34 | # Randomize the order test cases are executed.
35 | config.active_support.test_order = :random
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 |
--------------------------------------------------------------------------------
/spec/javascripts/spec_helper.js:
--------------------------------------------------------------------------------
1 | // Teaspoon includes some support files, but you can use anything from your own support path too.
2 | // require support/expect
3 | // require support/sinon
4 | //= require support/chai
5 | // require support/chai-jq-0.0.7
6 | // require support/your-support-file
7 | //
8 | // PhantomJS (Teaspoons default driver) doesn't have support for Function.prototype.bind, which has caused confusion.
9 | // Use this polyfill to avoid the confusion.
10 | //= require support/bind-poly
11 | //
12 | // You can require your own javascript files here. By default this will include everything in application, however you
13 | // may get better load performance if you require the specific files that are being used in the spec that tests them.
14 | //= require application
15 | //
16 | // Deferring execution
17 | // If you're using CommonJS, RequireJS or some other asynchronous library you can defer execution. Call
18 | // Teaspoon.execute() after everything has been loaded. Simple example of a timeout:
19 | //
20 | // Teaspoon.defer = true
21 | // setTimeout(Teaspoon.execute, 1000)
22 | //
23 | // Matching files
24 | // By default Teaspoon will look for files that match _spec.{js,js.coffee,.coffee}. Add a filename_spec.js file in your
25 | // spec path and it'll be included in the default suite automatically. If you want to customize suites, check out the
26 | // configuration in teaspoon_env.rb
27 | //
28 | // Manifest
29 | // If you'd rather require your spec files manually (to control order for instance) you can disable the suite matcher in
30 | // the configuration and use this file as a manifest.
31 | //
32 | // For more information: http://github.com/modeset/teaspoon
33 | //
34 | // Chai
35 | // If you're using Chai, you'll probably want to initialize your preferred assertion style. You can read more about Chai
36 | // at: http://chaijs.com/guide/styles
37 | //
38 | // window.assert = chai.assert;
39 | window.expect = chai.expect;
40 | // window.should = chai.should();
41 |
--------------------------------------------------------------------------------
/app/models/user.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: users
4 | #
5 | # id :integer not null, primary key
6 | # email :string default(""), not null
7 | # encrypted_password :string default(""), not null
8 | # reset_password_token :string
9 | # reset_password_sent_at :datetime
10 | # remember_created_at :datetime
11 | # sign_in_count :integer default(0), not null
12 | # current_sign_in_at :datetime
13 | # last_sign_in_at :datetime
14 | # current_sign_in_ip :string
15 | # last_sign_in_ip :string
16 | # created_at :datetime
17 | # updated_at :datetime
18 | # master :boolean default(FALSE)
19 | #
20 |
21 | class User < ActiveRecord::Base
22 | # Include default devise modules. Others available are:
23 | # :confirmable, :lockable, :timeoutable and :omniauthable
24 | if SingleUserMode.enabled?
25 | # In Single User mode Devise doesn't need an email for the strategy to become valid
26 | # nor does anyone need to register.
27 | devise :database_authenticatable,
28 | :recoverable, :rememberable, :trackable, :validatable, authentication_keys: {email: false}
29 | else
30 | devise :database_authenticatable,
31 | :recoverable, :rememberable, :trackable, :validatabled, :registerable
32 | end
33 |
34 | has_many :items
35 |
36 | validates_uniqueness_of :master, if: :master
37 |
38 | def valid_password?(maybe_password)
39 | if master
40 | Devise.secure_compare(maybe_password, Rails.application.secrets.master_password)
41 | else
42 | super
43 | end
44 | end
45 |
46 | def self.find_first_by_auth_conditions(*)
47 | if SingleUserMode.enabled?
48 | SingleUserMode.master_user
49 | else
50 | super
51 | end
52 | end
53 |
54 | private
55 |
56 | def password_required?
57 | !master && super
58 | end
59 |
60 | def email_required?
61 | !master && super
62 | end
63 |
64 | end
65 |
--------------------------------------------------------------------------------
/db/schema.rb:
--------------------------------------------------------------------------------
1 | # encoding: UTF-8
2 | # This file is auto-generated from the current state of the database. Instead
3 | # of editing this file, please use the migrations feature of Active Record to
4 | # incrementally modify your database, and then regenerate this schema definition.
5 | #
6 | # Note that this schema.rb definition is the authoritative source for your
7 | # database schema. If you need to create the application database on another
8 | # system, you should be using db:schema:load, not running all the migrations
9 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10 | # you'll amass, the slower it'll run and the greater likelihood for issues).
11 | #
12 | # It's strongly recommended that you check this file into your version control system.
13 |
14 | ActiveRecord::Schema.define(version: 20150821150455) do
15 |
16 | create_table "items", force: :cascade do |t|
17 | t.datetime "created_at", null: false
18 | t.datetime "updated_at", null: false
19 | t.string "url"
20 | end
21 |
22 | create_table "links", force: :cascade do |t|
23 | t.datetime "created_at", null: false
24 | t.datetime "updated_at", null: false
25 | t.string "label"
26 | t.integer "item_id"
27 | t.string "type"
28 | end
29 |
30 | add_index "links", ["label"], name: "index_links_on_label", unique: true
31 |
32 | create_table "users", force: :cascade do |t|
33 | t.string "email", default: "", null: false
34 | t.string "encrypted_password", default: "", null: false
35 | t.string "reset_password_token"
36 | t.datetime "reset_password_sent_at"
37 | t.datetime "remember_created_at"
38 | t.integer "sign_in_count", default: 0, null: false
39 | t.datetime "current_sign_in_at"
40 | t.datetime "last_sign_in_at"
41 | t.string "current_sign_in_ip"
42 | t.string "last_sign_in_ip"
43 | t.datetime "created_at"
44 | t.datetime "updated_at"
45 | t.boolean "master", default: false
46 | end
47 |
48 | add_index "users", ["email"], name: "index_users_on_email", unique: true
49 | add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
50 |
51 | end
52 |
--------------------------------------------------------------------------------
/deploy/ansible/roles/docker/tasks/main.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: Set vars
3 | set_fact:
4 | docker_image: "hellolocker:{{git_ref}}"
5 | docker_container: "hellolocker-{{git_ref}}-1"
6 |
7 | - name: Install pip for docker-py
8 | sudo: yes
9 | easy_install:
10 | name: pip
11 |
12 | - name: Install docker-py
13 | pip:
14 | name: docker-py
15 |
16 | - name: Download repository
17 | git:
18 | accept_hostkey: yes
19 | clone: yes
20 | dest: /tmp/hellolocker
21 | repo: git://github.com/dv/hellolocker.git
22 | version: "{{git_ref}}"
23 | update: yes
24 |
25 | - name: Build Docker image
26 | sudo: yes
27 | shell: "docker build -t '{{docker_image}}' ."
28 | args:
29 | chdir: /tmp/hellolocker
30 |
31 | - name: Tag Docker image as latest
32 | sudo: yes
33 | shell: "docker tag -f '{{docker_image}}' 'hellolocker:latest'"
34 |
35 | - name: Run migrations in container
36 | sudo: yes
37 | docker:
38 | name: "{{docker_container}}-migrations"
39 | image: "{{docker_image}}"
40 | docker_api_version: 1.18
41 | command: "bundle exec rake db:migrate"
42 | env:
43 | RAILS_ENV: "production"
44 | DATABASE_URL: "{{ database_url }}"
45 | SECRET_KEY_BASE: "{{ secret_key_base }}"
46 |
47 | - name: "Remove migration container"
48 | sudo: yes
49 | docker:
50 | name: "{{docker_container}}-migrations"
51 | image: "{{docker_image}}"
52 | docker_api_version: 1.18
53 | state: absent
54 |
55 | - name: Run Docker container
56 | sudo: yes
57 | docker:
58 | name: "{{docker_container}}"
59 | image: "{{docker_image}}"
60 | docker_api_version: 1.18
61 | ports: 80
62 | env:
63 | DATABASE_URL: "{{ database_url }}"
64 | SECRET_KEY_BASE: "{{ secret_key_base }}"
65 | MASTER_PASSWORD: "{{ master_password }}"
66 |
67 | - name: Fetch containers older than last 5
68 | sudo: yes
69 | shell: "sudo docker ps -f 'name=hellolocker' -q | tail -n +6"
70 | register: old_containers
71 |
72 | - name: Stop old containers
73 | sudo: yes
74 | shell: "docker stop {{ item }}"
75 | with_items: "{{old_containers.stdout_lines}}"
76 |
77 | - name: Get exposed address
78 | sudo: yes
79 | shell: "docker port '{{docker_container}}' 80"
80 | register: port_result
81 |
82 | - name: Save exposed address
83 | set_fact:
84 | hellolocker_address: "{{port_result.stdout}}"
85 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://coveralls.io/github/dv/hellolocker?branch=master)
2 | [](https://codeclimate.com/github/dv/hellolocker)
3 | 
4 |
5 | # Development
6 |
7 | ## Guard
8 |
9 | Guard uses `terminal-notifier-guard` and thus needs `terminal-notifier` installed:
10 |
11 | ```
12 | $ brew install terminal-notifier
13 | ```
14 |
15 | Then just run guard:
16 |
17 | ```
18 | $ guard
19 | ```
20 |
21 | # Testing
22 |
23 | Make sure a PostgreSQL database is running. For example:
24 |
25 | ```
26 | docker run --rm --name postgresql -e POSTGRES_PASSWORD=postgres -p 5432 postgres
27 | ```
28 |
29 | If you're running `boot2docker` (a requirement on Mac OS X), forward port 5432 to the docker Host as well:
30 |
31 | ```
32 | # Run vagrant global-status to get the ID of `boot2docker`
33 | VAGRANT_ID = vagrant global-status | grep boot2docker | awk '{print $1}'
34 | vagrant ssh $VAGRANT_ID -- -N -L 5432:localhost:5432
35 | ```
36 |
37 | Or easily in one command if you're running dockup:
38 |
39 | ```
40 | dockssh -N -L 5432:localhost:5432
41 | ```
42 |
43 | # Deployment
44 |
45 |
46 | ```
47 | ansible-playbook \
48 | -u deployer \
49 | -i "hellolocker.com," \
50 | --extra-vars "database_url=postgresql://user:pass@localhost/my_databaseans" \
51 | --extra-vars "secret_key_base=randomtokenhere" \
52 | deploy/ansible/deploy.yml
53 |
54 | # Start Rails app
55 | curl http://hellolocker.com
56 | ```
57 |
58 | ## Configure Database
59 |
60 | HelloLocker will use the `DATABASE_URL` environment variable to connect to the database. This should be of the form:
61 |
62 | ```
63 | postgresql://user:pass@localhost/database_name?pool=5
64 | ```
65 |
66 | ## Docker
67 |
68 | I'm mounting the `/var/run/postgresql` directory as a volume for the HelloLocker container so it can connect to it. You might want to change this to suit your needs.
69 |
70 | ### Nginx configuration
71 |
72 | We add `env DATABASE_URL` so Nginx wouldn't flush this variable from the environment before booting Passenger.
73 |
74 | # Continuous Integration
75 |
76 | ## Codeship
77 |
78 | We use Codeship. To set it up, add the following lines to the "setup" part:
79 |
80 | ```
81 | pip install ansible
82 | ```
83 |
--------------------------------------------------------------------------------
/spec/rails_helper.rb:
--------------------------------------------------------------------------------
1 | # This file is copied to spec/ when you run 'rails generate rspec:install'
2 | ENV['RAILS_ENV'] ||= 'test'
3 | require 'spec_helper'
4 | require File.expand_path('../../config/environment', __FILE__)
5 | require 'rspec/rails'
6 | # Add additional requires below this line. Rails is not loaded until this point!
7 |
8 | # Requires supporting ruby files with custom matchers and macros, etc, in
9 | # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
10 | # run as spec files by default. This means that files in spec/support that end
11 | # in _spec.rb will both be required and run as specs, causing the specs to be
12 | # run twice. It is recommended that you do not name files matching this glob to
13 | # end with _spec.rb. You can configure this pattern with the --pattern
14 | # option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
15 | #
16 | # The following line is provided for convenience purposes. It has the downside
17 | # of increasing the boot-up time by auto-requiring all files in the support
18 | # directory. Alternatively, in the individual `*_spec.rb` files, manually
19 | # require only the support files necessary.
20 | #
21 | Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
22 |
23 | # Checks for pending migrations before tests are run.
24 | # If you are not using ActiveRecord, you can remove this line.
25 | ActiveRecord::Migration.maintain_test_schema!
26 |
27 | RSpec.configure do |config|
28 | # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
29 | config.fixture_path = "#{::Rails.root}/spec/fixtures"
30 |
31 | # If you're not using ActiveRecord, or you'd prefer not to run each of your
32 | # examples within a transaction, remove the following line or assign false
33 | # instead of true.
34 | config.use_transactional_fixtures = false
35 |
36 | # RSpec Rails can automatically mix in different behaviours to your tests
37 | # based on their file location, for example enabling you to call `get` and
38 | # `post` in specs under `spec/controllers`.
39 | #
40 | # You can disable this behaviour by removing the line below, and instead
41 | # explicitly tag your specs with their type, e.g.:
42 | #
43 | # RSpec.describe UsersController, :type => :controller do
44 | # # ...
45 | # end
46 | #
47 | # The different available types are documented in the features, such as in
48 | # https://relishapp.com/rspec/rspec-rails/docs
49 | config.infer_spec_type_from_file_location!
50 | end
51 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 |
4 | # Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
5 | gem 'rails', '4.2.1'
6 | gem 'pg'
7 |
8 | # Use SCSS for stylesheets
9 | gem 'sass-rails', '~> 5.0'
10 |
11 | # Use Uglifier as compressor for JavaScript assets
12 | gem 'uglifier', '>= 1.3.0'
13 | # Use CoffeeScript for .coffee assets and views
14 | gem 'coffee-rails', '~> 4.1.0'
15 | # See https://github.com/rails/execjs#readme for more supported runtimes
16 | # gem 'therubyracer', platforms: :ruby
17 |
18 | # Use jquery as the JavaScript library
19 | gem 'jquery-rails'
20 | # Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
21 | gem 'turbolinks'
22 | # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
23 | gem 'jbuilder', '~> 2.0'
24 | # bundle exec rake doc:rails generates the API under doc/api.
25 | gem 'sdoc', '~> 0.4.0', group: :doc
26 |
27 | # Use ActiveModel has_secure_password
28 | # gem 'bcrypt', '~> 3.1.7'
29 |
30 | # Use Unicorn as the app server
31 | gem 'thin'
32 |
33 | # Use Capistrano for deployment
34 | # gem 'capistrano-rails', group: :development
35 | gem 'devise'
36 |
37 | gem 'whenever', require: false
38 |
39 | gem 'haml-rails'
40 | gem 'hashids'
41 | gem 'rails-settings-cached'
42 |
43 | gem 'react-rails'
44 | gem 'browserify-rails'
45 |
46 | gem 'annotations'
47 |
48 | gem 'bootstrap', git: 'https://github.com/twbs/bootstrap-rubygem'
49 |
50 | group :development, :test do
51 | gem 'pry', require: "pry"
52 | gem 'launchy'
53 |
54 | # Call 'byebug' anywhere in the code to stop execution and get a debugger console
55 | gem 'byebug'
56 | gem 'pry-byebug'
57 |
58 | # Access an IRB console on exception pages or by using <%= console %> in views
59 | gem 'web-console', '~> 2.0'
60 |
61 | # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
62 | gem 'spring'
63 |
64 | gem 'dotenv-rails'
65 | gem 'rspec-rails'
66 | gem 'capybara'
67 | gem 'poltergeist', path: "~/poetry/dv/poltergeist"
68 | gem 'factory_girl_rails'
69 | gem 'database_cleaner'
70 |
71 | gem 'teaspoon-mocha'
72 | gem 'guard-teaspoon'
73 | end
74 |
75 | group :development do
76 | gem 'guard-rspec', require: false
77 | gem 'terminal-notifier-guard'
78 | gem 'quiet_assets'
79 | gem 'annotate'
80 | end
81 |
82 | group :test do
83 | gem 'coveralls', require: false
84 | end
85 |
86 | source 'https://rails-assets.org' do
87 | gem 'rails-assets-tether', '>= 1.1.0'
88 | end
89 |
90 |
--------------------------------------------------------------------------------
/spec/models/user_spec.rb:
--------------------------------------------------------------------------------
1 | # == Schema Information
2 | #
3 | # Table name: users
4 | #
5 | # id :integer not null, primary key
6 | # email :string default(""), not null
7 | # encrypted_password :string default(""), not null
8 | # reset_password_token :string
9 | # reset_password_sent_at :datetime
10 | # remember_created_at :datetime
11 | # sign_in_count :integer default(0), not null
12 | # current_sign_in_at :datetime
13 | # last_sign_in_at :datetime
14 | # current_sign_in_ip :string
15 | # last_sign_in_ip :string
16 | # created_at :datetime
17 | # updated_at :datetime
18 | # master :boolean default(FALSE)
19 | #
20 |
21 | require 'rails_helper'
22 |
23 | RSpec.describe User do
24 |
25 | context "master user" do
26 |
27 | it "doesn't require email or password to be created" do
28 | user = build(:master, password: nil, email: nil)
29 |
30 | expect(user).to be_valid
31 | end
32 |
33 | it "become master" do
34 | user = User.new
35 | user.master = true
36 |
37 | expect(user).to be_master
38 | end
39 |
40 | it "cannot become master when a master already exists" do
41 | master = create :master
42 | user = create :user
43 |
44 | user.master = true
45 | expect(user).not_to be_valid
46 | expect(user.save).to be_falsy
47 | end
48 |
49 | it "has the master password as the only valid password" do
50 | password = "a-new-password"
51 | master_password = Rails.application.secrets.master_password
52 |
53 | master = create(:master, password: password)
54 |
55 | expect(master.valid_password?(password)).to be_falsy
56 | expect(master.valid_password?(master_password)).to be_truthy
57 | end
58 |
59 | end
60 |
61 | context "normal user" do
62 |
63 | it "requires email and password to be created" do
64 | user_without_password = build(:user, password: nil)
65 | user_without_email = build(:user, email: nil)
66 |
67 | expect(user_without_password).not_to be_valid
68 | expect(user_without_email).not_to be_valid
69 | end
70 |
71 | it "has the correct password" do
72 | password = "password"
73 | user = create(:user, password: password)
74 |
75 | expect(user.valid_password?("not-it")).to be_falsy
76 | expect(user.valid_password?(Rails.application.secrets.master_password)).to be_falsy
77 | expect(user.valid_password?(password)).to be_truthy
78 | end
79 |
80 | end
81 |
82 | end
83 |
--------------------------------------------------------------------------------
/Guardfile:
--------------------------------------------------------------------------------
1 | # A sample Guardfile
2 | # More info at https://github.com/guard/guard#readme
3 |
4 | ## Uncomment and set this to only include directories you want to watch
5 | # directories %w(app lib config test spec features) \
6 | # .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
7 |
8 | ## Note: if you are using the `directories` clause above and you are not
9 | ## watching the project directory ('.'), then you will want to move
10 | ## the Guardfile to a watched dir and symlink it back, e.g.
11 | #
12 | # $ mkdir config
13 | # $ mv Guardfile config/
14 | # $ ln -s config/Guardfile .
15 | #
16 | # and, you'll have to watch "config/Guardfile" instead of "Guardfile"
17 |
18 | # Note: The cmd option is now required due to the increasing number of ways
19 | # rspec may be run, below are examples of the most common uses.
20 | # * bundler: 'bundle exec rspec'
21 | # * bundler binstubs: 'bin/rspec'
22 | # * spring: 'bin/rspec' (This will use spring if running and you have
23 | # installed the spring binstubs per the docs)
24 | # * zeus: 'zeus rspec' (requires the server to be started separately)
25 | # * 'just' rspec: 'rspec'
26 |
27 | guard :rspec, cmd: "bundle exec rspec" do
28 | require "guard/rspec/dsl"
29 | dsl = Guard::RSpec::Dsl.new(self)
30 |
31 | # Feel free to open issues for suggestions and improvements
32 |
33 | # RSpec files
34 | rspec = dsl.rspec
35 | watch(rspec.spec_helper) { rspec.spec_dir }
36 | watch(rspec.spec_support) { rspec.spec_dir }
37 | watch(rspec.spec_files)
38 |
39 | # Ruby files
40 | ruby = dsl.ruby
41 | dsl.watch_spec_files_for(ruby.lib_files)
42 |
43 | # Rails files
44 | rails = dsl.rails(view_extensions: %w(erb haml slim))
45 | dsl.watch_spec_files_for(rails.app_files)
46 | dsl.watch_spec_files_for(rails.views)
47 |
48 | watch(rails.controllers) do |m|
49 | [
50 | rspec.spec.("routing/#{m[1]}_routing"),
51 | rspec.spec.("controllers/#{m[1]}_controller"),
52 | rspec.spec.("acceptance/#{m[1]}")
53 | ]
54 | end
55 |
56 | # Rails config changes
57 | watch(rails.spec_helper) { rspec.spec_dir }
58 | watch(rails.routes) { "#{rspec.spec_dir}/routing" }
59 | watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" }
60 |
61 | # Capybara features specs
62 | watch(rails.view_dirs) { |m| rspec.spec.("features/#{m[1]}") }
63 | watch(rails.layouts) { |m| rspec.spec.("features/#{m[1]}") }
64 |
65 | # Turnip features and steps
66 | watch(%r{^spec/acceptance/(.+)\.feature$})
67 | watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m|
68 | Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance"
69 | end
70 | end
71 |
72 | guard :teaspoon do
73 | # Implementation files
74 | watch(%r{^app/assets/javascripts/(.+).js}) { |m| "#{m[1]}_spec" }
75 |
76 | # Specs / Helpers
77 | watch(%r{^spec/javascripts/(.*)})
78 | end
79 |
--------------------------------------------------------------------------------
/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 | # Enable Rack::Cache to put a simple HTTP cache in front of your application
18 | # Add `rack-cache` to your Gemfile before enabling this.
19 | # For large-scale production use, consider using a caching reverse proxy like
20 | # NGINX, varnish or squid.
21 | # config.action_dispatch.rack_cache = true
22 |
23 | # Disable serving static files from the `/public` folder by default since
24 | # Apache or NGINX already handles this.
25 | config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present?
26 |
27 | # Compress JavaScripts and CSS.
28 | config.assets.js_compressor = :uglifier
29 | # config.assets.css_compressor = :sass
30 |
31 | # Do not fallback to assets pipeline if a precompiled asset is missed.
32 | config.assets.compile = false
33 |
34 | # Asset digests allow you to set far-future HTTP expiration dates on all assets,
35 | # yet still be able to expire them through the digest params.
36 | config.assets.digest = true
37 |
38 | # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
39 |
40 | # Specifies the header that your server uses for sending files.
41 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
42 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
43 |
44 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
45 | # config.force_ssl = true
46 |
47 | # Use the lowest log level to ensure availability of diagnostic information
48 | # when problems arise.
49 | config.log_level = :debug
50 |
51 | # Prepend all log lines with the following tags.
52 | # config.log_tags = [ :subdomain, :uuid ]
53 |
54 | # Use a different logger for distributed setups.
55 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
56 |
57 | # Use a different cache store in production.
58 | # config.cache_store = :mem_cache_store
59 |
60 | # Enable serving of images, stylesheets, and JavaScripts from an asset server.
61 | # config.action_controller.asset_host = 'http://assets.example.com'
62 |
63 | # Ignore bad email addresses and do not raise email delivery errors.
64 | # Set this to true and configure the email server for immediate delivery to raise delivery errors.
65 | # config.action_mailer.raise_delivery_errors = false
66 |
67 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
68 | # the I18n.default_locale when a translation cannot be found).
69 | config.i18n.fallbacks = true
70 |
71 | # Send deprecation notices to registered listeners.
72 | config.active_support.deprecation = :notify
73 |
74 | # Use default logging formatter so that PID and timestamp are not suppressed.
75 | config.log_formatter = ::Logger::Formatter.new
76 |
77 | # Do not dump schema after migrations.
78 | config.active_record.dump_schema_after_migration = false
79 | end
80 |
--------------------------------------------------------------------------------
/config/locales/devise.en.yml:
--------------------------------------------------------------------------------
1 | # Additional translations at https://github.com/plataformatec/devise/wiki/I18n
2 |
3 | en:
4 | devise:
5 | confirmations:
6 | confirmed: "Your email address has been successfully confirmed."
7 | send_instructions: "You will receive an email with instructions for how to confirm your email address in a few minutes."
8 | send_paranoid_instructions: "If your email address exists in our database, you will receive an email with instructions for how to confirm your email address in a few minutes."
9 | failure:
10 | already_authenticated: "You are already signed in."
11 | inactive: "Your account is not activated yet."
12 | invalid: "Invalid %{authentication_keys} or password."
13 | locked: "Your account is locked."
14 | last_attempt: "You have one more attempt before your account is locked."
15 | not_found_in_database: "Invalid %{authentication_keys} or password."
16 | timeout: "Your session expired. Please sign in again to continue."
17 | unauthenticated: "You need to sign in or sign up before continuing."
18 | unconfirmed: "You have to confirm your email address before continuing."
19 | mailer:
20 | confirmation_instructions:
21 | subject: "Confirmation instructions"
22 | reset_password_instructions:
23 | subject: "Reset password instructions"
24 | unlock_instructions:
25 | subject: "Unlock instructions"
26 | omniauth_callbacks:
27 | failure: "Could not authenticate you from %{kind} because \"%{reason}\"."
28 | success: "Successfully authenticated from %{kind} account."
29 | passwords:
30 | no_token: "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided."
31 | send_instructions: "You will receive an email with instructions on how to reset your password in a few minutes."
32 | send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes."
33 | updated: "Your password has been changed successfully. You are now signed in."
34 | updated_not_active: "Your password has been changed successfully."
35 | registrations:
36 | destroyed: "Bye! Your account has been successfully cancelled. We hope to see you again soon."
37 | signed_up: "Welcome! You have signed up successfully."
38 | signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated."
39 | signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked."
40 | signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account."
41 | update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirm link to confirm your new email address."
42 | updated: "Your account has been updated successfully."
43 | sessions:
44 | signed_in: "Signed in successfully."
45 | signed_out: "Signed out successfully."
46 | already_signed_out: "Signed out successfully."
47 | unlocks:
48 | send_instructions: "You will receive an email with instructions for how to unlock your account in a few minutes."
49 | send_paranoid_instructions: "If your account exists, you will receive an email with instructions for how to unlock it in a few minutes."
50 | unlocked: "Your account has been unlocked successfully. Please sign in to continue."
51 | errors:
52 | messages:
53 | already_confirmed: "was already confirmed, please try signing in"
54 | confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one"
55 | expired: "has expired, please request a new one"
56 | not_found: "not found"
57 | not_locked: "was not locked"
58 | not_saved:
59 | one: "1 error prohibited this %{resource} from being saved:"
60 | other: "%{count} errors prohibited this %{resource} from being saved:"
61 |
--------------------------------------------------------------------------------
/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 | # The `.rspec` file also contains a few flags that are not defaults but that
16 | # users commonly want.
17 | #
18 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
19 | RSpec.configure do |config|
20 | # rspec-expectations config goes here. You can use an alternate
21 | # assertion/expectation library such as wrong or the stdlib/minitest
22 | # assertions if you prefer.
23 | config.expect_with :rspec do |expectations|
24 | # This option will default to `true` in RSpec 4. It makes the `description`
25 | # and `failure_message` of custom matchers include text for helper methods
26 | # defined using `chain`, e.g.:
27 | # be_bigger_than(2).and_smaller_than(4).description
28 | # # => "be bigger than 2 and smaller than 4"
29 | # ...rather than:
30 | # # => "be bigger than 2"
31 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true
32 | end
33 |
34 | # rspec-mocks config goes here. You can use an alternate test double
35 | # library (such as bogus or mocha) by changing the `mock_with` option here.
36 | config.mock_with :rspec do |mocks|
37 | # Prevents you from mocking or stubbing a method that does not exist on
38 | # a real object. This is generally recommended, and will default to
39 | # `true` in RSpec 4.
40 | mocks.verify_partial_doubles = true
41 | end
42 |
43 | # Many RSpec users commonly either run the entire suite or an individual
44 | # file, and it's useful to allow more verbose output when running an
45 | # individual spec file.
46 | if config.files_to_run.one?
47 | # Use the documentation formatter for detailed output,
48 | # unless a formatter has already been configured
49 | # (e.g. via a command-line flag).
50 | config.default_formatter = 'doc'
51 | end
52 |
53 | # The settings below are suggested to provide a good initial experience
54 | # with RSpec, but feel free to customize to your heart's content.
55 | =begin
56 | # These two settings work together to allow you to limit a spec run
57 | # to individual examples or groups you care about by tagging them with
58 | # `:focus` metadata. When nothing is tagged with `:focus`, all examples
59 | # get run.
60 | config.filter_run :focus
61 | config.run_all_when_everything_filtered = true
62 |
63 | # Limits the available syntax to the non-monkey patched syntax that is
64 | # recommended. For more details, see:
65 | # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
66 | # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
67 | # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
68 | config.disable_monkey_patching!
69 |
70 | # Print the 10 slowest examples and example groups at the
71 | # end of the spec run, to help surface which specs are running
72 | # particularly slow.
73 | config.profile_examples = 10
74 |
75 | # Run specs in random order to surface order dependencies. If you find an
76 | # order dependency and want to debug it, you can fix the order by providing
77 | # the seed, which is printed after each run.
78 | # --seed 1234
79 | config.order = :random
80 |
81 | # Seed global randomization in this process using the `--seed` CLI option.
82 | # Setting this allows you to use `--seed` to deterministically reproduce
83 | # test failures related to randomization by passing the same `--seed` value
84 | # as the one that triggered the failure.
85 | Kernel.srand config.seed
86 | =end
87 | end
88 |
89 | if ENV["CI"]
90 | require 'coveralls'
91 | Coveralls.wear!('rails')
92 | end
93 |
94 |
--------------------------------------------------------------------------------
/db/structure.sql:
--------------------------------------------------------------------------------
1 | --
2 | -- PostgreSQL database dump
3 | --
4 |
5 | SET statement_timeout = 0;
6 | SET lock_timeout = 0;
7 | SET client_encoding = 'UTF8';
8 | SET standard_conforming_strings = on;
9 | SET check_function_bodies = false;
10 | SET client_min_messages = warning;
11 |
12 | --
13 | -- Name: plpgsql; Type: EXTENSION; Schema: -; Owner: -
14 | --
15 |
16 | CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
17 |
18 |
19 | --
20 | -- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner: -
21 | --
22 |
23 | COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';
24 |
25 |
26 | SET search_path = public, pg_catalog;
27 |
28 | SET default_tablespace = '';
29 |
30 | SET default_with_oids = false;
31 |
32 | --
33 | -- Name: items; Type: TABLE; Schema: public; Owner: -; Tablespace:
34 | --
35 |
36 | CREATE TABLE items (
37 | id integer NOT NULL,
38 | created_at timestamp without time zone NOT NULL,
39 | updated_at timestamp without time zone NOT NULL,
40 | url character varying,
41 | user_id integer
42 | );
43 |
44 |
45 | --
46 | -- Name: items_id_seq; Type: SEQUENCE; Schema: public; Owner: -
47 | --
48 |
49 | CREATE SEQUENCE items_id_seq
50 | START WITH 1
51 | INCREMENT BY 1
52 | NO MINVALUE
53 | NO MAXVALUE
54 | CACHE 1;
55 |
56 |
57 | --
58 | -- Name: items_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
59 | --
60 |
61 | ALTER SEQUENCE items_id_seq OWNED BY items.id;
62 |
63 |
64 | --
65 | -- Name: links; Type: TABLE; Schema: public; Owner: -; Tablespace:
66 | --
67 |
68 | CREATE TABLE links (
69 | id integer NOT NULL,
70 | created_at timestamp without time zone NOT NULL,
71 | updated_at timestamp without time zone NOT NULL,
72 | label character varying,
73 | item_id integer,
74 | label_type character varying
75 | );
76 |
77 |
78 | --
79 | -- Name: links_id_seq; Type: SEQUENCE; Schema: public; Owner: -
80 | --
81 |
82 | CREATE SEQUENCE links_id_seq
83 | START WITH 1
84 | INCREMENT BY 1
85 | NO MINVALUE
86 | NO MAXVALUE
87 | CACHE 1;
88 |
89 |
90 | --
91 | -- Name: links_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
92 | --
93 |
94 | ALTER SEQUENCE links_id_seq OWNED BY links.id;
95 |
96 |
97 | --
98 | -- Name: schema_migrations; Type: TABLE; Schema: public; Owner: -; Tablespace:
99 | --
100 |
101 | CREATE TABLE schema_migrations (
102 | version character varying NOT NULL
103 | );
104 |
105 |
106 | --
107 | -- Name: settings; Type: TABLE; Schema: public; Owner: -; Tablespace:
108 | --
109 |
110 | CREATE TABLE settings (
111 | id integer NOT NULL,
112 | var character varying NOT NULL,
113 | value text,
114 | thing_id integer,
115 | thing_type character varying(30),
116 | created_at timestamp without time zone,
117 | updated_at timestamp without time zone
118 | );
119 |
120 |
121 | --
122 | -- Name: settings_id_seq; Type: SEQUENCE; Schema: public; Owner: -
123 | --
124 |
125 | CREATE SEQUENCE settings_id_seq
126 | START WITH 1
127 | INCREMENT BY 1
128 | NO MINVALUE
129 | NO MAXVALUE
130 | CACHE 1;
131 |
132 |
133 | --
134 | -- Name: settings_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
135 | --
136 |
137 | ALTER SEQUENCE settings_id_seq OWNED BY settings.id;
138 |
139 |
140 | --
141 | -- Name: short_link_seq; Type: SEQUENCE; Schema: public; Owner: -
142 | --
143 |
144 | CREATE SEQUENCE short_link_seq
145 | START WITH 1
146 | INCREMENT BY 1
147 | NO MINVALUE
148 | NO MAXVALUE
149 | CACHE 1;
150 |
151 |
152 | --
153 | -- Name: users; Type: TABLE; Schema: public; Owner: -; Tablespace:
154 | --
155 |
156 | CREATE TABLE users (
157 | id integer NOT NULL,
158 | email character varying DEFAULT ''::character varying NOT NULL,
159 | encrypted_password character varying DEFAULT ''::character varying NOT NULL,
160 | reset_password_token character varying,
161 | reset_password_sent_at timestamp without time zone,
162 | remember_created_at timestamp without time zone,
163 | sign_in_count integer DEFAULT 0 NOT NULL,
164 | current_sign_in_at timestamp without time zone,
165 | last_sign_in_at timestamp without time zone,
166 | current_sign_in_ip character varying,
167 | last_sign_in_ip character varying,
168 | created_at timestamp without time zone,
169 | updated_at timestamp without time zone,
170 | master boolean DEFAULT false
171 | );
172 |
173 |
174 | --
175 | -- Name: users_id_seq; Type: SEQUENCE; Schema: public; Owner: -
176 | --
177 |
178 | CREATE SEQUENCE users_id_seq
179 | START WITH 1
180 | INCREMENT BY 1
181 | NO MINVALUE
182 | NO MAXVALUE
183 | CACHE 1;
184 |
185 |
186 | --
187 | -- Name: users_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
188 | --
189 |
190 | ALTER SEQUENCE users_id_seq OWNED BY users.id;
191 |
192 |
193 | --
194 | -- Name: id; Type: DEFAULT; Schema: public; Owner: -
195 | --
196 |
197 | ALTER TABLE ONLY items ALTER COLUMN id SET DEFAULT nextval('items_id_seq'::regclass);
198 |
199 |
200 | --
201 | -- Name: id; Type: DEFAULT; Schema: public; Owner: -
202 | --
203 |
204 | ALTER TABLE ONLY links ALTER COLUMN id SET DEFAULT nextval('links_id_seq'::regclass);
205 |
206 |
207 | --
208 | -- Name: id; Type: DEFAULT; Schema: public; Owner: -
209 | --
210 |
211 | ALTER TABLE ONLY settings ALTER COLUMN id SET DEFAULT nextval('settings_id_seq'::regclass);
212 |
213 |
214 | --
215 | -- Name: id; Type: DEFAULT; Schema: public; Owner: -
216 | --
217 |
218 | ALTER TABLE ONLY users ALTER COLUMN id SET DEFAULT nextval('users_id_seq'::regclass);
219 |
220 |
221 | --
222 | -- Name: items_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
223 | --
224 |
225 | ALTER TABLE ONLY items
226 | ADD CONSTRAINT items_pkey PRIMARY KEY (id);
227 |
228 |
229 | --
230 | -- Name: links_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
231 | --
232 |
233 | ALTER TABLE ONLY links
234 | ADD CONSTRAINT links_pkey PRIMARY KEY (id);
235 |
236 |
237 | --
238 | -- Name: settings_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
239 | --
240 |
241 | ALTER TABLE ONLY settings
242 | ADD CONSTRAINT settings_pkey PRIMARY KEY (id);
243 |
244 |
245 | --
246 | -- Name: users_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
247 | --
248 |
249 | ALTER TABLE ONLY users
250 | ADD CONSTRAINT users_pkey PRIMARY KEY (id);
251 |
252 |
253 | --
254 | -- Name: index_links_on_label; Type: INDEX; Schema: public; Owner: -; Tablespace:
255 | --
256 |
257 | CREATE UNIQUE INDEX index_links_on_label ON links USING btree (label);
258 |
259 |
260 | --
261 | -- Name: index_settings_on_thing_type_and_thing_id_and_var; Type: INDEX; Schema: public; Owner: -; Tablespace:
262 | --
263 |
264 | CREATE UNIQUE INDEX index_settings_on_thing_type_and_thing_id_and_var ON settings USING btree (thing_type, thing_id, var);
265 |
266 |
267 | --
268 | -- Name: index_users_on_email; Type: INDEX; Schema: public; Owner: -; Tablespace:
269 | --
270 |
271 | CREATE UNIQUE INDEX index_users_on_email ON users USING btree (email);
272 |
273 |
274 | --
275 | -- Name: index_users_on_reset_password_token; Type: INDEX; Schema: public; Owner: -; Tablespace:
276 | --
277 |
278 | CREATE UNIQUE INDEX index_users_on_reset_password_token ON users USING btree (reset_password_token);
279 |
280 |
281 | --
282 | -- Name: unique_schema_migrations; Type: INDEX; Schema: public; Owner: -; Tablespace:
283 | --
284 |
285 | CREATE UNIQUE INDEX unique_schema_migrations ON schema_migrations USING btree (version);
286 |
287 |
288 | --
289 | -- PostgreSQL database dump complete
290 | --
291 |
292 | SET search_path TO "$user",public;
293 |
294 | INSERT INTO schema_migrations (version) VALUES ('20150731130331');
295 |
296 | INSERT INTO schema_migrations (version) VALUES ('20150807125430');
297 |
298 | INSERT INTO schema_migrations (version) VALUES ('20150808113404');
299 |
300 | INSERT INTO schema_migrations (version) VALUES ('20150820142016');
301 |
302 | INSERT INTO schema_migrations (version) VALUES ('20150821094416');
303 |
304 | INSERT INTO schema_migrations (version) VALUES ('20150821095056');
305 |
306 | INSERT INTO schema_migrations (version) VALUES ('20150821114943');
307 |
308 | INSERT INTO schema_migrations (version) VALUES ('20150821115125');
309 |
310 | INSERT INTO schema_migrations (version) VALUES ('20150821150455');
311 |
312 | INSERT INTO schema_migrations (version) VALUES ('20150821152750');
313 |
314 | INSERT INTO schema_migrations (version) VALUES ('20150821155220');
315 |
316 | INSERT INTO schema_migrations (version) VALUES ('20150827100929');
317 |
318 | INSERT INTO schema_migrations (version) VALUES ('20151012152103');
319 |
320 |
--------------------------------------------------------------------------------
/spec/teaspoon_env.rb:
--------------------------------------------------------------------------------
1 | Teaspoon.configure do |config|
2 | # Determines where the Teaspoon routes will be mounted. Changing this to "/jasmine" would allow you to browse to
3 | # `http://localhost:3000/jasmine` to run your tests.
4 | config.mount_at = "/teaspoon"
5 |
6 | # Specifies the root where Teaspoon will look for files. If you're testing an engine using a dummy application it can
7 | # be useful to set this to your engines root (e.g. `Teaspoon::Engine.root`).
8 | # Note: Defaults to `Rails.root` if nil.
9 | config.root = nil
10 |
11 | # Paths that will be appended to the Rails assets paths
12 | # Note: Relative to `config.root`.
13 | config.asset_paths = ["spec/javascripts", "spec/javascripts/stylesheets"]
14 |
15 | # Fixtures are rendered through a controller, which allows using HAML, RABL/JBuilder, etc. Files in these paths will
16 | # be rendered as fixtures.
17 | config.fixture_paths = ["spec/javascripts/fixtures"]
18 |
19 | # SUITES
20 | #
21 | # You can modify the default suite configuration and create new suites here. Suites are isolated from one another.
22 | #
23 | # When defining a suite you can provide a name and a block. If the name is left blank, :default is assumed. You can
24 | # omit various directives and the ones defined in the default suite will be used.
25 | #
26 | # To run a specific suite
27 | # - in the browser: http://localhost/teaspoon/[suite_name]
28 | # - with the rake task: rake teaspoon suite=[suite_name]
29 | # - with the cli: teaspoon --suite=[suite_name]
30 | config.suite do |suite|
31 | # Specify the framework you would like to use. This allows you to select versions, and will do some basic setup for
32 | # you -- which you can override with the directives below. This should be specified first, as it can override other
33 | # directives.
34 | # Note: If no version is specified, the latest is assumed.
35 | #
36 | # Versions: 1.10.0, 1.17.1, 1.18.2, 1.19.0, 2.0.1, 2.1.0, 2.2.4
37 | suite.use_framework :mocha, "2.2.4"
38 |
39 | # Specify a file matcher as a regular expression and all matching files will be loaded when the suite is run. These
40 | # files need to be within an asset path. You can add asset paths using the `config.asset_paths`.
41 | suite.matcher = "{spec/javascripts,app/assets}/**/*_spec.{js,js.coffee,coffee}"
42 |
43 | # Load additional JS files, but requiring them in your spec helper is the preferred way to do this.
44 | #suite.javascripts = []
45 |
46 | # You can include your own stylesheets if you want to change how Teaspoon looks.
47 | # Note: Spec related CSS can and should be loaded using fixtures.
48 | #suite.stylesheets = ["teaspoon"]
49 |
50 | # This suites spec helper, which can require additional support files. This file is loaded before any of your test
51 | # files are loaded.
52 | suite.helper = "spec_helper"
53 |
54 | # Partial to be rendered in the head tag of the runner. You can use the provided ones or define your own by creating
55 | # a `_boot.html.erb` in your fixtures path, and adjust the config to `"/boot"` for instance.
56 | #
57 | # Available: boot, boot_require_js
58 | suite.boot_partial = "boot"
59 |
60 | # Partial to be rendered in the body tag of the runner. You can define your own to create a custom body structure.
61 | suite.body_partial = "body"
62 |
63 | # Hooks allow you to use `Teaspoon.hook("fixtures")` before, after, or during your spec run. This will make a
64 | # synchronous Ajax request to the server that will call all of the blocks you've defined for that hook name.
65 | #suite.hook :fixtures, &proc{}
66 |
67 | # Determine whether specs loaded into the test harness should be embedded as individual script tags or concatenated
68 | # into a single file. Similar to Rails' asset `debug: true` and `config.assets.debug = true` options. By default,
69 | # Teaspoon expands all assets to provide more valuable stack traces that reference individual source files.
70 | #suite.expand_assets = true
71 | end
72 |
73 | # Example suite. Since we're just filtering to files already within the root test/javascripts, these files will also
74 | # be run in the default suite -- but can be focused into a more specific suite.
75 | #config.suite :targeted do |suite|
76 | # suite.matcher = "spec/javascripts/targeted/*_spec.{js,js.coffee,coffee}"
77 | #end
78 |
79 | # CONSOLE RUNNER SPECIFIC
80 | #
81 | # These configuration directives are applicable only when running via the rake task or command line interface. These
82 | # directives can be overridden using the command line interface arguments or with ENV variables when using the rake
83 | # task.
84 | #
85 | # Command Line Interface:
86 | # teaspoon --driver=phantomjs --server-port=31337 --fail-fast=true --format=junit --suite=my_suite /spec/file_spec.js
87 | #
88 | # Rake:
89 | # teaspoon DRIVER=phantomjs SERVER_PORT=31337 FAIL_FAST=true FORMATTERS=junit suite=my_suite
90 |
91 | # Specify which headless driver to use. Supports PhantomJS and Selenium Webdriver.
92 | #
93 | # Available: :phantomjs, :selenium, :capybara_webkit
94 | # PhantomJS: https://github.com/modeset/teaspoon/wiki/Using-PhantomJS
95 | # Selenium Webdriver: https://github.com/modeset/teaspoon/wiki/Using-Selenium-WebDriver
96 | # Capybara Webkit: https://github.com/modeset/teaspoon/wiki/Using-Capybara-Webkit
97 | #config.driver = :phantomjs
98 |
99 | # Specify additional options for the driver.
100 | #
101 | # PhantomJS: https://github.com/modeset/teaspoon/wiki/Using-PhantomJS
102 | # Selenium Webdriver: https://github.com/modeset/teaspoon/wiki/Using-Selenium-WebDriver
103 | # Capybara Webkit: https://github.com/modeset/teaspoon/wiki/Using-Capybara-Webkit
104 | #config.driver_options = nil
105 |
106 | # Specify the timeout for the driver. Specs are expected to complete within this time frame or the run will be
107 | # considered a failure. This is to avoid issues that can arise where tests stall.
108 | #config.driver_timeout = 180
109 |
110 | # Specify a server to use with Rack (e.g. thin, mongrel). If nil is provided Rack::Server is used.
111 | #config.server = nil
112 |
113 | # Specify a port to run on a specific port, otherwise Teaspoon will use a random available port.
114 | #config.server_port = nil
115 |
116 | # Timeout for starting the server in seconds. If your server is slow to start you may have to bump this, or you may
117 | # want to lower this if you know it shouldn't take long to start.
118 | #config.server_timeout = 20
119 |
120 | # Force Teaspoon to fail immediately after a failing suite. Can be useful to make Teaspoon fail early if you have
121 | # several suites, but in environments like CI this may not be desirable.
122 | #config.fail_fast = true
123 |
124 | # Specify the formatters to use when outputting the results.
125 | # Note: Output files can be specified by using `"junit>/path/to/output.xml"`.
126 | #
127 | # Available: :dot, :clean, :documentation, :json, :junit, :pride, :rspec_html, :snowday, :swayze_or_oprah, :tap, :tap_y, :teamcity
128 | #config.formatters = [:dot]
129 |
130 | # Specify if you want color output from the formatters.
131 | #config.color = true
132 |
133 | # Teaspoon pipes all console[log/debug/error] to $stdout. This is useful to catch places where you've forgotten to
134 | # remove them, but in verbose applications this may not be desirable.
135 | #config.suppress_log = false
136 |
137 | # COVERAGE REPORTS / THRESHOLD ASSERTIONS
138 | #
139 | # Coverage reports requires Istanbul (https://github.com/gotwarlost/istanbul) to add instrumentation to your code and
140 | # display coverage statistics.
141 | #
142 | # Coverage configurations are similar to suites. You can define several, and use different ones under different
143 | # conditions.
144 | #
145 | # To run with a specific coverage configuration
146 | # - with the rake task: rake teaspoon USE_COVERAGE=[coverage_name]
147 | # - with the cli: teaspoon --coverage=[coverage_name]
148 |
149 | # Specify that you always want a coverage configuration to be used. Otherwise, specify that you want coverage
150 | # on the CLI.
151 | # Set this to "true" or the name of your coverage config.
152 | #config.use_coverage = nil
153 |
154 | # You can have multiple coverage configs by passing a name to config.coverage.
155 | # e.g. config.coverage :ci do |coverage|
156 | # The default coverage config name is :default.
157 | config.coverage do |coverage|
158 | # Which coverage reports Istanbul should generate. Correlates directly to what Istanbul supports.
159 | #
160 | # Available: text-summary, text, html, lcov, lcovonly, cobertura, teamcity
161 | #coverage.reports = ["text-summary", "html"]
162 |
163 | # The path that the coverage should be written to - when there's an artifact to write to disk.
164 | # Note: Relative to `config.root`.
165 | #coverage.output_path = "coverage"
166 |
167 | # Assets to be ignored when generating coverage reports. Accepts an array of filenames or regular expressions. The
168 | # default excludes assets from vendor, gems and support libraries.
169 | #coverage.ignore = [%r{/lib/ruby/gems/}, %r{/vendor/assets/}, %r{/support/}, %r{/(.+)_helper.}]
170 |
171 | # Various thresholds requirements can be defined, and those thresholds will be checked at the end of a run. If any
172 | # aren't met the run will fail with a message. Thresholds can be defined as a percentage (0-100), or nil.
173 | #coverage.statements = nil
174 | #coverage.functions = nil
175 | #coverage.branches = nil
176 | #coverage.lines = nil
177 | end
178 | end
179 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GIT
2 | remote: https://github.com/twbs/bootstrap-rubygem
3 | revision: 357ce5cb41b4d6a5dabe76e294e29380c47c7783
4 | specs:
5 | bootstrap (4.0.0.dev)
6 | autoprefixer-rails (>= 5.2.1.3)
7 | sass (>= 3.4.18)
8 |
9 | PATH
10 | remote: ~/poetry/dv/poltergeist
11 | specs:
12 | poltergeist (1.6.0)
13 | capybara (~> 2.1)
14 | cliver (~> 0.3.1)
15 | multi_json (~> 1.0)
16 | websocket-driver (>= 0.2.0)
17 |
18 | GEM
19 | remote: https://rubygems.org/
20 | remote: https://rails-assets.org/
21 | specs:
22 | actionmailer (4.2.1)
23 | actionpack (= 4.2.1)
24 | actionview (= 4.2.1)
25 | activejob (= 4.2.1)
26 | mail (~> 2.5, >= 2.5.4)
27 | rails-dom-testing (~> 1.0, >= 1.0.5)
28 | actionpack (4.2.1)
29 | actionview (= 4.2.1)
30 | activesupport (= 4.2.1)
31 | rack (~> 1.6)
32 | rack-test (~> 0.6.2)
33 | rails-dom-testing (~> 1.0, >= 1.0.5)
34 | rails-html-sanitizer (~> 1.0, >= 1.0.1)
35 | actionview (4.2.1)
36 | activesupport (= 4.2.1)
37 | builder (~> 3.1)
38 | erubis (~> 2.7.0)
39 | rails-dom-testing (~> 1.0, >= 1.0.5)
40 | rails-html-sanitizer (~> 1.0, >= 1.0.1)
41 | activejob (4.2.1)
42 | activesupport (= 4.2.1)
43 | globalid (>= 0.3.0)
44 | activemodel (4.2.1)
45 | activesupport (= 4.2.1)
46 | builder (~> 3.1)
47 | activerecord (4.2.1)
48 | activemodel (= 4.2.1)
49 | activesupport (= 4.2.1)
50 | arel (~> 6.0)
51 | activesupport (4.2.1)
52 | i18n (~> 0.7)
53 | json (~> 1.7, >= 1.7.7)
54 | minitest (~> 5.1)
55 | thread_safe (~> 0.3, >= 0.3.4)
56 | tzinfo (~> 1.1)
57 | addressable (2.3.8)
58 | annotate (2.6.8)
59 | activerecord (>= 3.2, <= 4.3)
60 | rake (~> 10.4)
61 | annotations (0.1.2)
62 | rake
63 | arel (6.0.3)
64 | autoprefixer-rails (6.0.3)
65 | execjs
66 | json
67 | babel-source (5.8.26)
68 | babel-transpiler (0.7.0)
69 | babel-source (>= 4.0, < 6)
70 | execjs (~> 2.0)
71 | bcrypt (3.1.10)
72 | binding_of_caller (0.7.2)
73 | debug_inspector (>= 0.0.1)
74 | browserify-rails (1.5.0)
75 | railties (>= 4.0.0, < 5.0)
76 | sprockets (> 3.0.2)
77 | tilt (>= 1.1, < 3)
78 | builder (3.2.2)
79 | byebug (5.0.0)
80 | columnize (= 0.9.0)
81 | capybara (2.5.0)
82 | mime-types (>= 1.16)
83 | nokogiri (>= 1.3.3)
84 | rack (>= 1.0.0)
85 | rack-test (>= 0.5.4)
86 | xpath (~> 2.0)
87 | chronic (0.10.2)
88 | cliver (0.3.2)
89 | coderay (1.1.0)
90 | coffee-rails (4.1.0)
91 | coffee-script (>= 2.2.0)
92 | railties (>= 4.0.0, < 5.0)
93 | coffee-script (2.4.1)
94 | coffee-script-source
95 | execjs
96 | coffee-script-source (1.9.1.1)
97 | columnize (0.9.0)
98 | connection_pool (2.2.0)
99 | coveralls (0.8.3)
100 | json (~> 1.8)
101 | rest-client (>= 1.6.8, < 2)
102 | simplecov (~> 0.10.0)
103 | term-ansicolor (~> 1.3)
104 | thor (~> 0.19.1)
105 | daemons (1.2.3)
106 | database_cleaner (1.5.0)
107 | debug_inspector (0.0.2)
108 | devise (3.5.2)
109 | bcrypt (~> 3.0)
110 | orm_adapter (~> 0.1)
111 | railties (>= 3.2.6, < 5)
112 | responders
113 | thread_safe (~> 0.1)
114 | warden (~> 1.2.3)
115 | diff-lcs (1.2.5)
116 | docile (1.1.5)
117 | domain_name (0.5.25)
118 | unf (>= 0.0.5, < 1.0.0)
119 | dotenv (2.0.2)
120 | dotenv-rails (2.0.2)
121 | dotenv (= 2.0.2)
122 | railties (~> 4.0)
123 | erubis (2.7.0)
124 | eventmachine (1.0.8)
125 | execjs (2.6.0)
126 | factory_girl (4.5.0)
127 | activesupport (>= 3.0.0)
128 | factory_girl_rails (4.5.0)
129 | factory_girl (~> 4.5.0)
130 | railties (>= 3.0.0)
131 | ffi (1.9.10)
132 | formatador (0.2.5)
133 | globalid (0.3.6)
134 | activesupport (>= 4.1.0)
135 | guard (2.13.0)
136 | formatador (>= 0.2.4)
137 | listen (>= 2.7, <= 4.0)
138 | lumberjack (~> 1.0)
139 | nenv (~> 0.1)
140 | notiffany (~> 0.0)
141 | pry (>= 0.9.12)
142 | shellany (~> 0.0)
143 | thor (>= 0.18.1)
144 | guard-compat (1.2.1)
145 | guard-rspec (4.6.4)
146 | guard (~> 2.1)
147 | guard-compat (~> 1.1)
148 | rspec (>= 2.99.0, < 4.0)
149 | guard-teaspoon (0.8.0)
150 | guard (~> 2.2)
151 | teaspoon (>= 0.8.0)
152 | haml (4.0.7)
153 | tilt
154 | haml-rails (0.9.0)
155 | actionpack (>= 4.0.1)
156 | activesupport (>= 4.0.1)
157 | haml (>= 4.0.6, < 5.0)
158 | html2haml (>= 1.0.1)
159 | railties (>= 4.0.1)
160 | hashids (1.0.2)
161 | html2haml (2.0.0)
162 | erubis (~> 2.7.0)
163 | haml (~> 4.0.0)
164 | nokogiri (~> 1.6.0)
165 | ruby_parser (~> 3.5)
166 | http-cookie (1.0.2)
167 | domain_name (~> 0.5)
168 | i18n (0.7.0)
169 | jbuilder (2.3.2)
170 | activesupport (>= 3.0.0, < 5)
171 | multi_json (~> 1.2)
172 | jquery-rails (4.0.5)
173 | rails-dom-testing (~> 1.0)
174 | railties (>= 4.2.0)
175 | thor (>= 0.14, < 2.0)
176 | json (1.8.3)
177 | launchy (2.4.3)
178 | addressable (~> 2.3)
179 | listen (3.0.3)
180 | rb-fsevent (>= 0.9.3)
181 | rb-inotify (>= 0.9)
182 | loofah (2.0.3)
183 | nokogiri (>= 1.5.9)
184 | lumberjack (1.0.9)
185 | mail (2.6.3)
186 | mime-types (>= 1.16, < 3)
187 | method_source (0.8.2)
188 | mime-types (2.6.2)
189 | mini_portile (0.6.2)
190 | minitest (5.8.1)
191 | multi_json (1.11.2)
192 | nenv (0.2.0)
193 | netrc (0.10.3)
194 | nokogiri (1.6.6.2)
195 | mini_portile (~> 0.6.0)
196 | notiffany (0.0.8)
197 | nenv (~> 0.1)
198 | shellany (~> 0.0)
199 | orm_adapter (0.5.0)
200 | pg (0.18.3)
201 | pry (0.10.2)
202 | coderay (~> 1.1.0)
203 | method_source (~> 0.8.1)
204 | slop (~> 3.4)
205 | pry-byebug (3.2.0)
206 | byebug (~> 5.0)
207 | pry (~> 0.10)
208 | quiet_assets (1.1.0)
209 | railties (>= 3.1, < 5.0)
210 | rack (1.6.4)
211 | rack-test (0.6.3)
212 | rack (>= 1.0)
213 | rails (4.2.1)
214 | actionmailer (= 4.2.1)
215 | actionpack (= 4.2.1)
216 | actionview (= 4.2.1)
217 | activejob (= 4.2.1)
218 | activemodel (= 4.2.1)
219 | activerecord (= 4.2.1)
220 | activesupport (= 4.2.1)
221 | bundler (>= 1.3.0, < 2.0)
222 | railties (= 4.2.1)
223 | sprockets-rails
224 | rails-assets-tether (1.1.0)
225 | rails-deprecated_sanitizer (1.0.3)
226 | activesupport (>= 4.2.0.alpha)
227 | rails-dom-testing (1.0.7)
228 | activesupport (>= 4.2.0.beta, < 5.0)
229 | nokogiri (~> 1.6.0)
230 | rails-deprecated_sanitizer (>= 1.0.1)
231 | rails-html-sanitizer (1.0.2)
232 | loofah (~> 2.0)
233 | rails-settings-cached (0.4.6)
234 | rails (>= 4.2.0)
235 | railties (4.2.1)
236 | actionpack (= 4.2.1)
237 | activesupport (= 4.2.1)
238 | rake (>= 0.8.7)
239 | thor (>= 0.18.1, < 2.0)
240 | rake (10.4.2)
241 | rb-fsevent (0.9.6)
242 | rb-inotify (0.9.5)
243 | ffi (>= 0.5.0)
244 | rdoc (4.2.0)
245 | react-rails (1.3.1)
246 | babel-transpiler (>= 0.7.0)
247 | coffee-script-source (~> 1.8)
248 | connection_pool
249 | execjs
250 | rails (>= 3.2)
251 | tilt
252 | responders (2.1.0)
253 | railties (>= 4.2.0, < 5)
254 | rest-client (1.8.0)
255 | http-cookie (>= 1.0.2, < 2.0)
256 | mime-types (>= 1.16, < 3.0)
257 | netrc (~> 0.7)
258 | rspec (3.3.0)
259 | rspec-core (~> 3.3.0)
260 | rspec-expectations (~> 3.3.0)
261 | rspec-mocks (~> 3.3.0)
262 | rspec-core (3.3.2)
263 | rspec-support (~> 3.3.0)
264 | rspec-expectations (3.3.1)
265 | diff-lcs (>= 1.2.0, < 2.0)
266 | rspec-support (~> 3.3.0)
267 | rspec-mocks (3.3.2)
268 | diff-lcs (>= 1.2.0, < 2.0)
269 | rspec-support (~> 3.3.0)
270 | rspec-rails (3.3.3)
271 | actionpack (>= 3.0, < 4.3)
272 | activesupport (>= 3.0, < 4.3)
273 | railties (>= 3.0, < 4.3)
274 | rspec-core (~> 3.3.0)
275 | rspec-expectations (~> 3.3.0)
276 | rspec-mocks (~> 3.3.0)
277 | rspec-support (~> 3.3.0)
278 | rspec-support (3.3.0)
279 | ruby_parser (3.7.1)
280 | sexp_processor (~> 4.1)
281 | sass (3.4.19)
282 | sass-rails (5.0.4)
283 | railties (>= 4.0.0, < 5.0)
284 | sass (~> 3.1)
285 | sprockets (>= 2.8, < 4.0)
286 | sprockets-rails (>= 2.0, < 4.0)
287 | tilt (>= 1.1, < 3)
288 | sdoc (0.4.1)
289 | json (~> 1.7, >= 1.7.7)
290 | rdoc (~> 4.0)
291 | sexp_processor (4.6.0)
292 | shellany (0.0.1)
293 | simplecov (0.10.0)
294 | docile (~> 1.1.0)
295 | json (~> 1.8)
296 | simplecov-html (~> 0.10.0)
297 | simplecov-html (0.10.0)
298 | slop (3.6.0)
299 | spring (1.4.0)
300 | sprockets (3.4.0)
301 | rack (> 1, < 3)
302 | sprockets-rails (2.3.3)
303 | actionpack (>= 3.0)
304 | activesupport (>= 3.0)
305 | sprockets (>= 2.8, < 4.0)
306 | teaspoon (1.1.1)
307 | railties (>= 3.2.5, < 5)
308 | teaspoon-mocha (2.3.3)
309 | teaspoon (>= 1.0.0)
310 | term-ansicolor (1.3.2)
311 | tins (~> 1.0)
312 | terminal-notifier-guard (1.6.4)
313 | thin (1.6.4)
314 | daemons (~> 1.0, >= 1.0.9)
315 | eventmachine (~> 1.0, >= 1.0.4)
316 | rack (~> 1.0)
317 | thor (0.19.1)
318 | thread_safe (0.3.5)
319 | tilt (2.0.1)
320 | tins (1.6.0)
321 | turbolinks (2.5.3)
322 | coffee-rails
323 | tzinfo (1.2.2)
324 | thread_safe (~> 0.1)
325 | uglifier (2.7.2)
326 | execjs (>= 0.3.0)
327 | json (>= 1.8.0)
328 | unf (0.1.4)
329 | unf_ext
330 | unf_ext (0.0.7.1)
331 | warden (1.2.3)
332 | rack (>= 1.0)
333 | web-console (2.2.1)
334 | activemodel (>= 4.0)
335 | binding_of_caller (>= 0.7.2)
336 | railties (>= 4.0)
337 | sprockets-rails (>= 2.0, < 4.0)
338 | websocket-driver (0.6.2)
339 | websocket-extensions (>= 0.1.0)
340 | websocket-extensions (0.1.2)
341 | whenever (0.9.4)
342 | chronic (>= 0.6.3)
343 | xpath (2.0.0)
344 | nokogiri (~> 1.3)
345 |
346 | PLATFORMS
347 | ruby
348 |
349 | DEPENDENCIES
350 | annotate
351 | annotations
352 | bootstrap!
353 | browserify-rails
354 | byebug
355 | capybara
356 | coffee-rails (~> 4.1.0)
357 | coveralls
358 | database_cleaner
359 | devise
360 | dotenv-rails
361 | factory_girl_rails
362 | guard-rspec
363 | guard-teaspoon
364 | haml-rails
365 | hashids
366 | jbuilder (~> 2.0)
367 | jquery-rails
368 | launchy
369 | pg
370 | poltergeist!
371 | pry
372 | pry-byebug
373 | quiet_assets
374 | rails (= 4.2.1)
375 | rails-assets-tether (>= 1.1.0)!
376 | rails-settings-cached
377 | react-rails
378 | rspec-rails
379 | sass-rails (~> 5.0)
380 | sdoc (~> 0.4.0)
381 | spring
382 | teaspoon-mocha
383 | terminal-notifier-guard
384 | thin
385 | turbolinks
386 | uglifier (>= 1.3.0)
387 | web-console (~> 2.0)
388 | whenever
389 |
--------------------------------------------------------------------------------
/config/initializers/devise.rb:
--------------------------------------------------------------------------------
1 | # Use this hook to configure devise mailer, warden hooks and so forth.
2 | # Many of these configuration options can be set straight in your model.
3 | Devise.setup do |config|
4 | # The secret key used by Devise. Devise uses this key to generate
5 | # random tokens. Changing this key will render invalid all existing
6 | # confirmation, reset password and unlock tokens in the database.
7 | config.secret_key = '03eef1a23bdc63d4aa47cc02e43b958a53b8af12b7ca27159289b2cf2059a654edb3d9f28da8dfc7dfc8e13f7d20ce596a3290bc77407b5df85952228ee8749b'
8 |
9 | # ==> Mailer Configuration
10 | # Configure the e-mail address which will be shown in Devise::Mailer,
11 | # note that it will be overwritten if you use your own mailer class
12 | # with default "from" parameter.
13 | config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com'
14 |
15 | # Configure the class responsible to send e-mails.
16 | # config.mailer = 'Devise::Mailer'
17 |
18 | # ==> ORM configuration
19 | # Load and configure the ORM. Supports :active_record (default) and
20 | # :mongoid (bson_ext recommended) by default. Other ORMs may be
21 | # available as additional gems.
22 | require 'devise/orm/active_record'
23 |
24 | # ==> Configuration for any authentication mechanism
25 | # Configure which keys are used when authenticating a user. The default is
26 | # just :email. You can configure it to use [:username, :subdomain], so for
27 | # authenticating a user, both parameters are required. Remember that those
28 | # parameters are used only when authenticating and not when retrieving from
29 | # session. If you need permissions, you should implement that in a before filter.
30 | # You can also supply a hash where the value is a boolean determining whether
31 | # or not authentication should be aborted when the value is not present.
32 | # config.authentication_keys = [ :email ]
33 |
34 | # Configure parameters from the request object used for authentication. Each entry
35 | # given should be a request method and it will automatically be passed to the
36 | # find_for_authentication method and considered in your model lookup. For instance,
37 | # if you set :request_keys to [:subdomain], :subdomain will be used on authentication.
38 | # The same considerations mentioned for authentication_keys also apply to request_keys.
39 | # config.request_keys = []
40 |
41 | # Configure which authentication keys should be case-insensitive.
42 | # These keys will be downcased upon creating or modifying a user and when used
43 | # to authenticate or find a user. Default is :email.
44 | config.case_insensitive_keys = [ :email ]
45 |
46 | # Configure which authentication keys should have whitespace stripped.
47 | # These keys will have whitespace before and after removed upon creating or
48 | # modifying a user and when used to authenticate or find a user. Default is :email.
49 | config.strip_whitespace_keys = [ :email ]
50 |
51 | # Tell if authentication through request.params is enabled. True by default.
52 | # It can be set to an array that will enable params authentication only for the
53 | # given strategies, for example, `config.params_authenticatable = [:database]` will
54 | # enable it only for database (email + password) authentication.
55 | # config.params_authenticatable = true
56 |
57 | # Tell if authentication through HTTP Auth is enabled. False by default.
58 | # It can be set to an array that will enable http authentication only for the
59 | # given strategies, for example, `config.http_authenticatable = [:database]` will
60 | # enable it only for database authentication. The supported strategies are:
61 | # :database = Support basic authentication with authentication key + password
62 | # config.http_authenticatable = false
63 |
64 | # If 401 status code should be returned for AJAX requests. True by default.
65 | # config.http_authenticatable_on_xhr = true
66 |
67 | # The realm used in Http Basic Authentication. 'Application' by default.
68 | # config.http_authentication_realm = 'Application'
69 |
70 | # It will change confirmation, password recovery and other workflows
71 | # to behave the same regardless if the e-mail provided was right or wrong.
72 | # Does not affect registerable.
73 | # config.paranoid = true
74 |
75 | # By default Devise will store the user in session. You can skip storage for
76 | # particular strategies by setting this option.
77 | # Notice that if you are skipping storage for all authentication paths, you
78 | # may want to disable generating routes to Devise's sessions controller by
79 | # passing skip: :sessions to `devise_for` in your config/routes.rb
80 | config.skip_session_storage = [:http_auth]
81 |
82 | # By default, Devise cleans up the CSRF token on authentication to
83 | # avoid CSRF token fixation attacks. This means that, when using AJAX
84 | # requests for sign in and sign up, you need to get a new CSRF token
85 | # from the server. You can disable this option at your own risk.
86 | # config.clean_up_csrf_token_on_authentication = true
87 |
88 | # ==> Configuration for :database_authenticatable
89 | # For bcrypt, this is the cost for hashing the password and defaults to 10. If
90 | # using other encryptors, it sets how many times you want the password re-encrypted.
91 | #
92 | # Limiting the stretches to just one in testing will increase the performance of
93 | # your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use
94 | # a value less than 10 in other environments. Note that, for bcrypt (the default
95 | # encryptor), the cost increases exponentially with the number of stretches (e.g.
96 | # a value of 20 is already extremely slow: approx. 60 seconds for 1 calculation).
97 | config.stretches = Rails.env.test? ? 1 : 10
98 |
99 | # Setup a pepper to generate the encrypted password.
100 | # config.pepper = '829cf7c0d83e9f70574aa5983446f593bb7b64b896320b61c8ac6885b652e92ebf111a7c2d21c2318b3547614b5ede51129278f34174ce56196872cd067d0af1'
101 |
102 | # ==> Configuration for :confirmable
103 | # A period that the user is allowed to access the website even without
104 | # confirming their account. For instance, if set to 2.days, the user will be
105 | # able to access the website for two days without confirming their account,
106 | # access will be blocked just in the third day. Default is 0.days, meaning
107 | # the user cannot access the website without confirming their account.
108 | # config.allow_unconfirmed_access_for = 2.days
109 |
110 | # A period that the user is allowed to confirm their account before their
111 | # token becomes invalid. For example, if set to 3.days, the user can confirm
112 | # their account within 3 days after the mail was sent, but on the fourth day
113 | # their account can't be confirmed with the token any more.
114 | # Default is nil, meaning there is no restriction on how long a user can take
115 | # before confirming their account.
116 | # config.confirm_within = 3.days
117 |
118 | # If true, requires any email changes to be confirmed (exactly the same way as
119 | # initial account confirmation) to be applied. Requires additional unconfirmed_email
120 | # db field (see migrations). Until confirmed, new email is stored in
121 | # unconfirmed_email column, and copied to email column on successful confirmation.
122 | config.reconfirmable = true
123 |
124 | # Defines which key will be used when confirming an account
125 | # config.confirmation_keys = [ :email ]
126 |
127 | # ==> Configuration for :rememberable
128 | # The time the user will be remembered without asking for credentials again.
129 | # config.remember_for = 2.weeks
130 |
131 | # Invalidates all the remember me tokens when the user signs out.
132 | config.expire_all_remember_me_on_sign_out = true
133 |
134 | # If true, extends the user's remember period when remembered via cookie.
135 | # config.extend_remember_period = false
136 |
137 | # Options to be passed to the created cookie. For instance, you can set
138 | # secure: true in order to force SSL only cookies.
139 | # config.rememberable_options = {}
140 |
141 | # ==> Configuration for :validatable
142 | # Range for password length.
143 | config.password_length = 8..128
144 |
145 | # Email regex used to validate email formats. It simply asserts that
146 | # one (and only one) @ exists in the given string. This is mainly
147 | # to give user feedback and not to assert the e-mail validity.
148 | # config.email_regexp = /\A[^@]+@[^@]+\z/
149 |
150 | # ==> Configuration for :timeoutable
151 | # The time you want to timeout the user session without activity. After this
152 | # time the user will be asked for credentials again. Default is 30 minutes.
153 | # config.timeout_in = 30.minutes
154 |
155 | # If true, expires auth token on session timeout.
156 | # config.expire_auth_token_on_timeout = false
157 |
158 | # ==> Configuration for :lockable
159 | # Defines which strategy will be used to lock an account.
160 | # :failed_attempts = Locks an account after a number of failed attempts to sign in.
161 | # :none = No lock strategy. You should handle locking by yourself.
162 | # config.lock_strategy = :failed_attempts
163 |
164 | # Defines which key will be used when locking and unlocking an account
165 | # config.unlock_keys = [ :email ]
166 |
167 | # Defines which strategy will be used to unlock an account.
168 | # :email = Sends an unlock link to the user email
169 | # :time = Re-enables login after a certain amount of time (see :unlock_in below)
170 | # :both = Enables both strategies
171 | # :none = No unlock strategy. You should handle unlocking by yourself.
172 | # config.unlock_strategy = :both
173 |
174 | # Number of authentication tries before locking an account if lock_strategy
175 | # is failed attempts.
176 | # config.maximum_attempts = 20
177 |
178 | # Time interval to unlock the account if :time is enabled as unlock_strategy.
179 | # config.unlock_in = 1.hour
180 |
181 | # Warn on the last attempt before the account is locked.
182 | # config.last_attempt_warning = true
183 |
184 | # ==> Configuration for :recoverable
185 | #
186 | # Defines which key will be used when recovering the password for an account
187 | # config.reset_password_keys = [ :email ]
188 |
189 | # Time interval you can reset your password with a reset password key.
190 | # Don't put a too small interval or your users won't have the time to
191 | # change their passwords.
192 | config.reset_password_within = 6.hours
193 |
194 | # ==> Configuration for :encryptable
195 | # Allow you to use another encryption algorithm besides bcrypt (default). You can use
196 | # :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1,
197 | # :authlogic_sha512 (then you should set stretches above to 20 for default behavior)
198 | # and :restful_authentication_sha1 (then you should set stretches to 10, and copy
199 | # REST_AUTH_SITE_KEY to pepper).
200 | #
201 | # Require the `devise-encryptable` gem when using anything other than bcrypt
202 | # config.encryptor = :sha512
203 |
204 | # ==> Scopes configuration
205 | # Turn scoped views on. Before rendering "sessions/new", it will first check for
206 | # "users/sessions/new". It's turned off by default because it's slower if you
207 | # are using only default views.
208 | # config.scoped_views = false
209 |
210 | # Configure the default scope given to Warden. By default it's the first
211 | # devise role declared in your routes (usually :user).
212 | # config.default_scope = :user
213 |
214 | # Set this configuration to false if you want /users/sign_out to sign out
215 | # only the current scope. By default, Devise signs out all scopes.
216 | # config.sign_out_all_scopes = true
217 |
218 | # ==> Navigation configuration
219 | # Lists the formats that should be treated as navigational. Formats like
220 | # :html, should redirect to the sign in page when the user does not have
221 | # access, but formats like :xml or :json, should return 401.
222 | #
223 | # If you have any extra navigational formats, like :iphone or :mobile, you
224 | # should add them to the navigational formats lists.
225 | #
226 | # The "*/*" below is required to match Internet Explorer requests.
227 | # config.navigational_formats = ['*/*', :html]
228 |
229 | # The default HTTP method used to sign out a resource. Default is :delete.
230 | config.sign_out_via = :delete
231 |
232 | # ==> OmniAuth
233 | # Add a new OmniAuth provider. Check the wiki for more information on setting
234 | # up on your models and hooks.
235 | # config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
236 |
237 | # ==> Warden configuration
238 | # If you want to use other strategies, that are not supported by Devise, or
239 | # change the failure app, you can configure them inside the config.warden block.
240 | #
241 | # config.warden do |manager|
242 | # manager.intercept_401 = false
243 | # manager.default_strategies(scope: :user).unshift :some_external_strategy
244 | # end
245 |
246 | # ==> Mountable engine configurations
247 | # When using Devise inside an engine, let's call it `MyEngine`, and this engine
248 | # is mountable, there are some extra configurations to be taken into account.
249 | # The following options are available, assuming the engine is mounted as:
250 | #
251 | # mount MyEngine, at: '/my_engine'
252 | #
253 | # The router that invoked `devise_for`, in the example above, would be:
254 | # config.router_name = :my_engine
255 | #
256 | # When using omniauth, Devise cannot automatically set Omniauth path,
257 | # so you need to do it manually. For the users scope, it would be:
258 | # config.omniauth_path_prefix = '/my_engine/users/auth'
259 | end
260 |
--------------------------------------------------------------------------------