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