Name | Total Lines | Lines of Code | Total Coverage | Code Coverage |
---|---|---|---|---|
/home/masa/ywesee/oddb.org/src/util/oddbapp.rb | 1857 | 1800 | 87.94%
|
87.72%
|
Code reported as executed by Ruby looks like this...and this: this line is also marked as covered.Lines considered as run by rcov, but not reported by Ruby, look like this,and this: these lines were inferred by rcov (using simple heuristics).Finally, here's a line marked as not executed.
1 #!/usr/bin/env ruby |
2 # OddbApp -- oddb -- hwyss@ywesee.com |
3 |
4 require 'odba' |
5 require 'odba/index_definition' |
6 require 'odba/drbwrapper' |
7 require 'odba/18_19_loading_compatibility' |
8 require 'custom/lookandfeelbase' |
9 require 'util/currency' |
10 require 'util/failsafe' |
11 require 'util/ipn' |
12 require 'util/oddbconfig' |
13 require 'util/searchterms' |
14 require 'util/session' |
15 require 'util/updater' |
16 require 'util/exporter' |
17 require 'util/validator' |
18 require 'util/loggroup' |
19 require 'util/soundex' |
20 require 'util/iso-latin1' |
21 require 'util/notification_logger' |
22 require 'util/ngram_similarity' |
23 require 'util/today' |
24 require 'models' |
25 require 'commands' |
26 require 'paypal' |
27 require 'sbsm/drbserver' |
28 require 'sbsm/index' |
29 require 'util/config' |
30 require 'fileutils' |
31 require 'yaml' |
32 require 'yus/session' |
33 require 'model/migel/group' |
34 require 'model/analysis/group' |
35 |
36 class OddbPrevalence |
37 include ODDB::Failsafe |
38 include ODBA::Persistable |
39 RESULT_SIZE_LIMIT = 250 |
40 ODBA_EXCLUDE_VARS = [ |
41 "@atc_chooser", "@bean_counter", "@sorted_fachinfos", "@sorted_feedbacks", |
42 "@sorted_minifis", |
43 ] |
44 ODBA_SERIALIZABLE = [ '@currency_rates', '@rss_updates' ] |
45 attr_reader :address_suggestions, :atc_chooser, :atc_classes, :analysis_groups, |
46 :companies, :doctors, :fachinfos, :galenic_groups, :migel_groups, |
47 :hospitals, :invoices, :last_medication_update, :last_update, |
48 :minifis, :notification_logger, :orphaned_fachinfos, |
49 :orphaned_patinfos, :patinfos, :patinfos_deprived_sequences, |
50 :registrations, :slates, :users, :narcotics, :accepted_orphans, |
51 :commercial_forms, :rss_updates, :feedbacks, :indices_therapeutici, |
52 :generic_groups |
53 def initialize |
54 init |
55 @last_medication_update ||= Time.now() |
56 end |
57 def init |
58 create_unknown_galenic_group() |
59 @accepted_orphans ||= {} |
60 @address_suggestions ||= {} |
61 @analysis_groups ||= {} |
62 @atc_classes ||= {} |
63 @commercial_forms ||= {} |
64 @companies ||= {} |
65 @currency_rates ||= {} |
66 @cyp450s ||= {} |
67 @doctors ||= {} |
68 @fachinfos ||= {} |
69 @feedbacks ||= {} |
70 @galenic_forms ||= [] |
71 @galenic_groups ||= [] |
72 @generic_groups ||= {} |
73 @hospitals ||= {} |
74 @indications ||= {} |
75 @indices_therapeutici ||= {} |
76 @invoices ||= {} |
77 @log_groups ||= {} |
78 @migel_groups ||= {} |
79 @minifis ||= {} |
80 @narcotics ||= {} |
81 @notification_logger ||= ODDB::NotificationLogger.new |
82 @orphaned_fachinfos ||= {} |
83 @orphaned_patinfos ||= {} |
84 @patinfos ||= {} |
85 @patinfos_deprived_sequences ||= [] |
86 @registrations ||= {} |
87 @rss_updates ||= {} |
88 @slates ||= {} |
89 @sponsors ||= {} |
90 @substances ||= {} |
91 #recount() |
92 rebuild_atc_chooser() |
93 end |
94 # prevalence-methods ################################ |
95 def create(pointer) |
96 @last_update = Time.now() |
97 failsafe { |
98 if(item = pointer.issue_create(self)) |
99 updated(item) |
100 item |
101 end |
102 } |
103 end |
104 def delete(pointer) |
105 @last_update = Time.now() |
106 failsafe(ODDB::Persistence::UninitializedPathError) { |
107 if(item = pointer.resolve(self)) |
108 updated(item) |
109 end |
110 pointer.issue_delete(self) |
111 } |
112 end |
113 def update(pointer, values, origin=nil) |
114 #puts [__FILE__,__LINE__,"update(#{pointer}, #{values})"].join(':') |
115 @last_update = Time.now() |
116 item = nil |
117 failsafe(ODDB::Persistence::UninitializedPathError, nil) { |
118 item = pointer.issue_update(self, values, origin) |
119 updated(item) unless(item.nil?) |
120 } |
121 item |
122 end |
123 def clean_odba_stubs |
124 _clean_odba_stubs_hash(@substances) |
125 @substances.each_value { |sub| _clean_odba_stubs_array(sub.sequences) } |
126 _clean_odba_stubs_hash(@atc_classes) |
127 @atc_classes.each_value { |atc| _clean_odba_stubs_array(atc.sequences) } |
128 _clean_odba_stubs_hash(@registrations) |
129 @registrations.each_value { |reg| |
130 _clean_odba_stubs_hash(reg.sequences) |
131 reg.sequences.each_value { |seq| |
132 _clean_odba_stubs_hash(seq.packages) |
133 _clean_odba_stubs_array(seq.active_agents) |
134 } |
135 } |
136 end |
137 def _clean_odba_stubs_hash(hash) |
138 if(hash.values.any? { |val| val.odba_instance.nil? }) |
139 hash.delete_if { |key, val| val.odba_instance.nil? } |
140 hash.odba_store |
141 end |
142 end |
143 def _clean_odba_stubs_array(array) |
144 if(array.any? { |val| val.odba_instance.nil? }) |
145 array.delete_if { |val| val.odba_instance.nil? } |
146 array.odba_store |
147 end |
148 end |
149 ##################################################### |
150 def admin(oid) |
151 @users[oid.to_i] |
152 end |
153 def admin_subsystem |
154 ODBA.cache.fetch_named('admin', self) { |
155 ODDB::Admin::Subsystem.new |
156 } |
157 end |
158 def active_fachinfos |
159 active = {} |
160 @registrations.each_value { |reg| |
161 if(reg.active? && reg.fachinfo) |
162 active.store(reg.pointer, 1) |
163 end |
164 } |
165 active |
166 end |
167 def active_pdf_patinfos |
168 active = {} |
169 each_sequence { |seq| |
170 if(str = seq.active_patinfo) |
171 active.store(str, 1) |
172 end |
173 } |
174 active |
175 end |
176 def address_suggestion(oid) |
177 @address_suggestions[oid.to_i] |
178 end |
179 def analysis_group(grpcd) |
180 @analysis_groups[grpcd] |
181 end |
182 def analysis_positions |
183 @analysis_groups.values.inject([]) { |memo, group| |
184 memo.concat(group.positions.values) |
185 } |
186 end |
187 def atcless_sequences |
188 ODBA.cache.retrieve_from_index('atcless', 'true') |
189 end |
190 def atc_class(code) |
191 @atc_classes[code] |
192 end |
193 def atc_ddd_count |
194 @atc_ddd_count ||= count_atc_ddd() |
195 end |
196 def clean_invoices |
197 @invoices.delete_if { |oid, invoice| invoice.odba_instance.nil? } |
198 deletables = @invoices.values.select { |invoice| |
199 invoice.deletable? |
200 } |
201 unless(deletables.empty?) |
202 deletables.each { |invoice| |
203 delete(invoice.pointer) |
204 } |
205 @invoices.odba_isolated_store |
206 end |
207 end |
208 def commercial_form(oid) |
209 @commercial_forms[oid.to_i] |
210 end |
211 def commercial_form_by_name(name) |
212 ODDB::CommercialForm.find_by_name(name) |
213 end |
214 def company(oid) |
215 @companies[oid.to_i] |
216 end |
217 def company_by_name(name, ngram_cutoff=nil) |
218 _company_by_name(name, ngram_cutoff) \ |
219 || _company_by_name(name, ngram_cutoff, /\s*(ag|gmbh|sa)\b/i) |
220 end |
221 def _company_by_name(name, ngram_cutoff=nil, filter=nil) |
222 namedown = name.to_s.downcase |
223 if filter |
224 namedown.gsub! filter, '' |
225 end |
226 @companies.each_value { |company| |
227 name = company.name.to_s.downcase |
228 if filter |
229 name.gsub! filter, '' |
230 end |
231 if name == namedown \ |
232 || (ngram_cutoff \ |
233 && ODDB::Util::NGramSimilarity.compare(name, namedown) > ngram_cutoff) |
234 return company |
235 end |
236 } |
237 nil |
238 end |
239 def company_count |
240 @company_count ||= @companies.size |
241 end |
242 def config(*args) |
243 if(@config.nil?) |
244 @config = ODDB::Config.new |
245 @config.pointer = ODDB::Persistence::Pointer.new(:config) |
246 self.odba_store |
247 end |
248 hook = @config |
249 args.each { |arg| |
250 conf = hook.send(arg) |
251 if(conf.nil?) |
252 conf = hook.send("create_#{arg}") |
253 conf.pointer = hook.pointer + arg |
254 hook.odba_store |
255 end |
256 hook = conf |
257 } |
258 hook |
259 end |
260 def count_atc_ddd |
261 @atc_classes.values.inject(0) { |inj, atc| |
262 inj += 1 if(atc.has_ddd?) |
263 inj |
264 } |
265 end |
266 def count_limitation_texts |
267 @registrations.values.inject(0) { |inj,reg| |
268 inj + reg.limitation_text_count |
269 } |
270 end |
271 def count_packages |
272 @registrations.values.inject(0) { |inj, reg| |
273 inj + reg.active_package_count |
274 } |
275 end |
276 def count_patinfos |
277 @patinfos.size + active_pdf_patinfos.size |
278 end |
279 def count_recent_registrations |
280 if((grp = log_group(:swissmedic) || log_group(:swissmedic_journal)) \ |
281 && (log = grp.latest)) |
282 log.change_flags.select { |ptr, flags| |
283 flags.include?(:new) |
284 }.size |
285 else |
286 0 |
287 end |
288 end |
289 def count_vaccines |
290 @registrations.values.inject(0) { |inj, reg| |
291 if(reg.vaccine) |
292 inj += reg.active_package_count |
293 end |
294 inj |
295 } |
296 end |
297 def cyp450(id) |
298 @cyp450s[id] |
299 end |
300 def cyp450s |
301 @cyp450s.values |
302 end |
303 def create_analysis_group(groupcd) |
304 group = ODDB::Analysis::Group.new(groupcd) |
305 @analysis_groups.store(groupcd, group) |
306 end |
307 def create_atc_class(atc_class) |
308 atc = ODDB::AtcClass.new(atc_class) |
309 @atc_chooser.add_offspring(ODDB::AtcNode.new(atc)) |
310 @atc_classes.store(atc_class, atc) |
311 end |
312 def create_commercial_form |
313 form = ODDB::CommercialForm.new |
314 @commercial_forms.store(form.oid, form) |
315 end |
316 def create_company |
317 company = ODDB::Company.new |
318 @companies.store(company.oid, company) |
319 end |
320 def create_doctor |
321 doctor = ODDB::Doctor.new |
322 @doctors ||= {} |
323 @doctors.store(doctor.oid, doctor) |
324 end |
325 def create_hospital(ean13) |
326 hospital = ODDB::Hospital.new(ean13) |
327 @hospitals.store(ean13, hospital) |
328 end |
329 def create_cyp450(cyp_id) |
330 cyp450 = ODDB::CyP450.new(cyp_id) |
331 @cyp450s.store(cyp_id, cyp450) |
332 end |
333 def create_fachinfo |
334 fachinfo = ODDB::Fachinfo.new |
335 @fachinfos.store(fachinfo.oid, fachinfo) |
336 end |
337 def create_feedback |
338 feedback = ODDB::Feedback.new |
339 @feedbacks.store(feedback.oid, feedback) |
340 end |
341 def create_galenic_group |
342 galenic_group = ODDB::GalenicGroup.new |
343 @galenic_groups.store(galenic_group.oid, galenic_group) |
344 end |
345 def create_generic_group(package_pointer) |
346 @generic_groups.store(package_pointer, ODDB::GenericGroup.new) |
347 end |
348 def create_index_therapeuticus(code) |
349 code = code.to_s |
350 it = ODDB::IndexTherapeuticus.new(code) |
351 @indices_therapeutici.store(code, it) |
352 end |
353 def create_indication |
354 indication = ODDB::Indication.new |
355 @indications.store(indication.oid, indication) |
356 end |
357 def create_invoice |
358 invoice = ODDB::Invoice.new |
359 @invoices.store(invoice.oid, invoice) |
360 end |
361 def create_address_suggestion |
362 address = ODDB::AddressSuggestion.new |
363 @address_suggestions.store(address.oid, address) |
364 end |
365 def create_log_group(key) |
366 @log_groups[key] ||= ODDB::LogGroup.new(key) |
367 end |
368 def create_minifi |
369 minifi = ODDB::MiniFi.new |
370 @minifis.store(minifi.oid, minifi) |
371 end |
372 def create_narcotic |
373 narc = ODDB::Narcotic.new |
374 @narcotics.store(narc.oid, narc) |
375 end |
376 def create_orphaned_fachinfo |
377 @orphaned_fachinfos ||= {} |
378 orphan = ODDB::OrphanedTextInfo.new |
379 @orphaned_fachinfos.store(orphan.oid, orphan) |
380 end |
381 def create_orphaned_patinfo |
382 orphan = ODDB::OrphanedTextInfo.new |
383 @orphaned_patinfos.store(orphan.oid, orphan) |
384 end |
385 def create_patinfo |
386 patinfo = ODDB::Patinfo.new |
387 @patinfos.store(patinfo.oid, patinfo) |
388 end |
389 def create_poweruser |
390 user = ODDB::PowerUser.new |
391 @users.store(user.oid, user) |
392 end |
393 def create_registration(iksnr) |
394 unless @registrations.include?(iksnr) |
395 reg = ODDB::Registration.new(iksnr) |
396 @registrations.store(iksnr, reg) |
397 reg |
398 end |
399 end |
400 def create_slate(name) |
401 slate = ODDB::Slate.new(name) |
402 @slates.store(name, slate) |
403 end |
404 def create_sponsor(flavor) |
405 sponsor = ODDB::Sponsor.new |
406 @sponsors.store(flavor, sponsor) |
407 end |
408 def create_substance(key=nil) |
409 if(!key.nil? && (subs = substance(key))) |
410 subs |
411 else |
412 subs = ODDB::Substance.new |
413 unless(key.nil?) |
414 values = { |
415 'lt' => key, |
416 } |
417 diff = subs.diff(values, self) |
418 subs.update_values(diff) |
419 end |
420 @substances.store(subs.oid, subs) |
421 end |
422 end |
423 def create_user |
424 @users ||= {} |
425 user = ODDB::CompanyUser.new |
426 @users.store(user.oid, user) |
427 end |
428 def currencies |
429 @currency_rates.keys.sort |
430 end |
431 def create_migel_group(groupcd) |
432 migel = ODDB::Migel::Group.new(groupcd) |
433 @migel_groups.store(groupcd, migel) |
434 end |
435 def analysis_count |
436 @analysis_count ||= analysis_positions.size |
437 end |
438 def delete_address_suggestion(oid) |
439 if(sug = @address_suggestions.delete(oid)) |
440 @address_suggestions.odba_isolated_store |
441 sug |
442 end |
443 end |
444 def delete_atc_class(atccode) |
445 atc = @atc_classes[atccode] |
446 @atc_chooser.delete(atccode) |
447 if(@atc_classes.delete(atccode)) |
448 @atc_classes.odba_isolated_store |
449 end |
450 atc |
451 end |
452 def delete_cyp450(cyp_id) |
453 if(cyp = @cyp450s.delete(cyp_id)) |
454 @cyp450s.odba_isolated_store |
455 cyp |
456 end |
457 end |
458 def delete_commercial_form(oid) |
459 if(form = @commercial_forms.delete(oid)) |
460 @commercial_forms.odba_isolated_store |
461 form |
462 end |
463 end |
464 def delete_company(oid) |
465 if(comp = @companies.delete(oid)) |
466 @companies.odba_isolated_store |
467 comp |
468 end |
469 end |
470 def delete_doctor(oid) |
471 if(doc = @doctors.delete(oid.to_i)) |
472 @doctors.odba_isolated_store |
473 doc |
474 end |
475 end |
476 def delete_fachinfo(oid) |
477 if(fi = @fachinfos.delete(oid)) |
478 @fachinfos.odba_isolated_store |
479 fi |
480 end |
481 end |
482 def delete_galenic_group(oid) |
483 group = galenic_group(oid) |
484 unless (group.nil? || group.empty?) |
485 raise 'e_nonempty_galenic_group' |
486 end |
487 if(grp = @galenic_groups.delete(oid.to_i)) |
488 @galenic_groups.odba_isolated_store |
489 grp |
490 end |
491 end |
492 def delete_index_therapeuticus(code) |
493 code = code.to_s |
494 if(it = @indices_therapeutici.delete(code)) |
495 @indices_therapeutici.odba_isolated_store |
496 it |
497 end |
498 end |
499 def delete_indication(oid) |
500 if(ind = @indications.delete(oid)) |
501 @indications.odba_isolated_store |
502 ind |
503 end |
504 end |
505 def delete_invoice(oid) |
506 if(inv = @invoices.delete(oid)) |
507 @invoices.odba_isolated_store |
508 inv |
509 end |
510 end |
511 def delete_migel_group(code) |
512 if(grp = @migel_groups[code]) |
513 @migel_groups.odba_isolated_store |
514 grp |
515 end |
516 end |
517 def delete_minifi(oid) |
518 if(minifi = @minifis.delete(oid.to_i)) |
519 @minifis.odba_isolated_store |
520 minifi |
521 end |
522 end |
523 def delete_orphaned_fachinfo(oid) |
524 if(fi = @orphaned_fachinfos.delete(oid.to_i)) |
525 @orphaned_fachinfos.odba_isolated_store |
526 fi |
527 end |
528 end |
529 def delete_orphaned_patinfo(oid) |
530 if(pi = @orphaned_patinfos.delete(oid.to_i)) |
531 @orphaned_patinfos.odba_isolated_store |
532 pi |
533 end |
534 end |
535 def delete_patinfo(oid) |
536 if(fi = @patinfos.delete(oid)) |
537 @patinfos.odba_isolated_store |
538 fi |
539 end |
540 end |
541 def delete_registration(iksnr) |
542 if(reg = @registrations.delete(iksnr)) |
543 @registrations.odba_isolated_store |
544 reg |
545 end |
546 end |
547 def delete_substance(key) |
548 substance = nil |
549 if(key.to_i.to_s == key.to_s) |
550 substance = @substances.delete(key.to_i) |
551 else |
552 substance = @substances.delete(key.to_s.downcase) |
553 end |
554 if(substance) |
555 @substances.odba_isolated_store |
556 substance |
557 end |
558 end |
559 def doctor(oid) |
560 @doctors[oid.to_i] |
561 end |
562 def hospital(ean13) |
563 @hospitals[ean13] |
564 end |
565 def hospital_count |
566 @hospitals.size |
567 end |
568 def doctor_count |
569 @doctor_count ||= @doctors.size |
570 end |
571 def doctor_by_origin(origin_db, origin_id) |
572 # values.each instead of each_value for testing |
573 @doctors.values.each { |doctor| |
574 if(doctor.record_match?(origin_db, origin_id)) |
575 return doctor |
576 end |
577 } |
578 nil |
579 end |
580 def each_atc_class(&block) |
581 @atc_classes.each_value(&block) |
582 end |
583 def each_galenic_form(&block) |
584 @galenic_groups.each_value { |galgroup| |
585 galgroup.each_galenic_form(&block) |
586 } |
587 end |
588 def each_migel_product(&block) |
589 @migel_groups.each_value { |group| |
590 group.subgroups.each_value { |subgr| |
591 subgr.products.each_value(&block) |
592 } |
593 } |
594 end |
595 def each_package(&block) |
596 @registrations.each_value { |reg| |
597 reg.each_package(&block) |
598 } |
599 end |
600 def each_sequence(&block) |
601 @registrations.each_value { |reg| |
602 reg.each_sequence(&block) |
603 } |
604 end |
605 def execute_command(command) |
606 command.execute(self) |
607 end |
608 def fachinfo(oid) |
609 @fachinfos[oid.to_i] |
610 end |
611 def fachinfo_count |
612 @fachinfos.size |
613 end |
614 def fachinfos_by_name(name, lang) |
615 if(lang.to_s != "fr") |
616 lang = "de" |
617 end |
618 ODBA.cache.retrieve_from_index("fachinfo_name_#{lang}", |
619 name) |
620 end |
621 def feedback(id) |
622 @feedbacks[id.to_i] |
623 end |
624 def galenic_form(name) |
625 @galenic_groups.values.collect { |galenic_group| |
626 galenic_group.get_galenic_form(name) |
627 }.compact.first |
628 end |
629 def galenic_group(oid) |
630 @galenic_groups[oid.to_i] |
631 end |
632 def generic_group(package_pointer) |
633 @generic_groups[package_pointer] |
634 end |
635 def get_currency_rate(symbol) |
636 ODDB::Currency.rate('CHF', symbol) |
637 end |
638 def index_therapeuticus(code) |
639 @indices_therapeutici[code.to_s] |
640 end |
641 def indication(oid) |
642 @indications[oid.to_i] |
643 end |
644 def indication_by_text(text) |
645 @indications.values.select { |indication| |
646 indication.has_description?(text) |
647 }.first |
648 end |
649 def indications |
650 @indications.values |
651 end |
652 def invoice(oid) |
653 @invoices ||= {} |
654 @invoices[oid.to_i] |
655 end |
656 def limitation_text_count |
657 @limitation_text_count ||= count_limitation_texts() |
658 end |
659 def log_group(key) |
660 @log_groups[key] |
661 end |
662 def migel_count |
663 @migel_count ||= migel_products.size |
664 end |
665 def migel_group(groupcd) |
666 @migel_groups[groupcd] |
667 end |
668 def migel_product(code) |
669 parts = code.split('.', 3) |
670 migel_group(parts[0]).subgroup(parts[1]).product(parts[2]) |
671 rescue NoMethodError |
672 # invalid migel_code |
673 nil |
674 end |
675 def migel_products |
676 products = [] |
677 @migel_groups.each_value { |group| |
678 group.subgroups.each_value { |subgr| |
679 products.concat(subgr.products.values) |
680 } |
681 } |
682 products |
683 end |
684 def minifi(oid) |
685 @minifis[oid.to_i] |
686 end |
687 def narcotic(odba_id) |
688 @narcotics[odba_id.to_i] |
689 end |
690 def narcotic_by_casrn(casrn) |
691 unless(casrn.nil?) |
692 @narcotics.values.find do |narc| narc.casrn == casrn end |
693 end |
694 end |
695 def narcotic_by_smcd(smcd) |
696 unless(smcd.nil?) |
697 @narcotics.values.find do |narc| narc.swissmedic_codes.include?(smcd) end |
698 end |
699 end |
700 def narcotics_count |
701 @narcotics.size |
702 end |
703 def orphaned_fachinfo(oid) |
704 @orphaned_fachinfos[oid.to_i] |
705 end |
706 def orphaned_patinfo(oid) |
707 @orphaned_patinfos[oid.to_i] |
708 end |
709 def package(pcode) |
710 ODDB::Package.find_by_pharmacode(pcode.to_s.gsub(/^0+/u, '')) |
711 end |
712 def package_by_ikskey(ikskey) |
713 ikskey = ikskey.to_s |
714 iksnr = "%05i" % ikskey[-8..-4].to_i |
715 ikscd = ikskey[-3..-1] |
716 if reg = registration(iksnr) |
717 reg.package ikscd |
718 end |
719 end |
720 def package_count |
721 @package_count ||= count_packages() |
722 end |
723 def packages |
724 @registrations.inject([]) { |pacs, (iksnr,reg)| |
725 pacs.concat(reg.packages) |
726 } |
727 end |
728 def patinfo(oid) |
729 @patinfos[oid.to_i] |
730 end |
731 def patinfo_count |
732 @patinfo_count ||= count_patinfos() |
733 end |
734 def poweruser(oid) |
735 @users[oid.to_i] |
736 end |
737 def rebuild_atc_chooser |
738 chooser = ODDB::AtcNode.new(nil) |
739 @atc_classes.sort.each { |key, atc| |
740 chooser.add_offspring(ODDB::AtcNode.new(atc)) |
741 } |
742 @atc_chooser = chooser |
743 end |
744 def recent_registration_count |
745 @recent_registration_count ||= count_recent_registrations() |
746 end |
747 def recount |
748 again = true |
749 if(@bean_counter.is_a?(Thread) && @bean_counter.status) |
750 return again = true |
751 end |
752 @bean_counter = Thread.new { |
753 while(again) |
754 again = false |
755 @analysis_count = analysis_positions.size |
756 @atc_ddd_count = count_atc_ddd() |
757 @doctor_count = @doctors.size |
758 @company_count = @companies.size |
759 @substance_count = @substances.size |
760 @limitation_text_count = count_limitation_texts() |
761 @migel_count = migel_products.size |
762 @package_count = count_packages() |
763 @patinfo_count = count_patinfos() |
764 @recent_registration_count = count_recent_registrations() |
765 @vaccine_count = count_vaccines() |
766 self.odba_isolated_store |
767 end |
768 } |
769 end |
770 def registration(registration_id) |
771 @registrations[registration_id] |
772 end |
773 def resolve(pointer) |
774 pointer.resolve(self) |
775 end |
776 def refactor_addresses |
777 # 3 Iterationen |
778 puts "refactoring doctors" |
779 $stdout.flush |
780 @doctors.each_value { |doc| |
781 doc.refactor_addresses |
782 doc.odba_store |
783 } |
784 puts "refactoring hospitals" |
785 $stdout.flush |
786 @hospitals.each_value { |spi| |
787 spi.refactor_addresses |
788 spi.odba_store |
789 } |
790 puts "refactoring companies" |
791 $stdout.flush |
792 @companies.each_value { |comp| |
793 comp.refactor_addresses |
794 comp.odba_store |
795 } |
796 puts "finished refactoring addresses" |
797 $stdout.flush |
798 end |
799 def search_analysis(key, lang) |
800 if(lang == 'en') |
801 lang = 'de' |
802 end |
803 ODBA.cache.retrieve_from_index("analysis_index_#{lang}", key) |
804 end |
805 def search_analysis_alphabetical(query, lang) |
806 if(lang == 'en') |
807 lang = 'de' |
808 end |
809 index_name = "analysis_alphabetical_index_#{lang}" |
810 ODBA.cache.retrieve_from_index(index_name, query) |
811 end |
812 @@iks_or_ean = /(?:\d{4})?(\d{5})(?:\d{4})?/u |
813 def search_oddb(query, lang) |
814 # current search_order: |
815 # 1. atcless |
816 # 2. iksnr or ean13 |
817 # 3. atc-code |
818 # 4. exact word in sequence name |
819 # 5. company-name |
820 # 6. substance |
821 # 7. indication |
822 # 8. sequence |
823 result = ODDB::SearchResult.new |
824 result.exact = true |
825 result.search_query = query |
826 # atcless |
827 if(query == 'atcless') |
828 atc = ODDB::AtcClass.new('n.n.') |
829 atc.sequences = atcless_sequences |
830 atc.instance_eval { |
831 alias :active_packages :packages |
832 } |
833 result.atc_classes = [atc] |
834 result.search_type = :atcless |
835 return result |
836 end |
837 # iksnr or ean13 |
838 if(match = @@iks_or_ean.match(query)) |
839 iksnr = match[1] |
840 if(reg = registration(iksnr)) |
841 atc = ODDB::AtcClass.new('n.n.') |
842 atc.sequences = reg.sequences.values |
843 result.atc_classes = [atc] |
844 result.search_type = :iksnr |
845 return result |
846 end |
847 end |
848 # pharmacode |
849 if(match = /^\d{6,}$/u.match(query)) |
850 if(pac = package(query)) |
851 atc = ODDB::AtcClass.new('n.n.') |
852 seq = ODDB::Sequence.new(pac.sequence.seqnr) |
853 seq.registration = pac.registration |
854 seq.packages.store pac.ikscd, pac |
855 atc.sequences = [seq] |
856 result.atc_classes = [atc] |
857 result.search_type = :pharmacode |
858 return result |
859 end |
860 end |
861 key = query.to_s.downcase |
862 # atc-code |
863 atcs = search_by_atc(key) |
864 result.search_type = :atc |
865 result.error_limit = RESULT_SIZE_LIMIT |
866 # exact word in sequence name |
867 if(atcs.empty?) |
868 atcs = search_by_sequence(key, result) |
869 result.search_type = :sequence |
870 end |
871 # company-name |
872 if(atcs.empty?) |
873 atcs = search_by_company(key) |
874 result.search_type = :company |
875 end |
876 # substance |
877 if(atcs.empty?) |
878 atcs = search_by_substance(key) |
879 result.search_type = :substance |
880 end |
881 # indication |
882 if(atcs.empty?) |
883 atcs = search_by_indication(key, lang, result) |
884 result.search_type = :indication |
885 end |
886 # sequence |
887 if(atcs.empty?) |
888 atcs = search_by_sequence(key) |
889 result.search_type = :sequence |
890 end |
891 result.atc_classes = atcs |
892 # interaction |
893 if(atcs.empty?) |
894 result = search_by_interaction(key, lang) |
895 end |
896 # unwanted effects |
897 if(result.atc_classes.empty?) |
898 result = search_by_unwanted_effect(key, lang) |
899 end |
900 result |
901 end |
902 def search_by_atc(key) |
903 ODBA.cache.retrieve_from_index('atc_index', key.dup) |
904 end |
905 def search_by_company(key) |
906 result = ODDB::SearchResult.new |
907 result.error_limit = RESULT_SIZE_LIMIT |
908 atcs = ODBA.cache.retrieve_from_index('atc_index_company', key.dup, result) |
909 filtered = atcs.collect { |atc| |
910 atc.company_filter_search(key.dup) |
911 } |
912 filtered.flatten.compact.uniq |
913 end |
914 def search_by_indication(key, lang, result) |
915 if(lang.to_s != "fr") |
916 lang = "de" |
917 end |
918 atcs = ODBA.cache.\ |
919 retrieve_from_index("fachinfo_index_#{lang}", key.dup, result) |
920 atcs += ODBA.cache.\ |
921 retrieve_from_index("indication_index_atc_#{lang}", |
922 key.dup, result) |
923 atcs.uniq |
924 end |
925 def search_by_sequence(key, result=nil) |
926 ODBA.cache.retrieve_from_index('sequence_index_atc', key.dup, result) |
927 end |
928 def search_by_interaction(key, lang) |
929 result = ODDB::SearchResult.new |
930 result.error_limit = RESULT_SIZE_LIMIT |
931 if(lang.to_s != "fr") |
932 lang = "de" |
933 end |
934 sequences = ODBA.cache.retrieve_from_index("interactions_index_#{lang}", |
935 key, result) |
936 key = key.downcase |
937 sequences.reject! { |seq| |
938 ODDB.search_terms(seq.search_terms, :downcase => true).include?(key) \ |
939 || seq.substances.any? { |sub| |
940 sub.search_keys.any? { |skey| skey.downcase.include?(key) } |
941 } |
942 } |
943 _search_exact_classified_result(sequences, :interaction, result) |
944 end |
945 def search_by_substance(key) |
946 ODBA.cache.retrieve_from_index('substance_index_atc', key.dup) |
947 end |
948 def search_by_unwanted_effect(key, lang) |
949 result = ODDB::SearchResult.new |
950 if(lang.to_s != "fr") |
951 lang = "de" |
952 end |
953 sequences = ODBA.cache.retrieve_from_index("unwanted_effects_index_#{lang}", |
954 key, result) |
955 _search_exact_classified_result(sequences, :unwanted_effect, result) |
956 end |
957 def search_doctors(key) |
958 ODBA.cache.retrieve_from_index("doctor_index", key) |
959 end |
960 def search_companies(key) |
961 ODBA.cache.retrieve_from_index("company_index", key) |
962 end |
963 def search_exact_company(query) |
964 result = ODDB::SearchResult.new |
965 result.search_type = :company |
966 result.atc_classes = search_by_company(query) |
967 result |
968 end |
969 def search_exact_indication(query, lang) |
970 result = ODDB::SearchResult.new |
971 result.exact = true |
972 result.search_type = :indication |
973 result.atc_classes = search_by_indication(query, lang, result) |
974 result |
975 end |
976 def search_migel_alphabetical(query, lang) |
977 if(lang.to_s != "fr") |
978 lang = "de" |
979 end |
980 index_name = "migel_index_#{lang}" |
981 ODBA.cache.retrieve_from_index(index_name, query) |
982 end |
983 def search_migel_products(query, lang) |
984 if(lang.to_s != "fr") |
985 lang = "de" |
986 end |
987 index_name = "migel_fulltext_index_#{lang}" |
988 ODBA.cache.retrieve_from_index(index_name, query) |
989 end |
990 def search_narcotics(query, lang) |
991 if(lang.to_s != "fr") |
992 lang = "de" |
993 end |
994 index_name = "narcotics_#{lang}" |
995 ODBA.cache.retrieve_from_index(index_name, query) |
996 end |
997 def search_patinfos(query) |
998 ODBA.cache.retrieve_from_index('sequence_patinfos', query) |
999 end |
1000 def search_vaccines(query) |
1001 ODBA.cache.retrieve_from_index('sequence_vaccine', query) |
1002 end |
1003 def search_exact_sequence(query) |
1004 sequences = search_sequences(query) |
1005 _search_exact_classified_result(sequences, :sequence) |
1006 end |
1007 def search_exact_substance(query) |
1008 sequences = ODBA.cache.\ |
1009 retrieve_from_index('substance_index_sequence', query) |
1010 _search_exact_classified_result(sequences, :substance) |
1011 end |
1012 def _search_exact_classified_result(sequences, type=:unknown, result=nil) |
1013 atc_classes = {} |
1014 sequences.each { |seq| |
1015 code = (atc = seq.atc_class) ? atc.code : 'n.n' |
1016 new_atc = atc_classes.fetch(code) { |
1017 atc_class = ODDB::AtcClass.new(code) |
1018 atc_class.descriptions = atc.descriptions unless(atc.nil?) |
1019 atc_classes.store(code, atc_class) |
1020 } |
1021 new_atc.sequences.push(seq) |
1022 } |
1023 result ||= ODDB::SearchResult.new |
1024 result.search_type = type |
1025 result.atc_classes = atc_classes.values |
1026 result |
1027 end |
1028 def search_hospitals(key) |
1029 ODBA.cache.retrieve_from_index("hospital_index", key) |
1030 end |
1031 def search_indications(query) |
1032 ODBA.cache.retrieve_from_index("indication_index", query) |
1033 end |
1034 def search_interactions(query) |
1035 result = ODBA.cache.retrieve_from_index("sequence_index_substance", query) |
1036 if(subs = substance(query, false)) |
1037 result.unshift(subs) |
1038 end |
1039 if(result.empty?) |
1040 result = soundex_substances(query) |
1041 end |
1042 result |
1043 end |
1044 def search_sequences(query, chk_all_words=true) |
1045 index = (chk_all_words) ? 'sequence_index' : 'sequence_index_exact' |
1046 ODBA.cache.retrieve_from_index(index, query) |
1047 end |
1048 def search_single_substance(key) |
1049 result = ODDB::SearchResult.new |
1050 result.exact = true |
1051 key = ODDB.search_term(key) |
1052 ODBA.cache.retrieve_from_index("substance_index", key, result).find { |sub| |
1053 sub.same_as? key |
1054 } |
1055 end |
1056 def search_substances(query) |
1057 if(subs = substance(query)) |
1058 [subs] |
1059 else |
1060 soundex_substances(query) |
1061 end |
1062 end |
1063 def sequences |
1064 @registrations.values.inject([]) { |seq, reg| |
1065 seq.concat(reg.sequences.values) |
1066 } |
1067 end |
1068 def set_currency_rate(symbol, value) |
1069 @currency_rates.store(symbol, value) |
1070 end |
1071 def slate(name) |
1072 @slates[name] |
1073 end |
1074 def soundex_substances(name) |
1075 parts = ODDB::Text::Soundex.prepare(name).split(/\s+/u) |
1076 soundex = ODDB::Text::Soundex.soundex(parts) |
1077 key = soundex.join(' ') |
1078 ODBA.cache.retrieve_from_index("substance_soundex_index", key) |
1079 end |
1080 def sorted_fachinfos |
1081 @sorted_fachinfos ||= @fachinfos.values.select { |fi| |
1082 fi.revision }.sort_by { |fi| fi.revision }.reverse |
1083 end |
1084 def sorted_feedbacks |
1085 @sorted_feedbacks ||= @feedbacks.values.sort_by { |fb| fb.time }.reverse |
1086 end |
1087 def sorted_minifis |
1088 @sorted_minifis ||= @minifis.values.sort_by { |minifi| |
1089 [ -minifi.publication_date.year, |
1090 -minifi.publication_date.month, minifi.name] } |
1091 end |
1092 def sorted_patented_registrations |
1093 @registrations.values.select { |reg| |
1094 (pat = reg.patent) && pat.expiry_date #_protected? |
1095 }.sort_by { |reg| reg.patent.expiry_date } |
1096 end |
1097 def sponsor(flavor) |
1098 @sponsors[flavor.to_s] |
1099 end |
1100 def substance(key, neurotic=false) |
1101 if(key.to_i.to_s == key.to_s) |
1102 @substances[key.to_i] |
1103 elsif(substance = search_single_substance(key)) |
1104 substance |
1105 elsif neurotic |
1106 @substances.values.find { |subs| |
1107 subs.same_as?(key) |
1108 } |
1109 end |
1110 end |
1111 def substance_by_connection_key(connection_key) |
1112 @substances.values.select { |substance| |
1113 substance.has_connection_key?(connection_key) |
1114 }.first |
1115 end |
1116 def substance_by_smcd(smcd) |
1117 @substances.values.select { |sub| |
1118 sub.swissmedic_code == smcd |
1119 }.first |
1120 end |
1121 def substances |
1122 @substances.values |
1123 end |
1124 def substance_count |
1125 @substance_count ||= @substances.size |
1126 end |
1127 def updated(item) |
1128 case item |
1129 when ODDB::Registration, ODDB::Sequence, ODDB::Package, ODDB::AtcClass |
1130 @last_medication_update = @@today |
1131 odba_isolated_store |
1132 when ODDB::LimitationText, ODDB::AtcClass::DDD |
1133 when ODDB::Substance |
1134 @substances.each_value { |subs| |
1135 if(!subs.is_effective_form? && subs.effective_form == item) |
1136 subs.odba_isolated_store |
1137 end |
1138 } |
1139 when ODDB::Fachinfo, ODDB::FachinfoDocument |
1140 @sorted_fachinfos = nil |
1141 when ODDB::Feedback |
1142 @sorted_feedbacks = nil |
1143 when ODDB::MiniFi |
1144 @sorted_minifis = nil |
1145 end |
1146 end |
1147 def user(oid) |
1148 @users[oid] |
1149 end |
1150 def user_by_email(email) |
1151 @users.values.find { |user| user.unique_email == email } |
1152 end |
1153 def unique_atc_class(substance) |
1154 atc_array = search_by_substance(substance) |
1155 =begin ## this is much too unstable, completely wrong assignment is |
1156 ## probable! |
1157 if(atc_array.size > 1) |
1158 atc_array = atc_array.select { |atc| |
1159 atc.substances.size == 1 |
1160 } |
1161 end |
1162 =end |
1163 if(atc_array.size == 1) |
1164 atc_array.first |
1165 end |
1166 end |
1167 def vaccine_count |
1168 @vaccine_count ||= count_vaccines() |
1169 end |
1170 |
1171 ## indices |
1172 def rebuild_indices(name=nil, &block) |
1173 ODBA.cache.indices.size |
1174 begin |
1175 start = Time.now |
1176 path = File.expand_path("../../etc/index_definitions.yaml", |
1177 File.dirname(__FILE__)) |
1178 FileUtils.mkdir_p(File.dirname(path)) |
1179 file = File.open(path) |
1180 YAML.load_documents(file) { |index_definition| |
1181 doit = if(name) |
1182 name.match(index_definition.index_name) |
1183 elsif(block) |
1184 block.call(index_definition) |
1185 else |
1186 true |
1187 end |
1188 if(doit) |
1189 index_start = Time.now |
1190 begin |
1191 puts "dropping: #{index_definition.index_name}" |
1192 ODBA.cache.drop_index(index_definition.index_name) |
1193 rescue StandardError => e |
1194 puts e.message |
1195 end |
1196 puts "creating: #{index_definition.index_name}" |
1197 ODBA.cache.create_index(index_definition, ODDB) |
1198 begin |
1199 puts "filling: #{index_definition.index_name}" |
1200 puts index_definition.init_source |
1201 source = instance_eval(index_definition.init_source) |
1202 puts "source.size: #{source.size}" |
1203 ODBA.cache.fill_index(index_definition.index_name, |
1204 source) |
1205 rescue StandardError => e |
1206 puts e.class |
1207 puts e.message |
1208 puts e.backtrace |
1209 end |
1210 puts "finished in #{(Time.now - index_start) / 60.0} min" |
1211 end |
1212 } |
1213 puts "all Indices Created in total: #{(Time.now - start) / 3600.0} h" |
1214 rescue StandardError => e |
1215 puts "INDEX CREATION ERROR:" |
1216 puts e.message |
1217 puts e.backtrace |
1218 ensure |
1219 file.close |
1220 end |
1221 end |
1222 def generate_dictionary(language, locale) |
1223 ODBA.storage.remove_dictionary(language) |
1224 base = File.expand_path("../../ext/fulltext/data/dicts/#{language}", |
1225 File.dirname(__FILE__)) |
1226 ODBA.storage.generate_dictionary(language, locale, base) |
1227 end |
1228 def generate_dictionaries |
1229 generate_french_dictionary |
1230 generate_german_dictionary |
1231 end |
1232 def generate_french_dictionary |
1233 generate_dictionary('french', 'fr_FR@euro') |
1234 end |
1235 def generate_german_dictionary |
1236 generate_dictionary('german', 'de_DE@euro') |
1237 end |
1238 private |
1239 def create_unknown_galenic_group |
1240 unless(@galenic_groups.is_a?(Hash) && @galenic_groups.size > 0) |
1241 @galenic_groups = {} |
1242 pointer = ODDB::Persistence::Pointer.new([:galenic_group]) |
1243 group = create(pointer) |
1244 raise "Default GalenicGroup has illegal Object ID (#{group.oid})" unless group.oid == 1 |
1245 update(group.pointer, {'de'=>'Unbekannt'}) |
1246 end |
1247 end |
1248 end |
1249 |
1250 module ODDB |
1251 class App < SBSM::DRbServer |
1252 include Failsafe |
1253 AUTOSNAPSHOT = true |
1254 CLEANING_INTERVAL = 5*60 |
1255 EXPORT_HOUR = 2 |
1256 UPDATE_HOUR = 9 |
1257 MEMORY_LIMIT = 20480 |
1258 RUN_CLEANER = true |
1259 RUN_UPDATER = true |
1260 SESSION = Session |
1261 UNKNOWN_USER = UnknownUser |
1262 UPDATE_INTERVAL = 24*60*60 |
1263 VALIDATOR = Validator |
1264 YUS_SERVER = DRb::DRbObject.new(nil, YUS_URI) |
1265 attr_reader :cleaner, :updater |
1266 def initialize opts={} |
1267 @rss_mutex = Mutex.new |
1268 @admin_threads = ThreadGroup.new |
1269 start = Time.now |
1270 @system = ODBA.cache.fetch_named('oddbapp', self){ |
1271 OddbPrevalence.new |
1272 } |
1273 puts "init system" |
1274 @system.init |
1275 @system.odba_store |
1276 puts "init system: #{Time.now - start}" |
1277 puts "setup drb-delegation" |
1278 super(@system) |
1279 return if opts[:auxiliary] |
1280 puts "reset" |
1281 reset() |
1282 puts "reset: #{Time.now - start}" |
1283 log_size |
1284 puts "system initialized" |
1285 puts "initialized: #{Time.now - start}" |
1286 end |
1287 # prevalence-methods ################################ |
1288 def accept_orphaned(orphan, pointer, symbol, origin=nil) |
1289 command = AcceptOrphan.new(orphan, pointer,symbol, origin) |
1290 @system.execute_command(command) |
1291 end |
1292 def clean |
1293 super |
1294 @system.clean_invoices |
1295 end |
1296 def create(pointer) |
1297 @system.execute_command(CreateCommand.new(pointer)) |
1298 end |
1299 def create_commercial_forms |
1300 @system.each_package { |pac| |
1301 if(comform = pac.comform) |
1302 possibilities = [ |
1303 comform.strip, |
1304 comform.gsub(/\([^\)]+\)/u, '').strip, |
1305 comform.gsub(/[()]/u, '').strip, |
1306 ].uniq.delete_if { |possibility| possibility.empty? } |
1307 cform = nil |
1308 possibilities.each { |possibility| |
1309 if(cform = CommercialForm.find_by_name(possibility)) |
1310 break |
1311 end |
1312 } |
1313 if(cform.nil?) |
1314 args = { :de => possibilities.first, |
1315 :synonyms => possibilities[1..-1] } |
1316 possibilities.each { |possibility| |
1317 if(form = @system.galenic_form(possibility)) |
1318 args = form.descriptions |
1319 args.store(:synonyms, form.synonyms) |
1320 break |
1321 end |
1322 } |
1323 pointer = Persistence::Pointer.new(:commercial_form) |
1324 cform = @system.update(pointer.creator, args) |
1325 end |
1326 pac.commercial_form = cform |
1327 pac.odba_store |
1328 end |
1329 } |
1330 end |
1331 def delete(pointer) |
1332 @system.execute_command(DeleteCommand.new(pointer)) |
1333 end |
1334 def inject_poweruser(email, pass, days) |
1335 user_pointer = Persistence::Pointer.new(:poweruser) |
1336 user_data = { |
1337 :unique_email => email, |
1338 :pass_hash => Digest::MD5.hexdigest(pass), |
1339 } |
1340 invoice_pointer = Persistence::Pointer.new(:invoice) |
1341 time = Time.now |
1342 expiry = InvoiceItem.expiry_time(days, time) |
1343 invoice_data = { :currency => State::PayPal::Checkout::CURRENCY } |
1344 item_data = { |
1345 :duration => days, |
1346 :expiry_time => expiry, |
1347 :total_netto => State::Limit.price(days.to_i), |
1348 :quantity => days, |
1349 :text => 'unlimited access', |
1350 :time => time, |
1351 :type => :poweruser, |
1352 :vat_rate => VAT_RATE, |
1353 } |
1354 user = @system.update(user_pointer.creator, user_data, :admin) |
1355 invoice = @system.update(invoice_pointer.creator, invoice_data, :admin) |
1356 item_pointer = invoice.pointer + [:item] |
1357 @system.update(item_pointer.creator, item_data, :admin) |
1358 user.add_invoice(invoice) |
1359 invoice.payment_received! |
1360 invoice.odba_isolated_store |
1361 end |
1362 def merge_commercial_forms(source, target) |
1363 command = MergeCommand.new(source.pointer, target.pointer) |
1364 @system.execute_command(command) |
1365 end |
1366 def merge_companies(source_pointer, target_pointer) |
1367 command = MergeCommand.new(source_pointer, target_pointer) |
1368 @system.execute_command(command) |
1369 end |
1370 def merge_galenic_forms(source, target) |
1371 command = MergeCommand.new(source.pointer, target.pointer) |
1372 @system.execute_command(command) |
1373 end |
1374 def merge_indications(source, target) |
1375 command = MergeCommand.new(source.pointer, target.pointer) |
1376 @system.execute_command(command) |
1377 end |
1378 def merge_substances(source_pointer, target_pointer) |
1379 command = MergeCommand.new(source_pointer, target_pointer) |
1380 @system.execute_command(command) |
1381 end |
1382 def replace_fachinfo(iksnr, pointer) |
1383 @system.execute_command(ReplaceFachinfoCommand.new(iksnr, pointer)) |
1384 end |
1385 def update(pointer, values, origin=nil) |
1386 @system.update(pointer, values, origin) |
1387 end |
1388 ##################################################### |
1389 def _admin(src, result, priority=0) |
1390 t = Thread.new { |
1391 Thread.current.abort_on_exception = false |
1392 result << failsafe { |
1393 response = instance_eval(src) |
1394 str = response.to_s |
1395 if(str.length > 200) |
1396 response.class |
1397 else |
1398 str |
1399 end |
1400 }.to_s |
1401 } |
1402 t[:source] = src |
1403 t.priority = priority |
1404 @admin_threads.add(t) |
1405 t |
1406 end |
1407 def login(email, pass) |
1408 YusUser.new(YUS_SERVER.login(email, pass, YUS_DOMAIN)) |
1409 end |
1410 def login_token(email, token) |
1411 YusUser.new(YUS_SERVER.login_token(email, token, YUS_DOMAIN)) |
1412 end |
1413 def logout(session) |
1414 YUS_SERVER.logout(session) |
1415 rescue DRb::DRbError, RangeError |
1416 end |
1417 def peer_cache cache |
1418 ODBA.peer cache |
1419 end |
1420 def reset |
1421 @random_updater.kill if(@random_updater.is_a? Thread) |
1422 if RUN_UPDATER |
1423 @random_updater = run_random_updater |
1424 end |
1425 @mutex.synchronize { |
1426 @sessions.clear |
1427 } |
1428 end |
1429 def run_random_updater |
1430 Thread.new { |
1431 Thread.current.abort_on_exception = true |
1432 update_hour = rand(24) |
1433 update_min = rand(60) |
1434 today = (update_hour > Time.now.hour) ? \ |
1435 @@today : @@today.next |
1436 loop { |
1437 next_run = Time.local(today.year, today.month, today.day, |
1438 update_hour, update_min) |
1439 puts "next random update will take place at #{next_run}" |
1440 $stdout.flush |
1441 sleep(next_run - Time.now) |
1442 Updater.new(self).run_random |
1443 @system.recount |
1444 GC.start |
1445 today = @@today.next |
1446 update_hour = rand(24) |
1447 update_min = rand(60) |
1448 } |
1449 } |
1450 end |
1451 def unpeer_cache cache |
1452 ODBA.unpeer cache |
1453 end |
1454 def update_feedback_rss_feed |
1455 async { |
1456 begin |
1457 @rss_mutex.synchronize { |
1458 values = @system.sorted_feedbacks |
1459 plg = Plugin.new(self) |
1460 plg.update_rss_feeds('feedback.rss', values, View::Rss::Feedback) |
1461 } |
1462 rescue StandardError => e |
1463 puts e.message |
1464 puts e.backtrace |
1465 end |
1466 } |
1467 end |
1468 |
1469 def ipn(notification) |
1470 Util::Ipn.process notification, self |
1471 nil # don't return the invoice back across drb - it's not defined in yipn |
1472 end |
1473 def grant_download(email, filename, price, expires=Time.now+2592000) |
1474 ip = Persistence::Pointer.new(:invoice) |
1475 inv = update ip.creator, :yus_name => email, :currency => 'EUR' |
1476 itp = inv.pointer + :item |
1477 update itp.creator, :text => filename, :price => price, :time => Time.now, |
1478 :type => :download, :expiry_time => expires, |
1479 :duration => (Time.now - expires) / 86400, |
1480 :vat_rate => 8.0 |
1481 inv.payment_received! |
1482 inv.odba_store |
1483 "http://#{SERVER_NAME}/de/gcc/download/invoice/#{inv.oid}/email/#{email}/filename/#{filename}" |
1484 end |
1485 |
1486 def assign_effective_forms(arg=nil) |
1487 _assign_effective_forms(arg) |
1488 end |
1489 def _assign_effective_forms(arg=nil) |
1490 result = nil |
1491 last = nil |
1492 @system.substances.select { |subs| |
1493 !subs.has_effective_form? && (arg.nil? || arg.to_s < subs.to_s) |
1494 }.sort_by { |subs| subs.name }.each { |subs| |
1495 puts "Looking for effective form of ->#{subs}<- (#{subs.sequences.size} Sequences)" |
1496 name = subs.to_s |
1497 parts = name.split(/\s/u) |
1498 suggest = if(parts.size == 1) |
1499 subs |
1500 elsif(![nil, '', 'Acidum'].include?(parts.first)) |
1501 @system.search_single_substance(parts.first) \ |
1502 || @system.search_single_substance(parts.first.gsub(/i$/u, 'um')) |
1503 end |
1504 last = result |
1505 result = nil |
1506 while(result.nil?) |
1507 possibles = [ |
1508 "d(elete)", |
1509 "S(elf)", |
1510 "n(othing)", |
1511 "other_name", |
1512 ] |
1513 if(suggest) |
1514 puts "Suggestion: ->#{suggest}<-" |
1515 possibles.unshift("s(uggestion)") |
1516 end |
1517 if(last) |
1518 puts "Last: ->#{last}<-" |
1519 possibles.unshift("l(ast)") |
1520 end |
1521 print possibles.join(", ") |
1522 print " > " |
1523 $stdout.flush |
1524 answer = $stdin.readline.strip |
1525 puts "you typed: ->#{answer}<-" |
1526 case answer |
1527 when '' |
1528 # do nothing |
1529 when 'l' |
1530 result = last |
1531 when 's' |
1532 result = suggest |
1533 when 'S' |
1534 result = subs |
1535 when 'd' |
1536 subs.sequences.each { |seq| |
1537 seq.delete_active_agent(subs) |
1538 seq.active_agents.odba_isolated_store |
1539 } |
1540 subs.odba_delete |
1541 break |
1542 when 'n' |
1543 break |
1544 when 'q' |
1545 return |
1546 when /c .+/u |
1547 puts "creating:" |
1548 pointer = Persistence::Pointer.new(:substance) |
1549 puts "pointer: #{pointer}" |
1550 args = { :lt => answer.split(/\s+/u, 2).last.strip } |
1551 argstr = args.collect { |*pair| pair.join(' => ') }.join(', ') |
1552 puts "args: #{argstr}" |
1553 result = @system.update(pointer.creator, args) |
1554 result.effective_form = result |
1555 result.odba_store |
1556 puts "result: #{result}" |
1557 else |
1558 result = @system.substance(answer) |
1559 end |
1560 end |
1561 if(result) |
1562 subs.effective_form = result |
1563 subs.odba_store |
1564 end |
1565 } |
1566 nil |
1567 end |
1568 |
1569 def yus_allowed?(email, action, key=nil) |
1570 YUS_SERVER.autosession(YUS_DOMAIN) { |session| |
1571 session.entity_allowed?(email, action, key) |
1572 } |
1573 end |
1574 def yus_create_user(email, pass=nil) |
1575 YUS_SERVER.autosession(YUS_DOMAIN) { |session| |
1576 session.create_entity(email, pass) |
1577 } |
1578 # if there is a password, we can log in |
1579 login(email, pass) if(pass) |
1580 end |
1581 def yus_grant(name, key, item, expires=nil) |
1582 YUS_SERVER.autosession(YUS_DOMAIN) { |session| |
1583 session.grant(name, key, item, expires) |
1584 } |
1585 end |
1586 def yus_get_preference(name, key) |
1587 YUS_SERVER.autosession(YUS_DOMAIN) { |session| |
1588 session.get_entity_preference(name, key) |
1589 } |
1590 rescue Yus::YusError |
1591 # user not found |
1592 end |
1593 def yus_get_preferences(name, keys) |
1594 YUS_SERVER.autosession(YUS_DOMAIN) { |session| |
1595 session.get_entity_preferences(name, keys) |
1596 } |
1597 rescue Yus::YusError |
1598 {} # return an empty hash |
1599 end |
1600 def yus_model(name) |
1601 if(odba_id = yus_get_preference(name, 'association')) |
1602 ODBA.cache.fetch(odba_id, nil) |
1603 end |
1604 rescue Yus::YusError, ODBA::OdbaError |
1605 # association not found |
1606 end |
1607 def yus_reset_password(name, token, password) |
1608 YUS_SERVER.autosession(YUS_DOMAIN) { |session| |
1609 session.reset_entity_password(name, token, password) |
1610 } |
1611 end |
1612 def yus_set_preference(name, key, value, domain=YUS_DOMAIN) |
1613 YUS_SERVER.autosession(YUS_DOMAIN) { |session| |
1614 session.set_entity_preference(name, key, value, domain) |
1615 } |
1616 end |
1617 |
1618 def multilinguify_analysis |
1619 @system.analysis_positions.each { |pos| |
1620 if(descr = pos.description) |
1621 pos.instance_variable_set('@description', nil) |
1622 @system.update(pos.pointer, {:de => descr}) |
1623 end |
1624 if(fn = pos.footnote) |
1625 pos.instance_variable_set('@footnote', nil) |
1626 ptr = pos.pointer + :footnote |
1627 @system.update(ptr.creator, {:de => fn}) |
1628 end |
1629 if(lt = pos.list_title) |
1630 pos.instance_variable_set('@list_title', nil) |
1631 ptr = pos.pointer + :list_title |
1632 @system.update(ptr.creator, {:de => lt}) |
1633 end |
1634 if(tn = pos.taxnote) |
1635 pos.instance_variable_set('@taxnote', nil) |
1636 ptr = pos.pointer + :taxnote |
1637 @system.update(ptr.creator, {:de => tn}) |
1638 end |
1639 if(perm = pos.permissions) |
1640 pos.instance_variable_set('@permissions', nil) |
1641 ptr = pos.pointer + :permissions |
1642 @system.update(ptr.creator, {:de => perm}) |
1643 end |
1644 if(lim = pos.instance_variable_get('@limitation')) |
1645 pos.instance_variable_set('@limitation', nil) |
1646 ptr = pos.pointer + :limitation_text |
1647 @system.update(ptr.creator, {:de => lim}) |
1648 end |
1649 pos.odba_store |
1650 } |
1651 end |
1652 def migrate_feedbacks |
1653 @system.each_package { |pac| |
1654 _migrate_feedbacks(pac) |
1655 } |
1656 @system.each_migel_product { |prd| |
1657 _migrate_feedbacks(prd) |
1658 } |
1659 @system.feedbacks.odba_store |
1660 @system.odba_store |
1661 update_feedback_rss_feed |
1662 end |
1663 def _migrate_feedbacks(item) |
1664 item = item.odba_instance |
1665 fbs = item.instance_variable_get('@feedbacks').odba_instance |
1666 case fbs |
1667 when Array |
1668 # already migrated, ignore |
1669 when Hash |
1670 new = fbs.values.select { |fb| |
1671 fb.is_a?(Feedback) |
1672 }.sort_by { |fb| fb.time }.reverse |
1673 fbs.odba_delete |
1674 new.odba_store |
1675 item.instance_variable_set('@feedbacks', new) |
1676 item.odba_store |
1677 new.each { |fb| |
1678 id = fb.odba_id |
1679 fb.instance_variable_set('@oid', id) |
1680 ptr = Persistence::Pointer.new([:feedback, id]) |
1681 fb.instance_variable_set('@pointer', ptr) |
1682 @system.feedbacks.store(id, fb) |
1683 fb.instance_variable_set('@item', item) |
1684 fb.odba_store |
1685 } |
1686 when nil |
1687 item.instance_variable_set('@feedbacks', []) |
1688 item.odba_store |
1689 end |
1690 end |
1691 def utf8ify(object, opts={}) |
1692 from = 'ISO-8859-1' |
1693 to = 'UTF-8//TRANSLIT//IGNORE' |
1694 if opts[:reverse] |
1695 from, to = to, from |
1696 end |
1697 iconv = ::Iconv.new to, from |
1698 _migrate_to_utf8([object], {}, iconv) |
1699 end |
1700 def migrate_to_utf8 |
1701 iconv = ::Iconv.new 'UTF-8//TRANSLIT//IGNORE', 'ISO-8859-1' |
1702 ODBA.cache.retire_age = 5 |
1703 ODBA.cache.cleaner_step = 100000 |
1704 system = @system.odba_instance |
1705 table = { system.odba_id => true, :serialized => {} } |
1706 table.store :finalizer, proc { |object_id| |
1707 table[:serialized].delete object_id } |
1708 queue = [ system ] |
1709 last_size = 0 |
1710 system.instance_variable_set '@config', nil |
1711 while !queue.empty? |
1712 if (queue.size - last_size).abs >= 10000 |
1713 puts last_size = queue.size |
1714 end |
1715 _migrate_to_utf8 queue, table, iconv, :all => true |
1716 end |
1717 end |
1718 def _migrate_to_utf8 queue, table, iconv, opts={} |
1719 obj = queue.shift |
1720 if obj.is_a?(Numeric) |
1721 begin |
1722 obj = ODBA.cache.fetch obj |
1723 rescue ODBA::OdbaError |
1724 return |
1725 end |
1726 else |
1727 obj = obj.odba_instance |
1728 end |
1729 _migrate_obj_to_utf8 obj, queue, table, iconv, opts |
1730 obj.odba_store unless obj.odba_unsaved? |
1731 end |
1732 def _migrate_obj_to_utf8 obj, queue, table, iconv, opts={} |
1733 obj.instance_variables.each do |name| |
1734 child = obj.instance_variable_get name |
1735 if child.respond_to?(:odba_unsaved?) && !child.odba_unsaved? \ |
1736 && obj.respond_to?(:odba_serializables) \ |
1737 && obj.odba_serializables.include?(name) |
1738 child.instance_variable_set '@odba_persistent', nil |
1739 end |
1740 child = _migrate_child_to_utf8 child, queue, table, iconv, opts |
1741 obj.instance_variable_set name, child |
1742 end |
1743 if obj.is_a?(Array) |
1744 obj.collect! do |child| |
1745 _migrate_child_to_utf8 child, queue, table, iconv, opts |
1746 end |
1747 end |
1748 if obj.is_a?(Hash) |
1749 obj.dup.each do |key, child| |
1750 obj.store key, _migrate_child_to_utf8(child, queue, table, iconv, opts) |
1751 end |
1752 if obj.is_a?(ODDB::SimpleLanguage::Descriptions) |
1753 obj.default = _migrate_child_to_utf8 obj.default, queue, table, iconv, opts |
1754 end |
1755 end |
1756 obj |
1757 end |
1758 def _migrate_child_to_utf8 child, queue, table, iconv, opts={} |
1759 @serialized ||= {} |
1760 case child |
1761 when ODBA::Persistable, ODBA::Stub |
1762 if child = child.odba_instance |
1763 if child.odba_unsaved? |
1764 _migrate_to_utf8 [child], table, iconv, opts |
1765 elsif opts[:all] |
1766 odba_id = child.odba_id |
1767 unless table[odba_id] |
1768 table.store odba_id, true |
1769 queue.push odba_id |
1770 end |
1771 end |
1772 end |
1773 when String |
1774 child = iconv.iconv(child) |
1775 when ODDB::Text::Section, ODDB::Text::Paragraph, ODDB::PatinfoDocument, |
1776 ODDB::PatinfoDocument2001, ODDB::Text::Table, ODDB::Text::Cell, |
1777 ODDB::Analysis::Permission, ODDB::Interaction::AbstractLink, |
1778 ODDB::Dose |
1779 child = _migrate_obj_to_utf8 child, queue, table, iconv, opts |
1780 when ODDB::Address2 |
1781 ## Address2 may cause StackOverflow if not controlled |
1782 unless table[:serialized][child.object_id] |
1783 table[:serialized].store child.object_id, true |
1784 ObjectSpace.define_finalizer child, table[:finalizer] |
1785 child = _migrate_obj_to_utf8 child, queue, table, iconv, opts |
1786 end |
1787 when Float, Fixnum, TrueClass, FalseClass, NilClass, |
1788 ODDB::Persistence::Pointer, Symbol, Time, Date, ODDB::Dose, Quanty, |
1789 ODDB::Util::Money, ODDB::Fachinfo::ChangeLogItem, ODDB::AtcNode, |
1790 DateTime, ODDB::NotificationLogger::LogEntry, ODDB::Text::Format, |
1791 ODDB::YusStub, ODDB::Text::ImageLink |
1792 # do nothing |
1793 else |
1794 @ignored ||= {} |
1795 unless @ignored[child.class] |
1796 @ignored.store child.class, true |
1797 warn "ignoring #{child.class}" |
1798 end |
1799 end |
1800 child |
1801 rescue SystemStackError |
1802 puts child.class |
1803 raise |
1804 end |
1805 |
1806 def log_size |
1807 @size_logger = Thread.new { |
1808 time = Time.now |
1809 bytes = 0 |
1810 threads = 0 |
1811 sessions = 0 |
1812 format = "%s %s: sessions: %4i - threads: %4i - memory: %4iMB %s" |
1813 loop { |
1814 begin |
1815 lasttime = time |
1816 time = Time.now |
1817 alarm = time - lasttime > 60 ? '*' : ' ' |
1818 lastthreads = threads |
1819 threads = Thread.list.size |
1820 lastbytes = bytes |
1821 bytes = File.read("/proc/#{$$}/stat").split(' ').at(22).to_i |
1822 mbytes = bytes / (2**20) |
1823 if mbytes > MEMORY_LIMIT |
1824 puts "Footprint exceeds #{MEMORY_LIMIT}MB. Exiting." |
1825 Thread.main.raise SystemExit |
1826 end |
1827 lastsessions = sessions |
1828 sessions = @sessions.size |
1829 gc = '' |
1830 gc << 'S' if sessions < lastsessions |
1831 gc << 'T' if threads < lastthreads |
1832 gc << 'M' if bytes < lastbytes |
1833 path = File.expand_path('../../doc/resources/downloads/status', |
1834 File.dirname(__FILE__)) |
1835 lines = File.readlines(path)[0,100] rescue [] |
1836 lines.unshift sprintf(format, alarm, |
1837 time.strftime('%Y-%m-%d %H:%M:%S'), |
1838 sessions, threads, mbytes, gc) |
1839 File.open(path, 'w') { |fh| |
1840 fh.puts lines |
1841 } |
1842 rescue StandardError => e |
1843 puts e.class |
1844 puts e.message |
1845 $stdout.flush |
1846 end |
1847 sleep 5 |
1848 } |
1849 } |
1850 end |
1851 end |
1852 end |
1853 |
1854 begin |
1855 require 'testenvironment' |
1856 rescue LoadError |
1857 end |
Generated on Fri Feb 18 16:44:24 +0100 2011 with rcov 0.9.8