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.
- 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
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# To change this template, choose Tools | Templates
|
|
2
|
+
# and open the template in the editor.
|
|
3
|
+
|
|
4
|
+
class CourseTypes < Entities
|
|
5
|
+
def setup_data
|
|
6
|
+
value_str :file_diploma
|
|
7
|
+
value_str :file_exam
|
|
8
|
+
|
|
9
|
+
value_block :strings
|
|
10
|
+
value_str :name
|
|
11
|
+
value_str :duration
|
|
12
|
+
|
|
13
|
+
value_block :long
|
|
14
|
+
value_str :description
|
|
15
|
+
value_text :contents
|
|
16
|
+
|
|
17
|
+
value_block :central
|
|
18
|
+
value_list_drop :diploma_type, '%w( simple files accredited report )'
|
|
19
|
+
value_list_drop :output, '%w( certificate label )'
|
|
20
|
+
value_list_drop :diploma_lang, '%w( en fr )'
|
|
21
|
+
value_list_drop :page_format,
|
|
22
|
+
"[[1,'normal'],[2,'interchanged'],[3,'landscape'],[4,'seascape']]"
|
|
23
|
+
value_list_drop :remark, '%w(false true)'
|
|
24
|
+
|
|
25
|
+
value_block :lists
|
|
26
|
+
value_str :tests_str
|
|
27
|
+
value_int :tests_nbr
|
|
28
|
+
value_str :files_str
|
|
29
|
+
value_int :files_nbr
|
|
30
|
+
|
|
31
|
+
value_block :accounting
|
|
32
|
+
value_int :salary_teacher
|
|
33
|
+
value_int :cost_student
|
|
34
|
+
|
|
35
|
+
value_block :account
|
|
36
|
+
value_entity_account :account_base, :drop, :path
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def self.files
|
|
40
|
+
ddir = Courses.dir_diplomas
|
|
41
|
+
Dir.glob(ddir + '/*{odt,odg,ods}').
|
|
42
|
+
collect { |f| f.sub(/^.*\//, '') }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def set_entry(id, field, value)
|
|
46
|
+
case field.to_s
|
|
47
|
+
when 'name'
|
|
48
|
+
value.gsub!(/[^a-zA-Z0-9_-]/, '_')
|
|
49
|
+
end
|
|
50
|
+
super(id, field, value)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def listp_name
|
|
54
|
+
CourseTypes.listp_name
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def self.listp_name
|
|
58
|
+
self.search_all_.collect { |ct|
|
|
59
|
+
[ct.coursetype_id, ct.name]
|
|
60
|
+
}.sort { |a, b| a[1].downcase <=> b[1].downcase }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def migration_1(ct)
|
|
64
|
+
ct.tests = 1
|
|
65
|
+
ct.output = ['certificate']
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def migration_2(ct)
|
|
69
|
+
ct.diploma_type = ['simple']
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def migration_3(ct)
|
|
73
|
+
ct.page_format = [0]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def migration_4(ct)
|
|
77
|
+
ct.page_format[0] += 1
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Changed tests to tests_str and files_needed to files_str
|
|
81
|
+
def migration_5_raw(ct)
|
|
82
|
+
if (ct._tests_nbr = ct._tests.to_i) > 0
|
|
83
|
+
ct._tests_str = (1..ct._tests_nbr).collect { |t| "Test #{t}" }.join("\n")
|
|
84
|
+
end
|
|
85
|
+
if (ct._files_nbr = ct._files_needed.to_i) > 0
|
|
86
|
+
ct._files_str = (1..ct._files_nbr).collect { |f| "Files #{f}" }.join("\n")
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def migration_6(ct)
|
|
91
|
+
ct.diploma_lang = ['fr']
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def icc_list(arg)
|
|
95
|
+
list_name
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def icc_fetch(arg)
|
|
99
|
+
if ct_names = arg._course_type_names
|
|
100
|
+
ct_names.collect { |ct|
|
|
101
|
+
self.find_by_name(ct) or return "Error: CourseType #{ct} doesn't exist"
|
|
102
|
+
}
|
|
103
|
+
else
|
|
104
|
+
return 'Error: no course_type_name given'
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def icc_file(arg)
|
|
109
|
+
file = "#{ConfigBase.template_dir}/#{File.basename(arg._name.first)}"
|
|
110
|
+
if File.exists? file
|
|
111
|
+
log_msg :CourseTypes, "Sending file #{file}"
|
|
112
|
+
IO.binread(file)
|
|
113
|
+
else
|
|
114
|
+
log_msg :CourseTypes, "Didn't find #{file.inspect}"
|
|
115
|
+
return "Error: can't find file"
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
class CourseType < Entity
|
|
121
|
+
def setup_instance
|
|
122
|
+
self.diploma_lang ||= ['fr']
|
|
123
|
+
self.files_nbr ||= 0
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def get_unique
|
|
127
|
+
name
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def clean_str(str)
|
|
131
|
+
s = str.to_s.split("\n").
|
|
132
|
+
collect { |s| s.sub(/^\s*/, '').sub(/\s*$/, '') }.
|
|
133
|
+
select { |s| s.length > 0 }
|
|
134
|
+
[s.join("\n"), s.length]
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def tests_str=(str)
|
|
138
|
+
self._tests_str, self.tests_nbr = clean_str(str)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def tests_arr
|
|
142
|
+
tests_str.to_s.split("\n")
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def files_str=(str)
|
|
146
|
+
self._files_str, self.files_nbr = clean_str(str)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def files_arr
|
|
150
|
+
files_str.to_s.split("\n")
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def delete
|
|
154
|
+
if Courses.search_by_ctype(self).size > 0
|
|
155
|
+
log_msg :CourseType, "Tried to delete #{self.name} while courses still depend on it"
|
|
156
|
+
return false
|
|
157
|
+
else
|
|
158
|
+
super
|
|
159
|
+
return true
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def file_diploma=(f)
|
|
164
|
+
return if @loading
|
|
165
|
+
self._file_diploma = f
|
|
166
|
+
Courses.search_by_ctype(self).each{|c|
|
|
167
|
+
c.update_exam_file
|
|
168
|
+
}
|
|
169
|
+
f
|
|
170
|
+
end
|
|
171
|
+
end
|
data/Entities/DFiles.rb
ADDED
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
# DFiles is used to manage the updating of the files-repository on the
|
|
2
|
+
# Profeda-installations.
|
|
3
|
+
# - sync with a harddisk or over ssh
|
|
4
|
+
# - update the file-tree
|
|
5
|
+
|
|
6
|
+
class DFiles < Entities
|
|
7
|
+
attr_accessor :dir_base, :dir_files, :dir_descs, :url_html
|
|
8
|
+
|
|
9
|
+
def setup_data
|
|
10
|
+
value_int :dfile_id
|
|
11
|
+
value_str :name
|
|
12
|
+
value_str :desc_file
|
|
13
|
+
# url_file holds the url to the file. It can be preceded
|
|
14
|
+
# by a name held between two ":", which will be the
|
|
15
|
+
# save_file-name. Else the save_file-name is the 'basename' of the
|
|
16
|
+
# url_file
|
|
17
|
+
value_str :url_file
|
|
18
|
+
value_str :save_file
|
|
19
|
+
value_str :url_page
|
|
20
|
+
value_str :desc
|
|
21
|
+
# os and category are used to build the dokuwiki-pages
|
|
22
|
+
value_str :os
|
|
23
|
+
value_str :category
|
|
24
|
+
# tags are additional fields
|
|
25
|
+
value_str :tags
|
|
26
|
+
value_int :file_size
|
|
27
|
+
|
|
28
|
+
# Only used once a DFile is found - will not be stored, but represents
|
|
29
|
+
# the priority that will be used for pruning.
|
|
30
|
+
value_int :priority
|
|
31
|
+
|
|
32
|
+
set_dir_base('/opt/Files')
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def set_dir_base(dir)
|
|
36
|
+
@dir_base = dir
|
|
37
|
+
@dir_files = File.join(@dir_base, 'files')
|
|
38
|
+
@dir_descs = File.join(@dir_base, 'descs')
|
|
39
|
+
@dir_html = File.join(@dir_base, 'html')
|
|
40
|
+
@url_html = 'http://files.ndjair.net/'
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# searches for all descriptions in @dir_descs
|
|
44
|
+
def load(has_static = true)
|
|
45
|
+
#dputs_func
|
|
46
|
+
delete_all(true)
|
|
47
|
+
dputs(2) { "Loading descs from #{@dir_descs}" }
|
|
48
|
+
if Dir.exists?(@dir_descs)
|
|
49
|
+
dputs(4) { 'Directory exists' }
|
|
50
|
+
file_id = 1
|
|
51
|
+
Dir.glob("#{@dir_descs}/*.desc").each { |f|
|
|
52
|
+
dputs(4) { "Working on file #{f}" }
|
|
53
|
+
name = File.basename(f)
|
|
54
|
+
lines = IO.readlines(f).collect { |l| l.chomp }
|
|
55
|
+
if lines.size >= 7
|
|
56
|
+
file = {
|
|
57
|
+
dfile_id: file_id,
|
|
58
|
+
desc_file: name,
|
|
59
|
+
name: name.sub(/.desc$/, ''),
|
|
60
|
+
url_file: lines[0],
|
|
61
|
+
url_page: lines[1],
|
|
62
|
+
desc: lines[3],
|
|
63
|
+
os: lines[5],
|
|
64
|
+
category: lines[6],
|
|
65
|
+
tags: lines[5..-1].collect { |t|
|
|
66
|
+
t.split(' ')
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if file[:url_file][0] == ':'
|
|
70
|
+
su = file[:url_file].match(/^:([^:]*):(.*)$/)
|
|
71
|
+
file[:save_file] = su[1]
|
|
72
|
+
file[:url_file] = su[2]
|
|
73
|
+
else
|
|
74
|
+
file[:save_file] = File.basename(file[:url_file])
|
|
75
|
+
end
|
|
76
|
+
dputs(3) { "Saving description #{file}" }
|
|
77
|
+
file_path = File.join(@dir_files, file[:save_file])
|
|
78
|
+
file[:file_size] = File.exists?(file_path) ? File.size(file_path) : 0
|
|
79
|
+
@data[file_id] = file
|
|
80
|
+
file_id += 1
|
|
81
|
+
else
|
|
82
|
+
dputs(2) { "Description #{f} has not enough lines, skipping" }
|
|
83
|
+
end
|
|
84
|
+
}
|
|
85
|
+
else
|
|
86
|
+
dputs(2) { "Didn't find directory #{@dir_descs}" }
|
|
87
|
+
end
|
|
88
|
+
dputs(3) { @data.inspect }
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# saves back the descriptions to @dir_descs
|
|
92
|
+
def save()
|
|
93
|
+
return unless @changed
|
|
94
|
+
if Dir.exists?(@dir_descs)
|
|
95
|
+
FileUtils.rm(Dir.glob("#{@dir_descs}/*.desc"))
|
|
96
|
+
else
|
|
97
|
+
FileUtils.mkpath(@dir_descs)
|
|
98
|
+
end
|
|
99
|
+
@data.each { |k, v|
|
|
100
|
+
File.open("#{@dir_descs}/#{v[:desc_file]}", 'w') { |f|
|
|
101
|
+
if (file = v[:save_file]) != File.basename(v[:url_file])
|
|
102
|
+
v[:url_file] = ":#{file}:#{v[:url_file]}"
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
f.puts(v[:url_file], v[:url_page], '',
|
|
106
|
+
v[:desc], '',
|
|
107
|
+
v[:os], v[:category])
|
|
108
|
+
v[:tags].each { |t| f.puts(t.join(' ')) }
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# updates the descriptions from a directory (probably a mount-point, has to
|
|
114
|
+
# be mounted before)
|
|
115
|
+
def update_desc_from_dir(update_dir)
|
|
116
|
+
return unless Dir.exists?(update_dir)
|
|
117
|
+
Dir.glob(File.join(update_dir, '*.desc')).each { |f|
|
|
118
|
+
name = File.basename(f)
|
|
119
|
+
local_name = File.join(@dir_descs, name)
|
|
120
|
+
if File.size(f) == 0
|
|
121
|
+
# This is a file that has to be removed
|
|
122
|
+
File.rm(local_name)
|
|
123
|
+
else
|
|
124
|
+
dputs(3) { "Copying #{f} to #{local_name}" }
|
|
125
|
+
FileUtils.cp(f, local_name)
|
|
126
|
+
end
|
|
127
|
+
}
|
|
128
|
+
load
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# copies the files from a directory to @dir_files
|
|
132
|
+
def update_files_from_dir(update_dir)
|
|
133
|
+
#dputs_func
|
|
134
|
+
load
|
|
135
|
+
unless Dir.exists? @dir_files
|
|
136
|
+
FileUtils.mkpath @dir_files
|
|
137
|
+
end
|
|
138
|
+
# Update all sizes, delete if file is missing
|
|
139
|
+
search_all_.each { |df|
|
|
140
|
+
df.file_size = 0
|
|
141
|
+
[@dir_files, update_dir].each { |d|
|
|
142
|
+
file = File.join(d, df.save_file)
|
|
143
|
+
if File.exists?(file)
|
|
144
|
+
df.file_size = File.size(file)
|
|
145
|
+
dputs(3) { "Found file #{file} with size #{df.file_size}" }
|
|
146
|
+
else
|
|
147
|
+
df.file_size = 0
|
|
148
|
+
end
|
|
149
|
+
}
|
|
150
|
+
if df.file_size == 0
|
|
151
|
+
df.delete
|
|
152
|
+
end
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
files_wanted = get_limited_files(DFilePriorities.get_most_wanted,
|
|
156
|
+
DFileConfig.limit_size * 2**30).
|
|
157
|
+
collect { |f| f.save_file }
|
|
158
|
+
files_here = Dir.glob(File.join(@dir_files, '/*')).
|
|
159
|
+
collect { |f| File.basename(f) }
|
|
160
|
+
files_delete = files_here - files_wanted
|
|
161
|
+
files_copy = files_wanted - files_here
|
|
162
|
+
dputs(3) { "Files to delete are: #{files_delete}" }
|
|
163
|
+
dputs(3) { "Files to copy are: #{files_delete}" }
|
|
164
|
+
|
|
165
|
+
# Delete not used files
|
|
166
|
+
files_delete.each { |f|
|
|
167
|
+
file = File.join(@dir_files, f)
|
|
168
|
+
dputs(3) { "Deleting file #{file}" }
|
|
169
|
+
FileUtils.rm(file)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
# Copy new files
|
|
173
|
+
files_copy.each { |f|
|
|
174
|
+
file = File.join(update_dir, f)
|
|
175
|
+
dputs(3) { "Copying file #{file}" }
|
|
176
|
+
FileUtils.cp(file, @dir_files)
|
|
177
|
+
}
|
|
178
|
+
save
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# Returns the first files so that the total is not above the
|
|
182
|
+
# size_limit
|
|
183
|
+
def get_limited_files(files, size_limit)
|
|
184
|
+
ret = files.dup
|
|
185
|
+
if size_limit > 0
|
|
186
|
+
# Prioritize the files
|
|
187
|
+
while ret.inject(0) { |tot, f| tot + f.file_size } > size_limit
|
|
188
|
+
# We have too many files and need to prune some entries
|
|
189
|
+
ret.delete(ret.last)
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
ret
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def get_size(dir, files)
|
|
196
|
+
files.inject(0) { |tot, file|
|
|
197
|
+
tot += File.size(dir + "/#{file}")
|
|
198
|
+
}
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# get_tags returns all tags with the most common tags at the beginning
|
|
202
|
+
def get_tags(tag)
|
|
203
|
+
# Get a list of all tags wihtout the priority
|
|
204
|
+
tags = search_by_tags(tag).collect { |df| df.tags.collect { |_, t| t } }.flatten.sort
|
|
205
|
+
# Count how many times each tag appears and sort inversely
|
|
206
|
+
tags_count = tags.uniq.collect { |t| [tags.count(t), t] }.sort { |a, b| b[0] <=> a[0] }
|
|
207
|
+
# Remove the counter
|
|
208
|
+
tags_count.collect { |_, t| t }
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# creates html-files for downloading the files
|
|
212
|
+
def update_html
|
|
213
|
+
used_tags = %w(windows mac linux android media).select { |tag|
|
|
214
|
+
get_tags(tag).size > 0 }
|
|
215
|
+
|
|
216
|
+
# First create index.html
|
|
217
|
+
save_html('index.html',
|
|
218
|
+
"<ul>\n" +
|
|
219
|
+
used_tags.collect { |tag|
|
|
220
|
+
"<li><a href='#{@url_html}/html/#{tag}_all.html'>#{tag.capitalize}</a>"
|
|
221
|
+
}.join("\n") +
|
|
222
|
+
"</ul>\n")
|
|
223
|
+
|
|
224
|
+
unless File.exists?(@dir_html)
|
|
225
|
+
FileUtils.mkdir(@dir_html)
|
|
226
|
+
end
|
|
227
|
+
# Add each main tag that exists
|
|
228
|
+
used_tags.each { |tag|
|
|
229
|
+
save_html(File.join('html', "#{tag}_all.html"),
|
|
230
|
+
"<h1>#{tag.capitalize}</h1>\n" +
|
|
231
|
+
html_tag_links(tag) +
|
|
232
|
+
"<h3><a href='../index.html'>Home</a></h3>" +
|
|
233
|
+
html_tag_files(tag)
|
|
234
|
+
)
|
|
235
|
+
# Add tag-files
|
|
236
|
+
(get_tags(tag) - [tag]).each { |t|
|
|
237
|
+
save_html(File.join('html', "#{tag}_#{t}.html"),
|
|
238
|
+
"<h1><a href='#{tag}_all.html'>#{tag.capitalize}</a></h1>\n" +
|
|
239
|
+
"<h2 class='subtitle'>#{t.capitalize}</h2>" +
|
|
240
|
+
html_tag_links(tag) +
|
|
241
|
+
"<h4 class='back'><a href='../index.html'>Home</a></h4>" +
|
|
242
|
+
html_tag_files([tag, t]))
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def save_html(file, text)
|
|
248
|
+
html = IO.read(File.join(@dir_base, 'index_pre.html')) +
|
|
249
|
+
text +
|
|
250
|
+
IO.read(File.join(@dir_base, 'index_post.html'))
|
|
251
|
+
IO.write(File.join(@dir_base, file), html)
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def html_tag_links(tag)
|
|
255
|
+
"<h3>" + ([:all] + get_tags(tag) - [tag]).collect { |t|
|
|
256
|
+
"<a href='#{tag}_#{t}.html'>#{t.capitalize}</a>"
|
|
257
|
+
}.join(" - ") + '</h3>'
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def html_tag_files(tags)
|
|
261
|
+
"<div class='files'><ul>\n" +
|
|
262
|
+
DFiles.search_by_all(:tags, tags.to_a).collect { |df|
|
|
263
|
+
"<li><a href='../files/#{df.save_file}'>" +
|
|
264
|
+
"#{df.name}</a> - #{df.desc} - " +
|
|
265
|
+
"<a href='#{df.url_page}'>#{df.url_page}</a>" +
|
|
266
|
+
"</li>"
|
|
267
|
+
}.join("\n") +
|
|
268
|
+
"</ul></div>"
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
# Returns a hash of the file-content
|
|
272
|
+
def self.hash(name)
|
|
273
|
+
if File.exists?(name)
|
|
274
|
+
return IO.read(name).bytes.inject { |a, b| a + a * b } % (2**64-1)
|
|
275
|
+
end
|
|
276
|
+
return 0
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
class DFile < Entity
|
|
281
|
+
def print
|
|
282
|
+
p self
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
def get_tag_prio(tag)
|
|
286
|
+
p, _ = tags.find { |_, t|
|
|
287
|
+
t == tag }
|
|
288
|
+
return p ? p.to_i : nil
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
# Singleton entity which holds the configuration
|
|
293
|
+
class DFileConfigs < Entities
|
|
294
|
+
def setup_data
|
|
295
|
+
# 0 for no limit, else limit in GBytes
|
|
296
|
+
value_int :limit_size
|
|
297
|
+
# at what time of the day the system should update
|
|
298
|
+
# -1 = no auto_update
|
|
299
|
+
value_int :auto_update
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
def migration_1(d)
|
|
303
|
+
d.limit_size = 10
|
|
304
|
+
d.auto_update = -1
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
def self.singleton
|
|
308
|
+
first or
|
|
309
|
+
self.create({limit_size: 10, auto_update: -1})
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
class DFileConfig < Entity
|
|
314
|
+
def self.method_missing(m, *args)
|
|
315
|
+
dputs(4) { "#{m} - #{args.inspect} - #{DFileConfigs.singleton.inspect}" }
|
|
316
|
+
if args.length > 0
|
|
317
|
+
DFileConfigs.singleton.send(m, *args)
|
|
318
|
+
else
|
|
319
|
+
DFileConfigs.singleton.send(m)
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
def self.respond_to?(cmd)
|
|
324
|
+
DFileConfigs.singleton.respond_to?(cmd)
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
class DFilePriorities < Entities
|
|
329
|
+
def setup_data
|
|
330
|
+
value_int :priority
|
|
331
|
+
value_str :tags_str
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
def load(has_static = true)
|
|
335
|
+
delete_all
|
|
336
|
+
config = File.join(DFiles.dir_base, 'priorities')
|
|
337
|
+
if File.exists?(config)
|
|
338
|
+
IO.readlines(config).each { |l|
|
|
339
|
+
case l[0]
|
|
340
|
+
when '#'
|
|
341
|
+
#comment
|
|
342
|
+
when /[0-9]/
|
|
343
|
+
# We have a priority
|
|
344
|
+
priority, tags = l.chomp.split(' ', 2)
|
|
345
|
+
DFilePriorities.create({priority: priority.to_i, tags_str: tags})
|
|
346
|
+
else
|
|
347
|
+
# Should be the space
|
|
348
|
+
DFileConfig.limit_size = l.sub(/.*=/, '').to_i
|
|
349
|
+
end
|
|
350
|
+
}
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
def save
|
|
355
|
+
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
# Uses DFilePriorities to decide which files are most important
|
|
359
|
+
def get_most_wanted
|
|
360
|
+
files = []
|
|
361
|
+
|
|
362
|
+
# First add all matching tags for every priority of 1-5
|
|
363
|
+
(1..5).to_a.each { |p|
|
|
364
|
+
search_all_.each { |fp|
|
|
365
|
+
if p == fp.priority
|
|
366
|
+
dputs(4) { "Adding files #{fp.get_files} for prio #{p}" }
|
|
367
|
+
files.push(*fp.get_files)
|
|
368
|
+
end
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
# Then add all other priorities for every line in DFilePriorities
|
|
373
|
+
search_all_.each { |fp|
|
|
374
|
+
if fp.priority >= 6
|
|
375
|
+
dputs(4) { "Adding files #{fp.get_files} for #{fp.inspect}" }
|
|
376
|
+
files.push(*fp.get_files)
|
|
377
|
+
end
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
files.uniq
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
class DFilePriority < Entity
|
|
386
|
+
def get_files
|
|
387
|
+
#dputs_func
|
|
388
|
+
# Search for all tags, then filter according to priorities
|
|
389
|
+
dputs(4) { "Searching tags #{tags.to_s} in #{self.inspect}" }
|
|
390
|
+
DFiles.search_by_all(:tags, tags).select { |df|
|
|
391
|
+
dputs(4) { "Searching DFile #{df.inspect}" }
|
|
392
|
+
prio_min = 10
|
|
393
|
+
df.tags.each { |prio, tag|
|
|
394
|
+
if tags.index(tag)
|
|
395
|
+
prio_min = [prio_min, prio.to_i].min
|
|
396
|
+
end
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
# This will return nil if the priority is not matched,
|
|
400
|
+
# else the priority found, which will be evaluated by
|
|
401
|
+
# the select above to be true.
|
|
402
|
+
if prio_min <= priority.to_i
|
|
403
|
+
dputs(3) { "Found tags #{tags} with priority #{prio_min}" }
|
|
404
|
+
df.priority = prio_min
|
|
405
|
+
end
|
|
406
|
+
}
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
def tags
|
|
410
|
+
tags_str.split(' ')
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
=begin
|
|
415
|
+
files.ndjair.net
|
|
416
|
+
|
|
417
|
+
- copy from profeda.org to markas-al-nour.org
|
|
418
|
+
- only serve completed copies
|
|
419
|
+
- copy Antivirus first, then other things
|
|
420
|
+
|
|
421
|
+
- copy from profeda.org to external hard-disk
|
|
422
|
+
|
|
423
|
+
- copy from external hard-disk to cubox
|
|
424
|
+
- only copy up to N GB of files
|
|
425
|
+
- separated into categories
|
|
426
|
+
- every category has it’s preference
|
|
427
|
+
|
|
428
|
+
- present as web-page
|
|
429
|
+
- first use dokuwiki
|
|
430
|
+
- then use static pages
|
|
431
|
+
|
|
432
|
+
-> move all .file in one directory
|
|
433
|
+
-> move all files in another directory
|
|
434
|
+
-> use hard links to re-create the ./update-files-structure
|
|
435
|
+
-> update .file-directory using rsync
|
|
436
|
+
-> update binary directory according to .file, priority
|
|
437
|
+
|
|
438
|
+
- priority
|
|
439
|
+
- each line contains the tags/directories and a priority
|
|
440
|
+
- first lines have highest priority, last lines are pruned first if too much space
|
|
441
|
+
- 1-5 are pruned in order of importance
|
|
442
|
+
- 6-9 are more important at the beginning
|
|
443
|
+
- 1 is pruned last
|
|
444
|
+
- if more than one tag is given, the lowest priority in the description is taken for
|
|
445
|
+
comparison. So a "3 windows\n1 antivirus"-description would not fit the 1st line, but
|
|
446
|
+
it would fit the 2nd line as priority of 1
|
|
447
|
+
|
|
448
|
+
SPACE=10G
|
|
449
|
+
1 windows
|
|
450
|
+
2 windows antivirus
|
|
451
|
+
9 medias
|
|
452
|
+
|
|
453
|
+
- .file
|
|
454
|
+
add a priority-field: 1 is most important, 9 is least important, for each category
|
|
455
|
+
|
|
456
|
+
- decision which files to include
|
|
457
|
+
1. make list of all files with sizes according to ‘priority’
|
|
458
|
+
2. if total > SPACE
|
|
459
|
+
2.1. starting from the last line in ‘priority’, remove 9 through 6, repeat up the list until SPACE is met
|
|
460
|
+
2.2 if total > SPACE
|
|
461
|
+
2.2.1 prune ‘priority’ 5 to 1, one priority at the time, from end to beginning, starting with biggest files first
|
|
462
|
+
|
|
463
|
+
-> make list and delete from end till space-requirement is met:
|
|
464
|
+
- from priority 1 to priority 5 for all lines, collect files, starting with smallest
|
|
465
|
+
- from first to last line in list do priorities 6 to 9 from smallest to tallest
|
|
466
|
+
=end
|