rdomino 0.0.2
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/lib/rdomino.rb +32 -0
- data/lib/rdomino/1modules.rb +77 -0
- data/lib/rdomino/database.rb +380 -0
- data/lib/rdomino/database_collection.rb +43 -0
- data/lib/rdomino/database_directory.rb +20 -0
- data/lib/rdomino/database_library.rb +34 -0
- data/lib/rdomino/databases/testdb.rb +9 -0
- data/lib/rdomino/document.rb +112 -0
- data/lib/rdomino/document_collection.rb +41 -0
- data/lib/rdomino/item.rb +57 -0
- data/lib/rdomino/name.rb +9 -0
- data/lib/rdomino/richtext_item.rb +7 -0
- data/lib/rdomino/server.rb +22 -0
- data/lib/rdomino/session.rb +115 -0
- data/lib/rdomino/version.rb +3 -0
- data/lib/rdomino/view.rb +89 -0
- data/readme.rdoc +1 -0
- data/spec/helper.rb +1 -0
- data/spec/rdomino/database_directory_spec.rb +14 -0
- data/spec/rdomino/database_helper_spec.rb +17 -0
- data/spec/rdomino/database_spec.rb +111 -0
- data/spec/rdomino/datetime_spec.rb +12 -0
- data/spec/rdomino/document_collection_spec.rb +56 -0
- data/spec/rdomino/document_spec.rb +55 -0
- data/spec/rdomino/dxl_spec.rb +16 -0
- data/spec/rdomino/item_spec.rb +26 -0
- data/spec/rdomino/name_spec.rb +13 -0
- data/spec/rdomino/session_spec.rb +46 -0
- data/spec/rdomino/view_spec.rb +43 -0
- metadata +132 -0
data/lib/rdomino.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#require 'rubygems'
|
2
|
+
require 'win32ole'
|
3
|
+
require 'highline/import'
|
4
|
+
require 'active_support'
|
5
|
+
|
6
|
+
Dir[File.dirname(__FILE__).gsub(/\\/,'/') + '/*/*.rb'].each{|f| require f}
|
7
|
+
module Rdomino
|
8
|
+
|
9
|
+
class Datetime
|
10
|
+
include DomObject
|
11
|
+
def initialize(time)
|
12
|
+
@obj = Session.session.createDatetime(time.strftime("%d.%m.%Y %H:%M:%S"))
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
class Daterange
|
18
|
+
include DomObject
|
19
|
+
def initialize(sdt,edt)
|
20
|
+
@obj = Session.session.Createdaterange
|
21
|
+
@obj.StartDateTime = sdt.obj
|
22
|
+
@obj.EndDateTime = edt.obj
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class Agent
|
27
|
+
include DomObject
|
28
|
+
end
|
29
|
+
|
30
|
+
puts "rdomino(#{VERSION}) loaded"
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Rdomino
|
2
|
+
|
3
|
+
module DomObject
|
4
|
+
|
5
|
+
def method_missing(m,*args)
|
6
|
+
# puts "#{@obj}.send #{m} #{args.inspect}"
|
7
|
+
@obj.__send__(m,*args)
|
8
|
+
end
|
9
|
+
|
10
|
+
def obj
|
11
|
+
@obj
|
12
|
+
end
|
13
|
+
|
14
|
+
def empty?
|
15
|
+
@obj.nil?
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(obj)
|
19
|
+
@obj = obj
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
module DbDcDoc
|
25
|
+
|
26
|
+
def dxl_to_file(filename)
|
27
|
+
File.open(filename, "w") do |f|
|
28
|
+
f << dxl
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def dxl
|
33
|
+
dxl_exporter = Session.session.createDXLExporter
|
34
|
+
dxl_exporter.export(@obj)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
module DcView
|
40
|
+
|
41
|
+
def each
|
42
|
+
doc = @obj.getLastDocument
|
43
|
+
while doc
|
44
|
+
next_doc = @obj.getPrevDocument(doc)
|
45
|
+
yield(Document.new(doc))
|
46
|
+
doc = next_doc
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
module DatabaseHelper
|
53
|
+
def is_replica_id?(s)
|
54
|
+
( s =~ /[A-F0-9]{16}/ ? true : false)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
module PersonDoc
|
59
|
+
def maildb
|
60
|
+
Session.get["#{get :mailserver}!!#{get :mailfile}"]
|
61
|
+
end
|
62
|
+
|
63
|
+
def maildb_cluster
|
64
|
+
Session.get["#{cluster(get(:mailserver)[0])}!!#{get :mailfile}"]
|
65
|
+
end
|
66
|
+
|
67
|
+
def cluster(s) # CN=EU-MAIL36/OU=DE/O=BAYER"
|
68
|
+
server,*ou = s.split("/")
|
69
|
+
nr = server[-2..-1]
|
70
|
+
h={'35'=>'36','37' => '38'}
|
71
|
+
clnr = h[nr] || h.invert[nr]
|
72
|
+
raise "cluster not defined" unless clnr
|
73
|
+
ou.insert(0,server[0..-3]+clnr).join("/")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,380 @@
|
|
1
|
+
# autoload database specific modules
|
2
|
+
Dir["#{File.dirname(__FILE__).gsub(/\\/,'/')}/databases/*.rb"].each{|f| require f}
|
3
|
+
|
4
|
+
module Rdomino
|
5
|
+
|
6
|
+
class Database
|
7
|
+
attr_reader :name,:server_path
|
8
|
+
include Enumerable,DomObject,DbDcDoc, DatabaseHelper
|
9
|
+
|
10
|
+
def replication
|
11
|
+
@replication ||= self.replicationInfo
|
12
|
+
end
|
13
|
+
|
14
|
+
def cut_off_intervall
|
15
|
+
replication.cutoffInterval
|
16
|
+
end
|
17
|
+
|
18
|
+
def cut_off_intervall=(v)
|
19
|
+
replication.cutoffInterval = v
|
20
|
+
replication.save()
|
21
|
+
end
|
22
|
+
|
23
|
+
def each(&b)
|
24
|
+
dc = DocumentCollection.new(@obj.allDocuments)
|
25
|
+
dc.each(&b)
|
26
|
+
end
|
27
|
+
|
28
|
+
def [](view_string)
|
29
|
+
if view_string =~ /^search:(.*)/
|
30
|
+
search( $1 )
|
31
|
+
else
|
32
|
+
v = get_view( view_string )
|
33
|
+
v.obj ? v : nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_s
|
38
|
+
"#{obj.title} (#{server_path})"
|
39
|
+
end
|
40
|
+
|
41
|
+
# server,path or object
|
42
|
+
def initialize(name,obj)
|
43
|
+
m = Rdomino::Databases.const_get(name.to_s.camelize) rescue nil
|
44
|
+
self.extend(m) if m
|
45
|
+
@name = name
|
46
|
+
case obj
|
47
|
+
when String
|
48
|
+
@server_path = obj
|
49
|
+
server, path = obj.split("!!")
|
50
|
+
@obj = Session.session.getDatabase(server, path)
|
51
|
+
flag = @obj.OpenByReplicaID( server, path ) if is_replica_id?(path)
|
52
|
+
else
|
53
|
+
@obj = obj
|
54
|
+
@server_path = "#{obj.server}!!#{obj.filepath}"
|
55
|
+
end
|
56
|
+
print "\ndb.open:#{self}"
|
57
|
+
end
|
58
|
+
|
59
|
+
def open!
|
60
|
+
unless isopen
|
61
|
+
@obj = Session.session.getDatabase(@obj.server, @obj.filepath)
|
62
|
+
end
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_view(v)
|
67
|
+
View.new(@obj,v)
|
68
|
+
end
|
69
|
+
|
70
|
+
def get_agent(v)
|
71
|
+
Agent.new(obj.getAgent(v))
|
72
|
+
end
|
73
|
+
|
74
|
+
# contains deleted documents
|
75
|
+
def all_documents
|
76
|
+
DocumentCollection.new(@obj.allDocuments)
|
77
|
+
end
|
78
|
+
alias :all :all_documents
|
79
|
+
|
80
|
+
def count
|
81
|
+
all_documents.count
|
82
|
+
end
|
83
|
+
|
84
|
+
# search(:Memo) => all Memos
|
85
|
+
# only documents modified within cutoff_days
|
86
|
+
def search(filter,since=Time.local(1980,1,1,0,0,0),count=0)
|
87
|
+
filter = "Form='#{filter}'" if filter.kind_of? Symbol
|
88
|
+
DocumentCollection.new(@obj.search(filter,Datetime.new(since).obj,count))
|
89
|
+
end
|
90
|
+
|
91
|
+
def create_document(attributes={})
|
92
|
+
doc = Document.new( obj.CreateDocument )
|
93
|
+
attributes.each do |field,value|
|
94
|
+
doc.replaceItemValue(field.to_s,value)
|
95
|
+
end
|
96
|
+
doc.save(true, false)
|
97
|
+
doc
|
98
|
+
end
|
99
|
+
|
100
|
+
def fixtures
|
101
|
+
Session.get.configuration[name][:fixtures]
|
102
|
+
end
|
103
|
+
|
104
|
+
# :xml from test/fixtures/db.xml
|
105
|
+
# :yml from config.yml [db][fixtures]
|
106
|
+
# hash or Array of
|
107
|
+
# tabular text: f1|f2\nv1|v2
|
108
|
+
def load_fixtures(p=:xml)
|
109
|
+
delete_documents
|
110
|
+
p = ( [] << p ) if p.kind_of? Hash
|
111
|
+
p = fixtures if p == :yml
|
112
|
+
case p
|
113
|
+
when String
|
114
|
+
f,*d = p.split("\n")
|
115
|
+
fields = f.split("|")
|
116
|
+
d.each do |line|
|
117
|
+
hash = {}
|
118
|
+
values = line.split("|")
|
119
|
+
values.each_index{ |i| hash[fields[i]] = values[i] }
|
120
|
+
create_document(hash)
|
121
|
+
end
|
122
|
+
when Array
|
123
|
+
p.map{|h|
|
124
|
+
create_document(h) }[0]
|
125
|
+
else
|
126
|
+
dxl_import(IO.read(fixture_file))
|
127
|
+
end
|
128
|
+
self
|
129
|
+
end
|
130
|
+
|
131
|
+
def fixture_file
|
132
|
+
File.dirname(__FILE__)+"/../../test/fixtures/#{name}.xml"
|
133
|
+
end
|
134
|
+
|
135
|
+
def dump
|
136
|
+
all_documents.dxl_to_file( fixture_file )
|
137
|
+
end
|
138
|
+
|
139
|
+
def import_all_documents_by_dxl(db)
|
140
|
+
d = db.all_documents.dxl
|
141
|
+
dxl_import(d)
|
142
|
+
end
|
143
|
+
|
144
|
+
# returns number al deleted documents
|
145
|
+
def delete_documents(*form)
|
146
|
+
if form.empty?
|
147
|
+
dc = allDocuments
|
148
|
+
else
|
149
|
+
filter = "Form='#{form.map{|i| i.to_s}.join("':'")}'"
|
150
|
+
dc = search( filter )
|
151
|
+
end
|
152
|
+
c = dc.count
|
153
|
+
dc.removeAll true
|
154
|
+
c == 0 ? nil : c
|
155
|
+
end
|
156
|
+
|
157
|
+
def dxl_import(s)
|
158
|
+
imp = Session.session.createDXLImporter
|
159
|
+
imp.replaceDBProperties = false
|
160
|
+
imp.replicaRequiredForReplaceOrUpdate = false
|
161
|
+
imp.aCLImportOption = 5 # DXLIMPORTOPTION_REPLACE_ELSE_IGNORE
|
162
|
+
imp.designImportOption = 2 # DXLIMPORTOPTION_CREATE
|
163
|
+
imp.import(s, obj)
|
164
|
+
end
|
165
|
+
|
166
|
+
# multiple Documents are yielded to a block
|
167
|
+
# returns the number of documents found
|
168
|
+
# ReplicationFormulas Actions DataConnections Documents
|
169
|
+
# Agents Folders Forms ScriptLibraries Subforms Views
|
170
|
+
# FrameSets Navigators Pages Outlines
|
171
|
+
# ImageResources JavaResources MiscCodeElements MiscFormatElements MiscIndexElements
|
172
|
+
# Profiles SharedFields StyleSheetResources
|
173
|
+
def design_documents(*elements)
|
174
|
+
elements.map!{|e| "#{e}=" }
|
175
|
+
elements << :alldesignelements if elements.empty?
|
176
|
+
# its nv.alldesignelements(true)
|
177
|
+
# but nv.views = true
|
178
|
+
nc = @obj.CreateNoteCollection false
|
179
|
+
elements.each{|v|
|
180
|
+
nc.send("select#{v}",true)}
|
181
|
+
nc.BuildCollection
|
182
|
+
id = nc.GetFirstNoteId
|
183
|
+
# check if its a single element which doesn't end with 's'
|
184
|
+
if elements.length == 1 && elements[0].to_s !~ /s=?$/
|
185
|
+
find(id)
|
186
|
+
else
|
187
|
+
while id != ''
|
188
|
+
yield find(id)
|
189
|
+
id = nc.GetNextNoteId(id)
|
190
|
+
end
|
191
|
+
nc.count
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
# single returns the document
|
196
|
+
[:acl,:databasescript,:helpabout,:helpindex,:helpusing].each do |m|
|
197
|
+
define_method(m) do
|
198
|
+
design_documents m
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def icon
|
203
|
+
find('FFFF0010')
|
204
|
+
end
|
205
|
+
|
206
|
+
def flags
|
207
|
+
f = icon.g(:$flags)
|
208
|
+
r =[f]
|
209
|
+
(f.length).times {|i| c = f[i].chr; r << "#{c} - #{FLAGS[c]}" }
|
210
|
+
r
|
211
|
+
end
|
212
|
+
|
213
|
+
# underscored will be omitted (as in selection list)
|
214
|
+
def default_frameset
|
215
|
+
icon.g(:$DefaultFrameset)
|
216
|
+
end
|
217
|
+
|
218
|
+
def default_frameset=(value)
|
219
|
+
icon.replace :$DefaultFrameset => value
|
220
|
+
icon.save
|
221
|
+
end
|
222
|
+
|
223
|
+
# options(:open => true) => :no_action, :refreshed, :pasted
|
224
|
+
def refresh_view_design(template_view,options={})
|
225
|
+
view_name = template_view.name
|
226
|
+
view = get_view( view_name )
|
227
|
+
if view.obj
|
228
|
+
if view == template_view
|
229
|
+
remove,paste,result = false,false, :no_action
|
230
|
+
else
|
231
|
+
remove,paste,result = true,true,:refreshed
|
232
|
+
end
|
233
|
+
else
|
234
|
+
remove,paste,result = false,true,:pasted
|
235
|
+
end
|
236
|
+
view.document.removepermanently(true) if remove
|
237
|
+
if paste
|
238
|
+
template_view.document.copytodatabase(@obj)
|
239
|
+
get_view( view_name ).refresh if options[:open]
|
240
|
+
end
|
241
|
+
result
|
242
|
+
end
|
243
|
+
|
244
|
+
# defaults :duration => 1, :location => '' , :body => nil
|
245
|
+
def create_meeting(start_time,subject,p={})
|
246
|
+
end_time = start_time + (p[:duration]||1) * 3600
|
247
|
+
sdt = Datetime.new(start_time)
|
248
|
+
edt = Datetime.new(end_time)
|
249
|
+
date_range = Daterange.new(sdt,edt)
|
250
|
+
target = create_document(
|
251
|
+
:form => 'Appointment',
|
252
|
+
:subject => subject,
|
253
|
+
:chair => 'CN=Frank Behrens/OU=IMBEH/OU=BBS/O=BAYER',
|
254
|
+
:principal => 'CN=Frank Behrens/OU=IMBEH/OU=BBS/O=BAYER',
|
255
|
+
:location => p[:location]||'' ,
|
256
|
+
:appointmentType => '3',
|
257
|
+
:KLCategories_2 => "",
|
258
|
+
:Alarms => "0",
|
259
|
+
:Logo => "StdNotesLtr14",
|
260
|
+
:BookFreeTime => "",
|
261
|
+
:Duration => 105,
|
262
|
+
:SequenceNum => 1,
|
263
|
+
:OrgTable => "CO",
|
264
|
+
:tmpOwnerHW => "1",
|
265
|
+
:WebDateTimeInit => "1",
|
266
|
+
:TimeRange => date_range.obj,
|
267
|
+
:CalendarDateTime => sdt.obj,
|
268
|
+
:startDate => sdt.obj,
|
269
|
+
:startDateTime => sdt.obj,
|
270
|
+
:startTime => sdt.obj,
|
271
|
+
:endDate => edt.obj,
|
272
|
+
:endDateTime => edt.obj,
|
273
|
+
:endTime => edt.obj,
|
274
|
+
:_ViewIcon => 9,
|
275
|
+
:Org_Table=> "")
|
276
|
+
# Call doc.ReplaceItemValue("Org_Table", ORS_ITEM_PLANNER)
|
277
|
+
# Set newitem = New NotesItem(doc,"_ViewIcon",9)
|
278
|
+
# newitem.issummary = True
|
279
|
+
# doc.PostedDate = Now
|
280
|
+
target.obj.CopyItem( p[:body], "" ) if p[:body]
|
281
|
+
target.ComputeWithForm false, false
|
282
|
+
target.save(true, false)
|
283
|
+
target
|
284
|
+
end
|
285
|
+
|
286
|
+
def copy(destination)
|
287
|
+
server, path = destination.split("!!")
|
288
|
+
new(obj.CreateReplica( server, path ))
|
289
|
+
end
|
290
|
+
|
291
|
+
def move(destination)
|
292
|
+
target = copy(destination)
|
293
|
+
obj.Remove
|
294
|
+
@obj = nil
|
295
|
+
target
|
296
|
+
end
|
297
|
+
|
298
|
+
# finds document by noteid or unid
|
299
|
+
def find(id)
|
300
|
+
if id.length == 32
|
301
|
+
Document.new(obj.getdocumentbyunid(id))
|
302
|
+
else
|
303
|
+
Document.new(obj.getdocumentbyid(id))
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
def by( f=:Form, s=nil)
|
308
|
+
field = f.to_s
|
309
|
+
h = Hash.new { |hash, key| hash[key] = 0 }
|
310
|
+
(s ? search(s) : all_documents).each do |d|
|
311
|
+
h[d.getItemValue(field)[0]] += 1 unless d.isDeleted
|
312
|
+
end
|
313
|
+
puts "-----------------------------"
|
314
|
+
h.keys.sort.each{|k| puts "%10s %10d"%[k,h[k]]}
|
315
|
+
h
|
316
|
+
# while dc.count > 0
|
317
|
+
# doc = dc.GetFirstDocument
|
318
|
+
# value = doc.getitemValue(field)[0]
|
319
|
+
# dc_sub = search("#{field}='#{value}'")
|
320
|
+
# h[field] = dc_sub.count
|
321
|
+
# dc.obj.Subtract( dc_sub ) # doesn't work
|
322
|
+
# end
|
323
|
+
end
|
324
|
+
|
325
|
+
def first
|
326
|
+
all.first
|
327
|
+
end
|
328
|
+
|
329
|
+
def last
|
330
|
+
all.last
|
331
|
+
end
|
332
|
+
|
333
|
+
FLAGS = {
|
334
|
+
'4' => :allow_soft_deletes_,
|
335
|
+
'Z' => :enable_lz1_compression,
|
336
|
+
'f' => :do_not_allow_stored_forms,
|
337
|
+
'z' => :do_not_maintain_unread_marks,
|
338
|
+
'h' => :mark_parent_document_on_reply_or_forward,
|
339
|
+
'J' => :use_javascript_when_generating_web_pages,
|
340
|
+
'n' => :never_show_policy_never_show_about_database_when_first_opened,
|
341
|
+
'7' => :large_unk_table_allow_more_fields_in_database,
|
342
|
+
'6' => :allow_design_locking,
|
343
|
+
'K' => :restore_as_lasted_viewed_by_user,
|
344
|
+
'c' => :show_about_database_if_modified,
|
345
|
+
'Q' => :replicate_unread_marks_to_clustered_servers_only,
|
346
|
+
'U' => :replicate_unread_marks_to_all_servers_appears_with_q_set,
|
347
|
+
'2' => :optimise_document_table_bitmap,
|
348
|
+
'3' => :maintain_lastaccessed_property,
|
349
|
+
'1' => :dont_support_specialised_response_hierarchy,
|
350
|
+
'M' => :multilingual_database,
|
351
|
+
'X' => :web_access_requires_ssl_connection,
|
352
|
+
'8' => :web_access_dont_allow_url_open,
|
353
|
+
'i' => :display_images_after_loading,
|
354
|
+
'5' => :allow_document_locking,
|
355
|
+
'g' => :database_type_library,
|
356
|
+
'j' => :database_type_personal_journal,
|
357
|
+
'b' => :database_type_domino_directory,
|
358
|
+
'B' => :database_type_directory_catalog,
|
359
|
+
'm' => :database_type_multi_db_search,
|
360
|
+
'u' => :database_type_portfolio,
|
361
|
+
'A' => :database_type_mailbox,
|
362
|
+
'r' => :database_type_mailfile,
|
363
|
+
'p' => :always_show_about_database_document_when_opened_in_the_client_property,
|
364
|
+
'F' => :launch_designated_frameset,
|
365
|
+
'l' => :launch_designated_navigator,
|
366
|
+
's' => :launch_designated_navigator_in_own_window_used_in_conjuction_with_l_above,
|
367
|
+
'a' => :launch_first_attachment_in_about_database_document,
|
368
|
+
'd' => :launch_first_doclink_in_about_database_document,
|
369
|
+
'P' => :web_launch_show_about_database_document,
|
370
|
+
'S' => :web_launch_open_designated_frameset,
|
371
|
+
'E' => :web_launch_open_designated_page,
|
372
|
+
'L' => :web_launch_open_designated_navigator_in_its_own_window,
|
373
|
+
'D' => :web_launch_open_first_doclink_in_about_database_document,
|
374
|
+
'T' => :web_launch_open_designated_doclink,
|
375
|
+
'V' => :web_launch_open_first_document_in_designated_view
|
376
|
+
}
|
377
|
+
|
378
|
+
end
|
379
|
+
|
380
|
+
end
|