knjappserver 0.0.6

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 (47) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +18 -0
  4. data/Gemfile.lock +39 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.rdoc +19 -0
  7. data/Rakefile +49 -0
  8. data/VERSION +1 -0
  9. data/bin/check_running.rb +71 -0
  10. data/bin/knjappserver_start.rb +50 -0
  11. data/knjappserver.gemspec +107 -0
  12. data/lib/conf/README +1 -0
  13. data/lib/conf/conf_example.rb +109 -0
  14. data/lib/conf/conf_vars_example.rb +3 -0
  15. data/lib/files/database_schema.rb +111 -0
  16. data/lib/files/run/README +1 -0
  17. data/lib/include/class_customio.rb +21 -0
  18. data/lib/include/class_erbhandler.rb +36 -0
  19. data/lib/include/class_httpresp.rb +91 -0
  20. data/lib/include/class_httpserver.rb +91 -0
  21. data/lib/include/class_httpsession.rb +350 -0
  22. data/lib/include/class_httpsession_knjengine.rb +189 -0
  23. data/lib/include/class_httpsession_mongrel.rb +75 -0
  24. data/lib/include/class_httpsession_webrick.rb +75 -0
  25. data/lib/include/class_knjappserver.rb +455 -0
  26. data/lib/include/class_knjappserver_cleaner.rb +109 -0
  27. data/lib/include/class_knjappserver_errors.rb +117 -0
  28. data/lib/include/class_knjappserver_logging.rb +272 -0
  29. data/lib/include/class_knjappserver_mailing.rb +97 -0
  30. data/lib/include/class_knjappserver_threadding.rb +87 -0
  31. data/lib/include/class_knjappserver_web.rb +23 -0
  32. data/lib/include/class_log.rb +81 -0
  33. data/lib/include/class_log_access.rb +103 -0
  34. data/lib/include/class_log_data.rb +42 -0
  35. data/lib/include/class_log_data_link.rb +16 -0
  36. data/lib/include/class_log_data_value.rb +34 -0
  37. data/lib/include/class_log_link.rb +51 -0
  38. data/lib/include/class_session.rb +43 -0
  39. data/lib/include/gettext_funcs.rb +10 -0
  40. data/lib/include/magic_methods.rb +59 -0
  41. data/lib/knjappserver.rb +1 -0
  42. data/lib/pages/logs_latest.rhtml +57 -0
  43. data/lib/pages/logs_show.rhtml +32 -0
  44. data/lib/pages/spec.rhtml +10 -0
  45. data/spec/knjappserver_spec.rb +110 -0
  46. data/spec/spec_helper.rb +12 -0
  47. metadata +188 -0
@@ -0,0 +1,272 @@
1
+ class Knjappserver
2
+ def initialize_logging
3
+ @logs_access_pending = []
4
+ @logs_mutex = Mutex.new
5
+
6
+ if @config[:logging] and @config[:logging][:access_db]
7
+ self.timeout(:time => 30) do
8
+ if @logs_access_pending.length > 0
9
+ flush_access_log
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+ def flush_access_log
16
+ @logs_mutex.synchronize do
17
+ ins_arr = @logs_access_pending
18
+ @logs_access_pending = []
19
+ inserts = []
20
+ inserts_links = []
21
+
22
+ ins_arr.each do |ins|
23
+ gothrough = [{
24
+ :col => :get_keys_data_id,
25
+ :hash => ins[:get],
26
+ :type => :keys
27
+ },{
28
+ :col => :get_values_data_id,
29
+ :hash => ins[:get],
30
+ :type => :values
31
+ },{
32
+ :col => :post_keys_data_id,
33
+ :hash => ins[:post],
34
+ :type => :keys
35
+ },{
36
+ :col => :post_values_data_id,
37
+ :hash => ins[:post],
38
+ :type => :values
39
+ },{
40
+ :col => :cookie_keys_data_id,
41
+ :hash => ins[:cookie],
42
+ :type => :keys
43
+ },{
44
+ :col => :cookie_values_data_id,
45
+ :hash => ins[:cookie],
46
+ :type => :values
47
+ },{
48
+ :col => :meta_keys_data_id,
49
+ :hash => ins[:meta],
50
+ :type => :keys
51
+ },{
52
+ :col => :meta_values_data_id,
53
+ :hash => ins[:meta],
54
+ :type => :values
55
+ }]
56
+ ins_hash = {
57
+ :session_id => ins[:session_id],
58
+ :date_request => ins[:date_request]
59
+ }
60
+
61
+ gothrough.each do |data|
62
+ if data[:type] == :keys
63
+ hash = Knj::ArrayExt.hash_keys_hash(data[:hash])
64
+ else
65
+ hash = Knj::ArrayExt.hash_values_hash(data[:hash])
66
+ end
67
+
68
+ data_id = @ob.static(:Log_data, :by_id_hash, hash)
69
+ if !data_id
70
+ data_id = @db.insert(:Log_data, {"id_hash" => hash}, {:return_id => true})
71
+
72
+ link_count = 0
73
+ data[:hash].keys.sort.each do |key|
74
+ if data[:type] == :keys
75
+ ins_data = "#{key.to_s}"
76
+ else
77
+ ins_data = "#{data[:hash][key]}"
78
+ end
79
+
80
+ ins_data = ins_data.force_encoding("UTF-8") if ins_data.respond_to?(:force_encoding)
81
+ data_value_id = @ob.static(:Log_data_value, :force_id, ins_data)
82
+ inserts_links << {:no => link_count, :data_id => data_id, :value_id => data_value_id}
83
+ link_count += 1
84
+ end
85
+ end
86
+
87
+ ins_hash[data[:col]] = data_id
88
+ end
89
+
90
+ hash = Knj::ArrayExt.array_hash(ins[:ips])
91
+ data_id = @ob.static(:Log_data, :by_id_hash, hash)
92
+
93
+ if !data_id
94
+ data_id = @db.insert(:Log_data, {"id_hash" => hash}, {:return_id => true})
95
+
96
+ link_count = 0
97
+ ins[:ips].each do |ip|
98
+ data_value_id = @ob.static(:Log_data_value, :force_id, ip)
99
+ inserts_links << {:no => link_count, :data_id => data_id, :value_id => data_value_id}
100
+ link_count += 1
101
+ end
102
+ end
103
+
104
+ ins_hash[:ip_data_id] = data_id
105
+ inserts << ins_hash
106
+ end
107
+
108
+ @db.insert_multi(:Log_access, inserts)
109
+ @db.insert_multi(:Log_data_link, inserts_links)
110
+ @ob.unset_class([:Log_access, :Log_data, :Log_data_link, :Log_data_value])
111
+ end
112
+ end
113
+
114
+ def log_hash_ins(hash_obj)
115
+ inserts_links = []
116
+ ret = {}
117
+ [:keys, :values].each do |type|
118
+ if type == :keys
119
+ hash = Knj::ArrayExt.hash_keys_hash(hash_obj)
120
+ else
121
+ hash = Knj::ArrayExt.hash_values_hash(hash_obj)
122
+ end
123
+
124
+ data_id = @db.single(:Log_data, {"id_hash" => hash})
125
+ data_id = data_id[:id] if data_id
126
+
127
+ if !data_id
128
+ data_id = @db.insert(:Log_data, {"id_hash" => hash}, {:return_id => true})
129
+
130
+ link_count = 0
131
+ hash_obj.keys.sort.each do |key|
132
+ if type == :keys
133
+ ins_data = "#{key.to_s}"
134
+ else
135
+ ins_data = "#{hash_obj[key].to_s}"
136
+ end
137
+
138
+ ins_data = ins_data.force_encoding("UTF-8") if ins_data.respond_to?(:force_encoding)
139
+ data_value_id = @ob.static(:Log_data_value, :force_id, ins_data)
140
+ inserts_links << {:no => link_count, :data_id => data_id, :value_id => data_value_id}
141
+ link_count += 1
142
+ end
143
+ end
144
+
145
+ if type == :keys
146
+ ret[:keys_data_id] = data_id
147
+ else
148
+ ret[:values_data_id] = data_id
149
+ end
150
+ end
151
+
152
+ @db.insert_multi(:Log_data_link, inserts_links)
153
+
154
+ return ret
155
+ end
156
+
157
+ def log_data_hash(keys_id, values_id)
158
+ keys_data_obj = @ob.get(:Log_data, keys_id)
159
+ values_data_obj = @ob.get(:Log_data, values_id)
160
+
161
+ sql = "
162
+ SELECT
163
+ key_value.value AS `key`,
164
+ value_value.value AS value
165
+
166
+ FROM
167
+ Log_data_link AS key_links,
168
+ Log_data_link AS value_links,
169
+ Log_data_value AS key_value,
170
+ Log_data_value AS value_value
171
+
172
+ WHERE
173
+ key_links.data_id = '#{keys_id}' AND
174
+ value_links.data_id = '#{values_id}' AND
175
+ key_links.no = value_links.no AND
176
+ key_value.id = key_links.value_id AND
177
+ value_value.id = value_links.value_id
178
+
179
+ ORDER BY
180
+ key_links.no
181
+ "
182
+
183
+ hash = {}
184
+ q_hash = db.query(sql)
185
+ while d_hash = q_hash.fetch
186
+ hash[d_hash[:key].to_sym] = d_hash[:value]
187
+ end
188
+
189
+ return hash
190
+ end
191
+
192
+ def log(msg, objs)
193
+ @logs_mutex.synchronize do
194
+ objs = [objs] if !objs.is_a?(Array)
195
+ log_value_id = @ob.static(:Log_data_value, :force_id, msg)
196
+ ins_data = {
197
+ :date_saved => Time.new,
198
+ :text_value_id => log_value_id
199
+ }
200
+
201
+ get_hash = log_hash_ins(_get) if _get
202
+ if get_hash
203
+ ins_data[:get_keys_data_id] = get_hash[:keys_data_id]
204
+ ins_data[:get_values_data_id] = get_hash[:values_data_id]
205
+ end
206
+
207
+ post_hash = log_hash_ins(_post) if _post
208
+ if post_hash
209
+ ins_data[:post_keys_data_id] = post_hash[:keys_data_id]
210
+ ins_data[:post_values_data_id] = post_hash[:values_data_id]
211
+ end
212
+
213
+ log_id = @db.insert(:Log, ins_data, {:return_id => true})
214
+
215
+ log_links = []
216
+ objs.each do |obj|
217
+ class_data_id = @ob.static(:Log_data_value, :force_id, obj.class.name)
218
+
219
+ log_links << {
220
+ :object_class_value_id => class_data_id,
221
+ :object_id => obj.id,
222
+ :log_id => log_id
223
+ }
224
+ end
225
+
226
+ @db.insert_multi(:Log_link, log_links)
227
+ end
228
+ end
229
+
230
+ def logs_table(obj, args = {})
231
+ links = @ob.list(:Log_link, {"object_class" => obj.class.name, "object_id" => obj.id, "limit" => 500, "orderby" => [["id", "desc"]]})
232
+
233
+ html = "<table class=\"list knjappserver_log_table\">"
234
+ html += "<thead>"
235
+ html += "<tr>"
236
+ html += "<th>ID</th>"
237
+ html += "<th>Message</th>"
238
+ html += "<th>Date &amp; time</th>"
239
+ html += "<th>Objects</th>" if args[:ob_use]
240
+ html += "</tr>"
241
+ html += "</thead>"
242
+ html += "<tbody>"
243
+
244
+ links.each do |link|
245
+ log = link.log
246
+
247
+ msg_lines = log.text.split("\n")
248
+ first_line = msg_lines[0].to_s
249
+
250
+ classes = ["knjappserver_log", "knjappserver_log_#{log.id}"]
251
+ classes << "knjappserver_log_multiple_lines" if msg_lines.length > 1
252
+
253
+ html += "<tr class=\"#{classes.join(" ")}\">"
254
+ html += "<td>#{log.id}</td>"
255
+ html += "<td>#{first_line.html}</td>"
256
+ html += "<td>#{log.date_saved_str}</td>"
257
+ html += "<td>#{log.objects_html(args[:ob_use])}</td>" if args[:ob_use]
258
+ html += "</tr>"
259
+ end
260
+
261
+ if links.empty?
262
+ html += "<tr>"
263
+ html += "<td colspan=\"2\" class=\"error\">No logs were found for that object.</td>"
264
+ html += "</tr>"
265
+ end
266
+
267
+ html += "</tbody>"
268
+ html += "</table>"
269
+
270
+ return html
271
+ end
272
+ end
@@ -0,0 +1,97 @@
1
+ class Knjappserver
2
+ attr_reader :mails_waiting
3
+
4
+ def initialize_mailing
5
+ @mails_waiting = []
6
+ @mails_mutex = Mutex.new
7
+ @mails_queue_mutex = Mutex.new
8
+ @mails_timeout = self.timeout(:time => 10) do
9
+ self.mail_flush
10
+ end
11
+ end
12
+
13
+ def mail(mail_args)
14
+ @mails_queue_mutex.synchronize do
15
+ count_wait = 0
16
+ while @mails_waiting.length > 100
17
+ if count_wait >= 30
18
+ raise "Could not send email - too many emails was pending and none of them were being sent?"
19
+ end
20
+
21
+ count_wait += 1
22
+ sleep 1
23
+ end
24
+
25
+ mailobj = Knjappserver::Mail.new({:kas => self, :errors => {}, :status => :waiting}.merge(mail_args))
26
+ @mails_waiting << mailobj
27
+ return mailobj
28
+ end
29
+ end
30
+
31
+ def mail_flush
32
+ @mails_mutex.synchronize do
33
+ return false if @mails_waiting.length <= 0
34
+
35
+ status = Ping.pingecho("google.dk", 10, 80)
36
+ if !status
37
+ STDOUT.print "We are not online - skipping mail flush.\n"
38
+ return false #Dont run if we dont have a connection to the internet and then properly dont have a connection to the SMTP as well.
39
+ end
40
+
41
+ @mails_waiting.each do |mail|
42
+ begin
43
+ if mail.send
44
+ @mails_waiting.delete(mail)
45
+ end
46
+ rescue Timeout::Error
47
+ #ignore -
48
+ rescue => e
49
+ @mails_waiting.delete(mail)
50
+ self.handle_error(e, {:email => false})
51
+ end
52
+
53
+ sleep 1 #sleep so we dont take up too much bandwidth.
54
+ end
55
+ end
56
+ end
57
+
58
+ class Mail
59
+ def initialize(args)
60
+ @args = args
61
+
62
+ raise "No knjappserver-object was given (as :kas)." if !@args[:kas].is_a?(Knjappserver)
63
+ raise "No :to was given." if !@args[:to]
64
+ raise "No content was given (:html)." if !@args[:html]
65
+ end
66
+
67
+ def [](key)
68
+ return @args[key]
69
+ end
70
+
71
+ def send
72
+ mail = Knj::Mailobj.new(@args[:kas].config[:smtp_args])
73
+ mail.to = @args[:to]
74
+ mail.subject = @args[:subject] if @args[:subject]
75
+ mail.html = @args[:html] if @args[:html]
76
+
77
+ if @args[:from]
78
+ mail.from = @args[:from]
79
+ else
80
+ mail.from = @args[:kas].config[:error_report_from]
81
+ end
82
+
83
+ begin
84
+ mail.send
85
+ @args[:status] = :sent
86
+ return true
87
+ rescue SocketError => e
88
+ @args[:errors][e.class.name] = {:count => 0} if !@args[:errors].has_key?(e.class.name)
89
+ @args[:errors][e.class.name][:count] += 1
90
+ raise e if @args[:errors][e.class.name][:count] >= 5
91
+ @args[:status] = :error
92
+ @args[:error] = e
93
+ return false
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,87 @@
1
+ class Knjappserver
2
+ def initialize_threadding
3
+ @config[:threadding] = {} if !@config.has_key?(:threadding)
4
+ @config[:threadding][:max_running] = 25 if !@config[:threadding].has_key?(:max_running)
5
+
6
+ @threadpool = Knj::Threadpool.new(:threads => @config[:threadding][:max_running])
7
+ @threadpool.events.connect(:on_error) do |event, error|
8
+ STDOUT.print "Error!\n"
9
+ self.handle_error(error)
10
+ end
11
+ end
12
+
13
+ def thread(args = {})
14
+ raise "No block given." if !block_given?
15
+ args[:args] = [] if !args[:args]
16
+
17
+ @threadpool.run_async do
18
+ @ob.db.get_and_register_thread if @ob.db.opts[:threadsafe]
19
+ @db_handler.get_and_register_thread if @db_handler.opts[:threadsafe]
20
+
21
+ Thread.current[:knjappserver] = {
22
+ :kas => self,
23
+ :db => @db_handler
24
+ }
25
+
26
+ begin
27
+ yield(*args[:args])
28
+ rescue Exception => e
29
+ handle_error(e)
30
+ ensure
31
+ @ob.db.free_thread if @ob.db.opts[:threadsafe]
32
+ @db_handler.free_thread if @db_handler.opts[:threadsafe]
33
+ end
34
+ end
35
+ end
36
+
37
+ def timeout(args = {})
38
+ raise "No time given." if !args.has_key?(:time)
39
+ raise "No block given." if !block_given?
40
+ args[:args] = [] if !args[:args]
41
+
42
+ thread = Thread.new do
43
+ loop do
44
+ begin
45
+ if args[:counting]
46
+ Thread.current[:knjappserver_timeout] = args[:time].to_s.to_i
47
+
48
+ while Thread.current[:knjappserver_timeout] > 0
49
+ Thread.current[:knjappserver_timeout] += -1
50
+ break if @should_restart
51
+ sleep 1
52
+ end
53
+ else
54
+ sleep args[:time]
55
+ end
56
+
57
+ break if @should_restart
58
+
59
+ @threadpool.run do
60
+ @ob.db.get_and_register_thread if @ob.db.opts[:threadsafe]
61
+ @db_handler.get_and_register_thread if @db_handler.opts[:threadsafe]
62
+
63
+ Thread.current[:knjappserver] = {
64
+ :kas => self,
65
+ :db => @db_handler
66
+ }
67
+
68
+ begin
69
+ yield(*args[:args])
70
+ ensure
71
+ @ob.db.free_thread if @ob.db.opts[:threadsafe]
72
+ @db_handler.free_thread if @db_handler.opts[:threadsafe]
73
+ end
74
+ end
75
+ rescue Exception => e
76
+ handle_error(e)
77
+ end
78
+ end
79
+ end
80
+
81
+ return thread
82
+ end
83
+
84
+ def threadded_content(&block)
85
+ _httpsession.threadded_content(block)
86
+ end
87
+ end
@@ -0,0 +1,23 @@
1
+ class Knjappserver
2
+ def redirect(url, args = {})
3
+ return Knj::Web.redirect(url, args)
4
+ end
5
+
6
+ def alert(msg)
7
+ Knj::Web.alert(msg)
8
+ return self
9
+ end
10
+
11
+ def header(key, val)
12
+ Knj::Php.header("#{key}: #{val}")
13
+ end
14
+
15
+ def header_raw(str)
16
+ Knj::Php.header(str)
17
+ end
18
+
19
+ def back
20
+ Knj::Web.back
21
+ return self
22
+ end
23
+ end
@@ -0,0 +1,81 @@
1
+ class Knjappserver::Log < Knj::Datarow
2
+ def self.list(d)
3
+ sql = "SELECT #{table}.* FROM #{table}"
4
+
5
+ if d.args["object_lookup"]
6
+ data_val = d.ob.get_by(:Log_data_value, {"value" => d.args["object_lookup"].class.name})
7
+ return [] if !data_val #if this data-value cannot be found, nothing has been logged for the object. So just return empty array here and skip the rest.
8
+
9
+ sql += "
10
+ LEFT JOIN Log_link ON
11
+ Log_link.log_id = #{table}.id AND
12
+ Log_link.object_class_value_id = '#{d.db.esc(data_val.id)}' AND
13
+ Log_link.object_id = '#{d.db.esc(d.args["object_lookup"].id)}'
14
+ "
15
+ end
16
+
17
+ sql += " WHERE 1=1"
18
+
19
+ ret = list_helper(d)
20
+ d.args.each do |key, val|
21
+ case key
22
+ when "object_lookup"
23
+ sql += " AND Log_link.id IS NOT NULL"
24
+ else
25
+ raise "Invalid key: #{key}."
26
+ end
27
+ end
28
+
29
+ sql += ret[:sql_where]
30
+ sql += ret[:sql_order]
31
+ sql += ret[:sql_limit]
32
+
33
+ return d.ob.list_bysql(:Log, sql)
34
+ end
35
+
36
+ def self.add(d)
37
+ if !d.data.has_key?(:date_saved)
38
+ d.data[:date_saved] = d.db.date_out(Knj::Datet.new)
39
+ end
40
+ end
41
+
42
+ def text
43
+ return ob.get(:Log_data_value, self[:text_value_id])[:value]
44
+ end
45
+
46
+ def get
47
+ ob.args[:knjappserver].log_data_hash(self[:get_keys_data_id], self[:get_values_data_id])
48
+ end
49
+
50
+ def post
51
+ ob.args[:knjappserver].log_data_hash(self[:post_keys_data_id], self[:post_values_data_id])
52
+ end
53
+
54
+ def first_line
55
+ lines = self.text.to_s.split("\n").first.to_s
56
+ end
57
+
58
+ def links(args = {})
59
+ return ob.list(:Log_link, {"log" => self}.merge(args))
60
+ end
61
+
62
+ def objects_html(ob_use)
63
+ html = ""
64
+ first = true
65
+
66
+ self.links.each do |link|
67
+ obj = link.object(ob_use)
68
+
69
+ html += ", " if !first
70
+ first = false if first
71
+
72
+ if obj.respond_to?(:html)
73
+ html += obj.html
74
+ else
75
+ html += "#{obj.class.name}{#{obj.id}}"
76
+ end
77
+ end
78
+
79
+ return html
80
+ end
81
+ end
@@ -0,0 +1,103 @@
1
+ class Knjappserver::Log_access < Knj::Datarow
2
+ def self.list(d)
3
+ sql = "SELECT * FROM #{table} WHERE 1=1"
4
+
5
+ ret = list_helper(d)
6
+ d.args.each do |key, val|
7
+ raise "Invalid key: #{key}."
8
+ end
9
+
10
+ sql += ret[:sql_where]
11
+ sql += ret[:sql_order]
12
+ sql += ret[:sql_limit]
13
+
14
+ return d.ob.list_bysql(:Log_access, sql)
15
+ end
16
+
17
+ def get
18
+ return data_hash("get")
19
+ end
20
+
21
+ def post
22
+ return data_hash("post")
23
+ end
24
+
25
+ def meta
26
+ return data_hash("meta")
27
+ end
28
+
29
+ def cookie
30
+ return data_hash("cookie")
31
+ end
32
+
33
+ def ips
34
+ return data_array(self[:ip_data_id])
35
+ end
36
+
37
+ def data_array(data_id)
38
+ sql = "
39
+ SELECT
40
+ value_value.value AS value
41
+
42
+ FROM
43
+ Log_data_link AS value_links,
44
+ Log_data_value AS value_value
45
+
46
+ WHERE
47
+ value_links.data_id = '#{data_id}' AND
48
+ value_value.id = value_links.value_id
49
+
50
+ ORDER BY
51
+ key_links.no
52
+ "
53
+
54
+ arr = []
55
+ q_array = db.query(sql)
56
+ while d_array = q_array.fetch
57
+ arr << d_array[:value]
58
+ end
59
+
60
+ return arr
61
+ end
62
+
63
+ def data_hash(type)
64
+ col_keys_id = "#{type}_keys_data_id".to_sym
65
+ col_values_id = "#{type}_values_data_id".to_sym
66
+
67
+ keys_id = self[col_keys_id]
68
+ values_id = self[col_values_id]
69
+
70
+ keys_data_obj = ob.get(:Log_data, keys_id)
71
+ values_data_obj = ob.get(:Log_data, values_id)
72
+
73
+ sql = "
74
+ SELECT
75
+ key_value.value AS `key`,
76
+ value_value.value AS value
77
+
78
+ FROM
79
+ Log_data_link AS key_links,
80
+ Log_data_link AS value_links,
81
+ Log_data_value AS key_value,
82
+ Log_data_value AS value_value
83
+
84
+ WHERE
85
+ key_links.data_id = '#{keys_id}' AND
86
+ value_links.data_id = '#{values_id}' AND
87
+ key_links.no = value_links.no AND
88
+ key_value.id = key_links.value_id AND
89
+ value_value.id = value_links.value_id
90
+
91
+ ORDER BY
92
+ key_links.no
93
+ "
94
+
95
+ hash = {}
96
+ q_hash = db.query(sql)
97
+ while d_hash = q_hash.fetch
98
+ hash[d_hash[:key].to_s] = d_hash[:value]
99
+ end
100
+
101
+ return hash
102
+ end
103
+ end
@@ -0,0 +1,42 @@
1
+ class Knjappserver::Log_data < Knj::Datarow
2
+ def self.list(d)
3
+ sql = "SELECT * FROM #{table} WHERE 1=1"
4
+
5
+ ret = list_helper(d)
6
+ d.args.each do |key, val|
7
+ raise "Invalid key: #{key}."
8
+ end
9
+
10
+ sql += ret[:sql_where]
11
+ sql += ret[:sql_order]
12
+ sql += ret[:sql_limit]
13
+
14
+ return d.ob.list_bysql(:Log_data, sql)
15
+ end
16
+
17
+ def self.force(d, id_hash)
18
+ data_obj = d.ob.get_by(:Log_data, {"id_hash" => id_hash})
19
+
20
+ if !data_obj
21
+ data_obj = d.ob.add(:Log_data, {"id_hash" => id_hash})
22
+ end
23
+
24
+ return data_obj
25
+ end
26
+
27
+ def self.force_id(d, id_hash)
28
+ data = d.db.query("SELECT * FROM Log_data WHERE id_hash = '#{d.db.esc(id_hash)}' LIMIT 1").fetch
29
+ return data[:id].to_i if data
30
+ return d.db.insert(:Log_data, {:id_hash => id_hash}, {:return_id => true}).to_i
31
+ end
32
+
33
+ def self.by_id_hash(d, id_hash)
34
+ data = d.db.query("SELECT * FROM Log_data WHERE id_hash = '#{d.db.esc(id_hash)}' LIMIT 1").fetch
35
+ return data[:id].to_i if data
36
+ return false
37
+ end
38
+
39
+ def links(args = {})
40
+ return ob.list(:Log_data_link, {"data" => self}.merge(args))
41
+ end
42
+ end