contact_sync 0.2.1

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 (73) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +3 -0
  4. data/Rakefile +37 -0
  5. data/app/assets/javascripts/con_sync/api/users_sync.js +2 -0
  6. data/app/assets/javascripts/con_sync/application.js +13 -0
  7. data/app/assets/stylesheets/con_sync/api/users_sync.css +4 -0
  8. data/app/assets/stylesheets/con_sync/application.css +15 -0
  9. data/app/controllers/con_sync/api/users_sync_controller.rb +27 -0
  10. data/app/controllers/con_sync/application_controller.rb +4 -0
  11. data/app/helpers/con_sync/api/users_sync_helper.rb +4 -0
  12. data/app/helpers/con_sync/application_helper.rb +4 -0
  13. data/app/models/address.rb +5 -0
  14. data/app/models/contact.rb +72 -0
  15. data/app/models/email.rb +5 -0
  16. data/app/models/phone.rb +38 -0
  17. data/app/models/user.rb +3 -0
  18. data/app/views/layouts/con_sync/application.html.erb +14 -0
  19. data/config/routes.rb +0 -0
  20. data/db/global_phone.json +6648 -0
  21. data/lib/contact_sync.rb +12 -0
  22. data/lib/contact_sync/acts_as_syncable.rb +7 -0
  23. data/lib/contact_sync/engine.rb +5 -0
  24. data/lib/contact_sync/syncable.rb +124 -0
  25. data/lib/contact_sync/util/api_constraints.rb +10 -0
  26. data/lib/contact_sync/util/global_phone.rb +3 -0
  27. data/lib/contact_sync/util/string_phone.rb +28 -0
  28. data/lib/contact_sync/version.rb +3 -0
  29. data/lib/generators/install_contact_sync/USAGE +8 -0
  30. data/lib/generators/install_contact_sync/install_contact_sync_generator.rb +33 -0
  31. data/lib/generators/install_contact_sync/templates/create_contact_sync_schema.rb +70 -0
  32. data/lib/generators/install_contact_sync/templates/routes.rb +9 -0
  33. data/lib/tasks/con_sync_tasks.rake +4 -0
  34. data/test/con_sync_test.rb +7 -0
  35. data/test/controllers/con_sync/api/users_sync_controller_test.rb +9 -0
  36. data/test/dummy/README.rdoc +28 -0
  37. data/test/dummy/Rakefile +6 -0
  38. data/test/dummy/app/assets/javascripts/application.js +13 -0
  39. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  40. data/test/dummy/app/controllers/application_controller.rb +5 -0
  41. data/test/dummy/app/helpers/application_helper.rb +2 -0
  42. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  43. data/test/dummy/bin/bundle +3 -0
  44. data/test/dummy/bin/rails +4 -0
  45. data/test/dummy/bin/rake +4 -0
  46. data/test/dummy/bin/setup +29 -0
  47. data/test/dummy/config.ru +4 -0
  48. data/test/dummy/config/application.rb +26 -0
  49. data/test/dummy/config/boot.rb +5 -0
  50. data/test/dummy/config/database.yml +25 -0
  51. data/test/dummy/config/environment.rb +5 -0
  52. data/test/dummy/config/environments/development.rb +41 -0
  53. data/test/dummy/config/environments/production.rb +79 -0
  54. data/test/dummy/config/environments/test.rb +42 -0
  55. data/test/dummy/config/initializers/assets.rb +11 -0
  56. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  57. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  58. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  59. data/test/dummy/config/initializers/inflections.rb +16 -0
  60. data/test/dummy/config/initializers/mime_types.rb +4 -0
  61. data/test/dummy/config/initializers/session_store.rb +3 -0
  62. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  63. data/test/dummy/config/locales/en.yml +23 -0
  64. data/test/dummy/config/routes.rb +4 -0
  65. data/test/dummy/config/secrets.yml +22 -0
  66. data/test/dummy/public/404.html +67 -0
  67. data/test/dummy/public/422.html +67 -0
  68. data/test/dummy/public/500.html +66 -0
  69. data/test/dummy/public/favicon.ico +0 -0
  70. data/test/integration/navigation_test.rb +10 -0
  71. data/test/lib/generators/con_sync/install_con_sync_generator_test.rb +16 -0
  72. data/test/test_helper.rb +20 -0
  73. metadata +210 -0
@@ -0,0 +1,12 @@
1
+ require "contact_sync/engine"
2
+ require 'contact_sync/util/api_constraints'
3
+ require 'contact_sync/util/string_phone'
4
+ require 'contact_sync/util/global_phone'
5
+ require 'contact_sync/acts_as_syncable'
6
+ require 'contact_sync/syncable'
7
+ require 'encrypted_strings'
8
+
9
+ module ContactSync
10
+ end
11
+
12
+ ActiveRecord::Base.send :extend, ContactSync::ActsAsSyncable
@@ -0,0 +1,7 @@
1
+ module ContactSync
2
+ module ActsAsSyncable
3
+ def acts_as_syncable
4
+ include ContactSync::Syncable
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ module ContactSync
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace ContactSync
4
+ end
5
+ end
@@ -0,0 +1,124 @@
1
+ module ContactSync
2
+ module Syncable
3
+ def phone_number
4
+ return self.encrypted_number.try(:decrypt,:symmetric) || ""
5
+ end
6
+
7
+ def phone_number=(string)
8
+ self.cc_prefix, num = string.extract_country_code
9
+ self.encrypted_number = num.encrypt(:symmetric)
10
+ self.encrypted_number
11
+ end
12
+
13
+ def complete_phone_number
14
+ if self.cc_prefix.blank?
15
+ "00#{self.phone_number}"
16
+ else
17
+ "+#{self.cc_prefix}#{self.phone_number}"
18
+ end
19
+ end
20
+ def sync_contacts(contact_hash = {})
21
+ result = {:new => {success:[], failed:[]}, modified: {success:[], failed:[]}, deleted: {success:[], failed:[]}}
22
+ raise ArgumentError, "You need to provide contacts hash." if contact_hash.blank?
23
+
24
+ ##########################################################################
25
+ #########################Create new Contacts##############################
26
+ if !contact_hash[:new].blank?
27
+ contacts = contact_hash[:new]
28
+ contacts.each do |aContact|
29
+ phones = aContact[:phones]
30
+ emails = aContact[:emails]
31
+
32
+ aContact.delete :phones
33
+ aContact.delete :emails
34
+
35
+ newContact = Contact.new(contact_params(aContact))
36
+ if phones
37
+ phones.each do |aPhone|
38
+ newContact.phones.build(phone_params(aPhone))
39
+ end
40
+ end
41
+ if emails
42
+ emails.each do |anEmail|
43
+ newContact.emails.build(email_params(anEmail))
44
+ end
45
+ end
46
+ if newContact.save
47
+ # result[:new][:success] << newContact.record_id
48
+ self.contacts << newContact
49
+ else
50
+ result[:new][:failed] << newContact.record_id
51
+ end
52
+ end
53
+ end
54
+ ##########################################################################
55
+ ########################Modify Contacts###################################
56
+ if !contact_hash[:modified].blank?
57
+ modified_contacts = contact_hash[:modified]
58
+ modified_contacts.each do |con|
59
+ theContact = self.contacts.find_by_record_id(con[:record_id])
60
+ if ! theContact.blank?
61
+ if !theContact.update_attributes(contact_params(con))
62
+ result[:modified][:failed] << theContact.record_id
63
+ puts "Error Updating Contact."
64
+ else
65
+ # result[:modified][:success] << theContact.record_id
66
+ end
67
+ end
68
+ end
69
+ end
70
+ ##########################################################################
71
+ ########################Delete Contacts###################################
72
+ if !contact_hash[:deleted].blank?
73
+ delete_contacts = contact_hash[:deleted]
74
+ delete_contacts.each do |con|
75
+ if self.contacts.find_by_record_id(con[:record_id].to_i).destroy
76
+ # result[:deleted][:success] << con[:record_id]
77
+ else
78
+ result[:deleted][:failed] << con[:record_id]
79
+ end
80
+ end
81
+ end
82
+ after_contact_sync
83
+ self.save
84
+ return result
85
+ end
86
+
87
+ def matched_contacts
88
+ matched_contacts = []
89
+ user_phones = []
90
+ user_emails = []
91
+ self.contacts.each do |con|
92
+ user_phones.concat con.phones
93
+ user_emails.concat con.emails
94
+ end
95
+
96
+ user_phones.each do |phone|
97
+ u = User.where(phone_number: phone.number.encrypt(:symmetric)).limit(1).first
98
+ matched_contacts << u unless u.blank?
99
+ end
100
+ user_emails.each do |mail|
101
+ u = User.where(email: mail.email).limit(1).first
102
+ matched_contacts << u unless u.blank?
103
+ end
104
+ return matched_contacts
105
+ end
106
+
107
+ private
108
+ def contact_params(aContact)
109
+ aContact.permit(:composite_name, :first_name, :middle_name, :last_name, :prefix, :suffix, :nickname, :job_title, :department, :organization, :birthdate, :note, :creation_date, :modification_date, :record_id)
110
+ end
111
+
112
+ def phone_params aPhone
113
+ aPhone.permit(:label, :number)
114
+ end
115
+
116
+ def email_params anEmail
117
+ anEmail.permit(:label, :email)
118
+ end
119
+
120
+ def after_contact_sync
121
+ self.last_contact_sync = DateTime.now.utc
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,10 @@
1
+ class ApiConstraints
2
+ def initialize(options)
3
+ @version = options[:version]
4
+ @default = options[:default]
5
+ end
6
+
7
+ def matches?(req)
8
+ @default || req.headers['Accept'].include?("application/vnd.kanari.v#{@version}")
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ require 'global_phone'
2
+ puts "\n\n\n\n\n\n\n\n\n\n\n#{ContactSync::Engine.root}\n\n\n\n\n\n\n\n"
3
+ GlobalPhone.db_path = ContactSync::Engine.root.join('db/global_phone.json')
@@ -0,0 +1,28 @@
1
+ require 'active_support/concern'
2
+
3
+ module ContactSync
4
+ module StringPhone
5
+ # extend ActiveSupport::Concern
6
+ def extract_country_code
7
+ string = self
8
+ if string[0..1] == "00"
9
+ string[0..1] = "+"
10
+ end
11
+ if string[0] == "+"
12
+ breakdown = GlobalPhone.parse(string)
13
+ prefix = breakdown.country_code
14
+ num = breakdown.national_string
15
+ return [prefix,num]
16
+ elsif string[0] == "0"
17
+ num = string[1..-1]
18
+ prefix = "0"
19
+ return [prefix, num]
20
+ else
21
+ return ["", string]
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ puts "Including StringPhoner Module to: '#{String.name}' class"
28
+ String.send(:include, ContactSync::StringPhone)
@@ -0,0 +1,3 @@
1
+ module ContactSync
2
+ VERSION = "0.2.1"
3
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Explain the generator
3
+
4
+ Example:
5
+ rails generate install_contact_sync Thing
6
+
7
+ This will create:
8
+ what/will/it/create
@@ -0,0 +1,33 @@
1
+ require 'rails/generators/active_record'
2
+
3
+ class InstallContactSyncGenerator < Rails::Generators::Base
4
+ include Rails::Generators::Migration
5
+
6
+ def self.next_migration_number(path)
7
+ ActiveRecord::Generators::Base.next_migration_number(path)
8
+ end
9
+
10
+ source_root File.expand_path('../templates', __FILE__)
11
+
12
+ def generate_migration
13
+ migration_template "create_contact_sync_schema.rb", "db/migrate/create_contact_sync_schema.rb"
14
+ end
15
+
16
+ def generate_routes
17
+ route(File.read(File.join(File.dirname(__FILE__), 'templates/routes.rb') ))
18
+ end
19
+
20
+ # def generate_global_phone_db
21
+ # copy_file "global_phone.json", "db/global_phone.json"
22
+ # end
23
+
24
+ def generate_encrypted_strings_config
25
+ inject_into_file 'config/environments/development.rb', before: "end\n" do <<-'RUBY'
26
+
27
+ EncryptedStrings::SymmetricCipher.default_algorithm = 'aes-256-cbc'
28
+ EncryptedStrings::SymmetricCipher.default_password = 'Replace This with some long alphanumeric string'
29
+
30
+ RUBY
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,70 @@
1
+ class CreateContactSyncSchema < ActiveRecord::Migration
2
+ def up
3
+ create_table :contacts do |t|
4
+ t.string :composite_name
5
+ t.string :first_name
6
+ t.string :middle_name
7
+ t.string :last_name
8
+ t.string :prefix
9
+ t.string :suffix
10
+ t.string :nickname
11
+ t.string :organization
12
+ t.string :job_title
13
+ t.string :department
14
+ t.date :birthdate
15
+ t.text :note
16
+ t.string :device_id
17
+ t.integer :record_id, default: 0
18
+ t.datetime :creation_date
19
+ t.datetime :modification_date
20
+ t.integer :user_id
21
+ t.timestamps
22
+ end
23
+
24
+ create_table :phones do |t|
25
+ t.string :label
26
+ t.string :encrypted_number
27
+ t.string :cc_prefix
28
+ t.string :extension
29
+ t.integer :contact_id
30
+
31
+ t.timestamps
32
+ end
33
+
34
+ create_table :emails do |t|
35
+ t.string :label
36
+ t.string :encrypted_email
37
+ t.integer :contact_id
38
+
39
+ t.timestamps
40
+ end
41
+
42
+ if table_exists? :users
43
+ add_column :users, :last_contact_sync, :datetime
44
+ add_column :users, :encrypted_number, :string
45
+ add_column :users, :cc_prefix, :string
46
+ add_index :users, :encrypted_number
47
+ else
48
+ create_table :users do |t|
49
+ t.string :first_name
50
+ t.string :middle_name
51
+ t.string :last_name
52
+ t.string :email
53
+ t.string :encrypted_number
54
+ t.string :cc_prefix
55
+ t.datetime :last_contact_sync
56
+ end
57
+ add_index :users, :encrypted_number
58
+ end
59
+
60
+ add_index :contacts, [:record_id, :device_id], name: "unique_device_contact", unique: true
61
+ add_index :contacts, :user_id
62
+ add_index :phones, :encrypted_number
63
+ add_index :emails, :encrypted_email
64
+
65
+ end
66
+
67
+ def down
68
+
69
+ end
70
+ end
@@ -0,0 +1,9 @@
1
+
2
+ namespace :api do
3
+ scope module: :v1, constraints: ApiConstraints.new(version: 1, default: :true) do
4
+ resources :users, only: [] do
5
+ post :sync_contacts
6
+ get :match_contacts
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :contact_sync do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class ContactSyncTest < ActiveSupport::TestCase
4
+ test "truth" do
5
+ assert_kind_of Module, ContactSync
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ require 'test_helper'
2
+
3
+ module ContactSync
4
+ class Api::UsersSyncControllerTest < ActionController::TestCase
5
+ # test "the truth" do
6
+ # assert true
7
+ # end
8
+ end
9
+ end
@@ -0,0 +1,28 @@
1
+ == README
2
+
3
+ This README would normally document whatever steps are necessary to get the
4
+ application up and running.
5
+
6
+ Things you may want to cover:
7
+
8
+ * Ruby version
9
+
10
+ * System dependencies
11
+
12
+ * Configuration
13
+
14
+ * Database creation
15
+
16
+ * Database initialization
17
+
18
+ * How to run the test suite
19
+
20
+ * Services (job queues, cache servers, search engines, etc.)
21
+
22
+ * Deployment instructions
23
+
24
+ * ...
25
+
26
+
27
+ Please feel free to use a different markup language if you do not plan to run
28
+ <tt>rake doc:app</tt>.
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require File.expand_path('../config/application', __FILE__)
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,5 @@
1
+ class ApplicationController < ActionController::Base
2
+ # Prevent CSRF attacks by raising an exception.
3
+ # For APIs, you may want to use :null_session instead.
4
+ protect_from_forgery with: :exception
5
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Dummy</title>
5
+ <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
6
+ <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>