bookingsync_portal 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +47 -0
  4. data/Rakefile +28 -0
  5. data/app/assets/javascripts/bookingsync_portal/admin/application.js +20 -0
  6. data/app/assets/javascripts/bookingsync_portal/admin/handle_remote_errors.js.coffee +3 -0
  7. data/app/assets/javascripts/bookingsync_portal/admin/live_updates.js.coffee +7 -0
  8. data/app/assets/javascripts/bookingsync_portal/admin/rentals.js.coffee +77 -0
  9. data/app/assets/javascripts/bookingsync_portal/admin/templates/rentals/connected_rental.hbs +8 -0
  10. data/app/assets/stylesheets/bookingsync_portal/admin/application.css.scss +120 -0
  11. data/app/controllers/bookingsync_portal/admin/base_controller.rb +19 -0
  12. data/app/controllers/bookingsync_portal/admin/remote_accounts_controller.rb +24 -0
  13. data/app/controllers/bookingsync_portal/admin/rentals_controller.rb +64 -0
  14. data/app/controllers/bookingsync_portal/admin_api/base_controller.rb +13 -0
  15. data/app/controllers/bookingsync_portal/admin_api/connections_controller.rb +6 -0
  16. data/app/controllers/bookingsync_portal/admin_api/remote_rentals_controller.rb +18 -0
  17. data/app/controllers/bookingsync_portal/admin_api/rentals_controller.rb +18 -0
  18. data/app/controllers/bookingsync_portal/application_controller.rb +4 -0
  19. data/app/helpers/bookingsync_portal/admin/rentals_helper.rb +34 -0
  20. data/app/models/bookingsync_portal/account.rb +10 -0
  21. data/app/models/bookingsync_portal/connection.rb +21 -0
  22. data/app/models/bookingsync_portal/remote_account.rb +9 -0
  23. data/app/models/bookingsync_portal/remote_rental.rb +27 -0
  24. data/app/models/bookingsync_portal/rental.rb +15 -0
  25. data/app/resources/bookingsync_portal/admin_api/connection_resource.rb +22 -0
  26. data/app/resources/bookingsync_portal/admin_api/remote_account_resource.rb +14 -0
  27. data/app/resources/bookingsync_portal/admin_api/remote_rental_resource.rb +14 -0
  28. data/app/resources/bookingsync_portal/admin_api/rental_resource.rb +14 -0
  29. data/app/views/bookingsync_portal/admin/remote_accounts/_form.html.erb +11 -0
  30. data/app/views/bookingsync_portal/admin/remote_accounts/_how_to_connect.html.erb +1 -0
  31. data/app/views/bookingsync_portal/admin/remote_accounts/new.html.erb +5 -0
  32. data/app/views/bookingsync_portal/admin/rentals/_connected_rental.html.erb +27 -0
  33. data/app/views/bookingsync_portal/admin/rentals/_remote_rental.html.erb +9 -0
  34. data/app/views/bookingsync_portal/admin/rentals/_rental.html.erb +17 -0
  35. data/app/views/bookingsync_portal/admin/rentals/index.html.erb +58 -0
  36. data/app/views/bookingsync_portal/admin/rentals/show.js.erb +6 -0
  37. data/app/views/layouts/bookingsync_portal/admin.html.erb +13 -0
  38. data/config/locales/en.yml +58 -0
  39. data/config/routes.rb +19 -0
  40. data/db/migrate/20150222172825_create_accounts.rb +13 -0
  41. data/db/migrate/20150222173413_create_rentals.rb +14 -0
  42. data/db/migrate/20150222173711_create_remote_accounts.rb +10 -0
  43. data/db/migrate/20150222174023_create_remote_rentals.rb +12 -0
  44. data/db/migrate/20150222174234_create_connections.rb +9 -0
  45. data/lib/bookingsync_portal.rb +77 -0
  46. data/lib/bookingsync_portal/engine.rb +9 -0
  47. data/lib/bookingsync_portal/mash_serializer.rb +9 -0
  48. data/lib/bookingsync_portal/version.rb +3 -0
  49. data/lib/generators/bookingsync_portal/install_generator.rb +15 -0
  50. data/lib/generators/templates/bookingsync_portal.rb +46 -0
  51. data/lib/tasks/bookingsync_portal_tasks.rake +4 -0
  52. metadata +374 -0
@@ -0,0 +1,13 @@
1
+ module BookingsyncPortal
2
+ module AdminApi
3
+ class BaseController < BookingsyncApplication::Admin::BaseController
4
+
5
+ private
6
+
7
+ def messagebus_channel
8
+ "/account-#{current_account.id}"
9
+ end
10
+ helper_method :messagebus_channel
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,6 @@
1
+ module BookingsyncPortal
2
+ module AdminApi
3
+ class ConnectionsController < BookingsyncPortal::AdminApi::BaseController
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,18 @@
1
+ module BookingsyncPortal
2
+ module AdminApi
3
+ class RemoteRentalsController < BookingsyncPortal::AdminApi::BaseController
4
+ prepend_before_action :set_resource_klass_name
5
+ before_action :fetch_remote_rentals, only: :index
6
+
7
+ private
8
+
9
+ def fetch_remote_rentals
10
+ BookingsyncPortal.fetch_remote_rentals(current_account)
11
+ end
12
+
13
+ def set_resource_klass_name
14
+ @resource_klass_name = BookingsyncPortal.remote_rental_resource
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ module BookingsyncPortal
2
+ module AdminApi
3
+ class RentalsController < BookingsyncPortal::AdminApi::BaseController
4
+ prepend_before_action :set_resource_klass_name
5
+ before_action :synchronize_rentals, only: :index
6
+
7
+ private
8
+
9
+ def synchronize_rentals
10
+ BookingsyncPortal.rental_model.constantize.synchronize(scope: current_account)
11
+ end
12
+
13
+ def set_resource_klass_name
14
+ @resource_klass_name = BookingsyncPortal.rental_resource
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,4 @@
1
+ module BookingsyncPortal
2
+ class ApplicationController < ::ApplicationController
3
+ end
4
+ end
@@ -0,0 +1,34 @@
1
+ module BookingsyncPortal
2
+ module Admin
3
+ module RentalsHelper
4
+ def rental_details(rental)
5
+ scope = 'bookingsync_portal.admin.rentals.rental'
6
+
7
+ details = Array.new
8
+ if rental.sleeps.to_i > 0
9
+ if rental.sleeps_max.to_i > 0 && rental.sleeps_max.to_i > rental.sleeps.to_i
10
+ details << t(:sleeps_html, scope: scope,
11
+ count: "#{rental.sleeps.to_i}-#{rental.sleeps_max.to_i}")
12
+ else
13
+ details << t(:sleeps_html, scope: scope,
14
+ count: rental.sleeps.to_i)
15
+ end
16
+ end
17
+ if rental.bedrooms_count.to_i > 0
18
+ details << t(:bedrooms_html, scope: scope,
19
+ count: rental.bedrooms_count.to_i)
20
+ end
21
+ if rental.bathrooms_count.to_i > 0
22
+ details << t(:bathrooms_html, scope: scope,
23
+ count: rental.bathrooms_count.to_i)
24
+ end
25
+ if rental.surface.to_i > 0
26
+ details << t(:surface_html, scope: scope,
27
+ count: rental.surface.to_i)
28
+ end
29
+
30
+ safe_join(details, ', ')
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,10 @@
1
+ class BookingsyncPortal::Account < ActiveRecord::Base
2
+ self.table_name = 'accounts'
3
+
4
+ include BookingSync::Engine::Model
5
+
6
+ has_many :remote_accounts, class_name: BookingsyncPortal.remote_account_model, dependent: :destroy
7
+ has_many :remote_rentals, class_name: BookingsyncPortal.remote_rental_model, through: :remote_accounts
8
+ has_many :rentals, class_name: BookingsyncPortal.rental_model, dependent: :destroy
9
+ has_many :connections, class_name: BookingsyncPortal.connection_model, through: :rentals
10
+ end
@@ -0,0 +1,21 @@
1
+ class BookingsyncPortal::Connection < ActiveRecord::Base
2
+ self.table_name = 'connections'
3
+
4
+ belongs_to :remote_rental, class_name: BookingsyncPortal.remote_rental_model
5
+ belongs_to :rental, class_name: BookingsyncPortal.rental_model
6
+
7
+ validates :remote_rental, presence: true
8
+ validates :rental, presence: true
9
+
10
+ validate :matching_accounts, if: -> { rental && remote_rental }
11
+
12
+ private
13
+
14
+ def matching_accounts?
15
+ rental.account == remote_rental.remote_account.account
16
+ end
17
+
18
+ def matching_accounts
19
+ errors.add(:base, :not_matching_accounts) unless matching_accounts?
20
+ end
21
+ end
@@ -0,0 +1,9 @@
1
+ class BookingsyncPortal::RemoteAccount < ActiveRecord::Base
2
+ self.table_name = 'remote_accounts'
3
+
4
+ belongs_to :account, class_name: BookingsyncPortal.account_model
5
+ has_many :remote_rentals, class_name: BookingsyncPortal.remote_rental_model, dependent: :destroy
6
+
7
+ validates :uid, presence: true, uniqueness: true
8
+ validates :account, presence: true
9
+ end
@@ -0,0 +1,27 @@
1
+ require 'bookingsync_portal/mash_serializer'
2
+
3
+ class BookingsyncPortal::RemoteRental < ActiveRecord::Base
4
+ self.table_name = 'remote_rentals'
5
+
6
+ belongs_to :remote_account, class_name: BookingsyncPortal.remote_account_model
7
+ has_one :account, class_name: BookingsyncPortal.account_model, through: :remote_account
8
+ has_one :connection, class_name: BookingsyncPortal.connection_model, dependent: :destroy
9
+ has_one :rental, class_name: BookingsyncPortal.rental_model, through: :connection
10
+
11
+ serialize :remote_data, BookingsyncPortal::MashSerializer
12
+
13
+ validates :uid, presence: true, uniqueness: true
14
+ validates :remote_account, presence: true
15
+
16
+ scope :ordered, -> { order(created_at: :desc) }
17
+ scope :connected, -> { joins(:rental) }
18
+ scope :not_connected, -> { includes(:rental).where(rentals: { id: nil }) }
19
+
20
+ def connected?
21
+ rental.present?
22
+ end
23
+
24
+ def synchronized?
25
+ synchronized_at.present?
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ class BookingsyncPortal::Rental < ActiveRecord::Base
2
+ self.table_name = 'rentals'
3
+
4
+ belongs_to :account, class_name: BookingsyncPortal.account_model
5
+ has_one :connection, class_name: BookingsyncPortal.connection_model, dependent: :destroy
6
+ has_one :remote_rental, class_name: BookingsyncPortal.remote_rental_model, through: :connection
7
+
8
+ scope :ordered, -> { order(created_at: :desc) }
9
+ scope :connected, -> { joins(:remote_rental) }
10
+ scope :not_connected, -> { includes(:connection).where(connections: { remote_rental_id: nil }) }
11
+
12
+ def connected?
13
+ remote_rental.present?
14
+ end
15
+ end
@@ -0,0 +1,22 @@
1
+ module BookingsyncPortal
2
+ module AdminApi
3
+ class ConnectionResource < JSONAPI::Resource
4
+ model_name BookingsyncPortal.connection_model
5
+
6
+ attributes :id, :rental_id, :remote_rental_id
7
+
8
+ def self.records(options = {})
9
+ context = options[:context]
10
+ context[:current_account].connections
11
+ end
12
+
13
+ def save
14
+ unless context[:current_account].id == @model.rental.account_id &&
15
+ context[:current_account].id == @model.remote_rental.account.id
16
+ raise JSONAPI::Exceptions::RecordNotFound.new(@model.rental_id)
17
+ end
18
+ super
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ module BookingsyncPortal
2
+ module AdminApi
3
+ class RemoteAccountResource < JSONAPI::Resource
4
+ model_name BookingsyncPortal.remote_account_model
5
+
6
+ attributes :id, :uid
7
+
8
+ def self.records(options = {})
9
+ context = options[:context]
10
+ context[:current_account].remote_accounts
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module BookingsyncPortal
2
+ module AdminApi
3
+ class RemoteRentalResource < JSONAPI::Resource
4
+ model_name BookingsyncPortal.remote_rental_model
5
+
6
+ attributes :id
7
+
8
+ def self.records(options = {})
9
+ context = options[:context]
10
+ context[:current_account].remote_rentals
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module BookingsyncPortal
2
+ module AdminApi
3
+ class RentalResource < JSONAPI::Resource
4
+ model_name BookingsyncPortal.rental_model
5
+
6
+ attributes :id
7
+
8
+ def self.records(options = {})
9
+ context = options[:context]
10
+ context[:current_account].rentals
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ <div class="col-sm-offset-4 col-sm-4 form-group">
2
+ <%= simple_form_for [:admin, remote_account] do |f| -%>
3
+ <div class="form-group">
4
+ <%= f.input :uid, input_html: { class: 'input-lg form-control' } -%>
5
+ </div>
6
+
7
+ <div class="form-group">
8
+ <%= f.submit t('.submit_new'), class: "btn btn-primary btn-lg btn-block" %>
9
+ </div>
10
+ <%- end -%>
11
+ </div>
@@ -0,0 +1 @@
1
+ <p class="lead">Info on how to connect with remote account, modify app/views/bookingsync_portal/admin/remote_accounts/_how_to_connect.html.erb</p>
@@ -0,0 +1,5 @@
1
+ <div class="text-center">
2
+ <h1><%=t '.title' %></h1>
3
+ <%= render 'how_to_connect' %>
4
+ <%= render 'form', remote_account: @remote_account %>
5
+ </div>
@@ -0,0 +1,27 @@
1
+ <div
2
+ class="panel panel-connected <%= "pending" unless remote_rental.synchronized? %>"
3
+ id="<%= dom_id rental %>">
4
+ <div class="panel-heading" title="<%= RemoteRental.human_attribute_name(:uid) %>
5
+ <%= remote_rental.uid %>">
6
+ <%= rental.name %>
7
+ <%= link_to t('.disconnect_rental'),
8
+ bookingsync_portal.disconnect_admin_rental_path(rental),
9
+ class: "btn btn-default btn-xs remove-connection",
10
+ data: {disable_with: t('.disconnecting_rental')},
11
+ method: :put %>
12
+ </div>
13
+ <% if rental.remote_rental.synchronized? %>
14
+ <div class="panel-body-grid">
15
+ <div class="panel-body-grid-photo">
16
+ <%- if rental.ordered_photos.first -%>
17
+ <%= image_tag rental.ordered_photos.first.thumb_url, class: "img-responsive" %>
18
+ <%- end -%>
19
+ </div>
20
+ <div class="panel-body-grid-text">
21
+ <%= rental_details(rental) %>
22
+ </div>
23
+ </div>
24
+ <% else %>
25
+ <div class="panel-body"><%= icon('spinner fa-spin', t('.synchronizing')) %></div>
26
+ <% end %>
27
+ </div>
@@ -0,0 +1,9 @@
1
+ <div class="panel panel-remote not-connected-remote-rental" id="<%= dom_id remote_rental %>"
2
+ data-uid="<%= remote_rental.uid %>">
3
+ <div class="panel-heading" title="<%= RemoteRental.human_attribute_name(:uid) %>
4
+ <%= remote_rental.uid %>">
5
+ <%= remote_rental.name.presence || t('.no_name') %><br/>
6
+ </div>
7
+ <div class="panel-body">
8
+ </div>
9
+ </div>
@@ -0,0 +1,17 @@
1
+ <div class="panel panel-bookingsync bookingsync-rental"
2
+ id="<%= dom_id rental %>"
3
+ data-connect-url="<%= connect_admin_rental_url(rental) %>">
4
+ <div class="panel-heading">
5
+ <%= rental.name.presence || t('.no_name') %>
6
+ </div>
7
+ <div class="panel-body-grid">
8
+ <div class="panel-body-grid-photo">
9
+ <%- if rental.ordered_photos.first -%>
10
+ <%= image_tag rental.ordered_photos.first.thumb_url, class: "img-responsive" %>
11
+ <%- end -%>
12
+ </div>
13
+ <div class="panel-body-grid-text">
14
+ <%= rental_details rental %>
15
+ </div>
16
+ </div>
17
+ </div>
@@ -0,0 +1,58 @@
1
+ <div class="rentals-container row-fluid">
2
+ <div class="bookingsync-rentals-list rentals-list col-xs-4">
3
+ <div class="rentals-list-header">
4
+ <legend><%=t '.bookingsync_header', account_name: current_account.name %></legend>
5
+ </div>
6
+ <div class="rentals-list-scroll">
7
+ <%- if @not_connected_rentals.length > 0 -%>
8
+ <% @not_connected_rentals.each do |rental| %>
9
+ <%= render rental %>
10
+ <% end %>
11
+ <%- else -%>
12
+ <div class="lead text-center well">
13
+ <p class=""><%= icon 'thumbs-up fa-lg' %></p>
14
+ <p><%=t '.all_synchronized' %></p>
15
+ </div>
16
+ <%- end -%>
17
+ </div>
18
+ </div>
19
+
20
+ <% if @remote_accounts.any? %>
21
+ <% @remote_accounts.each do |remote_account| %>
22
+ <div class="remote-rentals-list rentals-list col-xs-4">
23
+ <div class="rentals-list-header">
24
+ <legend><%=t '.remote_header', account_name: remote_account.name %></legend>
25
+ </div>
26
+
27
+ <div class="rentals-list-scroll">
28
+ <%- if @remote_account_not_registered %>
29
+ <div class="lead text-center well">
30
+ <p class=""><%= icon 'warning fa-lg' %></p>
31
+ <%= render 'bookingsync_portal/admin/remote_accounts/how_to_connect' %>
32
+ </div>
33
+ <%- elsif Array(@remote_rentals_by_account[remote_account]).length > 0 -%>
34
+ <% Array(@remote_rentals_by_account[remote_account]).each do |remote_rental| %>
35
+ <% if remote_rental.connected? %>
36
+ <%= render "connected_rental", remote_rental: remote_rental, rental: remote_rental.rental %>
37
+ <% else %>
38
+ <%= render "remote_rental", remote_rental: remote_rental %>
39
+ <% end %>
40
+ <% end %>
41
+ <%- else -%>
42
+ <div class="lead text-center well">
43
+ <p class=""><%= icon 'info fa-lg' %></p>
44
+ <p><%=t '.create_listings_first' %></p>
45
+ </div>
46
+ <%- end -%>
47
+ </div>
48
+ </div>
49
+ <% end %>
50
+ <% else %>
51
+ <div class="rentals-list col-xs-4">
52
+ <legend><%=t '.connect' %></legend>
53
+ <%= link_to new_admin_remote_account_path, class: "btn btn-primary btn-lg btn-block" do %>
54
+ <%= icon "plus-circle" %> <%= t '.connect_accounts' %>
55
+ <% end %>
56
+ </div>
57
+ <% end %>
58
+ </div>
@@ -0,0 +1,6 @@
1
+ $("#<%= dom_id @rental %>").replaceWith(
2
+ <%- if @rental.connected? %>
3
+ "<%=j render 'connected_rental', rental: @rental, remote_rental: @rental.remote_rental %>");
4
+ <%- else %>
5
+ "<%=j render 'rental', rental: @rental %>");
6
+ <%- end %>
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>BookingSync - HolidayLettings integration</title>
5
+ <%= stylesheet_link_tag 'admin/application', media: 'all', 'data-turbolinks-track' => true %>
6
+ <%= csrf_meta_tags %>
7
+ </head>
8
+ <body data-messagebus-channel="<%= messagebus_channel %>">
9
+ <%= yield %>
10
+ <%= javascript_include_tag 'admin/application', 'data-turbolinks-track' => true %>
11
+ <div class="footer"></div>
12
+ </body>
13
+ </html>
@@ -0,0 +1,58 @@
1
+ en:
2
+ activerecord:
3
+ attributes:
4
+ remote_account:
5
+ uid: Remote account ID
6
+ errors:
7
+ messages:
8
+ not_matching_accounts: Different ownership of rental and remote_rental
9
+
10
+ bookingsync_portal:
11
+ admin:
12
+ remote_accounts:
13
+ new:
14
+ title: Connect A New Remote Account
15
+ form:
16
+ submit_new: Connect This Remote Account
17
+
18
+ remote_rentals:
19
+ show:
20
+ listing_id: "Listing #%{id}"
21
+
22
+ rentals:
23
+ index:
24
+ connect: Connect
25
+ bookingsync_header: "BookingSync: %{account_name}"
26
+ all_synchronized: Perfect! All your rentals are synchronized.
27
+ create_listings_first: You must create your rentals on Remote Account before you can synchronize them automatically.
28
+ connect_accounts: Add External Portal Account
29
+ remote_header: "Remote Account: %{account_name}"
30
+ rental:
31
+ bedrooms_html:
32
+ one: '<strong>1</strong> Bedroom'
33
+ other: '<strong>%{count}</strong> Bedrooms'
34
+ bathrooms_html:
35
+ one: '<strong>1</strong> Bathroom'
36
+ other: '<strong>%{count}</strong> Bathrooms'
37
+ sleeps_html:
38
+ one: '<strong>%{count}</strong> Person'
39
+ other: '<strong>%{count}</strong> People'
40
+ surface_html:
41
+ zero: ''
42
+ other: '<span>Surface</span> <strong>%{count}m²</strong>'
43
+ no_name: Unnamed rental
44
+ remote_rental:
45
+ no_name: Unnamed remote rental
46
+ connected_rental:
47
+ disconnect_rental: 'Disconnect'
48
+ disconnecting_rental: 'Disconnecting...'
49
+ synchronizing: 'Synchronizing...'
50
+
51
+ simple_form:
52
+ "yes": 'Yes'
53
+ "no": 'No'
54
+ required:
55
+ text: 'required'
56
+ mark: '*'
57
+ error_notification:
58
+ default_message: "Please review the problems below:"