schild.rb 20 KB

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