schild.rb 19 KB

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