addressbook 0.0.6

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.
Files changed (129) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +21 -0
  4. data/app/assets/images/addressbook/default.png +0 -0
  5. data/app/assets/javascripts/addressbook/application.js +15 -0
  6. data/app/assets/stylesheets/addressbook/application.css +15 -0
  7. data/app/controllers/addressbook/application_controller.rb +11 -0
  8. data/app/controllers/addressbook/contacts_controller.rb +96 -0
  9. data/app/controllers/addressbook/groups_controller.rb +53 -0
  10. data/app/helpers/addressbook/application_helper.rb +25 -0
  11. data/app/models/concerns/addressbook_owner.rb +29 -0
  12. data/app/views/addressbook/contacts/_address.html.erb +35 -0
  13. data/app/views/addressbook/contacts/_email.html.erb +15 -0
  14. data/app/views/addressbook/contacts/_form.html.erb +97 -0
  15. data/app/views/addressbook/contacts/_phone.html.erb +19 -0
  16. data/app/views/addressbook/contacts/destroy.js.erb +1 -0
  17. data/app/views/addressbook/contacts/edit.html.erb +3 -0
  18. data/app/views/addressbook/contacts/index.html.erb +115 -0
  19. data/app/views/addressbook/contacts/new.html.erb +3 -0
  20. data/app/views/addressbook/groups/_form.html.erb +25 -0
  21. data/app/views/addressbook/groups/destroy.js.erb +1 -0
  22. data/app/views/addressbook/groups/edit.html.erb +3 -0
  23. data/app/views/addressbook/groups/index.html.erb +29 -0
  24. data/app/views/addressbook/groups/new.html.erb +3 -0
  25. data/app/views/layouts/addressbook/application.html.erb +24 -0
  26. data/config/initializers/addressbook.rb +1 -0
  27. data/config/locales/en.yml +73 -0
  28. data/config/routes.rb +10 -0
  29. data/db/migrate/20141110080715_add_addressbook_account_id_to_user_table.rb +11 -0
  30. data/lib/addressbook.rb +23 -0
  31. data/lib/addressbook/account.rb +27 -0
  32. data/lib/addressbook/base_uploader.rb +33 -0
  33. data/lib/addressbook/contact.rb +128 -0
  34. data/lib/addressbook/engine.rb +10 -0
  35. data/lib/addressbook/group.rb +18 -0
  36. data/lib/addressbook/import_file_uploader.rb +7 -0
  37. data/lib/addressbook/photo_uploader.rb +27 -0
  38. data/lib/addressbook/resource.rb +24 -0
  39. data/lib/addressbook/version.rb +3 -0
  40. data/lib/generators/addressbook/controllers/controllers_generator.rb +42 -0
  41. data/lib/generators/addressbook/initializer/initializer_generator.rb +9 -0
  42. data/lib/generators/addressbook/views/views_generator.rb +42 -0
  43. data/lib/tasks/addressbook_tasks.rake +4 -0
  44. data/spec/controllers/addressbook/contacts_controller_spec.rb +169 -0
  45. data/spec/controllers/addressbook/groups_controller_spec.rb +106 -0
  46. data/spec/dummy/README.rdoc +28 -0
  47. data/spec/dummy/Rakefile +6 -0
  48. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  49. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  50. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  51. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  52. data/spec/dummy/app/models/account.rb +3 -0
  53. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  54. data/spec/dummy/bin/bundle +3 -0
  55. data/spec/dummy/bin/rails +4 -0
  56. data/spec/dummy/bin/rake +4 -0
  57. data/spec/dummy/config.ru +4 -0
  58. data/spec/dummy/config/application.rb +29 -0
  59. data/spec/dummy/config/boot.rb +5 -0
  60. data/spec/dummy/config/database.yml +25 -0
  61. data/spec/dummy/config/environment.rb +5 -0
  62. data/spec/dummy/config/environments/development.rb +41 -0
  63. data/spec/dummy/config/environments/production.rb +78 -0
  64. data/spec/dummy/config/environments/test.rb +39 -0
  65. data/spec/dummy/config/initializers/addressbook.rb +8 -0
  66. data/spec/dummy/config/initializers/assets.rb +8 -0
  67. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  68. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  69. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  70. data/spec/dummy/config/initializers/inflections.rb +16 -0
  71. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  72. data/spec/dummy/config/initializers/session_store.rb +3 -0
  73. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  74. data/spec/dummy/config/locales/en.yml +23 -0
  75. data/spec/dummy/config/routes.rb +4 -0
  76. data/spec/dummy/config/secrets.yml +22 -0
  77. data/spec/dummy/db/development.sqlite3 +0 -0
  78. data/spec/dummy/db/migrate/20141119152457_create_accounts.rb +11 -0
  79. data/spec/dummy/db/migrate/20141119152801_add_addressbook_account_id_to_user_table.addressbook.rb +12 -0
  80. data/spec/dummy/db/schema.rb +27 -0
  81. data/spec/dummy/db/seeds.rb +1 -0
  82. data/spec/dummy/db/test.sqlite3 +0 -0
  83. data/spec/dummy/log/development.log +13510 -0
  84. data/spec/dummy/log/test.log +1468 -0
  85. data/spec/dummy/public/404.html +67 -0
  86. data/spec/dummy/public/422.html +67 -0
  87. data/spec/dummy/public/500.html +66 -0
  88. data/spec/dummy/public/favicon.ico +0 -0
  89. data/spec/dummy/public/uploads/addressbook/contact/imported/test.csv +10 -0
  90. data/spec/dummy/public/uploads/addressbook/contact/imported/test.vcf +23 -0
  91. data/spec/dummy/spec/factories/accounts.rb +9 -0
  92. data/spec/dummy/spec/models/account_spec.rb +5 -0
  93. data/spec/dummy/tmp/cache/assets/development/sprockets/006961e21c4f6a44101d2e9587f863f4 +0 -0
  94. data/spec/dummy/tmp/cache/assets/development/sprockets/032ca99c7bed652dbad8de691558648d +0 -0
  95. data/spec/dummy/tmp/cache/assets/development/sprockets/06b00b7743f1b8c8020fabbb5c63e13a +0 -0
  96. data/spec/dummy/tmp/cache/assets/development/sprockets/0765e86c020fb088284e8f45c584f8c6 +0 -0
  97. data/spec/dummy/tmp/cache/assets/development/sprockets/1648d5d40aa02876f2cbb311ab2c4712 +0 -0
  98. data/spec/dummy/tmp/cache/assets/development/sprockets/17405e31165e7d8129c846ceabaafec0 +0 -0
  99. data/spec/dummy/tmp/cache/assets/development/sprockets/1dcb75c883fc0e57d08de7a76f0ada73 +0 -0
  100. data/spec/dummy/tmp/cache/assets/development/sprockets/30f5fe3df78dce04aa1f998f6d790113 +0 -0
  101. data/spec/dummy/tmp/cache/assets/development/sprockets/4b14ea7024b3a7934c5cf77c17cc92aa +0 -0
  102. data/spec/dummy/tmp/cache/assets/development/sprockets/604356b7aab9d373aa02548bf52b266b +0 -0
  103. data/spec/dummy/tmp/cache/assets/development/sprockets/69fcb234f5e891fcb7fbeb727a703968 +0 -0
  104. data/spec/dummy/tmp/cache/assets/development/sprockets/6ec3857048c9b608a152271ff3991df6 +0 -0
  105. data/spec/dummy/tmp/cache/assets/development/sprockets/786158650544be3da3cd56983ff6540f +0 -0
  106. data/spec/dummy/tmp/cache/assets/development/sprockets/790fb0d33aad92cb9a1745822d4668aa +0 -0
  107. data/spec/dummy/tmp/cache/assets/development/sprockets/7954e67edaec86854ad0d70dfdc1df99 +0 -0
  108. data/spec/dummy/tmp/cache/assets/development/sprockets/816240bd34b73344a7ac901c29906f1d +0 -0
  109. data/spec/dummy/tmp/cache/assets/development/sprockets/8a8a4eebb0809e6e5a1d1dc83dafb50d +0 -0
  110. data/spec/dummy/tmp/cache/assets/development/sprockets/8e844acaef03b740a1d21aafa3030124 +0 -0
  111. data/spec/dummy/tmp/cache/assets/development/sprockets/91d3ad598e6e79937286c98b2b259cee +0 -0
  112. data/spec/dummy/tmp/cache/assets/development/sprockets/98e43302695126215ff9abe4b05eda56 +0 -0
  113. data/spec/dummy/tmp/cache/assets/development/sprockets/aa5e472ff34ac18d968ac316ca9caff2 +0 -0
  114. data/spec/dummy/tmp/cache/assets/development/sprockets/aa9a9307e1b4596e0b92b403107a2cfb +0 -0
  115. data/spec/dummy/tmp/cache/assets/development/sprockets/aee3f8a82c799313c63b922ed8b0f975 +0 -0
  116. data/spec/dummy/tmp/cache/assets/development/sprockets/c1f56035111b730c0c3807bf5ca35251 +0 -0
  117. data/spec/dummy/tmp/cache/assets/development/sprockets/c497b90d7dd45d368ec4e83d97d0a2b9 +0 -0
  118. data/spec/dummy/tmp/cache/assets/development/sprockets/d23b864a4a8239210d53e50644405687 +0 -0
  119. data/spec/dummy/tmp/cache/assets/development/sprockets/dee437547d5fb5fab72af8a8d8582d4d +0 -0
  120. data/spec/dummy/tmp/cache/assets/development/sprockets/e9553c97dc4fe95dc10736ee0475dc45 +0 -0
  121. data/spec/dummy/tmp/cache/assets/development/sprockets/ec3c091506a3d1ea73ac726b7ee9b3c2 +0 -0
  122. data/spec/fixtures/test.csv +10 -0
  123. data/spec/fixtures/test.vcf +23 -0
  124. data/spec/model/addressbook/account_spec.rb +33 -0
  125. data/spec/model/addressbook/contact_spec.rb +79 -0
  126. data/spec/model/addressbook/group_spec.rb +11 -0
  127. data/spec/model/addressbook/resource_spec.rb +10 -0
  128. data/spec/spec_helper.rb +65 -0
  129. metadata +517 -0
@@ -0,0 +1,19 @@
1
+ <div class="nested-fields addressbook-contact-fields">
2
+ <%= hidden_field_tag "contact[phones_attributes][][id]", phone.id if phone.id.present? %>
3
+ <%= hidden_field_tag "contact[phones_attributes][][_destroy]", false, class: 'destroy_association_field' %>
4
+
5
+ <div class="field">
6
+ <%= label_tag :number, t('addressbook.contact.number') %>
7
+ <%= text_field_tag "contact[phones_attributes][][number]", phone.number %>
8
+ </div>
9
+ <div class="field">
10
+ <%= label_tag :phone_type, t('addressbook.contact.phone_type') %>
11
+ <%= select_tag "contact[phones_attributes][][phone_type]", options_for_select(Addressbook::Contact::Phone::TYPES, phone.phone_type) %>
12
+ </div>
13
+ <div class="field">
14
+ <%= label_tag :preferred, t('addressbook.contact.preferred') %>
15
+ <%= check_box_tag "contact[phones_attributes][][preferred]", true, (phone.try(:preferred) || false) %>
16
+ </div>
17
+
18
+ <a class="remove_contact_associaton" href="#"><%= t('addressbook.contact.remove_phone') %></a>
19
+ </div>
@@ -0,0 +1 @@
1
+ $('.addressbook-contact[data-id="<%= @contact.id %>"]').fadeOut().remove();
@@ -0,0 +1,3 @@
1
+ <h1>Edit Contact</h1>
2
+
3
+ <%= render 'form' %>
@@ -0,0 +1,115 @@
1
+ <%= link_to t('addressbook.contact.new_contact'), new_contact_path %>
2
+ <%= form_tag({ action: 'import_vcard' }, { class: 'import-form', multipart: true }) do %>
3
+ <input type="file" name="vcard" style="display: none;">
4
+ <%= link_to t('addressbook.contact.import_vcard'), '#', class: 'import-file' %>
5
+ <% end %>
6
+ <%= form_tag({ action: 'import_csv' }, { class: 'import-form', multipart: true }) do %>
7
+ <input type="file" name="csv" style="display: none;">
8
+ <%= link_to t('addressbook.contact.import_csv'), '#', class: 'import-file' %>
9
+ <% end %>
10
+
11
+ <p>
12
+ <%= form_tag contacts_path, method: :get, class: 'form-horizontal' do %>
13
+ <div class="field">
14
+ <%= label_tag :query, t('addressbook.contact.query') %>
15
+ <%= text_field_tag :query, params[:query], placeholder: t('addressbook.contact.query_placeholder') %>
16
+ </div>
17
+ <%= submit_tag t('addressbook.actions.search') %>
18
+ <% end %>
19
+ </p>
20
+
21
+ <% unless @contacts.blank? %>
22
+ <p><%= t('addressbook.contact.total') %>: <%= @contacts.total_count %></p>
23
+
24
+ <table class="table table-striped table-bordered table-condensed">
25
+ <thead>
26
+ <th><%= t('addressbook.contact.photo') %></th>
27
+ <th><%= t('addressbook.contact.name') %></th>
28
+ <th><%= t('addressbook.contact.group') %></th>
29
+ <th><%= t('addressbook.contact.company_address') %></th>
30
+ <th><%= t('addressbook.contact.contact_methods') %></th>
31
+ <th><%= t('addressbook.contact.status') %></th>
32
+ <th><%= t('addressbook.contact.created_at') %></th>
33
+ <th></th>
34
+ </thead>
35
+ <tbody>
36
+ <% @contacts.each do |contact| %>
37
+ <tr class="addressbook-contact" data-id='<%= contact.id %>'>
38
+ <td><%= image_tag contact.thumb_url || 'addressbook/default.png' %></td>
39
+ <td>
40
+ <%= [contact.first_name, contact.last_name].reject(&:blank?).join(' ') %>
41
+ <% unless contact.title.blank? %>
42
+ <br>
43
+ <%= contact.title %>
44
+ <% end %>
45
+ <% unless contact.nickname.blank? %>
46
+ <br>
47
+ <%= contact.nickname %>
48
+ <% end %>
49
+ <% unless contact.dob.blank? %>
50
+ <br>
51
+ <%= Time.parse(contact.dob).strftime('%m/%d/%Y') %>
52
+ <% end %>
53
+ <% unless contact.gender.blank? %>
54
+ <br>
55
+ <%= contact.gender %>
56
+ <% end %>
57
+ </td>
58
+ <td><%= contact.groups.map { |x| x.name }. join(', ') %></td>
59
+ <td>
60
+ <% unless contact.company.blank? %>
61
+ <%= contact.company %>
62
+ <br>
63
+ <% end %>
64
+ <% unless (address = contact.addresses.first).blank? %>
65
+ <%= [address.line1, address.line2, address.line3].reject(&:blank?).join(' ') %>
66
+ <br>
67
+ <%= [address.zipcode, address.city, address.state].reject(&:blank?).join(' ') %>
68
+ <br>
69
+ <%= address.country %>
70
+ <br>
71
+ <% end %>
72
+ </td>
73
+ <td>
74
+ <% contact.emails.each do |m| %>
75
+ <span class="glyphicon glyphicon-envelope"></span>
76
+ <%= m.email %>
77
+ <br>
78
+ <% end %>
79
+ <% contact.phones.each do |p| %>
80
+ <span class="glyphicon glyphicon-#{phone_icon_class(p.phone_type)}"></span>
81
+ <%= p.number %>
82
+ <br>
83
+ <% end %>
84
+ <% unless contact.homepage.blank? %>
85
+ <span class="glyphicon glyphicon-globe"></span>
86
+ <%= link_to contact.homepage.gsub(/http(s)?:\/\//, ''), contact.homepage, target: '_blank' %>
87
+ <% end %>
88
+ </td>
89
+ <td><%= contact.status %></td>
90
+ <td><%= Time.parse(contact.created_at) %></td>
91
+ <td>
92
+ <%= link_to t('addressbook.actions.edit'), edit_contact_path(contact.id) %> |
93
+ <%= link_to t('addressbook.actions.delete'), contact_path(contact.id), method: :delete, remote: true, data: { confirm: t('addressbook.contact.delete_confirm') } %>
94
+ </td>
95
+ </tr>
96
+ <%end%>
97
+ </tbody>
98
+ </table>
99
+ <% else %>
100
+ <p><%= t('addressbook.contact.no_contacts') %></p>
101
+ <% end %>
102
+
103
+ <%= paginate @contacts %>
104
+
105
+ <script>
106
+ $('.import-file').click(function(e) {
107
+ e.preventDefault();
108
+ $(this).parents('form').find('input').click();
109
+ return false;
110
+ });
111
+
112
+ $('.import-form input').change(function(e) {
113
+ $(this).parents('form').submit();
114
+ });
115
+ </script>
@@ -0,0 +1,3 @@
1
+ <h1>New Contact</h1>
2
+
3
+ <%= render 'form' %>
@@ -0,0 +1,25 @@
1
+ <%= form_for @group do |f| %>
2
+ <% if @group.errors.any? %>
3
+ <div id="error_explanation">
4
+ <h2><%= t('addressbook.group.error_explanation', count: @group.errors.count) %></h2>
5
+ <ul>
6
+ <% @group.errors.full_messages.each do |msg| %>
7
+ <li><%= msg %></li>
8
+ <% end %>
9
+ </ul>
10
+ </div>
11
+ <% end %>
12
+
13
+ <div class="field">
14
+ <%= f.label :name, t('addressbook.group.name') %>
15
+ <%= f.text_field :name %>
16
+ </div>
17
+ <div class="field">
18
+ <%= f.label :description, t('addressbook.group.description') %>
19
+ <%= f.text_field :description %>
20
+ </div>
21
+
22
+ <div class="form-actions">
23
+ <%= f.submit t('addressbook.actions.save') %>
24
+ </div>
25
+ <% end %>
@@ -0,0 +1 @@
1
+ $('.addressbook-group[data-id="<%= @group.id %>"]').fadeOut().remove();
@@ -0,0 +1,3 @@
1
+ <h1>Edit Group</h1>
2
+
3
+ <%= render 'form' %>
@@ -0,0 +1,29 @@
1
+ <%= link_to t('addressbook.group.new_group'), new_group_path %>
2
+
3
+ <% unless @groups.blank? %>
4
+ <table class="table table-striped table-bordered table-condensed">
5
+ <thead>
6
+ <th><%= t('addressbook.group.name') %></th>
7
+ <th><%= t('addressbook.group.description') %></th>
8
+ <th><%= t('addressbook.group.contacts_count') %></th>
9
+ <th><%= t('addressbook.group.created_at') %></th>
10
+ <th></th>
11
+ </thead>
12
+ <tbody>
13
+ <% @groups.each do |group| %>
14
+ <tr class="addressbook-group" data-id='<%= group.id %>'>
15
+ <td><%= group.name %></td>
16
+ <td><%= group.description %></td>
17
+ <td><%= group.contacts_count %></td>
18
+ <td><%= Time.parse(group.created_at) %></td>
19
+ <td>
20
+ <%= link_to t('addressbook.actions.edit'), edit_group_path(group.id) %> |
21
+ <%= link_to t('addressbook.actions.delete'), group_path(group.id), method: :delete, remote: true, data: { confirm: t('addressbook.group.delete_confirm') } %>
22
+ </td>
23
+ </tr>
24
+ <%end%>
25
+ </tbody>
26
+ </table>
27
+ <% else %>
28
+ <p><%= t('addressbook.group.no_groups') %></p>
29
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <h1>New Group</h1>
2
+
3
+ <%= render 'form' %>
@@ -0,0 +1,24 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Addressbook</title>
5
+ <%= stylesheet_link_tag "addressbook/application", :media => "all" %>
6
+ <%= javascript_include_tag "addressbook/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <div id="addressbook_container">
12
+ <% unless flash.blank? %>
13
+ <% flash.each do |type, message| %>
14
+ <div class="alert alert-#{type}">
15
+ <%= message %>
16
+ </div>
17
+ <% end %>
18
+ <% end %>
19
+
20
+ <%= yield %>
21
+ </div>
22
+
23
+ </body>
24
+ </html>
@@ -0,0 +1 @@
1
+ Addressbook.user_class = 'Account'
@@ -0,0 +1,73 @@
1
+ en:
2
+ addressbook:
3
+ actions:
4
+ create: Create
5
+ save: Save
6
+ edit: Edit
7
+ delete: Delete
8
+ add: Add
9
+ search: Search
10
+ contact:
11
+ new_contact: New contact
12
+ query: Query
13
+ query_placeholder: Enter name, email or phone number
14
+ name: Name
15
+ photo: Photo
16
+ group: Group
17
+ company_address: Company, Address
18
+ contact_methods: Contact Methods
19
+ status: Status
20
+ created_at: Created at
21
+ delete_confirm: Are you sure?
22
+ no_contacts: No contacts.
23
+ first_name: First Name
24
+ last_name: Last Name
25
+ nickname: Nickname
26
+ gender: Gender
27
+ company: Company
28
+ homepage: Homepage
29
+ dob: Birthday
30
+ create_notice: Contact was saved successfully.
31
+ update_notice: Contact was updated successfully.
32
+ import_notice:
33
+ zero: There is no contact to import
34
+ one: Imported 1 contact successfully.
35
+ other: 'Imported %{count} contact successfully.'
36
+ invalid_vcard: Please select valid VCard file.
37
+ invalid_csv: Please select valid CSV file.
38
+ email: Email
39
+ preferred: Preferred
40
+ address: Address
41
+ line1: Line 1
42
+ line2: Line 2
43
+ line3: Line 3
44
+ zipcode: Zipcode
45
+ city: City
46
+ state: State
47
+ country: Country
48
+ add_email: Add email
49
+ remove_email: Remove email
50
+ add_address: Add address
51
+ remove_address: Remove address
52
+ add_phone: Add phone
53
+ remove_phone: Remove phone
54
+ phone: Phone
55
+ number: Number
56
+ phone_type: Phone type
57
+ total: Total
58
+ import_vcard: Import VCard
59
+ error_explanation:
60
+ one: '1 error prohibited this contact from being saved:'
61
+ other: '%{count} errors prohibited this contact from being saved:'
62
+ group:
63
+ name: Name
64
+ description: Description
65
+ contacts_count: Contacts
66
+ new_group: New group
67
+ no_groups: You have no groups yet.
68
+ create_notice: Group was saved successfully.
69
+ update_notice: Group was updated successfully.
70
+ delete_confirm: Are you sure?
71
+ error_explanation:
72
+ one: '1 error prohibited this group from being saved:'
73
+ other: '%{count} errors prohibited this group from being saved:'
@@ -0,0 +1,10 @@
1
+ Addressbook::Engine.routes.draw do
2
+ root to: "contacts#index"
3
+ resources :contacts, except: [:show] do
4
+ collection do
5
+ post :import_vcard
6
+ post :import_csv
7
+ end
8
+ end
9
+ resources :groups, except: [:show]
10
+ end
@@ -0,0 +1,11 @@
1
+ class AddAddressbookAccountIdToUserTable < ActiveRecord::Migration
2
+ def self.up
3
+ add_column Addressbook.user_class.tableize, :addressbook_account_id, :integer
4
+ add_index Addressbook.user_class.tableize, :addressbook_account_id
5
+ end
6
+
7
+ def self.down
8
+ remove_index Addressbook.user_class.tableize, :addressbook_account_id
9
+ remove_column Addressbook.user_class.tableize, :addressbook_account_id
10
+ end
11
+ end
@@ -0,0 +1,23 @@
1
+ require "addressbook/engine"
2
+ require 'carrierwave'
3
+ require 'fog'
4
+ require 'mini_magick'
5
+ require 'kaminari'
6
+ require 'jquery-rails'
7
+ require "addressbook/base_uploader"
8
+ require "addressbook/import_file_uploader"
9
+ require "addressbook/photo_uploader"
10
+ require "addressbook/resource"
11
+ require "addressbook/contact"
12
+ require "addressbook/group"
13
+ require "addressbook/account"
14
+
15
+
16
+ module Addressbook
17
+
18
+ mattr_accessor :user_class, :aws_config
19
+
20
+ def self.configure &block
21
+ yield
22
+ end
23
+ end
@@ -0,0 +1,27 @@
1
+ module Addressbook
2
+ class Account < Resource
3
+
4
+ has_many :contacts, class_name: 'Addressbook::Contact'
5
+ has_many :groups, class_name: 'Addressbook::Group'
6
+
7
+ validates_presence_of :email
8
+
9
+ alias_method :original_contacts, :contacts
10
+ alias_method :original_groups, :groups
11
+
12
+ def contacts
13
+ original_contacts.extend Addressbook::Contact::RelationExtensions
14
+ original_contacts
15
+ end
16
+
17
+ def groups
18
+ original_groups.extend Addressbook::Group::RelationExtensions
19
+ original_groups
20
+ end
21
+
22
+ schema do
23
+ attribute 'email', :string
24
+ attribute 'name', :string
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ module Addressbook
4
+ class BaseUploader < CarrierWave::Uploader::Base
5
+ if Rails.env.test? or Rails.env.cucumber?# or (Rails.env.development? and Figaro.env.host == 'localhost:3000')
6
+ storage :file
7
+ else
8
+ storage :fog
9
+ end
10
+
11
+ def initialize(*)
12
+ super
13
+
14
+ unless Rails.env.test?
15
+ self.fog_credentials = {
16
+ provider: 'AWS',
17
+ aws_access_key_id: Addressbook.aws_config['access_key_id'],
18
+ aws_secret_access_key: Addressbook.aws_config['secret_access_key'],
19
+ region: 'eu-west-1'
20
+ }
21
+ self.fog_directory = Addressbook.aws_config['bucket']
22
+ end
23
+ end
24
+
25
+ def store_dir
26
+ "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.token}"
27
+ end
28
+
29
+ def cache_dir
30
+ "tmp/uploads"
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,128 @@
1
+ require 'active_resource_response'
2
+
3
+ module Addressbook
4
+ class Contact < Resource
5
+ extend CarrierWave::Mount
6
+
7
+ self.element_name = "contact"
8
+ add_response_method :http_response
9
+
10
+ GENDER = %w(male female)
11
+
12
+ mount_uploader :photo, PhotoUploader
13
+
14
+ module RelationExtensions
15
+ def new(params = {})
16
+ params.merge!(original_params)
17
+ resource_class.new(params)
18
+ end
19
+
20
+ def count
21
+ http_response['X-total'].to_i
22
+ end
23
+ end
24
+
25
+ def self.search(query = {})
26
+ self.find(:all, params: query)
27
+ end
28
+
29
+ def self.import_vcard(account, vcard)
30
+ uploader = ImportFileUploader.new
31
+ File.open(vcard.tempfile) { |file| uploader.store!(file) }
32
+ Addressbook::Contact.get :import_vcard, { account_id: account.id, filename: uploader.filename }
33
+ end
34
+
35
+ def self.import_csv(account, csv)
36
+ uploader = ImportFileUploader.new
37
+ File.open(csv.tempfile) { |file| uploader.store!(file) }
38
+ Addressbook::Contact.get :import_csv, { account_id: account.id, filename: uploader.filename }
39
+ end
40
+
41
+ def full_name
42
+ [first_name, last_name].reject(&:blank?).join(' ')
43
+ end
44
+
45
+ def active?
46
+ status == 'active'
47
+ end
48
+
49
+ schema do
50
+ attribute 'first_name', :string
51
+ attribute 'last_name', :string
52
+ attribute 'nickname', :string
53
+ attribute 'title', :string
54
+ attribute 'gender', :string
55
+ attribute 'company', :string
56
+ attribute 'homepage', :string
57
+ attribute 'dob', :string
58
+ attribute 'group_ids', :string
59
+ attribute 'token', :string
60
+ attribute 'status', :integer
61
+ attribute 'photo_file_name', :string
62
+ end
63
+
64
+ class Nested < Resource
65
+ def initialize(attributes={}, persisted=false)
66
+ @attributes = attributes.present? ? attributes.stringify_keys : default_attributes
67
+ end
68
+ end
69
+
70
+ class Email < Nested
71
+
72
+ schema do
73
+ attribute 'email', :string
74
+ attribute 'preferred', :boolean
75
+ end
76
+
77
+ private
78
+
79
+ def default_attributes
80
+ { email: nil, preferred: false }
81
+ end
82
+ end
83
+
84
+ class Address < Nested
85
+
86
+ def full_address
87
+ [line1, line2, line3].reject(&:blank?).join(' ')
88
+ end
89
+
90
+ def location
91
+ [zipcode, city, state].reject(&:blank?).join(' ')
92
+ end
93
+
94
+ schema do
95
+ attribute 'line1', :string
96
+ attribute 'line2', :string
97
+ attribute 'line3', :string
98
+ attribute 'zipcode', :string
99
+ attribute 'city', :string
100
+ attribute 'state', :string
101
+ attribute 'country', :string
102
+ end
103
+
104
+ private
105
+
106
+ def default_attributes
107
+ { line1: nil, line2: nil, line3: nil, zipcode: nil, city: nil, state: nil, country: nil }
108
+ end
109
+ end
110
+
111
+ class Phone < Nested
112
+
113
+ TYPES = %w(mobile home iPhone cell work other)
114
+
115
+ schema do
116
+ attribute 'number', :string
117
+ attribute 'phone_type', :string
118
+ attribute 'preferred', :boolean
119
+ end
120
+
121
+ private
122
+
123
+ def default_attributes
124
+ { number: nil, phone_type: nil, preferred: false }
125
+ end
126
+ end
127
+ end
128
+ end