schild.rb 20 KB

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