noticesys 0.3.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/noticesys.rb CHANGED
@@ -7,8 +7,19 @@ require 'weblet' # HTML retrieval
7
7
  require 'dynarex' # flat file storage system
8
8
  require 'unichron' # universal chron tool (i.e. time calculation)
9
9
  require 'ogextractor' # extract metadata
10
+ require 'recordx_sqlite'
10
11
 
11
12
 
13
+ # classes:
14
+ #
15
+ # Client - sends the msg to the messaging broker
16
+ # StatusView - renders the HTML for a user status
17
+ # StatusListView - renders the HTML for a user timeline
18
+ # CardView - renders the HTML for a card; used within a status
19
+ # HashtagQueryView - renders the HTML for the results for a hashtag search
20
+ # SearchQueryView - renders the HTML for the results for a keyword search
21
+ # CssView - outputs the default CSS used by the microblog
22
+
12
23
  module NoticeSys
13
24
 
14
25
  class Client
@@ -23,29 +34,29 @@ module NoticeSys
23
34
 
24
35
  # save the file attachments containing the images etc.
25
36
 
26
- files = (1..3).map do |n|
27
-
37
+ files = (1..3).map do |n|
38
+
28
39
  f = params['file' + n.to_s]
29
- next unless f
30
-
40
+ next unless f
41
+
31
42
  original = f[:tempfile].to_path
32
-
43
+
33
44
  scale_img original
34
-
35
- end.compact
36
-
45
+
46
+ end.compact
47
+
37
48
  msg = params['msg']
38
49
 
39
50
  urls = msg.scan(/https:\/\/[^ ]+/)
40
-
51
+
41
52
  if urls.any? then
42
53
 
43
54
  h2 = OgExtractor.new(urls.last).to_h
44
-
55
+
45
56
  puts 'h2: ' + h2.inspect if @debug
46
-
57
+
47
58
  if h2 then
48
- h = {msg: msg, files: files}
59
+ h = {msg: msg, files: files}
49
60
 
50
61
  h[:site]= h2[:url][/https?:\/\/([^\/]+)/,1].sub(/^www\./,'')
51
62
 
@@ -53,55 +64,55 @@ module NoticeSys
53
64
  tmpfile = Down.download h2[:img]
54
65
  files2 = scale_img tmpfile.to_path
55
66
  end
56
-
67
+
57
68
  h[:files] = files2 || []
58
- h[:card] = {h2[:card] => { title: h2[:title], desc: h2[:desc],
69
+ h[:card] = {h2[:card] => { title: h2[:title], desc: h2[:desc],
59
70
  url: h2[:url]}}
60
71
  h[:msg] = msg.sub(urls.last,'')
61
72
 
62
73
  return "notice/%s/json: %s" % [@user, h.to_json]
63
-
74
+
64
75
  end
65
-
66
- end
67
76
 
68
- return "notice/%s: %s" % [@user, msg]
77
+ end
78
+
79
+ return "notice/%s: %s" % [@user, msg]
80
+
81
+ end
69
82
 
70
- end
71
-
72
83
  private
73
84
 
74
- def scale_img(raworiginal)
85
+ def scale_img(raworiginal)
75
86
 
76
87
  original = if raworiginal =~ /\.\w+$/ then
77
-
88
+
78
89
  raworiginal
79
-
90
+
80
91
  else
81
-
92
+
82
93
  neworiginal = raworiginal + '.jpg'
83
94
  FileUtils.mv raworiginal, neworiginal
84
95
  neworiginal
85
-
96
+
86
97
  end
87
-
88
- res = %w(240x240 360x360 *518x389 1280x720 2048x1080)
98
+
99
+ res = %w(240x240 360x360 *518x389 1280x720 2048x1080)
89
100
  a = @rmagick.resize(original, res)
90
101
  a2 = (a + [nil,nil,nil]).take(res.length)
91
102
 
92
103
  oldfile = nil
93
104
  sizes = %w(240x240 360x360 small medium large)
94
-
105
+
95
106
  file_sizes = a2.zip(sizes).map.with_index do |x, i|
96
107
 
97
108
  f, label = x
98
109
 
99
- if f then
100
-
110
+ if f then
111
+
101
112
  f2 = f.sub(/_(n\d+x\d+)\.\w+$/) {|x| x.sub($1, label)}
102
113
 
103
114
  FileUtils.mv f, f2
104
- oldfile = f2
115
+ oldfile = f2
105
116
 
106
117
  elsif oldfile
107
118
 
@@ -112,12 +123,12 @@ module NoticeSys
112
123
  FileUtils.cp oldfile, f2
113
124
 
114
125
  end
115
-
116
-
126
+
127
+
117
128
  f2
118
129
 
119
- end
120
-
130
+ end
131
+
121
132
  imgfile = original.sub(/\.\w+$/,'2\0')
122
133
  FileUtils.mv original, imgfile
123
134
 
@@ -125,31 +136,31 @@ module NoticeSys
125
136
 
126
137
  end
127
138
 
128
- end
129
-
130
-
139
+ end
140
+
141
+
131
142
  class CardView
132
-
143
+
133
144
  def initialize(weblet)
134
-
145
+
135
146
  @w = weblet
136
-
147
+
137
148
  end
138
-
149
+
139
150
  def render(dx, rx, card)
140
-
141
- card2 = case card.keys.first
151
+
152
+ card2 = case card.keys.first
142
153
  when :images
143
-
154
+
144
155
  card[:images].map.with_index do |img, i|
145
-
146
- href = [dx.link.sub(/\/$/,''), rx.topic, 'status', rx.id,
156
+
157
+ href = [dx.link.sub(/\/$/,''), rx.topic, 'status', rx.id,
147
158
  'photo', (i+1).to_s ].join('/')
148
159
  url, align = img[:url], img[:align]
149
160
  "<a href='%s'><div class='top-crop %s'><img class='img1' src='%s'/></div></a>" % [href, align, url]
150
-
161
+
151
162
  end.join
152
-
163
+
153
164
  when :summary_large_image
154
165
 
155
166
  h2 = card[:summary_large_image]
@@ -160,7 +171,7 @@ module NoticeSys
160
171
  site = h2[:url][/https?:\/\/([^\/]+)/,1].sub(/^www\./,'')
161
172
  title = h2[:title]
162
173
  img = h2[:img]
163
- url = h2[:url]
174
+ url = h2[:url]
164
175
 
165
176
  @w.render('card', binding)
166
177
 
@@ -175,45 +186,46 @@ module NoticeSys
175
186
  title = h2[:title].length > 46 ? h2[:title][0..46] + '...' : h2[:title]
176
187
  img = h2[:img]
177
188
  url = h2[:url]
178
-
179
- img_element = if img then
189
+
190
+ img_element = if img then
180
191
  "<img src='#{img}'>"
181
192
  else
182
193
  @w.render('svg/article')
183
194
  end
184
195
 
185
- @w.render('card2', binding)
186
-
196
+ @w.render('card2', binding)
197
+
187
198
  end
188
- end
199
+ end
189
200
  end
190
-
201
+
191
202
  class StatusView
192
-
193
- def initialize(basepath, xslfile, css_url, weblet_file)
194
-
203
+ include RXFHelperModule
204
+
205
+ def initialize(basepath, xslfile, css_url, weblet)
206
+
195
207
  @basepath, @xslfile, @css_url = basepath, xslfile, css_url
196
- @w = Weblet.new(weblet_file, binding)
208
+ @w = weblet
197
209
  @card = CardView.new(@w)
198
-
210
+
199
211
  end
200
-
201
- def render(topic, rawid, referer)
212
+
213
+ def render(topic, rawid, referer)
202
214
 
203
215
  id = rawid[0..9].to_i
204
-
205
- filepath = File.join(@basepath, topic)
216
+
217
+ filepath = File.join(@basepath, 'u', topic)
206
218
  a = [Time.at(id).strftime("%Y/%b/%-d").downcase, rawid]
207
219
  xmlfile = File.join(filepath, "%s/%s/index.xml" % a)
208
220
  xslfile = File.join(@basepath, "/xsl/notices/#{topic}.xsl")
209
-
221
+
210
222
  unless File.exists? xslfile then
211
223
  xslfile = @xslfile
212
224
  end
213
225
 
214
226
  dx = Dynarex.new(File.join(filepath, 'feed.xml'))
215
- doc = Rexle.new(File.read(xmlfile))
216
-
227
+ doc = Rexle.new(FileX.read(xmlfile))
228
+
217
229
  doc.root.element('summary/title').text = dx.title
218
230
  e = doc.root.element('summary/image')
219
231
 
@@ -221,120 +233,435 @@ module NoticeSys
221
233
  e = Rexle::Element.new 'image'
222
234
  doc.root.element('summary').add e
223
235
  end
224
-
236
+
225
237
  doc.root.element('summary/image').text = dx.image
226
-
238
+
227
239
  # remove the card from the description
228
240
  desc = doc.root.element('body/description')
229
241
  desc.xpath('img|div').each(&:delete)
230
242
 
231
243
  doc = Nokogiri::XML(doc.root.xml)
232
- xslt = Nokogiri::XSLT(File.read(xslfile))
244
+ xslt = Nokogiri::XSLT(FileX.read(xslfile))
233
245
 
234
246
  s = xslt.transform(doc)
235
247
  doc = Rexle.new(s.to_s)
236
-
237
- rx = Kvx.new(xmlfile)
248
+
249
+ rx = Kvx.new(xmlfile)
238
250
 
239
251
  rawcard = rx.card
240
252
 
241
253
 
242
254
  card2, meta = if rawcard and rawcard.length > 10 then
243
-
255
+
244
256
  card = JSON.parse(rawcard, symbolize_names: true)
245
-
246
- if card.is_a? Hash then
247
-
257
+
258
+ if card.is_a? Hash then
259
+
248
260
  type = card.keys.first
249
261
  h = card[type]
250
262
  #img = h[:img].sub(/small(?=\.\w+$)/,'large')
251
263
  img = h[:img]
252
264
  metadata = @w.render(:meta, binding)
253
265
  [@card.render(dx, rx, card), metadata]
254
-
266
+
255
267
  end
256
268
  else
257
269
  '<span/>'
258
270
  end
259
-
271
+
260
272
 
261
273
  e = doc.root.at_css '#notice'
262
274
  desc = e.at_css '#desc'
263
- desc.add Rexle.new(card2).root
275
+ desc.add Rexle.new(card2).root
264
276
 
265
277
  ref = referer
266
278
  svg = @w.render 'svg/backarrow', binding
267
-
279
+
268
280
  back = if ref then
269
281
  "<div id='back'><a href='#{ref}' title='back'>#{svg}</a></div>"
270
282
  else
271
- ''
283
+ "<div id='back'><a href='/' title='back'>#{svg}</a></div>"
272
284
  end
273
-
285
+
274
286
  @w.render :status, binding
275
287
 
276
288
  end
277
-
289
+
290
+ end
291
+
292
+ class CssView
293
+
294
+ def initialize(weblet_file)
295
+
296
+ @weblet_file = weblet_file
297
+
298
+ end
299
+
300
+ def noticelist_css()
301
+
302
+ w = Weblet.new(@weblet_file)
303
+
304
+ lines = []
305
+ lines << w.render(:main)
306
+ lines << w.render('main/user')
307
+ lines << w.render(:notice)
308
+ lines << w.render('notice/cards')
309
+ lines << w.render('main/noticelist')
310
+ lines << w.render('main/footer')
311
+ lines.join("\n")
312
+
313
+ end
314
+
315
+ def notice_css()
316
+
317
+ w = Weblet.new(@weblet_file)
318
+
319
+ lines = []
320
+ lines << w.render(:status)
321
+ lines << w.render(:cards)
322
+ lines.join("\n")
323
+
324
+ end
325
+
326
+ end
327
+
328
+ class NoticeView
329
+
330
+ def render()
331
+ end
332
+
278
333
  end
279
-
334
+
335
+
280
336
  class StatusListView
281
-
282
- def initialize(basepath, css_url, weblet_file, static_urlbase)
283
-
337
+
338
+ def initialize(basepath, css_url, static_urlbase, weblet)
339
+
284
340
  @basepath, @css_url, @static_urlbase = basepath, css_url, static_urlbase
285
- @w = Weblet.new(weblet_file, binding)
341
+ @w = weblet
286
342
  @card = CardView.new(@w)
287
-
343
+
288
344
  end
289
-
290
- def render(username)
345
+
346
+ def render(username)
291
347
 
292
348
  s = ''
293
-
294
- dx = Dynarex.new(File.join(@basepath, username, 'feed.xml'))
295
-
349
+
350
+ dx = Dynarex.new(File.join(@basepath, 'u', username, 'feed.xml'))
351
+
296
352
  s += @w.render 'user/ptop', binding
297
-
353
+
298
354
  notices = dx.all.map do |rx|
299
-
355
+
300
356
  card2 = ''
301
- rawcard = rx.to_h[:card]
302
-
357
+ rawcard = rx.to_h[:card]
358
+
303
359
  card2 = if rawcard and rawcard.length > 10 then
304
-
305
- card = JSON.parse(rawcard, symbolize_names: true)
306
-
307
- if card.is_a? Hash then
360
+
361
+ card = JSON.parse(rawcard, symbolize_names: true)
362
+
363
+ if card.is_a? Hash then
308
364
  @card.render(dx, rx, card)
309
365
  end
310
-
366
+
311
367
  else
312
368
  ''
313
- end
314
-
369
+ end
370
+
315
371
  t2 = Time.at rx.id.to_s[0..9].to_i
316
372
  relative_time = Unichron.new(t2).elapsed
317
-
373
+
318
374
  d = t2.strftime("%I:%M%p %b %d %Y")
319
-
375
+
320
376
  description = if rx.description.length > 1 then
321
- doc = Rexle.new "<node>%s</node>" % rx.description.gsub(/<\/?p>/,'')
377
+ doc = Rexle.new "<node>%s</node>" % rx.description.gsub(/<\/?p>/,'')
322
378
  doc.root.xpath('img|div').each(&:delete)
323
379
  "<p>%s</p>" % doc.root.xml
324
380
  else
325
381
  ''
326
382
  end
327
383
 
384
+ utitle, uimage, ubio = dx.title, dx.image, dx.bio
328
385
  @w.render :notice, binding
329
-
386
+
330
387
  end
331
388
 
332
- s += notices.join
333
- s += @w.render 'user/rsslink', binding
389
+ s += notices.join
390
+ s += @w.render 'user/rsslink', binding
334
391
  @w.render :user, binding
335
-
392
+
336
393
  end
337
-
338
394
  end
339
-
340
- end
395
+
396
+ class HashtagQueryView
397
+
398
+ def initialize(basepath, db_basepath, css_url, weblet, static_urlbase,
399
+ urlbase, debug: false)
400
+
401
+ @basepath, @css_url, @static_urlbase = basepath, css_url, static_urlbase
402
+ @db_basepath, @w, @urlbase, @debug = db_basepath, weblet, urlbase, debug
403
+ @card = CardView.new(@w)
404
+
405
+ end
406
+
407
+ def render(q, referer)
408
+ #q = args.first
409
+ dbindex_path = File.join(@db_basepath, '/hashtag/index.db')
410
+ puts 'dbindex_path: ' + dbindex_path.inspect if @debug
411
+
412
+ db = RecordxSqlite.new(dbindex_path, table: 'hashtags')
413
+
414
+
415
+ a = db.find_all_by_tag q
416
+
417
+ topics = a.map(&:topic).uniq.map do |topic|
418
+
419
+ topicpath = File.join(@basepath, 'u', topic)
420
+ topic_db_path = File.join(@db_basepath, 'u', topic)
421
+
422
+ db_filepath = File.join(topic_db_path, "notices.db")
423
+ puts 'db_filepath: ' + db_filepath.inspect if @debug
424
+ db = RecordxSqlite.new(db_filepath, table: 'notices')
425
+
426
+ dx = Dynarex.new(File.join(topicpath, 'feed.xml'))
427
+ [topic, OpenStruct.new(title: dx.title, image: dx.image, db: db)]
428
+
429
+ end.to_h
430
+
431
+
432
+ rows = a.map do |x|
433
+
434
+ r = topics[x.topic]
435
+ rx = r.db.find x.noticeid
436
+ link = "%s/%s/status/%s" % [@urlbase, x.topic, x.noticeid]
437
+ OpenStruct.new(rx.to_h.merge({topic: x.topic, title: r.title,
438
+ image: r.image, bio: r.bio, link: link}))
439
+
440
+ end
441
+
442
+
443
+ s = ''
444
+
445
+ notices = rows.sort_by {|x| -(x.id.to_i)}.take(20).map do |rx|
446
+
447
+ next unless rx.description
448
+
449
+ card2 = ''
450
+ rawcard = rx.to_h[:card]
451
+
452
+ card2 = if rawcard and rawcard.length > 10 then
453
+
454
+ card = JSON.parse(rawcard, symbolize_names: true)
455
+
456
+ if card.is_a? Hash then
457
+ @card.render(dx, rx, card)
458
+ end
459
+
460
+ else
461
+ ''
462
+ end
463
+
464
+ t2 = Time.at rx.id.to_s[0..9].to_i
465
+ relative_time = Unichron.new(t2).elapsed
466
+
467
+ d = t2.strftime("%I:%M%p %b %d %Y")
468
+
469
+ description = if rx.description.length > 1 then
470
+ doc = Rexle.new "<node>%s</node>" % rx.description.gsub(/<\/?p>/,'')
471
+ doc.root.xpath('img|div').each(&:delete)
472
+ "<p>%s</p>" % doc.root.xml
473
+ else
474
+ ''
475
+ end
476
+
477
+ utitle, uimage, ubio = rx.title, rx.image, rx.bio
478
+ @w.render :notice, binding
479
+
480
+ end
481
+
482
+ s += if notices.any? then
483
+ notices.compact.join
484
+ else
485
+ "<p>No results for #{q}</p>"
486
+ end
487
+
488
+ ref = referer
489
+ ref = '../' if ref =~ /(?:status|hashtag)\/\d+/
490
+
491
+ svg = @w.render 'svg/backarrow', binding
492
+ back = ref ? "<a href='#{ref}'>#{svg}</a>" : ''
493
+
494
+ @w.render :search_pg, binding
495
+
496
+ end
497
+
498
+
499
+ end
500
+
501
+ class SearchQueryView
502
+
503
+ def initialize(basepath, db_basepath, css_url, weblet, static_urlbase, urlbase)
504
+
505
+ @basepath, @css_url, @static_urlbase = basepath, css_url, static_urlbase
506
+ @db_basepath, @w, @urlbase = db_basepath, weblet, urlbase
507
+ @card = CardView.new(@w)
508
+
509
+ end
510
+
511
+ def render(q, referer)
512
+
513
+
514
+ users = Dir.glob(File.join(@basepath, 'u', '*')).map do |x|
515
+ File.basename(x)
516
+ end
517
+
518
+ topics = users.map do |topic|
519
+
520
+ topicpath = File.join(@basepath, 'u', topic)
521
+ topic_db_path = File.join(@db_basepath, 'u', topic)
522
+ db_filepath = File.join(topic_db_path, "notices.db")
523
+ db = RecordxSqlite.new(db_filepath, table: 'notices')
524
+
525
+ dx = Dynarex.new(File.join(topicpath, 'feed.xml'))
526
+ [topic, OpenStruct.new(title: dx.title, image: dx.image, bio: dx.bio, db: db)]
527
+
528
+ end.to_h
529
+
530
+ #return topics.inspect
531
+ rows = topics.flat_map do |topic, r|
532
+
533
+ a = r.db.all.select {|x| x.description =~ /#{q.gsub('$',"\\$")}/i}
534
+ a.map do |rx|
535
+ link = "%s/%s/status/%s" % [@urlbase, topic, rx.noticeid]
536
+ OpenStruct.new(rx.to_h.merge({topic: topic, title: r.title, image: r.image, link: link}))
537
+ end
538
+
539
+ end
540
+
541
+
542
+ #return rows.inspect
543
+ s = ''
544
+
545
+ notices = rows.sort_by {|x| -(x.id.to_i)}.take(20).map do |rx|
546
+
547
+
548
+ card2 = ''
549
+ rawcard = rx.to_h[:card]
550
+
551
+ card2 = if rawcard and rawcard.length > 10 then
552
+
553
+ card = JSON.parse(rawcard, symbolize_names: true)
554
+
555
+ if card.is_a? Hash then
556
+ @card.render(dx, rx, card)
557
+ end
558
+
559
+ else
560
+ ''
561
+ end
562
+
563
+ #rx.description
564
+ t2 = Time.at rx.id.to_s[0..9].to_i
565
+ relative_time = Unichron.new(t2).elapsed
566
+
567
+ d = t2.strftime("%I:%M%p %b %d %Y")
568
+
569
+ #desc = rx.description.gsub(/<\/?p>/,'').gsub('&lt;','<').gsub('&gt;','>')
570
+
571
+ topic = rx.topic
572
+ title, image, bio = %i(title image bio).map do |x|
573
+ topics[topic].method(x).call
574
+ end
575
+
576
+ description = if rx.description.length > 1 then
577
+ doc = Rexle.new "<node>%s</node>" % rx.description.gsub(/<\/?p>/,'')
578
+ doc.root.xpath('img|div').each(&:delete)
579
+ "<p>%s</p>" % doc.root.xml
580
+ else
581
+ ''
582
+ end
583
+
584
+ utitle, uimage, ubio = title, image, bio
585
+ @w.render :notice, binding
586
+
587
+
588
+ end
589
+ #return notices.inspect
590
+
591
+ s += if notices.any? then
592
+ notices.join
593
+ else
594
+ "<p>No results for #{q}</p>"
595
+ end
596
+
597
+ #ref = @env["HTTP_REFERER"]
598
+ ref = referer
599
+ ref = '../' if ref =~ /(?:status\/\d+|search)/
600
+ svg = @w.render 'svg/backarrow', binding
601
+ back = ref ? "<a href='#{ref}'>#{svg}</a>" : "<a href='/'>#{svg}</a>"
602
+
603
+ @w.render :search_pg, binding
604
+
605
+
606
+ end
607
+
608
+
609
+ end
610
+
611
+ class Main
612
+
613
+ def initialize(basepath, db_basepath, xslfile, statuscss_url,
614
+ statuslistcss_url, weblet_file, static_urlbase,
615
+ urlbase, weblet_cssfile, debug: false)
616
+
617
+ weblet_file ||= File.join(File.dirname(__FILE__), '..',
618
+ 'data', 'microblog.txt')
619
+
620
+ weblet = Weblet.new(weblet_file)
621
+
622
+ @status = StatusView.new(basepath, xslfile, statuscss_url, weblet)
623
+
624
+ @statuslist = StatusListView.new(basepath, statuslistcss_url,
625
+ static_urlbase, weblet)
626
+
627
+ @hashtag = HashtagQueryView.new(basepath, db_basepath,
628
+ statuslistcss_url, weblet,
629
+ static_urlbase, urlbase, debug: debug)
630
+
631
+ @search = SearchQueryView.new(basepath, db_basepath, statuslistcss_url,
632
+ weblet, static_urlbase, urlbase)
633
+
634
+ weblet_cssfile ||= File.join(File.dirname(__FILE__), '..',
635
+ 'data', 'css.txt')
636
+ @css = CssView.new(weblet_cssfile)
637
+
638
+ end
639
+
640
+ def notice_css()
641
+ @css.notice_css()
642
+ end
643
+
644
+ def noticelist_css()
645
+ @css.noticelist_css()
646
+ end
647
+
648
+ def status(topic, rawid, referer)
649
+ @status.render topic, rawid, referer
650
+ end
651
+
652
+ def status_list(username)
653
+ @statuslist.render username
654
+ end
655
+
656
+ def hashtag_query(s, referer)
657
+ @hashtag.render s, referer
658
+ end
659
+
660
+ def search_query(s, referer)
661
+ @search.render s, referer
662
+ end
663
+
664
+
665
+ end
666
+
667
+ end