has_vcards 0.20.3 → 1.0.0.rc0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. data/MIT-LICENSE +4 -1
  2. data/README.md +18 -0
  3. data/Rakefile +28 -0
  4. data/app/assets/javascripts/has_vcards/application.js +13 -0
  5. data/app/assets/stylesheets/has_vcards/application.css +15 -0
  6. data/app/controllers/has_vcards/directory_lookup_controller.rb +21 -0
  7. data/app/controllers/has_vcards/phone_numbers_controller.rb +16 -0
  8. data/app/controllers/has_vcards/vcards_controller.rb +22 -0
  9. data/app/helpers/has_vcards/application_helper.rb +18 -0
  10. data/app/input/has_vcards/zip_locality_input.rb +16 -0
  11. data/app/models/has_vcards/address.rb +42 -0
  12. data/app/models/has_vcards/concerns/has_vcards.rb +42 -0
  13. data/app/models/has_vcards/phone_number.rb +61 -0
  14. data/app/models/has_vcards/vcard.rb +123 -0
  15. data/app/models/has_vcards/vcard/directory_address.rb +25 -0
  16. data/app/models/has_vcards/vcard/directory_lookup.rb +123 -0
  17. data/app/views/has_vcards/layouts/has_vcards/application.html.erb +14 -0
  18. data/app/views/{people → has_vcards/people}/_address_form.html.haml +1 -1
  19. data/app/views/{phone_numbers → has_vcards/phone_numbers}/_form.html.haml +0 -0
  20. data/app/views/{phone_numbers → has_vcards/phone_numbers}/_list.html.haml +0 -0
  21. data/app/views/{phone_numbers → has_vcards/phone_numbers}/_nested_form.html.haml +0 -0
  22. data/app/views/{phone_numbers → has_vcards/phone_numbers}/_phone_number.html.haml +0 -0
  23. data/app/views/{vcards → has_vcards/vcards}/_address.html.haml +0 -0
  24. data/app/views/{vcards → has_vcards/vcards}/_directory_lookup.html.haml +0 -0
  25. data/app/views/{vcards → has_vcards/vcards}/_directory_matches.html.haml +0 -0
  26. data/app/views/{vcards → has_vcards/vcards}/_form.html.haml +1 -1
  27. data/app/views/{vcards → has_vcards/vcards}/_show.html.haml +1 -1
  28. data/app/views/{vcards → has_vcards/vcards}/directory_lookup.js.erb +0 -0
  29. data/config/locales/de.yml +11 -18
  30. data/config/locales/en.yml +21 -6
  31. data/config/locales/fr.yml +6 -18
  32. data/config/routes.rb +1 -1
  33. data/db/migrate/20121113120000_create_honorific_prefixes_table.rb +1 -1
  34. data/db/migrate/20140617113710_rename_tables_for_namespacing.rb +8 -0
  35. data/db/migrate/20140619101337_remove_object_from_phone_number.rb +6 -0
  36. data/db/migrate/20140619102041_rename_vcard_object_to_reference.rb +6 -0
  37. data/db/migrate/20140619121756_refactor_honorific_prefix.rb +5 -0
  38. data/lib/has_vcards.rb +5 -18
  39. data/lib/has_vcards/engine.rb +29 -0
  40. data/lib/has_vcards/version.rb +4 -1
  41. data/spec/controllers/has_vcards/phone_numbers_controller_spec.rb +42 -0
  42. data/spec/controllers/has_vcards/vcards_controller_spec.rb +42 -0
  43. data/spec/dummy/README.rdoc +28 -0
  44. data/spec/dummy/Rakefile +6 -0
  45. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  46. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  47. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  48. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  49. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  50. data/spec/dummy/bin/bundle +3 -0
  51. data/spec/dummy/bin/rails +4 -0
  52. data/spec/dummy/bin/rake +4 -0
  53. data/spec/dummy/config.ru +4 -0
  54. data/spec/dummy/config/application.rb +29 -0
  55. data/spec/dummy/config/boot.rb +5 -0
  56. data/spec/dummy/config/database.yml +37 -0
  57. data/spec/dummy/config/environment.rb +5 -0
  58. data/spec/dummy/config/environments/development.rb +37 -0
  59. data/spec/dummy/config/environments/production.rb +83 -0
  60. data/spec/dummy/config/environments/test.rb +39 -0
  61. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  62. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  63. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  64. data/spec/dummy/config/initializers/inflections.rb +16 -0
  65. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  66. data/spec/dummy/config/initializers/session_store.rb +3 -0
  67. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  68. data/spec/dummy/config/locales/en.yml +23 -0
  69. data/spec/dummy/config/routes.rb +4 -0
  70. data/spec/dummy/config/secrets.yml +22 -0
  71. data/spec/dummy/db/development.sqlite3 +0 -0
  72. data/spec/dummy/db/migrate/20140620151641_create_somethings.rb +7 -0
  73. data/spec/dummy/db/schema.rb +66 -0
  74. data/spec/dummy/db/test.sqlite3 +0 -0
  75. data/spec/dummy/log/development.log +2513 -0
  76. data/spec/dummy/log/test.log +11671 -0
  77. data/spec/dummy/public/404.html +67 -0
  78. data/spec/dummy/public/422.html +67 -0
  79. data/spec/dummy/public/500.html +66 -0
  80. data/spec/dummy/public/favicon.ico +0 -0
  81. data/spec/factories/addresses.rb +7 -0
  82. data/spec/factories/phone_numbers.rb +7 -0
  83. data/spec/factories/vcards.rb +5 -0
  84. data/spec/models/has_vcards/address_spec.rb +58 -0
  85. data/spec/models/has_vcards/concerns/has_vcards_spec.rb +50 -0
  86. data/spec/models/has_vcards/phone_number_spec.rb +82 -0
  87. data/spec/models/has_vcards/vcard_spec.rb +172 -0
  88. data/spec/rails_helper.rb +18 -0
  89. data/spec/spec_helper.rb +74 -0
  90. metadata +262 -47
  91. data/README.markdown +0 -14
  92. data/app/controllers/directory_lookup_controller.rb +0 -17
  93. data/app/controllers/phone_numbers_controller.rb +0 -14
  94. data/app/controllers/vcards_controller.rb +0 -20
  95. data/app/helpers/has_vcards_helper.rb +0 -13
  96. data/app/input/zip_locality_input.rb +0 -14
  97. data/app/models/address.rb +0 -40
  98. data/app/models/honorific_prefix.rb +0 -6
  99. data/app/models/phone_number.rb +0 -43
  100. data/app/models/vcard.rb +0 -112
  101. data/app/models/vcard/directory_address.rb +0 -21
  102. data/app/models/vcard/directory_lookup.rb +0 -122
  103. data/config/application.rb +0 -19
  104. data/config/boot.rb +0 -6
  105. data/lib/has_vcards/railtie.rb +0 -19
@@ -0,0 +1,25 @@
1
+ module HasVcards
2
+ class Vcard
3
+ module DirectoryAddress
4
+ def to_vcard
5
+ Vcard.new(
6
+ given_name: first_name,
7
+ family_name: family_name,
8
+ street_address: street,
9
+ postal_code: zip_code,
10
+ locality: city
11
+ )
12
+ end
13
+
14
+ def to_vcard_attributes
15
+ {
16
+ given_name: first_name,
17
+ family_name: family_name,
18
+ street_address: street,
19
+ postal_code: zip_code,
20
+ locality: city
21
+ }
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,123 @@
1
+ module HasVcards
2
+ module Vcard::DirectoryLookup
3
+ def map_for_directory
4
+ search = {}
5
+ search[:first_name] = given_name
6
+ search[:family_name] = family_name
7
+ search[:street] = street_address
8
+ search[:zip_code] = postal_code
9
+ search[:city] = locality
10
+
11
+ search
12
+ end
13
+
14
+ def directory_lookup(ignore_fields = [])
15
+ search = map_for_directory
16
+
17
+ search.reject! { |key, _value| ignore_fields.include? key }
18
+
19
+ # TODO: We should fetch additional pages if the result indicates there
20
+ # are more pages.
21
+ ::SwissMatch.directory_service.addresses(search, per_page: 10)
22
+ end
23
+
24
+ def directory_found?(ignore_fields = [])
25
+ directory_lookup(ignore_fields).present?
26
+ end
27
+
28
+ def normalize(value)
29
+ normalized_value = UnicodeUtils.downcase(value.to_s)
30
+ normalized_value.gsub!(/str\./, 'strasse')
31
+ normalized_value.gsub!(/str([ $])/, 'strasse\1')
32
+
33
+ normalized_value
34
+ end
35
+
36
+ def directory_matches(ignore_lookup_fields = [])
37
+ matches = directory_lookup(ignore_lookup_fields)
38
+ matches.map do |match|
39
+ search = map_for_directory
40
+
41
+ perfect = []
42
+ search.each do |key, value|
43
+ perfect << key if normalize(match.send(key)) == normalize(value)
44
+ end
45
+
46
+ partial = []
47
+ search.each do |key, value|
48
+ partial << key if value.present? && normalize(match.send(key)).include?(normalize(value))
49
+ end
50
+ partial -= perfect
51
+
52
+ bad = search.keys - perfect - partial - ignore_lookup_fields
53
+
54
+ { address: match, perfect: perfect, partial: partial, bad: bad, ignore: ignore_lookup_fields }
55
+ end
56
+ end
57
+
58
+ def directory_filter(match, filter = {})
59
+ # Exact filters
60
+ filter[:perfect].each do |field|
61
+ return false unless match[:perfect].include?(field)
62
+ end if filter[:perfect]
63
+ filter[:partial].each do |field|
64
+ return false unless match[:partial].include?(field)
65
+ end if filter[:partial]
66
+ filter[:bad].each do |field|
67
+ return false unless match[:bad].include?(field)
68
+ end if filter[:bad]
69
+
70
+ # "Better than" filters
71
+ filter[:partial_or_perfect].each do |field|
72
+ return false unless match[:perfect].include?(field) || match[:partial].include?(field)
73
+ end if filter[:partial_or_perfect]
74
+
75
+ true
76
+ end
77
+
78
+ def filtered_matches(filters)
79
+ ignores = filters.delete(:ignore) || []
80
+
81
+ directory_matches(ignores).map do |match|
82
+ match[:address] if directory_filter(match, filters)
83
+ end.compact
84
+ end
85
+
86
+ # Everything matches
87
+ def perfect_matches
88
+ filtered_matches(perfect: [:family_name, :first_name, :street, :city])
89
+ end
90
+
91
+ def perfect_match?
92
+ perfect_matches.present?
93
+ end
94
+
95
+ # Everything is found, given or family name does is partial match
96
+ def great_matches
97
+ filtered_matches(partial_or_perfect: [:family_name, :first_name], perfect: [:street, :city])
98
+ end
99
+
100
+ def great_match?
101
+ great_matches.present?
102
+ end
103
+
104
+ # Everything but given name matches, family name might be partial
105
+ def family_name_matches
106
+ filtered_matches(ignore: [:first_name], partial_or_perfect: [:family_name], perfect: [:street, :city])
107
+ end
108
+
109
+ def family_name_match?
110
+ family_name_matches.present?
111
+ end
112
+
113
+ # Same address different names
114
+ def address_matches
115
+ filtered_matches(ignore: [:first_name, :family_name], perfect: [:street, :city])
116
+ end
117
+
118
+ # Similar name in same locality
119
+ def locality_matches
120
+ filtered_matches(ignore: [:first_name, :street], partial_or_perfect: [:family_name], perfect: [:city])
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>HasVcards</title>
5
+ <%= stylesheet_link_tag "has_vcards/application", media: "all" %>
6
+ <%= javascript_include_tag "has_vcards/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
@@ -7,7 +7,7 @@
7
7
  %h3= t_model(PhoneNumber)
8
8
  .nested-form.list.contacts
9
9
  = f.fields_for :vcard do |vcard|
10
- - vcard.object.contacts.build_defaults
10
+ - vcard.reference.contacts.build_defaults
11
11
  - vcard.fields_for :contacts do |contact|
12
12
  = render 'phone_numbers/form', :item => contact
13
13
  = link_to [:new_phone_number, resource.persisted? ? resource : controller_name], :remote => true, :class => 'btn' do
@@ -7,7 +7,7 @@
7
7
  .span12= vcard.input :honorific_prefix, :collection => HonorificPrefix.find(:all, :order => 'sex DESC, position').collect { |prefix| prefix.name }
8
8
  .row-fluid
9
9
  .span12
10
- .control-group{:class => "#{'error' if vcard.object.errors.include?(:family_name) or vcard.object.errors.include?(:given_name)}"}
10
+ .control-group{:class => "#{'error' if vcard.reference.errors.include?(:family_name) or vcard.reference.errors.include?(:given_name)}"}
11
11
  %label.control-label= "#{t_attr(:family_name, Vcard)}, #{t_attr(:given_name, Vcard)}"
12
12
  .controls
13
13
  = vcard.input :family_name, :wrapper => :inline, :input_html => {'data-autofocus' => true}
@@ -1,5 +1,5 @@
1
1
  - vcard = vcard if defined?(vcard)
2
- - vcard ||= object.try(:vcard) if defined?(object)
2
+ - vcard ||= reference.try(:vcard) if defined?(reference)
3
3
  - vcard ||= @vcard
4
4
  - vcard ||= resource.try(:vcard) if defined?(resource)
5
5
  = show_for vcard do |vcard|
@@ -18,12 +18,12 @@ de:
18
18
 
19
19
  activerecord:
20
20
  models:
21
- vcard: Kontakt
22
- address: Adresse
23
- phone_number: Kontakt
21
+ has_vcards/vcard: Kontakt
22
+ has_vcards/address: Adresse
23
+ has_vcards/phone_number: Kontakt
24
24
 
25
25
  attributes:
26
- vcard:
26
+ has_vcards/vcard:
27
27
  full_name: Name
28
28
  nickname: Spitzname
29
29
  family_name: Nachname
@@ -44,7 +44,7 @@ de:
44
44
  phone_number: Telefon
45
45
  mobile_number: Mobile
46
46
  fax_number: Fax
47
- address:
47
+ has_vcards/address:
48
48
  post_office_box: Postfach
49
49
  extended_address: Adresszusatz
50
50
  street_address: Strasse
@@ -53,9 +53,14 @@ de:
53
53
  postal_code: PLZ
54
54
  country_name: Land
55
55
  address_type: Art
56
- phone_number:
56
+ has_vcards/phone_number:
57
57
  number: Nummer
58
58
  phone_number_type: Nummer-Typ
59
+ phone_number_type_enum:
60
+ phone: Tel
61
+ fax: Fax
62
+ mobile: Mob
63
+ email: Mail
59
64
 
60
65
  formtastic:
61
66
  labels:
@@ -77,15 +82,3 @@ de:
77
82
  family_name: Anderer Vorname
78
83
  address: An dieser Adresse
79
84
  locality: In diesem Ort
80
-
81
- # Honorific Prefixes
82
- salutation:
83
- 'Herr Dr. med.': Sehr geehrter Herr Dr. %{family_name}
84
- 'Frau Dr. med.': Sehr geehrte Frau Dr. %{family_name}
85
- 'Herr Dr.': Sehr geehrter Herr Dr. %{family_name}
86
- 'Frau Dr.': Sehr geehrte Frau Dr. %{family_name}
87
- 'Herr': Sehr geehrter Herr %{family_name}
88
- 'Frau': Sehr geehrte Frau %{family_name}
89
- 'Br.': Sehr geehrter Bruder %{family_name}
90
- 'Sr.': Sehr geehrte Schwester %{family_name}
91
- default: Sehr geehrte Damen und Herren
@@ -6,12 +6,12 @@ en:
6
6
 
7
7
  activerecord:
8
8
  models:
9
- vcard: VCard
10
- address: Address
11
- phone_number: Contact
9
+ has_vcards/vcard: VCard
10
+ has_vcards/address: Address
11
+ has_vcards/phone_number: Contact
12
12
 
13
13
  attributes:
14
- vcard:
14
+ has_vcards/vcard:
15
15
  full_name: Name
16
16
  nickname: Nickname
17
17
  family_name: Family name
@@ -32,7 +32,7 @@ en:
32
32
  phone_number: Phone
33
33
  mobile_number: Mobile
34
34
  fax_number: Fax
35
- address:
35
+ has_vcards/address:
36
36
  post_office_box: Post Office Box
37
37
  extended_address: Extended address
38
38
  extended_address: Adresszusatz
@@ -42,9 +42,14 @@ en:
42
42
  postal_code: PLZ
43
43
  country_name: Land
44
44
  address_type: Art
45
- phone_number:
45
+ has_vcards/phone_number:
46
46
  number: Number
47
47
  phone_number_type: Number Type
48
+ phone_number_type_enum:
49
+ phone: Phone
50
+ fax: Fax
51
+ mobile: Mobile
52
+ email: Mail
48
53
 
49
54
  formtastic:
50
55
  labels:
@@ -57,3 +62,13 @@ en:
57
62
  region: Region
58
63
  postal_code: PLZ
59
64
  country_name: Land
65
+
66
+ # DirectoryLookup
67
+ directory_lookup:
68
+ title: Treffer in Telefonbuch
69
+ match_type:
70
+ perfect: Genauer Treffer
71
+ great: Ungenauer Name
72
+ family_name: Anderer Vorname
73
+ address: An dieser Adresse
74
+ locality: In diesem Ort
@@ -18,12 +18,12 @@ fr:
18
18
 
19
19
  activerecord:
20
20
  models:
21
- vcard: Kontakt
22
- address: Adresse
23
- phone_number: Kontakt
21
+ has_vcards/vcard: Kontakt
22
+ has_vcards/address: Adresse
23
+ has_vcards/phone_number: Kontakt
24
24
 
25
25
  attributes:
26
- vcard:
26
+ has_vcards/vcard:
27
27
  full_name: Name
28
28
  nickname: Spitzname
29
29
  family_name: Nachname
@@ -44,7 +44,7 @@ fr:
44
44
  phone_number: Telefon
45
45
  mobile_number: Mobile
46
46
  fax_number: Fax
47
- address:
47
+ has_vcards/address:
48
48
  post_office_box: Postfach
49
49
  extended_address: Adresszusatz
50
50
  street_address: Strasse
@@ -53,7 +53,7 @@ fr:
53
53
  postal_code: PLZ
54
54
  country_name: Land
55
55
  address_type: Art
56
- phone_number:
56
+ has_vcards/phone_number:
57
57
  number: Nummer
58
58
  phone_number_type: Nummer-Typ
59
59
 
@@ -77,15 +77,3 @@ fr:
77
77
  family_name: Anderer Vorname
78
78
  address: An dieser Adresse
79
79
  locality: In diesem Ort
80
-
81
- # Honorific Prefixes
82
- salutation:
83
- 'Herr Dr. med.': Sehr geehrter Herr Dr.
84
- 'Frau Dr. med.': Sehr geehrte Frau Dr.
85
- 'Herr Dr.': Sehr geehrter Herr Dr.
86
- 'Frau Dr.': Sehr geehrte Frau Dr.
87
- 'Herr': Monsieur
88
- 'Frau': Madame
89
- 'Br.': Sehr geehrter Bruder
90
- 'Sr.': Sehr geehrte Schwester
91
- default: Mesdames, Messieurs,
data/config/routes.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # Routes
2
- Rails.application.routes.draw do
2
+ HasVcards::Engine.routes.draw do
3
3
  # Phone Numbers
4
4
  resources :phone_numbers
5
5
 
@@ -1,6 +1,6 @@
1
1
  class CreateHonorificPrefixesTable < ActiveRecord::Migration
2
2
  def up
3
- change_table "honorific_prefixes" do |t|
3
+ create_table "honorific_prefixes" do |t|
4
4
  t.integer "sex"
5
5
  t.string "name"
6
6
  t.integer "position"
@@ -0,0 +1,8 @@
1
+ class RenameTablesForNamespacing < ActiveRecord::Migration
2
+ def change
3
+ rename_table :addresses, :has_vcards_addresses
4
+ rename_table :honorific_prefixes, :has_vcards_honorific_prefixes
5
+ rename_table :phone_numbers, :has_vcards_phone_numbers
6
+ rename_table :vcards, :has_vcards_vcards
7
+ end
8
+ end
@@ -0,0 +1,6 @@
1
+ class RemoveObjectFromPhoneNumber < ActiveRecord::Migration
2
+ def change
3
+ remove_column :has_vcards_phone_numbers, :object_id
4
+ remove_column :has_vcards_phone_numbers, :object_type
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ class RenameVcardObjectToReference < ActiveRecord::Migration
2
+ def change
3
+ rename_column :has_vcards_vcards, :object_id, :reference_id
4
+ rename_column :has_vcards_vcards, :object_type, :reference_type
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ class RefactorHonorificPrefix < ActiveRecord::Migration
2
+ def change
3
+ drop_table :has_vcards_honorific_prefixes
4
+ end
5
+ end
data/lib/has_vcards.rb CHANGED
@@ -1,20 +1,7 @@
1
- require 'has_vcards/railtie' if defined?(::Rails::Railtie)
1
+ require 'has_vcards/engine'
2
2
 
3
- module HasVcardsClassMethods
4
- def has_vcards(options = {})
5
- class_eval <<-end_eval
6
- scope :by_name, lambda {|name| {:include => :vcard, :order => 'vcards.full_name', :conditions => Vcard.by_name_conditions(name)}}
7
-
8
- has_one :vcard, :as => 'object', :autosave => true, :validate => true
9
- delegate :full_name, :nickname, :family_name, :given_name, :additional_name, :honorific_prefix, :honorific_suffix, :to => :vcard
10
- delegate :full_name=, :nickname=, :family_name=, :given_name=, :additional_name=, :honorific_prefix=, :honorific_suffix=, :to => :vcard
11
-
12
- has_many :vcards, :as => 'object', :autosave => true, :validate => true
13
-
14
- def vcard_with_autobuild
15
- vcard_without_autobuild || build_vcard
16
- end
17
- alias_method_chain :vcard, :autobuild
18
- end_eval
19
- end
3
+ # Base module
4
+ #
5
+ # This defines the namespace and adds autoload definitions.
6
+ module HasVcards
20
7
  end