gestion 1.9.12

Sign up to get free protection for your applications and to get access to all the features.
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,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
@@ -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