xing-backend 0.0.19 → 0.0.20

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/app/models/role.rb +24 -0
  3. data/config/locales/json.yml +29 -0
  4. data/config/routes.rb +3 -0
  5. data/db/migrate/20140828011806_initial.rb +45 -0
  6. data/db/migrate/20140914030703_devise_token_auth_add_token_info_to_users.rb +20 -0
  7. data/db/migrate/20140929192921_remove_login_from_users.rb +5 -0
  8. data/lib/xing-backend.rb +1 -0
  9. data/lib/xing/engine.rb +4 -0
  10. data/lib/xing/nominal/database_config_validator.rb +31 -0
  11. data/lib/xing/nominal/dependency_utils.rb +26 -0
  12. data/lib/xing/nominal/secrets_validator.rb +50 -0
  13. data/lib/xing/nominal/yaml_config_validator.rb +44 -0
  14. data/lib/xing/services.rb +0 -2
  15. data/lib/xing/services/class_registry.rb +31 -0
  16. data/lib/xing/services/{page_wrapper.rb → paged_wrapper.rb} +2 -2
  17. data/lib/xing/snapshot.rb +4 -0
  18. data/lib/xing/snapshot/domain_helpers.rb +24 -0
  19. data/lib/xing/snapshot/fetcher.rb +35 -0
  20. data/lib/xing/snapshot/local_site_snapshot.rb +37 -0
  21. data/lib/xing/snapshot/remote_site_snapshot.rb +16 -0
  22. data/lib/xing/snapshot/site_page_set.rb +29 -0
  23. data/lib/xing/snapshot/site_snapshot.rb +41 -0
  24. data/lib/xing/snapshot/sitemap.rb +68 -0
  25. data/lib/xing/snapshot/writer.rb +15 -0
  26. data/lib/xing/spec_helpers.rb +7 -0
  27. data/lib/xing/spec_helpers/api_response_matchers.rb +26 -0
  28. data/lib/xing/spec_helpers/ci_support.rb +6 -0
  29. data/lib/xing/spec_helpers/dom_equiv.rb +26 -0
  30. data/lib/xing/spec_helpers/json_requests.rb +58 -0
  31. data/lib/xing/spec_helpers/routing_spec_patch.rb +28 -0
  32. data/lib/xing/spec_helpers/split_servers.rb +15 -0
  33. data/lib/xing/spec_helpers/test_url_helpers.rb +5 -0
  34. data/lib/xing/static.rb +1 -0
  35. data/lib/xing/static/backend_url_cookie.rb +16 -0
  36. data/lib/xing/static/goto_param.rb +30 -0
  37. data/lib/xing/static/logger.rb +11 -0
  38. data/lib/xing/static/rack_app.rb +40 -0
  39. data/lib/xing/tasks/all.rake +4 -0
  40. data/lib/xing/tasks/db_recycle.rake +4 -0
  41. data/lib/xing/tasks/dependencies_common.rake +49 -0
  42. data/lib/xing/tasks/sample_data.rake +49 -0
  43. data/lib/xing/tasks/take_snapshot.rake +4 -0
  44. data/spec/xing/builders/list_builder_spec.rb +0 -2
  45. data/spec/xing/builders/ordered_list_builder_spec.rb +0 -2
  46. data/spec/xing/nominal/database_config_validator_spec.rb +98 -0
  47. data/spec/xing/nominal/secrets_validator_spec.rb +78 -0
  48. data/spec/xing/serializers/list_spec.rb +116 -0
  49. data/spec/xing/serializers/paged_index_spec.rb +2 -2
  50. data/spec/xing/serializers/paged_list_spec.rb +1 -1
  51. data/spec/xing/services/error_converter_spec.rb +1 -3
  52. data/spec/xing/services/paged_wrapper_spec.rb +30 -0
  53. data/spec/xing/snapshot/remote_snapshot_fetcher_spec.rb +81 -0
  54. data/spec/xing/{services → snapshot}/snapshot_fetcher_spec.rb +6 -4
  55. data/spec_help/dummy/db/test.sqlite3 +0 -0
  56. data/spec_help/dummy/log/test.log +143 -0
  57. data/spec_help/file-sandbox.rb +164 -0
  58. data/spec_help/spec_helper.rb +0 -2
  59. metadata +152 -12
  60. data/lib/xing/services/snapshot_fetcher.rb +0 -33
  61. data/lib/xing/services/snapshot_writer.rb +0 -19
@@ -0,0 +1,37 @@
1
+ require 'selenium-webdriver'
2
+ require 'xing/snapshot/site_snapshot'
3
+ require 'xing/snapshot/writer'
4
+
5
+ module Xing
6
+ module Snapshot
7
+ class LocalSiteSnapshot < SiteSnapshot
8
+ include Writer
9
+
10
+ def initialize(url)
11
+ super(url)
12
+ @wait = Selenium::WebDriver::Wait.new
13
+ end
14
+
15
+ def setup
16
+ @driver = Selenium::WebDriver.for :chrome
17
+ end
18
+ attr_accessor :driver, :wait
19
+
20
+ def teardown
21
+ @driver.close
22
+ end
23
+
24
+ def fetch(url, path)
25
+ @driver.navigate.to(url+path)
26
+ # better way to wait till javascript complete?
27
+ @wait.until do
28
+ @driver.execute_script("return window.frontendContentLoaded == true;")
29
+ end
30
+ element = @driver.find_element(:tag_name, "html")
31
+ html = element.attribute("outerHTML")
32
+ write(path, html)
33
+ end
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,16 @@
1
+ require 'xing/snapshot/site_snapshot'
2
+ require 'xing/snapshot/fetcher'
3
+
4
+ module Xing
5
+ module Snapshot
6
+ class RemoteSiteSnapshot < SiteSnapshot
7
+ def setup
8
+ @fetcher = Xing::Snapshot::Fetcher.new
9
+ end
10
+
11
+ def fetch(url, path)
12
+ @fetcher.perform(url, path)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,29 @@
1
+ require 'xing/snapshot/domain_helpers'
2
+
3
+ module Xing
4
+ module Snapshot
5
+ class SitePageSet
6
+ include DomainHelpers
7
+
8
+ def initialize(url)
9
+ @url = domain(url)
10
+ end
11
+
12
+ def pages_to_visit
13
+ @pages_to_visit ||= Page.published.where.not(type: "Page::Homepage")
14
+ end
15
+
16
+ def visit_pages(&block)
17
+ STATIC_PATHS_FOR_SITEMAP.each do |path|
18
+ yield(@url,path,Time.now)
19
+ end
20
+
21
+ pages_to_visit.each do |page|
22
+ path = page_frontend_url(page.url_slug)
23
+ yield(@url, path, page.updated_at)
24
+ end
25
+ end
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,41 @@
1
+ require "xing/snapshot/site_page_set"
2
+
3
+ module Xing
4
+ module Snapshot
5
+ class SiteSnapshot
6
+ class << self
7
+ def create!(url)
8
+ self.new(url).create!
9
+ end
10
+ end
11
+
12
+ def initialize(url)
13
+ @url = url
14
+ end
15
+ attr_accessor :url
16
+
17
+ def create!
18
+ @sitemap_page_set = SitePageSet.new(url)
19
+ setup
20
+ generate_snapshot
21
+ teardown
22
+ end
23
+
24
+ def setup
25
+ end
26
+
27
+ def generate_snapshot
28
+ @sitemap_page_set.visit_pages do |url, path, updated_at|
29
+ fetch(url, path)
30
+ end
31
+ end
32
+
33
+ def fetch(url, path)
34
+ end
35
+
36
+ def teardown
37
+ end
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,68 @@
1
+ require 'builder'
2
+ require 'xing/snapshot/site_page_set'
3
+ require 'xing/snapshot/domain_helpers'
4
+
5
+ module Xing
6
+ module Snapshot
7
+ class Sitemap
8
+ class << self
9
+ include DomainHelpers
10
+
11
+ def create!(url = nil)
12
+ @bad_pages = []
13
+
14
+ @sitemap_page_set = SitePageSet.new(url)
15
+
16
+ generate_sitemap
17
+ update_search_engines if Rails.env.production?
18
+ end
19
+
20
+ private
21
+ def generate_sitemap
22
+ xml_str = ""
23
+
24
+ xml = Builder::XmlMarkup.new(:target => xml_str, :indent => 2)
25
+
26
+ xml.instruct!
27
+ xml.urlset(:xmlns=>'http://www.sitemaps.org/schemas/sitemap/0.9') {
28
+ @sitemap_page_set.visit_pages do |url, path, update_time|
29
+ xml.url {
30
+ xml.loc(url+path)
31
+ xml.lastmod(update_time.utc.strftime('%Y-%m-%dT%H:%M:%S+00:00'))
32
+ }
33
+ end
34
+ }
35
+
36
+ save_file(xml_str)
37
+ end
38
+
39
+ def save_file(xml)
40
+ File.open("#{ Rails.root }/public/sitemap.xml", "w+") do |f|
41
+ f.write(xml)
42
+ end
43
+ end
44
+
45
+ def update_search_engine(host, path, sitemap_uri)
46
+ Rails.logger.info{"Notifying #{host}"}
47
+ begin
48
+ res = Net::HTTP.get_response(host, path + sitemap_uri)
49
+ rescue Object => ex
50
+ Rails.logger.info "Error while notifying #{host}: #{ex.inspect}"
51
+ end
52
+ Rails.logger.info res.class
53
+ end
54
+
55
+ # Notify popular search engines of the updated sitemap.xml
56
+ def update_search_engines
57
+ sitemap_uri = domain + 'sitemap.xml'
58
+ escaped_sitemap_uri = CGI.escape(sitemap_uri)
59
+
60
+ update_search_engine('www.google.com', '/webmasters/tools/ping?sitemap=', escaped_sitemap_uri)
61
+ update_search_engine('search.yahooapis.com', '/SiteExplorerService/V1/updateNotification?appid=SitemapWriter&url=', escaped_sitemap_uri)
62
+ update_search_engine('www.bing.com', '/webmaster/ping.aspx?siteMap=', escaped_sitemap_uri)
63
+ end
64
+ end
65
+ end
66
+
67
+ end
68
+ end
@@ -0,0 +1,15 @@
1
+ module Xing
2
+ module Snapshot
3
+ module Writer
4
+ def write(path, html)
5
+ snapshot_file = "#{ Rails.root }/public/frontend_snapshots/#{path.present? ? path : 'index'}.html"
6
+ dirname = File.dirname(snapshot_file)
7
+ FileUtils.mkdir_p(dirname)
8
+
9
+ File.open(snapshot_file, "w+:ASCII-8BIT:UTF-8") do |f|
10
+ f.write(html)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ require 'xing/spec_helpers/api_response_matchers'
2
+ require 'xing/spec_helpers/ci_support'
3
+ require 'xing/spec_helpers/dom_equiv'
4
+ require 'xing/spec_helpers/json_requests'
5
+ require 'xing/spec_helpers/routing_spec_patch'
6
+ require 'xing/spec_helpers/split_servers'
7
+ require 'xing/spec_helpers/test_url_helpers'
@@ -0,0 +1,26 @@
1
+ module APIResponseMatchers
2
+ extend RSpec::Matchers::DSL
3
+
4
+ matcher :reject_as_unprocessable do
5
+ match_unless_raises ActiveSupport::TestCase::Assertion do |response|
6
+ expect(response.status).to eq(422)
7
+ end
8
+
9
+ failure_message do |response|
10
+ "Expected response to be a 422: Unprocessable Entity"
11
+ end
12
+
13
+ failure_message_when_negated do |source|
14
+ "Expected response not to be a 422: Unprocessable Entity"
15
+ end
16
+
17
+ description do
18
+ "should send a 422: Unprocessable Entity status"
19
+ end
20
+ end
21
+ end
22
+
23
+
24
+ class RSpec::Core::ExampleGroup
25
+ include APIResponseMatchers
26
+ end
@@ -0,0 +1,6 @@
1
+ $RAW_SELENIUM_WAIT = 5
2
+ if ENV["CI_SERVER"] == "yes"
3
+ puts "Setting up longer timeouts for CI"
4
+ Capybara.default_wait_time = 30
5
+ $RAW_SELENIUM_WAIT = 30
6
+ end
@@ -0,0 +1,26 @@
1
+ module DomEquivalence
2
+ extend RSpec::Matchers::DSL
3
+
4
+ matcher :match_dom_of do |target|
5
+ match_unless_raises ActiveSupport::TestCase::Assertion do |source|
6
+ assert_dom_equal source, target
7
+ end
8
+
9
+ failure_message do |source|
10
+ "Expected #{source} to have equivalent DOM to #{target}"
11
+ end
12
+
13
+ failure_message_when_negated do |source|
14
+ "Expected #{source} not to have equivalent DOM to #{target}"
15
+ end
16
+
17
+ description do
18
+ "should be DOM equivalent to #{target}"
19
+ end
20
+ end
21
+ end
22
+
23
+
24
+ class RSpec::Core::ExampleGroup
25
+ include DomEquivalence
26
+ end
@@ -0,0 +1,58 @@
1
+ module JSONRequests
2
+
3
+ def json_get(url, arg2 = nil)
4
+ get rootify(url), arg2, { 'HTTP_ACCEPT' => 'application/json' }
5
+ end
6
+
7
+ def json_post(url, arg2 = nil)
8
+ post rootify(url), arg2, { 'HTTP_ACCEPT' => 'application/json' }
9
+ end
10
+
11
+ def json_put(url, arg2 = nil)
12
+ put rootify(url), arg2, { 'HTTP_ACCEPT' => 'application/json' }
13
+ end
14
+
15
+ def json_delete(url, arg2 = nil)
16
+ delete rootify(url), arg2, { 'HTTP_ACCEPT' => 'application/json' }
17
+ end
18
+
19
+ def authenticated_json_get(user, url, arg2 = nil)
20
+ auth_header = user.create_new_auth_token
21
+ get rootify(url), arg2, auth_header.merge({ 'HTTP_ACCEPT' => 'application/json' })
22
+ end
23
+
24
+ def authenticated_json_post(user, url, arg2 = nil)
25
+ auth_header = user.create_new_auth_token
26
+ post rootify(url), arg2, auth_header.merge({ 'HTTP_ACCEPT' => 'application/json' })
27
+ end
28
+
29
+ def authenticated_json_put(user, url, arg2 = nil)
30
+ auth_header = user.create_new_auth_token
31
+ put rootify(url), arg2, auth_header.merge({ 'HTTP_ACCEPT' => 'application/json' })
32
+ end
33
+
34
+ def authenticated_json_delete(user, url, arg2 = nil)
35
+ auth_header = user.create_new_auth_token
36
+ delete rootify(url), arg2, auth_header.merge({ 'HTTP_ACCEPT' => 'application/json' })
37
+ end
38
+
39
+ def rootify(url)
40
+ if url[0] == '/'
41
+ url
42
+ else
43
+ "/#{url}"
44
+ end
45
+ end
46
+
47
+
48
+ end
49
+
50
+ module RSpec::Rails::RequestExampleGroup
51
+ include JSONRequests
52
+ include JsonSpec::Matchers
53
+ include JsonSpec::Helpers
54
+ end
55
+
56
+ RSpec.configure do |config|
57
+ config.include JsonSpec::Helpers, :type => :serializer
58
+ end
@@ -0,0 +1,28 @@
1
+ module RSpec
2
+ module Rails
3
+ module Matchers
4
+ # Matchers to help with specs for routing code.
5
+ module RoutingMatchers
6
+ class RouteToMatcher
7
+ def matches_with_patches?(verb_to_path_map)
8
+ path = verb_to_path_map.values.first
9
+ verb_to_path_map[verb_to_path_map.keys.first] = "http://#{BACKEND_SUBDOMAIN}.example.com#{path[0] == "/" ? "" : "/"}#{path}";
10
+ matches_without_patches?(verb_to_path_map)
11
+ end
12
+ alias_method_chain :matches?, :patches
13
+ end
14
+
15
+ class FrontendRouteToMatcher < RouteToMatcher
16
+ def matches?(verb_to_path_map)
17
+ matches_without_patches?(verb_to_path_map)
18
+ end
19
+ end
20
+
21
+ def frontend_route_to(*expected)
22
+ FrontendRouteToMatcher.new(self, *expected)
23
+ end
24
+
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,15 @@
1
+ begin
2
+ require 'static-app'
3
+
4
+ Capybara.configure do |capy|
5
+ backend_server = Capybara::Server.new(Capybara.app)
6
+ backend_server.boot
7
+ puts "Rails API server started on #{backend_server.host}:#{backend_server.port}"
8
+ ActionMailer::Base.default_url_options[:host] = "#{backend_server.host}:#{backend_server.port}"
9
+ Capybara.app = APP_MODULE::StaticApp.build("../frontend/bin", backend_server.port)
10
+ RSpec.configure do |config|
11
+ config.waterpig_clearable_logs << 'test_static'
12
+ end
13
+ end
14
+ rescue LoadError
15
+ end
@@ -0,0 +1,5 @@
1
+ module TestUrlHelpers
2
+ def full_url(rails_path)
3
+ return "http://127.0.0.1:"+Capybara.current_session.server.port.to_s+rails_path
4
+ end
5
+ end
@@ -0,0 +1 @@
1
+ require 'xing/static/rack_app'
@@ -0,0 +1,16 @@
1
+ module Xing
2
+ module Static
3
+ class BackendUrlCookie
4
+ def initialize(app, backend_url)
5
+ @backend_url = backend_url
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ status, headers, body = @app.call(env)
11
+ headers["Set-Cookie"] = [(headers["Set-Cookie"]), "lrdBackendUrl=#@backend_url"].compact.join(";") unless @backend_url.nil?
12
+ [ status, headers, body ]
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,30 @@
1
+ require 'pp'
2
+ module Xing
3
+ module Static
4
+ class GotoParam
5
+ def initialize(app)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ status, headers, body = @app.call(env)
11
+ default = [ status, headers, body ]
12
+ request_path = env["SCRIPT_NAME"] + env["PATH_INFO"]
13
+ if env["QUERY_STRING"]
14
+ request_path += "&#{env["QUERY_STRING"]}"
15
+ end
16
+
17
+ redirect = [ 301, headers.merge("Location" => "/?goto=#{request_path}", "Content-Length" => "0"), [] ]
18
+
19
+ return default unless status == 404
20
+ return default if /\A(assets|fonts|system)/ =~ request_path
21
+ return default if /\.(xml|html|ico|txt)\z/ =~ request_path
22
+ return default if /goto=/ =~ env["QUERY_STRING"]
23
+
24
+ return redirect
25
+ rescue => ex
26
+ pp ex
27
+ end
28
+ end
29
+ end
30
+ end