gestion 1.9.12

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 (233) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +48 -0
  3. data/.project +14 -0
  4. data/Binaries/adduser_to_buzz +15 -0
  5. data/Binaries/backup +7 -0
  6. data/Binaries/check_gestion +8 -0
  7. data/Binaries/gestion.gnumail +22 -0
  8. data/Binaries/gestion.logrotate +34 -0
  9. data/Binaries/gestion.service +12 -0
  10. data/Binaries/gestion_update.rb +183 -0
  11. data/Binaries/gestion_update.service +10 -0
  12. data/Binaries/get_compta +11 -0
  13. data/Binaries/kill_gestion +16 -0
  14. data/Binaries/ldap/add_indexes +51 -0
  15. data/Binaries/ldap/backup +2 -0
  16. data/Binaries/ldap/install_ldap +92 -0
  17. data/Binaries/ldap/restore +7 -0
  18. data/Binaries/lib_backup +5 -0
  19. data/Binaries/log_scan_errors +8 -0
  20. data/Binaries/loop_gestion +64 -0
  21. data/Binaries/onetimers/sync_courses_from_compta.rb +74 -0
  22. data/Binaries/onetimers/transfer_cash_from_ldap_to_csv +26 -0
  23. data/Binaries/reboot +5 -0
  24. data/Binaries/restore +3 -0
  25. data/Binaries/restore_do +22 -0
  26. data/Binaries/sort_events +31 -0
  27. data/Binaries/start_gestion +18 -0
  28. data/Binaries/swipe_gestion +18 -0
  29. data/Binaries/update_africompta +21 -0
  30. data/Binaries/update_users +3 -0
  31. data/Diplomas.src/accredited.odg +0 -0
  32. data/Diplomas.src/diploma.odg +0 -0
  33. data/Diplomas.src/label.odg +0 -0
  34. data/Diplomas.src/presence_sheet.ods +0 -0
  35. data/Diplomas.src/presence_sheet_small.ods +0 -0
  36. data/Diplomas.src/student_card.odg +0 -0
  37. data/Doc/130514-it-ideas.odt +0 -0
  38. data/Doc/Compta-cash.mm +179 -0
  39. data/Doc/General.odt +0 -0
  40. data/Entities/AccessGroups.rb +117 -0
  41. data/Entities/Activity.rb +178 -0
  42. data/Entities/ChatMsg.rb +142 -0
  43. data/Entities/Classroom.rb +11 -0
  44. data/Entities/Client.rb +19 -0
  45. data/Entities/Computer.rb +21 -0
  46. data/Entities/ConfigBase.rb +280 -0
  47. data/Entities/Course.rb +1588 -0
  48. data/Entities/CourseType.rb +171 -0
  49. data/Entities/DFiles.rb +466 -0
  50. data/Entities/FilesManage.rb +226 -0
  51. data/Entities/Grade.rb +186 -0
  52. data/Entities/Internet.rb +300 -0
  53. data/Entities/Netdev.rb +10 -0
  54. data/Entities/Person.rb +1175 -0
  55. data/Entities/Plug.rb +98 -0
  56. data/Entities/Quiz.rb +33 -0
  57. data/Entities/Recharges.rb +37 -0
  58. data/Entities/Report.rb +136 -0
  59. data/Entities/Room.rb +12 -0
  60. data/Entities/SMS.rb +30 -0
  61. data/Entities/ScheduleType.rb +33 -0
  62. data/Entities/Share.rb +120 -0
  63. data/Entities/Task.rb +51 -0
  64. data/Entities/Ticket.rb +72 -0
  65. data/Entities/Usage.rb +143 -0
  66. data/Entities/Worker.rb +29 -0
  67. data/Files/apache-profeda.conf +36 -0
  68. data/Files/label.erb +121 -0
  69. data/Files/label_notfound.erb +64 -0
  70. data/Files/label_notpassed.erb +84 -0
  71. data/Files/mobileinfo.erb +115 -0
  72. data/Files/smb.conf +333 -0
  73. data/Files/timetable.html +36 -0
  74. data/Files/timetable.js +239 -0
  75. data/Gemfile +12 -0
  76. data/Gemfile.dev +12 -0
  77. data/Gemfile.dev.lock +127 -0
  78. data/Gemfile.lock +127 -0
  79. data/Gemfile.prod +8 -0
  80. data/Gestion +35 -0
  81. data/Gestion.rb +220 -0
  82. data/INSTALL +40 -0
  83. data/Images/connection.xcf +0 -0
  84. data/Images/connection_no.png +0 -0
  85. data/Images/connection_wait.png +0 -0
  86. data/Images/connection_yes.png +0 -0
  87. data/Paths/Exas.rb +13 -0
  88. data/Paths/Files.rb +19 -0
  89. data/Paths/GetDiplomas.rb +20 -0
  90. data/Paths/Info.rb +114 -0
  91. data/Paths/Label.rb +187 -0
  92. data/Paths/MobileInfo.rb +19 -0
  93. data/Paths/internetCash.rb +34 -0
  94. data/Paths/internetWifi.rb +54 -0
  95. data/README.md +60 -0
  96. data/Rakefile +13 -0
  97. data/TODO +1391 -0
  98. data/Test/.gitignore +3 -0
  99. data/Test/Diplomas/base_gestion.odt +0 -0
  100. data/Test/Diplomas/base_report.odt +0 -0
  101. data/Test/Diplomas/carte_etudiant.odg +0 -0
  102. data/Test/Diplomas/exam_language.odt +0 -0
  103. data/Test/Diplomas/label.odg +0 -0
  104. data/Test/Diplomas/presence_sheet.ods +0 -0
  105. data/Test/Diplomas/presence_sheet_small.ods +0 -0
  106. data/Test/Diplomas/student_card.odg +0 -0
  107. data/Test/Manual/testMerge +18 -0
  108. data/Test/config_test.yaml +26 -0
  109. data/Test/db.testGestion +0 -0
  110. data/Test/dfiles/descs/avg-rescue.desc +10 -0
  111. data/Test/dfiles/descs/avg.desc +8 -0
  112. data/Test/dfiles/descs/driver.desc +8 -0
  113. data/Test/dfiles/descs/linuxmint.desc +7 -0
  114. data/Test/dfiles/files/avg-160203.exe +1 -0
  115. data/Test/dfiles/files/avg.iso +1 -0
  116. data/Test/dfiles/files/driver.exe +1 -0
  117. data/Test/dfiles/index_post.html +3 -0
  118. data/Test/dfiles/index_pre.html +8 -0
  119. data/Test/dfiles/priorities +5 -0
  120. data/Test/ge_activity.rb +124 -0
  121. data/Test/ge_chat.rb +106 -0
  122. data/Test/ge_compta.rb +67 -0
  123. data/Test/ge_configbase.rb +54 -0
  124. data/Test/ge_course.rb +1114 -0
  125. data/Test/ge_dfiles.rb +121 -0
  126. data/Test/ge_filesmanage.rb +180 -0
  127. data/Test/ge_info.rb +27 -0
  128. data/Test/ge_internet.rb +246 -0
  129. data/Test/ge_login.rb +55 -0
  130. data/Test/ge_person.rb +373 -0
  131. data/Test/ge_qvinfo.rb +28 -0
  132. data/Test/ge_report.rb +97 -0
  133. data/Test/ge_share.rb +27 -0
  134. data/Test/ge_sms.rb +34 -0
  135. data/Test/ge_tasks.rb +19 -0
  136. data/Test/ge_usage.rb +168 -0
  137. data/Test/ge_view.rb +46 -0
  138. data/Test/multiconf-captive +29 -0
  139. data/Test/test.conf +7 -0
  140. data/Test/test.rb +49 -0
  141. data/Test/test_bytes.png +0 -0
  142. data/VERSION +140 -0
  143. data/Views/Admin/Backup.rb +91 -0
  144. data/Views/Admin/Configuration.rb +44 -0
  145. data/Views/Admin/Credit.rb +32 -0
  146. data/Views/Admin/FilesManage.rb +219 -0
  147. data/Views/Admin/Function.rb +39 -0
  148. data/Views/Admin/Power.rb +49 -0
  149. data/Views/Admin/Printer.rb +37 -0
  150. data/Views/Admin/Server.rb +252 -0
  151. data/Views/Admin/Tabs.rb +5 -0
  152. data/Views/Admin/Update.rb +73 -0
  153. data/Views/Admin/UpdateSystem.rb +26 -0
  154. data/Views/Cashbox/Activity.rb +191 -0
  155. data/Views/Cashbox/Course.rb +141 -0
  156. data/Views/Cashbox/Credit.rb +79 -0
  157. data/Views/Cashbox/Report.rb +115 -0
  158. data/Views/Cashbox/Service.rb +105 -0
  159. data/Views/Cashbox/Tabs.rb +10 -0
  160. data/Views/Compta/Accounts.rb +36 -0
  161. data/Views/Compta/Course.rb +96 -0
  162. data/Views/Compta/Show.rb +6 -0
  163. data/Views/Compta/Transfer.rb +66 -0
  164. data/Views/Course/Diploma.rb +203 -0
  165. data/Views/Course/Grade.rb +401 -0
  166. data/Views/Course/Modify.rb +447 -0
  167. data/Views/Course/Print.rb +94 -0
  168. data/Views/Course/Responsible.rb +44 -0
  169. data/Views/Course/Stats.rb +76 -0
  170. data/Views/Course/Students.rb +92 -0
  171. data/Views/Course/Tabs.rb +220 -0
  172. data/Views/Internet/Access.rb +134 -0
  173. data/Views/Internet/ClassEdit.rb +24 -0
  174. data/Views/Internet/ClassUsers.rb +81 -0
  175. data/Views/Internet/Config.rb +32 -0
  176. data/Views/Internet/Mobile.rb +213 -0
  177. data/Views/Internet/Recharges.rb +49 -0
  178. data/Views/Internet/Tabs.rb +6 -0
  179. data/Views/Inventory/Computer.rb +24 -0
  180. data/Views/Inventory/Room.rb +18 -0
  181. data/Views/Inventory/Tabs.rb +9 -0
  182. data/Views/Inventory/TicketClosed.rb +7 -0
  183. data/Views/Inventory/TicketOpen.rb +23 -0
  184. data/Views/Library/Person.rb +36 -0
  185. data/Views/Library/Tabs.rb +7 -0
  186. data/Views/Network/Block.rb +87 -0
  187. data/Views/Network/Netdevs.rb +21 -0
  188. data/Views/Network/Restriction.rb +37 -0
  189. data/Views/Network/Share.rb +167 -0
  190. data/Views/Network/Tables.rb +28 -0
  191. data/Views/Network/Tabs.rb +6 -0
  192. data/Views/Person/Admin.rb +99 -0
  193. data/Views/Person/Center.rb +48 -0
  194. data/Views/Person/Course.rb +72 -0
  195. data/Views/Person/Modify.rb +153 -0
  196. data/Views/Person/Tabs.rb +162 -0
  197. data/Views/Report/ComptaExecutive.rb +221 -0
  198. data/Views/Report/ComptaFlat.rb +79 -0
  199. data/Views/Report/ReportCourse.rb +47 -0
  200. data/Views/Report/Tabs.rb +8 -0
  201. data/Views/Report/Usage.rb +52 -0
  202. data/Views/Report/UsageCases.rb +59 -0
  203. data/Views/Self/Cash.rb +67 -0
  204. data/Views/Self/Chat.rb +55 -0
  205. data/Views/Self/Concours.rb +109 -0
  206. data/Views/Self/Email.rb +34 -0
  207. data/Views/Self/Internet.rb +255 -0
  208. data/Views/Self/Results.rb +17 -0
  209. data/Views/Self/Services.rb +85 -0
  210. data/Views/Self/Show.rb +47 -0
  211. data/Views/Self/Tabs.rb +5 -0
  212. data/Views/Special/DFileEdit.rb +13 -0
  213. data/Views/Special/PlugEdit.rb +56 -0
  214. data/Views/Special/Tabs.rb +6 -0
  215. data/Views/Special/Vnc.rb +39 -0
  216. data/Views/Task/Client.rb +21 -0
  217. data/Views/Task/Edit.rb +33 -0
  218. data/Views/Task/List.rb +55 -0
  219. data/Views/Task/Tabs.rb +9 -0
  220. data/Views/Task/Worker.rb +30 -0
  221. data/Views/Template/Activity.rb +33 -0
  222. data/Views/Template/CourseType.rb +63 -0
  223. data/Views/Template/ScheduleType.rb +29 -0
  224. data/Views/Template/Tabs.rb +5 -0
  225. data/Views/Welcome.rb +121 -0
  226. data/config.yaml.default +36 -0
  227. data/po/Gestion-ar.po +2356 -0
  228. data/po/Gestion-en.mo +0 -0
  229. data/po/Gestion-en.po +4363 -0
  230. data/po/Gestion-fr.mo +0 -0
  231. data/po/Gestion-fr.po +4345 -0
  232. data/po/traduction-ar.rtf +76 -0
  233. metadata +381 -0
@@ -0,0 +1,1175 @@
1
+ # Holds the data available for a person. The permission is a regexp
2
+ # giving access to different views and it's blocks
3
+ #
4
+ # Configuration:
5
+ # adduser_cmd - is called after ldapadduser returns with the username as argument
6
+
7
+ class String
8
+ def capitalize_all
9
+ self.split(' ').collect { |s| s.capitalize }.join(' ')
10
+ end
11
+
12
+ def capitalize_all!
13
+ self.replace self.capitalize_all
14
+ end
15
+ end
16
+
17
+ class IsNecessary < Exception
18
+ attr :for_course
19
+
20
+ def initialize(course)
21
+ @for_course = course
22
+ end
23
+ end
24
+
25
+
26
+ class Persons < Entities
27
+ attr_accessor :print_card_student, :print_card_responsible, :resps
28
+ self.needs :Courses
29
+
30
+ def setup_data
31
+ add_new_storage :LDAP
32
+
33
+ value_block :address
34
+ value_str_LDAP :first_name, :ldap_name => 'sn'
35
+ value_str_LDAP :family_name, :ldap_name => 'givenname'
36
+ value_list_drop :gender, '%w( male female n/a )'
37
+ value_date :birthday
38
+ value_str :address
39
+ value_str_LDAP :phone, :ldap_name => 'mobile'
40
+ value_str_LDAP :email, :ldap_name => 'mail'
41
+ value_str_LDAP :town, :ldap_name => 'l'
42
+ value_str_LDAP :country, :ldap_name => 'st'
43
+ value_str :profession
44
+ value_str :school_grade
45
+
46
+ value_block :admin
47
+ #value_str :account_name_due
48
+ #value_str :account_name_cash
49
+ value_str :role_diploma
50
+ value_list :permissions, 'Permission.list.sort'
51
+
52
+ value_block :accounts
53
+ value_entity_account :account_due
54
+ value_entity_account :account_due_paid
55
+ value_entity_account :account_cash
56
+
57
+ value_block :internet
58
+ value_list :groups, '%w( freesurf sudo print localonly share ).sort'
59
+ value_list_single :internet_none, '[]'
60
+
61
+ value_block :read_only
62
+ value_str_ro_LDAP :login_name, :ldap_name => 'uid'
63
+ # credit -> internet_credit
64
+ # credit_due -> account_total_due
65
+ value_int_ro :internet_credit
66
+ value_int_ro :account_total_due
67
+
68
+ value_block :email_account
69
+ value_str :acc_remote
70
+ value_str :acc_pass
71
+ value_list_drop :acc_proto, '%w( POP3 IMAP )'
72
+ value_list_drop :acc_port, '%w( 110 993 995 )'
73
+ value_list_drop :acc_supp, '["ssl keep", "ssl", "keep", ""]'
74
+
75
+ value_block :hidden
76
+ value_str :session_id
77
+ value_str_LDAP :password, :ldap_name => 'userPassword'
78
+ value_str :password_plain
79
+ value_int_LDAP :person_id, :ldap_name => 'uidnumber'
80
+
81
+ @resps = []
82
+ @resps_course = []
83
+ ConfigBases.add_observer(self, :update_config)
84
+ update_config(nil, nil, nil)
85
+ end
86
+
87
+ def self.admin_users
88
+ ConfigBase.persons_add_del_users == %w(true) &&
89
+ !get_config(false, :Entities, :Persons, :user_simulation)
90
+ end
91
+
92
+ def update_config(action, value, old)
93
+ dputs(3) { "Updating #{action} with #{value.inspect}" }
94
+ case action
95
+ when :function_add
96
+ if value.index :accounting_courses
97
+ search_all_.each { |p|
98
+ dputs(3) { "Searching if #{p.login_name} needs new accounts" }
99
+ p.update_accounts
100
+ }
101
+ end
102
+ when :function_del
103
+ else
104
+ ddir = Courses.dir_diplomas
105
+ cdir = "#{ddir}/cartes"
106
+ if !File.exist? cdir
107
+ FileUtils::mkdir_p(cdir)
108
+ end
109
+ @print_card_student = OpenPrint.new(
110
+ ConfigBase.template_path(:card_student), cdir)
111
+ @print_card_responsible = OpenPrint.new(
112
+ ConfigBase.template_path(:card_responsible), cdir)
113
+ end
114
+ end
115
+
116
+ def migration_1(p)
117
+ if p.person_id == 0
118
+ dputs(0) { 'Error: Oups, found person with id 0 - trying to change this' }
119
+ p.person_id = Persons.new_id[:person_id]
120
+ dputs(2) { "Putting person-id to #{p.person_id}" }
121
+ end
122
+ end
123
+
124
+ def migration_2_raw(p)
125
+ dputs(2) { "p is #{p.class}" }
126
+ p._internet_credit = p._credit
127
+ p._account_total_due = p._credit_due
128
+ p._account_name_due = p._account_due
129
+ end
130
+
131
+ def migration_3(p)
132
+ if p.permissions.class != Array
133
+ p.permissions = []
134
+ end
135
+ end
136
+
137
+ def migration_4(p)
138
+ p.gender = %w( n/a )
139
+ end
140
+
141
+ def fetch_account(r, a)
142
+ Accounts.get_by_path_or_create("#{r}::#{a}")
143
+ end
144
+
145
+ def migration_5_raw(d)
146
+ #dp d.inspect
147
+ if d._account_name_due
148
+ r = get_config('Root::Lending', :Accounting, :lending)
149
+ d._account_due = fetch_account(r, d._account_name_due).id
150
+ d._account_due_paid = fetch_account(r, "#{d._account_name_due}::Paid").id
151
+ end
152
+ if d._account_name_cash
153
+ r = get_config('Root::Cash', :Accounting, :cash)
154
+ d._account_cash = fetch_account(r, d._account_name_cash).id
155
+ end
156
+ #dp d.inspect
157
+ end
158
+
159
+ # Searches for an empty name starting with "login", adding 2, 3, 4, ...
160
+ def find_empty_login_name(login)
161
+ suffix = ''
162
+ login = accents_replace(login)
163
+ while match_by_login_name(login + suffix.to_s)
164
+ dputs(2) { "Found #{login + suffix.to_s} to already exist" }
165
+ suffix = suffix.to_i + 1
166
+ suffix = 2 if suffix == 1
167
+ end
168
+ login + suffix.to_s
169
+ end
170
+
171
+ def create_first_family(fullname)
172
+ # Trying to be intelligent about splitting up of names
173
+ if fullname.split(' ').length > 1
174
+ names = fullname.split(' ')
175
+ s = names.length < 4 ? 0 : 1
176
+ first = names[0..s].join(' ')
177
+ family = names[(s+1)..-1].join(' ')
178
+ dputs(2) { "Creating user #{names.inspect} as #{first} - #{family}" }
179
+ [first, family]
180
+ else
181
+ [fullname, '']
182
+ end
183
+ end
184
+
185
+ def accents_replace(login)
186
+ login = login.downcase.gsub(/ /, '_')
187
+ accents = Hash[*%w( a àáâä e éèêë i ìíîï o òóôöœ u ùúûü c ç ss ß )]
188
+ dputs(2) { "Login was #{login}" }
189
+ accents.each { |k, v|
190
+ login.gsub!(/[#{v}]/, k)
191
+ }
192
+ login.gsub!(/[^a-z0-9_-]/, '_')
193
+ dputs(2) { "Login is #{login}" }
194
+ login
195
+ end
196
+
197
+ # Creates a login-name out of "first" and "family" name - should work nicely in
198
+ # Africa, perhaps a bit bizarre in Western-countries (like "tlinus" instead of
199
+ # "ltorvalds")
200
+ # if "family" is empty, it tries to generate some sensible values for "first" and
201
+ # "family" by itself
202
+ def create_login_name(first, family = '')
203
+ if family.length == 0
204
+ first, family = create_first_family(first)
205
+ end
206
+ if family.length > 0
207
+ dputs(2) { 'Family name + First name' }
208
+ login = family.chars.first + first.split.first
209
+ else
210
+ login = first.split.first
211
+ end
212
+
213
+ accents_replace(login)
214
+ end
215
+
216
+ def create(d)
217
+ # Sanitize first and family-name
218
+ if d.has_key? :complete_name
219
+ d[:first_name] = d[:complete_name]
220
+ end
221
+ if d.has_key? :first_name
222
+ if not d.has_key? :family_name or d[:family_name].length == 0
223
+ d[:first_name], d[:family_name] = create_first_family(d[:first_name])
224
+ end
225
+ d[:first_name].capitalize_all!
226
+ d[:family_name].capitalize_all!
227
+ elsif d.has_key? :login_name
228
+ d[:first_name] = d[:login_name]
229
+ else
230
+ dputs(0) { "Error: Trying to create Person with missing names: #{d.inspect}" }
231
+ return nil
232
+ end
233
+ if !d[:login_name] or d[:login_name].length == 0
234
+ d[:login_name] = create_login_name(d[:first_name], d[:family_name])
235
+ end
236
+
237
+ if d.has_key? :login_name_prefix
238
+ d[:login_name] = d[:login_name_prefix] + d[:login_name]
239
+ end
240
+ d[:login_name] = find_empty_login_name(d[:login_name])
241
+ d[:person_id] = nil
242
+ log_msg :person, "Creating Person #{d.inspect}"
243
+
244
+ person = super(d, true)
245
+
246
+ person.password_plain = d.has_key?(:password) ? d[:password] : rand(10000).to_s.rjust(4, '0')
247
+ person.password = person.password_plain
248
+
249
+ if (cmd = ConfigBase.persons_addeduser_cmd).to_s.length > 0
250
+ dputs(2) { "Going to call #{cmd} #{person.login_name} #{person.password_plain}" }
251
+ System.run_bool("#{cmd} #{person.login_name} #{person.password_plain}")
252
+ end
253
+
254
+ return person
255
+ end
256
+
257
+ def self.create_empty
258
+ Entities.Persons.create([])
259
+ end
260
+
261
+ def create_person(full_name, creator = nil, login_prop = nil)
262
+ new_data = {:login_name => login_prop,
263
+ :complete_name => full_name}
264
+ perms = ['internet']
265
+ if creator and creator.permissions.index('center')
266
+ new_data.merge!({:login_name_prefix => "#{creator.login_name}_"})
267
+ perms.push('teacher')
268
+ end
269
+ Persons.create(new_data.merge(:permissions => perms))
270
+ end
271
+
272
+ def update(session)
273
+ super(session).merge({:account_total_due => session.owner.internet_credit})
274
+ end
275
+
276
+ # Adds cash to a persons account. The hash "data" should contain the following
277
+ # fields:
278
+ # - credit_add : how much CFA to add
279
+ # - person_id : the id of the person to receive the credit
280
+ def add_internet_credit(session, data)
281
+ dputs(5) { "data is #{data.inspect}" }
282
+ client = match_by_login_name(data['login_name'].to_s)
283
+ if data._credit_add and client
284
+ actor = session.owner
285
+ dputs(3) { "Adding cash to #{client.full_name} from #{actor.full_name}" }
286
+ if client.login_name.to_s.length > 0
287
+ actor.add_internet_credit(client, data._credit_add)
288
+ else
289
+ dputs(0) { "Bizarre client: #{client.inspect} - #{session.inspect} - #{data.inspect}" }
290
+ end
291
+ return client
292
+ end
293
+ return nil
294
+ end
295
+
296
+ def get_login_with_permission(perm)
297
+ #persons = Entities.Persons.search_by_permissions(perm)
298
+ persons = Persons.data.select { |k, v|
299
+ v._permissions && v._permissions.index(perm) }.
300
+ collect { |k, v| Persons.get_data_instance(k) }
301
+ if persons
302
+ # The "select" at the end removes empty entries
303
+ persons.collect { |p|
304
+ p.login_name
305
+ }.select { |s| s }
306
+ else
307
+ []
308
+ end
309
+ end
310
+
311
+ def list_teachers
312
+ get_login_with_permission('teacher').sort
313
+ end
314
+
315
+ def list_assistants
316
+ get_login_with_permission('assistant').sort
317
+ end
318
+
319
+ def list_students
320
+ get_login_with_permission('student').sort
321
+ end
322
+
323
+ def listp_account_due
324
+ search_by_account_due('.+').select { |p|
325
+ # CashboxCredit-permission is the least for everybody who handles money.
326
+ p.login_name != 'admin' && p.has_permission?(:CashboxCredit)
327
+ }.collect { |p|
328
+ if p.account_due != nil
329
+ dputs(4) { "p is #{p.full_name}" }
330
+ dputs(4) { "account is #{p.account_due.get_path}" }
331
+ amount = (p.account_due.total.to_f * 1000).to_i.separator
332
+ name = p.full_name
333
+ if name.length == 0
334
+ name = p.login_name
335
+ end
336
+ [p.person_id, "#{amount.to_s.rjust(6)} - #{name}"]
337
+ else
338
+ [p.person_id, "0 - #{name}"]
339
+ end
340
+ }.sort { |a, b|
341
+ a[1] <=> b[1]
342
+ }.reverse
343
+ end
344
+
345
+ def save_data(d)
346
+ d = d.to_sym
347
+ dputs(3) { "d is #{d.inspect}" }
348
+
349
+ if !d[:first_name] and !d[:person_id]
350
+ return {:first_name => 'user'}
351
+ end
352
+
353
+ [:first_name, :family_name].each { |n|
354
+ d[n] && d[n].capitalize_all!
355
+ }
356
+
357
+ super(d)
358
+ end
359
+
360
+ def data_create(data)
361
+ dputs(2) { "Creating new data #{data.inspect}" }
362
+ if has_storage? :LDAP
363
+ user = data[:login_name]
364
+ if Kernel.system("ldapadduser #{user} plugdev")
365
+ if (cmd = ConfigBase.persons_adduser_cmd).to_s.length > 0
366
+ dputs(2) { "Going to call #{cmd} #{user.inspect}" }
367
+ System.run_bool("#{cmd} #{user}")
368
+ end
369
+ else
370
+ dputs(0) { "Error: Couldn't create #{user}" }
371
+ end
372
+ end
373
+ end
374
+
375
+ def find_full_name(name)
376
+ dputs(2) { "Searching for #{name}" }
377
+ @data.each_key { |k|
378
+ if @data[k]
379
+ fn = "#{data[k][:first_name]} #{data[k][:family_name]}"
380
+ dputs(2) { "Searching in #{fn}" }
381
+ if fn =~ /#{name}/i
382
+ dputs(2) { 'Found it' }
383
+ return get_data_instance(k)
384
+ end
385
+ end
386
+ }
387
+ return nil
388
+ end
389
+
390
+ def find_name_or_create(name)
391
+ first, last = name.split(' ', 2)
392
+ find_full_name(name) or
393
+ create(:first_name => first, :family_name => last)
394
+ end
395
+
396
+ def login_to_full(login)
397
+ p = match_by_login_name(login)
398
+ p ? p.full_name : ''
399
+ end
400
+
401
+ def listp_responsible(session = nil)
402
+ list = search_by_permissions('teacher')
403
+ if session
404
+ list = list.select { |p|
405
+ p.login_name =~ /^#{session.owner.login_name}_/
406
+ }.push(session.owner)
407
+ end
408
+ list.collect { |p|
409
+ [p.person_id, p.full_name]
410
+ }
411
+ end
412
+
413
+ def self.responsibles_raw
414
+ return Persons.data.select { |k, v|
415
+ v._permissions &&
416
+ Permission.can_view(v._permissions.reject { |perm| perm.to_s == 'admin' },
417
+ 'FlagResponsible')
418
+ }.collect { |k, v| Persons.find_by_person_id(k) }
419
+ end
420
+
421
+ def self.responsibles_sort(resps)
422
+ resps.collect { |p|
423
+ [p.person_id, p.full_name]
424
+ }.sort { |a, b| a.last <=> b.last }
425
+ end
426
+
427
+ def responsibles(force_update = false)
428
+ #dputs_func
429
+ if force_update || @resps.size == 0
430
+ dputs(3) { "Making responsible-cache with #{@data.size} entities" }
431
+ @resps = Persons.responsibles_raw
432
+ @resps = Persons.responsibles_sort(@resps)
433
+ else
434
+ dputs(3) { 'Lazily using responsible-cache' }
435
+ end
436
+ if force_update || @resps_course.size == 0
437
+ @resps_course = Courses.search_all_.collect { |c| [c.teacher, c.responsible, c.assistant] }.
438
+ flatten.compact.uniq
439
+ @resps_course = Persons.responsibles_sort(@resps_course)
440
+ end
441
+ (@resps + @resps_course).uniq.sort_by { |p| p[1] }
442
+ end
443
+
444
+ def responsibles_add(p)
445
+ e = [[p.person_id, p.full_name]]
446
+ if not @resps.index(e)
447
+ @resps = (@resps + e).sort { |a, b| a.last <=> b.last }
448
+ end
449
+ end
450
+
451
+ def responsibles_del(p)
452
+ e = [[p.person_id, p.full_name]]
453
+ if @resps.index(e)
454
+ @resps = (@resps - e).sort { |a, b| a.last <=> b.last }
455
+ end
456
+ end
457
+
458
+ def create_add_course(student, owner, course, check_double = false)
459
+ prefix = ConfigBase.has_function?(:course_server) ?
460
+ "#{owner.login_name}_" : ''
461
+ login_name = Persons.create_login_name(student)
462
+ if not (person = Persons.match_by_login_name(prefix + student))
463
+ if check_double and
464
+ Persons.search_by_login_name("^#{prefix}#{login_name}[0-9]*$").length > 0
465
+ return nil
466
+ else
467
+ person = Persons.create({:first_name => student,
468
+ :login_name_prefix => prefix,
469
+ :permissions => %w( student ), :town => @town, :country => @country})
470
+ end
471
+ end
472
+ #person.email = "#{person.login_name}@ndjair.net"
473
+ person and course.students_add person
474
+ person
475
+ end
476
+
477
+ def delete_all(local_only = false)
478
+ super(local_only)
479
+ @resps = []
480
+ end
481
+
482
+ def self.update_fetchmailrc
483
+ begin
484
+ File.open('/etc/fetchmailrc', 'w') { |f|
485
+ f.write <<-start
486
+ set daemon 600
487
+
488
+ start
489
+ Persons.search_by_permissions(:email).each { |p|
490
+ if p.acc_proto.class == Array &&
491
+ p.acc_port.class == Array &&
492
+ p.acc_supp.class == Array &&
493
+ p.email && p.acc_pass
494
+ proto, port, supp =
495
+ p.acc_proto.join, p.acc_port.join, p.acc_supp.join
496
+ if proto.length * port.length * p.email.length * p.acc_pass.length > 0
497
+ dputs(2) { "Adding #{p.login_name} to fetchmailrc" }
498
+ f.write <<-person
499
+ poll #{p.acc_remote} uidl with proto #{p.acc_proto.join}
500
+ auth password port #{p.acc_port.join}
501
+ user '#{p.email}' there with password '#{p.acc_pass}'
502
+ is #{p.login_name} here
503
+ mimedecode #{p.acc_supp.join}
504
+ option limit 1000000 batchlimit 10 fetchlimit 10 fetchsizelimit 20
505
+
506
+ person
507
+ end
508
+ end
509
+ }
510
+
511
+ f.chmod 0700
512
+ }
513
+ FileUtils.chown 'fetchmail', 'nobody', '/etc/fetchmailrc'
514
+ rescue Errno::EACCES => e
515
+ dputs(0) { "Can't write fetchmailrc here..." }
516
+ self.permissions = permissions - %w(email)
517
+ rescue ArgumentError
518
+ dputs(0) { "Didn't find fetchmail-user" }
519
+ self.permissions = permissions - %w(email)
520
+ end
521
+ end
522
+
523
+ def Persons.center
524
+ Persons.find_by_permissions(:center)
525
+ end
526
+
527
+ def Persons.centers
528
+ Persons.search_by_permissions(:center)
529
+ end
530
+
531
+ def Persons.master_center
532
+ Persons.centers.find { |c| c.has_permission?(:center_director) }
533
+ end
534
+
535
+ def Persons.master_center_login_name
536
+ (c = Persons.master_center) ? c.login_name : 'master'
537
+ end
538
+
539
+ def Persons.search_in(str, field = nil, center: nil, max: 20)
540
+ # Don't search if there are few caracters and lots of Persons
541
+ dputs(3) { "search_in - _#{str}_ - #{Persons.data.length}" }
542
+ if (!str || str.length < 3) && (Persons.data.length > max)
543
+ return field ? View.reply(:empty, field) : []
544
+ end
545
+
546
+ result = Persons.data.select { |k, v|
547
+ #dp v
548
+ str.split(/ /).collect { |s|
549
+ ret = false
550
+ %i( login_name family_name first_name
551
+ permissions person_id email phone groups ).each { |i|
552
+ #dp "#{i} - #{v[i]} - #{v[i].to_s =~ /#{str}/}"
553
+ ret ||= !!(v[i].to_s =~ /#{s}/i)
554
+ }
555
+ ret
556
+ }.compact.inject(:&)
557
+ }.sort { |a, b|
558
+ if a[1]._login_name.to_s == str
559
+ -1
560
+ elsif b[1]._login_name.to_s == str
561
+ 1
562
+ else
563
+ "#{a[1]._first_name} #{a[1]._family_name}" <=>
564
+ "#{b[1]._first_name} #{b[1]._family_name}"
565
+ end
566
+ }.first(max).collect { |k, v| Persons.get_data_instance(k) }
567
+
568
+ dputs(3) { "Result is: #{result.collect { |r| r.login_name }}" }
569
+ not result and result = []
570
+
571
+ result
572
+ end
573
+
574
+ def Persons.check_login(login, password)
575
+ return nil unless p = Persons.match_by_login_name(login)
576
+ p.check_pass(password) ? p : nil
577
+ end
578
+
579
+ def icc_get(tr)
580
+ c = tr._center
581
+ return "Error: Didn't find center #{c.inspect}}" unless center = Persons.match_by_login_name(c._login_name)
582
+ return "Error: Passwords do not match for #{c.inspect}" unless center.password_plain == c._password_plain
583
+ login_name = "#{c._login_name}_#{tr._name.first}"
584
+ log_msg :Persons, "ICC-get for #{login_name.inspect}"
585
+ if p = Persons.match_by_login_name(login_name)
586
+ p = p.to_hash
587
+ p._login_name = tr._name.first
588
+ p
589
+ else
590
+ "Error: Didn't find #{login_name}"
591
+ end
592
+ end
593
+ end
594
+
595
+ #
596
+ ### One person only
597
+ #
598
+
599
+ class Person < Entity
600
+ def setup_instance
601
+ dputs(3) { "Data is #{@proxy.data[@id].inspect}" }
602
+
603
+ self.internet_credit = internet_credit.to_i
604
+ update_accounts
605
+ end
606
+
607
+ def update_accounts
608
+ return unless ConfigBase.has_function? :accounting
609
+ update_account_cash
610
+ update_account_due
611
+ end
612
+
613
+ def update_account_due
614
+ # dputs_func
615
+ return unless ConfigBase.has_function? :accounting
616
+ if can_view :FlagAddInternet and login_name != 'admin'
617
+ dputs(3) { "Adding account_due to -#{login_name.inspect}-" }
618
+ if login_name.to_s == ''
619
+ dputs(0) { "Error: account_name_due empty and no login_name #{self.inspect}" }
620
+ return
621
+ end
622
+ acc = (full_name || login_name).capitalize_all
623
+ return unless ConfigBase.account_lending
624
+ lending = "#{ConfigBase.account_lending.get_path}::#{acc}"
625
+ service = ConfigBase.account_services.get_path
626
+ dputs(2) { "Preparing accounts for #{full_name} - #{acc}" }
627
+ if !self.account_due
628
+ dputs(2) { "Creating account #{lending}" }
629
+ self.account_due = Accounts.get_by_path_or_create(lending,
630
+ acc, false, -1, true)
631
+ end
632
+ if !self.account_due_paid
633
+ dputs(2) { "Creating account #{lending}::Paid" }
634
+ self.account_due_paid = Accounts.get_by_path_or_create("#{lending}::Paid",
635
+ acc, false, -1, true)
636
+ end
637
+ end
638
+ end
639
+
640
+ def update_account_cash
641
+ return unless ConfigBase.has_function?(:accounting)
642
+ if can_view(:FlagAccounting) && login_name != 'admin'
643
+ acc = (first_name || login_name).capitalize
644
+ dputs(3) { "Getting cash account #{acc}" }
645
+ return unless ConfigBase.account_cash
646
+ cc = "#{ConfigBase.account_cash.get_path}::#{acc}"
647
+ dputs(3){"Account will be #{cc}"}
648
+ self.account_cash = Accounts.get_by_path_or_create(cc, cc, false, -1, true)
649
+ dputs(3) { "Account is #{account_cash.inspect}" }
650
+ end
651
+ end
652
+
653
+ def total_cash
654
+ if account_cash
655
+ (account_cash.total.to_f * 1000).to_i
656
+ else
657
+ 0
658
+ end
659
+ end
660
+
661
+ def groups=(g)
662
+ self._groups = g
663
+ update_smb_passwd
664
+ end
665
+
666
+ def permissions=(p)
667
+ has_teacher = self._permissions and self._permissions.concat(p).index('teacher')
668
+ dputs(3) { "#{self.login_name}: has_teacher is #{has_teacher} - permissions are #{p.inspect}" }
669
+ old_permissions = self._permissions
670
+ self._permissions = p.uniq
671
+ if has_teacher
672
+ if Permission.can_view(p.reject { |perm| perm.to_s == 'admin' },
673
+ 'FlagResponsible')
674
+ Persons.responsibles_add(self)
675
+ else
676
+ Persons.responsibles_del(self)
677
+ end
678
+ end
679
+ if permissions.index 'email'
680
+ add_local_email
681
+ end
682
+ if (old_permissions || self._permissions).index('email')
683
+ Persons.update_fetchmailrc
684
+ end
685
+ update_accounts
686
+ end
687
+
688
+ def update_local_passwd(pass)
689
+ if permissions and permissions.index 'email'
690
+ dputs(2) { "Updating password #{pass} for #{login_name}" }
691
+ System.run_bool("echo -e '#{pass}\n#{pass}' | passwd #{login_name}")
692
+ end
693
+ end
694
+
695
+ def add_local_email
696
+ add_user_account
697
+ dir = "/home/#{login_name}/Maildir"
698
+ if !File.exists? dir
699
+ Dir.mkdir dir
700
+ %w( new cur tmp ).each { |d|
701
+ Dir.mkdir File.join(dir, d)
702
+ }
703
+ FileUtils.chown login_name, login_name, Dir.glob("/home/#{login_name}/**/**")
704
+ end
705
+ squirrel_base = '/srv/http/squirrelmail/config/var/data'
706
+ if Files.exists? squirrel_base
707
+ squirrel_pref = "#{squirrel_base}/#{login_name}.pref"
708
+ if !File.exists? squirrel_pref
709
+ IO.write(squirrel_pref, "full_name=#{full_name}\nemail_address=#{email}")
710
+ FileUtils.chown 'http', 'http', squirrel_pref
711
+ end
712
+ end
713
+ update_local_passwd(password)
714
+ end
715
+
716
+ def add_user_account
717
+ if not @proxy.has_storage? :LDAP
718
+ if Persons.admin_users
719
+ if !File.exist? "/home/#{login_name}"
720
+ log_msg :Person, "Adding user-account for #{login_name} with #{permissions.inspect}"
721
+ System.run_str("if which adduser; then adduser --disabled-password --gecos '#{self.full_name}' #{self.login_name};
722
+ else useradd -m #{self.login_name}; fi")
723
+ end
724
+ end
725
+ end
726
+ end
727
+
728
+ def update_smb_passwd(pass = password_plain)
729
+ if ConfigBase.has_function?(:share) && (groups && groups.index('share'))
730
+ add_user_account
731
+ if Persons.admin_users && pass
732
+ p = pass.chomp
733
+ log_msg :person, "Changing password in Samba to #{p.inspect}"
734
+ pwd_change = "/bin/echo -e '#{p}\\n#{p}' | smbpasswd -s -a #{self.login_name} "
735
+ dputs(3) { pwd_change.inspect }
736
+ System.run_str pwd_change
737
+ end
738
+ end
739
+ end
740
+
741
+ def account_total_due
742
+ if account_due
743
+ dputs(3) { "account_due is #{account_due.total.inspect}" }
744
+ (account_due.total.to_f * 1000.0).round.to_i
745
+ else
746
+ _account_total_due
747
+ end
748
+ end
749
+
750
+ def add_internet_credit(client, internet_credit)
751
+ dputs(3) { "Adding #{internet_credit}CFA to #{client.internet_credit} for #{client.login_name}" }
752
+ internet_credit_before = client.internet_credit
753
+ if internet_credit.to_i < 0 and internet_credit.to_i.abs > client.internet_credit.to_i
754
+ internet_credit = -client.internet_credit.to_i
755
+ end
756
+ if pay_service(internet_credit, "internet_credit pour -#{client.login_name}:#{internet_credit}-")
757
+ client.data_set(:_internet_credit, (client.internet_credit.to_i + internet_credit.to_i).to_s)
758
+ log_msg(:AddCash, "#{self.login_name} added #{internet_credit} for #{client.login_name}: " +
759
+ "#{internet_credit_before} + #{internet_credit} = #{client.internet_credit}")
760
+ log_msg(:AddCash, "Total due: #{account_total_due}")
761
+ end
762
+ end
763
+
764
+ def pay_service(credit, msg, date = nil)
765
+ if account_due
766
+ date = date ? Date.parse(date) : Date.today
767
+
768
+ Movements.create("#{msg}", date.strftime('%Y-%m-%d'),
769
+ credit.to_i / 1000.0, account_due, ConfigBase.account_services)
770
+ self.account_total_due = (account_due.total.to_f * 1000.0).round.to_i
771
+ else
772
+ return false
773
+ end
774
+ end
775
+
776
+ def check_pass(pass)
777
+ if @proxy.has_storage? :LDAP
778
+ # We have to try to bind to the LDAP
779
+ dputs(2) { 'Trying LDAP' }
780
+ #return @proxy.storage[:LDAP].check_login( data_get(:login_name), pass )
781
+ return @proxy.storage[:LDAP].check_login(login_name, pass)
782
+ else
783
+ #dputs( 0 ){ "is #{pass} equal to #{data_get( :password ) }" }
784
+ dputs(2) { "is #{pass} equal to #{password}" }
785
+ #return pass == data_get( :password )
786
+ return pass == password
787
+ end
788
+ end
789
+
790
+ def password=(pass)
791
+ (@pre_init || @loading) and return
792
+
793
+ p = pass.to_s.chomp
794
+ if @proxy.has_storage? :LDAP
795
+ dputs(2) { "Changing password for #{self.login_name}: #{pass}" }
796
+ p = System.run_str("slappasswd -s #{pass}").chomp
797
+ dputs(2) { "Hashed password for #{self.login_name} is: #{pass}" }
798
+ end
799
+ update_smb_passwd(pass)
800
+ update_local_passwd(pass)
801
+ if self._password != p
802
+ log_msg :person, "Setting password (#{pass}) for #{self.login_name} to #{p}"
803
+ self._password = p
804
+ end
805
+ if (permissions and permissions.index('center')) or
806
+ (groups and groups.index('share')) or
807
+ (not self.password_plain or self.password_plain == '' or
808
+ self.password_plain == pass)
809
+ self.password_plain = pass
810
+ else
811
+ dputs(2) { self.password_plain.inspect }
812
+ self.password_plain = '****'
813
+ end
814
+ end
815
+
816
+ def full_name
817
+ ret = []
818
+ first_name and ret.push first_name
819
+ family_name and ret.push family_name
820
+ ret.length == 0 and ret.push login_name
821
+ ret.join(' ')
822
+ end
823
+
824
+ def full_login
825
+ "#{full_name} (#{login_name})"
826
+ end
827
+
828
+ def replace(orig, field, str)
829
+ fields.each { |f|
830
+ orig.gsub!(f[0], f[1].to_s)
831
+ }
832
+ orig
833
+ end
834
+
835
+ def lp_cmd=(v)
836
+ @proxy.print_card_student.lp_cmd = v
837
+ @proxy.print_card_responsible.lp_cmd = v
838
+ end
839
+
840
+ def print(card = :student)
841
+ ctype = 'Visiteur'
842
+ courses = Courses.list_courses_for_person(self)
843
+ if courses and courses.length > 0
844
+ dputs(3) { "Courses is #{courses.inspect}" }
845
+ ctype = Courses.match_by_course_id(courses[0][0]).description
846
+ end
847
+ fname = "#{person_id.to_s.rjust(6, '0')}-#{full_name.gsub(/ /, '_')}"
848
+ courses = ['', '']
849
+ Courses.list_courses_for_person(self).each { |c|
850
+ dputs(3) { "Course #{c.inspect}" }
851
+ courses.unshift(Courses.match_by_course_id(c.first).description)
852
+ }
853
+ replace = [[/--NAME1--/, first_name],
854
+ [/--NAME2--/, family_name],
855
+ [/--GENDER--/, gender_i18n(ConfigBase.locale_force)],
856
+ [/--BDAY--/, birthday],
857
+ [/--TDAY--/, System.run_str('LC_ALL=fr_FR.UTF-8 date +"%d %B %Y"')],
858
+ [/--TOWN--/, town],
859
+ [/--TEL--/, phone],
860
+ [/--UNAME--/, login_name],
861
+ [/--EMAIL--/, email],
862
+ [/--CTYPE--/, ctype],
863
+ [/--COURSE1--/, courses[0]],
864
+ [/--COURSE2--/, courses[1]],
865
+ [/--PASS--/, password_plain]]
866
+ if center = Persons.center
867
+ url, email = center.email.to_s.split('::')
868
+ replace.concat([[/--CENTER_NAME--/, center.full_name],
869
+ [/--CENTER_ADDRESS--/, center.address],
870
+ [/--CENTER_TOWN--/, center.town],
871
+ [/--CENTER_COUNTRY--/, center.country],
872
+ [/--CENTER_TEL--/, center.phone],
873
+ [/--CENTER_URL--/, url],
874
+ [/--CENTER_EMAIL--/, email]])
875
+ end
876
+ dputs(3) { "Replace is #{replace.inspect}" }
877
+ case card
878
+ when /student/
879
+ @proxy.print_card_student.print(replace, nil, fname)
880
+ when /responsible/
881
+ @proxy.print_card_responsible.print(replace, nil, fname)
882
+ end
883
+ end
884
+
885
+ def simple
886
+ return true if !permissions
887
+ (permissions-%w(internet student)).length == 0
888
+ end
889
+
890
+ def to_list(user = nil)
891
+ [login_name, "#{full_name} - #{login_name}" +
892
+ (show_password?(user) ? ":#{password_plain}" : '')]
893
+ end
894
+
895
+ def to_list_id(user = nil)
896
+ [person_id, "#{full_name} - #{login_name}" +
897
+ (show_password?(user) ? ":#{password_plain}" : '')]
898
+ end
899
+
900
+ def session
901
+ Sessions.match_by_sid(self.session_id)
902
+ end
903
+
904
+ def first_name=(v)
905
+ self._first_name = v.to_s.capitalize_all
906
+ end
907
+
908
+ def family_name=(v)
909
+ self._family_name = v.to_s.capitalize_all
910
+ end
911
+
912
+ def get_cash(person, amount)
913
+ dputs(3) { "Amount is #{amount.inspect} and #{person.inspect} will receive it" }
914
+ amount = amount.to_i
915
+ if amount < 0
916
+ dputs(0) { "Error: Can't transfer a negative amount here" }
917
+ return false
918
+ end
919
+ if not person.account_due
920
+ dputs(0) { "Error: #{person.login_name}::#{person.full_name} has no account_due" }
921
+ return false
922
+ end
923
+ if not account_cash
924
+ dputs(0) { "Error: #{self.inspect} has no account_cash" }
925
+ return false
926
+ end
927
+ dputs(3) { "Transferring #{amount} from #{account_cash.get_path} to " +
928
+ "#{person.account_due.get_path}"
929
+ }
930
+ Movements.create('Transfert au comptable', Date.today,
931
+ amount / 1000.0, account_cash, person.account_due)
932
+ return true
933
+ end
934
+
935
+ def get_all_due(person, date = Date.today)
936
+ if person.account_due && account_cash
937
+ value = 0
938
+ person.account_due.movements.each { |m|
939
+ if m.date <= date
940
+ dputs(3) { "Moving #{m.inspect}" }
941
+ value += m.get_value(person.account_due)
942
+ m.move_from_to(person.account_due, person.account_due_paid)
943
+ end
944
+ }
945
+ dputs(3) { "Value is #{value}" }
946
+ Movements.create('Transfert au comptable', date,
947
+ value, account_cash, person.account_due_paid)
948
+ end
949
+ end
950
+
951
+ def can_view(v)
952
+ #Permission.can_view( data_get(:permissions), v )
953
+ Permission.can_view(permissions, v)
954
+ end
955
+
956
+ def has_role(r)
957
+ Permission.has_role(permissions, r)
958
+ end
959
+
960
+ def has_all_rights_of(person)
961
+ dputs(4) { "#{person.permissions} - #{permissions}" }
962
+ pv1 = Permission.views(permissions)
963
+ Permission.views(person.permissions).each { |p|
964
+ found = false
965
+ pv1.each { |p1|
966
+ if p =~ /^#{p1}$/
967
+ found = true
968
+ dputs(4) { "Found my #{p1} matches his #{p}" }
969
+ end
970
+ }
971
+ not found and return false
972
+ }
973
+ return true
974
+ end
975
+
976
+ def delete
977
+ Courses.search_all_.each { |course|
978
+ dputs(3) { "Checking course #{course.name}" }
979
+ [:teacher, :assistant, :responsible, :center].each { |role|
980
+ begin
981
+ r = course.data_get("_#{role}")
982
+ rescue Exception => e
983
+ if e.message == 'WrongIndex'
984
+ dputs(0) { "Error: Role :#{role} is not well defined - resetting to nil" }
985
+ course.data_set("_#{role}", nil)
986
+ end
987
+ end
988
+ dputs(3) { "Role #{role} is #{r.inspect}" }
989
+ if r and r.login_name == login_name
990
+ raise IsNecessary.new(course)
991
+ end
992
+ }
993
+ }
994
+
995
+ Courses.data.values.each { |d|
996
+ if d[:students] and d[:students].index(login_name)
997
+ d[:students] -= [login_name]
998
+ end
999
+ }
1000
+ Shares.search_all_.each { |s|
1001
+ s.acl.delete login_name
1002
+ }
1003
+ AccessGroups.search_all_.each { |ag|
1004
+ ag.members and ag.members.delete login_name
1005
+ }
1006
+ Grades.search_by_student(self).each { |g|
1007
+ g.delete
1008
+ }
1009
+
1010
+ if @proxy.has_storage? :LDAP
1011
+ if !Kernel.system("ldapdeleteuser #{self.login_name}")
1012
+ dputs(0) { "Error: couldn't delete user #{self.inspect}" }
1013
+ end
1014
+ elsif Persons.admin_users
1015
+ System.run_bool("if which deluser; then deluser #{self.login_name}; else
1016
+ userdel #{self.login_name}; fi")
1017
+ end
1018
+ if ConfigBase.has_function?(:share) && Persons.admin_users
1019
+ System.run_bool("smbpasswd -x #{self.login_name}")
1020
+ end
1021
+ super
1022
+
1023
+ @proxy.resps = []
1024
+ end
1025
+
1026
+ def get_unique
1027
+ login_name
1028
+ end
1029
+
1030
+ def has_permission?(perm)
1031
+ #dputs_func
1032
+ dputs(4) { "Checking #{perm.inspect} in #{permissions.inspect}" }
1033
+ dputs(4) { "Which is #{Permission.views(permissions).inspect }" }
1034
+ return false unless permissions
1035
+ return true if permissions.index(perm.to_s)
1036
+ Permission.views(permissions).select { |p|
1037
+ dputs(4) { "Checking permission #{p.inspect} of #{perm.inspect}" }
1038
+ dputs(4) { "Result is #{perm.to_s =~ /^#{p.to_s}$/}" }
1039
+ perm.to_s =~ /^#{p.to_s}$/
1040
+ }.length > 0
1041
+ end
1042
+
1043
+ def courses
1044
+ Courses.search_all.select { |c|
1045
+ c[:students] and c[:students].index(login_name)
1046
+ }
1047
+ end
1048
+
1049
+ def report_list_movements(from = nil, to = from, account = account_due)
1050
+ total = 0
1051
+ account or return [[]]
1052
+ if from
1053
+ account.movements.select { |m|
1054
+ dputs(3) { "Date is #{m.date.inspect}" }
1055
+ (from..to).include? m.date
1056
+ }
1057
+ elsif to
1058
+ dputs(3) { "Fetching only dates upto #{to}" }
1059
+ account.movements.select { |m|
1060
+ dputs(3) { "Date is #{m.date.inspect}" }
1061
+ m.date <= to
1062
+ }
1063
+ else
1064
+ account.movements
1065
+ end.reverse.collect { |m|
1066
+ v = m.get_value(account)
1067
+ [m.global_id,
1068
+ [m.date,
1069
+ "#{m.get_other_account(account).name}: #{m.desc}",
1070
+ Account.total_form(v),
1071
+ Account.total_form(total += v)]
1072
+ ]
1073
+ }.reverse
1074
+ end
1075
+
1076
+ def report_list(report, date = nil)
1077
+ date ||= Date.today
1078
+ case report
1079
+ when :daily, 1
1080
+ report_list_movements(date)
1081
+ when :weekly, 2
1082
+ week = Date.commercial(date.year, date.cweek, 1)
1083
+ report_list_movements(week, week + 6)
1084
+ when :monthly, 3
1085
+ report_list_movements(
1086
+ Date.new(date.year, date.month, 1),
1087
+ Date.new(date.year, date.month, -1))
1088
+ when :all, 4
1089
+ report_list_movements(nil, date)
1090
+ when :all_paid, 5
1091
+ report_list_movements(nil, nil, account_due_paid)
1092
+ end
1093
+ end
1094
+
1095
+ def report_pdf(report, date = nil)
1096
+ file = "/tmp/cash_#{login_name}.pdf"
1097
+ Prawn::Document.generate(file,
1098
+ :page_size => 'A4',
1099
+ :page_layout => :portrait,
1100
+ :bottom_margin => 2.cm) do |pdf|
1101
+
1102
+ sum = 0
1103
+ movs = report_list(report, date).reverse
1104
+ pdf.text "Report for #{full_name}", :align => :center, :size => 20
1105
+ pdf.font_size 10
1106
+ if movs.length > 0
1107
+ pdf.text "From #{movs.first[1][0]} to #{movs.last[1][0]}"
1108
+ end
1109
+ pdf.text "Account: #{account_due.path}"
1110
+ pdf.move_down 1.cm
1111
+
1112
+ if movs.length > 0
1113
+ header = [['Date', 'Description', 'Value', 'Sum'].collect { |ch|
1114
+ {:content => ch, :align => :center} }]
1115
+ dputs(3) { "Movs is #{movs.inspect}" }
1116
+ pdf.table(header + movs.collect { |m_id, m|
1117
+ [{:content => "#{m[0]}", :align => :center},
1118
+ m[1],
1119
+ {:content => "#{m[2]}", :align => :right},
1120
+ {:content => "#{Account.total_form(
1121
+ sum += m[2].gsub(',', '').to_f / 1000)}",
1122
+ :align => :right}]
1123
+ }, :header => true, :column_widths => [70, 300, 75, 75])
1124
+ pdf.move_down(2.cm)
1125
+ end
1126
+
1127
+ pdf.repeat(:all, :dynamic => true) do
1128
+ pdf.draw_text "#{Date.today} - #{account_due.path}",
1129
+ :at => [0, -20], :size => 10
1130
+ pdf.draw_text pdf.page_number, :at => [19.cm, -20]
1131
+ end
1132
+ end
1133
+ file
1134
+ end
1135
+
1136
+ def to_frontend(owner)
1137
+ to_list_id(owner)
1138
+ end
1139
+
1140
+ def is_responsible?
1141
+ %w( director teacher assistant center_director ).each { |p|
1142
+ return true if has_permission? p
1143
+ }
1144
+ return false
1145
+ end
1146
+
1147
+ def is_staff?
1148
+ (permissions.to_a - %w(student internet)).length > 0
1149
+ end
1150
+
1151
+ def show_password?(user = nil)
1152
+ case ConfigBase.show_passwords.first
1153
+ when 'always'
1154
+ return true
1155
+ when 'never'
1156
+ return false
1157
+ when 'students'
1158
+ return !is_staff?
1159
+ when 'lesser'
1160
+ return user ? user.has_all_rights_of(self) : false
1161
+ end
1162
+ end
1163
+
1164
+ def gender_i18n(lang)
1165
+ g = (gender ? gender.first : '').to_sym
1166
+ case lang
1167
+ when /en/
1168
+ {male: 'Mister', female: 'Madam'}[g]
1169
+ when /fr/
1170
+ {male: 'Monsieur', female: 'Madame'}[g]
1171
+ else
1172
+ ''
1173
+ end
1174
+ end
1175
+ end