gestion 1.9.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +48 -0
  3. data/.project +14 -0
  4. data/Binaries/adduser_to_buzz +15 -0
  5. data/Binaries/backup +7 -0
  6. data/Binaries/check_gestion +8 -0
  7. data/Binaries/gestion.gnumail +22 -0
  8. data/Binaries/gestion.logrotate +34 -0
  9. data/Binaries/gestion.service +12 -0
  10. data/Binaries/gestion_update.rb +183 -0
  11. data/Binaries/gestion_update.service +10 -0
  12. data/Binaries/get_compta +11 -0
  13. data/Binaries/kill_gestion +16 -0
  14. data/Binaries/ldap/add_indexes +51 -0
  15. data/Binaries/ldap/backup +2 -0
  16. data/Binaries/ldap/install_ldap +92 -0
  17. data/Binaries/ldap/restore +7 -0
  18. data/Binaries/lib_backup +5 -0
  19. data/Binaries/log_scan_errors +8 -0
  20. data/Binaries/loop_gestion +64 -0
  21. data/Binaries/onetimers/sync_courses_from_compta.rb +74 -0
  22. data/Binaries/onetimers/transfer_cash_from_ldap_to_csv +26 -0
  23. data/Binaries/reboot +5 -0
  24. data/Binaries/restore +3 -0
  25. data/Binaries/restore_do +22 -0
  26. data/Binaries/sort_events +31 -0
  27. data/Binaries/start_gestion +18 -0
  28. data/Binaries/swipe_gestion +18 -0
  29. data/Binaries/update_africompta +21 -0
  30. data/Binaries/update_users +3 -0
  31. data/Diplomas.src/accredited.odg +0 -0
  32. data/Diplomas.src/diploma.odg +0 -0
  33. data/Diplomas.src/label.odg +0 -0
  34. data/Diplomas.src/presence_sheet.ods +0 -0
  35. data/Diplomas.src/presence_sheet_small.ods +0 -0
  36. data/Diplomas.src/student_card.odg +0 -0
  37. data/Doc/130514-it-ideas.odt +0 -0
  38. data/Doc/Compta-cash.mm +179 -0
  39. data/Doc/General.odt +0 -0
  40. data/Entities/AccessGroups.rb +117 -0
  41. data/Entities/Activity.rb +178 -0
  42. data/Entities/ChatMsg.rb +142 -0
  43. data/Entities/Classroom.rb +11 -0
  44. data/Entities/Client.rb +19 -0
  45. data/Entities/Computer.rb +21 -0
  46. data/Entities/ConfigBase.rb +280 -0
  47. data/Entities/Course.rb +1588 -0
  48. data/Entities/CourseType.rb +171 -0
  49. data/Entities/DFiles.rb +466 -0
  50. data/Entities/FilesManage.rb +226 -0
  51. data/Entities/Grade.rb +186 -0
  52. data/Entities/Internet.rb +300 -0
  53. data/Entities/Netdev.rb +10 -0
  54. data/Entities/Person.rb +1175 -0
  55. data/Entities/Plug.rb +98 -0
  56. data/Entities/Quiz.rb +33 -0
  57. data/Entities/Recharges.rb +37 -0
  58. data/Entities/Report.rb +136 -0
  59. data/Entities/Room.rb +12 -0
  60. data/Entities/SMS.rb +30 -0
  61. data/Entities/ScheduleType.rb +33 -0
  62. data/Entities/Share.rb +120 -0
  63. data/Entities/Task.rb +51 -0
  64. data/Entities/Ticket.rb +72 -0
  65. data/Entities/Usage.rb +143 -0
  66. data/Entities/Worker.rb +29 -0
  67. data/Files/apache-profeda.conf +36 -0
  68. data/Files/label.erb +121 -0
  69. data/Files/label_notfound.erb +64 -0
  70. data/Files/label_notpassed.erb +84 -0
  71. data/Files/mobileinfo.erb +115 -0
  72. data/Files/smb.conf +333 -0
  73. data/Files/timetable.html +36 -0
  74. data/Files/timetable.js +239 -0
  75. data/Gemfile +12 -0
  76. data/Gemfile.dev +12 -0
  77. data/Gemfile.dev.lock +127 -0
  78. data/Gemfile.lock +127 -0
  79. data/Gemfile.prod +8 -0
  80. data/Gestion +35 -0
  81. data/Gestion.rb +220 -0
  82. data/INSTALL +40 -0
  83. data/Images/connection.xcf +0 -0
  84. data/Images/connection_no.png +0 -0
  85. data/Images/connection_wait.png +0 -0
  86. data/Images/connection_yes.png +0 -0
  87. data/Paths/Exas.rb +13 -0
  88. data/Paths/Files.rb +19 -0
  89. data/Paths/GetDiplomas.rb +20 -0
  90. data/Paths/Info.rb +114 -0
  91. data/Paths/Label.rb +187 -0
  92. data/Paths/MobileInfo.rb +19 -0
  93. data/Paths/internetCash.rb +34 -0
  94. data/Paths/internetWifi.rb +54 -0
  95. data/README.md +60 -0
  96. data/Rakefile +13 -0
  97. data/TODO +1391 -0
  98. data/Test/.gitignore +3 -0
  99. data/Test/Diplomas/base_gestion.odt +0 -0
  100. data/Test/Diplomas/base_report.odt +0 -0
  101. data/Test/Diplomas/carte_etudiant.odg +0 -0
  102. data/Test/Diplomas/exam_language.odt +0 -0
  103. data/Test/Diplomas/label.odg +0 -0
  104. data/Test/Diplomas/presence_sheet.ods +0 -0
  105. data/Test/Diplomas/presence_sheet_small.ods +0 -0
  106. data/Test/Diplomas/student_card.odg +0 -0
  107. data/Test/Manual/testMerge +18 -0
  108. data/Test/config_test.yaml +26 -0
  109. data/Test/db.testGestion +0 -0
  110. data/Test/dfiles/descs/avg-rescue.desc +10 -0
  111. data/Test/dfiles/descs/avg.desc +8 -0
  112. data/Test/dfiles/descs/driver.desc +8 -0
  113. data/Test/dfiles/descs/linuxmint.desc +7 -0
  114. data/Test/dfiles/files/avg-160203.exe +1 -0
  115. data/Test/dfiles/files/avg.iso +1 -0
  116. data/Test/dfiles/files/driver.exe +1 -0
  117. data/Test/dfiles/index_post.html +3 -0
  118. data/Test/dfiles/index_pre.html +8 -0
  119. data/Test/dfiles/priorities +5 -0
  120. data/Test/ge_activity.rb +124 -0
  121. data/Test/ge_chat.rb +106 -0
  122. data/Test/ge_compta.rb +67 -0
  123. data/Test/ge_configbase.rb +54 -0
  124. data/Test/ge_course.rb +1114 -0
  125. data/Test/ge_dfiles.rb +121 -0
  126. data/Test/ge_filesmanage.rb +180 -0
  127. data/Test/ge_info.rb +27 -0
  128. data/Test/ge_internet.rb +246 -0
  129. data/Test/ge_login.rb +55 -0
  130. data/Test/ge_person.rb +373 -0
  131. data/Test/ge_qvinfo.rb +28 -0
  132. data/Test/ge_report.rb +97 -0
  133. data/Test/ge_share.rb +27 -0
  134. data/Test/ge_sms.rb +34 -0
  135. data/Test/ge_tasks.rb +19 -0
  136. data/Test/ge_usage.rb +168 -0
  137. data/Test/ge_view.rb +46 -0
  138. data/Test/multiconf-captive +29 -0
  139. data/Test/test.conf +7 -0
  140. data/Test/test.rb +49 -0
  141. data/Test/test_bytes.png +0 -0
  142. data/VERSION +140 -0
  143. data/Views/Admin/Backup.rb +91 -0
  144. data/Views/Admin/Configuration.rb +44 -0
  145. data/Views/Admin/Credit.rb +32 -0
  146. data/Views/Admin/FilesManage.rb +219 -0
  147. data/Views/Admin/Function.rb +39 -0
  148. data/Views/Admin/Power.rb +49 -0
  149. data/Views/Admin/Printer.rb +37 -0
  150. data/Views/Admin/Server.rb +252 -0
  151. data/Views/Admin/Tabs.rb +5 -0
  152. data/Views/Admin/Update.rb +73 -0
  153. data/Views/Admin/UpdateSystem.rb +26 -0
  154. data/Views/Cashbox/Activity.rb +191 -0
  155. data/Views/Cashbox/Course.rb +141 -0
  156. data/Views/Cashbox/Credit.rb +79 -0
  157. data/Views/Cashbox/Report.rb +115 -0
  158. data/Views/Cashbox/Service.rb +105 -0
  159. data/Views/Cashbox/Tabs.rb +10 -0
  160. data/Views/Compta/Accounts.rb +36 -0
  161. data/Views/Compta/Course.rb +96 -0
  162. data/Views/Compta/Show.rb +6 -0
  163. data/Views/Compta/Transfer.rb +66 -0
  164. data/Views/Course/Diploma.rb +203 -0
  165. data/Views/Course/Grade.rb +401 -0
  166. data/Views/Course/Modify.rb +447 -0
  167. data/Views/Course/Print.rb +94 -0
  168. data/Views/Course/Responsible.rb +44 -0
  169. data/Views/Course/Stats.rb +76 -0
  170. data/Views/Course/Students.rb +92 -0
  171. data/Views/Course/Tabs.rb +220 -0
  172. data/Views/Internet/Access.rb +134 -0
  173. data/Views/Internet/ClassEdit.rb +24 -0
  174. data/Views/Internet/ClassUsers.rb +81 -0
  175. data/Views/Internet/Config.rb +32 -0
  176. data/Views/Internet/Mobile.rb +213 -0
  177. data/Views/Internet/Recharges.rb +49 -0
  178. data/Views/Internet/Tabs.rb +6 -0
  179. data/Views/Inventory/Computer.rb +24 -0
  180. data/Views/Inventory/Room.rb +18 -0
  181. data/Views/Inventory/Tabs.rb +9 -0
  182. data/Views/Inventory/TicketClosed.rb +7 -0
  183. data/Views/Inventory/TicketOpen.rb +23 -0
  184. data/Views/Library/Person.rb +36 -0
  185. data/Views/Library/Tabs.rb +7 -0
  186. data/Views/Network/Block.rb +87 -0
  187. data/Views/Network/Netdevs.rb +21 -0
  188. data/Views/Network/Restriction.rb +37 -0
  189. data/Views/Network/Share.rb +167 -0
  190. data/Views/Network/Tables.rb +28 -0
  191. data/Views/Network/Tabs.rb +6 -0
  192. data/Views/Person/Admin.rb +99 -0
  193. data/Views/Person/Center.rb +48 -0
  194. data/Views/Person/Course.rb +72 -0
  195. data/Views/Person/Modify.rb +153 -0
  196. data/Views/Person/Tabs.rb +162 -0
  197. data/Views/Report/ComptaExecutive.rb +221 -0
  198. data/Views/Report/ComptaFlat.rb +79 -0
  199. data/Views/Report/ReportCourse.rb +47 -0
  200. data/Views/Report/Tabs.rb +8 -0
  201. data/Views/Report/Usage.rb +52 -0
  202. data/Views/Report/UsageCases.rb +59 -0
  203. data/Views/Self/Cash.rb +67 -0
  204. data/Views/Self/Chat.rb +55 -0
  205. data/Views/Self/Concours.rb +109 -0
  206. data/Views/Self/Email.rb +34 -0
  207. data/Views/Self/Internet.rb +255 -0
  208. data/Views/Self/Results.rb +17 -0
  209. data/Views/Self/Services.rb +85 -0
  210. data/Views/Self/Show.rb +47 -0
  211. data/Views/Self/Tabs.rb +5 -0
  212. data/Views/Special/DFileEdit.rb +13 -0
  213. data/Views/Special/PlugEdit.rb +56 -0
  214. data/Views/Special/Tabs.rb +6 -0
  215. data/Views/Special/Vnc.rb +39 -0
  216. data/Views/Task/Client.rb +21 -0
  217. data/Views/Task/Edit.rb +33 -0
  218. data/Views/Task/List.rb +55 -0
  219. data/Views/Task/Tabs.rb +9 -0
  220. data/Views/Task/Worker.rb +30 -0
  221. data/Views/Template/Activity.rb +33 -0
  222. data/Views/Template/CourseType.rb +63 -0
  223. data/Views/Template/ScheduleType.rb +29 -0
  224. data/Views/Template/Tabs.rb +5 -0
  225. data/Views/Welcome.rb +121 -0
  226. data/config.yaml.default +36 -0
  227. data/po/Gestion-ar.po +2356 -0
  228. data/po/Gestion-en.mo +0 -0
  229. data/po/Gestion-en.po +4363 -0
  230. data/po/Gestion-fr.mo +0 -0
  231. data/po/Gestion-fr.po +4345 -0
  232. data/po/traduction-ar.rtf +76 -0
  233. metadata +381 -0
@@ -0,0 +1,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