schild.rb 20 KB

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