schild.rb 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. require 'schild/version'
  2. require 'sequel'
  3. ##
  4. # === Schild Basis-Modul
  5. # Das Schild Modul, das alle Klassen für die Datenbankanbindung bereitstellt.
  6. # Die zur Verfügung gestellten Klassen entsprechen dabei den Schild-Tabellen,
  7. # und den damit verbundenen Assoaziationen.
  8. #
  9. # Neben dem Zugriff aus Daten innerhalb einer Tabelle kann über die Schild-Klassen
  10. # auch auf weitere verknüpfte Tabellen zugegriffen werden. Dazu ein Beispiel:
  11. #
  12. # Schueler[0].name
  13. # => "Olsen"
  14. #
  15. # Schueler[0].abschnitte[0].jahr
  16. # => 2017
  17. #
  18. # Im ersten Beispiel wurde auf den ersten Schüler in der Datenbank ([0]) zugegriffen,
  19. # und der `name` ausgelesen.
  20. #
  21. # Im zweiten Beispiel wird auf den gleichen Schüler zugegriffen und dessen Abschnitt-Tabelle
  22. # ebenfalls abgefragt. D.h. es wird bereits auf die Abschnitte-Tabelle zugegriffen
  23. # und automatisch nur Abschnitte zurückgegeben, die zum Schüler gehören. Aus
  24. # dieser Menge wird ebenfalls der erste Abschnitt gewählt ([0]).
  25. #
  26. # Auf diesem Weg können beliebig verschachtelte Anfragen gestartet werden.
  27. #
  28. # Es wird empfohlen statt Schild das Modul SchildErweitert einzubinden. Es
  29. # beinhaltet neben den Assoaziationen auch weitere Methoden.
  30. # Weitere Erläuterungen dazu weiter im Modul.
  31. module Schild
  32. Sequel::Model.plugin :tactical_eager_loading
  33. # @db ist die Datenbank-Verbindung. Alle Daten können über diese Variable abgerufen werden
  34. @db = Sequel.connect("#{ENV['S_ADAPTER']}://#{ENV['S_HOST']}/#{ENV['S_DB']}?user=#{ENV['S_USER']}&password=#{ENV['S_PASSWORD']}&zeroDateTimeBehavior=convertToNull")
  35. begin
  36. retries ||= 0
  37. @db.test_connection
  38. rescue
  39. puts "Verbindung zum Server konnte nicht hergestellt werden"
  40. puts "#{retries += 1}. Verbindungsversuch in 5s (max 50 Versuche)"
  41. puts "Sie können mit Strg-c abbrechen."
  42. sleep 5
  43. retry if retries < 50
  44. end
  45. @db.extension(:freeze_datasets)
  46. @db.extension(:connection_validator)
  47. @db.extension(:null_dataset)
  48. # gibt die Datenbank zurück
  49. def self.db
  50. @db
  51. end
  52. # Stellt die Schüler-Tabelle mit Assoziationen bereit.
  53. # Die aufgeführten Instanzmethoden sind ausschließlich Assoaziationen.
  54. #
  55. # Tabellenname: schueler
  56. class Schueler < Sequel::Model(:schueler)
  57. # @!method fachklasse
  58. # @return [Fachklasse]
  59. many_to_one :fachklasse, :class => :Fachklasse
  60. # @!method abschnitte
  61. # @return [Array<Abschnitt>]
  62. one_to_many :abschnitte, :class => :Abschnitt
  63. # @!method bk_abschluss
  64. # @return [BKAbschluss]
  65. one_to_one :bk_abschluss, :class => :BKAbschluss
  66. # @!method bk_abschluss_leistungen
  67. # @return [Array<BKAbschlussFach>]
  68. one_to_many :bk_abschluss_leistungen, :class => :BKAbschlussFach
  69. # @!method abi_abschluss
  70. # @return [AbiAbschluss]
  71. one_to_one :abi_abschluss, :class => :AbiAbschluss
  72. # @!method abi_abschluss_leistungen
  73. # @return [Array<AbiAbschlussFach>]
  74. one_to_many :abi_abschluss_leistungen, :class => :AbiAbschlussFach
  75. # @!method fhr_abschluss
  76. # @return [FHRAbschluss]
  77. one_to_one :fhr_abschluss, :class => :FHRAbschluss
  78. # @!method fhr_abschluss_leistungen
  79. # @return [Array<FHRAbschlussFach>]
  80. one_to_many :fhr_abschluss_leistungen, :class => :FHRAbschlussFach
  81. # @!method vermerke
  82. # @return [Array<Vermerk>]
  83. one_to_many :vermerke, :class => :Vermerk
  84. # @!method schuelerfoto
  85. # @return [Schuelerfoto]
  86. one_to_one :schuelerfoto, :class => :Schuelerfoto
  87. # @!method sprachenfolgen
  88. # @return [Array<Sprachenfolge>]
  89. one_to_many :sprachenfolgen, :class => :Sprachenfolge
  90. end
  91. # Informationen zu Klassenbezeichnung und weiteren Daten über die jeweiligen
  92. # Bildungsgänge. Verfügbar als Assoziationen für Schüler.
  93. #
  94. # Tabellenname: eigeneschule_fachklassen
  95. class Fachklasse < Sequel::Model(:eigeneschule_fachklassen)
  96. # @!method schueler
  97. # @return [Array<Schueler>]
  98. one_to_many :schueler, :class => :Schueler
  99. end
  100. # Versetzungstabelle für Fachklassen. D.h. Klassenbezeichnungen für vorhergehende
  101. # und nachfolgende Klassen.
  102. #
  103. # Tabellenname: versetzung
  104. class Versetzung < Sequel::Model(:versetzung)
  105. # @!method fachklasse
  106. # @return [Fachklasse]
  107. many_to_one :fachklasse, :class => :Fachklasse
  108. end
  109. # Assoziation für Lehrer, hauptsächlich für Klassenlehrer
  110. #
  111. # Tabellenname: k_lehrer
  112. class Klassenlehrer < Sequel::Model(:k_lehrer)
  113. end
  114. # Ist die Assoziation, die Halbjahre, sog. Abschnitte zurückgibt.
  115. #
  116. # Tabellenname: schuelerlernabschnittsdaten
  117. class Abschnitt < Sequel::Model(:schuelerlernabschnittsdaten)
  118. # @!method schueler
  119. # @return [Schueler]
  120. many_to_one :schueler, :class => :Schueler
  121. # @!method noten
  122. # @return [Array<Note>]
  123. one_to_many :noten, :class => :Note
  124. # @!method fachklasse
  125. # @return [Fachklasse]
  126. many_to_one :fachklasse, :class => :Fachklasse
  127. # @!method klassenlehrer
  128. # @return [Klassenlehrer]
  129. many_to_one :klassenlehrer, :primary_key=>:Kuerzel, :key=>:KlassenLehrer, :class=>:Klassenlehrer
  130. end
  131. # Assoziation für Noten
  132. #
  133. # Tabellenname: schuelerleistungsdaten
  134. class Note < Sequel::Model(:schuelerleistungsdaten)
  135. # @!method fach
  136. # @return [Fach]
  137. many_to_one :fach, :class => :Fach
  138. end
  139. # Assoziation für Fächer
  140. #
  141. # Tabellenname: eigeneschule_faecher
  142. class Fach < Sequel::Model(:eigeneschule_faecher)
  143. # @!method note
  144. # @return [Note]
  145. one_to_one :note, :class => :Note
  146. # @!method abi_abschluss_leistungen
  147. # @return [Array<AbiAbschlussFach>]
  148. one_to_many :abi_abschluss_leistungen, :class => :AbiAbschlussFach
  149. # @!method sprachenfolge
  150. # @return [Sprachenfolge]
  151. one_to_one :sprachenfolge, :class => :Sprachenfolge, :key => :Fach_ID
  152. # @!method gliederungen
  153. # @return [Array<Fach_Gliederung>]
  154. one_to_many :gliederungen, :class => :Fach_Gliederung, :key => :Fach_ID
  155. end
  156. # Assoziation für BK-Abschluss des Schülers
  157. #
  158. # Tabellenname: schuelerbkabschluss
  159. class BKAbschluss < Sequel::Model(:schuelerbkabschluss)
  160. end
  161. # Assoziation für die Prüfungsfächer des Schülers
  162. #
  163. # Tabellenname: schuelerbkfaecher
  164. class BKAbschlussFach < Sequel::Model(:schuelerbkfaecher)
  165. # @!method fach
  166. # @return [Fach]
  167. many_to_one :fach, :class => :Fach
  168. end
  169. # Assoziation für Abi-Abschluss des Schülers
  170. #
  171. # Tabellenname: schuelerabitur
  172. class AbiAbschluss < Sequel::Model(:schuelerabitur)
  173. end
  174. # Assoziation für die Abifächer des Schülers
  175. #
  176. # Tabellenname: schuelerabifaecher
  177. class AbiAbschlussFach < Sequel::Model(:schuelerabifaecher)
  178. # @!method fach
  179. # @return [Fach]
  180. many_to_one :fach, :class => :Fach
  181. end
  182. # Assoziation für FHR-Abschluss des Schülers
  183. #
  184. # Tabellenname: schuelerfhr
  185. class FHRAbschluss < Sequel::Model(:schuelerfhr)
  186. end
  187. # Assoziation für die FHR-fächer des Schülers
  188. #
  189. # Tabellenname: schuelerfhrfaecher
  190. class FHRAbschlussFach < Sequel::Model(:schuelerfhrfaecher)
  191. # @!method fach
  192. # @return [Fach]
  193. many_to_one :fach, :class => :Fach
  194. end
  195. # Assoziation für die bisher erreichten Sprachniveaus
  196. #
  197. # Tabellenname: schuelersprachenfolge
  198. class Sprachenfolge < Sequel::Model(:schuelersprachenfolge)
  199. # @!method fach
  200. # @return [Fach]
  201. many_to_one :fach, :class => :Fach
  202. end
  203. # Besondere Facheinstellungen nach Fachklasse. Betrifft v.a. Sortierung,
  204. # Festlegungen über Prüfungsfächer etc.
  205. #
  206. # Tabellenname: fach_gliederungen
  207. class Fach_Gliederung < Sequel::Model(:fach_gliederungen)
  208. # @!method fach
  209. # @return [Fach]
  210. many_to_one :fach, :class => :Fach
  211. # @!method fachklasse
  212. # @return [Fachklasse]
  213. many_to_one :fachklasse, :class => :Fachklasse
  214. end
  215. # Vermerke von Schülern
  216. #
  217. # Tabellenname: schuelervermerke
  218. class Vermerk < Sequel::Model(:schuelervermerke)
  219. end
  220. # Schülerfotos als jpg
  221. #
  222. # Tabellenname: schuelerfotos
  223. class Schuelerfoto < Sequel::Model(:schuelerfotos)
  224. end
  225. # Schul-Tabelle
  226. #
  227. # Tabellenname: eigeneschule
  228. class Schule < Sequel::Model(:eigeneschule)
  229. end
  230. # Tabelle für Schild-Nutzer
  231. #
  232. # Tabellenname: users
  233. class Nutzer < Sequel::Model(:users)
  234. end
  235. end
  236. # ==SchildErweitert
  237. # Dieses Modul bindet das Schild-Modul ein und erweitert es mit zusätzlichen Methoden
  238. # zum einfachen Zugriff auf Schild-Methoden, die teilweise verschachtelt sind.
  239. # Ebenso bietet SchildErweitert alle Methoden mit Null-Objekten, d.h. es
  240. # gibt kein +nil+, nur Standardwerte.
  241. module SchildErweitert
  242. if Module.private_method_defined? :include
  243. # erst Ruby 2.1.0 macht include zu einer public-Methode
  244. class Module
  245. public :include
  246. end
  247. end
  248. # String und Symbol werden um snake_case ergänzt, das die Schild-Tabellen umbenennt
  249. # Legacy-Methoden aus alten Schild-Versionen wird teilweise auch unterstützt.
  250. module CoreExtensions
  251. # Patch für String
  252. module String
  253. # wandelt Strings in +Snake Case+ um.
  254. # Beispiel:
  255. # CamelCase.snake_case
  256. # => camel_case
  257. def snake_case
  258. return downcase if match(/\A[A-Z]+\z/)
  259. gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
  260. gsub(/([a-z])([A-Z])/, '\1_\2').
  261. downcase
  262. end
  263. end
  264. # Patch für Symbol
  265. module Symbol
  266. # snake_case für Symbol, verwandel Symbol in String
  267. def snake_case
  268. to_s.snake_case
  269. end
  270. end
  271. end
  272. # Schild hat teilweise nil in DB-Feldern. SchildTypeSaver gibt entweder einen
  273. # Leer-String zurück ("") oder bei strftime das 1899 Datum zurück.
  274. module SchildTypeSaver
  275. Symbol.include SchildErweitert::CoreExtensions::Symbol
  276. String.include CoreExtensions::String
  277. # es wird für jede Spalte in der Schild-Tabelle eine Ersatzmethode
  278. # erstellt, die bei nil ein Null-Objekt erstellt.
  279. # Dazu wird die neu angelegte Methode per MethodLogger gesichert.
  280. def self.included(klass)
  281. klass.columns.each do |column|
  282. name = column.snake_case
  283. MethodLogger::Methods.add(klass, name)
  284. # allow_nil ist als Argument optional und lässt bei +true+ alle Ergebnisse durch
  285. define_method(("_"+name.to_s).to_sym) {public_send(column)}
  286. define_method(name) do |allow_nil=false|
  287. ret = public_send(column)
  288. if allow_nil || ret
  289. ret = ret.strip if ret.class == String
  290. ret
  291. else
  292. create_null_object(klass, column)
  293. end
  294. end
  295. end
  296. end
  297. # Es wird ein Null-Objekt erstellt, das einen Standardwert zurückgibt.
  298. def create_null_object(klass, column)
  299. k = Sequel::Database::SCHEMA_TYPE_CLASSES[klass.db_schema[column][:type]]
  300. case
  301. # Sequel stellt :datetime als [Time, DateTime] dar, deswegen die Abfrage nach Array
  302. # Schild verwendet Time Objekte, wir machen das auch
  303. when k.class == Array then Time.new(1899)
  304. when k == Integer then 0
  305. when k == Float then 0.0
  306. # alle anderen types werden als Klasse zurückgegeben
  307. else k.new
  308. end
  309. end
  310. end
  311. # Halten wir Protokoll zu den erstellten Methoden
  312. # Ist brauchbar, wenn man z.B. noch extremer als der SchildTypeSaver arbeiten möchte
  313. module MethodLogger
  314. # Methoden-Klasse die alles Daten sammelt
  315. class Methods
  316. @@accessor_methods = {}
  317. # Eine Methode dem MethodLogger hinzufügen
  318. # @param [Class, method]
  319. def self.add(klass, meth)
  320. @@accessor_methods[klass] ||= []
  321. @@accessor_methods[klass] << meth
  322. end
  323. # Liste von Methoden für eine Klasse auslesen
  324. def self.list(klass)
  325. @@accessor_methods[klass]
  326. end
  327. end
  328. end
  329. # Mixin für Notenbezeichnungen
  330. module NotenHelfer
  331. # Noten können als Punkte abgerufen werden:
  332. # note[5] => "4-"
  333. # oder auch andersherum: note.index("4-") => 5
  334. @note = %w[6 5- 5 5+ 4- 4 4+ 3- 3 3+ 2- 2 2+ 1- 1 1+]
  335. # @param note [Integer]
  336. def self.punkte_aus_note(note)
  337. return if note.nil?
  338. @note.index(note)
  339. end
  340. # @param punkte [Integer]
  341. def self.note_aus_punkten(punkte)
  342. return unless punkte && punkte.to_i.between?(1,15) || punkte == "0"
  343. return punkte if ((punkte.to_i == 0) && (punkte.size > 1))
  344. return if (punkte.class == String) && punkte.empty?
  345. @note[punkte.to_i]
  346. end
  347. # Notenbezeichnung als String
  348. # @param ziffer [String]
  349. def note_s(ziffer)
  350. case ziffer
  351. when "1", "1+", "1-"
  352. "sehr gut"
  353. when "2", "2+", "2-"
  354. "gut"
  355. when "3", "3+", "3-"
  356. "befriedigend"
  357. when "4", "4+", "4-"
  358. "ausreichend"
  359. when "5", "5+", "5-"
  360. "mangelhaft"
  361. when "6"
  362. "ungenügend"
  363. when 'NB'
  364. "––––––"
  365. when "E1"
  366. "mit besonderem Erfolg teilgenommen"
  367. when "E2"
  368. "mit Erfolg teilgenommen"
  369. when 'E3'
  370. "teilgenommen"
  371. end
  372. end
  373. end
  374. # Klassen sind Konstanten. Deswegen alle auslesen, die Klassen behalten und
  375. # dynamisch neue Klassen mit gleichem Namen erstellen.
  376. # Automatisch SchildTypeSaver einbinden.
  377. #
  378. # Sollen zusätzliche Methoden eingebunden werden, muss - wie unten Schueler
  379. # und andere Klassen - die neu erstelle Klasse gepatcht werden.
  380. # Die alten Methoden bleiben erhalten, d.h. auch die TypeSaver-Methoden.
  381. Schild.constants.map {|name| Schild.const_get(name)}.select {|o| o.is_a?(Class)}.each do |klass|
  382. name = Schild.const_get(klass.to_s).name.split("::").last
  383. klass = Class.new(klass) do
  384. include SchildTypeSaver
  385. end
  386. name = const_set(name, klass)
  387. end
  388. # Stellt die Schüler-Tabelle samt Assoziationen bereit.
  389. class Schueler
  390. # gibt das z.Zt. aktuelle Halbjahr zurück.
  391. def akt_halbjahr
  392. abschnitte.last
  393. end
  394. # gibt aus +jahr+ das Halbjahr +1+ oder +2+ zurück.
  395. def halbjahr(jahr, abschnitt)
  396. abschnitte_dataset.where(:jahr => jahr, :abschnitt => abschnitt).first
  397. end
  398. # gibt +Herr+ oder +Frau+ als Anrede für Schüler zurück.
  399. def anrede
  400. self.geschlecht == 3 ? "Herr" : "Frau"
  401. end
  402. # gibt die passende Bezeichnung zurück Schüler
  403. def schueler_in
  404. self.geschlecht == 3 ? "Schüler" : "Schülerin"
  405. end
  406. # gibt die passende Bezeichnung zurück Studierende
  407. def studierende_r
  408. self.geschlecht == 3 ? "Studierender" : "Studierende"
  409. end
  410. # gibt die jeweilige Berufsbezeichnung nach Geschlecht zurück.
  411. def berufsbezeichnung_mw
  412. return "Keine Fachklasse zugeordnet" if self.fachklasse.nil?
  413. self.geschlecht == 3 ? self.fachklasse.bezeichnung : self.fachklasse.beschreibung_w
  414. end
  415. # gibt +true+ zurück, wenn Schüler volljährig.
  416. def volljaehrig?
  417. self.volljaehrig == "+"
  418. end
  419. # gibt an, ob der Schüler zu einem Zeitpunkt *datum* volljährig war.
  420. def volljaehrig_bei?(datum)
  421. return false if datum.nil? || self.Geburtsdatum.nil?
  422. geb, datum = self.Geburtsdatum.to_date, datum.to_date
  423. (datum.year - geb.year - ((datum.month > geb.month || (datum.month == geb.month && datum.day >= geb.day)) ? 0 : 1)) >= 18
  424. end
  425. # fragt ab, ob in Schild ein Foto als hinterlegt eingetragen ist.
  426. def foto_vorhanden?
  427. !!(self.schuelerfoto && self.schuelerfoto.foto)
  428. end
  429. # gibt, wenn vorhanden, ein Foto als jpg-String zurück, ansonsten nil.
  430. def foto
  431. self.schuelerfoto.foto if self.foto_vorhanden?
  432. end
  433. end
  434. # Ist die Assoziation, die Halbjahre, sog. Abschnitte zurückgibt.
  435. class Abschnitt
  436. dataset_module do
  437. # filtert den Datensatz nach Jahr
  438. def jahr(i)
  439. where(:Jahr => i)
  440. end
  441. # filtert den Datensatz nach Halbjahr
  442. def halbjahr(i,j)
  443. jahr(i).where(:Abschnitt => j)
  444. end
  445. # filtert und gibt den Datensatz als Abschnitt des aktuellen Halbjahrs zurück
  446. def akt_halbjahr
  447. halbjahr(Time.new.year-1, 1).first
  448. end
  449. end
  450. # Hilfsmethode für die folgenden Methoden
  451. def faecher_nach_id(id)
  452. noten.select{ |n| n.fach.Fachgruppe_ID == id && n.AufZeugnis == '+' }.sort_by{ |n| n.fach.SortierungS2 }
  453. end
  454. # wählt alle berufsübergreifenden Fächer des gewählten Schülers in angegeben Halbjahr.
  455. def berufsuebergreifend
  456. faecher_nach_id 10
  457. end
  458. # wählt alle berufsbezogenen Fächer des gewählten Schülers in angegeben Halbjahr.
  459. def berufsbezogen
  460. faecher_nach_id 20
  461. end
  462. # wählt alle Fächer des Differenzierungsbreichs des gewählten Schülers in angegeben Halbjahr.
  463. def differenzierungsbereich
  464. faecher_nach_id 30
  465. end
  466. # wählt alle Fächergruppen aus.
  467. def faechergruppen
  468. [berufsuebergreifend, berufsbezogen, differenzierungsbereich]
  469. end
  470. # gibt den Namen des Klassenlehrers mit gekürztem Vornamen.
  471. def v_name_klassenlehrer
  472. return "Kein Klassenlehrer angelegt" if klassenlehrer.nil?
  473. v = klassenlehrer.vorname
  474. n = klassenlehrer.nachname
  475. "#{v[0]}. #{n}"
  476. end
  477. # gibt "Klassenlehrer" entsprechend Geschlecht zurück
  478. def klassenlehrer_in
  479. return "Kein Klassenlehrer angelegt" if klassenlehrer.nil?
  480. klassenlehrer.geschlecht == "3" ? "Klassenlehrer" : "Klassenlehrerin"
  481. end
  482. # gibt das aktuelle Schuljahr als String im Format "2014/15" zurück.
  483. def schuljahr
  484. jahr = self.jahr
  485. "#{jahr}/#{jahr-1999}"
  486. end
  487. end
  488. # Assoziation für Noten
  489. class Note
  490. include NotenHelfer
  491. # note in String umwandeln
  492. def note
  493. note_s self.noten_krz
  494. end
  495. # Bezeichnung des Fachs
  496. def bezeichnung
  497. fach.bezeichnung
  498. end
  499. # Die Fachgruppen-ID des Fachs
  500. def fachgruppe_ID
  501. fach.fachgruppe_id
  502. end
  503. end
  504. # Assoziation für BK-Abschlussdaten
  505. class BKAbschluss
  506. # Ist der Schüler zugelassen?
  507. def zulassung?
  508. self.Zulassung == "+"
  509. end
  510. # Ist der Schüler für den Berufsabschluss zugelassen?
  511. def zulassung_ba?
  512. self.ZulassungBA == "+"
  513. end
  514. # Hat der Schüler den Berufsabschluss bestanden?
  515. def bestanden_ba?
  516. self.BestandenBA == "+"
  517. end
  518. end
  519. # Assoziation für die jeweiligen BK-Prüfungsfächer
  520. class BKAbschlussFach
  521. include NotenHelfer
  522. # Wurde das Fach schriftlich geprüft?
  523. def fach_schriftlich?
  524. self.FachSchriftlich == "+"
  525. end
  526. # Wurde das Fach mündlich geprüft?
  527. def fach_muendlich?
  528. self.MdlPruefung == "+"
  529. end
  530. # holt die jeweilige Note aus der Tabelle.
  531. # Standard ist note_abschluss_ba, als Argument kann auch eine andere
  532. # verwendet werden (siehe Tabelle)
  533. def note(notenart=:note_abschluss_ba)
  534. note_s send(notenart)
  535. end
  536. end
  537. # Assoziation für Abi-Abschlussdaten
  538. class AbiAbschluss
  539. # Ist der Schüler zugelassen?
  540. def zulassung?
  541. self.Zugelassen == "+"
  542. end
  543. alias_method :zugelassen?, :zulassung?
  544. # Hat der Schüler die Abi-Prüfung bestanden?
  545. def bestanden_abi?
  546. self.PruefungBestanden == "+"
  547. end
  548. alias_method :pruefung_bestanden?, :bestanden_abi?
  549. # Latinum gemacht?
  550. def latinum?
  551. self.Latinum == "+"
  552. end
  553. # Kleines Latinum erreicht?
  554. def kl_latinum?
  555. self.KlLatinum == "+"
  556. end
  557. # Gräcum erreicht?
  558. def graecum?
  559. self.Graecum == "+"
  560. end
  561. # Hebraicum erreicht?
  562. def hebraicum?
  563. self.Hebraicum == "+"
  564. end
  565. end
  566. # Assoziation für die jeweiligen Abi-Prüfungsfächer
  567. class AbiAbschlussFach
  568. include NotenHelfer
  569. # Note aus Tebelle abfragen, Notenart angeben (siehe Tabelle)
  570. def note(notenart)
  571. note_s send(notenart)
  572. end
  573. end
  574. # Assoziation für die jeweiligen FHR-Prüfungsfächer
  575. class FHRAbschlussFach
  576. include NotenHelfer
  577. # Note aus Tebelle abfragen, Notenart angeben (siehe Tabelle)
  578. def note(notenart)
  579. note_s send(notenart)
  580. end
  581. end
  582. # Schul-Tabelle mit vereinfachtem Zugriff auf Datenfelder mittel class-Methoden
  583. class Schule
  584. # gibt die Schulnummer zurück
  585. def self.schulnummer
  586. self.first.schul_nr
  587. end
  588. # gibt den Namen des Schulleiters als V. Name zurück
  589. def self.v_name_schulleiter
  590. "#{self.first.schulleiter_vorname[0]}. #{self.first.schulleiter_name}"
  591. end
  592. # gibt die männliche bzw. weibliche Form des Schulleiters zurück
  593. def self.schulleiter_in
  594. self.first.schulleiter_geschlecht == 3 ? "Schulleiter" : "Schulleiterin"
  595. end
  596. # gibt den Ort der Schule zurück
  597. def self.ort
  598. self.first.ort
  599. end
  600. end
  601. # Tabelle der Schuld-Benutzer zum Abgleichen der Daten
  602. class Nutzer
  603. alias :name :us_name
  604. alias :login :us_login_name
  605. alias :passwort :us_password
  606. alias :password :passwort
  607. # prüft, ob das angegebene Passwort mit dem gespeicherten Passwort übereinstimmt
  608. def passwort?(passwort='')
  609. crypt(passwort) == self.passwort
  610. end
  611. alias :password? :passwort?
  612. # ver- bzw. entschlüsselt einen String mit dem Schild-Passwortalgorithmus
  613. def crypt(passwort)
  614. passwort.codepoints.map{|c| ((c/16)*32+15-c).chr}.join('')
  615. end
  616. end
  617. end