vines 0.1.1 → 0.2.0
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.
- data/README +2 -2
- data/Rakefile +63 -8
- data/bin/vines +0 -1
- data/conf/config.rb +16 -7
- data/lib/vines.rb +21 -16
- data/lib/vines/command/init.rb +5 -3
- data/lib/vines/config.rb +34 -0
- data/lib/vines/contact.rb +14 -0
- data/lib/vines/stanza.rb +26 -0
- data/lib/vines/stanza/iq.rb +1 -1
- data/lib/vines/stanza/iq/disco_info.rb +3 -0
- data/lib/vines/stanza/iq/private_storage.rb +83 -0
- data/lib/vines/stanza/iq/roster.rb +26 -30
- data/lib/vines/stanza/presence.rb +0 -12
- data/lib/vines/stanza/presence/subscribe.rb +3 -20
- data/lib/vines/stanza/presence/subscribed.rb +9 -10
- data/lib/vines/stanza/presence/unsubscribe.rb +8 -15
- data/lib/vines/stanza/presence/unsubscribed.rb +8 -8
- data/lib/vines/storage.rb +28 -0
- data/lib/vines/storage/couchdb.rb +29 -0
- data/lib/vines/storage/local.rb +22 -0
- data/lib/vines/storage/redis.rb +26 -0
- data/lib/vines/storage/sql.rb +48 -5
- data/lib/vines/stream/client.rb +6 -8
- data/lib/vines/stream/http.rb +23 -21
- data/lib/vines/stream/http/auth.rb +1 -1
- data/lib/vines/stream/http/bind.rb +1 -1
- data/lib/vines/stream/http/bind_restart.rb +4 -3
- data/lib/vines/stream/http/ready.rb +1 -1
- data/lib/vines/stream/http/request.rb +94 -5
- data/lib/vines/stream/http/session.rb +8 -6
- data/lib/vines/version.rb +1 -1
- data/test/config_test.rb +12 -0
- data/test/contact_test.rb +40 -0
- data/test/rake_test_loader.rb +11 -3
- data/test/stanza/iq/private_storage_test.rb +177 -0
- data/test/stanza/iq/roster_test.rb +1 -1
- data/test/stanza/iq_test.rb +63 -0
- data/test/storage/couchdb_test.rb +7 -1
- data/test/storage/local_test.rb +8 -2
- data/test/storage/redis_test.rb +16 -7
- data/test/storage/sql_test.rb +8 -1
- data/test/storage/storage_tests.rb +50 -0
- data/test/stream/http/auth_test.rb +3 -0
- data/test/stream/http/ready_test.rb +3 -0
- data/test/stream/http/request_test.rb +86 -0
- data/test/stream/parser_test.rb +2 -0
- data/web/404.html +43 -0
- data/web/apple-touch-icon.png +0 -0
- data/web/chat/coffeescripts/chat.coffee +385 -0
- data/web/chat/coffeescripts/init.coffee +15 -0
- data/web/chat/coffeescripts/logout.coffee +5 -0
- data/web/chat/index.html +17 -0
- data/web/chat/javascripts/app.js +1 -0
- data/web/chat/javascripts/chat.js +436 -0
- data/web/chat/javascripts/init.js +21 -0
- data/web/chat/javascripts/logout.js +11 -0
- data/web/chat/stylesheets/chat.css +290 -0
- data/web/favicon.png +0 -0
- data/web/lib/coffeescripts/contact.coffee +32 -0
- data/web/lib/coffeescripts/layout.coffee +30 -0
- data/web/lib/coffeescripts/login.coffee +52 -0
- data/web/lib/coffeescripts/navbar.coffee +84 -0
- data/web/lib/coffeescripts/router.coffee +40 -0
- data/web/lib/coffeescripts/session.coffee +211 -0
- data/web/lib/images/default-user.png +0 -0
- data/web/lib/images/logo-large.png +0 -0
- data/web/lib/images/logo-small.png +0 -0
- data/web/lib/javascripts/base.js +9 -0
- data/web/lib/javascripts/contact.js +94 -0
- data/web/lib/javascripts/icons.js +101 -0
- data/web/lib/javascripts/jquery.cookie.js +91 -0
- data/web/lib/javascripts/jquery.js +18 -0
- data/web/lib/javascripts/layout.js +48 -0
- data/web/lib/javascripts/login.js +61 -0
- data/web/lib/javascripts/navbar.js +69 -0
- data/web/lib/javascripts/raphael.js +8 -0
- data/web/lib/javascripts/router.js +105 -0
- data/web/lib/javascripts/session.js +322 -0
- data/web/lib/javascripts/strophe.js +1 -0
- data/web/lib/stylesheets/base.css +223 -0
- data/web/lib/stylesheets/login.css +63 -0
- metadata +51 -9
@@ -77,13 +77,8 @@ module Vines
|
|
77
77
|
raise StanzaErrors::ItemNotFound.new(self, 'modify') unless contact
|
78
78
|
if router.local_jid?(contact.jid)
|
79
79
|
user = storage(contact.jid.domain).find_user(contact.jid)
|
80
|
-
remove(contact, user)
|
81
|
-
else
|
82
|
-
remove(contact, nil)
|
83
80
|
end
|
84
|
-
end
|
85
81
|
|
86
|
-
def remove(contact, user=nil)
|
87
82
|
if user && user.contact(stream.user.jid)
|
88
83
|
user.contact(stream.user.jid).subscription = 'none'
|
89
84
|
user.contact(stream.user.jid).ask = nil
|
@@ -93,52 +88,53 @@ module Vines
|
|
93
88
|
storage(save.jid.domain).save_user(save)
|
94
89
|
stream.update_user_streams(save)
|
95
90
|
end
|
91
|
+
|
96
92
|
send_result_iq
|
97
93
|
push_roster_updates(stream.user.jid, Contact.new(
|
98
94
|
:jid => contact.jid,
|
99
95
|
:subscription => 'remove'))
|
100
96
|
|
101
|
-
|
102
|
-
if contact.
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
'to' => contact.jid.to_s,
|
107
|
-
'type' => type)
|
97
|
+
if router.local_jid?(contact.jid)
|
98
|
+
send_unavailable(stream.user.jid, contact.jid) if contact.subscribed_from?
|
99
|
+
send_unsubscribe(contact)
|
100
|
+
if user.contact(stream.user.jid)
|
101
|
+
push_roster_updates(contact.jid, user.contact(stream.user.jid))
|
108
102
|
end
|
103
|
+
else
|
104
|
+
send_unsubscribe(contact)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Notify the contact that it's been removed from the user's roster
|
109
|
+
# and no longer has any presence relationship with the user.
|
110
|
+
def send_unsubscribe(contact)
|
111
|
+
presence = [%w[to unsubscribe], %w[from unsubscribed]].map do |meth, type|
|
112
|
+
presence(contact.jid, type) if contact.send("subscribed_#{meth}?")
|
109
113
|
end.compact
|
110
114
|
|
111
115
|
if router.local_jid?(contact.jid)
|
112
116
|
router.interested_resources(contact.jid).each do |recipient|
|
113
117
|
presence.each {|el| recipient.write(el) }
|
114
|
-
doc = Document.new
|
115
|
-
el = doc.create_element('presence',
|
116
|
-
'from' => stream.user.jid.bare.to_s,
|
117
|
-
'to' => recipient.user.jid.to_s,
|
118
|
-
'type' => 'unavailable')
|
119
|
-
recipient.write(el)
|
120
118
|
end
|
121
|
-
push_roster_updates(contact.jid, Contact.new(
|
122
|
-
:jid => stream.user.jid,
|
123
|
-
:subscription => 'none'))
|
124
119
|
else
|
125
120
|
presence.each {|el| router.route(el) }
|
126
121
|
end
|
127
122
|
end
|
128
123
|
|
124
|
+
def presence(to, type)
|
125
|
+
doc = Document.new
|
126
|
+
doc.create_element('presence',
|
127
|
+
'from' => stream.user.jid.bare.to_s,
|
128
|
+
'id' => Kit.uuid,
|
129
|
+
'to' => to.to_s,
|
130
|
+
'type' => type)
|
131
|
+
end
|
132
|
+
|
129
133
|
# Send an iq set stanza to the user's interested resources, letting them
|
130
134
|
# know their roster has been updated.
|
131
135
|
def push_roster_updates(to, contact)
|
132
|
-
doc = Document.new
|
133
|
-
el = doc.create_element('iq', 'type' => 'set') do |node|
|
134
|
-
node << doc.create_element('query', 'xmlns' => NAMESPACES[:roster]) do |query|
|
135
|
-
query << contact.to_roster_xml
|
136
|
-
end
|
137
|
-
end
|
138
136
|
router.interested_resources(to).each do |recipient|
|
139
|
-
|
140
|
-
el['to'] = recipient.user.jid.to_s
|
141
|
-
recipient.write(el)
|
137
|
+
contact.send_roster_push(recipient)
|
142
138
|
end
|
143
139
|
end
|
144
140
|
|
@@ -81,18 +81,6 @@ module Vines
|
|
81
81
|
router.route(probe)
|
82
82
|
end
|
83
83
|
|
84
|
-
def send_subscribed_roster_push(recipient, jid, state)
|
85
|
-
doc = Document.new
|
86
|
-
node = doc.create_element('iq',
|
87
|
-
'id' => Kit.uuid,
|
88
|
-
'to' => recipient.user.jid.to_s,
|
89
|
-
'type' => 'set')
|
90
|
-
node << doc.create_element('query', 'xmlns' => NAMESPACES[:roster]) do |query|
|
91
|
-
query << doc.create_element('item', 'jid' => jid.to_s, 'subscription' => state)
|
92
|
-
end
|
93
|
-
recipient.write(node)
|
94
|
-
end
|
95
|
-
|
96
84
|
def auto_reply_to_subscription_request(from, type)
|
97
85
|
doc = Document.new
|
98
86
|
node = doc.create_element('presence') do |el|
|
@@ -13,16 +13,15 @@ module Vines
|
|
13
13
|
def process_outbound
|
14
14
|
self['from'] = stream.user.jid.bare.to_s
|
15
15
|
to = stamp_to
|
16
|
-
|
16
|
+
local? ? process_inbound : route
|
17
17
|
|
18
18
|
stream.user.request_subscription(to)
|
19
19
|
storage.save_user(stream.user)
|
20
20
|
stream.update_user_streams(stream.user)
|
21
21
|
|
22
|
-
|
23
|
-
|
22
|
+
contact = stream.user.contact(to)
|
24
23
|
router.interested_resources(stream.user.jid).each do |recipient|
|
25
|
-
|
24
|
+
contact.send_roster_push(recipient)
|
26
25
|
end
|
27
26
|
end
|
28
27
|
|
@@ -44,22 +43,6 @@ module Vines
|
|
44
43
|
end
|
45
44
|
end
|
46
45
|
end
|
47
|
-
|
48
|
-
private
|
49
|
-
|
50
|
-
def send_subscribe_roster_push(recipient, contact)
|
51
|
-
doc = Document.new
|
52
|
-
node = doc.create_element('iq') do |el|
|
53
|
-
el['id'] = Kit.uuid
|
54
|
-
el['to'] = recipient.user.jid.to_s
|
55
|
-
el['type'] = 'set'
|
56
|
-
el << doc.create_element('query') do |query|
|
57
|
-
query.default_namespace = NAMESPACES[:roster]
|
58
|
-
query << contact.to_roster_xml
|
59
|
-
end
|
60
|
-
end
|
61
|
-
recipient.write(node)
|
62
|
-
end
|
63
46
|
end
|
64
47
|
end
|
65
48
|
end
|
@@ -13,22 +13,23 @@ module Vines
|
|
13
13
|
def process_outbound
|
14
14
|
self['from'] = stream.user.jid.bare.to_s
|
15
15
|
to = stamp_to
|
16
|
-
|
16
|
+
local? ? process_inbound : route
|
17
17
|
|
18
18
|
stream.user.add_subscription_from(to)
|
19
19
|
storage.save_user(stream.user)
|
20
20
|
stream.update_user_streams(stream.user)
|
21
21
|
|
22
|
+
contact = stream.user.contact(to)
|
22
23
|
router.interested_resources(stream.user.jid).each do |recipient|
|
23
|
-
|
24
|
+
contact.send_roster_push(recipient)
|
24
25
|
end
|
25
26
|
|
26
27
|
presences = router.available_resources(stream.user.jid).map do |c|
|
27
|
-
|
28
|
-
|
29
|
-
'
|
30
|
-
'
|
31
|
-
|
28
|
+
c.last_broadcast_presence.clone.tap do |node|
|
29
|
+
node['from'] = c.user.jid.to_s
|
30
|
+
node['id'] = Kit.uuid
|
31
|
+
node['to'] = to.to_s
|
32
|
+
end
|
32
33
|
end
|
33
34
|
|
34
35
|
if local?
|
@@ -38,8 +39,6 @@ module Vines
|
|
38
39
|
else
|
39
40
|
presences.each {|el| router.route(el) }
|
40
41
|
end
|
41
|
-
|
42
|
-
process_inbound if local?
|
43
42
|
end
|
44
43
|
|
45
44
|
def process_inbound
|
@@ -55,7 +54,7 @@ module Vines
|
|
55
54
|
|
56
55
|
router.interested_resources(to).each do |recipient|
|
57
56
|
recipient.write(@node)
|
58
|
-
|
57
|
+
contact.send_roster_push(recipient)
|
59
58
|
end
|
60
59
|
end
|
61
60
|
end
|
@@ -13,18 +13,17 @@ module Vines
|
|
13
13
|
def process_outbound
|
14
14
|
self['from'] = stream.user.jid.bare.to_s
|
15
15
|
to = stamp_to
|
16
|
-
|
16
|
+
|
17
|
+
return unless stream.user.subscribed_to?(to)
|
18
|
+
local? ? process_inbound : route
|
17
19
|
|
18
20
|
stream.user.remove_subscription_to(to)
|
19
21
|
storage.save_user(stream.user)
|
20
22
|
stream.update_user_streams(stream.user)
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
router.interested_resources(stream.user.jid).each do |recipient|
|
26
|
-
send_subscribed_roster_push(recipient, to, contact.subscription)
|
27
|
-
end
|
24
|
+
contact = stream.user.contact(to)
|
25
|
+
router.interested_resources(stream.user.jid).each do |recipient|
|
26
|
+
contact.send_roster_push(recipient)
|
28
27
|
end
|
29
28
|
end
|
30
29
|
|
@@ -41,15 +40,9 @@ module Vines
|
|
41
40
|
|
42
41
|
router.interested_resources(to).each do |recipient|
|
43
42
|
recipient.write(@node)
|
44
|
-
|
45
|
-
doc = Document.new
|
46
|
-
el = doc.create_element('presence',
|
47
|
-
'from' => stream.user.jid.bare.to_s,
|
48
|
-
'id' => Kit.uuid,
|
49
|
-
'to' => recipient.user.jid.to_s,
|
50
|
-
'type' => 'unavailable')
|
51
|
-
recipient.write(el)
|
43
|
+
contact.send_roster_push(recipient)
|
52
44
|
end
|
45
|
+
send_unavailable(to, stream.user.jid.bare)
|
53
46
|
end
|
54
47
|
end
|
55
48
|
end
|
@@ -13,19 +13,19 @@ module Vines
|
|
13
13
|
def process_outbound
|
14
14
|
self['from'] = stream.user.jid.bare.to_s
|
15
15
|
to = stamp_to
|
16
|
-
|
16
|
+
|
17
|
+
return unless stream.user.subscribed_from?(to)
|
18
|
+
send_unavailable(stream.user.jid, to)
|
19
|
+
local? ? process_inbound : route
|
17
20
|
|
18
21
|
stream.user.remove_subscription_from(to)
|
19
22
|
storage.save_user(stream.user)
|
20
23
|
stream.update_user_streams(stream.user)
|
21
24
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
end
|
25
|
+
contact = stream.user.contact(to)
|
26
|
+
router.interested_resources(stream.user.jid).each do |recipient|
|
27
|
+
contact.send_roster_push(recipient)
|
26
28
|
end
|
27
|
-
|
28
|
-
process_inbound if local?
|
29
29
|
end
|
30
30
|
|
31
31
|
def process_inbound
|
@@ -41,7 +41,7 @@ module Vines
|
|
41
41
|
|
42
42
|
router.interested_resources(to).each do |recipient|
|
43
43
|
recipient.write(@node)
|
44
|
-
|
44
|
+
contact.send_roster_push(recipient)
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
data/lib/vines/storage.rb
CHANGED
@@ -168,6 +168,34 @@ module Vines
|
|
168
168
|
raise 'subclass must implement'
|
169
169
|
end
|
170
170
|
|
171
|
+
# Return the Nokogiri::XML::Node for the XML fragment stored for this JID.
|
172
|
+
# Return nil if the fragment could not be found. JID may be +nil+, a
|
173
|
+
# +String+, or a +Vines::JID+ object. It may be a bare JID or a full JID.
|
174
|
+
# Implementations of this method must convert the JID to a bare JID before
|
175
|
+
# searching for the fragment in the database.
|
176
|
+
#
|
177
|
+
# Private XML storage uniquely identifies fragments by JID, root element name,
|
178
|
+
# and root element namespace.
|
179
|
+
#
|
180
|
+
# root = Nokogiri::XML('<custom xmlns="urn:custom:ns"/>').root
|
181
|
+
# fragment = storage.find_fragment('alice@wonderland.lit', root)
|
182
|
+
# puts fragment.nil?
|
183
|
+
def find_fragment(jid, node)
|
184
|
+
raise 'subclass must implement'
|
185
|
+
end
|
186
|
+
|
187
|
+
# Save the XML fragment to the database and return when the save is complete.
|
188
|
+
# JID may be a +String+ or a +Vines::JID+ object. It may be a bare JID or a
|
189
|
+
# full JID. Implementations of this method must convert the JID to a bare
|
190
|
+
# JID before saving the fragment. Fragment is a +Nokogiri::XML::Node+ object.
|
191
|
+
#
|
192
|
+
# fragment = Nokogiri::XML('<custom xmlns="urn:custom:ns">some data</custom>').root
|
193
|
+
# storage.save_fragment('alice@wonderland.lit', fragment)
|
194
|
+
# puts 'saved'
|
195
|
+
def save_fragment(jid, fragment)
|
196
|
+
raise 'subclass must implement'
|
197
|
+
end
|
198
|
+
|
171
199
|
private
|
172
200
|
|
173
201
|
# Return true if any of the arguments are nil or empty strings.
|
@@ -84,8 +84,37 @@ module Vines
|
|
84
84
|
end
|
85
85
|
fiber :save_vcard
|
86
86
|
|
87
|
+
def find_fragment(jid, node)
|
88
|
+
jid = JID.new(jid || '').bare.to_s
|
89
|
+
if jid.empty? then yield; return end
|
90
|
+
get(fragment_id(jid, node)) do |doc|
|
91
|
+
fragment = if doc && doc['type'] == 'Fragment'
|
92
|
+
Nokogiri::XML(doc['xml']).root rescue nil
|
93
|
+
end
|
94
|
+
yield fragment
|
95
|
+
end
|
96
|
+
end
|
97
|
+
fiber :find_fragment
|
98
|
+
|
99
|
+
def save_fragment(jid, node, &callback)
|
100
|
+
jid = JID.new(jid).bare.to_s
|
101
|
+
id = fragment_id(jid, node)
|
102
|
+
get(id) do |doc|
|
103
|
+
doc ||= {'_id' => id}
|
104
|
+
doc['type'] = 'Fragment'
|
105
|
+
doc['xml'] = node.to_xml
|
106
|
+
save_doc(doc, &callback)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
fiber :save_fragment
|
110
|
+
|
87
111
|
private
|
88
112
|
|
113
|
+
def fragment_id(jid, node)
|
114
|
+
id = Digest::SHA1.hexdigest("#{node.name}:#{node.namespace.href}")
|
115
|
+
"fragment:#{jid}:#{id}"
|
116
|
+
end
|
117
|
+
|
89
118
|
def url(config)
|
90
119
|
scheme = config[:tls] ? 'https' : 'http'
|
91
120
|
user, password = config.values_at(:username, :password)
|
data/lib/vines/storage/local.rb
CHANGED
@@ -61,6 +61,28 @@ module Vines
|
|
61
61
|
f.write(card.to_xml)
|
62
62
|
end
|
63
63
|
end
|
64
|
+
|
65
|
+
def find_fragment(jid, node)
|
66
|
+
jid = JID.new(jid || '').bare.to_s
|
67
|
+
return if jid.empty?
|
68
|
+
file = File.join(@dir, fragment_id(jid, node))
|
69
|
+
Nokogiri::XML(File.read(file)).root rescue nil
|
70
|
+
end
|
71
|
+
|
72
|
+
def save_fragment(jid, node)
|
73
|
+
jid = JID.new(jid).bare.to_s
|
74
|
+
file = File.join(@dir, fragment_id(jid, node))
|
75
|
+
File.open(file, 'w') do |f|
|
76
|
+
f.write(node.to_xml)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def fragment_id(jid, node)
|
83
|
+
id = Digest::SHA1.hexdigest("#{node.name}:#{node.namespace.href}")
|
84
|
+
"#{jid}-#{id}.fragment"
|
85
|
+
end
|
64
86
|
end
|
65
87
|
end
|
66
88
|
end
|
data/lib/vines/storage/redis.rb
CHANGED
@@ -74,8 +74,34 @@ module Vines
|
|
74
74
|
end
|
75
75
|
fiber :save_vcard
|
76
76
|
|
77
|
+
def find_fragment(jid, node)
|
78
|
+
jid = JID.new(jid || '').bare.to_s
|
79
|
+
if jid.empty? then yield; return end
|
80
|
+
redis.hget("fragments:#{jid}", fragment_id(node)) do |response|
|
81
|
+
fragment = if response
|
82
|
+
doc = JSON.parse(response) rescue nil
|
83
|
+
Nokogiri::XML(doc['xml']).root rescue nil
|
84
|
+
end
|
85
|
+
yield fragment
|
86
|
+
end
|
87
|
+
end
|
88
|
+
fiber :find_fragment
|
89
|
+
|
90
|
+
def save_fragment(jid, node)
|
91
|
+
jid = JID.new(jid).bare.to_s
|
92
|
+
doc = {:xml => node.to_xml}
|
93
|
+
redis.hset("fragments:#{jid}", fragment_id(node), doc.to_json) do
|
94
|
+
yield
|
95
|
+
end
|
96
|
+
end
|
97
|
+
fiber :save_fragment
|
98
|
+
|
77
99
|
private
|
78
100
|
|
101
|
+
def fragment_id(node)
|
102
|
+
Digest::SHA1.hexdigest("#{node.name}:#{node.namespace.href}")
|
103
|
+
end
|
104
|
+
|
79
105
|
# Retrieve the hash stored at roster:jid and yield an array of
|
80
106
|
# +Vines::Contact+ objects to the provided block.
|
81
107
|
#
|
data/lib/vines/storage/sql.rb
CHANGED
@@ -8,9 +8,13 @@ module Vines
|
|
8
8
|
class Contact < ActiveRecord::Base
|
9
9
|
belongs_to :user
|
10
10
|
end
|
11
|
+
class Fragment < ActiveRecord::Base
|
12
|
+
belongs_to :user
|
13
|
+
end
|
11
14
|
class Group < ActiveRecord::Base; end
|
12
15
|
class User < ActiveRecord::Base
|
13
16
|
has_many :contacts
|
17
|
+
has_many :fragments
|
14
18
|
end
|
15
19
|
|
16
20
|
%w[adapter host port database username password pool].each do |name|
|
@@ -38,7 +42,7 @@ module Vines
|
|
38
42
|
|
39
43
|
jid = JID.new(jid || '').bare.to_s
|
40
44
|
return if jid.empty?
|
41
|
-
xuser =
|
45
|
+
xuser = user_by_jid(jid)
|
42
46
|
return Vines::User.new(:jid => jid).tap do |user|
|
43
47
|
user.name, user.password = xuser.name, xuser.password
|
44
48
|
xuser.contacts.each do |contact|
|
@@ -57,7 +61,7 @@ module Vines
|
|
57
61
|
def save_user(user)
|
58
62
|
ActiveRecord::Base.clear_reloadable_connections!
|
59
63
|
|
60
|
-
xuser =
|
64
|
+
xuser = user_by_jid(user.jid) || Sql::User.new(:jid => user.jid.bare.to_s)
|
61
65
|
xuser.name = user.name
|
62
66
|
xuser.password = user.password
|
63
67
|
|
@@ -97,7 +101,7 @@ module Vines
|
|
97
101
|
|
98
102
|
jid = JID.new(jid || '').bare.to_s
|
99
103
|
return if jid.empty?
|
100
|
-
if xuser =
|
104
|
+
if xuser = user_by_jid(jid)
|
101
105
|
Nokogiri::XML(xuser.vcard).root rescue nil
|
102
106
|
end
|
103
107
|
end
|
@@ -106,7 +110,7 @@ module Vines
|
|
106
110
|
def save_vcard(jid, card)
|
107
111
|
ActiveRecord::Base.clear_reloadable_connections!
|
108
112
|
|
109
|
-
xuser =
|
113
|
+
xuser = user_by_jid(jid)
|
110
114
|
if xuser
|
111
115
|
xuser.vcard = card.to_xml
|
112
116
|
xuser.save
|
@@ -114,6 +118,31 @@ module Vines
|
|
114
118
|
end
|
115
119
|
defer :save_vcard
|
116
120
|
|
121
|
+
def find_fragment(jid, node)
|
122
|
+
ActiveRecord::Base.clear_reloadable_connections!
|
123
|
+
|
124
|
+
jid = JID.new(jid || '').bare.to_s
|
125
|
+
return if jid.empty?
|
126
|
+
if fragment = fragment_by_jid(jid, node)
|
127
|
+
Nokogiri::XML(fragment.xml).root rescue nil
|
128
|
+
end
|
129
|
+
end
|
130
|
+
defer :find_fragment
|
131
|
+
|
132
|
+
def save_fragment(jid, node)
|
133
|
+
ActiveRecord::Base.clear_reloadable_connections!
|
134
|
+
|
135
|
+
jid = JID.new(jid).bare.to_s
|
136
|
+
fragment = fragment_by_jid(jid, node) ||
|
137
|
+
Sql::Fragment.new(
|
138
|
+
:user => user_by_jid(jid),
|
139
|
+
:root => node.name,
|
140
|
+
:namespace => node.namespace.href)
|
141
|
+
fragment.xml = node.to_xml
|
142
|
+
fragment.save
|
143
|
+
end
|
144
|
+
defer :save_fragment
|
145
|
+
|
117
146
|
# Create the tables and indexes used by this storage engine.
|
118
147
|
def create_schema(args={})
|
119
148
|
ActiveRecord::Base.clear_reloadable_connections!
|
@@ -148,6 +177,14 @@ module Vines
|
|
148
177
|
t.integer :group_id, :null => false
|
149
178
|
end
|
150
179
|
add_index :contacts_groups, [:contact_id, :group_id], :unique => true
|
180
|
+
|
181
|
+
create_table :fragments, :force => args[:force] do |t|
|
182
|
+
t.integer :user_id, :null => false
|
183
|
+
t.string :root, :limit => 1000, :null => false
|
184
|
+
t.string :namespace, :limit => 1000, :null => false
|
185
|
+
t.text :xml, :null => false
|
186
|
+
end
|
187
|
+
add_index :fragments, [:user_id, :root, :namespace], :unique => true
|
151
188
|
end
|
152
189
|
end
|
153
190
|
|
@@ -161,11 +198,17 @@ module Vines
|
|
161
198
|
Sql::Group.has_and_belongs_to_many :contacts
|
162
199
|
end
|
163
200
|
|
164
|
-
def
|
201
|
+
def user_by_jid(jid)
|
165
202
|
jid = JID.new(jid).bare.to_s
|
166
203
|
Sql::User.find_by_jid(jid, :include => {:contacts => :groups})
|
167
204
|
end
|
168
205
|
|
206
|
+
def fragment_by_jid(jid, node)
|
207
|
+
jid = JID.new(jid).bare.to_s
|
208
|
+
clause = 'user_id=(select id from users where jid=?) and root=? and namespace=?'
|
209
|
+
Sql::Fragment.where(clause, jid, node.name, node.namespace.href).first
|
210
|
+
end
|
211
|
+
|
169
212
|
def groups(contact)
|
170
213
|
contact.groups.map {|name| Sql::Group.find_or_create_by_name(name.strip) }
|
171
214
|
end
|