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