gestion 1.9.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +48 -0
- data/.project +14 -0
- data/Binaries/adduser_to_buzz +15 -0
- data/Binaries/backup +7 -0
- data/Binaries/check_gestion +8 -0
- data/Binaries/gestion.gnumail +22 -0
- data/Binaries/gestion.logrotate +34 -0
- data/Binaries/gestion.service +12 -0
- data/Binaries/gestion_update.rb +183 -0
- data/Binaries/gestion_update.service +10 -0
- data/Binaries/get_compta +11 -0
- data/Binaries/kill_gestion +16 -0
- data/Binaries/ldap/add_indexes +51 -0
- data/Binaries/ldap/backup +2 -0
- data/Binaries/ldap/install_ldap +92 -0
- data/Binaries/ldap/restore +7 -0
- data/Binaries/lib_backup +5 -0
- data/Binaries/log_scan_errors +8 -0
- data/Binaries/loop_gestion +64 -0
- data/Binaries/onetimers/sync_courses_from_compta.rb +74 -0
- data/Binaries/onetimers/transfer_cash_from_ldap_to_csv +26 -0
- data/Binaries/reboot +5 -0
- data/Binaries/restore +3 -0
- data/Binaries/restore_do +22 -0
- data/Binaries/sort_events +31 -0
- data/Binaries/start_gestion +18 -0
- data/Binaries/swipe_gestion +18 -0
- data/Binaries/update_africompta +21 -0
- data/Binaries/update_users +3 -0
- data/Diplomas.src/accredited.odg +0 -0
- data/Diplomas.src/diploma.odg +0 -0
- data/Diplomas.src/label.odg +0 -0
- data/Diplomas.src/presence_sheet.ods +0 -0
- data/Diplomas.src/presence_sheet_small.ods +0 -0
- data/Diplomas.src/student_card.odg +0 -0
- data/Doc/130514-it-ideas.odt +0 -0
- data/Doc/Compta-cash.mm +179 -0
- data/Doc/General.odt +0 -0
- data/Entities/AccessGroups.rb +117 -0
- data/Entities/Activity.rb +178 -0
- data/Entities/ChatMsg.rb +142 -0
- data/Entities/Classroom.rb +11 -0
- data/Entities/Client.rb +19 -0
- data/Entities/Computer.rb +21 -0
- data/Entities/ConfigBase.rb +280 -0
- data/Entities/Course.rb +1588 -0
- data/Entities/CourseType.rb +171 -0
- data/Entities/DFiles.rb +466 -0
- data/Entities/FilesManage.rb +226 -0
- data/Entities/Grade.rb +186 -0
- data/Entities/Internet.rb +300 -0
- data/Entities/Netdev.rb +10 -0
- data/Entities/Person.rb +1175 -0
- data/Entities/Plug.rb +98 -0
- data/Entities/Quiz.rb +33 -0
- data/Entities/Recharges.rb +37 -0
- data/Entities/Report.rb +136 -0
- data/Entities/Room.rb +12 -0
- data/Entities/SMS.rb +30 -0
- data/Entities/ScheduleType.rb +33 -0
- data/Entities/Share.rb +120 -0
- data/Entities/Task.rb +51 -0
- data/Entities/Ticket.rb +72 -0
- data/Entities/Usage.rb +143 -0
- data/Entities/Worker.rb +29 -0
- data/Files/apache-profeda.conf +36 -0
- data/Files/label.erb +121 -0
- data/Files/label_notfound.erb +64 -0
- data/Files/label_notpassed.erb +84 -0
- data/Files/mobileinfo.erb +115 -0
- data/Files/smb.conf +333 -0
- data/Files/timetable.html +36 -0
- data/Files/timetable.js +239 -0
- data/Gemfile +12 -0
- data/Gemfile.dev +12 -0
- data/Gemfile.dev.lock +127 -0
- data/Gemfile.lock +127 -0
- data/Gemfile.prod +8 -0
- data/Gestion +35 -0
- data/Gestion.rb +220 -0
- data/INSTALL +40 -0
- data/Images/connection.xcf +0 -0
- data/Images/connection_no.png +0 -0
- data/Images/connection_wait.png +0 -0
- data/Images/connection_yes.png +0 -0
- data/Paths/Exas.rb +13 -0
- data/Paths/Files.rb +19 -0
- data/Paths/GetDiplomas.rb +20 -0
- data/Paths/Info.rb +114 -0
- data/Paths/Label.rb +187 -0
- data/Paths/MobileInfo.rb +19 -0
- data/Paths/internetCash.rb +34 -0
- data/Paths/internetWifi.rb +54 -0
- data/README.md +60 -0
- data/Rakefile +13 -0
- data/TODO +1391 -0
- data/Test/.gitignore +3 -0
- data/Test/Diplomas/base_gestion.odt +0 -0
- data/Test/Diplomas/base_report.odt +0 -0
- data/Test/Diplomas/carte_etudiant.odg +0 -0
- data/Test/Diplomas/exam_language.odt +0 -0
- data/Test/Diplomas/label.odg +0 -0
- data/Test/Diplomas/presence_sheet.ods +0 -0
- data/Test/Diplomas/presence_sheet_small.ods +0 -0
- data/Test/Diplomas/student_card.odg +0 -0
- data/Test/Manual/testMerge +18 -0
- data/Test/config_test.yaml +26 -0
- data/Test/db.testGestion +0 -0
- data/Test/dfiles/descs/avg-rescue.desc +10 -0
- data/Test/dfiles/descs/avg.desc +8 -0
- data/Test/dfiles/descs/driver.desc +8 -0
- data/Test/dfiles/descs/linuxmint.desc +7 -0
- data/Test/dfiles/files/avg-160203.exe +1 -0
- data/Test/dfiles/files/avg.iso +1 -0
- data/Test/dfiles/files/driver.exe +1 -0
- data/Test/dfiles/index_post.html +3 -0
- data/Test/dfiles/index_pre.html +8 -0
- data/Test/dfiles/priorities +5 -0
- data/Test/ge_activity.rb +124 -0
- data/Test/ge_chat.rb +106 -0
- data/Test/ge_compta.rb +67 -0
- data/Test/ge_configbase.rb +54 -0
- data/Test/ge_course.rb +1114 -0
- data/Test/ge_dfiles.rb +121 -0
- data/Test/ge_filesmanage.rb +180 -0
- data/Test/ge_info.rb +27 -0
- data/Test/ge_internet.rb +246 -0
- data/Test/ge_login.rb +55 -0
- data/Test/ge_person.rb +373 -0
- data/Test/ge_qvinfo.rb +28 -0
- data/Test/ge_report.rb +97 -0
- data/Test/ge_share.rb +27 -0
- data/Test/ge_sms.rb +34 -0
- data/Test/ge_tasks.rb +19 -0
- data/Test/ge_usage.rb +168 -0
- data/Test/ge_view.rb +46 -0
- data/Test/multiconf-captive +29 -0
- data/Test/test.conf +7 -0
- data/Test/test.rb +49 -0
- data/Test/test_bytes.png +0 -0
- data/VERSION +140 -0
- data/Views/Admin/Backup.rb +91 -0
- data/Views/Admin/Configuration.rb +44 -0
- data/Views/Admin/Credit.rb +32 -0
- data/Views/Admin/FilesManage.rb +219 -0
- data/Views/Admin/Function.rb +39 -0
- data/Views/Admin/Power.rb +49 -0
- data/Views/Admin/Printer.rb +37 -0
- data/Views/Admin/Server.rb +252 -0
- data/Views/Admin/Tabs.rb +5 -0
- data/Views/Admin/Update.rb +73 -0
- data/Views/Admin/UpdateSystem.rb +26 -0
- data/Views/Cashbox/Activity.rb +191 -0
- data/Views/Cashbox/Course.rb +141 -0
- data/Views/Cashbox/Credit.rb +79 -0
- data/Views/Cashbox/Report.rb +115 -0
- data/Views/Cashbox/Service.rb +105 -0
- data/Views/Cashbox/Tabs.rb +10 -0
- data/Views/Compta/Accounts.rb +36 -0
- data/Views/Compta/Course.rb +96 -0
- data/Views/Compta/Show.rb +6 -0
- data/Views/Compta/Transfer.rb +66 -0
- data/Views/Course/Diploma.rb +203 -0
- data/Views/Course/Grade.rb +401 -0
- data/Views/Course/Modify.rb +447 -0
- data/Views/Course/Print.rb +94 -0
- data/Views/Course/Responsible.rb +44 -0
- data/Views/Course/Stats.rb +76 -0
- data/Views/Course/Students.rb +92 -0
- data/Views/Course/Tabs.rb +220 -0
- data/Views/Internet/Access.rb +134 -0
- data/Views/Internet/ClassEdit.rb +24 -0
- data/Views/Internet/ClassUsers.rb +81 -0
- data/Views/Internet/Config.rb +32 -0
- data/Views/Internet/Mobile.rb +213 -0
- data/Views/Internet/Recharges.rb +49 -0
- data/Views/Internet/Tabs.rb +6 -0
- data/Views/Inventory/Computer.rb +24 -0
- data/Views/Inventory/Room.rb +18 -0
- data/Views/Inventory/Tabs.rb +9 -0
- data/Views/Inventory/TicketClosed.rb +7 -0
- data/Views/Inventory/TicketOpen.rb +23 -0
- data/Views/Library/Person.rb +36 -0
- data/Views/Library/Tabs.rb +7 -0
- data/Views/Network/Block.rb +87 -0
- data/Views/Network/Netdevs.rb +21 -0
- data/Views/Network/Restriction.rb +37 -0
- data/Views/Network/Share.rb +167 -0
- data/Views/Network/Tables.rb +28 -0
- data/Views/Network/Tabs.rb +6 -0
- data/Views/Person/Admin.rb +99 -0
- data/Views/Person/Center.rb +48 -0
- data/Views/Person/Course.rb +72 -0
- data/Views/Person/Modify.rb +153 -0
- data/Views/Person/Tabs.rb +162 -0
- data/Views/Report/ComptaExecutive.rb +221 -0
- data/Views/Report/ComptaFlat.rb +79 -0
- data/Views/Report/ReportCourse.rb +47 -0
- data/Views/Report/Tabs.rb +8 -0
- data/Views/Report/Usage.rb +52 -0
- data/Views/Report/UsageCases.rb +59 -0
- data/Views/Self/Cash.rb +67 -0
- data/Views/Self/Chat.rb +55 -0
- data/Views/Self/Concours.rb +109 -0
- data/Views/Self/Email.rb +34 -0
- data/Views/Self/Internet.rb +255 -0
- data/Views/Self/Results.rb +17 -0
- data/Views/Self/Services.rb +85 -0
- data/Views/Self/Show.rb +47 -0
- data/Views/Self/Tabs.rb +5 -0
- data/Views/Special/DFileEdit.rb +13 -0
- data/Views/Special/PlugEdit.rb +56 -0
- data/Views/Special/Tabs.rb +6 -0
- data/Views/Special/Vnc.rb +39 -0
- data/Views/Task/Client.rb +21 -0
- data/Views/Task/Edit.rb +33 -0
- data/Views/Task/List.rb +55 -0
- data/Views/Task/Tabs.rb +9 -0
- data/Views/Task/Worker.rb +30 -0
- data/Views/Template/Activity.rb +33 -0
- data/Views/Template/CourseType.rb +63 -0
- data/Views/Template/ScheduleType.rb +29 -0
- data/Views/Template/Tabs.rb +5 -0
- data/Views/Welcome.rb +121 -0
- data/config.yaml.default +36 -0
- data/po/Gestion-ar.po +2356 -0
- data/po/Gestion-en.mo +0 -0
- data/po/Gestion-en.po +4363 -0
- data/po/Gestion-fr.mo +0 -0
- data/po/Gestion-fr.po +4345 -0
- data/po/traduction-ar.rtf +76 -0
- metadata +381 -0
data/Entities/Person.rb
ADDED
@@ -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
|