addressbook 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
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