rdomino 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|