Mercurial Hosting > linkmystyle
comparison src/lib/Reporting.luan @ 0:8f4df159f06b
start public repo
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Fri, 11 Jul 2025 20:57:49 -0600 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:8f4df159f06b |
---|---|
1 local Luan = require "luan:Luan.luan" | |
2 local error = Luan.error | |
3 local stringify = Luan.stringify or error() | |
4 local pairs = Luan.pairs or error() | |
5 local ipairs = Luan.ipairs or error() | |
6 local range = Luan.range or error() | |
7 local Io = require "luan:Io.luan" | |
8 local uri = Io.uri or error() | |
9 local Number = require "luan:Number.luan" | |
10 local long = Number.long or error() | |
11 local Time = require "luan:Time.luan" | |
12 local time_now = Time.now or error() | |
13 local Table = require "luan:Table.luan" | |
14 local copy = Table.copy or error() | |
15 local sort = Table.sort or error() | |
16 local Thread = require "luan:Thread.luan" | |
17 local Lucene = require "luan:lucene/Lucene.luan" | |
18 local Shared = require "site:/lib/Shared.luan" | |
19 local compressed = Shared.compressed or error() | |
20 local Utils = require "site:/lib/Utils.luan" | |
21 local list_to_set = Utils.list_to_set or error() | |
22 local Logging = require "luan:logging/Logging.luan" | |
23 local logger = Logging.logger "Reporting" | |
24 | |
25 | |
26 local Reporting = {} | |
27 | |
28 local dir = uri("site:/private/local/reporting") | |
29 | |
30 local db = Lucene.index( dir ) | |
31 Reporting.db = db | |
32 | |
33 db.indexed_fields.owner = Lucene.type.string | |
34 db.indexed_fields.value = Lucene.type.string | |
35 db.indexed_fields.day = Lucene.type.long | |
36 | |
37 | |
38 local day = Time.period{days=1} | |
39 local days = Time.period{days=30} | |
40 local offset_from_GMT = Time.period{hours=7} | |
41 | |
42 local function today() | |
43 local today = (time_now() - offset_from_GMT) // day * day + offset_from_GMT | |
44 return long(today) | |
45 end | |
46 | |
47 local function by_count(rec1,rec2) | |
48 return rec1.count > rec2.count | |
49 end | |
50 | |
51 local limit = 20 | |
52 | |
53 function Reporting.get_data( query, sum_by ) | |
54 local first_day = long(today() - days) | |
55 query = query.." +day:["..first_day.." TO *]" | |
56 local data | |
57 if sum_by == nil then | |
58 data = db.search( query, 1, 1000000 ) | |
59 else | |
60 local t = {} | |
61 db.advanced_search( query, function(_,doc_fn,_) | |
62 local doc = doc_fn() | |
63 local key = doc[sum_by] | |
64 if key == nil then | |
65 logger.warn("missing '"..sum_by.."' in "..stringify(doc)) | |
66 return | |
67 end | |
68 local count = doc.count or error() | |
69 local found = t[key] | |
70 if found == nil then | |
71 t[key] = { | |
72 [sum_by] = key | |
73 count = count | |
74 } | |
75 else | |
76 found.count = found.count + count | |
77 end | |
78 end ) | |
79 data = {} | |
80 for _, val in pairs(t) do | |
81 data[#data+1] = val | |
82 end | |
83 end | |
84 | |
85 -- for graph | |
86 if sum_by == nil or sum_by == "day" then | |
87 local last_day = today() | |
88 local first_day = last_day - days | |
89 local map = {} | |
90 for _, el in ipairs(data) do | |
91 map[long(el.day)] = el.count | |
92 end | |
93 data = {} | |
94 for date in range(first_day,last_day,day) do | |
95 date = long(date) | |
96 local count = map[date] or 0 | |
97 data[#data+1] = {date,count} | |
98 end | |
99 return data | |
100 else | |
101 sort(data,by_count) | |
102 local t = {nil} | |
103 local n = 0 | |
104 for _, el in ipairs(data) do | |
105 t[#t+1] = { x=el[sum_by], y=el.count } | |
106 n = n + 1 | |
107 if n == limit then | |
108 break | |
109 end | |
110 end | |
111 return t | |
112 end | |
113 end | |
114 | |
115 local function delete_old() | |
116 logger.warn "delete_old" | |
117 local expired = long( today() - Time.period{days=31} ) | |
118 db.delete( "day:[* TO "..expired.."}" ) | |
119 end | |
120 -- delete_old() | |
121 Thread.schedule( delete_old, { repeating_delay=Time.period{days=1} } ) | |
122 | |
123 | |
124 -- for ads | |
125 | |
126 db.indexed_fields.ad_visit_owner_id = Lucene.type.long | |
127 | |
128 local visit_period = Time.period{hours=1} | |
129 -- visit_period = Time.period{seconds=1} | |
130 | |
131 function Reporting.maybe_track_visit(owner) | |
132 local doc = db.get_document{ ad_visit_owner_id = owner.id } | |
133 return doc == nil or doc.time + visit_period < time_now() | |
134 end | |
135 | |
136 function Reporting.should_track_visit(owner) | |
137 return db.run_in_transaction( function() | |
138 local now = time_now() | |
139 local doc = db.get_document{ ad_visit_owner_id = owner.id } | |
140 if doc == nil then | |
141 db.save{ | |
142 type = "ad_visit" | |
143 ad_visit_owner_id = owner.id | |
144 time = now | |
145 } | |
146 return true | |
147 elseif doc.time + visit_period < now then | |
148 doc.time = now | |
149 db.save(doc) | |
150 return true | |
151 else | |
152 return false | |
153 end | |
154 end ) | |
155 end | |
156 | |
157 function Reporting.owners_with_visits() | |
158 local owner_ids = list_to_set{} | |
159 local docs = db.search("type:ad_visit",1,1000000) | |
160 for _, doc in ipairs(docs) do | |
161 owner_ids[doc.ad_visit_owner_id] = true | |
162 end | |
163 return owner_ids | |
164 end | |
165 | |
166 return Reporting |