2 |
3 | <%= render 'users/form' %>
--------------------------------------------------------------------------------
/bin/bundle:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3 | load Gem.bin_path('bundler', 'bundle')
4 |
--------------------------------------------------------------------------------
/bin/rails:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 | begin
3 | load File.expand_path("../spring", __FILE__)
4 | rescue LoadError
5 | end
6 | APP_PATH = File.expand_path('../../config/application', __FILE__)
7 | require_relative '../config/boot'
8 | require 'rails/commands'
9 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | ENV["GEM_PATH"] = ([Bundler.bundle_path.to_s] + Gem.path).join(File::PATH_SEPARATOR)
12 | ENV["GEM_HOME"] = ""
13 | Gem.paths = ENV
14 |
15 | gem "spring", match[1]
16 | require "spring/binstub"
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/config/application.rb:
--------------------------------------------------------------------------------
1 | require File.expand_path('../boot', __FILE__)
2 |
3 | # Pick the frameworks you want:
4 | require "active_model/railtie"
5 | require "active_record/railtie"
6 | require "action_controller/railtie"
7 | require "action_mailer/railtie"
8 | require "action_view/railtie"
9 | require "sprockets/railtie"
10 | # require "rails/test_unit/railtie"
11 |
12 | # Require the gems listed in Gemfile, including any gems
13 | # you've limited to :test, :development, or :production.
14 | Bundler.require(*Rails.groups)
15 |
16 | module Workflowy
17 | class Application < Rails::Application
18 |
19 | config.generators do |g|
20 | g.test_framework :rspec,
21 | :fixtures => true,
22 | :view_specs => false,
23 | :helper_specs => false,
24 | :routing_specs => false,
25 | :controller_specs => true,
26 | :request_specs => true
27 | g.fixture_replacement :factory_girl, dir: 'spec/factories'
28 |
29 | g.javascript_engine :js
30 | end
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/config/boot.rb:
--------------------------------------------------------------------------------
1 | # Set up gems listed in the Gemfile.
2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3 |
4 | require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
5 |
--------------------------------------------------------------------------------
/config/database.yml:
--------------------------------------------------------------------------------
1 | # PostgreSQL. Versions 8.2 and up are supported.
2 | #
3 | # Install the pg driver:
4 | # gem install pg
5 | # On OS X with Homebrew:
6 | # gem install pg -- --with-pg-config=/usr/local/bin/pg_config
7 | # On OS X with MacPorts:
8 | # gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config
9 | # On Windows:
10 | # gem install pg
11 | # Choose the win32 build.
12 | # Install PostgreSQL and put its /bin directory on your path.
13 | #
14 | # Configure Using Gemfile
15 | # gem 'pg'
16 | #
17 | default: &default
18 | adapter: postgresql
19 | encoding: unicode
20 | # For details on connection pooling, see rails configuration guide
21 | # http://guides.rubyonrails.org/configuring.html#database-pooling
22 | pool: 5
23 | template: template0
24 |
25 | development:
26 | <<: *default
27 | database: workflowy_development
28 |
29 | # The specified database role being used to connect to postgres.
30 | # To create additional roles in postgres see `$ createuser --help`.
31 | # When left blank, postgres will use the default role. This is
32 | # the same name as the operating system user that initialized the database.
33 | #username: workflowy
34 |
35 | # The password associated with the postgres role (username).
36 | #password:
37 |
38 | # Connect on a TCP socket. Omitted by default since the client uses a
39 | # domain socket that doesn't need configuration. Windows does not have
40 | # domain sockets, so uncomment these lines.
41 | #host: localhost
42 |
43 | # The TCP port the server listens on. Defaults to 5432.
44 | # If your server runs on a different port number, change accordingly.
45 | #port: 5432
46 |
47 | # Schema search path. The server defaults to $user,public
48 | #schema_search_path: myapp,sharedapp,public
49 |
50 | # Minimum log levels, in increasing order:
51 | # debug5, debug4, debug3, debug2, debug1,
52 | # log, notice, warning, error, fatal, and panic
53 | # Defaults to warning.
54 | #min_messages: notice
55 |
56 | # Warning: The database defined as "test" will be erased and
57 | # re-generated from your development database when you run "rake".
58 | # Do not set this db to the same as development or production.
59 | test:
60 | <<: *default
61 | database: workflowy_test
62 |
63 | # As with config/secrets.yml, you never want to store sensitive information,
64 | # like your database password, in your source code. If your source code is
65 | # ever seen by anyone, they now have access to your database.
66 | #
67 | # Instead, provide the password as a unix environment variable when you boot
68 | # the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database
69 | # for a full rundown on how to provide these environment variables in a
70 | # production deployment.
71 | #
72 | # On Heroku and other platform providers, you may have a full connection URL
73 | # available as an environment variable. For example:
74 | #
75 | # DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase"
76 | #
77 | # You can use this database configuration with:
78 | #
79 | # production:
80 | # url: <%= ENV['DATABASE_URL'] %>
81 | #
82 | production:
83 | <<: *default
84 | database: workflowy_production
85 | username: workflowy
86 | password: <%= ENV['WORKFLOWY_DATABASE_PASSWORD'] %>
87 |
--------------------------------------------------------------------------------
/config/database.yml.travis:
--------------------------------------------------------------------------------
1 | default: &default
2 | adapter: postgresql
3 | encoding: unicode
4 | # For details on connection pooling, see rails configuration guide
5 | # http://guides.rubyonrails.org/configuring.html#database-pooling
6 | pool: 5
7 | template: template0
8 |
9 | test:
10 | <<: *default
11 | adapter: postgresql
12 | database: travis_ci_test
13 | username: postgres
14 |
--------------------------------------------------------------------------------
/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/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 | # Adds additional error checking when serving assets at runtime.
31 | # Checks for improperly declared sprockets dependencies.
32 | # Raises helpful error messages.
33 | config.assets.raise_runtime_errors = true
34 |
35 | # Raises error for missing translations
36 | # config.action_view.raise_on_missing_translations = true
37 | end
38 |
--------------------------------------------------------------------------------
/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 nginx, varnish or squid.
20 | # config.action_dispatch.rack_cache = true
21 |
22 | # Disable Rails's static asset server (Apache or nginx will already do this).
23 | config.serve_static_assets = true
24 |
25 | # Compress JavaScripts and CSS.
26 | config.assets.js_compressor = :uglifier
27 | # config.assets.css_compressor = :sass
28 |
29 | # Do not fallback to assets pipeline if a precompiled asset is missed.
30 | config.assets.compile = true
31 |
32 | # Generate digests for assets URLs.
33 | config.assets.digest = true
34 |
35 | # Version of your assets, change this if you want to expire all your assets.
36 | config.assets.version = '1.0'
37 |
38 | # Specifies the header that your server uses for sending files.
39 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
40 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
41 |
42 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
43 | # config.force_ssl = true
44 |
45 | # Set to :debug to see everything in the log.
46 | config.log_level = :info
47 |
48 | # Prepend all log lines with the following tags.
49 | # config.log_tags = [ :subdomain, :uuid ]
50 |
51 | # Use a different logger for distributed setups.
52 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
53 |
54 | # Use a different cache store in production.
55 | # config.cache_store = :mem_cache_store
56 |
57 | # Enable serving of images, stylesheets, and JavaScripts from an asset server.
58 | # config.action_controller.asset_host = "http://assets.example.com"
59 |
60 | # Precompile additional assets.
61 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
62 | # config.assets.precompile += %w( search.js )
63 |
64 | # Ignore bad email addresses and do not raise email delivery errors.
65 | # Set this to true and configure the email server for immediate delivery to raise delivery errors.
66 | # config.action_mailer.raise_delivery_errors = false
67 |
68 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
69 | # the I18n.default_locale when a translation cannot be found).
70 | config.i18n.fallbacks = true
71 |
72 | # Send deprecation notices to registered listeners.
73 | config.active_support.deprecation = :notify
74 |
75 | # Disable automatic flushing of the log to improve performance.
76 | # config.autoflush_log = false
77 |
78 | # Use default logging formatter so that PID and timestamp are not suppressed.
79 | config.log_formatter = ::Logger::Formatter.new
80 |
81 | # Do not dump schema after migrations.
82 | config.active_record.dump_schema_after_migration = false
83 | end
84 |
--------------------------------------------------------------------------------
/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 asset server for tests with Cache-Control for performance.
16 | config.serve_static_assets = true
17 | config.static_cache_control = 'public, max-age=3600'
18 |
19 | # Show full error reports and disable caching.
20 | config.consider_all_requests_local = true
21 | config.action_controller.perform_caching = false
22 |
23 | # Raise exceptions instead of rendering exception templates.
24 | config.action_dispatch.show_exceptions = false
25 |
26 | # Disable request forgery protection in test environment.
27 | config.action_controller.allow_forgery_protection = false
28 |
29 | # Tell Action Mailer not to deliver emails to the real world.
30 | # The :test delivery method accumulates sent emails in the
31 | # ActionMailer::Base.deliveries array.
32 | config.action_mailer.delivery_method = :test
33 |
34 | # Print deprecation notices to the stderr.
35 | config.active_support.deprecation = :stderr
36 |
37 | # Raises error for missing translations
38 | # config.action_view.raise_on_missing_translations = true
39 | end
40 |
--------------------------------------------------------------------------------
/config/initializers/backtrace_silencers.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
5 |
6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7 | # Rails.backtrace_cleaner.remove_silencers!
8 |
--------------------------------------------------------------------------------
/config/initializers/cookies_serializer.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | Rails.application.config.action_dispatch.cookies_serializer = :json
--------------------------------------------------------------------------------
/config/initializers/filter_parameter_logging.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Configure sensitive parameters which will be filtered from the log file.
4 | Rails.application.config.filter_parameters += [:password]
5 |
--------------------------------------------------------------------------------
/config/initializers/inflections.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new inflection rules using the following format. Inflections
4 | # are locale specific, and you may define rules for as many different
5 | # locales as you wish. All of these examples are active by default:
6 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
7 | # inflect.plural /^(ox)$/i, '\1en'
8 | # inflect.singular /^(ox)en/i, '\1'
9 | # inflect.irregular 'person', 'people'
10 | # inflect.uncountable %w( fish sheep )
11 | # end
12 |
13 | # These inflection rules are supported but not enabled by default:
14 | # ActiveSupport::Inflector.inflections(:en) do |inflect|
15 | # inflect.acronym 'RESTful'
16 | # end
17 |
--------------------------------------------------------------------------------
/config/initializers/mime_types.rb:
--------------------------------------------------------------------------------
1 | # Be sure to restart your server when you modify this file.
2 |
3 | # Add new mime types for use in respond_to blocks:
4 | # Mime::Type.register "text/richtext", :rtf
5 |
--------------------------------------------------------------------------------
/config/initializers/omniauth.rb:
--------------------------------------------------------------------------------
1 | Rails.application.config.middleware.use OmniAuth::Builder do
2 | provider :google_oauth2, ENV["GOOGLE_CLIENT_ID"], ENV["GOOGLE_CLIENT_SECRET"]
3 | end
--------------------------------------------------------------------------------
/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: '_workflowy_session'
4 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/config/newrelic.yml:
--------------------------------------------------------------------------------
1 | #
2 | # This file configures the New Relic Agent. New Relic monitors Ruby, Java,
3 | # .NET, PHP, Python and Node applications with deep visibility and low
4 | # overhead. For more information, visit www.newrelic.com.
5 | #
6 | # Generated July 03, 2014
7 | #
8 | # This configuration file is custom generated for app26739848@heroku.com
9 |
10 |
11 | # Here are the settings that are common to all environments
12 | common: &default_settings
13 | # ============================== LICENSE KEY ===============================
14 |
15 | # You must specify the license key associated with your New Relic
16 | # account. This key binds your Agent's data to your account in the
17 | # New Relic service.
18 | license_key: ENV['NEW_RELIC_LICENSE_KEY']
19 |
20 | # Agent Enabled (Ruby/Rails Only)
21 | # Use this setting to force the agent to run or not run.
22 | # Default is 'auto' which means the agent will install and run only
23 | # if a valid dispatcher such as Mongrel is running. This prevents
24 | # it from running with Rake or the console. Set to false to
25 | # completely turn the agent off regardless of the other settings.
26 | # Valid values are true, false and auto.
27 | #
28 | # agent_enabled: auto
29 |
30 | # Application Name Set this to be the name of your application as
31 | # you'd like it show up in New Relic. The service will then auto-map
32 | # instances of your application into an "application" on your
33 | # dashboard page. If you want to map this instance into multiple
34 | # apps, like "AJAX Requests" and "All UI" then specify a semicolon
35 | # separated list of up to three distinct names, or a yaml list.
36 | # Defaults to the capitalized RAILS_ENV or RACK_ENV (i.e.,
37 | # Production, Staging, etc)
38 | #
39 | # Example:
40 | #
41 | # app_name:
42 | # - Ajax Service
43 | # - All Services
44 | #
45 | app_name: My Application
46 |
47 | # When "true", the agent collects performance data about your
48 | # application and reports this data to the New Relic service at
49 | # newrelic.com. This global switch is normally overridden for each
50 | # environment below. (formerly called 'enabled')
51 | monitor_mode: true
52 |
53 | # Developer mode should be off in every environment but
54 | # development as it has very high overhead in memory.
55 | developer_mode: false
56 |
57 | # The newrelic agent generates its own log file to keep its logging
58 | # information separate from that of your application. Specify its
59 | # log level here.
60 | log_level: info
61 |
62 | # Optionally set the path to the log file This is expanded from the
63 | # root directory (may be relative or absolute, e.g. 'log/' or
64 | # '/var/log/') The agent will attempt to create this directory if it
65 | # does not exist.
66 | # log_file_path: 'log'
67 |
68 | # Optionally set the name of the log file, defaults to 'newrelic_agent.log'
69 | # log_file_name: 'newrelic_agent.log'
70 |
71 | # The newrelic agent communicates with the service via https by default. This
72 | # prevents eavesdropping on the performance metrics transmitted by the agent.
73 | # The encryption required by SSL introduces a nominal amount of CPU overhead,
74 | # which is performed asynchronously in a background thread. If you'd prefer
75 | # to send your metrics over http uncomment the following line.
76 | # ssl: false
77 |
78 | #============================== Browser Monitoring ===============================
79 | # New Relic Real User Monitoring gives you insight into the performance real users are
80 | # experiencing with your website. This is accomplished by measuring the time it takes for
81 | # your users' browsers to download and render your web pages by injecting a small amount
82 | # of JavaScript code into the header and footer of each page.
83 | browser_monitoring:
84 | # By default the agent automatically injects the monitoring JavaScript
85 | # into web pages. Set this attribute to false to turn off this behavior.
86 | auto_instrument: true
87 |
88 | # Proxy settings for connecting to the New Relic server.
89 | #
90 | # If a proxy is used, the host setting is required. Other settings
91 | # are optional. Default port is 8080.
92 | #
93 | # proxy_host: hostname
94 | # proxy_port: 8080
95 | # proxy_user:
96 | # proxy_pass:
97 |
98 | # The agent can optionally log all data it sends to New Relic servers to a
99 | # separate log file for human inspection and auditing purposes. To enable this
100 | # feature, change 'enabled' below to true.
101 | # See: https://newrelic.com/docs/ruby/audit-log
102 | audit_log:
103 | enabled: false
104 |
105 | # Tells transaction tracer and error collector (when enabled)
106 | # whether or not to capture HTTP params. When true, frameworks can
107 | # exclude HTTP parameters from being captured.
108 | # Rails: the RoR filter_parameter_logging excludes parameters
109 | # Java: create a config setting called "ignored_params" and set it to
110 | # a comma separated list of HTTP parameter names.
111 | # ex: ignored_params: credit_card, ssn, password
112 | capture_params: false
113 |
114 | # Transaction tracer captures deep information about slow
115 | # transactions and sends this to the New Relic service once a
116 | # minute. Included in the transaction is the exact call sequence of
117 | # the transactions including any SQL statements issued.
118 | transaction_tracer:
119 |
120 | # Transaction tracer is enabled by default. Set this to false to
121 | # turn it off. This feature is only available at the Professional
122 | # and above product levels.
123 | enabled: true
124 |
125 | # Threshold in seconds for when to collect a transaction
126 | # trace. When the response time of a controller action exceeds
127 | # this threshold, a transaction trace will be recorded and sent to
128 | # New Relic. Valid values are any float value, or (default) "apdex_f",
129 | # which will use the threshold for an dissatisfying Apdex
130 | # controller action - four times the Apdex T value.
131 | transaction_threshold: apdex_f
132 |
133 | # When transaction tracer is on, SQL statements can optionally be
134 | # recorded. The recorder has three modes, "off" which sends no
135 | # SQL, "raw" which sends the SQL statement in its original form,
136 | # and "obfuscated", which strips out numeric and string literals.
137 | record_sql: obfuscated
138 |
139 | # Threshold in seconds for when to collect stack trace for a SQL
140 | # call. In other words, when SQL statements exceed this threshold,
141 | # then capture and send to New Relic the current stack trace. This is
142 | # helpful for pinpointing where long SQL calls originate from.
143 | stack_trace_threshold: 0.500
144 |
145 | # Determines whether the agent will capture query plans for slow
146 | # SQL queries. Only supported in mysql and postgres. Should be
147 | # set to false when using other adapters.
148 | # explain_enabled: true
149 |
150 | # Threshold for query execution time below which query plans will
151 | # not be captured. Relevant only when `explain_enabled` is true.
152 | # explain_threshold: 0.5
153 |
154 | # Error collector captures information about uncaught exceptions and
155 | # sends them to New Relic for viewing
156 | error_collector:
157 |
158 | # Error collector is enabled by default. Set this to false to turn
159 | # it off. This feature is only available at the Professional and above
160 | # product levels.
161 | enabled: true
162 |
163 | # To stop specific errors from reporting to New Relic, set this property
164 | # to comma-separated values. Default is to ignore routing errors,
165 | # which are how 404's get triggered.
166 | ignore_errors: "ActionController::RoutingError,Sinatra::NotFound"
167 |
168 | # If you're interested in capturing memcache keys as though they
169 | # were SQL uncomment this flag. Note that this does increase
170 | # overhead slightly on every memcached call, and can have security
171 | # implications if your memcached keys are sensitive
172 | # capture_memcache_keys: true
173 |
174 | # Application Environments
175 | # ------------------------------------------
176 | # Environment-specific settings are in this section.
177 | # For Rails applications, RAILS_ENV is used to determine the environment.
178 | # For Java applications, pass -Dnewrelic.environment to set
179 | # the environment.
180 |
181 | # NOTE if your application has other named environments, you should
182 | # provide newrelic configuration settings for these environments here.
183 |
184 | development:
185 | <<: *default_settings
186 | # Turn on communication to New Relic service in development mode
187 | monitor_mode: true
188 | app_name: My Application (Development)
189 |
190 | # Rails Only - when running in Developer Mode, the New Relic Agent will
191 | # present performance information on the last 100 transactions you have
192 | # executed since starting the mongrel.
193 | # NOTE: There is substantial overhead when running in developer mode.
194 | # Do not use for production or load testing.
195 | developer_mode: true
196 |
197 | test:
198 | <<: *default_settings
199 | # It almost never makes sense to turn on the agent when running
200 | # unit, functional or integration tests or the like.
201 | monitor_mode: false
202 |
203 | # Turn on the agent in production for 24x7 monitoring. NewRelic
204 | # testing shows an average performance impact of < 5 ms per
205 | # transaction, you can leave this on all the time without
206 | # incurring any user-visible performance degradation.
207 | production:
208 | <<: *default_settings
209 | monitor_mode: true
210 |
211 | # Many applications have a staging environment which behaves
212 | # identically to production. Support for that environment is provided
213 | # here. By default, the staging environment has the agent turned on.
214 | staging:
215 | <<: *default_settings
216 | monitor_mode: true
217 | app_name: My Application (Staging)
218 |
--------------------------------------------------------------------------------
/config/routes.rb:
--------------------------------------------------------------------------------
1 | Rails.application.routes.draw do
2 | root to: 'root#index'
3 |
4 | resource :session, only: [:new, :create, :destroy] do
5 | post :demo
6 | end
7 | get '/auth/google_oauth2/callback', to: 'sessions#google_login'
8 | resources :users, only: [:new, :create]
9 |
10 | resources :items, except: [:new, :edit], shallow: true do
11 | patch :rerank, on: :collection
12 | member do
13 | post action: :create
14 | patch :collapse
15 | patch :rerank
16 | end
17 |
18 | resources :shares, only: [:index, :create]
19 | end
20 |
21 | resources :shares, only: [:show, :destroy] do
22 | patch :editable, on: :member
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/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: 6f2f8a0e035b0c04299f9460a74787c3b6106b031f6328a7be68b6c3b637438676f916ef7b3305ed35cbd02d46aa195a5e4d5d4914908e7bbf2c2f3a97c63ca4
15 |
16 | test:
17 | secret_key_base: c052b057e64152a4ffd7bcb9fca1d085da54190f28b2a8ff5e0db06cbd41f3813a09756b854d8fe71624227f2d845411217e551cf55582090c5918a4222ed753
18 |
19 | # Do not keep production secrets in the repository,
20 | # instead read values from the environment.
21 | production:
22 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
23 |
--------------------------------------------------------------------------------
/db/migrate/20140618222800_create_users.rb:
--------------------------------------------------------------------------------
1 | class CreateUsers < ActiveRecord::Migration
2 | def change
3 | create_table :users do |t|
4 | t.string :email, null: false
5 | t.string :password_digest, null: false
6 | t.string :session_token, length: 32, null: false
7 |
8 | t.timestamps
9 | end
10 |
11 | add_index :users, :email, unique: true
12 | add_index :users, :session_token, unique: true
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/db/migrate/20140621025457_create_items.rb:
--------------------------------------------------------------------------------
1 | class CreateItems < ActiveRecord::Migration
2 | def change
3 | create_table :items do |t|
4 | t.references :user
5 | t.integer :parent_id
6 | t.integer :rank
7 | t.text :title
8 | t.text :notes
9 |
10 | t.timestamps
11 | end
12 |
13 | add_index :items, [:user_id, :parent_id, :rank], unique: true
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/db/migrate/20140624142227_create_views.rb:
--------------------------------------------------------------------------------
1 | class CreateViews < ActiveRecord::Migration
2 | def change
3 | create_table :views do |t|
4 | t.references :user, null: false
5 | t.references :item
6 | t.boolean :collapsed, null: false
7 | t.boolean :starred, null: false
8 |
9 | t.timestamps
10 | end
11 |
12 | add_index :views, [:user_id, :item_id], unique: true
13 | end
14 | end
--------------------------------------------------------------------------------
/db/migrate/20140625132201_create_shares.rb:
--------------------------------------------------------------------------------
1 | class CreateShares < ActiveRecord::Migration
2 | def change
3 | create_table :shares do |t|
4 | t.references :user, index: true
5 | t.references :item, index: true, null: false
6 | t.boolean :can_edit, null: false
7 |
8 | t.timestamps
9 | end
10 |
11 | add_column :items, :url, :string, length: 43
12 | add_index :items, :url, unique: true
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/db/migrate/20140626194425_change_items_url_to_uuid.rb:
--------------------------------------------------------------------------------
1 | class ChangeItemsUrlToUuid < ActiveRecord::Migration
2 | def change
3 | remove_index :items, :url
4 | remove_column :items, :url, :string, length: 43
5 |
6 | add_column :items, :uuid, :string, limit: 36, null: false
7 | add_index :items, :uuid, unique: true
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/db/migrate/20140627041832_add_uid_and_provider_to_users.rb:
--------------------------------------------------------------------------------
1 | class AddUidAndProviderToUsers < ActiveRecord::Migration
2 | def change
3 | add_column :users, :uid, :string
4 | add_column :users, :provider, :string
5 | end
6 | end
7 |
--------------------------------------------------------------------------------
/db/migrate/20140629233057_allow_null_item_titles.rb:
--------------------------------------------------------------------------------
1 | class AllowNullItemTitles < ActiveRecord::Migration
2 | def up
3 | change_table :items do |t|
4 | t.change :title, :string, null: true
5 | t.change :user_id, :integer, null: false
6 | t.change :uuid, :string, null: false
7 | end
8 | end
9 |
10 | def down
11 | change_table :items do |t|
12 | t.change :title, :string, null: false
13 | t.change :user_id, :integer, null: true
14 | t.change :uuid, :string, null: true
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/db/migrate/20140630232756_item_rank_deferrable.rb:
--------------------------------------------------------------------------------
1 | class ItemRankDeferrable < ActiveRecord::Migration
2 | def up
3 | remove_index :items, [:user_id, :parent_id, :rank]
4 |
5 | execute <<-SQL
6 | ALTER TABLE items
7 | ADD CONSTRAINT items_rank UNIQUE (user_id, parent_id, rank)
8 | DEFERRABLE INITIALLY IMMEDIATE;
9 | SQL
10 | end
11 |
12 | def down
13 | execute <<-SQL
14 | ALTER TABLE items
15 | DROP CONSTRAINT IF EXISTS items_rank;
16 | SQL
17 |
18 | add_index :items, [:user_id, :parent_id, :rank], unique: true
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/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: 20140630232756) do
15 |
16 | # These are extensions that must be enabled in order to support this database
17 | enable_extension "plpgsql"
18 |
19 | create_table "items", force: true do |t|
20 | t.integer "user_id", null: false
21 | t.integer "parent_id"
22 | t.integer "rank"
23 | t.string "title"
24 | t.text "notes"
25 | t.datetime "created_at"
26 | t.datetime "updated_at"
27 | t.string "uuid", null: false
28 | end
29 |
30 | add_index "items", ["user_id", "parent_id", "rank"], name: "items_rank", unique: true, using: :btree
31 | add_index "items", ["uuid"], name: "index_items_on_uuid", unique: true, using: :btree
32 |
33 | create_table "shares", force: true do |t|
34 | t.integer "user_id"
35 | t.integer "item_id", null: false
36 | t.boolean "can_edit", null: false
37 | t.datetime "created_at"
38 | t.datetime "updated_at"
39 | end
40 |
41 | add_index "shares", ["item_id"], name: "index_shares_on_item_id", using: :btree
42 | add_index "shares", ["user_id"], name: "index_shares_on_user_id", using: :btree
43 |
44 | create_table "users", force: true do |t|
45 | t.string "email", null: false
46 | t.string "password_digest", null: false
47 | t.string "session_token", null: false
48 | t.datetime "created_at"
49 | t.datetime "updated_at"
50 | t.string "uid"
51 | t.string "provider"
52 | end
53 |
54 | add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
55 | add_index "users", ["session_token"], name: "index_users_on_session_token", unique: true, using: :btree
56 |
57 | create_table "views", force: true do |t|
58 | t.integer "user_id", null: false
59 | t.integer "item_id"
60 | t.boolean "collapsed", null: false
61 | t.boolean "starred", null: false
62 | t.datetime "created_at"
63 | t.datetime "updated_at"
64 | end
65 |
66 | add_index "views", ["user_id", "item_id"], name: "index_views_on_user_id_and_item_id", unique: true, using: :btree
67 |
68 | end
69 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/lib/assets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daniel-light/workflowy-clone/454358cc7ca9b4055ded0428de84b799fd6d59ca/lib/assets/.keep
--------------------------------------------------------------------------------
/lib/tasks/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daniel-light/workflowy-clone/454358cc7ca9b4055ded0428de84b799fd6d59ca/lib/tasks/.keep
--------------------------------------------------------------------------------
/log/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daniel-light/workflowy-clone/454358cc7ca9b4055ded0428de84b799fd6d59ca/log/.keep
--------------------------------------------------------------------------------
/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.
If you are the application owner check the logs for more information.
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daniel-light/workflowy-clone/454358cc7ca9b4055ded0428de84b799fd6d59ca/public/favicon.ico
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
2 | #
3 | # To ban all spiders from the entire site uncomment the next two lines:
4 | # User-agent: *
5 | # Disallow: /
6 |
--------------------------------------------------------------------------------
/spec/controllers/items_controller_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe ItemsController, :type => :controller do
4 |
5 | end
6 |
--------------------------------------------------------------------------------
/spec/controllers/root_controller_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe RootController, :type => :controller do
4 |
5 | end
6 |
--------------------------------------------------------------------------------
/spec/controllers/sessions_controller_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe SessionsController, :type => :controller do
4 |
5 | end
6 |
--------------------------------------------------------------------------------
/spec/controllers/shares_controller_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe SharesController, :type => :controller do
4 |
5 | end
6 |
--------------------------------------------------------------------------------
/spec/controllers/users_controller_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe UsersController, :type => :controller do
4 |
5 | end
6 |
--------------------------------------------------------------------------------
/spec/factories/items.rb:
--------------------------------------------------------------------------------
1 | # Read about factories at https://github.com/thoughtbot/factory_girl
2 |
3 | FactoryGirl.define do
4 | factory :item do
5 | user_id 1
6 | sequence(:rank) { |n| n }
7 | title "title"
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/factories/shares.rb:
--------------------------------------------------------------------------------
1 | # Read about factories at https://github.com/thoughtbot/factory_girl
2 |
3 | FactoryGirl.define do
4 | factory :share do
5 | user_id 1
6 | item_id 1
7 | can_edit nil
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/spec/factories/users.rb:
--------------------------------------------------------------------------------
1 | FactoryGirl.define do
2 | factory :user do
3 | email "example@example.com"
4 | password "green1"
5 | end
6 | end
--------------------------------------------------------------------------------
/spec/factories/views.rb:
--------------------------------------------------------------------------------
1 | # Read about factories at https://github.com/thoughtbot/factory_girl
2 |
3 | FactoryGirl.define do
4 | factory :view do
5 | user_id 1
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/spec/models/item_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe Item, :type => :model do
4 |
5 | context 'validations' do
6 | it 'validates when given a user_id and rank' do
7 | expect(create(:item)).to be_valid
8 | end
9 |
10 | it { should validate_presence_of(:user_id) }
11 |
12 | it { should validate_presence_of(:rank) }
13 |
14 | it do
15 | create(:item)
16 |
17 | should validate_uniqueness_of(:rank).scoped_to([:user_id, :parent_id])
18 | end
19 |
20 | it 'can have the same rank as another item with a different parent' do
21 | parent = create(:item)
22 | first_child = parent.children.create(user_id: 1, rank: 1)
23 | second_parent = create(:item)
24 | second_child = second_parent.children.create(user_id: 1, rank: 1)
25 | expect(second_child).to be_valid
26 | end
27 |
28 | it do
29 | create(:item)
30 |
31 | should validate_uniqueness_of(:uuid)
32 | end
33 | it { should ensure_length_of(:uuid).is_equal_to(36) }
34 |
35 | it 'should automatically set a blank uuid' do
36 | item = build(:item, uuid: nil)
37 | item.valid?
38 | expect(item.uuid.length).to eq(36)
39 | end
40 |
41 | it 'should automatically set a blank title' do
42 | item = build(:item, title: nil)
43 |
44 | item.valid?
45 |
46 | expect(item.title).to eq('')
47 | end
48 |
49 | it 'should automatically set blank notes' do
50 | item = build(:item, notes: nil)
51 |
52 | item.valid?
53 |
54 | expect(item.notes).to eq('')
55 | end
56 | end
57 |
58 | context 'associations' do
59 | it { should belong_to(:user) }
60 | it { should belong_to(:parent) }
61 | it { should have_many(:children) }
62 | it { should have_many(:views) }
63 | it { should have_many(:shares) }
64 | end
65 |
66 | context '#can_view?' do
67 | let(:items) { [create(:item, id: 1, user: owner),
68 | create(:item, id: 2, parent_id: 1),
69 | create(:item, id: 3, parent_id: 2)] }
70 | let(:owner) { create(:user, id: 1) }
71 | let(:user) { User.create(id: 2, email: 'a', password: '123456') }
72 |
73 | it 'should be viewable by the owner' do
74 | expect(items.all? { |item| item.can_view?(owner) }).to be true
75 | end
76 |
77 | it 'shouldn\'t be viewable by another user' do
78 | expect(items.none? { |item| item.can_view?(user) }).to be true
79 | end
80 |
81 | it 'should be viewable by a user once shared' do
82 | items.first.shares.create!(user_id: 2)
83 | expect(items.all? { |item| item.can_view?(user) }).to be true
84 | end
85 |
86 | it 'should be viewable by anyone once shared anonymously' do
87 | items.first.shares.create!(user_id: nil)
88 | expect(items.all? { |item| item.can_view?(nil) }).to be true
89 | end
90 | end
91 |
92 | context '#can_edit?' do
93 | let(:items) { [create(:item, id: 1, user: owner),
94 | create(:item, id: 2, parent_id: 1),
95 | create(:item, id: 3, parent_id: 2)] }
96 | let(:owner) { create(:user, id: 1) }
97 | let(:user) { User.create(id: 2, email: 'a', password: '123456') }
98 |
99 | it 'should be editable by the owner' do
100 | expect(items.all? { |item| item.can_edit?(owner) }).to be true
101 | end
102 |
103 | it 'shouldn\'t be editable by another user' do
104 | expect(items.none? { |item| item.can_edit?(user) }).to be true
105 | end
106 |
107 | it 'should be editable by a user once shared with edit set' do
108 | items.first.shares.create!(user_id: 2, can_edit: true)
109 | expect(items.all? { |item| item.can_edit?(user) }).to be true
110 | end
111 |
112 | it 'should\'t be editable by a user if shared without edit set' do
113 | items.first.shares.create!(user_id: 2, can_edit: false)
114 | expect(items.none? { |item| item.can_edit?(user) }).to be true
115 | end
116 |
117 | it 'should be editable by anyone once shared anonymously with edit set' do
118 | items.first.shares.create!(user_id: nil, can_edit: true)
119 | expect(items.all? { |item| item.can_edit?(nil) }).to be true
120 | end
121 |
122 | it 'should\'t be editable by anonymous without edit set' do
123 | items.first.shares.create!(user_id: 2, can_edit: false)
124 | expect(items.none? { |item| item.can_edit?(nil) }).to be true
125 | end
126 | end
127 | end
128 |
--------------------------------------------------------------------------------
/spec/models/share_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe Share, :type => :model do
4 | before(:each) do
5 | create(:user, id: 1)
6 | create(:item, id: 1, user_id: 1)
7 | end
8 |
9 | context 'validations' do
10 | it 'should be valid with a user_id and an item_id' do
11 | expect(create(:item).shares.new(user_id: 3)).to be_valid
12 | end
13 |
14 | it { should validate_presence_of(:item_id) }
15 |
16 | it do
17 | create(:share, user_id: 0, item_id: 1)
18 | should validate_uniqueness_of(:user_id).scoped_to(:item_id)
19 | end
20 |
21 | it 'should be able to have multiple users per item' do
22 | create(:share, user_id: 2, item_id: 1)
23 | expect(build(:share, user_id: 3, item_id: 1)).to be_valid
24 | end
25 |
26 | it 'should automatically set a nil can_edit' do
27 | share = build(:share, can_edit: nil)
28 | share.valid?
29 | expect(share.can_edit).to be false
30 | end
31 |
32 | it 'should not let you share with yourself' do
33 | expect(build(:share, user_id: 1, item_id: 1)).not_to be_valid
34 | end
35 | end
36 |
37 | context 'associations' do
38 | it { should belong_to(:user) }
39 | it { should belong_to(:item) }
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/spec/models/user_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe User, :type => :model do
4 | let(:user) { create(:user) }
5 |
6 | it 'should not generate a password digest from a nil password' do
7 | expect(build(:user, password: nil).password_digest).to be_nil
8 | end
9 |
10 | it '#reset_session_token! should reset the session token' do
11 | starting_token = user.session_token
12 | user.reset_session_token!
13 | expect(user.session_token).not_to eq(starting_token)
14 | end
15 |
16 | context '#is_password?' do
17 | it 'should return true if the password matches' do
18 | expect(user.is_password?('green1')).to be true
19 | end
20 |
21 | it 'should return false if the password does not match' do
22 | expect(user.is_password?('green2')).to be false
23 | end
24 | end
25 |
26 | context '::find_by_credentials' do
27 | before(:each) do
28 | user
29 | end
30 |
31 | it 'should return the user if email and password match' do
32 | expect(User.find_by_credentials('example@example.com', 'green1')).to eq(user)
33 | end
34 |
35 | it 'should return nil if there is no such user' do
36 | expect(User.find_by_credentials('not_a_user', '')).to be nil
37 | end
38 |
39 | it 'should return nil if the password does not match' do
40 | expect(User.find_by_credentials('example@example.com', '')).to be nil
41 | end
42 | end
43 |
44 | context 'validations' do
45 | it 'validates when given an email and password' do
46 | expect(create(:user)).to be_valid
47 | end
48 |
49 | it 'must have an email' do
50 | expect(build(:user, email: nil)).not_to be_valid
51 | end
52 |
53 | it 'must have a password that is six characters or more' do
54 | expect(build(:user, password: 'abc')).not_to be_valid
55 | end
56 |
57 | it 'can have a nil password only when password digest is provied' do
58 | expect(build(:user, password: nil)).not_to be_valid
59 | expect(build(:user, password: nil, password_digest: 'a')).to be_valid
60 | end
61 |
62 | it 'should generate a session token on validation' do
63 | user = build(:user)
64 | expect(user.session_token).to be_nil
65 | user.valid?
66 | expect(user.session_token).not_to be_nil
67 | end
68 | end
69 |
70 | context 'associations' do
71 | it { should have_many(:items) }
72 | it { should have_many(:views) }
73 | it { should have_many(:shares) }
74 | it { should have_many(:shared_items) }
75 | end
76 | end
77 |
--------------------------------------------------------------------------------
/spec/models/view_spec.rb:
--------------------------------------------------------------------------------
1 | require 'rails_helper'
2 |
3 | RSpec.describe View, :type => :model do
4 | context 'validations' do
5 | it 'should be valid when created with a user id' do
6 | expect(create(:view)).to be_valid
7 | end
8 |
9 | it 'should automatically set the collapsed and starred to false' do
10 | view = build(:view, collapsed: nil, starred: nil)
11 | view.valid?
12 | expect(view.collapsed).to be false
13 | expect(view.starred).to be false
14 | end
15 |
16 | it 'should be invalid when created without a user id' do
17 | expect(build(:view, user_id: nil)).not_to be_valid
18 | end
19 |
20 | it 'should be invalid to create two views for the same item and user' do
21 | expect(create(:view, user_id: 1, item_id: 1)).to be_valid
22 | expect(build(:view, user_id: 1, item_id: 1)).not_to be_valid
23 | end
24 | end
25 |
26 | context 'associations' do
27 | it { should belong_to(:user) }
28 | it { should belong_to(:item) }
29 | end
30 | end
31 |
--------------------------------------------------------------------------------
/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 |
7 | # Requires supporting ruby files with custom matchers and macros, etc, in
8 | # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
9 | # run as spec files by default. This means that files in spec/support that end
10 | # in _spec.rb will both be required and run as specs, causing the specs to be
11 | # run twice. It is recommended that you do not name files matching this glob to
12 | # end with _spec.rb. You can configure this pattern with with the --pattern
13 | # option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
14 | Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
15 |
16 | # Checks for pending migrations before tests are run.
17 | # If you are not using ActiveRecord, you can remove this line.
18 | ActiveRecord::Migration.maintain_test_schema!
19 |
20 | RSpec.configure do |config|
21 | # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
22 | config.fixture_path = "#{::Rails.root}/spec/fixtures"
23 |
24 | # If you're not using ActiveRecord, or you'd prefer not to run each of your
25 | # examples within a transaction, remove the following line or assign false
26 | # instead of true.
27 | config.use_transactional_fixtures = true
28 |
29 | # RSpec Rails can automatically mix in different behaviours to your tests
30 | # based on their file location, for example enabling you to call `get` and
31 | # `post` in specs under `spec/controllers`.
32 | #
33 | # You can disable this behaviour by removing the line below, and instead
34 | # explicitly tag your specs with their type, e.g.:
35 | #
36 | # RSpec.describe UsersController, :type => :controller do
37 | # # ...
38 | # end
39 | #
40 | # The different available types are documented in the features, such as in
41 | # https://relishapp.com/rspec/rspec-rails/docs
42 | config.infer_spec_type_from_file_location!
43 | end
44 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | require 'factory_girl_rails'
2 |
3 | RSpec.configure do |config|
4 |
5 | config.include FactoryGirl::Syntax::Methods
6 | =begin
7 | # These two settings work together to allow you to limit a spec run
8 | # to individual examples or groups you care about by tagging them with
9 | # `:focus` metadata. When nothing is tagged with `:focus`, all examples
10 | # get run.
11 | config.filter_run :focus
12 | config.run_all_when_everything_filtered = true
13 |
14 | # Many RSpec users commonly either run the entire suite or an individual
15 | # file, and it's useful to allow more verbose output when running an
16 | # individual spec file.
17 | if config.files_to_run.one?
18 | # Use the documentation formatter for detailed output,
19 | # unless a formatter has already been configured
20 | # (e.g. via a command-line flag).
21 | config.default_formatter = 'doc'
22 | end
23 |
24 | # Print the 10 slowest examples and example groups at the
25 | # end of the spec run, to help surface which specs are running
26 | # particularly slow.
27 | config.profile_examples = 10
28 |
29 | # Run specs in random order to surface order dependencies. If you find an
30 | # order dependency and want to debug it, you can fix the order by providing
31 | # the seed, which is printed after each run.
32 | # --seed 1234
33 | config.order = :random
34 |
35 | # Seed global randomization in this process using the `--seed` CLI option.
36 | # Setting this allows you to use `--seed` to deterministically reproduce
37 | # test failures related to randomization by passing the same `--seed` value
38 | # as the one that triggered the failure.
39 | Kernel.srand config.seed
40 |
41 | # rspec-expectations config goes here. You can use an alternate
42 | # assertion/expectation library such as wrong or the stdlib/minitest
43 | # assertions if you prefer.
44 | config.expect_with :rspec do |expectations|
45 | # Enable only the newer, non-monkey-patching expect syntax.
46 | # For more details, see:
47 | # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
48 | expectations.syntax = :expect
49 | end
50 |
51 | # rspec-mocks config goes here. You can use an alternate test double
52 | # library (such as bogus or mocha) by changing the `mock_with` option here.
53 | config.mock_with :rspec do |mocks|
54 | # Enable only the newer, non-monkey-patching expect syntax.
55 | # For more details, see:
56 | # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
57 | mocks.syntax = :expect
58 |
59 | # Prevents you from mocking or stubbing a method that does not exist on
60 | # a real object. This is generally recommended.
61 | mocks.verify_partial_doubles = true
62 | end
63 | =end
64 | end
65 |
--------------------------------------------------------------------------------
/vendor/assets/javascripts/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daniel-light/workflowy-clone/454358cc7ca9b4055ded0428de84b799fd6d59ca/vendor/assets/javascripts/.keep
--------------------------------------------------------------------------------
/vendor/assets/javascripts/keymaster.js:
--------------------------------------------------------------------------------
1 | // keymaster.js
2 | // (c) 2011-2013 Thomas Fuchs
3 | // keymaster.js may be freely distributed under the MIT license.
4 |
5 | ;(function(global){
6 | var k,
7 | _handlers = {},
8 | _mods = { 16: false, 18: false, 17: false, 91: false },
9 | _scope = 'all',
10 | // modifier keys
11 | _MODIFIERS = {
12 | '⇧': 16, shift: 16,
13 | '⌥': 18, alt: 18, option: 18,
14 | '⌃': 17, ctrl: 17, control: 17,
15 | '⌘': 91, command: 91
16 | },
17 | // special keys
18 | _MAP = {
19 | backspace: 8, tab: 9, clear: 12,
20 | enter: 13, 'return': 13,
21 | esc: 27, escape: 27, space: 32,
22 | left: 37, up: 38,
23 | right: 39, down: 40,
24 | del: 46, 'delete': 46,
25 | home: 36, end: 35,
26 | pageup: 33, pagedown: 34,
27 | ',': 188, '.': 190, '/': 191,
28 | '`': 192, '-': 189, '=': 187,
29 | ';': 186, '\'': 222,
30 | '[': 219, ']': 221, '\\': 220
31 | },
32 | code = function(x){
33 | return _MAP[x] || x.toUpperCase().charCodeAt(0);
34 | },
35 | _downKeys = [];
36 |
37 | for(k=1;k<20;k++) _MAP['f'+k] = 111+k;
38 |
39 | // IE doesn't support Array#indexOf, so have a simple replacement
40 | function index(array, item){
41 | var i = array.length;
42 | while(i--) if(array[i]===item) return i;
43 | return -1;
44 | }
45 |
46 | // for comparing mods before unassignment
47 | function compareArray(a1, a2) {
48 | if (a1.length != a2.length) return false;
49 | for (var i = 0; i < a1.length; i++) {
50 | if (a1[i] !== a2[i]) return false;
51 | }
52 | return true;
53 | }
54 |
55 | var modifierMap = {
56 | 16:'shiftKey',
57 | 18:'altKey',
58 | 17:'ctrlKey',
59 | 91:'metaKey'
60 | };
61 | function updateModifierKey(event) {
62 | for(k in _mods) _mods[k] = event[modifierMap[k]];
63 | };
64 |
65 | // handle keydown event
66 | function dispatch(event) {
67 | var key, handler, k, i, modifiersMatch, scope;
68 | key = event.keyCode;
69 |
70 | if (index(_downKeys, key) == -1) {
71 | _downKeys.push(key);
72 | }
73 |
74 | // if a modifier key, set the key. property to true and return
75 | if(key == 93 || key == 224) key = 91; // right command on webkit, command on Gecko
76 | if(key in _mods) {
77 | _mods[key] = true;
78 | // 'assignKey' from inside this closure is exported to window.key
79 | for(k in _MODIFIERS) if(_MODIFIERS[k] == key) assignKey[k] = true;
80 | return;
81 | }
82 | updateModifierKey(event);
83 |
84 | // see if we need to ignore the keypress (filter() can can be overridden)
85 | // by default ignore key presses if a select, textarea, or input is focused
86 | if(!assignKey.filter.call(this, event)) return;
87 |
88 | // abort if no potentially matching shortcuts found
89 | if (!(key in _handlers)) return;
90 |
91 | scope = getScope();
92 |
93 | // for each potential shortcut
94 | for (i = 0; i < _handlers[key].length; i++) {
95 | handler = _handlers[key][i];
96 |
97 | // see if it's in the current scope
98 | if(handler.scope == scope || handler.scope == 'all'){
99 | // check if modifiers match if any
100 | modifiersMatch = handler.mods.length > 0;
101 | for(k in _mods)
102 | if((!_mods[k] && index(handler.mods, +k) > -1) ||
103 | (_mods[k] && index(handler.mods, +k) == -1)) modifiersMatch = false;
104 | // call the handler and stop the event if neccessary
105 | if((handler.mods.length == 0 && !_mods[16] && !_mods[18] && !_mods[17] && !_mods[91]) || modifiersMatch){
106 | if(handler.method(event, handler)===false){
107 | if(event.preventDefault) event.preventDefault();
108 | else event.returnValue = false;
109 | if(event.stopPropagation) event.stopPropagation();
110 | if(event.cancelBubble) event.cancelBubble = true;
111 | }
112 | }
113 | }
114 | }
115 | };
116 |
117 | // unset modifier keys on keyup
118 | function clearModifier(event){
119 | var key = event.keyCode, k,
120 | i = index(_downKeys, key);
121 |
122 | // remove key from _downKeys
123 | if (i >= 0) {
124 | _downKeys.splice(i, 1);
125 | }
126 |
127 | if(key == 93 || key == 224) key = 91;
128 | if(key in _mods) {
129 | _mods[key] = false;
130 | for(k in _MODIFIERS) if(_MODIFIERS[k] == key) assignKey[k] = false;
131 | }
132 | };
133 |
134 | function resetModifiers() {
135 | for(k in _mods) _mods[k] = false;
136 | for(k in _MODIFIERS) assignKey[k] = false;
137 | };
138 |
139 | // parse and assign shortcut
140 | function assignKey(key, scope, method){
141 | var keys, mods;
142 | keys = getKeys(key);
143 | if (method === undefined) {
144 | method = scope;
145 | scope = 'all';
146 | }
147 |
148 | // for each shortcut
149 | for (var i = 0; i < keys.length; i++) {
150 | // set modifier keys if any
151 | mods = [];
152 | key = keys[i].split('+');
153 | if (key.length > 1){
154 | mods = getMods(key);
155 | key = [key[key.length-1]];
156 | }
157 | // convert to keycode and...
158 | key = key[0]
159 | key = code(key);
160 | // ...store handler
161 | if (!(key in _handlers)) _handlers[key] = [];
162 | _handlers[key].push({ shortcut: keys[i], scope: scope, method: method, key: keys[i], mods: mods });
163 | }
164 | };
165 |
166 | // unbind all handlers for given key in current scope
167 | function unbindKey(key, scope) {
168 | var multipleKeys, keys,
169 | mods = [],
170 | i, j, obj;
171 |
172 | multipleKeys = getKeys(key);
173 |
174 | for (j = 0; j < multipleKeys.length; j++) {
175 | keys = multipleKeys[j].split('+');
176 |
177 | if (keys.length > 1) {
178 | mods = getMods(keys);
179 | key = keys[keys.length - 1];
180 | }
181 |
182 | key = code(key);
183 |
184 | if (scope === undefined) {
185 | scope = getScope();
186 | }
187 | if (!_handlers[key]) {
188 | return;
189 | }
190 | for (i = 0; i < _handlers[key].length; i++) {
191 | obj = _handlers[key][i];
192 | // only clear handlers if correct scope and mods match
193 | if (obj.scope === scope && compareArray(obj.mods, mods)) {
194 | _handlers[key][i] = {};
195 | }
196 | }
197 | }
198 | };
199 |
200 | // Returns true if the key with code 'keyCode' is currently down
201 | // Converts strings into key codes.
202 | function isPressed(keyCode) {
203 | if (typeof(keyCode)=='string') {
204 | keyCode = code(keyCode);
205 | }
206 | return index(_downKeys, keyCode) != -1;
207 | }
208 |
209 | function getPressedKeyCodes() {
210 | return _downKeys.slice(0);
211 | }
212 |
213 | function filter(event){
214 | var tagName = (event.target || event.srcElement).tagName;
215 | // ignore keypressed in any elements that support keyboard data input
216 | return !(tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA');
217 | }
218 |
219 | // initialize key. to false
220 | for(k in _MODIFIERS) assignKey[k] = false;
221 |
222 | // set current scope (default 'all')
223 | function setScope(scope){ _scope = scope || 'all' };
224 | function getScope(){ return _scope || 'all' };
225 |
226 | // delete all handlers for a given scope
227 | function deleteScope(scope){
228 | var key, handlers, i;
229 |
230 | for (key in _handlers) {
231 | handlers = _handlers[key];
232 | for (i = 0; i < handlers.length; ) {
233 | if (handlers[i].scope === scope) handlers.splice(i, 1);
234 | else i++;
235 | }
236 | }
237 | };
238 |
239 | // abstract key logic for assign and unassign
240 | function getKeys(key) {
241 | var keys;
242 | key = key.replace(/\s/g, '');
243 | keys = key.split(',');
244 | if ((keys[keys.length - 1]) == '') {
245 | keys[keys.length - 2] += ',';
246 | }
247 | return keys;
248 | }
249 |
250 | // abstract mods logic for assign and unassign
251 | function getMods(key) {
252 | var mods = key.slice(0, key.length - 1);
253 | for (var mi = 0; mi < mods.length; mi++)
254 | mods[mi] = _MODIFIERS[mods[mi]];
255 | return mods;
256 | }
257 |
258 | // cross-browser events
259 | function addEvent(object, event, method) {
260 | if (object.addEventListener)
261 | object.addEventListener(event, method, false);
262 | else if(object.attachEvent)
263 | object.attachEvent('on'+event, function(){ method(window.event) });
264 | };
265 |
266 | // set the handlers globally on document
267 | addEvent(document, 'keydown', function(event) { dispatch(event) }); // Passing _scope to a callback to ensure it remains the same by execution. Fixes #48
268 | addEvent(document, 'keyup', clearModifier);
269 |
270 | // reset modifiers to false whenever the window is (re)focused.
271 | addEvent(window, 'focus', resetModifiers);
272 |
273 | // store previously defined key
274 | var previousKey = global.key;
275 |
276 | // restore previously defined key and return reference to our key object
277 | function noConflict() {
278 | var k = global.key;
279 | global.key = previousKey;
280 | return k;
281 | }
282 |
283 | // set window.key and window.key.set/get/deleteScope, and the default filter
284 | global.key = assignKey;
285 | global.key.setScope = setScope;
286 | global.key.getScope = getScope;
287 | global.key.deleteScope = deleteScope;
288 | global.key.filter = filter;
289 | global.key.isPressed = isPressed;
290 | global.key.getPressedKeyCodes = getPressedKeyCodes;
291 | global.key.noConflict = noConflict;
292 | global.key.unbind = unbindKey;
293 |
294 | if(typeof module !== 'undefined') module.exports = assignKey;
295 |
296 | })(this);
297 |
--------------------------------------------------------------------------------
/vendor/assets/stylesheets/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daniel-light/workflowy-clone/454358cc7ca9b4055ded0428de84b799fd6d59ca/vendor/assets/stylesheets/.keep
--------------------------------------------------------------------------------