ig3tool 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. data/bin/ig3tool +17 -21
  2. data/lib/actions/bib.rb +295 -0
  3. data/lib/actions/bitching.rb +19 -0
  4. data/lib/actions/cultuur.rb +3 -0
  5. data/lib/actions/interne.rb +98 -0
  6. data/lib/actions/kaching.rb +90 -0
  7. data/lib/actions/people.rb +178 -0
  8. data/lib/actions/printing.rb +125 -0
  9. data/lib/actions/product.rb +154 -0
  10. data/lib/bib.rb +94 -0
  11. data/lib/billing.rb +112 -0
  12. data/lib/bitching.rb +49 -0
  13. data/lib/config.rb +19 -0
  14. data/lib/glade/cola_light_small.png +0 -0
  15. data/lib/glade/cola_light_xsmall.png +0 -0
  16. data/lib/glade/cola_small.png +0 -0
  17. data/lib/glade/cola_xsmall.png +0 -0
  18. data/lib/glade/doos_small.png +0 -0
  19. data/lib/glade/doos_xsmall.png +0 -0
  20. data/lib/glade/icons/cola_light_small.png +0 -0
  21. data/lib/glade/icons/cola_light_xsmall.png +0 -0
  22. data/lib/glade/icons/cola_small.png +0 -0
  23. data/lib/glade/icons/cola_xsmall.png +0 -0
  24. data/lib/glade/icons/doos_small.png +0 -0
  25. data/lib/glade/icons/doos_xsmall.png +0 -0
  26. data/lib/glade/icons/piggy_small.png +0 -0
  27. data/lib/glade/icons/piggy_xsmall.png +0 -0
  28. data/lib/glade/money_small.png +0 -0
  29. data/lib/glade/money_xsmall.png +0 -0
  30. data/lib/glade/newinterne.glade +504 -0
  31. data/lib/glade/piggy_small.png +0 -0
  32. data/lib/glade/piggy_xsmall.png +0 -0
  33. data/lib/glade/sales.glade +89 -87
  34. data/lib/horrible_hack.rb +15 -0
  35. data/lib/interne.rb +111 -0
  36. data/lib/ldap.rb +104 -0
  37. data/lib/log.rb +25 -0
  38. data/lib/membership.rb +32 -0
  39. data/lib/mymd5.rb +95 -0
  40. data/lib/people.rb +143 -0
  41. data/lib/printing.rb +238 -0
  42. data/lib/request.rb +14 -0
  43. data/lib/sales.rb +158 -0
  44. data/lib/ui/automaatwindow.rb +2 -2
  45. data/lib/ui/bibliotheekwindow.rb +16 -17
  46. data/lib/ui/bibwindow.rb +15 -15
  47. data/lib/ui/gladehelper.rb +20 -6
  48. data/lib/ui/internewindow.rb +12 -9
  49. data/lib/ui/loginwindow.rb +2 -4
  50. data/lib/ui/memberswindow.rb +9 -9
  51. data/lib/ui/newinterne.rb +258 -0
  52. data/lib/ui/peoplewindow.rb +14 -16
  53. data/lib/ui/printenwindow.rb +11 -11
  54. data/lib/ui/printingwindow.rb +19 -20
  55. data/lib/ui/productswindow.rb +27 -15
  56. data/lib/ui/saleswindow.rb +21 -8
  57. data/lib/ui/toolwindow.rb +5 -3
  58. data/lib/utils.rb +106 -0
  59. data/lib/web.rb +98 -0
  60. metadata +48 -3
data/lib/ldap.rb ADDED
@@ -0,0 +1,104 @@
1
+ =begin
2
+
3
+ beetje stuff om te authen naar ldap
4
+ bvb:
5
+ bitch?("joske", "dejoszijnpasswd")
6
+ => true/false
7
+
8
+ TODO: filteren op debugger!
9
+
10
+ =end
11
+
12
+ require 'mymd5'
13
+
14
+ begin
15
+
16
+ require "ldap"
17
+
18
+ class IGLDAP < LDAP::Conn
19
+ DN = "cn=Proxyuser,dc=infogroep,dc=be"
20
+ PASS = "pRoxyAuth"
21
+ BASE_DN = "dc=infogroep,dc=be"
22
+ PEOPLE_DN = "ou=People,dc=infogroep,dc=be"
23
+ LDAP_HOST = "infogroep.be"
24
+ LDAP_PORT = 389
25
+ PROTOCOL_VERSION = 3
26
+
27
+ def initialize (host = LDAP_HOST, version = PROTOCOL_VERSION)
28
+ super( host, LDAP_PORT )
29
+ set_option( LDAP::LDAP_OPT_PROTOCOL_VERSION, version )
30
+ return self
31
+ end
32
+
33
+ def bind(dn = DN, pass = PASS)
34
+ super( dn, pass )
35
+ end
36
+
37
+ def self.bitchke?(user, pass)
38
+ begin
39
+ conn = IGLDAP.new.bind
40
+ attrs = %w{uid userPassword}
41
+ filter = "uid=#{user}"
42
+ result = conn.search2(IGLDAP::PEOPLE_DN, LDAP::LDAP_SCOPE_SUBTREE,filter, attrs)
43
+
44
+ passr = result.first["userPassword"].first.gsub(/\{crypt\}/, "")
45
+
46
+
47
+ match = passr.match(/(\$.+\$.+\$)(.*)/)
48
+ #salt = match[1]
49
+ salt = match[1].gsub(/\$1\$/, "").delete("$")
50
+ passh = match[2]
51
+ #pass.crypt(salt) == passr
52
+ crypt(pass, :md5, salt) == passr
53
+ rescue Exception => e
54
+ false
55
+ end
56
+ end
57
+
58
+ end
59
+
60
+ rescue
61
+
62
+ require 'net/ldap'
63
+ include Net
64
+
65
+ class IGLDAP
66
+ DN = "cn=Proxyuser,dc=infogroep,dc=be"
67
+ PASS = "pRoxyAuth"
68
+ BASE_DN = "dc=infogroep,dc=be"
69
+ PEOPLE_DN = "ou=People,dc=infogroep,dc=be"
70
+ LDAP_HOST = "infogroep.be"
71
+ LDAP_PORT = 389
72
+ PROTOCOL_VERSION = 3
73
+
74
+ def initialize
75
+ @conn = Net::LDAP.new( {:host => LDAP_HOST, :port => LDAP_PORT, :auth => { :method => :simple, :username => DN, :password => PASS }} )
76
+ end
77
+
78
+ def bind
79
+ @conn.bind
80
+ @conn
81
+ end
82
+
83
+ def self.bitchke?(user, pass)
84
+ begin
85
+ conn = IGLDAP.new.bind
86
+ attrs = %w{uid userPassword}
87
+ filter = "uid=#{user}"
88
+ result = conn.search(:base => PEOPLE_DN, :filter => filter)
89
+
90
+ passr = result.first["userPassword"].first.gsub(/\{crypt\}/, "")
91
+
92
+ match = passr.match(/(\$.+\$.+\$)(.*)/)
93
+ salt = match[1].gsub(/\$1\$/, "").delete("$")
94
+ #salt = match[1]
95
+ passh = match[2]
96
+ crypt(pass, :md5, salt) == passr
97
+ #pass.crypt(salt) == passr
98
+ rescue Exception => e
99
+ false
100
+ end
101
+ end
102
+
103
+ end
104
+ end
data/lib/log.rb ADDED
@@ -0,0 +1,25 @@
1
+ module Ig3tool
2
+
3
+ class LogEntry < ActiveRecord::Base
4
+
5
+ set_table_name "log"
6
+
7
+ validates_presence_of :system,
8
+ :subsystem,
9
+ :timestamp,
10
+ :message
11
+
12
+ end
13
+
14
+ class Logger
15
+
16
+ def self.log(system, subsystem, message)
17
+ LogEntry.create(:system => system.to_s,
18
+ :timestamp => Time.now.to_i,
19
+ :subsystem => subsystem.to_s,
20
+ :message => message.to_s)
21
+ end
22
+
23
+ end
24
+
25
+ end
data/lib/membership.rb ADDED
@@ -0,0 +1,32 @@
1
+ module Ig3tool
2
+ class Membership < ActiveRecord::Base
3
+ set_table_name "Memberships"
4
+ set_nonauto_primary_key :barcode
5
+
6
+ validates_uniqueness_of :barcode
7
+
8
+ validates_presence_of :barcode,
9
+ :username,
10
+ :year,
11
+ :status
12
+
13
+ validates_inclusion_of :status,
14
+ :in => ["debugger",
15
+ "ex-debugger",
16
+ "member",
17
+ "honorary member"]
18
+
19
+ belongs_to :person,
20
+ :class_name => "Person",
21
+ :foreign_key => "username"
22
+
23
+ def self.member?(barcode)
24
+ begin
25
+ membership = find(barcode)
26
+ membership.year == Time.werkjaar
27
+ rescue ActiveRecord::RecordNotFound
28
+ false
29
+ end
30
+ end
31
+ end
32
+ end
data/lib/mymd5.rb ADDED
@@ -0,0 +1,95 @@
1
+ require 'English'
2
+ require 'base64'
3
+ require 'md5'
4
+ require 'sha1'
5
+
6
+ ITOA64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
7
+
8
+
9
+ def crypt(password, algo = :md5, salt = nil, magic='$1$')
10
+
11
+ salt ||= generate_salt(8)
12
+
13
+ case algo
14
+ when :md5, :sha1, :rmd160
15
+ require "digest/#{algo}"
16
+ when :sha256, :sha384, :sha512
17
+ require "digest/sha2"
18
+ else
19
+ raise(ArgumentError, "unknown algorithm")
20
+ end
21
+ digest_class = Digest.const_get(algo.to_s.upcase)
22
+
23
+ # The password first, since that is what is most unknown. Then our magic string. Then the raw salt.
24
+ m = digest_class.new
25
+ m.update(password + magic + salt)
26
+
27
+ # Then just as many characters of the MD5(pw,salt,pw)
28
+ mixin = digest_class.new.update(password + salt + password).digest
29
+ password.length.times do |i|
30
+ m.update(mixin[i % 16].chr)
31
+ end
32
+
33
+ # Then something really weird...
34
+ # Also really broken, as far as I can tell. -m
35
+ i = password.length
36
+ while i != 0
37
+ if (i & 1) != 0
38
+ m.update("\x00")
39
+ else
40
+ m.update(password[0].chr)
41
+ end
42
+ i >>= 1
43
+ end
44
+
45
+ final = m.digest
46
+
47
+ # and now, just to make sure things don't run too fast
48
+ 1000.times do |i|
49
+ m2 = digest_class.new
50
+
51
+ if (i & 1) != 0
52
+ m2.update(password)
53
+ else
54
+ m2.update(final)
55
+ end
56
+
57
+ if (i % 3) != 0
58
+ m2.update(salt)
59
+ end
60
+ if (i % 7) != 0
61
+ m2.update(password)
62
+ end
63
+
64
+ if (i & 1) != 0
65
+ m2.update(final)
66
+ else
67
+ m2.update(password)
68
+ end
69
+
70
+ final = m2.digest
71
+ end
72
+
73
+ # This is the bit that uses to64() in the original code.
74
+
75
+ rearranged = ""
76
+
77
+ [ [0, 6, 12], [1, 7, 13], [2, 8, 14], [3, 9, 15], [4, 10, 5] ].each do |a, b, c|
78
+
79
+ v = final[a] << 16 | final[b] << 8 | final[c]
80
+
81
+ 4.times do
82
+ rearranged += ITOA64[v & 0x3f].chr
83
+ v >>= 6
84
+ end
85
+ end
86
+
87
+ v = final[11]
88
+
89
+ 2.times do
90
+ rearranged += ITOA64[v & 0x3f].chr
91
+ v >>= 6
92
+ end
93
+
94
+ magic + salt + '$' + rearranged
95
+ end
data/lib/people.rb ADDED
@@ -0,0 +1,143 @@
1
+ require 'utils'
2
+
3
+ module Ig3tool
4
+
5
+ class Person < ActiveRecord::Base
6
+
7
+ set_table_name "people"
8
+ set_nonauto_primary_key :username
9
+
10
+ # XXX wat willen we dat aanwezig is?
11
+ validates_presence_of :username,
12
+ :email,
13
+ :first_name,
14
+ :last_name
15
+
16
+ validates_uniqueness_of :username,
17
+ :email
18
+
19
+ has_one :interne,
20
+ :class_name => "Interne",
21
+ :foreign_key => "username"
22
+
23
+ # breekt horribly met to_yaml, zucht
24
+ # has_one :membership,
25
+ # :conditions => ["year = ?", Time.werkjaar],
26
+ # :class_name => 'Membership',
27
+ # :foreign_key => "username"
28
+
29
+ has_many :memberships,
30
+ :class_name => "Membership",
31
+ :foreign_key => "username",
32
+ :order => "year desc"
33
+
34
+ has_one :print_user,
35
+ :class_name => "PrintUser",
36
+ :foreign_key => "username"
37
+ # :dependent => :destroy # destroyes printuser when person gets deleted
38
+ # XXX do we want that?
39
+
40
+ def membership
41
+ if !memberships.empty? and memberships[0].year == Time.werkjaar
42
+ memberships[0]
43
+ else
44
+ nil
45
+ end
46
+ end
47
+
48
+ def username=(newusername)
49
+ write_attribute(:username, newusername)
50
+ end
51
+
52
+ def member?
53
+ not membership.nil?
54
+ end
55
+
56
+ def honorarymember?
57
+ member? and membership.status == "honorary member"
58
+ end
59
+
60
+ def exhonorarymember?
61
+ not honorarymember? and not memberships.find(:all).find_all{|m| m.status == "honorary member"}.empty?
62
+ end
63
+
64
+ def debugger?
65
+ (not interne.nil?) and (interne.afgesloten != 1) and member? and (membership.status == "debugger")
66
+ end
67
+
68
+ def exdebugger?
69
+ (not debugger?) and (not memberships.find(:all).find_all{|m| m.status == "debugger" or m.status == "ex-debugger"}.empty?)
70
+ end
71
+
72
+ def self.everybody
73
+ find(:all)
74
+ end
75
+
76
+ def self.members
77
+ find(:all).find_all{|p| p.member?}
78
+ end
79
+
80
+ def self.nonmembers
81
+ find(:all).find_all{|p| p.membership.nil?}
82
+ end
83
+
84
+ def self.debuggers
85
+ find(:all).find_all{|p| p.debugger?}
86
+ end
87
+
88
+ def self.exdebuggers
89
+ find(:all).find_all{|p| p.exdebugger?}
90
+ end
91
+
92
+ def self.honorarymembers
93
+ find(:all).find_all{|p| p.honorarymember?}
94
+ end
95
+
96
+ def self.exhonorarymembers
97
+ find(:all).find_all{|p| p.exhonorarymember?}
98
+ end
99
+
100
+ def unbugger!
101
+ raise NotADebugger unless debugger?
102
+ raise SaldoNotZero if interne.saldo != 0
103
+
104
+ interne.afgesloten = true
105
+ membership.status = "member"
106
+
107
+ transaction do
108
+ print_user.remove_aliases
109
+
110
+ membership.save!
111
+ interne.save!
112
+ end
113
+ end
114
+
115
+ def bugger!
116
+ raise NotAMember unless member?
117
+ raise IG3Error, "already a debugger" if debugger?
118
+
119
+ membership.status = "debugger"
120
+
121
+ # interne
122
+ self.interne = i = Interne.new
123
+ i.username = username
124
+ i.saldo = 0
125
+ i.afgesloten = false
126
+
127
+ transaction do
128
+ # centjes overzetten
129
+ if print_user.saldo > 0
130
+ i.deposit("printaccount", print_user.saldo, "printkrediet")
131
+ # XXX print krediet?
132
+ # print_user.saldo = 0
133
+ end
134
+
135
+ membership.save!
136
+ i.save!
137
+ end
138
+ end
139
+
140
+ end
141
+
142
+
143
+ end
data/lib/printing.rb ADDED
@@ -0,0 +1,238 @@
1
+ module Ig3tool
2
+
3
+ # The printing section of ig3tool
4
+ #
5
+ # Classes & methods:
6
+ #
7
+ # PrintUser
8
+ # ---------
9
+ # lookup(username)
10
+ # looks for a printuser by username as well as alias
11
+ # use this method to look usernames up
12
+ #
13
+ # add_credit(amount)
14
+ # adds amount of credit to a user' saldo
15
+ #
16
+ # refund(amount, printid, msg)
17
+ # refunds a failed job
18
+ # should ONLY be called from PrintTransaction
19
+ #
20
+ # remove(username)
21
+ # removes a printuser along its aliasses
22
+ #
23
+ # print(job, pages, copies, host, amount, queue, message)
24
+ # handles the printing of a job
25
+ # should ONLY be used by the printscript
26
+ #
27
+ # err(queue, message)
28
+ # logs an error
29
+ # again printscript ONLY
30
+ #
31
+ #
32
+ #
33
+ # PrintAlias
34
+ # ----------
35
+ # no special functions
36
+ #
37
+ #
38
+ #
39
+ # PrintTransaction
40
+ # ----------------
41
+ # refund()
42
+ # refunds a specific job, calls aprintuser.refund()
43
+ #
44
+ #
45
+ #
46
+
47
+
48
+
49
+
50
+ # Implements a printuser.
51
+ class PrintUser < ActiveRecord::Base
52
+
53
+ set_table_name "print_users"
54
+ set_nonauto_primary_key :username
55
+ validates_uniqueness_of :username
56
+
57
+ # _username_ and _saldo_ must be provided
58
+ # a PrintUser must be linked with an existing _person_
59
+ validates_presence_of :username, :saldo, :person
60
+ belongs_to :person, :class_name => "Person", :foreign_key => "username"
61
+ has_many :print_transactions, :class_name => "PrintTransaction", :foreign_key => "username"
62
+ has_many :print_aliases, :class_name => "PrintAlias", :foreign_key => "username", :dependent => :destroy
63
+ attr_accessible :username
64
+ validates_associated :person
65
+
66
+ # override because of non-standard primary key
67
+ def username=(newusername)
68
+ write_attribute(:username, newusername)
69
+ save!
70
+ end
71
+
72
+ def self.lookup(username)
73
+ user = nil
74
+ begin
75
+ user = PrintUser.find(username) # Error if not found
76
+ rescue
77
+ begin
78
+ user = PrintAlias.find(username).print_user
79
+ rescue
80
+ raise NotFound, "the ig3tool imps found no such user..."
81
+ end
82
+ end
83
+ user
84
+ end
85
+
86
+ def self.errortest
87
+ raise NotFound
88
+ end
89
+
90
+ def remove_aliases
91
+ print_aliases.each {|pa| pa.destroy }
92
+ end
93
+
94
+ def self.remove(username)
95
+ user = PrintUser.lookup(username)
96
+ user.destroy
97
+ end
98
+
99
+ def email
100
+ self.person.email
101
+ end
102
+
103
+ def debugger?
104
+ self.person.debugger?
105
+ end
106
+
107
+ def add_credit (amount)
108
+ if self.debugger?
109
+ raise PermissionDenied, "debuggers cannot add credits to their account..."
110
+ else
111
+ PrintUser.transaction do
112
+ reload()
113
+ PrintTransaction.new do |pt|
114
+ pt.time = Time.now()
115
+ pt.username = username
116
+ pt.refunded = 0
117
+ pt.amount = amount.to_i
118
+ pt.queue = "ig3tool"
119
+ pt.message = "added #{amount} eurocents to #{username}'s account."
120
+ pt.category = "add"
121
+ pt.save!
122
+ end
123
+ self.saldo += amount.to_i
124
+ save!
125
+ end
126
+ end
127
+ end
128
+
129
+ def refund(amount, printid, undo, msg)
130
+ PrintUser.transaction do
131
+ reload()
132
+ pt = PrintTransaction.new
133
+ pt.time = Time.now()
134
+ pt.username = username
135
+ pt.refunded = 0
136
+ pt.queue = "ig3tool"
137
+ pt.amount = amount.to_i
138
+ pt.message = "#{"undo " if undo}refunded print #{printid} of #{amount} euro to #{username}."
139
+ pt.category = "refund"
140
+ pt.save!
141
+ if debugger?
142
+ person.interne.refundprint(amount, "#{"undo " if undo }refund print, id: #{printid}", undo)
143
+ else
144
+ if undo
145
+ self.saldo += amount
146
+ else
147
+ self.saldo -= amount
148
+ end
149
+ save!
150
+ end
151
+ end
152
+ end
153
+
154
+ def print(job, pages, copies, host, amount, queue, message)
155
+ PrintUser.transaction do
156
+ reload()
157
+ PrintTransaction.new do |pt|
158
+ pt.time = Time.now()
159
+ pt.username = username
160
+ pt.refunded = 0
161
+ pt.amount = amount.to_i
162
+ pt.pages = pages.to_i
163
+ pt.copies = copies.to_i
164
+ pt.host = host
165
+ pt.queue = queue
166
+ pt.job = job
167
+ pt.message = "Printed #{job} of #{pages} pages for #{amount} EUR - #{message}"
168
+ pt.category = "print"
169
+ pt.save!
170
+ end
171
+ if debugger?
172
+ person.interne.print(amount, "job: #{job}")
173
+ else
174
+ if self.saldo < amount.to_i
175
+ raise NotEnoughCredit, "you are broke!"
176
+ else
177
+ self.saldo -= amount.to_i
178
+ save!
179
+ end
180
+ end
181
+ end
182
+ end
183
+
184
+
185
+ def err(message, queue)
186
+ PrintTransaction.new do |pt|
187
+ pt.time = Time.now()
188
+ pt.username = username
189
+ pt.queue = queue
190
+ pt.category = "error"
191
+ pt.save!
192
+ end
193
+ end
194
+
195
+ end
196
+
197
+
198
+ class PrintAlias < ActiveRecord::Base
199
+
200
+ set_table_name "print_aliases"
201
+ set_primary_key :alias
202
+ validates_uniqueness_of :alias
203
+ validates_presence_of :alias, :username, :print_user
204
+ belongs_to :print_user, :class_name => "PrintUser", :foreign_key => "username"
205
+ validates_associated :print_user
206
+
207
+ def alias=(newalias)
208
+ @attributes["alias"] = newalias
209
+ end
210
+
211
+ end
212
+
213
+
214
+ class PrintTransaction < ActiveRecord::Base
215
+
216
+ set_table_name "print_transactions"
217
+ validates_presence_of :time, :username, :category, :queue
218
+ validates_inclusion_of :category, :in => ["error", "add", "print", "refund", "debug"]
219
+ belongs_to :printuser, :class_name => "PrintUser", :foreign_key => "username"
220
+ attr_protected :refunded
221
+
222
+ def refund
223
+ PrintTransaction.transaction do
224
+ reload()
225
+ if category == "print" then
226
+ printuser.refund(amount, id, !refunded.to_b, message)
227
+ toggle!(:refunded)
228
+ else
229
+ raise WrongPrintlogType
230
+ end
231
+ end
232
+ end
233
+
234
+ end # class PrintTransaction
235
+
236
+
237
+
238
+ end # module Ig3tool