rails-contact 0.1.7 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/README.md +16 -0
- data/app/controllers/rails/contact/contacts_controller.rb +38 -1
- data/app/jobs/rails/contact/google_sync_unsynced_job.rb +13 -0
- data/app/views/rails/contact/_google_sync_panel.html.erb +27 -0
- data/app/views/rails/contact/_index_pagination.html.erb +25 -0
- data/app/views/rails/contact/index.html.erb +3 -0
- data/config/routes.rb +2 -0
- data/lib/generators/rails/contact/install/templates/rails_contact.rb.tt +2 -0
- data/lib/rails/contact/configuration.rb +3 -1
- data/lib/rails/contact/google/sync_service.rb +16 -0
- data/lib/rails/contact/search/backends/database.rb +13 -8
- data/lib/rails/contact/search/backends/elasticsearch.rb +19 -7
- data/lib/rails/contact/search/query.rb +12 -2
- data/lib/rails/contact/search/result.rb +13 -0
- data/lib/rails/contact/version.rb +1 -1
- data/lib/rails/contact.rb +1 -0
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 50cd2c0740daf7405d8085d2956f810cf0bf8883388ff12afb72ee07a6497b6c
|
|
4
|
+
data.tar.gz: 64db2836ff0701a348e215ea294dae2cef1326ef3fb633a4a69676c4b5e477ef
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6b8653a3e39f49d9d6aa1bb04463df1f4b5b10ac31d759af6b5bb465b8b2b4ecfbf9a83ee8cbf60a70296d805b5df91e942031ea85f0d530075d00e18bb5a4bc
|
|
7
|
+
data.tar.gz: e42099d4322b591d5ae7646560afda7178e5ce1674512efab58ef172d34fe74b99b46583553e6cad43ff2a47c96cf95efe34bdd9d2e68958fc77a3a164585812
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.11
|
|
4
|
+
|
|
5
|
+
- Default **Google sync panel** back on the engine index via `_google_sync_panel` when `google_sync_enabled` and `google_sync_ui_on_index` (default true). Host apps can override the partial or disable with `google_sync_ui_on_index = false`.
|
|
6
|
+
|
|
7
|
+
## 0.1.10
|
|
8
|
+
|
|
9
|
+
- Short-lived: engine index omitted the Google panel (use **0.1.11** instead).
|
|
10
|
+
|
|
11
|
+
## 0.1.9
|
|
12
|
+
|
|
13
|
+
- `POST /google_sync_rolling_window` → `ContactsController#google_sync_rolling_window` → `GoogleSyncJob` (re-sync rolling window: creates + updates).
|
|
14
|
+
|
|
15
|
+
## 0.1.8
|
|
16
|
+
|
|
17
|
+
- Contacts index: paginated search (total count, previous/next, page indicator) with Elasticsearch and database backends.
|
|
18
|
+
- `POST /google_sync_unsynced` and **Sync … not yet in Google** button when sync is enabled; `GoogleSyncUnsyncedJob` runs `SyncService#sync_unsynced!` for contacts with no `google_resource_name`.
|
|
19
|
+
|
|
3
20
|
## 0.1.7
|
|
4
21
|
|
|
5
22
|
- Google People API: `updateContact` sends required `updatePersonFields`; update payloads include `resourceName` and `etag`; sync preloads emails, phones, and addresses.
|
data/README.md
CHANGED
|
@@ -134,6 +134,22 @@ Rails::Contact.configure do |config|
|
|
|
134
134
|
end
|
|
135
135
|
```
|
|
136
136
|
|
|
137
|
+
### Google sync UI: gem default vs host override
|
|
138
|
+
|
|
139
|
+
**Recommendation:** keep the **default panel in the gem** so every app gets working buttons when `google_sync_enabled` is true. You avoid copy-paste and stay aligned with new endpoints.
|
|
140
|
+
|
|
141
|
+
- The index template renders `rails/contact/_google_sync_panel` when `google_sync_ui_on_index` is **true** (default).
|
|
142
|
+
- **Customize without forking the engine:** add `app/views/rails/contact/_google_sync_panel.html.erb` in the host app; Rails resolves that file instead of the gem’s partial.
|
|
143
|
+
- **Hide the default panel:** set `config.google_sync_ui_on_index = false` and render your own UI anywhere (same `POST` targets below).
|
|
144
|
+
- **Custom index only:** override `rails/contact/index` and `<%= render "rails/contact/google_sync_panel" %>` wherever it fits (e.g. after a CSV upload section).
|
|
145
|
+
|
|
146
|
+
Endpoints (used by the default partial):
|
|
147
|
+
|
|
148
|
+
- `google_sync_rolling_window_contacts_path` — `GoogleSyncJob` (rolling window re-sync).
|
|
149
|
+
- `google_sync_unsynced_contacts_path` — `GoogleSyncUnsyncedJob` (contacts with no `google_resource_name`).
|
|
150
|
+
|
|
151
|
+
`ContactsController#index` sets `@google_contacts_pending_sync` when sync is enabled.
|
|
152
|
+
|
|
137
153
|
---
|
|
138
154
|
|
|
139
155
|
## Rake tasks
|
|
@@ -10,10 +10,41 @@ module Rails
|
|
|
10
10
|
|
|
11
11
|
def index
|
|
12
12
|
@query = params[:q].to_s.strip
|
|
13
|
-
|
|
13
|
+
result = Search::Query.new(
|
|
14
|
+
@query,
|
|
15
|
+
filters: normalized_filters(filter_params),
|
|
16
|
+
page: params[:page]
|
|
17
|
+
).call
|
|
18
|
+
@contacts = result.records
|
|
19
|
+
@total_count = result.total_count
|
|
20
|
+
@page = result.page
|
|
21
|
+
@per_page = result.per_page
|
|
22
|
+
@total_pages = result.total_pages
|
|
23
|
+
@google_contacts_pending_sync = google_pending_sync_count
|
|
14
24
|
render "rails/contact/index"
|
|
15
25
|
end
|
|
16
26
|
|
|
27
|
+
def google_sync_unsynced
|
|
28
|
+
unless Rails::Contact.configuration.google_sync_enabled
|
|
29
|
+
redirect_to contacts_path, alert: "Google Contacts sync is disabled."
|
|
30
|
+
return
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
GoogleSyncUnsyncedJob.perform_later
|
|
34
|
+
redirect_to contacts_path, notice: "Google sync has been queued for contacts not yet linked."
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def google_sync_rolling_window
|
|
38
|
+
unless Rails::Contact.configuration.google_sync_enabled
|
|
39
|
+
redirect_to contacts_path, alert: "Google Contacts sync is disabled."
|
|
40
|
+
return
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
GoogleSyncJob.perform_later
|
|
44
|
+
redirect_to contacts_path,
|
|
45
|
+
notice: "Google re-sync has been queued for contacts in the recent window (creates and updates)."
|
|
46
|
+
end
|
|
47
|
+
|
|
17
48
|
def show
|
|
18
49
|
render "rails/contact/show"
|
|
19
50
|
end
|
|
@@ -99,6 +130,12 @@ module Rails
|
|
|
99
130
|
params.permit(:city, :region, :sync_eligible, :starred)
|
|
100
131
|
end
|
|
101
132
|
|
|
133
|
+
def google_pending_sync_count
|
|
134
|
+
return 0 unless Rails::Contact.configuration.google_sync_enabled
|
|
135
|
+
|
|
136
|
+
Contact.where("google_resource_name IS NULL OR google_resource_name = ?", "").count
|
|
137
|
+
end
|
|
138
|
+
|
|
102
139
|
def enqueue_index(contact_id)
|
|
103
140
|
IndexContactJob.perform_later(contact_id)
|
|
104
141
|
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<% if Rails::Contact.configuration.google_sync_enabled && Rails::Contact.configuration.google_sync_ui_on_index %>
|
|
2
|
+
<div class="rounded-xl border border-gray-200 bg-white p-4 shadow-sm space-y-4">
|
|
3
|
+
<h2 class="text-sm font-semibold text-gray-900">Google Contacts</h2>
|
|
4
|
+
|
|
5
|
+
<div>
|
|
6
|
+
<%= form_with url: google_sync_rolling_window_contacts_path, method: :post, local: true, class: "flex flex-wrap items-center gap-3" do %>
|
|
7
|
+
<%= submit_tag "Re-sync recent contacts with Google",
|
|
8
|
+
class: "inline-flex rounded-md bg-emerald-600 px-4 py-2 text-sm font-semibold text-white hover:bg-emerald-700",
|
|
9
|
+
data: { confirm: "Queue Google sync for the recent contact window? This updates contacts already in Google and creates any that are missing. Runs in the background." } %>
|
|
10
|
+
<% end %>
|
|
11
|
+
<p class="mt-2 text-xs text-gray-500">
|
|
12
|
+
Pushes the most recently updated contacts (up to your configured limit) to Google—new rows and changes to names, emails, phones, etc.
|
|
13
|
+
</p>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<% if @google_contacts_pending_sync.to_i.positive? %>
|
|
17
|
+
<div class="border-t border-gray-100 pt-4">
|
|
18
|
+
<%= form_with url: google_sync_unsynced_contacts_path, method: :post, local: true, class: "flex flex-wrap items-center gap-3" do %>
|
|
19
|
+
<%= submit_tag "Sync #{@google_contacts_pending_sync} contact#{'s' if @google_contacts_pending_sync != 1} with no Google link yet (any age)",
|
|
20
|
+
class: "inline-flex rounded-md border border-emerald-700 bg-white px-4 py-2 text-sm font-semibold text-emerald-800 hover:bg-emerald-50",
|
|
21
|
+
data: { confirm: "Queue Google sync for #{@google_contacts_pending_sync} contact(s) that are not linked yet? This runs in the background." } %>
|
|
22
|
+
<% end %>
|
|
23
|
+
<p class="mt-2 text-xs text-gray-500">For contacts outside the recent window or older imports that never received a Google <code class="rounded bg-gray-100 px-1">resourceName</code>.</p>
|
|
24
|
+
</div>
|
|
25
|
+
<% end %>
|
|
26
|
+
</div>
|
|
27
|
+
<% end %>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<% if defined?(@total_count) && @total_count.to_i > 0 %>
|
|
2
|
+
<div class="flex flex-col gap-3 border-t border-gray-200 bg-gray-50 px-4 py-3 sm:flex-row sm:items-center sm:justify-between">
|
|
3
|
+
<p class="text-sm text-gray-600">
|
|
4
|
+
<% start_i = (@page - 1) * @per_page + 1 %>
|
|
5
|
+
<% end_i = [ @page * @per_page, @total_count ].min %>
|
|
6
|
+
Showing <span class="font-medium text-gray-900"><%= start_i %>–<%= end_i %></span>
|
|
7
|
+
of <span class="font-medium text-gray-900"><%= number_with_delimiter(@total_count) %></span>
|
|
8
|
+
<% if @per_page.present? && @per_page > 0 %>
|
|
9
|
+
<span class="text-gray-500">(<%= @per_page %> per page)</span>
|
|
10
|
+
<% end %>
|
|
11
|
+
</p>
|
|
12
|
+
<% if defined?(@total_pages) && @total_pages > 1 %>
|
|
13
|
+
<div class="flex flex-wrap items-center gap-2">
|
|
14
|
+
<% qp = request.query_parameters.except(:page, :action, :controller) %>
|
|
15
|
+
<% if @page > 1 %>
|
|
16
|
+
<%= link_to "Previous", url_for(qp.merge(page: @page - 1)), class: "inline-flex rounded-md border border-gray-300 bg-white px-3 py-1.5 text-sm font-medium text-gray-700 hover:bg-gray-50" %>
|
|
17
|
+
<% end %>
|
|
18
|
+
<span class="text-sm text-gray-600">Page <%= @page %> / <%= @total_pages %></span>
|
|
19
|
+
<% if @page < @total_pages %>
|
|
20
|
+
<%= link_to "Next", url_for(qp.merge(page: @page + 1)), class: "inline-flex rounded-md border border-gray-300 bg-white px-3 py-1.5 text-sm font-medium text-gray-700 hover:bg-gray-50" %>
|
|
21
|
+
<% end %>
|
|
22
|
+
</div>
|
|
23
|
+
<% end %>
|
|
24
|
+
</div>
|
|
25
|
+
<% end %>
|
|
@@ -26,6 +26,8 @@
|
|
|
26
26
|
<% end %>
|
|
27
27
|
</div>
|
|
28
28
|
|
|
29
|
+
<%= render "rails/contact/google_sync_panel" %>
|
|
30
|
+
|
|
29
31
|
<div class="rounded-xl border border-gray-200 bg-white p-4 shadow-sm">
|
|
30
32
|
<%= form_with url: bulk_destroy_contacts_path, method: :post, local: true, class: "inline-flex items-center gap-2" do |f| %>
|
|
31
33
|
<%= hidden_field_tag :ids, "", id: "bulk-ids-field" %>
|
|
@@ -76,6 +78,7 @@
|
|
|
76
78
|
<% end %>
|
|
77
79
|
</tbody>
|
|
78
80
|
</table>
|
|
81
|
+
<%= render "rails/contact/index_pagination" %>
|
|
79
82
|
</div>
|
|
80
83
|
</div>
|
|
81
84
|
|
data/config/routes.rb
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
Rails::Contact::Engine.routes.draw do
|
|
2
2
|
post "/bulk_destroy", to: "contacts#bulk_destroy", as: :bulk_destroy_contacts
|
|
3
3
|
post "/merge", to: "contacts#merge", as: :merge_contacts
|
|
4
|
+
post "/google_sync_unsynced", to: "contacts#google_sync_unsynced", as: :google_sync_unsynced_contacts
|
|
5
|
+
post "/google_sync_rolling_window", to: "contacts#google_sync_rolling_window", as: :google_sync_rolling_window_contacts
|
|
4
6
|
get "/", to: "contacts#index", as: :contacts
|
|
5
7
|
get "/new", to: "contacts#new", as: :new_contact
|
|
6
8
|
post "/", to: "contacts#create"
|
|
@@ -4,6 +4,8 @@ Rails::Contact.configure do |config|
|
|
|
4
4
|
config.elasticsearch_url = ENV.fetch("ELASTICSEARCH_URL", "http://127.0.0.1:9200")
|
|
5
5
|
|
|
6
6
|
config.google_sync_enabled = ENV.fetch("RAILS_CONTACT_GOOGLE_SYNC_ENABLED", "false") == "true"
|
|
7
|
+
# When true (default), contacts index renders the gem’s Google sync panel; set false to supply your own UI.
|
|
8
|
+
# config.google_sync_ui_on_index = false
|
|
7
9
|
config.google_max_contacts = 25_000
|
|
8
10
|
config.rolling_window_sort = :updated_at
|
|
9
11
|
|
|
@@ -2,7 +2,7 @@ module Rails
|
|
|
2
2
|
module Contact
|
|
3
3
|
class Configuration
|
|
4
4
|
attr_accessor :contact_class_name, :elasticsearch_url, :search_backend,
|
|
5
|
-
:google_sync_enabled, :google_max_contacts, :rolling_window_sort,
|
|
5
|
+
:google_sync_enabled, :google_sync_ui_on_index, :google_max_contacts, :rolling_window_sort,
|
|
6
6
|
:google_client_id, :google_client_secret, :google_redirect_uri,
|
|
7
7
|
:google_token_path, :reset_index_on_boot, :default_per_page,
|
|
8
8
|
:inherit_host_layout,
|
|
@@ -13,6 +13,8 @@ module Rails
|
|
|
13
13
|
@elasticsearch_url = ENV.fetch("ELASTICSEARCH_URL", "http://127.0.0.1:9200")
|
|
14
14
|
@search_backend = :elasticsearch
|
|
15
15
|
@google_sync_enabled = false
|
|
16
|
+
# When true with google_sync_enabled, the default index renders _google_sync_panel (host can override that partial).
|
|
17
|
+
@google_sync_ui_on_index = true
|
|
16
18
|
@google_max_contacts = 25_000
|
|
17
19
|
@rolling_window_sort = :updated_at
|
|
18
20
|
@google_client_id = ENV["GOOGLE_CLIENT_ID"]
|
|
@@ -13,6 +13,22 @@ module Rails
|
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
def unsynced_contacts_scope
|
|
17
|
+
Rails::Contact::Contact.where("google_resource_name IS NULL OR google_resource_name = ?", "")
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def sync_unsynced!
|
|
21
|
+
unsynced_contacts_scope.in_batches(of: 100) do |batch|
|
|
22
|
+
batch.preload(:emails, :phones, :addresses).each do |contact|
|
|
23
|
+
sync_contact(contact)
|
|
24
|
+
rescue StandardError => e
|
|
25
|
+
Rails.logger.error(
|
|
26
|
+
"[Rails::Contact] Google sync_unsynced failed for contact #{contact.id}: #{e.class}: #{e.message}"
|
|
27
|
+
)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
16
32
|
def sync_contact(contact)
|
|
17
33
|
payload = PayloadMapper.new(contact).to_people_payload
|
|
18
34
|
response = if contact.google_resource_name.present?
|
|
@@ -3,13 +3,19 @@ module Rails
|
|
|
3
3
|
module Search
|
|
4
4
|
module Backends
|
|
5
5
|
class Database
|
|
6
|
-
def search(query, filters)
|
|
6
|
+
def search(query, filters, page:, per_page:)
|
|
7
|
+
offset = (page - 1) * per_page
|
|
7
8
|
scope = Contact.includes(:emails, :phones, :labels).recent_first
|
|
8
9
|
scope = apply_filters(scope, filters)
|
|
9
|
-
|
|
10
|
+
|
|
11
|
+
if query.blank?
|
|
12
|
+
total = scope.count
|
|
13
|
+
records = scope.offset(offset).limit(per_page).to_a
|
|
14
|
+
return Search::Result.new(records: records, total_count: total, page: page, per_page: per_page)
|
|
15
|
+
end
|
|
10
16
|
|
|
11
17
|
wildcard = "%#{query.downcase}%"
|
|
12
|
-
scope.left_joins(:emails, :phones, :labels).where(
|
|
18
|
+
filtered = scope.left_joins(:emails, :phones, :labels).where(
|
|
13
19
|
"LOWER(rails_contact_contacts.given_name) LIKE :q OR "\
|
|
14
20
|
"LOWER(rails_contact_contacts.family_name) LIKE :q OR "\
|
|
15
21
|
"LOWER(COALESCE(rails_contact_contacts.metadata->>'company', '')) LIKE :q OR "\
|
|
@@ -19,7 +25,10 @@ module Rails
|
|
|
19
25
|
"LOWER(rails_contact_labels.name) LIKE :q",
|
|
20
26
|
q: wildcard,
|
|
21
27
|
raw: "%#{query}%"
|
|
22
|
-
).distinct
|
|
28
|
+
).distinct
|
|
29
|
+
total = filtered.count(:id)
|
|
30
|
+
records = filtered.offset(offset).limit(per_page).to_a
|
|
31
|
+
Search::Result.new(records: records, total_count: total, page: page, per_page: per_page)
|
|
23
32
|
end
|
|
24
33
|
|
|
25
34
|
private
|
|
@@ -34,10 +43,6 @@ module Rails
|
|
|
34
43
|
end
|
|
35
44
|
scoped
|
|
36
45
|
end
|
|
37
|
-
|
|
38
|
-
def limit
|
|
39
|
-
Rails::Contact.configuration.default_per_page
|
|
40
|
-
end
|
|
41
46
|
end
|
|
42
47
|
end
|
|
43
48
|
end
|
|
@@ -23,13 +23,16 @@ module Rails
|
|
|
23
23
|
@client = client || self.class.default_client
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
def search(query, filters)
|
|
27
|
-
response = @client.search(index: INDEX, body: search_body(query, filters))
|
|
28
|
-
|
|
26
|
+
def search(query, filters, page:, per_page:)
|
|
27
|
+
response = @client.search(index: INDEX, body: search_body(query, filters, page: page, per_page: per_page))
|
|
28
|
+
hits = response.fetch("hits", {})
|
|
29
|
+
ids = hits.fetch("hits", []).map { |doc| doc["_id"] }
|
|
30
|
+
total_count = extract_total_hits(hits["total"])
|
|
29
31
|
records_by_id = Contact.where(id: ids).index_by { |record| record.id.to_s }
|
|
30
|
-
ids.filter_map { |id| records_by_id[id.to_s] }
|
|
32
|
+
records = ids.filter_map { |id| records_by_id[id.to_s] }
|
|
33
|
+
Search::Result.new(records: records, total_count: total_count, page: page, per_page: per_page)
|
|
31
34
|
rescue StandardError
|
|
32
|
-
Search::Backends::Database.new.search(query, filters)
|
|
35
|
+
Search::Backends::Database.new.search(query, filters, page: page, per_page: per_page)
|
|
33
36
|
end
|
|
34
37
|
|
|
35
38
|
def upsert(contact)
|
|
@@ -81,9 +84,12 @@ module Rails
|
|
|
81
84
|
}
|
|
82
85
|
end
|
|
83
86
|
|
|
84
|
-
def search_body(query, filters)
|
|
87
|
+
def search_body(query, filters, page:, per_page:)
|
|
88
|
+
from = (page - 1) * per_page
|
|
85
89
|
{
|
|
86
|
-
|
|
90
|
+
from: from,
|
|
91
|
+
size: per_page,
|
|
92
|
+
track_total_hits: true,
|
|
87
93
|
sort: [ { updated_at: { order: "desc" } }, { id: { order: "desc" } } ],
|
|
88
94
|
query: {
|
|
89
95
|
bool: {
|
|
@@ -94,6 +100,12 @@ module Rails
|
|
|
94
100
|
}
|
|
95
101
|
end
|
|
96
102
|
|
|
103
|
+
def extract_total_hits(raw)
|
|
104
|
+
return 0 if raw.nil?
|
|
105
|
+
|
|
106
|
+
raw.is_a?(Hash) ? raw.fetch("value", 0).to_i : raw.to_i
|
|
107
|
+
end
|
|
108
|
+
|
|
97
109
|
def search_clause(query)
|
|
98
110
|
return [ { match_all: {} } ] if query.blank?
|
|
99
111
|
|
|
@@ -2,13 +2,17 @@ module Rails
|
|
|
2
2
|
module Contact
|
|
3
3
|
module Search
|
|
4
4
|
class Query
|
|
5
|
-
|
|
5
|
+
MAX_PER_PAGE = 100
|
|
6
|
+
|
|
7
|
+
def initialize(query, filters: {}, page: nil, per_page: nil)
|
|
6
8
|
@query = query
|
|
7
9
|
@filters = filters.to_h.compact_blank
|
|
10
|
+
@page = page.to_i < 1 ? 1 : page.to_i
|
|
11
|
+
@per_page = resolve_per_page(per_page)
|
|
8
12
|
end
|
|
9
13
|
|
|
10
14
|
def call
|
|
11
|
-
backend.search(@query, @filters)
|
|
15
|
+
backend.search(@query, @filters, page: @page, per_page: @per_page)
|
|
12
16
|
end
|
|
13
17
|
|
|
14
18
|
private
|
|
@@ -21,6 +25,12 @@ module Rails
|
|
|
21
25
|
Search::Backends::Database.new
|
|
22
26
|
end
|
|
23
27
|
end
|
|
28
|
+
|
|
29
|
+
def resolve_per_page(per_page)
|
|
30
|
+
p = per_page.to_i
|
|
31
|
+
p = Rails::Contact.configuration.default_per_page if p <= 0
|
|
32
|
+
[ p, MAX_PER_PAGE ].min
|
|
33
|
+
end
|
|
24
34
|
end
|
|
25
35
|
end
|
|
26
36
|
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Contact
|
|
3
|
+
module Search
|
|
4
|
+
Result = Struct.new(:records, :total_count, :page, :per_page, keyword_init: true) do
|
|
5
|
+
def total_pages
|
|
6
|
+
return 0 if total_count.zero? || per_page.zero?
|
|
7
|
+
|
|
8
|
+
(total_count.to_f / per_page).ceil
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
data/lib/rails/contact.rb
CHANGED
|
@@ -4,6 +4,7 @@ require "rails/contact/engine"
|
|
|
4
4
|
require "rails/contact/configuration"
|
|
5
5
|
require "rails/contact/orm"
|
|
6
6
|
require "rails/contact/routing"
|
|
7
|
+
require "rails/contact/search/result"
|
|
7
8
|
require "rails/contact/search/query"
|
|
8
9
|
require "rails/contact/search/backends/database"
|
|
9
10
|
require "rails/contact/search/backends/elasticsearch"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails-contact
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.11
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kshitiz Sinha
|
|
@@ -119,6 +119,7 @@ files:
|
|
|
119
119
|
- app/helpers/rails/contact/application_helper.rb
|
|
120
120
|
- app/jobs/rails/contact/application_job.rb
|
|
121
121
|
- app/jobs/rails/contact/google_sync_job.rb
|
|
122
|
+
- app/jobs/rails/contact/google_sync_unsynced_job.rb
|
|
122
123
|
- app/jobs/rails/contact/index_contact_job.rb
|
|
123
124
|
- app/mailers/rails/contact/application_mailer.rb
|
|
124
125
|
- app/mailers/rails/contact/contact_mailer.rb
|
|
@@ -137,6 +138,8 @@ files:
|
|
|
137
138
|
- app/views/rails/contact/_email_fields.html.erb
|
|
138
139
|
- app/views/rails/contact/_event_fields.html.erb
|
|
139
140
|
- app/views/rails/contact/_form.html.erb
|
|
141
|
+
- app/views/rails/contact/_google_sync_panel.html.erb
|
|
142
|
+
- app/views/rails/contact/_index_pagination.html.erb
|
|
140
143
|
- app/views/rails/contact/_nested_fields_script.html.erb
|
|
141
144
|
- app/views/rails/contact/_phone_fields.html.erb
|
|
142
145
|
- app/views/rails/contact/_stylesheet.html.erb
|
|
@@ -181,6 +184,7 @@ files:
|
|
|
181
184
|
- lib/rails/contact/search/backends/database.rb
|
|
182
185
|
- lib/rails/contact/search/backends/elasticsearch.rb
|
|
183
186
|
- lib/rails/contact/search/query.rb
|
|
187
|
+
- lib/rails/contact/search/result.rb
|
|
184
188
|
- lib/rails/contact/version.rb
|
|
185
189
|
- lib/tasks/rails/contact_tasks.rake
|
|
186
190
|
- spec/concerns/filterable_spec.rb
|